diff options
author | Thierry Strudel <tstrudel@google.com> | 2016-12-13 12:19:52 -0800 |
---|---|---|
committer | Thierry Strudel <tstrudel@google.com> | 2016-12-15 12:22:15 -0800 |
commit | 0cfe6f8bff87bcbdeef6fcfdbb91d67d42f33927 (patch) | |
tree | 1c08d488f104ed297fdd31b6c513e8259f8c2876 /msm8998/mm-video-v4l2 | |
parent | b50ee0d49e33884a5f998649944fff0a8e27cda6 (diff) | |
download | media-0cfe6f8bff87bcbdeef6fcfdbb91d67d42f33927.tar.gz |
msm8998: rename msmcobalt to msm8998
Bug: 33556391
Change-Id: I608cbf071aa5862c5c9caf540b9a8597e4363c0d
Diffstat (limited to 'msm8998/mm-video-v4l2')
59 files changed, 75894 insertions, 0 deletions
diff --git a/msm8998/mm-video-v4l2/Android.mk b/msm8998/mm-video-v4l2/Android.mk new file mode 100644 index 0000000..6361f9b --- /dev/null +++ b/msm8998/mm-video-v4l2/Android.mk @@ -0,0 +1,2 @@ +LOCAL_PATH := $(call my-dir) +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/msm8998/mm-video-v4l2/Makefile.am b/msm8998/mm-video-v4l2/Makefile.am new file mode 100644 index 0000000..2265df9 --- /dev/null +++ b/msm8998/mm-video-v4l2/Makefile.am @@ -0,0 +1,5 @@ +# Makefile.am - Automake script for mm-omxvideo +# +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = vidc diff --git a/msm8998/mm-video-v4l2/vidc/Android.mk b/msm8998/mm-video-v4l2/vidc/Android.mk new file mode 100644 index 0000000..5c069fe --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/Android.mk @@ -0,0 +1,2 @@ +LOCAL_PATH := $(call my-dir) +include $(call all-makefiles-under, $(LOCAL_PATH)) diff --git a/msm8998/mm-video-v4l2/vidc/Makefile.am b/msm8998/mm-video-v4l2/vidc/Makefile.am new file mode 100644 index 0000000..4621239 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/Makefile.am @@ -0,0 +1,5 @@ +# Makefile.am - Automake script for mm-omxvideo +# +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = venc diff --git a/msm8998/mm-video-v4l2/vidc/common/Android.mk b/msm8998/mm-video-v4l2/vidc/common/Android.mk new file mode 100644 index 0000000..22d838f --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/common/Android.mk @@ -0,0 +1,51 @@ +ROOT_DIR := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_PATH:= $(ROOT_DIR) + +# --------------------------------------------------------------------------------- +# Common definitons +# --------------------------------------------------------------------------------- + +libmm-vidc-def := -g -O3 -Dlrintf=_ffix_r +libmm-vidc-def += -D__align=__alignx +libmm-vidc-def += -D__alignx\(x\)=__attribute__\(\(__aligned__\(x\)\)\) +libmm-vidc-def += -DT_ARM +libmm-vidc-def += -Dinline=__inline +libmm-vidc-def += -D_ANDROID_ +libmm-vidc-def += -Werror +libmm-vidc-def += -D_ANDROID_ICS_ + +# --------------------------------------------------------------------------------- +# Make the Shared library (libOmxVidcCommon) +# --------------------------------------------------------------------------------- + +libmm-vidc-inc := $(LOCAL_PATH)/inc +libmm-vidc-inc += $(QCOM_MEDIA_ROOT)/mm-core/inc +libmm-vidc-inc += $(TARGET_OUT_HEADERS)/qcom/display +libmm-vidc-inc += $(QCOM_MEDIA_ROOT)/libc2dcolorconvert +libmm-vidc-inc += $(TOP)/frameworks/av/include/media/stagefright +ifeq ($(TARGET_COMPILE_WITH_MSM_KERNEL),true) +libmm-vidc-inc += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +endif + +LOCAL_MODULE := libOmxVidcCommon +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libmm-vidc-def) +LOCAL_C_INCLUDES := $(libmm-vidc-inc) + +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := liblog libutils libcutils libdl + +LOCAL_SRC_FILES := src/extra_data_handler.cpp +LOCAL_SRC_FILES += src/vidc_color_converter.cpp + +ifeq ($(TARGET_COMPILE_WITH_MSM_KERNEL),true) +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +endif + +include $(BUILD_STATIC_LIBRARY) + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- diff --git a/msm8998/mm-video-v4l2/vidc/common/inc/extra_data_handler.h b/msm8998/mm-video-v4l2/vidc/common/inc/extra_data_handler.h new file mode 100644 index 0000000..dd1af29 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/common/inc/extra_data_handler.h @@ -0,0 +1,84 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ + +#ifndef __EXTRA_DATA_HANDLER_H__ +#define __EXTRA_DATA_HANDLER_H__ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include "OMX_QCOMExtns.h" +#include<linux/msm_vidc_dec.h> +#include<linux/msm_vidc_enc.h> + +#ifdef _ANDROID_ +extern "C" { +#include<utils/Log.h> +} +#endif // _ANDROID_ + +#include "vidc_debug.h" +#define SEI_PAYLOAD_FRAME_PACKING_ARRANGEMENT 0x2D +#define H264_START_CODE 0x01 +#define NAL_TYPE_SEI 0x06 +#define VDEC_OMX_SEI 0x7F000007 +#define FRAME_PACK_SIZE 18 +#define H264_EMULATION_BYTE 0x03 +class extra_data_handler +{ + public: + extra_data_handler(); + ~extra_data_handler(); + OMX_U32 parse_extra_data(OMX_BUFFERHEADERTYPE *buf_hdr); + OMX_U32 create_extra_data(OMX_BUFFERHEADERTYPE *buf_hdr); + OMX_U32 get_frame_pack_data(OMX_QCOM_FRAME_PACK_ARRANGEMENT *frame_pack); + OMX_U32 set_frame_pack_data(OMX_QCOM_FRAME_PACK_ARRANGEMENT *frame_pack); + private: + OMX_QCOM_FRAME_PACK_ARRANGEMENT frame_packing_arrangement; + OMX_U8 *rbsp_buf; + OMX_U32 bit_ptr; + OMX_U32 byte_ptr; + OMX_U32 pack_sei; + OMX_U32 sei_payload_type; + OMX_U32 d_u(OMX_U32 num_bits); + OMX_U32 d_ue(); + OMX_U32 parse_frame_pack(void); + OMX_S32 parse_rbsp(OMX_U8 *buf, OMX_U32 len); + OMX_S32 parse_sei(OMX_U8 *buffer, OMX_U32 buffer_length); + OMX_U32 e_u(OMX_U32 symbol, OMX_U32 num_bits); + OMX_U32 e_ue(OMX_U32 symbol); + OMX_U32 create_frame_pack(); + OMX_S32 create_rbsp(OMX_U8 *buf, OMX_U32 nalu_type); + OMX_U32 create_sei(OMX_U8 *buffer); + OMX_S32 parse_sliceinfo(OMX_BUFFERHEADERTYPE *pBufHdr, + OMX_OTHER_EXTRADATATYPE *pExtra); + OMX_S32 parse_ltrinfo(OMX_OTHER_EXTRADATATYPE *pExtra); +}; + +#endif diff --git a/msm8998/mm-video-v4l2/vidc/common/inc/vidc_color_converter.h b/msm8998/mm-video-v4l2/vidc/common/inc/vidc_color_converter.h new file mode 100644 index 0000000..5361c11 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/common/inc/vidc_color_converter.h @@ -0,0 +1,55 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2012-2013, 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. +--------------------------------------------------------------------------*/ +#include <dlfcn.h> +#include "C2DColorConverter.h" + +using namespace android; +class omx_c2d_conv +{ + public: + omx_c2d_conv(); + ~omx_c2d_conv(); + bool init(); + void destroy(); + bool open(unsigned int height,unsigned int width, + ColorConvertFormat src, + ColorConvertFormat dest); + bool convert(int src_fd, void *src_base, void *src_viraddr, + int dest_fd, void *dest_base, void *dest_viraddr); + bool get_buffer_size(int port,unsigned int &buf_size); + bool get_output_filled_length(unsigned int &filled_length); + int get_src_format(); + void close(); + private: + C2DColorConverterBase *c2dcc; + void *mLibHandle; + ColorConvertFormat src_format; + createC2DColorConverter_t *mConvertOpen; + destroyC2DColorConverter_t *mConvertClose; +}; diff --git a/msm8998/mm-video-v4l2/vidc/common/inc/vidc_debug.h b/msm8998/mm-video-v4l2/vidc/common/inc/vidc_debug.h new file mode 100644 index 0000000..3423a35 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/common/inc/vidc_debug.h @@ -0,0 +1,157 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2013 - 2016, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ + +#ifndef __VIDC_DEBUG_H__ +#define __VIDC_DEBUG_H__ + +#ifdef _ANDROID_ +#include <cstdio> +#include <pthread.h> +#include <sys/mman.h> + +enum { + PRIO_ERROR=0x1, + PRIO_INFO=0x1, + PRIO_HIGH=0x2, + PRIO_LOW=0x4, + PRIO_TRACE_HIGH = 0x10, + PRIO_TRACE_LOW = 0x20, +}; + +extern int debug_level; + +#undef DEBUG_PRINT_ERROR +#define DEBUG_PRINT_ERROR(fmt, args...) ({ \ + if (debug_level & PRIO_ERROR) \ + ALOGE(fmt,##args); \ + }) +#undef DEBUG_PRINT_INFO +#define DEBUG_PRINT_INFO(fmt, args...) ({ \ + if (debug_level & PRIO_INFO) \ + ALOGI(fmt,##args); \ + }) +#undef DEBUG_PRINT_LOW +#define DEBUG_PRINT_LOW(fmt, args...) ({ \ + if (debug_level & PRIO_LOW) \ + ALOGD(fmt,##args); \ + }) +#undef DEBUG_PRINT_HIGH +#define DEBUG_PRINT_HIGH(fmt, args...) ({ \ + if (debug_level & PRIO_HIGH) \ + ALOGD(fmt,##args); \ + }) +#else +#define DEBUG_PRINT_ERROR printf +#define DEBUG_PRINT_INFO printf +#define DEBUG_PRINT_LOW printf +#define DEBUG_PRINT_HIGH printf +#endif + +#define VALIDATE_OMX_PARAM_DATA(ptr, paramType) \ + { \ + if (ptr == NULL) { return OMX_ErrorBadParameter; } \ + paramType *p = reinterpret_cast<paramType *>(ptr); \ + if (p->nSize < sizeof(paramType)) { \ + ALOGE("Insufficient object size(%u) v/s expected(%zu) for type %s",\ + (unsigned int)p->nSize, sizeof(paramType), #paramType); \ + return OMX_ErrorBadParameter; \ + } \ + } \ + +class auto_lock { + public: + auto_lock(pthread_mutex_t &lock) + : mLock(lock) { + pthread_mutex_lock(&mLock); + } + ~auto_lock() { + pthread_mutex_unlock(&mLock); + } + private: + pthread_mutex_t &mLock; +}; + +class AutoUnmap { + void *vaddr; + int size; + + public: + AutoUnmap(void *vaddr, int size) { + this->vaddr = vaddr; + this->size = size; + } + + ~AutoUnmap() { + if (vaddr) + munmap(vaddr, size); + } +}; + +#ifdef _ANDROID_ +#define ATRACE_TAG ATRACE_TAG_VIDEO +#include <utils/Trace.h> + +class AutoTracer { + int mPrio; +public: + AutoTracer(int prio, const char* msg) + : mPrio(prio) { + if (debug_level & prio) { + ATRACE_BEGIN(msg); + } + } + ~AutoTracer() { + if (debug_level & mPrio) { + ATRACE_END(); + } + } +}; + +#define VIDC_TRACE_NAME_LOW(_name) AutoTracer _tracer(PRIO_TRACE_LOW, _name); +#define VIDC_TRACE_NAME_HIGH(_name) AutoTracer _tracer(PRIO_TRACE_HIGH, _name); + +#define VIDC_TRACE_INT_LOW(_name, _int) \ + if (debug_level & PRIO_TRACE_LOW) { \ + ATRACE_INT(_name, _int); \ + } + +#define VIDC_TRACE_INT_HIGH(_name, _int) \ + if (debug_level & PRIO_TRACE_HIGH) { \ + ATRACE_INT(_name, _int); \ + } + +#else // _ANDROID_ + +#define VIDC_TRACE_NAME_LOW(_name) +#define VIDC_TRACE_NAME_HIGH(_name) +#define VIDC_TRACE_INT_LOW(_name, _int) +#define VIDC_TRACE_INT_HIGH(_name, _int) + +#endif // !_ANDROID_ + +#endif diff --git a/msm8998/mm-video-v4l2/vidc/common/src/extra_data_handler.cpp b/msm8998/mm-video-v4l2/vidc/common/src/extra_data_handler.cpp new file mode 100644 index 0000000..187eb77 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/common/src/extra_data_handler.cpp @@ -0,0 +1,551 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ + +#include "extra_data_handler.h" + +int debug_level = PRIO_ERROR; + +extra_data_handler::extra_data_handler() +{ + rbsp_buf = (OMX_U8 *) calloc(1,100); + memset(&frame_packing_arrangement,0,sizeof(frame_packing_arrangement)); + frame_packing_arrangement.cancel_flag = 1; + pack_sei = false; + sei_payload_type = -1; +} + +extra_data_handler::~extra_data_handler() +{ + if (rbsp_buf) { + free(rbsp_buf); + rbsp_buf = NULL; + } +} + +OMX_U32 extra_data_handler::d_u(OMX_U32 num_bits) +{ + OMX_U32 rem_bits = num_bits, bins = 0, shift = 0; + + while (rem_bits >= bit_ptr) { + DEBUG_PRINT_LOW("In %s() bit_ptr/byte_ptr :%u/%u/%x", __func__, (unsigned int)bit_ptr, + (unsigned int)byte_ptr, rbsp_buf[byte_ptr]); + bins <<= shift; + shift = (8-bit_ptr); + bins |= ((rbsp_buf[byte_ptr] << shift) & 0xFF) >> shift; + rem_bits -= bit_ptr; + bit_ptr = 8; + byte_ptr ++; + } + + DEBUG_PRINT_LOW("In %s() bit_ptr/byte_ptr :%u/%u/%x", __func__, (unsigned int)bit_ptr, + (unsigned int)byte_ptr, rbsp_buf[byte_ptr]); + + if (rem_bits) { + bins <<= rem_bits; + bins |= ((rbsp_buf[byte_ptr] << (8-bit_ptr)) & 0xFF) >> (8-rem_bits); + bit_ptr -= rem_bits; + + if (bit_ptr == 0) { + bit_ptr = 8; + byte_ptr++; + } + } + + DEBUG_PRINT_LOW("In %s() bit_ptr/byte_ptr :%u/%u/%x", __func__, (unsigned int)bit_ptr, + (unsigned int)byte_ptr, rbsp_buf[byte_ptr]); + + DEBUG_PRINT_LOW("In %s() bin/num_bits : %x/%u", __func__, (unsigned)bins, (unsigned int)num_bits); + return bins; +} + +OMX_U32 extra_data_handler::d_ue() +{ + OMX_S32 lead_zeros = -1; + OMX_U32 symbol, bit; + + do { + bit = d_u(1); + lead_zeros++; + } while (!bit); + + symbol = ((1 << lead_zeros) - 1) + d_u(lead_zeros); + + DEBUG_PRINT_LOW("In %s() symbol : %u", __func__, (unsigned int)symbol); + return symbol; +} + +OMX_U32 extra_data_handler::parse_frame_pack(void) +{ + frame_packing_arrangement.id = d_ue(); + frame_packing_arrangement.cancel_flag = d_u(1); + + if (!frame_packing_arrangement.cancel_flag) { + frame_packing_arrangement.type = d_u(7); + frame_packing_arrangement.quincunx_sampling_flag = d_u(1); + frame_packing_arrangement.content_interpretation_type = d_u(6); + frame_packing_arrangement.spatial_flipping_flag = d_u(1); + frame_packing_arrangement.frame0_flipped_flag = d_u(1); + frame_packing_arrangement.field_views_flag = d_u(1); + frame_packing_arrangement.current_frame_is_frame0_flag = d_u(1); + frame_packing_arrangement.frame0_self_contained_flag = d_u(1); + frame_packing_arrangement.frame1_self_contained_flag = d_u(1); + + if (!frame_packing_arrangement.quincunx_sampling_flag && + frame_packing_arrangement.type != 5) { + frame_packing_arrangement.frame0_grid_position_x = d_u(4); + frame_packing_arrangement.frame0_grid_position_y = d_u(4); + frame_packing_arrangement.frame1_grid_position_x = d_u(4); + frame_packing_arrangement.frame1_grid_position_y = d_u(4); + } + + frame_packing_arrangement.reserved_byte = d_u(8); + frame_packing_arrangement.repetition_period = d_ue(); + } + + frame_packing_arrangement.extension_flag = d_u(1); + + return 1; +} + +OMX_S32 extra_data_handler::parse_rbsp(OMX_U8 *buf, OMX_U32 len) +{ + OMX_U32 i = 3, j=0, startcode; + OMX_U32 nal_unit_type, nal_ref_idc, forbidden_zero_bit; + + bit_ptr = 8; + byte_ptr = 0; + + startcode = buf[0] << 16 | buf[1] <<8 | buf[2]; + + if (!startcode) { + startcode |= buf[i++]; + } + + if (startcode != H264_START_CODE) { + DEBUG_PRINT_ERROR("ERROR: In %s() Start code not found", __func__); + return -1; + } + + forbidden_zero_bit = (buf[i] & 0x80) >>7; + + if (forbidden_zero_bit) { + DEBUG_PRINT_ERROR("ERROR: In %s() Non-zero forbidden bit", __func__); + return -1; + } + + nal_ref_idc = (buf[i] & 0x60) >>5; + DEBUG_PRINT_LOW("In %s() nal_ref_idc ; %u", __func__, (unsigned int)nal_ref_idc); + + nal_unit_type = (buf[i++] & 0x1F); + + while (i<len) { + if (!(buf[i] + buf[i+1]) && (buf[i+2] == H264_EMULATION_BYTE) && + (i+2 < len)) { + rbsp_buf[j++] = buf[i++]; + rbsp_buf[j++] = buf[i++]; + i++; + } else + rbsp_buf[j++] = buf[i++]; + } + + return nal_unit_type; +} +OMX_S32 extra_data_handler::parse_sei(OMX_U8 *buffer, OMX_U32 buffer_length) +{ + OMX_U32 nal_unit_type, payload_type = 0, payload_size = 0; + OMX_U32 marker = 0, pad = 0xFF; + + nal_unit_type = parse_rbsp(buffer, buffer_length); + + if (nal_unit_type != NAL_TYPE_SEI) { + DEBUG_PRINT_ERROR("ERROR: In %s() - Non SEI NAL ", __func__); + return -1; + } else { + + while (rbsp_buf[byte_ptr] == 0xFF) + payload_type += rbsp_buf[byte_ptr++]; + + payload_type += rbsp_buf[byte_ptr++]; + + DEBUG_PRINT_LOW("In %s() payload_type : %u", __func__, (unsigned int)payload_type); + + while (rbsp_buf[byte_ptr] == 0xFF) + payload_size += rbsp_buf[byte_ptr++]; + + payload_size += rbsp_buf[byte_ptr++]; + + DEBUG_PRINT_LOW("In %s() payload_size : %u", __func__, (unsigned int)payload_size); + + switch (payload_type) { + case SEI_PAYLOAD_FRAME_PACKING_ARRANGEMENT: + DEBUG_PRINT_LOW("In %s() Frame Packing SEI ", __func__); + parse_frame_pack(); + break; + default: + DEBUG_PRINT_LOW("INFO: In %s() Not Supported SEI NAL ", __func__); + break; + } + } + + if (bit_ptr != 8) { + marker = d_u(1); + + if (marker) { + if (bit_ptr != 8) { + pad = d_u(bit_ptr); + + if (pad) { + DEBUG_PRINT_ERROR("ERROR: In %s() padding Bits Error in SEI", + __func__); + return -1; + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: In %s() Marker Bit Error in SEI", + __func__); + return -1; + } + } + + DEBUG_PRINT_LOW("In %s() payload_size : %u/%u", __func__, + (unsigned int)payload_size, (unsigned int)byte_ptr); + return 1; +} + +OMX_S32 extra_data_handler::parse_ltrinfo(OMX_OTHER_EXTRADATATYPE *pExtra) +{ + OMX_U32 *pLTR; + pExtra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataVideoLTRInfo; + pLTR = (OMX_U32* )pExtra + 5; + DEBUG_PRINT_HIGH("ExtraData LTR ID %u", (unsigned int)*pLTR); + return 0; +} +/*====================================================================== + Slice Information will be available as below (each line is of 4 bytes) + | number of slices | + | 1st slice offset | + | 1st slice size | + | .. | + | Nth slice offset | + | Nth slice size | + ======================================================================*/ +OMX_S32 extra_data_handler::parse_sliceinfo( + OMX_BUFFERHEADERTYPE *pBufHdr, OMX_OTHER_EXTRADATATYPE *pExtra) +{ + OMX_U32 slice_offset = 0, slice_size = 0, total_size = 0; + OMX_U8 *pBuffer = (OMX_U8 *)pBufHdr->pBuffer; + OMX_U32 *data = (OMX_U32 *)(void *)pExtra->data; + OMX_U32 num_slices = *data; + DEBUG_PRINT_LOW("number of slices = %u", (unsigned int)num_slices); + + if ((4 + num_slices * 8) != (OMX_U32)pExtra->nDataSize) { + DEBUG_PRINT_ERROR("unknown error in slice info extradata"); + return -1; + } + + for (unsigned i = 0; i < num_slices; i++) { + slice_offset = (OMX_U32)(*(data + (i*2 + 1))); + + if ((*(pBuffer + slice_offset + 0) != 0x00) || + (*(pBuffer + slice_offset + 1) != 0x00) || + (*(pBuffer + slice_offset + 2) != 0x00) || + (*(pBuffer + slice_offset + 3) != H264_START_CODE)) { + DEBUG_PRINT_ERROR("found 0x%x instead of start code at offset[%u] " + "for slice[%u]", (unsigned)(*(OMX_U32 *)(pBuffer + slice_offset)), + (unsigned int)slice_offset, i); + return -1; + } + + if (slice_offset != total_size) { + DEBUG_PRINT_ERROR("offset of slice number %d is not correct " + "or previous slice size is not correct", i); + return -1; + } + + slice_size = (OMX_U32)(*(data + (i*2 + 2))); + total_size += slice_size; + DEBUG_PRINT_LOW("slice number %d offset/size = %u/%u", + i, (unsigned int)slice_offset, (unsigned int)slice_size); + } + + if (pBufHdr->nFilledLen != total_size) { + DEBUG_PRINT_ERROR("frame_size[%u] is not equal to " + "total slices size[%u]", (unsigned int)pBufHdr->nFilledLen, (unsigned int)total_size); + return -1; + } + + return 0; +} + +OMX_U32 extra_data_handler::parse_extra_data(OMX_BUFFERHEADERTYPE *buf_hdr) +{ + DEBUG_PRINT_LOW("In %s() flags: 0x%x", __func__, (unsigned)buf_hdr->nFlags); + + if (buf_hdr->nFlags & OMX_BUFFERFLAG_EXTRADATA) { + + OMX_OTHER_EXTRADATATYPE *extra_data = (OMX_OTHER_EXTRADATATYPE *) + ((unsigned long)(buf_hdr->pBuffer + buf_hdr->nOffset + + buf_hdr->nFilledLen + 3)&(~3)); + + while (extra_data && + ((unsigned long)extra_data > (unsigned long)buf_hdr->pBuffer) && + ((unsigned long)extra_data < (unsigned long)buf_hdr->pBuffer + buf_hdr->nAllocLen)) { + + DEBUG_PRINT_LOW("extradata(%p): nSize = 0x%x, eType = 0x%x," + " nDataSize = 0x%x", extra_data, (unsigned int)extra_data->nSize, + extra_data->eType, (unsigned int)extra_data->nDataSize); + + if ((extra_data->eType == VDEC_EXTRADATA_NONE) || + (extra_data->eType == VEN_EXTRADATA_NONE)) { + DEBUG_PRINT_LOW("No more extradata available"); + extra_data->eType = OMX_ExtraDataNone; + break; + } else if (extra_data->eType == VDEC_EXTRADATA_SEI) { + DEBUG_PRINT_LOW("Extradata SEI of size %u found, " + "parsing it", (unsigned int)extra_data->nDataSize); + parse_sei(extra_data->data, extra_data->nDataSize); + } else if (extra_data->eType == VEN_EXTRADATA_QCOMFILLER) { + DEBUG_PRINT_LOW("Extradata Qcom Filler found, skip %u bytes", + (unsigned int)extra_data->nSize); + } else if (extra_data->eType == VEN_EXTRADATA_SLICEINFO) { + DEBUG_PRINT_LOW("Extradata SliceInfo of size %u found, " + "parsing it", (unsigned int)extra_data->nDataSize); + parse_sliceinfo(buf_hdr, extra_data); + } + +#ifndef _MSM8974_ + else if (extra_data->eType == VEN_EXTRADATA_LTRINFO) { + DEBUG_PRINT_LOW("Extradata LTRInfo of size %d found, " + "parsing it", extra_data->nDataSize); + parse_ltrinfo(extra_data); + } + +#endif + else { + DEBUG_PRINT_ERROR("Unknown extradata(%p) found, nSize = 0x%x, " + "eType = 0x%x, nDataSize = 0x%x", extra_data, + (unsigned int)extra_data->nSize, extra_data->eType, (unsigned int)extra_data->nDataSize); + buf_hdr->nFlags &= ~(OMX_BUFFERFLAG_EXTRADATA); + break; + } + + extra_data = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) extra_data) + + extra_data->nSize); + } + } + + return 1; +} + +OMX_U32 extra_data_handler::get_frame_pack_data( + OMX_QCOM_FRAME_PACK_ARRANGEMENT *frame_pack) +{ + DEBUG_PRINT_LOW("%s:%d get frame data", __func__, __LINE__); + memcpy(&frame_pack->id,&frame_packing_arrangement.id, + FRAME_PACK_SIZE*sizeof(OMX_U32)); + return 1; +} + +OMX_U32 extra_data_handler::set_frame_pack_data(OMX_QCOM_FRAME_PACK_ARRANGEMENT + *frame_pack) +{ + DEBUG_PRINT_LOW("%s:%d set frame data", __func__, __LINE__); + memcpy(&frame_packing_arrangement.id, &frame_pack->id, + FRAME_PACK_SIZE*sizeof(OMX_U32)); + pack_sei = true; + sei_payload_type = SEI_PAYLOAD_FRAME_PACKING_ARRANGEMENT; + return 1; +} + +OMX_U32 extra_data_handler::e_u(OMX_U32 symbol, OMX_U32 num_bits) +{ + OMX_U32 rem_bits = num_bits, shift; + + DEBUG_PRINT_LOW("%s bin : %x/%u", __func__, (unsigned)symbol, (unsigned int)num_bits); + + while (rem_bits >= bit_ptr) { + shift = rem_bits - bit_ptr; + rbsp_buf[byte_ptr] |= (symbol >> shift); + symbol = (symbol << (32 - shift)) >> (32 - shift); + rem_bits -= bit_ptr; + DEBUG_PRINT_LOW("%sstream byte/rem_bits %x/%u", __func__, + (unsigned)rbsp_buf[byte_ptr], (unsigned int)rem_bits); + byte_ptr ++; + bit_ptr = 8; + } + + if (rem_bits) { + shift = bit_ptr - rem_bits; + rbsp_buf[byte_ptr] |= (symbol << shift); + bit_ptr -= rem_bits; + DEBUG_PRINT_LOW("%s 2 stream byte/rem_bits %x/%u", __func__, + (unsigned)rbsp_buf[byte_ptr], (unsigned int)rem_bits); + + if (bit_ptr == 0) { + bit_ptr = 8; + byte_ptr++; + } + } + + return 1; +} + +OMX_U32 extra_data_handler::e_ue(OMX_U32 symbol) +{ + OMX_U32 i, sym_len, sufix_len, info; + OMX_U32 nn =(symbol + 1) >> 1; + + DEBUG_PRINT_LOW("%s bin : %x", __func__, (unsigned)symbol); + + for (i=0; i < 33 && nn != 0; i++) + nn >>= 1; + + sym_len = ((i << 1) + 1); + info = symbol + 1 - (1 << i); + sufix_len = (1 << (sym_len >>1)); + info = sufix_len | (info & (sufix_len - 1)); + e_u(info, sym_len); + return 1; +} + +OMX_U32 extra_data_handler::create_frame_pack() +{ + e_ue(frame_packing_arrangement.id); + e_u(frame_packing_arrangement.cancel_flag, 1); + + if (!frame_packing_arrangement.cancel_flag) { + e_u(frame_packing_arrangement.type, 7); + e_u(frame_packing_arrangement.quincunx_sampling_flag, 1); + e_u(frame_packing_arrangement.content_interpretation_type, 6); + e_u(frame_packing_arrangement.spatial_flipping_flag, 1); + e_u(frame_packing_arrangement.frame0_flipped_flag, 1); + e_u(frame_packing_arrangement.field_views_flag, 1); + e_u(frame_packing_arrangement.current_frame_is_frame0_flag, 1); + e_u(frame_packing_arrangement.frame0_self_contained_flag, 1); + e_u(frame_packing_arrangement.frame1_self_contained_flag, 1); + + if (!frame_packing_arrangement.quincunx_sampling_flag && + frame_packing_arrangement.type != 5) { + e_u(frame_packing_arrangement.frame0_grid_position_x, 4); + e_u(frame_packing_arrangement.frame0_grid_position_y, 4); + e_u(frame_packing_arrangement.frame1_grid_position_x, 4); + e_u(frame_packing_arrangement.frame1_grid_position_y, 4); + } + + e_u(frame_packing_arrangement.reserved_byte, 8); + e_ue(frame_packing_arrangement.repetition_period); + } + + e_u(frame_packing_arrangement.extension_flag, 1); + return 1; +} + +OMX_S32 extra_data_handler::create_rbsp(OMX_U8 *buf, OMX_U32 nalu_type) +{ + OMX_U32 i, j = 7; + + for (i = 0; i < 3; i++) + *buf++ = 0x00; + + *buf++ = H264_START_CODE; + *buf++ = nalu_type; + *buf++ = (sei_payload_type & 0x000000FF); + *buf++ = byte_ptr - 1; //payload will contain 1 byte of rbsp_trailing_bits + //that shouldn't be taken into account + + for (i = 0; i < byte_ptr ; i += 2) { + *buf++ = rbsp_buf[i]; + j++; + + if (i+1 < byte_ptr) { + *buf++ = rbsp_buf[i+1]; + j++; + + if (!(rbsp_buf[i] + rbsp_buf[i+1])) { + *buf++ = H264_EMULATION_BYTE; + j++; + } + } + } + + DEBUG_PRINT_LOW("%s rbsp length %u", __func__, (unsigned int)j); + return j; +} + +OMX_U32 extra_data_handler::create_sei(OMX_U8 *buffer) +{ + OMX_U32 i, ret_val = 0; + + byte_ptr = 0; + bit_ptr = 8; + + if (sei_payload_type == SEI_PAYLOAD_FRAME_PACKING_ARRANGEMENT) { + create_frame_pack(); + + if (bit_ptr != 8) { + e_u(1,1); + + if (bit_ptr != 8) + e_u(0,bit_ptr); + } + + //Payload will have been byte aligned by now, + //insert the rbsp trailing bits + e_u(1, 1); + e_u(0, 7); + + ret_val = create_rbsp(buffer, NAL_TYPE_SEI); + } + + pack_sei = false; + sei_payload_type = -1; + + return ret_val; +} + +OMX_U32 extra_data_handler::create_extra_data(OMX_BUFFERHEADERTYPE *buf_hdr) +{ + OMX_U8 *buffer = (OMX_U8 *) (buf_hdr->pBuffer + + buf_hdr->nOffset + buf_hdr->nFilledLen); + OMX_U32 msg_size; + + if (buf_hdr->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { + DEBUG_PRINT_LOW("%s:%d create extra data with config", __func__, + __LINE__); + + if (pack_sei) { + msg_size = create_sei(buffer); + + if ( msg_size > 0) + buf_hdr->nFilledLen += msg_size; + } + } + + return 1; +} + diff --git a/msm8998/mm-video-v4l2/vidc/common/src/vidc_color_converter.cpp b/msm8998/mm-video-v4l2/vidc/common/src/vidc_color_converter.cpp new file mode 100644 index 0000000..413b27b --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/common/src/vidc_color_converter.cpp @@ -0,0 +1,189 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2012-2013, 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. +--------------------------------------------------------------------------*/ +#define LOG_TAG "OMX_C2D" + +#include <utils/Log.h> +#include <gralloc_priv.h> +#include "vidc_color_converter.h" +#include "vidc_debug.h" + +omx_c2d_conv::omx_c2d_conv() +{ + c2dcc = NULL; + mLibHandle = NULL; + mConvertOpen = NULL; + mConvertClose = NULL; + src_format = NV12_2K; +} + +bool omx_c2d_conv::init() +{ + bool status = true; + + if (mLibHandle || mConvertOpen || mConvertClose) { + DEBUG_PRINT_ERROR("omx_c2d_conv::init called twice"); + status = false; + } + + if (status) { + mLibHandle = dlopen("libc2dcolorconvert.so", RTLD_LAZY); + + if (mLibHandle) { + mConvertOpen = (createC2DColorConverter_t *) + dlsym(mLibHandle,"createC2DColorConverter"); + mConvertClose = (destroyC2DColorConverter_t *) + dlsym(mLibHandle,"destroyC2DColorConverter"); + + if (!mConvertOpen || !mConvertClose) + status = false; + } else + status = false; + } + + if (!status && mLibHandle) { + dlclose(mLibHandle); + mLibHandle = NULL; + mConvertOpen = NULL; + mConvertClose = NULL; + } + + return status; +} + +bool omx_c2d_conv::convert(int src_fd, void *src_base, void *src_viraddr, + int dest_fd, void *dest_base, void *dest_viraddr) +{ + int result; + + if (!src_viraddr || !dest_viraddr || !c2dcc || !dest_base || !src_base) { + DEBUG_PRINT_ERROR("Invalid arguments omx_c2d_conv::convert"); + return false; + } + + result = c2dcc->convertC2D(src_fd, src_base, src_viraddr, + dest_fd, dest_base, dest_viraddr); + DEBUG_PRINT_LOW("Color convert status %d",result); + return ((result < 0)?false:true); +} + +bool omx_c2d_conv::open(unsigned int height,unsigned int width, + ColorConvertFormat src, ColorConvertFormat dest) +{ + bool status = false; + + if (!c2dcc) { + c2dcc = mConvertOpen(width, height, width, height, + src,dest,0,0); + + if (c2dcc) { + src_format = src; + status = true; + } else + DEBUG_PRINT_ERROR("mConvertOpen failed"); + } + + return status; +} +void omx_c2d_conv::close() +{ + if (mLibHandle) { + if (mConvertClose && c2dcc) + mConvertClose(c2dcc); + + c2dcc = NULL; + } +} + +void omx_c2d_conv::destroy() +{ + DEBUG_PRINT_HIGH("Destroy C2D instance"); + + if (mLibHandle) { + if (mConvertClose && c2dcc) + mConvertClose(c2dcc); + + dlclose(mLibHandle); + } + + c2dcc = NULL; + mLibHandle = NULL; + mConvertOpen = NULL; + mConvertClose = NULL; +} +omx_c2d_conv::~omx_c2d_conv() +{ + destroy(); +} +int omx_c2d_conv::get_src_format() +{ + int format = -1; + + if (src_format == NV12_2K) { + format = HAL_PIXEL_FORMAT_NV12_ENCODEABLE; + } else if (src_format == RGBA8888) { + format = HAL_PIXEL_FORMAT_RGBA_8888; + } + + return format; +} +bool omx_c2d_conv::get_buffer_size(int port,unsigned int &buf_size) +{ + int cret = 0; + bool ret = false; + C2DBuffReq bufferreq; + + if (c2dcc) { + bufferreq.size = 0; + cret = c2dcc->getBuffReq(port,&bufferreq); + DEBUG_PRINT_LOW("Status of getbuffer is %d", cret); + ret = (cret)?false:true; + buf_size = bufferreq.size; + } + + return ret; +} + +bool omx_c2d_conv::get_output_filled_length(unsigned int &filled_length) +{ + bool ret = false; + C2DBuffReq req; + filled_length = 0; + + if (c2dcc) { + int cret = c2dcc->getBuffReq(C2D_OUTPUT, &req); + DEBUG_PRINT_LOW("Status of getBuffReq is %d", cret); + if (!cret && (req.bpp.denominator > 0)) { + filled_length = (req.stride * req.sliceHeight * req.bpp.numerator); + filled_length /= req.bpp.denominator; + ret = true; + } + } + + return ret; +} diff --git a/msm8998/mm-video-v4l2/vidc/vdec/Android.mk b/msm8998/mm-video-v4l2/vidc/vdec/Android.mk new file mode 100644 index 0000000..287bba7 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/Android.mk @@ -0,0 +1,161 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# --------------------------------------------------------------------------------- +# Common definitons +# --------------------------------------------------------------------------------- + +libmm-vdec-def := -D__alignx\(x\)=__attribute__\(\(__aligned__\(x\)\)\) +libmm-vdec-def += -D__align=__alignx +libmm-vdec-def += -Dinline=__inline +libmm-vdec-def += -g -O3 +libmm-vdec-def += -DIMAGE_APPS_PROC +libmm-vdec-def += -D_ANDROID_ +libmm-vdec-def += -DCDECL +libmm-vdec-def += -DT_ARM +libmm-vdec-def += -DNO_ARM_CLZ +libmm-vdec-def += -UENABLE_DEBUG_LOW +libmm-vdec-def += -UENABLE_DEBUG_HIGH +libmm-vdec-def += -DENABLE_DEBUG_ERROR +libmm-vdec-def += -UINPUT_BUFFER_LOG +libmm-vdec-def += -UOUTPUT_BUFFER_LOG +libmm-vdec-def += -Wno-parentheses +libmm-vdec-def += -D_ANDROID_ICS_ +libmm-vdec-def += -D_MSM8974_ +libmm-vdec-def += -DPROCESS_EXTRADATA_IN_OUTPUT_PORT +libmm-vdec-def += -DMAX_RES_1080P +libmm-vdec-def += -DMAX_RES_1080P_EBI + +TARGETS_THAT_USE_HEVC_ADSP_HEAP := msm8226 msm8974 +TARGETS_THAT_HAVE_VENUS_HEVC := apq8084 msm8994 msm8996 +TARGETS_THAT_SUPPORT_UBWC := msm8996 msm8953 msmcobalt +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_ +endif + +ifeq ($(call is-board-platform-in-list, $(TARGETS_THAT_HAVE_VENUS_HEVC)),true) +libmm-vdec-def += -DVENUS_HEVC +endif + +ifeq ($(TARGET_BOARD_PLATFORM),msm8610) +libmm-vdec-def += -DSMOOTH_STREAMING_DISABLED +libmm-vdec-def += -DH264_PROFILE_LEVEL_CHECK +endif + +ifeq ($(call is-board-platform-in-list, $(TARGETS_THAT_SUPPORT_UBWC)),true) +libmm-vdec-def += -D_UBWC_ +endif + +ifeq ($(TARGET_USES_ION),true) +libmm-vdec-def += -DUSE_ION +endif + +ifneq (1,$(filter 1,$(shell echo "$$(( $(PLATFORM_SDK_VERSION) >= 18 ))" ))) +libmm-vdec-def += -DANDROID_JELLYBEAN_MR1=1 +endif + +ifeq ($(call is-board-platform-in-list, $(MASTER_SIDE_CP_TARGET_LIST)),true) +libmm-vdec-def += -DMASTER_SIDE_CP +endif + +include $(CLEAR_VARS) + +# Common Includes +libmm-vdec-inc := $(LOCAL_PATH)/inc +libmm-vdec-inc += $(QCOM_MEDIA_ROOT)/mm-video-v4l2/vidc/common/inc +libmm-vdec-inc += $(QCOM_MEDIA_ROOT)/mm-core/inc +libmm-vdec-inc += $(TARGET_OUT_HEADERS)/qcom/display +libmm-vdec-inc += $(TARGET_OUT_HEADERS)/adreno +libmm-vdec-inc += $(TOP)/frameworks/native/include/media/openmax +libmm-vdec-inc += $(TOP)/frameworks/native/include/media/hardware +libmm-vdec-inc += $(QCOM_MEDIA_ROOT)/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 +ifeq ($(TARGET_COMPILE_WITH_MSM_KERNEL),true) +libmm-vdec-inc += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +endif + +ifeq ($(PLATFORM_SDK_VERSION), 18) #JB_MR2 +libmm-vdec-def += -DANDROID_JELLYBEAN_MR2=1 +libmm-vdec-inc += $(QCOM_MEDIA_ROOT)/libstagefrighthw +endif + +ifeq ($(TARGET_COMPILE_WITH_MSM_KERNEL),true) +# Common Dependencies +libmm-vdec-add-dep := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +endif + +ifeq ($(call is-platform-sdk-version-at-least, 19),true) +# This feature is enabled for Android KK+ +libmm-vdec-def += -DADAPTIVE_PLAYBACK_SUPPORTED +endif + +ifeq ($(call is-platform-sdk-version-at-least, 22),true) +# This feature is enabled for Android LMR1 +libmm-vdec-def += -DFLEXYUV_SUPPORTED +endif + +ifeq ($(TARGET_USES_MEDIA_EXTENSIONS),true) +libmm-vdec-def += -DALLOCATE_OUTPUT_NATIVEHANDLE +endif + +# --------------------------------------------------------------------------------- +# Make the Shared library (libOmxVdec) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +LOCAL_MODULE := libOmxVdec +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libmm-vdec-def) -Werror +LOCAL_C_INCLUDES += $(libmm-vdec-inc) +LOCAL_ADDITIONAL_DEPENDENCIES := $(libmm-vdec-add-dep) + +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := liblog libutils libbinder libcutils libdl + +LOCAL_SHARED_LIBRARIES += libqdMetaData + +LOCAL_SRC_FILES := src/frameparser.cpp +LOCAL_SRC_FILES += src/h264_utils.cpp +LOCAL_SRC_FILES += src/ts_parser.cpp +LOCAL_SRC_FILES += src/mp4_utils.cpp +LOCAL_SRC_FILES += src/hevc_utils.cpp +LOCAL_STATIC_LIBRARIES := libOmxVidcCommon +LOCAL_SRC_FILES += src/omx_vdec_v4l2.cpp + +include $(BUILD_SHARED_LIBRARY) + + + +# --------------------------------------------------------------------------------- +# 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 + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- diff --git a/msm8998/mm-video-v4l2/vidc/vdec/Makefile.am b/msm8998/mm-video-v4l2/vidc/vdec/Makefile.am new file mode 100644 index 0000000..b80e6d2 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/Makefile.am @@ -0,0 +1,86 @@ +AM_CFLAGS = -Wall +AM_CFLAGS += -Wundef +AM_CFLAGS += -Wstrict-prototypes +AM_CFLAGS += -Wno-trigraphs +AM_CFLAGS += -g -O3 + +AM_CPPFLAGS := -D__alignx\(x\)=__attribute__\(\(__aligned__\(x\)\)\) +AM_CPPFLAGS += -D__align=__alignx +AM_CPPFLAGS += -Dinline=__inline +AM_CPPFLAGS += -DIMAGE_APPS_PROC +AM_CPPFLAGS += -DCDECL +AM_CPPFLAGS += -DT_ARM +AM_CPPFLAGS += -DNO_ARM_CLZ +AM_CPPFLAGS += -UENABLE_DEBUG_LOW +AM_CPPFLAGS += -DENABLE_DEBUG_HIGH +AM_CPPFLAGS += -DENABLE_DEBUG_ERROR +AM_CPPFLAGS += -UINPUT_BUFFER_LOG +AM_CPPFLAGS += -UOUTPUT_BUFFER_LOG +AM_CPPFLAGS += -Wno-parentheses +AM_CPPFLAGS += -D_ANDROID_ICS_ +AM_CPPFLAGS += -D_MSM8974_ +AM_CPPFLAGS += -DPROCESS_EXTRADATA_IN_OUTPUT_PORT +AM_CPPFLAGS += -DMAX_RES_1080P +AM_CPPFLAGS += -DMAX_RES_1080P_EBI + +if TARGET_MSM8960 +AM_CPPFLAGS += -DMAX_RES_1080P +AM_CPPFLAGS += -DMAX_RES_1080P_EBI +AM_CPPFLAGS += -DPROCESS_EXTRADATA_IN_OUTPUT_PORT +AM_CPPFLAGS += -DUSE_ION +endif + +if TARGET_B_FAMILY +AM_CPPFLAGS += -DMAX_RES_1080P +AM_CPPFLAGS += -DMAX_RES_1080P_EBI +AM_CPPFLAGS += -DPROCESS_EXTRADATA_IN_OUTPUT_PORT +AM_CPPFLAGS += -DUSE_ION +AM_CPPFLAGS += -D_MSM8974_ +#AM_CPPFLAGS += -D_HEVC_USE_ADSP_HEAP_ +endif + +AM_CPPFLAGS += -I./inc +AM_CPPFLAGS += -I../common/inc +AM_CPPFLAGS += -I../../../libc2dcolorconvert +AM_CPPFLAGS += -I../../../mm-core/inc +AM_CPPFLAGS += -I../../../mm-core/src/common + +c_sources = src/frameparser.cpp +c_sources += src/h264_utils.cpp +c_sources += src/ts_parser.cpp +c_sources += src/mp4_utils.cpp + +if TARGET_MSM8960 +c_sources += src/omx_vdec.cpp +endif + +if TARGET_B_FAMILY +c_sources += src/omx_vdec_msm8974.cpp +endif + +c_sources += ../common/src/extra_data_handler.cpp +c_sources += ../common/src/vidc_color_converter.cpp + +lib_LTLIBRARIES = libOmxVdec.la +libOmxVdec_la_SOURCES = $(c_sources) +libOmxVdec_la_CFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS) -fPIC +libOmxVdec_la_CFLAGS += ../libc2d2colorconvert/libc2dcolorconvert.la +libOmxVdec_la_LDFLAGS = -shared -version-info $(OMXVIDEO_LIBRARY_VERSION) + +bin_PROGRAMS = mm-vdec-omx-test + +mm_vdec_omx_test_CPPFLAGS = -I./inc +mm_vdec_omx_test_CPPFLAGS += -I../../../mm-core/inc +mm_vdec_omx_test_CPPFLAGS += -I../common/inc +mm_vdec_omx_test_CPPFLAGS += -DUSE_ION +mm_vdec_omx_test_CPPFLAGS += -D_NOFBMEM_ + +if TARGET_B_FAMILY +mm_vdec_omx_test_CPPFLAGS += -D_MSM8974_ +endif + +mm_vdec_omx_test_SOURCES := src/queue.c +mm_vdec_omx_test_SOURCES += test/omx_vdec_test.cpp +mm_vdec_omx_test_LDADD = -ldl -lpthread -lOmxCore +mm_vdec_omx_test_LDADD += ./libOmxVdec.la + diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/Map.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/Map.h new file mode 100644 index 0000000..a222eb2 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/Map.h @@ -0,0 +1,244 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2011, 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#ifndef _MAP_H_ +#define _MAP_H_ + +#include <stdio.h> + +template <typename T,typename T2> +class Map +{ + struct node { + T data; + T2 data2; + node* prev; + node* next; + node(T t, T2 t2,node* p, node* n) : + data(t), data2(t2), prev(p), next(n) {} + }; + node* head; + node* tail; + node* tmp; + unsigned size_of_list; + static Map<T,T2> *m_self; + public: + Map() : head( NULL ), tail ( NULL ),tmp(head),size_of_list(0) {} + bool empty() const { + return ( !head || !tail ); + } + operator bool() const { + return !empty(); + } + void insert(T,T2); + void show(); + int size(); + T2 find(T); // Return VALUE + T find_ele(T);// Check if the KEY is present or not + T2 begin(); //give the first ele + bool erase(T); + bool eraseall(); + bool isempty(); + ~Map() { + while (head) { + node* temp(head); + head=head->next; + size_of_list--; + delete temp; + } + } +}; + + template <typename T,typename T2> +T2 Map<T,T2>::find(T d1) +{ + tmp = head; + + while (tmp) { + if (tmp->data == d1) { + return tmp->data2; + } + + tmp = tmp->next; + } + + return 0; +} + + template <typename T,typename T2> +T Map<T,T2>::find_ele(T d1) +{ + tmp = head; + + while (tmp) { + if (tmp->data == d1) { + return tmp->data; + } + + tmp = tmp->next; + } + + return 0; +} + + template <typename T,typename T2> +T2 Map<T,T2>::begin() +{ + tmp = head; + + if (tmp) { + return (tmp->data2); + } + + return 0; +} + + template <typename T,typename T2> +void Map<T,T2>::show() +{ + tmp = head; + + while (tmp) { + printf("%d-->%d\n",tmp->data,tmp->data2); + tmp = tmp->next; + } +} + + template <typename T,typename T2> +int Map<T,T2>::size() +{ + int count =0; + tmp = head; + + while (tmp) { + tmp = tmp->next; + count++; + } + + return count; +} + + template <typename T,typename T2> +void Map<T,T2>::insert(T data, T2 data2) +{ + tail = new node(data, data2,tail, NULL); + + if ( tail->prev ) + tail->prev->next = tail; + + if ( empty() ) { + head = tail; + tmp=head; + } + + tmp = head; + size_of_list++; +} + + template <typename T,typename T2> +bool Map<T,T2>::erase(T d) +{ + bool found = false; + tmp = head; + node* prevnode = tmp; + node *tempnode; + + while (tmp) { + if ((head == tail) && (head->data == d)) { + found = true; + tempnode = head; + head = tail = NULL; + delete tempnode; + break; + } + + if ((tmp ==head) && (tmp->data ==d)) { + found = true; + tempnode = tmp; + tmp = tmp->next; + tmp->prev = NULL; + head = tmp; + tempnode->next = NULL; + delete tempnode; + break; + } + + if ((tmp == tail) && (tmp->data ==d)) { + found = true; + tempnode = tmp; + prevnode->next = NULL; + tmp->prev = NULL; + tail = prevnode; + delete tempnode; + break; + } + + if (tmp->data == d) { + found = true; + prevnode->next = tmp->next; + tmp->next->prev = prevnode->next; + tempnode = tmp; + //tmp = tmp->next; + delete tempnode; + break; + } + + prevnode = tmp; + tmp = tmp->next; + } + + if (found)size_of_list--; + + return found; +} + + template <typename T,typename T2> +bool Map<T,T2>::eraseall() +{ + node *tempnode; + tmp = head; + + while (head) { + tempnode = head; + tempnode->next = NULL; + head = head->next; + delete tempnode; + } + + tail = head = NULL; + return true; +} + + + template <typename T,typename T2> +bool Map<T,T2>::isempty() +{ + if (!size_of_list) return true; + else return false; +} + +#endif // _MAP_H_ diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/decoder_driver_test.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/decoder_driver_test.h new file mode 100644 index 0000000..cc42fc1 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/decoder_driver_test.h @@ -0,0 +1,69 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2011,2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#include <stdio.h> +#include <stdlib.h> +#include "message_queue.h" +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <inttypes.h> +#include <linux/msm_vidc_dec.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> + +struct video_decoder_context { + enum vdec_codec decoder_format; + enum vdec_output_fromat output_format; + struct vdec_picsize video_resoultion; + struct vdec_allocatorproperty input_buffer; + struct vdec_allocatorproperty output_buffer; + struct vdec_bufferpayload **ptr_inputbuffer; + struct vdec_bufferpayload **ptr_outputbuffer; + struct vdec_output_frameinfo **ptr_respbuffer; + struct video_queue_context queue_context; + int video_driver_fd; + + FILE * inputBufferFile; + FILE * outputBufferFile; + + pthread_t videothread_id; + pthread_t asyncthread_id; + sem_t sem_synchronize; +}; + +int init_decoder ( struct video_decoder_context *init_decode ); +int allocate_buffer ( enum vdec_buffer, + struct video_decoder_context *decode_context + ); +int free_buffer ( enum vdec_buffer, + struct video_decoder_context *decode_context + ); +int start_decoding (struct video_decoder_context *decode_context); +int stop_decoding (struct video_decoder_context *decode_context); +int deinit_decoder (struct video_decoder_context *init_decode); diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/frameparser.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/frameparser.h new file mode 100644 index 0000000..916390a --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/frameparser.h @@ -0,0 +1,103 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#ifndef FRAMEPARSER_H +#define FRAMEPARSER_H + +#include "OMX_Core.h" +#include "OMX_QCOMExtns.h" +#include "h264_utils.h" +//#include <stdlib.h> + +enum codec_type { + CODEC_TYPE_MPEG4 = 0, + CODEC_TYPE_DIVX = 0, + CODEC_TYPE_H263 = 1, + CODEC_TYPE_H264 = 2, + CODEC_TYPE_VC1 = 3, + CODEC_TYPE_MPEG2 = 4, +#ifdef _MSM8974_ + CODEC_TYPE_VP8 = 5, + CODEC_TYPE_VP9 = 5, + CODEC_TYPE_HEVC, +#endif + CODEC_TYPE_MAX +}; + +enum state_start_code_parse { + A0, + A1, + A2, + A3, + A4, + A5 +}; + +enum state_nal_parse { + NAL_LENGTH_ACC, + NAL_PARSING +}; + +class frame_parse +{ + + public: + H264_Utils *mutils; + int init_start_codes (codec_type codec_type_parse); + int parse_sc_frame (OMX_BUFFERHEADERTYPE *source, + OMX_BUFFERHEADERTYPE *dest , + OMX_U32 *partialframe); + int init_nal_length (unsigned int nal_length); + int parse_h264_nallength (OMX_BUFFERHEADERTYPE *source, + OMX_BUFFERHEADERTYPE *dest , + OMX_U32 *partialframe); + void flush (); + frame_parse (); + ~frame_parse (); + + private: + /*Variables for Start code based Parsing*/ + enum state_start_code_parse parse_state; + unsigned char *start_code; + unsigned char *mask_code; + unsigned char last_byte_h263; + unsigned char last_byte; + bool header_found; + bool skip_frame_boundary; + + /*Variables for NAL Length Parsing*/ + enum state_nal_parse state_nal; + unsigned int nal_length; + unsigned int accum_length; + unsigned int bytes_tobeparsed; + /*Functions to support additional start code parsing*/ + void parse_additional_start_code(OMX_U8 *psource, OMX_U32 *parsed_length); + void check_skip_frame_boundary(OMX_U32 *partial_frame); + void update_skip_frame(); +}; + +#endif /* FRAMEPARSER_H */ diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/h264_utils.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/h264_utils.h new file mode 100644 index 0000000..ad05a9e --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/h264_utils.h @@ -0,0 +1,480 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#ifndef H264_UTILS_H +#define H264_UTILS_H + +/*======================================================================== + + O p e n M M + U t i l i t i e s a n d H e l p e r R o u t i n e s + +*//** @file H264_Utils.h +This module contains H264 video decoder utilities and helper routines. + +*//*====================================================================== */ + +/* ======================================================================= + + INCLUDE FILES FOR MODULE + +========================================================================== */ +#include <stdio.h> +#include "Map.h" +#include "qtypes.h" +#include "OMX_Core.h" +#include "OMX_QCOMExtns.h" + +#define STD_MIN(x,y) (((x) < (y)) ? (x) : (y)) + +#define OMX_CORE_720P_HEIGHT 720 +#define OMX_CORE_720P_WIDTH 1280 + +#define SIZE_NAL_FIELD_MAX 4 +#define BASELINE_PROFILE 66 +#define MAIN_PROFILE 77 +#define HIGH_PROFILE 100 + +#define PANSCAN_HDLR + +/* ======================================================================= + + DATA DECLARATIONS + + ========================================================================== */ + +/* ----------------------------------------------------------------------- + ** Constant / Define Declarations + ** ----------------------------------------------------------------------- */ +// Common format block header definitions +#define MT_VIDEO_META_STREAM_HEADER 0x00 +#define MT_VIDEO_MEDIA_STREAM_HEADER 0x01 +#define MT_VIDEO_META_MEDIA_STREAM_HEADER 0x02 + +// H.264 format block header definitions +#define MT_VIDEO_H264_ACCESS_UNIT_FORMAT 0x00 +#define MT_VIDEO_H264_NAL_FORMT 0x01 +#define MT_VIDEO_H264_BYTE_FORMAT 0x02 +#define MT_VIDEO_H264_BYTE_STREAM_FORMAT 0x00 +#define MT_VIDEO_H264_NAL_UNIT_STREAM_FORMAT 0x01 +#define MT_VIDEO_H264_FORMAT_BLOCK_HEADER_SIZE 18 + +// MPEG-4 format block header definitions +#define MT_VIDEO_MPEG4_VOP_FORMAT 0x00 +#define MT_VIDEO_MPEG4_SLICE_FORMAT 0x01 +#define MT_VIDEO_MPEG4_BYTE_FORMAT 0x02 +#define MT_VIDEO_MPEG4_FORMAT_BLOCK_HEADER_SIZE 15 + +// H.263 format block header definitions +#define MT_VIDEO_H263_PICTURE_FORMAT 0x00 +#define MT_VIDEO_H263_GOB_FORMAT 0x01 +#define MT_VIDEO_H263_SLICE_STRUCTURED_FORMAT 0x02 +#define MT_VIDEO_H263_BYTE_FORMAT 0x03 +#define MT_VIDEO_H263_FORMAT_BLOCK_HEADER_SIZE 16 + +/* ======================================================================= + ** Function Declarations + ** ======================================================================= */ + +/* ----------------------------------------------------------------------- + ** Type Declarations + ** ----------------------------------------------------------------------- */ + +// This type is used when parsing an H.264 bitstream to collect H.264 NAL +// units that need to go in the meta data. +struct H264ParamNalu { + uint32 picSetID; + uint32 seqSetID; + uint32 picOrderCntType; + bool frameMbsOnlyFlag; + bool picOrderPresentFlag; + uint32 picWidthInMbsMinus1; + uint32 picHeightInMapUnitsMinus1; + uint32 log2MaxFrameNumMinus4; + uint32 log2MaxPicOrderCntLsbMinus4; + bool deltaPicOrderAlwaysZeroFlag; + //std::vector<uint8> nalu; + uint32 nalu; + uint32 crop_left; + uint32 crop_right; + uint32 crop_top; + uint32 crop_bot; +}; +//typedef map<uint32, H264ParamNalu> H264ParamNaluSet; +typedef Map<uint32, H264ParamNalu *> H264ParamNaluSet; + +typedef enum { + NALU_TYPE_UNSPECIFIED = 0, + NALU_TYPE_NON_IDR, + NALU_TYPE_PARTITION_A, + NALU_TYPE_PARTITION_B, + NALU_TYPE_PARTITION_C, + NALU_TYPE_IDR, + NALU_TYPE_SEI, + NALU_TYPE_SPS, + NALU_TYPE_PPS, + NALU_TYPE_ACCESS_DELIM, + NALU_TYPE_EOSEQ, + NALU_TYPE_EOSTREAM, + NALU_TYPE_FILLER_DATA, + NALU_TYPE_RESERVED, +} NALU_TYPE; + +// NAL header information +typedef struct { + uint32 nal_ref_idc; + uint32 nalu_type; + uint32 forbidden_zero_bit; +} NALU; + +// This structure contains persistent information about an H.264 stream as it +// is parsed. +//struct H264StreamInfo { +// H264ParamNaluSet pic; +// H264ParamNaluSet seq; +//}; + +class extra_data_parser; + +class RbspParser +/****************************************************************************** + ** This class is used to convert an H.264 NALU (network abstraction layer + ** unit) into RBSP (raw byte sequence payload) and extract bits from it. + *****************************************************************************/ +{ + public: + RbspParser (const uint8 *begin, const uint8 *end); + + virtual ~RbspParser (); + + uint32 next (); + void advance (); + uint32 u (uint32 n); + uint32 ue (); + int32 se (); + + private: + const uint8 *begin, *end; + int32 pos; + uint32 bit; + uint32 cursor; + bool advanceNeeded; +}; + +class H264_Utils +{ + public: + H264_Utils(); + ~H264_Utils(); + void initialize_frame_checking_environment(); + void allocate_rbsp_buffer(uint32 inputBufferSize); + bool isNewFrame(OMX_BUFFERHEADERTYPE *p_buf_hdr, + OMX_IN OMX_U32 size_of_nal_length_field, + OMX_OUT OMX_BOOL &isNewFrame); + uint32 nalu_type; + + private: + boolean extract_rbsp(OMX_IN OMX_U8 *buffer, + OMX_IN OMX_U32 buffer_length, + OMX_IN OMX_U32 size_of_nal_length_field, + OMX_OUT OMX_U8 *rbsp_bistream, + OMX_OUT OMX_U32 *rbsp_length, + OMX_OUT NALU *nal_unit); + + unsigned m_height; + unsigned m_width; + H264ParamNaluSet pic; + H264ParamNaluSet seq; + uint8 *m_rbspBytes; + NALU m_prv_nalu; + bool m_forceToStichNextNAL; + bool m_au_data; +}; + +class perf_metrics +{ + public: + perf_metrics() : + start_time(0), + proc_time(0), + active(false) { + }; + ~perf_metrics() {}; + void start(); + void stop(); + void end(OMX_U32 units_cntr = 0); + void reset(); + OMX_U64 processing_time_us(); + private: + inline OMX_U64 get_act_time(); + OMX_U64 start_time; + OMX_U64 proc_time; + bool active; +}; + +#define EMULATION_PREVENTION_THREE_BYTE 0x03 +#define MAX_CPB_COUNT 32 +#define NO_PAN_SCAN_BIT 0x00000100 +#define MAX_PAN_SCAN_RECT 3 +#define VALID_TS(ts) ((ts < LLONG_MAX)? true : false) +#define NALU_TYPE_VUI (NALU_TYPE_RESERVED + 1) + +enum SEI_PAYLOAD_TYPE { + BUFFERING_PERIOD = 0, + PIC_TIMING, + PAN_SCAN_RECT, + FILLER_PAYLOAD, + USER_DATA_REGISTERED_ITU_T_T35, + USER_DATA_UNREGISTERED, + RECOVERY_POINT, + DEC_REF_PIC_MARKING_REPETITION, + SPARE_PIC, + SCENE_INFO, + SUB_SEQ_INFO, + SUB_SEQ_LAYER_CHARACTERISTICS, + SUB_SEQ_CHARACTERISTICS, + FULL_FRAME_FREEZE, + FULL_FRAME_FREEZE_RELEASE, + FULL_FRAME_SNAPSHOT, + PROGRESSIVE_REFINEMENT_SEGMENT_START, + PROGRESSIVE_REFINEMENT_SEGMENT_END, + SEI_PAYLOAD_FRAME_PACKING_ARRANGEMENT = 0x2D +}; + +typedef struct { + OMX_U32 cpb_cnt; + OMX_U8 bit_rate_scale; + OMX_U8 cpb_size_scale; + OMX_U32 bit_rate_value[MAX_CPB_COUNT]; + OMX_U32 cpb_size_value[MAX_CPB_COUNT]; + OMX_U8 cbr_flag[MAX_CPB_COUNT]; + OMX_U8 initial_cpb_removal_delay_length; + OMX_U8 cpb_removal_delay_length; + OMX_U8 dpb_output_delay_length; + OMX_U8 time_offset_length; +} h264_hrd_param; + +typedef struct { + OMX_U32 aspect_ratio_idc; + OMX_U32 aspect_ratio_x; + OMX_U32 aspect_ratio_y; +} h264_aspect_ratio_info; + +typedef struct { + OMX_U8 aspect_ratio_info_present_flag; + h264_aspect_ratio_info aspect_ratio_info; + OMX_U8 timing_info_present_flag; + OMX_U32 num_units_in_tick; + OMX_U32 time_scale; + OMX_U8 fixed_frame_rate_flag; + OMX_U8 nal_hrd_parameters_present_flag; + h264_hrd_param nal_hrd_parameters; + OMX_U8 vcl_hrd_parameters_present_flag; + h264_hrd_param vcl_hrd_parameters; + OMX_U8 low_delay_hrd_flag; + OMX_U8 pic_struct_present_flag; + OMX_S64 fixed_fps_prev_ts; +} h264_vui_param; + +typedef struct { + OMX_U32 cpb_removal_delay; + OMX_U32 dpb_output_delay; + OMX_U8 pic_struct; + OMX_U32 num_clock_ts; + bool clock_ts_flag; + OMX_U8 ct_type; + OMX_U32 nuit_field_based_flag; + OMX_U8 counting_type; + OMX_U8 full_timestamp_flag; + OMX_U8 discontinuity_flag; + OMX_U8 cnt_dropped_flag; + OMX_U32 n_frames; + OMX_U32 seconds_value; + OMX_U32 minutes_value; + OMX_U32 hours_value; + OMX_S32 time_offset; + bool is_valid; +} h264_sei_pic_timing; + +typedef struct { + OMX_U32 initial_cpb_removal_delay[MAX_CPB_COUNT]; + OMX_U32 initial_cpb_removal_delay_offset[MAX_CPB_COUNT]; + OMX_U32 au_cntr; + OMX_S64 reference_ts; + bool is_valid; +} h264_sei_buf_period; + +typedef struct { + OMX_U32 rect_id; + OMX_U8 rect_cancel_flag; + OMX_U32 cnt; + OMX_S32 rect_left_offset[MAX_PAN_SCAN_RECT]; + OMX_S32 rect_right_offset[MAX_PAN_SCAN_RECT]; + OMX_S32 rect_top_offset[MAX_PAN_SCAN_RECT]; + OMX_S32 rect_bottom_offset[MAX_PAN_SCAN_RECT]; + OMX_U32 rect_repetition_period; +} h264_pan_scan; + +#ifdef PANSCAN_HDLR +template <class NODE_STRUCT> +class omx_dl_list +{ + public: + omx_dl_list() { + head = tail = NULL; + } ; + ~omx_dl_list() {}; + void add_multiple(NODE_STRUCT *data_arr, int data_num); + NODE_STRUCT *remove_first(); + NODE_STRUCT *remove_last(); + void add_last(NODE_STRUCT *data_ptr); + NODE_STRUCT *watch_first(); + NODE_STRUCT *watch_last(); + private: + NODE_STRUCT *head, *tail; +}; + +class panscan_handler +{ + public: + panscan_handler(); + ~panscan_handler(); + bool initialize(int num_data); + h264_pan_scan *get_free(); + h264_pan_scan *get_populated(OMX_S64 frame_ts); + void update_last(OMX_S64 frame_ts); + private: + typedef struct PANSCAN_NODE { + h264_pan_scan pan_scan_param; + OMX_S64 start_ts, end_ts; + bool active; + PANSCAN_NODE *next, *prev; + } PANSCAN_NODE; + omx_dl_list<PANSCAN_NODE> panscan_used; + omx_dl_list<PANSCAN_NODE> panscan_free; + PANSCAN_NODE *panscan_data; +}; + +#if 1 // Debug panscan data + +#define PRINT_PANSCAN_PARAM(H264_PARAM) +#define PRINT_PANSCAN_DATA(NODE) + +#else + +#define PRINT_PANSCAN_PARAM(H264_PARAM) \ + do {\ + ALOGE("%s(): left_off(%ld) right_off(%ld) top_off(%ld) bottom_off(%ld)",\ + __FUNCTION__,\ + (H264_PARAM).rect_left_offset[0],\ + (H264_PARAM).rect_right_offset[0],\ + (H264_PARAM).rect_top_offset[0],\ + (H264_PARAM).rect_bottom_offset[0]);\ + }while(0) + +#define PRINT_PANSCAN_DATA(NODE) \ + do {\ + if (NODE) {\ + ALOGE("%s(): PANSCAN DATA start_ts(%lld) end_ts(%lld)", __FUNCTION__,\ + (NODE)->start_ts, (NODE)->end_ts);\ + PRINT_PANSCAN_PARAM(NODE->pan_scan_param);\ + }\ + }while(0) + +#endif // End debug panscan data + +#endif + +class h264_stream_parser +{ + public: + h264_stream_parser(); + ~h264_stream_parser(); + void reset(); + void fill_pan_scan_data(OMX_QCOM_PANSCAN *dest_pan_scan, OMX_S64 timestamp); + void fill_aspect_ratio_info(OMX_QCOM_ASPECT_RATIO *dest_aspect_ratio); + void parse_nal(OMX_U8* data_ptr, OMX_U32 data_len, + OMX_U32 nal_type = NALU_TYPE_UNSPECIFIED, + bool enable_emu_sc = true); + OMX_S64 process_ts_with_sei_vui(OMX_S64 timestamp); + void get_frame_pack_data(OMX_QCOM_FRAME_PACK_ARRANGEMENT *frame_pack); + bool is_mbaff(); + void get_frame_rate(OMX_U32 *frame_rate); + OMX_U32 get_profile(); +#ifdef PANSCAN_HDLR + void update_panscan_data(OMX_S64 timestamp); +#endif + + private: + void init_bitstream(OMX_U8* data, OMX_U32 size); + OMX_U32 extract_bits(OMX_U32 n); + inline bool more_bits(); + void read_word(); + OMX_U32 uev(); + OMX_S32 sev(); + OMX_S32 iv(OMX_U32 n_bits); + void parse_sps(); + void parse_vui(bool vui_in_extradata = true); + void aspect_ratio_info(); + void hrd_parameters(h264_hrd_param *hrd_param); + void parse_sei(); + void sei_buffering_period(); + void sei_picture_timing(); + void sei_pan_scan(); + void scaling_list(OMX_U32 size_of_scaling_list); + + void print_pan_data(h264_pan_scan *pan_scan_param); + void print_frame_pack(); + + OMX_U32 get_nal_unit_type(OMX_U32 *nal_unit_type); + OMX_S64 calculate_buf_period_ts(OMX_S64 timestamp); + OMX_S64 calculate_fixed_fps_ts(OMX_S64 timestamp, OMX_U32 DeltaTfiDivisor); + void parse_frame_pack(); + + OMX_U32 curr_32_bit; + OMX_U32 bits_read; + OMX_U32 profile; + OMX_U32 zero_cntr; + OMX_U32 emulation_code_skip_cntr; + OMX_U8* bitstream; + OMX_U32 bitstream_bytes; + OMX_U32 frame_rate; + bool emulation_sc_enabled; + + h264_vui_param vui_param; + h264_sei_buf_period sei_buf_period; + h264_sei_pic_timing sei_pic_timing; +#ifdef PANSCAN_HDLR + panscan_handler *panscan_hdl; +#else + h264_pan_scan panscan_param; +#endif + OMX_QCOM_FRAME_PACK_ARRANGEMENT frame_packing_arrangement; + bool mbaff_flag; +}; + +#endif /* H264_UTILS_H */ diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/hevc_utils.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/hevc_utils.h new file mode 100644 index 0000000..797d1d2 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/hevc_utils.h @@ -0,0 +1,146 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ + + +#ifndef HEVC_UTILS_H +#define HEVC_UTILS_H + +/*======================================================================== + + O p e n M M + U t i l i t i e s a n d H e l p e r R o u t i n e s + +*//** @file HEVC_Utils.h +This module contains H264 video decoder utilities and helper routines. + +*//*====================================================================== */ + +/* ======================================================================= + + INCLUDE FILES FOR MODULE + +========================================================================== */ +#include <stdio.h> +#include <utils/Log.h> +#include "Map.h" +#include "qtypes.h" +#include "OMX_Core.h" +#include "OMX_QCOMExtns.h" + + +class HEVC_Utils +{ + public: + HEVC_Utils(); + ~HEVC_Utils(); + + enum { + NAL_UNIT_CODED_SLICE_TRAIL_N, // 0 + NAL_UNIT_CODED_SLICE_TRAIL_R, // 1 + NAL_UNIT_CODED_SLICE_TSA_N, // 2 + NAL_UNIT_CODED_SLICE_TLA, // 3 + NAL_UNIT_CODED_SLICE_STSA_N, // 4 + NAL_UNIT_CODED_SLICE_STSA_R, // 5 + NAL_UNIT_CODED_SLICE_RADL_N, // 6 + NAL_UNIT_CODED_SLICE_DLP, // 7 + NAL_UNIT_CODED_SLICE_RASL_N, // 8 + NAL_UNIT_CODED_SLICE_TFD, // 9 + NAL_UNIT_RESERVED_10, + NAL_UNIT_RESERVED_11, + NAL_UNIT_RESERVED_12, + NAL_UNIT_RESERVED_13, + NAL_UNIT_RESERVED_14, + NAL_UNIT_RESERVED_15, + NAL_UNIT_CODED_SLICE_BLA, // 16 + NAL_UNIT_CODED_SLICE_BLANT, // 17 + NAL_UNIT_CODED_SLICE_BLA_N_LP, // 18 + NAL_UNIT_CODED_SLICE_IDR, // 19 + NAL_UNIT_CODED_SLICE_IDR_N_LP, // 20 + NAL_UNIT_CODED_SLICE_CRA, // 21 + NAL_UNIT_RESERVED_22, + NAL_UNIT_RESERVED_23, + NAL_UNIT_RESERVED_24, + NAL_UNIT_RESERVED_25, + NAL_UNIT_RESERVED_26, + NAL_UNIT_RESERVED_27, + + NAL_UNIT_RESERVED_28, + NAL_UNIT_RESERVED_29, + NAL_UNIT_RESERVED_30, + NAL_UNIT_RESERVED_31, + + NAL_UNIT_VPS, // 32 + NAL_UNIT_SPS, // 33 + NAL_UNIT_PPS, // 34 + NAL_UNIT_ACCESS_UNIT_DELIMITER, // 35 + NAL_UNIT_EOS, // 36 + NAL_UNIT_EOB, // 37 + NAL_UNIT_FILLER_DATA, // 38 + NAL_UNIT_SEI, // 39 Prefix SEI + NAL_UNIT_SEI_SUFFIX, // 40 Suffix SEI + + NAL_UNIT_RESERVED_41, + NAL_UNIT_RESERVED_42, + NAL_UNIT_RESERVED_43, + NAL_UNIT_RESERVED_44, + NAL_UNIT_RESERVED_45, + NAL_UNIT_RESERVED_46, + NAL_UNIT_RESERVED_47, + NAL_UNIT_UNSPECIFIED_48, + NAL_UNIT_UNSPECIFIED_49, + NAL_UNIT_UNSPECIFIED_50, + NAL_UNIT_UNSPECIFIED_51, + NAL_UNIT_UNSPECIFIED_52, + NAL_UNIT_UNSPECIFIED_53, + NAL_UNIT_UNSPECIFIED_54, + NAL_UNIT_UNSPECIFIED_55, + NAL_UNIT_UNSPECIFIED_56, + NAL_UNIT_UNSPECIFIED_57, + NAL_UNIT_UNSPECIFIED_58, + NAL_UNIT_UNSPECIFIED_59, + NAL_UNIT_UNSPECIFIED_60, + NAL_UNIT_UNSPECIFIED_61, + NAL_UNIT_UNSPECIFIED_62, + NAL_UNIT_UNSPECIFIED_63, + NAL_UNIT_INVALID, + }; + + + void initialize_frame_checking_environment(); + bool isNewFrame(OMX_BUFFERHEADERTYPE *p_buf_hdr, + OMX_IN OMX_U32 size_of_nal_length_field, + OMX_OUT OMX_BOOL &isNewFrame); + + private: + + bool m_forceToStichNextNAL; + bool m_au_data; + uint32 nalu_type; +}; + +#endif /* HEVC_UTILS_H */ diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/message_queue.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/message_queue.h new file mode 100644 index 0000000..7cae154 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/message_queue.h @@ -0,0 +1,76 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2011, 2013 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#ifndef QUEUE_H +#define QUEUE_H + +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <string.h> + +/* Message Queue structure */ +struct video_msgq { + /* Command to be executed */ + unsigned int cmd; + + unsigned int status; + + /* Client-specific data */ + void *clientdata; +}; + + +/* Thread & Message Queue information */ +struct video_queue_context { + /* Message Queue related members */ + pthread_mutex_t mutex; + sem_t sem_message; + int commandq_size; + int dataq_size; + struct video_msgq *ptr_dataq; + struct video_msgq *ptr_cmdq; + int write_dataq ; + int read_dataq; + int write_comq ; + int read_comq ; + +}; + +int check_if_queue_empty ( unsigned int queuetocheck,void* queuecontext ); + +struct video_msgq * queue_get_cmd ( void* queuecontext ); + +int queue_post_cmdq ( void *queuecontext, + struct video_msgq *post_msg + ); + +int queue_post_dataq ( void *queuecontext, + struct video_msgq *post_msg + ); + +#endif /* QUEUE_H */ diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/mp4_utils.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/mp4_utils.h new file mode 100644 index 0000000..93c04e7 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/mp4_utils.h @@ -0,0 +1,169 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010 - 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#ifndef MP4_UTILS_H +#define MP4_UTILS_H +#include "OMX_Core.h" +#include "OMX_QCOMExtns.h" +typedef signed long long int64; +typedef unsigned int uint32; /* Unsigned 32 bit value */ +typedef unsigned short uint16; /* Unsigned 16 bit value */ +typedef unsigned char uint8; /* Unsigned 8 bit value */ + +typedef int int32; /* Signed 32 bit value */ +typedef signed short int16; /* Signed 16 bit value */ +typedef signed char int8; /* Signed 8 bit value */ + +typedef unsigned char byte; /* Unsigned 8 bit value type. */ +#define SIMPLE_PROFILE_LEVEL0 0x08 +#define SIMPLE_PROFILE_LEVEL1 0x01 +#define SIMPLE_PROFILE_LEVEL2 0x02 +#define SIMPLE_PROFILE_LEVEL3 0x03 +#define SIMPLE_PROFILE_LEVEL4A 0x04 +#define SIMPLE_PROFILE_LEVEL5 0x05 +#define SIMPLE_PROFILE_LEVEL6 0x06 +#define SIMPLE_PROFILE_LEVEL0B 0x09 + +#define SIMPLE_SCALABLE_PROFILE_LEVEL0 0x10 +#define SIMPLE_SCALABLE_PROFILE_LEVEL1 0x11 +#define SIMPLE_SCALABLE_PROFILE_LEVEL2 0x12 + +#define SIMPLE_SCALABLE_PROFILE_LEVEL0 0x10 +#define SIMPLE_SCALABLE_PROFILE_LEVEL1 0x11 +#define SIMPLE_SCALABLE_PROFILE_LEVEL2 0x12 +#define ADVANCED_SIMPLE_PROFILE_LEVEL0 0xF0 +#define ADVANCED_SIMPLE_PROFILE_LEVEL1 0xF1 +#define ADVANCED_SIMPLE_PROFILE_LEVEL2 0xF2 +#define ADVANCED_SIMPLE_PROFILE_LEVEL3 0xF3 +#define ADVANCED_SIMPLE_PROFILE_LEVEL4 0xF4 +#define ADVANCED_SIMPLE_PROFILE_LEVEL5 0xF5 + +#define VISUAL_OBJECT_SEQUENCE_START_CODE 0x000001B0 +#define MP4ERROR_SUCCESS 0 + +#define VIDEO_OBJECT_LAYER_START_CODE_MASK 0xFFFFFFF0 +#define VIDEO_OBJECT_LAYER_START_CODE 0x00000120 +#define VOP_START_CODE_MASK 0xFFFFFFFF +#define VOP_START_CODE 0x000001B6 +#define GOV_START_CODE 0x000001B3 +#define SHORT_HEADER_MASK 0xFFFFFC00 +#define SHORT_HEADER_START_MARKER 0x00008000 +#define SHORT_HEADER_START_CODE 0x00008000 +#define SPARK1_START_CODE 0x00008400 +#define MPEG4_SHAPE_RECTANGULAR 0x00 +#define EXTENDED_PAR 0xF +#define SHORT_VIDEO_START_MARKER 0x20 +#define MP4_INVALID_VOL_PARAM (0x0001) // unsupported VOL parameter +#define MP4ERROR_UNSUPPORTED_UFEP -1068 +#define MP4ERROR_UNSUPPORTED_SOURCE_FORMAT -1069 +#define MASK(x) (0xFFFFFFFF >> (32 - (x))) +#define VISUAL_OBJECT_TYPE_VIDEO_ID 0x1 +#define VISUAL_OBJECT_START_CODE 0x000001B5 +#define VIDEO_OBJECT_START_CODE_MASK 0xFFFFFFE0 +#define VIDEO_OBJECT_START_CODE 0x00000100 + +#define RESERVED_OBJECT_TYPE 0x0 +#define SIMPLE_OBJECT_TYPE 0x1 +#define SIMPLE_SCALABLE_OBJECT_TYPE 0x2 +#define CORE_OBJECT_TYPE 0x3 +#define MAIN_OBJECT_TYPE 0x4 +#define N_BIT_OBJECT_TYPE 0x5 +#define BASIC_ANIMATED_2D_TEXTURE 0x6 +#define ANIMATED_2D_MESH 0x7 +#define ADVANCED_SIMPLE 0x11 + + +#define SIMPLE_L1_MAX_VBVBUFFERSIZE 10 /* VBV Max Buffer size=10 (p. 498) */ +#define SIMPLE_L1_MAX_BITRATE 160 /* is is 64kpbs or 160 400bits/sec units */ +#define SIMPLE_L2_MAX_VBVBUFFERSIZE 40 /* VBV Max Buffer size = 40 */ +#define SIMPLE_L2_MAX_BITRATE 320 /* 320 400bps units = 128kpbs */ +#define SIMPLE_L3_MAX_VBVBUFFERSIZE 40 /* VBV Max Buffer size = 40 */ +#define SIMPLE_L3_MAX_BITRATE 960 /* 960 400bps units = 384kpbs */ + +/* The MP4 decoder currently supports Simple Profile@L3 */ +#define MAX_VBVBUFFERSIZE (SIMPLE_L3_MAX_VBVBUFFERSIZE) +#define MAX_BITRATE (SIMPLE_L3_MAX_BITRATE) + +#define MAX_QUANTPRECISION 9 +#define MIN_QUANTPRECISION 3 + +#define MP4_VGA_WIDTH 640 +#define MP4_VGA_HEIGHT 480 +#define MP4_WVGA_WIDTH 800 +#define MP4_WVGA_HEIGHT 480 +#define MP4_720P_WIDTH 1280 +#define MP4_720P_HEIGHT 720 + +#define MP4_MAX_DECODE_WIDTH MP4_720P_WIDTH +#define MP4_MAX_DECODE_HEIGHT MP4_720P_HEIGHT + +typedef struct { + unsigned char *data; + unsigned long int numBytes; +} mp4StreamType; + +#define MAX_FRAMES_IN_CHUNK 10 +#define VOP_START_CODE 0x000001B6 +#define VOL_START_CODE 0x000001B0 + +typedef enum VOPTYPE { + NO_VOP = -1, // bitstream contains no VOP. + MPEG4_I_VOP = 0, // bitstream contains an MPEG4 I-VOP + MPEG4_P_VOP = 1, // bitstream contains an MPEG4 P-VOP + MPEG4_B_VOP = 2, // bitstream contains an MPEG4 B-VOP + MPEG4_S_VOP = 3, // bitstream contains an MPEG4 S-VOP +} VOP_TYPE; + +typedef struct { + uint32 timestamp_increment; + uint32 offset; + uint32 size; + VOP_TYPE vopType; +} mp4_frame_info_type; + +class MP4_Utils +{ + private: + struct posInfoType { + uint8 *bytePtr; + uint8 bitPos; + }; + + posInfoType m_posInfo; + byte *m_dataBeginPtr; + unsigned int vop_time_resolution; + bool vop_time_found; + uint16 m_SrcWidth, m_SrcHeight; // Dimensions of the source clip + public: + MP4_Utils(); + ~MP4_Utils(); + int16 populateHeightNWidthFromShortHeader(mp4StreamType * psBits); + bool parseHeader(mp4StreamType * psBits); + static uint32 read_bit_field(posInfoType * posPtr, uint32 size); + bool is_notcodec_vop(unsigned char *pbuffer, unsigned int len); +}; +#endif diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_swvdec.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_swvdec.h new file mode 100644 index 0000000..3037d8c --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_swvdec.h @@ -0,0 +1,459 @@ +/** + * @copyright + * + * Copyright (c) 2015-2016, 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_ + +//#undef NDEBUG // uncomment to enable assertions + +#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 "2016-10-24T17:37:33+0530" + +#define OMX_SPEC_VERSION 0x00000101 ///< OMX specification version + +#define OMX_SWVDEC_NUM_INSTANCES 1 ///< number of OMX SwVdec instances + +#define OMX_SWVDEC_IP_BUFFER_COUNT_MIN 5 ///< OMX SwVdec minimum ip buffer count + +#define OMX_SWVDEC_MAX_FRAMES_PER_ETB 2 ///< maximum number of frames per ETB + +/// 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; + unsigned int split_count; +} 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 { + int fd; ///< file descriptor + int ref_count; ///< reference count +} OMX_SWVDEC_META_BUFFER_INFO; + +#define DEFAULT_FRAME_WIDTH 1920 ///< default frame width +#define DEFAULT_FRAME_HEIGHT 1080 ///< default frame height + +#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_DIMENSIONS m_frame_dimensions; ///< frame dimensions + FRAME_ATTRIBUTES m_frame_attributes; ///< frame attributes + + FRAME_DIMENSIONS m_frame_dimensions_max; + ///< max frame dimensions for adaptive playback + + 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_disabled; ///< meta buffer mode disabled? + bool m_meta_buffer_mode; ///< meta buffer mode enabled? + bool m_adaptive_playback_mode; ///< adaptive playback mode enabled? + bool m_arbitrary_bytes_mode; ///< arbitrary bytes mode enabled? + + bool m_port_reconfig_inprogress; ///< port reconfiguration in progress? + + bool m_dimensions_update_inprogress; ///< dimensions update 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 + + std::priority_queue <OMX_TICKS, + std::vector<OMX_TICKS>, + std::greater<OMX_TICKS> > m_queue_timestamp; + ///< timestamp priority queue + + omx_swvdec_diag m_diag; ///< diagnostics class variable + + OMX_ERRORTYPE set_frame_dimensions(unsigned int width, + unsigned int height); + OMX_ERRORTYPE set_frame_attributes(OMX_COLOR_FORMATTYPE color_format); + OMX_ERRORTYPE set_adaptive_playback(unsigned int max_width, + unsigned int max_height); + + 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(); + OMX_ERRORTYPE set_adaptive_playback_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, int fd); + void meta_buffer_ref_remove(unsigned int index); + + 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); + void ion_flush_op(unsigned int index); + + // 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_SWVDEC_EVENT_DIMENSIONS_UPDATED ///< dimensions updated event + }; + + OMX_ERRORTYPE async_thread_create(); + void async_thread_destroy(); + + static void async_thread(void *p_cmp); + + void 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(); + OMX_ERRORTYPE async_process_event_dimensions_updated(); +}; + +#endif // #ifndef _OMX_SWVDEC_H_ diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_swvdec_utils.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_swvdec_utils.h new file mode 100644 index 0000000..cfd3676 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_swvdec_utils.h @@ -0,0 +1,145 @@ +/** + * @copyright + * + * Copyright (c) 2015-2016, 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 <queue> +#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) + +/// 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(); + + void push(OMX_SWVDEC_EVENT_INFO *p_event_info); + bool pop(OMX_SWVDEC_EVENT_INFO *p_event_info); + +private: + std::queue<OMX_SWVDEC_EVENT_INFO> m_queue; ///< queue + pthread_mutex_t m_mutex; ///< mutex +}; + +#define DIAG_FILE_PATH "/data/misc/media" ///< file path + +/// 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/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_vdec.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_vdec.h new file mode 100644 index 0000000..05d6bc7 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_vdec.h @@ -0,0 +1,1307 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010 - 2016, 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. +--------------------------------------------------------------------------*/ +#ifndef __OMX_VDEC_H__ +#define __OMX_VDEC_H__ +/*============================================================================ + O p e n M A X Component + Video Decoder + +*//** @file comx_vdec.h + This module contains the class definition for openMAX decoder component. + +*//*========================================================================*/ + +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <cstddef> +#include <cutils/atomic.h> +#include <qdMetaData.h> + +static ptrdiff_t x; + +#ifdef _ANDROID_ +#ifdef MAX_RES_720P +#define LOG_TAG "OMX-VDEC-720P" +#elif MAX_RES_1080P +#define LOG_TAG "OMX-VDEC-1080P" +#else +#define LOG_TAG "OMX-VDEC" +#endif + +#ifdef USE_ION +#include <linux/msm_ion.h> +//#include <binder/MemoryHeapIon.h> +//#else +#endif +#include <binder/MemoryHeapBase.h> +#include <ui/ANativeObjectBase.h> +extern "C" { +#include <utils/Log.h> +} +#include <linux/videodev2.h> +#include <poll.h> +#include "hevc_utils.h" +#define TIMEOUT 5000 +#endif // _ANDROID_ + +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) +#include <media/hardware/HardwareAPI.h> +#endif + +#include <unistd.h> + +#if defined (_ANDROID_ICS_) +#include <gralloc_priv.h> +#endif + +#include <pthread.h> +#ifndef PC_DEBUG +#include <semaphore.h> +#endif +#include "OMX_Core.h" +#include "OMX_QCOMExtns.h" +#include "OMX_Skype_VideoExtensions.h" +#include "OMX_VideoExt.h" +#include "OMX_IndexExt.h" +#include "qc_omx_component.h" +#include <linux/msm_vidc_dec.h> +#include <media/msm_vidc.h> +#include "frameparser.h" +#ifdef MAX_RES_1080P +#include "mp4_utils.h" +#endif +#include "extra_data_handler.h" +#include "ts_parser.h" +#include "vidc_color_converter.h" +#include "vidc_debug.h" +#ifdef _ANDROID_ +#include <cutils/properties.h> +#else +#define PROPERTY_VALUE_MAX 92 +#endif +extern "C" { + OMX_API void * get_omx_component_factory_fn(void); +} + +#ifdef _ANDROID_ +using namespace android; +#ifdef USE_ION +class VideoHeap : public MemoryHeapBase +{ + public: + VideoHeap(int devicefd, size_t size, void* base,ion_user_handle_t handle,int mapfd); + virtual ~VideoHeap() {} + private: + int m_ion_device_fd; + ion_user_handle_t m_ion_handle; +}; +#else +// local pmem heap object +class VideoHeap : public MemoryHeapBase +{ + public: + VideoHeap(int fd, size_t size, void* base); + virtual ~VideoHeap() {} +}; +#endif +#endif // _ANDROID_ +////////////////////////////////////////////////////////////////////////////// +// Module specific globals +////////////////////////////////////////////////////////////////////////////// +#define OMX_SPEC_VERSION 0x00000101 + + +////////////////////////////////////////////////////////////////////////////// +// Macros +////////////////////////////////////////////////////////////////////////////// +#define PrintFrameHdr(bufHdr) DEBUG_PRINT("bufHdr %x buf %x size %d TS %d\n",\ + (unsigned) bufHdr,\ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->pBuffer,\ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFilledLen,\ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nTimeStamp) + +// BitMask Management logic +#define BITS_PER_INDEX 64 +#define BITMASK_SIZE(mIndex) (((mIndex) + BITS_PER_INDEX - 1)/BITS_PER_INDEX) +#define BITMASK_OFFSET(mIndex) ((mIndex)/BITS_PER_INDEX) +#define BITMASK_FLAG(mIndex) ((uint64_t)1 << ((mIndex) % BITS_PER_INDEX)) +#define BITMASK_CLEAR(mArray,mIndex) (mArray)[BITMASK_OFFSET(mIndex)] \ + &= ~(BITMASK_FLAG(mIndex)) +#define BITMASK_SET(mArray,mIndex) (mArray)[BITMASK_OFFSET(mIndex)] \ + |= BITMASK_FLAG(mIndex) +#define BITMASK_PRESENT(mArray,mIndex) ((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) +#define BITMASK_ABSENT(mArray,mIndex) (((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) == 0x0) +#define BITMASK_PRESENT(mArray,mIndex) ((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) +#define BITMASK_ABSENT(mArray,mIndex) (((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) == 0x0) + +#define OMX_CORE_CONTROL_CMDQ_SIZE 100 +#define OMX_CORE_QCIF_HEIGHT 144 +#define OMX_CORE_QCIF_WIDTH 176 +#define OMX_CORE_VGA_HEIGHT 480 +#define OMX_CORE_VGA_WIDTH 640 +#define OMX_CORE_WVGA_HEIGHT 480 +#define OMX_CORE_WVGA_WIDTH 800 +#define OMX_CORE_FWVGA_HEIGHT 480 +#define OMX_CORE_FWVGA_WIDTH 864 + +#define DESC_BUFFER_SIZE (8192 * 16) + +#ifdef _ANDROID_ +#define MAX_NUM_INPUT_OUTPUT_BUFFERS 64 +#endif + +#define OMX_FRAMEINFO_EXTRADATA 0x00010000 +#define OMX_INTERLACE_EXTRADATA 0x00020000 +#define OMX_TIMEINFO_EXTRADATA 0x00040000 +#define OMX_PORTDEF_EXTRADATA 0x00080000 +#define OMX_EXTNUSER_EXTRADATA 0x00100000 +#define OMX_FRAMEDIMENSION_EXTRADATA 0x00200000 +#define OMX_FRAMEPACK_EXTRADATA 0x00400000 +#define OMX_QP_EXTRADATA 0x00800000 +#define OMX_BITSINFO_EXTRADATA 0x01000000 +#define OMX_VQZIPSEI_EXTRADATA 0x02000000 +#define OMX_OUTPUTCROP_EXTRADATA 0x04000000 + +#define OMX_VUI_DISPLAY_INFO_EXTRADATA 0x08000000 +#define OMX_MPEG2_SEQDISP_INFO_EXTRADATA 0x10000000 +#define OMX_VPX_COLORSPACE_INFO_EXTRADATA 0x20000000 +#define OMX_VC1_SEQDISP_INFO_EXTRADATA 0x40000000 +#define OMX_DISPLAY_INFO_EXTRADATA 0x80000000 +#define OMX_HDR_COLOR_INFO_EXTRADATA 0x100000000 +#define DRIVER_EXTRADATA_MASK 0x0000FFFF + +#define OMX_INTERLACE_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_STREAMINTERLACEFORMAT) + 3)&(~3)) +#define OMX_FRAMEINFO_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_QCOM_EXTRADATA_FRAMEINFO) + 3)&(~3)) +#define OMX_PORTDEF_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_PARAM_PORTDEFINITIONTYPE) + 3)&(~3)) +#define OMX_FRAMEDIMENSION_EXTRADATA_SIZE (sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_QCOM_EXTRADATA_FRAMEDIMENSION) + 3)&(~3) +#define OMX_FRAMEPACK_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_QCOM_FRAME_PACK_ARRANGEMENT) + 3)&(~3)) +#define OMX_QP_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_QCOM_EXTRADATA_QP) + 3)&(~3)) +#define OMX_BITSINFO_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_QCOM_EXTRADATA_BITS_INFO) + 3)&(~3)) +#define OMX_VQZIPSEI_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_QCOM_EXTRADATA_VQZIPSEI) + 3)&(~3)) +#define OMX_USERDATA_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + + 3)&(~3)) + +// Define next macro with required values to enable default extradata, +// VDEC_EXTRADATA_MB_ERROR_MAP +// OMX_INTERLACE_EXTRADATA +// OMX_FRAMEINFO_EXTRADATA +// OMX_TIMEINFO_EXTRADATA + +//#define DEFAULT_EXTRADATA (OMX_FRAMEINFO_EXTRADATA|OMX_INTERLACE_EXTRADATA) + +enum port_indexes { + OMX_CORE_INPUT_PORT_INDEX =0, + OMX_CORE_OUTPUT_PORT_INDEX =1 +}; +enum vidc_perf_level { + VIDC_SVS = 0, + VIDC_NOMINAL = 1, + VIDC_TURBO = 2 +}; +#ifdef USE_ION +struct vdec_ion { + int ion_device_fd; + struct ion_fd_data fd_ion_data; + struct ion_allocation_data ion_alloc_data; +}; +#endif + +#ifdef _MSM8974_ +struct extradata_buffer_info { + unsigned long buffer_size; + char* uaddr; + int count; + int size; +#ifdef USE_ION + struct vdec_ion ion; +#endif +}; +#endif + +struct video_driver_context { + int video_driver_fd; + enum vdec_codec decoder_format; + enum vdec_output_fromat output_format; + enum vdec_interlaced_format interlace; + enum vdec_output_order picture_order; + struct vdec_framesize frame_size; + struct vdec_picsize video_resolution; + struct vdec_allocatorproperty ip_buf; + struct vdec_allocatorproperty op_buf; + struct vdec_bufferpayload *ptr_inputbuffer; + struct vdec_bufferpayload *ptr_outputbuffer; + struct vdec_output_frameinfo *ptr_respbuffer; +#ifdef USE_ION + struct vdec_ion *ip_buf_ion_info; + struct vdec_ion *op_buf_ion_info; + struct vdec_ion h264_mv; + struct vdec_ion meta_buffer; + struct vdec_ion meta_buffer_iommu; +#endif + struct vdec_framerate frame_rate; + unsigned extradata; + bool timestamp_adjust; + char kind[128]; + bool idr_only_decoding; + unsigned disable_dmx; +#ifdef _MSM8974_ + struct extradata_buffer_info extradata_info; + int num_planes; +#endif +}; + +struct video_decoder_capability { + unsigned int min_width; + unsigned int max_width; + unsigned int min_height; + unsigned int max_height; +}; + +struct debug_cap { + bool in_buffer_log; + bool out_buffer_log; + bool out_meta_buffer_log; + char infile_name[PROPERTY_VALUE_MAX + 36]; + char outfile_name[PROPERTY_VALUE_MAX + 36]; + char out_ymetafile_name[PROPERTY_VALUE_MAX + 36]; + char out_uvmetafile_name[PROPERTY_VALUE_MAX + 36]; + char log_loc[PROPERTY_VALUE_MAX]; + FILE *infile; + FILE *outfile; + FILE *out_ymeta_file; + FILE *out_uvmeta_file; +}; + +struct dynamic_buf_list { + long fd; + long dup_fd; + OMX_U32 offset; + OMX_U32 ref_count; + void *buffaddr; + long mapped_size; +}; + +struct extradata_info { + OMX_BOOL output_crop_updated; + OMX_CONFIG_RECTTYPE output_crop_rect; + OMX_U32 output_width; + OMX_U32 output_height; +}; + +// OMX video decoder class +class omx_vdec: public qc_omx_component +{ + + public: + omx_vdec(); // constructor + virtual ~omx_vdec(); // destructor + + static int async_message_process (void *context, void* message); + static void process_event_cb(void *ctxt,unsigned char id); + + OMX_ERRORTYPE allocate_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes + ); + + + OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp); + + OMX_ERRORTYPE component_init(OMX_STRING role); + + OMX_ERRORTYPE component_role_enum( + OMX_HANDLETYPE hComp, + OMX_U8 *role, + OMX_U32 index + ); + + OMX_ERRORTYPE component_tunnel_request( + OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_HANDLETYPE peerComponent, + OMX_U32 peerPort, + OMX_TUNNELSETUPTYPE *tunnelSetup + ); + + OMX_ERRORTYPE empty_this_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ); + + + + OMX_ERRORTYPE fill_this_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ); + + + OMX_ERRORTYPE free_buffer( + OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_BUFFERHEADERTYPE *buffer + ); + + OMX_ERRORTYPE get_component_version( + OMX_HANDLETYPE hComp, + OMX_STRING componentName, + OMX_VERSIONTYPE *componentVersion, + OMX_VERSIONTYPE *specVersion, + OMX_UUIDTYPE *componentUUID + ); + + OMX_ERRORTYPE get_config( + OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData + ); + + OMX_ERRORTYPE get_extension_index( + OMX_HANDLETYPE hComp, + OMX_STRING paramName, + OMX_INDEXTYPE *indexType + ); + + OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE get_state(OMX_HANDLETYPE hComp, + OMX_STATETYPE *state); + + + + OMX_ERRORTYPE send_command(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + + + OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE hComp, + OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData); + + OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + + OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); + + OMX_ERRORTYPE use_input_heap_buffers( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8* buffer); + + OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + void * eglImage); + void complete_pending_buffer_done_cbs(); + struct video_driver_context drv_ctx; + int m_poll_efd; +#ifdef _MSM8974_ + OMX_ERRORTYPE allocate_extradata(); + void free_extradata(); + int update_resolution(int width, int height, int stride, int scan_lines); + OMX_ERRORTYPE is_video_session_supported(); +#endif + int m_pipe_in; + int m_pipe_out; + pthread_t msg_thread_id; + pthread_t async_thread_id; + bool is_component_secure(); + void buf_ref_add(int nPortIndex); + void buf_ref_remove(); + OMX_BUFFERHEADERTYPE* get_omx_output_buffer_header(int index); + OMX_ERRORTYPE set_dpb(bool is_split_mode, int dpb_color_format); + OMX_ERRORTYPE decide_dpb_buffer_mode(bool split_opb_dpb_with_same_color_fmt); + void request_perf_level(enum vidc_perf_level perf_level); + int dpb_bit_depth; + bool async_thread_force_stop; + volatile bool message_thread_stop; + struct extradata_info m_extradata_info; + int m_progressive; + + enum dither_type { + DITHER_DISABLE = 0, + DITHER_COLORSPACE_EXCEPTBT2020, + DITHER_ALL_COLORSPACE + }; + enum dither_type m_dither_config; + + enum color_space_type { + BT2020 = 0, + EXCEPT_BT2020, + UNKNOWN + }; + enum color_space_type m_color_space; + + private: + // Bit Positions + enum flags_bit_positions { + // Defer transition to IDLE + OMX_COMPONENT_IDLE_PENDING =0x1, + // Defer transition to LOADING + OMX_COMPONENT_LOADING_PENDING =0x2, + // First Buffer Pending + OMX_COMPONENT_FIRST_BUFFER_PENDING =0x3, + // Second Buffer Pending + OMX_COMPONENT_SECOND_BUFFER_PENDING =0x4, + // Defer transition to Enable + OMX_COMPONENT_INPUT_ENABLE_PENDING =0x5, + // Defer transition to Enable + OMX_COMPONENT_OUTPUT_ENABLE_PENDING =0x6, + // Defer transition to Disable + OMX_COMPONENT_INPUT_DISABLE_PENDING =0x7, + // Defer transition to Disable + OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x8, + //defer flush notification + OMX_COMPONENT_OUTPUT_FLUSH_PENDING =0x9, + OMX_COMPONENT_INPUT_FLUSH_PENDING =0xA, + OMX_COMPONENT_PAUSE_PENDING =0xB, + OMX_COMPONENT_EXECUTE_PENDING =0xC, + OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING =0xD, + OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED=0xE, + OMX_COMPONENT_FLUSH_DEFERRED = 0xF + }; + + // Deferred callback identifiers + enum { + //Event Callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_EVENT = 0x1, + //Buffer Done callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_BUFFER_DONE = 0x2, + //Frame Done callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_FRAME_DONE = 0x3, + //Buffer Done callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_FTB = 0x4, + //Frame Done callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_ETB = 0x5, + //Command + OMX_COMPONENT_GENERATE_COMMAND = 0x6, + //Push-Pending Buffers + OMX_COMPONENT_PUSH_PENDING_BUFS = 0x7, + // Empty Buffer Done callbacks + OMX_COMPONENT_GENERATE_EBD = 0x8, + //Flush Event Callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_EVENT_FLUSH = 0x9, + OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH = 0x0A, + OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH = 0x0B, + OMX_COMPONENT_GENERATE_FBD = 0xc, + OMX_COMPONENT_GENERATE_START_DONE = 0xD, + OMX_COMPONENT_GENERATE_PAUSE_DONE = 0xE, + OMX_COMPONENT_GENERATE_RESUME_DONE = 0xF, + OMX_COMPONENT_GENERATE_STOP_DONE = 0x10, + OMX_COMPONENT_GENERATE_HARDWARE_ERROR = 0x11, + OMX_COMPONENT_GENERATE_ETB_ARBITRARY = 0x12, + OMX_COMPONENT_GENERATE_PORT_RECONFIG = 0x13, + OMX_COMPONENT_GENERATE_EOS_DONE = 0x14, + OMX_COMPONENT_GENERATE_INFO_PORT_RECONFIG = 0x15, + OMX_COMPONENT_GENERATE_INFO_FIELD_DROPPED = 0x16, + OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING = 0x17, + OMX_COMPONENT_GENERATE_HARDWARE_OVERLOAD = 0x18, + OMX_COMPONENT_CLOSE_MSG = 0x19 + }; + + enum vc1_profile_type { + VC1_SP_MP_RCV = 1, + VC1_AP = 2 + }; + +#ifdef _MSM8974_ + enum v4l2_ports { + CAPTURE_PORT, + OUTPUT_PORT, + MAX_PORT + }; +#endif + + struct omx_event { + unsigned long param1; + unsigned long param2; + unsigned long id; + }; + + struct omx_cmd_queue { + omx_event m_q[OMX_CORE_CONTROL_CMDQ_SIZE]; + unsigned long m_read; + unsigned long m_write; + unsigned long m_size; + + omx_cmd_queue(); + ~omx_cmd_queue(); + bool insert_entry(unsigned long p1, unsigned long p2, unsigned long id); + bool pop_entry(unsigned long *p1,unsigned long *p2, unsigned long *id); + // get msgtype of the first ele from the queue + unsigned get_q_msg_type(); + + }; + struct v4l2_capability cap; +#ifdef _ANDROID_ + struct ts_entry { + OMX_TICKS timestamp; + bool valid; + }; + + struct ts_arr_list { + ts_entry m_ts_arr_list[MAX_NUM_INPUT_OUTPUT_BUFFERS]; + + ts_arr_list(); + ~ts_arr_list(); + + bool insert_ts(OMX_TICKS ts); + bool pop_min_ts(OMX_TICKS &ts); + bool reset_ts_list(); + }; +#endif + + struct desc_buffer_hdr { + OMX_U8 *buf_addr; + OMX_U32 desc_data_size; + }; + bool allocate_done(void); + bool allocate_input_done(void); + bool allocate_output_done(void); + + OMX_ERRORTYPE free_input_buffer(OMX_BUFFERHEADERTYPE *bufferHdr); + OMX_ERRORTYPE free_input_buffer(unsigned int bufferindex, + OMX_BUFFERHEADERTYPE *pmem_bufferHdr); + OMX_ERRORTYPE free_output_buffer(OMX_BUFFERHEADERTYPE *bufferHdr); + void free_output_buffer_header(); + void free_input_buffer_header(); + + OMX_ERRORTYPE allocate_input_heap_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + + OMX_ERRORTYPE allocate_input_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + OMX_ERRORTYPE allocate_output_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port,OMX_PTR appData, + OMX_U32 bytes); + OMX_ERRORTYPE use_output_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); + OMX_ERRORTYPE get_supported_profile_level(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType); + + OMX_ERRORTYPE allocate_desc_buffer(OMX_U32 index); + OMX_ERRORTYPE allocate_output_headers(); + bool execute_omx_flush(OMX_U32); + bool execute_output_flush(); + bool execute_input_flush(); + OMX_ERRORTYPE empty_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer); + + OMX_ERRORTYPE fill_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer); + OMX_ERRORTYPE empty_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + OMX_ERRORTYPE empty_this_buffer_proxy_arbitrary(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ); + + OMX_ERRORTYPE push_input_buffer (OMX_HANDLETYPE hComp); + OMX_ERRORTYPE push_input_sc_codec (OMX_HANDLETYPE hComp); + OMX_ERRORTYPE push_input_h264 (OMX_HANDLETYPE hComp); + OMX_ERRORTYPE push_input_hevc (OMX_HANDLETYPE hComp); + OMX_ERRORTYPE push_input_vc1 (OMX_HANDLETYPE hComp); + + OMX_ERRORTYPE fill_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + bool release_done(); + + bool release_output_done(); + bool release_input_done(); + OMX_ERRORTYPE get_buffer_req(vdec_allocatorproperty *buffer_prop); + OMX_ERRORTYPE set_buffer_req(vdec_allocatorproperty *buffer_prop); + OMX_ERRORTYPE start_port_reconfig(); + OMX_ERRORTYPE update_picture_resolution(); + int stream_off(OMX_U32 port); + void adjust_timestamp(OMX_S64 &act_timestamp); + void set_frame_rate(OMX_S64 act_timestamp); + void handle_extradata_secure(OMX_BUFFERHEADERTYPE *p_buf_hdr); + void handle_extradata(OMX_BUFFERHEADERTYPE *p_buf_hdr); + void convert_color_space_info(OMX_U32 primaries, OMX_U32 range, + OMX_U32 transfer, OMX_U32 matrix, ColorSpace_t *color_space, + ColorAspects *aspects); + bool handle_color_space_info(void *data, unsigned int buf_index); + void set_colorspace_in_handle(ColorSpace_t color, unsigned int buf_index); + void print_debug_color_aspects(ColorAspects *aspects, const char *prefix); + void print_debug_hdr_color_info(HDRStaticInfo *hdr_info, const char *prefix); + bool handle_content_light_level_info(void* data); + bool handle_mastering_display_color_info(void* data); + void print_debug_extradata(OMX_OTHER_EXTRADATATYPE *extra); +#ifdef _MSM8974_ + void append_interlace_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 interlaced_format_type); + OMX_ERRORTYPE enable_extradata(OMX_U64 requested_extradata, bool is_internal, + bool enable = true); + void append_frame_info_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 num_conceal_mb, + OMX_U32 picture_type, + OMX_U32 frame_rate, + OMX_TICKS time_stamp, + struct msm_vidc_panscan_window_payload *panscan_payload, + struct vdec_aspectratioinfo *aspect_ratio_info); +#else + void append_interlace_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 interlaced_format_type, OMX_U32 buf_index); + OMX_ERRORTYPE enable_extradata(OMX_U32 requested_extradata, bool enable = true); +#endif + void append_frame_info_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 num_conceal_mb, + OMX_U32 picture_type, + OMX_S64 timestamp, + OMX_U32 frame_rate, + struct vdec_aspectratioinfo *aspect_ratio_info); + void fill_aspect_ratio_info(struct vdec_aspectratioinfo *aspect_ratio_info, + OMX_QCOM_EXTRADATA_FRAMEINFO *frame_info); + void append_terminator_extradata(OMX_OTHER_EXTRADATATYPE *extra); + OMX_ERRORTYPE update_portdef(OMX_PARAM_PORTDEFINITIONTYPE *portDefn); + void append_portdef_extradata(OMX_OTHER_EXTRADATATYPE *extra); + void append_frame_dimension_extradata(OMX_OTHER_EXTRADATATYPE *extra); + void append_extn_extradata(OMX_OTHER_EXTRADATATYPE *extra, OMX_OTHER_EXTRADATATYPE *p_extn); + void append_user_extradata(OMX_OTHER_EXTRADATATYPE *extra, OMX_OTHER_EXTRADATATYPE *p_user); + void append_concealmb_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_OTHER_EXTRADATATYPE *p_concealmb, OMX_U8 *conceal_mb_data); + void append_framepack_extradata(OMX_OTHER_EXTRADATATYPE *extra, + struct msm_vidc_s3d_frame_packing_payload *s3d_frame_packing_payload); + void append_qp_extradata(OMX_OTHER_EXTRADATATYPE *extra, + struct msm_vidc_frame_qp_payload *qp_payload); + void append_bitsinfo_extradata(OMX_OTHER_EXTRADATATYPE *extra, + struct msm_vidc_frame_bits_info_payload *bits_payload); + void append_vqzip_extradata(OMX_OTHER_EXTRADATATYPE *extra, + struct msm_vidc_vqzip_sei_payload *vqzip_payload); + void insert_demux_addr_offset(OMX_U32 address_offset); + void extract_demux_addr_offsets(OMX_BUFFERHEADERTYPE *buf_hdr); + OMX_ERRORTYPE handle_demux_data(OMX_BUFFERHEADERTYPE *buf_hdr); + OMX_U32 count_MB_in_extradata(OMX_OTHER_EXTRADATATYPE *extra); + + bool align_pmem_buffers(int pmem_fd, OMX_U32 buffer_size, + OMX_U32 alignment); +#ifdef USE_ION + int alloc_map_ion_memory(OMX_U32 buffer_size, + OMX_U32 alignment, struct ion_allocation_data *alloc_data, + struct ion_fd_data *fd_data,int flag); + void free_ion_memory(struct vdec_ion *buf_ion_info); +#endif + + + OMX_ERRORTYPE send_command_proxy(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + bool post_event( unsigned long p1, + unsigned long p2, + unsigned long id + ); + inline int clip2(int x) { + x = x -1; + x = x | x >> 1; + x = x | x >> 2; + x = x | x >> 4; + x = x | x >> 16; + x = x + 1; + return x; + } + +#ifdef MAX_RES_1080P + OMX_ERRORTYPE vdec_alloc_h264_mv(); + void vdec_dealloc_h264_mv(); + OMX_ERRORTYPE vdec_alloc_meta_buffers(); + void vdec_dealloc_meta_buffers(); +#endif + + inline void omx_report_error () { + if (m_cb.EventHandler && !m_error_propogated && m_state != OMX_StateLoaded) { + DEBUG_PRINT_ERROR("ERROR: Sending OMX_ErrorHardware to Client"); + m_error_propogated = true; + m_cb.EventHandler(&m_cmp,m_app_data, + OMX_EventError,OMX_ErrorHardware,0,NULL); + } + } + + inline void omx_report_unsupported_setting () { + if (m_cb.EventHandler && !m_error_propogated && m_state != OMX_StateLoaded) { + DEBUG_PRINT_ERROR( + "ERROR: Sending OMX_ErrorUnsupportedSetting to Client"); + m_error_propogated = true; + m_cb.EventHandler(&m_cmp, m_app_data, + OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); + } + } + inline void omx_report_hw_overload () { + if (m_cb.EventHandler && !m_error_propogated && m_state != OMX_StateLoaded) { + DEBUG_PRINT_ERROR( + "ERROR: Sending OMX_ErrorInsufficientResources to Client"); + m_error_propogated = true; + m_cb.EventHandler(&m_cmp, m_app_data, + OMX_EventError, OMX_ErrorInsufficientResources, 0, NULL); + } + } + +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) + OMX_ERRORTYPE use_android_native_buffer(OMX_IN OMX_HANDLETYPE hComp, OMX_PTR data); +#endif +#if defined (_ANDROID_ICS_) + struct nativebuffer { + native_handle_t *nativehandle; + private_handle_t *privatehandle; + int inuse; + }; + nativebuffer native_buffer[MAX_NUM_INPUT_OUTPUT_BUFFERS]; +#endif + + //************************************************************* + //*******************MEMBER VARIABLES ************************* + //************************************************************* + pthread_mutex_t m_lock; + pthread_mutex_t c_lock; + pthread_mutex_t buf_lock; + //sem to handle the minimum procesing of commands + sem_t m_cmd_lock; + sem_t m_safe_flush; + bool m_error_propogated; + // compression format + OMX_VIDEO_CODINGTYPE eCompressionFormat; + // OMX State + OMX_STATETYPE m_state; + // Application data + OMX_PTR m_app_data; + // Application callbacks + OMX_CALLBACKTYPE m_cb; + OMX_PRIORITYMGMTTYPE m_priority_mgm ; + OMX_PARAM_BUFFERSUPPLIERTYPE m_buffer_supplier; + // fill this buffer queue + omx_cmd_queue m_ftb_q; + // Command Q for rest of the events + omx_cmd_queue m_cmd_q; + omx_cmd_queue m_etb_q; + // Input memory pointer + OMX_BUFFERHEADERTYPE *m_inp_mem_ptr; + // Output memory pointer + OMX_BUFFERHEADERTYPE *m_out_mem_ptr; + // number of input bitstream error frame count + unsigned int m_inp_err_count; +#ifdef _ANDROID_ + // Timestamp list + ts_arr_list m_timestamp_list; +#endif + + bool input_flush_progress; + bool output_flush_progress; + bool input_use_buffer; + bool output_use_buffer; + bool ouput_egl_buffers; + OMX_BOOL m_use_output_pmem; + OMX_BOOL m_out_mem_region_smi; + OMX_BOOL m_out_pvt_entry_pmem; + + int pending_input_buffers; + int pending_output_buffers; + // bitmask array size for output side + uint64_t m_out_bm_count; + // bitmask array size for input side + uint64_t m_inp_bm_count; + //Input port Populated + OMX_BOOL m_inp_bPopulated; + //Output port Populated + OMX_BOOL m_out_bPopulated; + // encapsulate the waiting states. + uint64_t m_flags; + +#ifdef _ANDROID_ + // Heap pointer to frame buffers + struct vidc_heap { + sp<MemoryHeapBase> video_heap_ptr; + }; + struct vidc_heap *m_heap_ptr; + unsigned int m_heap_count; +#endif //_ANDROID_ + // store I/P PORT state + OMX_BOOL m_inp_bEnabled; + // store O/P PORT state + OMX_BOOL m_out_bEnabled; + OMX_U32 m_in_alloc_cnt; + OMX_U8 m_cRole[OMX_MAX_STRINGNAME_SIZE]; + // Platform specific details + OMX_QCOM_PLATFORM_PRIVATE_LIST *m_platform_list; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY *m_platform_entry; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *m_pmem_info; + // SPS+PPS sent as part of set_config + OMX_VENDOR_EXTRADATATYPE m_vendor_config; + + /*Variables for arbitrary Byte parsing support*/ + frame_parse m_frame_parser; + h264_stream_parser *h264_parser; + MP4_Utils mp4_headerparser; + HEVC_Utils m_hevc_utils; + + omx_cmd_queue m_input_pending_q; + omx_cmd_queue m_input_free_q; + bool arbitrary_bytes; + OMX_BUFFERHEADERTYPE h264_scratch; + OMX_BUFFERHEADERTYPE *psource_frame; + OMX_BUFFERHEADERTYPE *pdest_frame; + OMX_BUFFERHEADERTYPE *m_inp_heap_ptr; + OMX_BUFFERHEADERTYPE **m_phdr_pmem_ptr; + unsigned int m_heap_inp_bm_count; + codec_type codec_type_parse; + bool first_frame_meta; + unsigned frame_count; + unsigned nal_count; + unsigned nal_length; + bool look_ahead_nal; + int first_frame; + unsigned char *first_buffer; + int first_frame_size; + unsigned char m_hwdevice_name[80]; + FILE *m_device_file_ptr; + enum vc1_profile_type m_vc1_profile; + OMX_S64 h264_last_au_ts; + OMX_U32 h264_last_au_flags; + OMX_U32 m_demux_offsets[8192]; + OMX_U32 m_demux_entries; + OMX_U32 m_disp_hor_size; + OMX_U32 m_disp_vert_size; + OMX_S64 prev_ts; + OMX_S64 prev_ts_actual; + bool rst_prev_ts; + OMX_U32 frm_int; + OMX_U32 m_fps_received; + float m_fps_prev; + bool m_drc_enable; + + struct vdec_allocatorproperty op_buf_rcnfg; + bool in_reconfig; + OMX_NATIVE_WINDOWTYPE m_display_id; + OMX_U32 client_extradata; +#ifdef _ANDROID_ + bool m_debug_timestamp; + bool perf_flag; + OMX_U32 proc_frms, latency; + perf_metrics fps_metrics; + perf_metrics dec_time; + bool m_reject_avc_1080p_mp; + bool m_enable_android_native_buffers; + bool m_use_android_native_buffers; + bool m_debug_extradata; + bool m_debug_concealedmb; + bool m_disable_dynamic_buf_mode; + OMX_U32 m_conceal_color; +#endif + + + struct h264_mv_buffer { + unsigned char* buffer; + int size; + int count; + int pmem_fd; + int offset; + }; + h264_mv_buffer h264_mv_buff; + + struct meta_buffer { + unsigned char* buffer; + int size; + int count; + int pmem_fd; + int pmem_fd_iommu; + int offset; + }; + meta_buffer meta_buff; + extra_data_handler extra_data_handle; + OMX_PARAM_PORTDEFINITIONTYPE m_port_def; + OMX_QCOM_FRAME_PACK_ARRANGEMENT m_frame_pack_arrangement; + omx_time_stamp_reorder time_stamp_dts; + desc_buffer_hdr *m_desc_buffer_ptr; + bool secure_mode; + bool allocate_native_handle; + bool external_meta_buffer; + bool external_meta_buffer_iommu; + OMX_QCOM_EXTRADATA_FRAMEINFO *m_extradata; + OMX_OTHER_EXTRADATATYPE *m_other_extradata; + bool codec_config_flag; +#ifdef _MSM8974_ + int capture_capability; + int output_capability; + bool streaming[MAX_PORT]; + OMX_FRAMESIZETYPE framesize; + OMX_CONFIG_RECTTYPE rectangle; + OMX_U32 prev_n_filled_len; + bool is_down_scalar_enabled; + bool m_force_down_scalar; +#endif + struct custom_buffersize { + OMX_U32 input_buffersize; + } m_custom_buffersize; + bool m_power_hinted; + bool is_q6_platform; + OMX_ERRORTYPE power_module_register(); + OMX_ERRORTYPE power_module_deregister(); + bool msg_thread_created; + bool async_thread_created; + + OMX_VIDEO_PARAM_PROFILELEVELTYPE m_profile_lvl; + OMX_U32 m_profile; + + //variables to handle dynamic buffer mode + bool dynamic_buf_mode; + struct dynamic_buf_list *out_dynamic_list; + OMX_U32 m_reconfig_width; + OMX_U32 m_reconfig_height; + bool m_smoothstreaming_mode; + + bool m_input_pass_buffer_fd; + DescribeColorAspectsParams m_client_color_space; + DescribeColorAspectsParams m_internal_color_space; + + // HDRStaticInfo defined in HardwareAPI.h + DescribeHDRStaticInfoParams m_client_hdr_info; + DescribeHDRStaticInfoParams m_internal_hdr_info; + bool m_change_client_hdr_info; + pthread_mutex_t m_hdr_info_client_lock; + + OMX_U32 operating_frame_rate; + bool high_fps; + + OMX_U32 m_smoothstreaming_width; + OMX_U32 m_smoothstreaming_height; + OMX_ERRORTYPE enable_smoothstreaming(); + OMX_ERRORTYPE enable_adaptive_playback(unsigned long width, unsigned long height); + bool is_thulium_v1; + bool m_disable_ubwc_mode; + bool m_disable_split_mode; + OMX_U32 m_downscalar_width; + OMX_U32 m_downscalar_height; + int decide_downscalar(); + int enable_downscalar(); + int disable_downscalar(); + + unsigned int m_fill_output_msg; + bool client_set_fps; + unsigned int stereo_output_mode; + class allocate_color_convert_buf + { + public: + allocate_color_convert_buf(); + ~allocate_color_convert_buf(); + void set_vdec_client(void *); + void update_client(); + bool set_color_format(OMX_COLOR_FORMATTYPE dest_color_format); + bool get_color_format(OMX_COLOR_FORMATTYPE &dest_color_format); + bool update_buffer_req(); + bool get_buffer_req(unsigned int &buffer_size); + OMX_ERRORTYPE set_buffer_req(OMX_U32 buffer_size, OMX_U32 actual_count); + OMX_BUFFERHEADERTYPE* get_il_buf_hdr(); + OMX_BUFFERHEADERTYPE* get_il_buf_hdr(OMX_BUFFERHEADERTYPE *input_hdr); + OMX_BUFFERHEADERTYPE* get_dr_buf_hdr(OMX_BUFFERHEADERTYPE *input_hdr); + OMX_BUFFERHEADERTYPE* convert(OMX_BUFFERHEADERTYPE *header); + OMX_BUFFERHEADERTYPE* queue_buffer(OMX_BUFFERHEADERTYPE *header); + OMX_ERRORTYPE allocate_buffers_color_convert(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr,OMX_U32 port,OMX_PTR appData, + OMX_U32 bytes); + OMX_ERRORTYPE free_output_buffer(OMX_BUFFERHEADERTYPE *bufferHdr); + bool is_color_conversion_enabled() {return enabled;} + private: +#define MAX_COUNT MAX_NUM_INPUT_OUTPUT_BUFFERS + omx_vdec *omx; + bool enabled; + OMX_COLOR_FORMATTYPE ColorFormat; + void init_members(); + bool color_convert_mode; + ColorConvertFormat dest_format; + class omx_c2d_conv c2d; + unsigned int allocated_count; + unsigned int buffer_size_req; + unsigned int buffer_alignment_req; + OMX_U32 m_c2d_width; + OMX_U32 m_c2d_height; + OMX_QCOM_PLATFORM_PRIVATE_LIST m_platform_list_client[MAX_COUNT]; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY m_platform_entry_client[MAX_COUNT]; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO m_pmem_info_client[MAX_COUNT]; + OMX_BUFFERHEADERTYPE m_out_mem_ptr_client[MAX_COUNT]; +#ifdef USE_ION + struct vdec_ion op_buf_ion_info[MAX_COUNT]; +#endif + unsigned char *pmem_baseaddress[MAX_COUNT]; + int pmem_fd[MAX_COUNT]; + struct vidc_heap { + sp<MemoryHeapBase> video_heap_ptr; + }; + struct vidc_heap m_heap_ptr[MAX_COUNT]; + + OMX_ERRORTYPE cache_ops(unsigned int index, unsigned int cmd); + inline OMX_ERRORTYPE cache_clean_buffer(unsigned int index) { + return cache_ops(index, ION_IOC_CLEAN_CACHES); + } + OMX_ERRORTYPE cache_clean_invalidate_buffer(unsigned int index) { + return cache_ops(index, ION_IOC_CLEAN_INV_CACHES); + } + }; +#if defined (_MSM8960_) || defined (_MSM8974_) + allocate_color_convert_buf client_buffers; +#endif + struct video_decoder_capability m_decoder_capability; + struct debug_cap m_debug; + int log_input_buffers(const char *, int); + int log_output_buffers(OMX_BUFFERHEADERTYPE *); +#ifdef _MSM8974_ + void send_codec_config(); +#endif + OMX_TICKS m_last_rendered_TS; + volatile int32_t m_queued_codec_config_count; + OMX_U32 current_perf_level; + bool secure_scaling_to_non_secure_opb; + bool m_force_compressed_for_dpb; + bool m_is_display_session; + class perf_lock { + private: + pthread_mutex_t mlock; + + public: + perf_lock() { + pthread_mutex_init(&mlock, NULL); + } + + ~perf_lock() { + pthread_mutex_destroy(&mlock); + } + + void lock() { + pthread_mutex_lock(&mlock); + } + + void unlock() { + pthread_mutex_unlock(&mlock); + } + }; + + class perf_control { + // 2 cores will be requested if framerate is beyond 45 fps + static const int MIN_FRAME_DURATION_FOR_PERF_REQUEST_US = (1e6 / 45); + typedef int (*perf_lock_acquire_t)(int, int, int*, int); + typedef int (*perf_lock_release_t)(int); + + private: + void *m_perf_lib; + int m_perf_handle; + perf_lock_acquire_t m_perf_lock_acquire; + perf_lock_release_t m_perf_lock_release; + bool load_lib(); + struct mpctl_stats { + int vid_inst_count; + bool vid_acquired; + int vid_disp_handle; + }; + static struct mpctl_stats mpctl_obj; + static perf_lock m_perf_lock; + + public: + perf_control(); + ~perf_control(); + void request_cores(int frame_duration_us); + void send_hint_to_mpctl(bool state); + }; + perf_control m_perf_control; + + static OMX_COLOR_FORMATTYPE getPreferredColorFormatNonSurfaceMode(OMX_U32 index) { + //On Android, we default to standard YUV formats for non-surface use-cases + //where apps prefer known color formats. + OMX_COLOR_FORMATTYPE formatsNonSurfaceMode[] = { + [0] = OMX_COLOR_FormatYUV420SemiPlanar, + [1] = OMX_COLOR_FormatYUV420Planar, + [2] = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m, + [3] = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView, + [4] = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed, + }; + return (index < sizeof(formatsNonSurfaceMode) / sizeof(OMX_COLOR_FORMATTYPE)) ? + formatsNonSurfaceMode[index] : OMX_COLOR_FormatMax; + } + + OMX_COLOR_FORMATTYPE getPreferredColorFormatDefaultMode(OMX_U32 index) { + //for surface mode (normal playback), advertise native/accelerated formats first + OMX_COLOR_FORMATTYPE format = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + + if (!m_disable_ubwc_mode) { + OMX_COLOR_FORMATTYPE formatsDefault[] = { + [0] = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed, + [1] = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m, + [2] = OMX_COLOR_FormatYUV420SemiPlanar, + [3] = OMX_COLOR_FormatYUV420Planar, + [4] = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView, + }; + format = (index < sizeof(formatsDefault) / sizeof(OMX_COLOR_FORMATTYPE)) ? + formatsDefault[index] : OMX_COLOR_FormatMax; + } else { + OMX_COLOR_FORMATTYPE formatsDefault[] = { + [0] = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m, + [1] = OMX_COLOR_FormatYUV420SemiPlanar, + [2] = OMX_COLOR_FormatYUV420Planar, + [3] = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView, + }; + format = (index < sizeof(formatsDefault) / sizeof(OMX_COLOR_FORMATTYPE)) ? + formatsDefault[index] : OMX_COLOR_FormatMax; + } + return format; + } + + static OMX_ERRORTYPE describeColorFormat(OMX_PTR params); + void prefetchNewBuffers(); + + class client_extradata_info { + private: + int fd; + OMX_U32 total_size; + OMX_U32 size; + void *vaddr; + public: + client_extradata_info() { + fd = -1; + size = 0; + total_size = 0; + vaddr = NULL; + } + + void reset() { + if (vaddr) { + munmap(vaddr, total_size); + vaddr = NULL; + } + if (fd != -1) { + close(fd); + fd = -1; + } + } + + ~client_extradata_info() { + reset(); + } + + bool set_extradata_info(int fd, OMX_U32 total_size, OMX_U32 size) { + reset(); + this->fd = fd; + this->size = size; + this->total_size = total_size; + vaddr = (OMX_U8*)mmap(0, total_size, + PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (vaddr == MAP_FAILED) { + vaddr = NULL; + reset(); + return false; + } + return true; + } + + OMX_U8 *getBase() const { + return (OMX_U8 *)vaddr; + } + + OMX_U32 getSize() const { + return size; + } + }; + client_extradata_info m_client_extradata_info; +}; + +#ifdef _MSM8974_ +enum instance_state { + MSM_VIDC_CORE_UNINIT_DONE = 0x0001, + MSM_VIDC_CORE_INIT, + MSM_VIDC_CORE_INIT_DONE, + MSM_VIDC_OPEN, + MSM_VIDC_OPEN_DONE, + MSM_VIDC_LOAD_RESOURCES, + MSM_VIDC_LOAD_RESOURCES_DONE, + MSM_VIDC_START, + MSM_VIDC_START_DONE, + MSM_VIDC_STOP, + MSM_VIDC_STOP_DONE, + MSM_VIDC_RELEASE_RESOURCES, + MSM_VIDC_RELEASE_RESOURCES_DONE, + MSM_VIDC_CLOSE, + MSM_VIDC_CLOSE_DONE, + MSM_VIDC_CORE_UNINIT, +}; + +enum vidc_resposes_id { + MSM_VIDC_DECODER_FLUSH_DONE = 0x11, + MSM_VIDC_DECODER_EVENT_CHANGE, +}; + +#endif // _MSM8974_ + +#endif // __OMX_VDEC_H__ diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_vdec_hevc.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_vdec_hevc.h new file mode 100644 index 0000000..24b6afa --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_vdec_hevc.h @@ -0,0 +1,934 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2013-2016, 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. +--------------------------------------------------------------------------*/ +#ifndef __OMX_VDEC_HEVC_H__ +#define __OMX_VDEC_HEVC_H__ +/*============================================================================ + O p e n M A X Component + Video Decoder + +*//** @file comx_vdec_hevc.h + This module contains the class definition for openMAX decoder component. + +*//*========================================================================*/ + +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <cstddef> + +static ptrdiff_t x; + +#ifdef _ANDROID_ +#ifdef MAX_RES_720P +#define LOG_TAG "OMX-VDEC-720P" +#elif MAX_RES_1080P +#define LOG_TAG "OMX-VDEC-1080P" +#else +#define LOG_TAG "OMX-VDEC" +#endif + +#ifdef USE_ION +#include <linux/msm_ion.h> +#endif +#include <binder/MemoryHeapBase.h> +#include <ui/ANativeObjectBase.h> +extern "C" { +#include <utils/Log.h> +} +#include <linux/videodev2.h> +#include <poll.h> +#include "hevc_utils.h" +#define TIMEOUT 5000 + +#endif // _ANDROID_ + + +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) +#include <media/hardware/HardwareAPI.h> +#endif + +#include <unistd.h> + +#if defined (_ANDROID_ICS_) +#include <gralloc_priv.h> +#endif + +#include <pthread.h> +#ifndef PC_DEBUG +#include <semaphore.h> +#endif +#include "OMX_Core.h" +#include "OMX_QCOMExtns.h" +#include "qc_omx_component.h" +#include <linux/msm_vidc_dec.h> +#include <media/msm_vidc.h> +#include "frameparser.h" +#ifdef MAX_RES_1080P +#include "mp4_utils.h" +#endif +#include <linux/android_pmem.h> +#include "extra_data_handler.h" +#include "ts_parser.h" +#include "vidc_color_converter.h" +#include "vidc_debug.h" +extern "C" { + OMX_API void * get_omx_component_factory_fn(void); +} + +#ifdef _ANDROID_ +using namespace android; +#ifdef USE_ION +class VideoHeap : public MemoryHeapBase +{ + public: + VideoHeap(int devicefd, size_t size, void* base,ion_user_handle_t handle,int mapfd); + virtual ~VideoHeap() {} + private: + int m_ion_device_fd; + ion_user_handle_t m_ion_handle; +}; +#else +// local pmem heap object +class VideoHeap : public MemoryHeapBase +{ + public: + VideoHeap(int fd, size_t size, void* base); + virtual ~VideoHeap() {} +}; +#endif +#endif // _ANDROID_ +////////////////////////////////////////////////////////////////////////////// +// Module specific globals +////////////////////////////////////////////////////////////////////////////// +#define OMX_SPEC_VERSION 0x00000101 + + +////////////////////////////////////////////////////////////////////////////// +// Macros +////////////////////////////////////////////////////////////////////////////// +#define PrintFrameHdr(bufHdr) DEBUG_PRINT("bufHdr %x buf %x size %d TS %d\n",\ + (unsigned) bufHdr,\ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->pBuffer,\ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFilledLen,\ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nTimeStamp) + +// BitMask Management logic +#define BITS_PER_BYTE 32 +#define BITMASK_SIZE(mIndex) (((mIndex) + BITS_PER_BYTE - 1)/BITS_PER_BYTE) +#define BITMASK_OFFSET(mIndex) ((mIndex)/BITS_PER_BYTE) +#define BITMASK_FLAG(mIndex) (1 << ((mIndex) % BITS_PER_BYTE)) +#define BITMASK_CLEAR(mArray,mIndex) (mArray)[BITMASK_OFFSET(mIndex)] \ + &= ~(BITMASK_FLAG(mIndex)) +#define BITMASK_SET(mArray,mIndex) (mArray)[BITMASK_OFFSET(mIndex)] \ + |= BITMASK_FLAG(mIndex) +#define BITMASK_PRESENT(mArray,mIndex) ((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) +#define BITMASK_ABSENT(mArray,mIndex) (((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) == 0x0) +#define BITMASK_PRESENT(mArray,mIndex) ((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) +#define BITMASK_ABSENT(mArray,mIndex) (((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) == 0x0) + +#define OMX_CORE_CONTROL_CMDQ_SIZE 100 +#define OMX_CORE_QCIF_HEIGHT 144 +#define OMX_CORE_QCIF_WIDTH 176 +#define OMX_CORE_VGA_HEIGHT 480 +#define OMX_CORE_VGA_WIDTH 640 +#define OMX_CORE_WVGA_HEIGHT 480 +#define OMX_CORE_WVGA_WIDTH 800 +#define OMX_CORE_FWVGA_HEIGHT 480 +#define OMX_CORE_FWVGA_WIDTH 864 + +#define DESC_BUFFER_SIZE (8192 * 16) + +#ifdef _ANDROID_ +#define MAX_NUM_INPUT_OUTPUT_BUFFERS 32 +#endif + +#define OMX_FRAMEINFO_EXTRADATA 0x00010000 +#define OMX_INTERLACE_EXTRADATA 0x00020000 +#define OMX_TIMEINFO_EXTRADATA 0x00040000 +#define OMX_PORTDEF_EXTRADATA 0x00080000 +#define OMX_EXTNUSER_EXTRADATA 0x00100000 +#define DRIVER_EXTRADATA_MASK 0x0000FFFF + +#define OMX_INTERLACE_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_STREAMINTERLACEFORMAT) + 3)&(~3)) +#define OMX_FRAMEINFO_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_QCOM_EXTRADATA_FRAMEINFO) + 3)&(~3)) +#define OMX_PORTDEF_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_PARAM_PORTDEFINITIONTYPE) + 3)&(~3)) + +// Define next macro with required values to enable default extradata, +// VDEC_EXTRADATA_MB_ERROR_MAP +// OMX_INTERLACE_EXTRADATA +// OMX_FRAMEINFO_EXTRADATA +// OMX_TIMEINFO_EXTRADATA + +//#define DEFAULT_EXTRADATA (OMX_FRAMEINFO_EXTRADATA|OMX_INTERLACE_EXTRADATA) + +enum port_indexes { + OMX_CORE_INPUT_PORT_INDEX =0, + OMX_CORE_OUTPUT_PORT_INDEX =1 +}; +#ifdef USE_ION +struct vdec_ion { + int ion_device_fd; + struct ion_fd_data fd_ion_data; + struct ion_allocation_data ion_alloc_data; +}; +#endif + +#ifdef _MSM8974_ +struct extradata_buffer_info { + int buffer_size; + char* uaddr; + int count; + int size; +#ifdef USE_ION + struct vdec_ion ion; +#endif +}; +#endif + +struct video_driver_context { + int video_driver_fd; + enum vdec_codec decoder_format; + enum vdec_output_fromat output_format; + enum vdec_interlaced_format interlace; + enum vdec_output_order picture_order; + struct vdec_picsize video_resolution; + struct vdec_allocatorproperty ip_buf; + struct vdec_allocatorproperty op_buf; + struct vdec_bufferpayload *ptr_inputbuffer; + struct vdec_bufferpayload *ptr_outputbuffer; + struct vdec_output_frameinfo *ptr_respbuffer; +#ifdef USE_ION + struct vdec_ion *ip_buf_ion_info; + struct vdec_ion *op_buf_ion_info; + struct vdec_ion h264_mv; + struct vdec_ion meta_buffer; + struct vdec_ion meta_buffer_iommu; +#endif + struct vdec_framerate frame_rate; + unsigned extradata; + bool timestamp_adjust; + char kind[128]; + bool idr_only_decoding; + unsigned disable_dmx; +#ifdef _MSM8974_ + struct extradata_buffer_info extradata_info; + int num_planes; +#endif +}; + +// OMX video decoder class +class omx_vdec: public qc_omx_component +{ + + public: + omx_vdec(); // constructor + virtual ~omx_vdec(); // destructor + + static int async_message_process (void *context, void* message); + static void process_event_cb(void *ctxt,unsigned char id); + + OMX_ERRORTYPE allocate_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes + ); + + + OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp); + + OMX_ERRORTYPE component_init(OMX_STRING role); + + OMX_ERRORTYPE component_role_enum( + OMX_HANDLETYPE hComp, + OMX_U8 *role, + OMX_U32 index + ); + + OMX_ERRORTYPE component_tunnel_request( + OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_HANDLETYPE peerComponent, + OMX_U32 peerPort, + OMX_TUNNELSETUPTYPE *tunnelSetup + ); + + OMX_ERRORTYPE empty_this_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ); + + + + OMX_ERRORTYPE fill_this_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ); + + + OMX_ERRORTYPE free_buffer( + OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_BUFFERHEADERTYPE *buffer + ); + + OMX_ERRORTYPE get_component_version( + OMX_HANDLETYPE hComp, + OMX_STRING componentName, + OMX_VERSIONTYPE *componentVersion, + OMX_VERSIONTYPE *specVersion, + OMX_UUIDTYPE *componentUUID + ); + + OMX_ERRORTYPE get_config( + OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData + ); + + OMX_ERRORTYPE get_extension_index( + OMX_HANDLETYPE hComp, + OMX_STRING paramName, + OMX_INDEXTYPE *indexType + ); + + OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE get_state(OMX_HANDLETYPE hComp, + OMX_STATETYPE *state); + + + + OMX_ERRORTYPE send_command(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + + + OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE hComp, + OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData); + + OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + + OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); + + OMX_ERRORTYPE use_input_heap_buffers( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8* buffer); + + OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + void * eglImage); + void complete_pending_buffer_done_cbs(); + struct video_driver_context drv_ctx; +#ifdef _MSM8974_ + OMX_ERRORTYPE allocate_extradata(); + void free_extradata(); + void update_resolution(int width, int height); +#endif + int m_pipe_in; + int m_pipe_out; + pthread_t msg_thread_id; + pthread_t async_thread_id; + bool is_component_secure(); + + private: + // Bit Positions + enum flags_bit_positions { + // Defer transition to IDLE + OMX_COMPONENT_IDLE_PENDING =0x1, + // Defer transition to LOADING + OMX_COMPONENT_LOADING_PENDING =0x2, + // First Buffer Pending + OMX_COMPONENT_FIRST_BUFFER_PENDING =0x3, + // Second Buffer Pending + OMX_COMPONENT_SECOND_BUFFER_PENDING =0x4, + // Defer transition to Enable + OMX_COMPONENT_INPUT_ENABLE_PENDING =0x5, + // Defer transition to Enable + OMX_COMPONENT_OUTPUT_ENABLE_PENDING =0x6, + // Defer transition to Disable + OMX_COMPONENT_INPUT_DISABLE_PENDING =0x7, + // Defer transition to Disable + OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x8, + //defer flush notification + OMX_COMPONENT_OUTPUT_FLUSH_PENDING =0x9, + OMX_COMPONENT_INPUT_FLUSH_PENDING =0xA, + OMX_COMPONENT_PAUSE_PENDING =0xB, + OMX_COMPONENT_EXECUTE_PENDING =0xC, + OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING =0xD, + OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED=0xE + }; + + // Deferred callback identifiers + enum { + //Event Callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_EVENT = 0x1, + //Buffer Done callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_BUFFER_DONE = 0x2, + //Frame Done callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_FRAME_DONE = 0x3, + //Buffer Done callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_FTB = 0x4, + //Frame Done callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_ETB = 0x5, + //Command + OMX_COMPONENT_GENERATE_COMMAND = 0x6, + //Push-Pending Buffers + OMX_COMPONENT_PUSH_PENDING_BUFS = 0x7, + // Empty Buffer Done callbacks + OMX_COMPONENT_GENERATE_EBD = 0x8, + //Flush Event Callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_EVENT_FLUSH = 0x9, + OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH = 0x0A, + OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH = 0x0B, + OMX_COMPONENT_GENERATE_FBD = 0xc, + OMX_COMPONENT_GENERATE_START_DONE = 0xD, + OMX_COMPONENT_GENERATE_PAUSE_DONE = 0xE, + OMX_COMPONENT_GENERATE_RESUME_DONE = 0xF, + OMX_COMPONENT_GENERATE_STOP_DONE = 0x10, + OMX_COMPONENT_GENERATE_HARDWARE_ERROR = 0x11, + OMX_COMPONENT_GENERATE_ETB_ARBITRARY = 0x12, + OMX_COMPONENT_GENERATE_PORT_RECONFIG = 0x13, + OMX_COMPONENT_GENERATE_EOS_DONE = 0x14, + OMX_COMPONENT_GENERATE_INFO_PORT_RECONFIG = 0x15, + OMX_COMPONENT_GENERATE_INFO_FIELD_DROPPED = 0x16, + }; + + enum vc1_profile_type { + VC1_SP_MP_RCV = 1, + VC1_AP = 2 + }; + +#ifdef _MSM8974_ + enum v4l2_ports { + CAPTURE_PORT, + OUTPUT_PORT, + MAX_PORT + }; +#endif + + struct omx_event { + unsigned param1; + unsigned param2; + unsigned id; + }; + + struct omx_cmd_queue { + omx_event m_q[OMX_CORE_CONTROL_CMDQ_SIZE]; + unsigned m_read; + unsigned m_write; + unsigned m_size; + + omx_cmd_queue(); + ~omx_cmd_queue(); + bool insert_entry(unsigned p1, unsigned p2, unsigned id); + bool pop_entry(unsigned *p1,unsigned *p2, unsigned *id); + // get msgtype of the first ele from the queue + unsigned get_q_msg_type(); + + }; + +#ifdef _ANDROID_ + struct ts_entry { + OMX_TICKS timestamp; + bool valid; + }; + + struct ts_arr_list { + ts_entry m_ts_arr_list[MAX_NUM_INPUT_OUTPUT_BUFFERS]; + + ts_arr_list(); + ~ts_arr_list(); + + bool insert_ts(OMX_TICKS ts); + bool pop_min_ts(OMX_TICKS &ts); + bool reset_ts_list(); + }; +#endif + + struct desc_buffer_hdr { + OMX_U8 *buf_addr; + OMX_U32 desc_data_size; + }; + bool allocate_done(void); + bool allocate_input_done(void); + bool allocate_output_done(void); + + OMX_ERRORTYPE free_input_buffer(OMX_BUFFERHEADERTYPE *bufferHdr); + OMX_ERRORTYPE free_input_buffer(unsigned int bufferindex, + OMX_BUFFERHEADERTYPE *pmem_bufferHdr); + OMX_ERRORTYPE free_output_buffer(OMX_BUFFERHEADERTYPE *bufferHdr); + void free_output_buffer_header(); + void free_input_buffer_header(); + + OMX_ERRORTYPE allocate_input_heap_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + + OMX_ERRORTYPE allocate_input_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + OMX_ERRORTYPE allocate_output_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port,OMX_PTR appData, + OMX_U32 bytes); + OMX_ERRORTYPE use_output_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); +#ifdef MAX_RES_720P + OMX_ERRORTYPE get_supported_profile_level_for_720p(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType); +#endif +#ifdef MAX_RES_1080P + OMX_ERRORTYPE get_supported_profile_level_for_1080p(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType); +#endif + + OMX_ERRORTYPE allocate_desc_buffer(OMX_U32 index); + OMX_ERRORTYPE allocate_output_headers(); + bool execute_omx_flush(OMX_U32); + bool execute_output_flush(); + bool execute_input_flush(); + OMX_ERRORTYPE empty_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer); + + OMX_ERRORTYPE fill_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer); + OMX_ERRORTYPE empty_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + OMX_ERRORTYPE empty_this_buffer_proxy_arbitrary(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ); + + OMX_ERRORTYPE push_input_buffer (OMX_HANDLETYPE hComp); + OMX_ERRORTYPE push_input_sc_codec (OMX_HANDLETYPE hComp); + OMX_ERRORTYPE push_input_h264 (OMX_HANDLETYPE hComp); + OMX_ERRORTYPE push_input_hevc (OMX_HANDLETYPE hComp); + OMX_ERRORTYPE push_input_vc1 (OMX_HANDLETYPE hComp); + + OMX_ERRORTYPE fill_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + bool release_done(); + + bool release_output_done(); + bool release_input_done(); + OMX_ERRORTYPE get_buffer_req(vdec_allocatorproperty *buffer_prop); + OMX_ERRORTYPE set_buffer_req(vdec_allocatorproperty *buffer_prop); + OMX_ERRORTYPE start_port_reconfig(); + OMX_ERRORTYPE update_picture_resolution(); + int stream_off(OMX_U32 port); + void adjust_timestamp(OMX_S64 &act_timestamp); + void set_frame_rate(OMX_S64 act_timestamp); + void handle_extradata_secure(OMX_BUFFERHEADERTYPE *p_buf_hdr); + void handle_extradata(OMX_BUFFERHEADERTYPE *p_buf_hdr); + void print_debug_extradata(OMX_OTHER_EXTRADATATYPE *extra); +#ifdef _MSM8974_ + void append_interlace_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 interlaced_format_type); + OMX_ERRORTYPE enable_extradata(OMX_U32 requested_extradata, bool is_internal, + bool enable = true); + void append_frame_info_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 num_conceal_mb, + OMX_U32 picture_type, + OMX_U32 frame_rate, + struct msm_vidc_panscan_window_payload *panscan_payload, + struct vdec_aspectratioinfo *aspect_ratio_info); +#else + void append_interlace_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 interlaced_format_type, OMX_U32 buf_index); + OMX_ERRORTYPE enable_extradata(OMX_U32 requested_extradata, bool enable = true); +#endif + void append_frame_info_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 num_conceal_mb, + OMX_U32 picture_type, + OMX_S64 timestamp, + OMX_U32 frame_rate, + struct vdec_aspectratioinfo *aspect_ratio_info); + void fill_aspect_ratio_info(struct vdec_aspectratioinfo *aspect_ratio_info, + OMX_QCOM_EXTRADATA_FRAMEINFO *frame_info); + void append_terminator_extradata(OMX_OTHER_EXTRADATATYPE *extra); + OMX_ERRORTYPE update_portdef(OMX_PARAM_PORTDEFINITIONTYPE *portDefn); + void append_portdef_extradata(OMX_OTHER_EXTRADATATYPE *extra); + void append_extn_extradata(OMX_OTHER_EXTRADATATYPE *extra, OMX_OTHER_EXTRADATATYPE *p_extn); + void append_user_extradata(OMX_OTHER_EXTRADATATYPE *extra, OMX_OTHER_EXTRADATATYPE *p_user); + void insert_demux_addr_offset(OMX_U32 address_offset); + void extract_demux_addr_offsets(OMX_BUFFERHEADERTYPE *buf_hdr); + OMX_ERRORTYPE handle_demux_data(OMX_BUFFERHEADERTYPE *buf_hdr); + OMX_U32 count_MB_in_extradata(OMX_OTHER_EXTRADATATYPE *extra); + + bool align_pmem_buffers(int pmem_fd, OMX_U32 buffer_size, + OMX_U32 alignment); +#ifdef USE_ION + int alloc_map_ion_memory(OMX_U32 buffer_size, + OMX_U32 alignment, struct ion_allocation_data *alloc_data, + struct ion_fd_data *fd_data,int flag); + void free_ion_memory(struct vdec_ion *buf_ion_info); +#endif + + + OMX_ERRORTYPE send_command_proxy(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + bool post_event( unsigned int p1, + unsigned int p2, + unsigned int id + ); + inline int clip2(int x) { + x = x -1; + x = x | x >> 1; + x = x | x >> 2; + x = x | x >> 4; + x = x | x >> 16; + x = x + 1; + return x; + } + +#ifdef MAX_RES_1080P + OMX_ERRORTYPE vdec_alloc_h264_mv(); + void vdec_dealloc_h264_mv(); + OMX_ERRORTYPE vdec_alloc_meta_buffers(); + void vdec_dealloc_meta_buffers(); +#endif + + inline void omx_report_error () { + if (m_cb.EventHandler && !m_error_propogated) { + ALOGE("\nERROR: Sending OMX_EventError to Client"); + m_error_propogated = true; + m_cb.EventHandler(&m_cmp,m_app_data, + OMX_EventError,OMX_ErrorHardware,0,NULL); + } + } +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) + OMX_ERRORTYPE use_android_native_buffer(OMX_IN OMX_HANDLETYPE hComp, OMX_PTR data); +#endif +#if defined (_ANDROID_ICS_) + struct nativebuffer { + native_handle_t *nativehandle; + private_handle_t *privatehandle; + int inuse; + }; + nativebuffer native_buffer[MAX_NUM_INPUT_OUTPUT_BUFFERS]; +#endif + + + //************************************************************* + //*******************MEMBER VARIABLES ************************* + //************************************************************* + pthread_mutex_t m_lock; + pthread_mutex_t c_lock; + //sem to handle the minimum procesing of commands + sem_t m_cmd_lock; + bool m_error_propogated; + // compression format + OMX_VIDEO_CODINGTYPE eCompressionFormat; + // OMX State + OMX_STATETYPE m_state; + // Application data + OMX_PTR m_app_data; + // Application callbacks + OMX_CALLBACKTYPE m_cb; + OMX_PRIORITYMGMTTYPE m_priority_mgm ; + OMX_PARAM_BUFFERSUPPLIERTYPE m_buffer_supplier; + // fill this buffer queue + omx_cmd_queue m_ftb_q; + // Command Q for rest of the events + omx_cmd_queue m_cmd_q; + omx_cmd_queue m_etb_q; + // Input memory pointer + OMX_BUFFERHEADERTYPE *m_inp_mem_ptr; + // Output memory pointer + OMX_BUFFERHEADERTYPE *m_out_mem_ptr; + // number of input bitstream error frame count + unsigned int m_inp_err_count; +#ifdef _ANDROID_ + // Timestamp list + ts_arr_list m_timestamp_list; +#endif + + bool input_flush_progress; + bool output_flush_progress; + bool input_use_buffer; + bool output_use_buffer; + bool ouput_egl_buffers; + OMX_BOOL m_use_output_pmem; + OMX_BOOL m_out_mem_region_smi; + OMX_BOOL m_out_pvt_entry_pmem; + + int pending_input_buffers; + int pending_output_buffers; + // bitmask array size for output side + unsigned int m_out_bm_count; + // bitmask array size for input side + unsigned int m_inp_bm_count; + //Input port Populated + OMX_BOOL m_inp_bPopulated; + //Output port Populated + OMX_BOOL m_out_bPopulated; + // encapsulate the waiting states. + unsigned int m_flags; + +#ifdef _ANDROID_ + // Heap pointer to frame buffers + struct vidc_heap { + sp<MemoryHeapBase> video_heap_ptr; + }; + struct vidc_heap *m_heap_ptr; + unsigned int m_heap_count; +#endif //_ANDROID_ + // store I/P PORT state + OMX_BOOL m_inp_bEnabled; + // store O/P PORT state + OMX_BOOL m_out_bEnabled; + OMX_U32 m_in_alloc_cnt; + OMX_U8 m_cRole[OMX_MAX_STRINGNAME_SIZE]; + // Platform specific details + OMX_QCOM_PLATFORM_PRIVATE_LIST *m_platform_list; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY *m_platform_entry; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *m_pmem_info; + // SPS+PPS sent as part of set_config + OMX_VENDOR_EXTRADATATYPE m_vendor_config; + + /*Variables for arbitrary Byte parsing support*/ + frame_parse m_frame_parser; + omx_cmd_queue m_input_pending_q; + omx_cmd_queue m_input_free_q; + bool arbitrary_bytes; + OMX_BUFFERHEADERTYPE h264_scratch; + OMX_BUFFERHEADERTYPE *psource_frame; + OMX_BUFFERHEADERTYPE *pdest_frame; + OMX_BUFFERHEADERTYPE *m_inp_heap_ptr; + OMX_BUFFERHEADERTYPE **m_phdr_pmem_ptr; + unsigned int m_heap_inp_bm_count; + codec_type codec_type_parse; + bool first_frame_meta; + unsigned frame_count; + unsigned nal_count; + unsigned nal_length; + bool look_ahead_nal; + int first_frame; + unsigned char *first_buffer; + int first_frame_size; + unsigned char m_hwdevice_name[80]; + FILE *m_device_file_ptr; + enum vc1_profile_type m_vc1_profile; + OMX_S64 h264_last_au_ts; + OMX_U32 h264_last_au_flags; + OMX_U32 m_demux_offsets[8192]; + OMX_U32 m_demux_entries; + OMX_U32 m_disp_hor_size; + OMX_U32 m_disp_vert_size; + + OMX_S64 prev_ts; + bool rst_prev_ts; + OMX_U32 frm_int; + + struct vdec_allocatorproperty op_buf_rcnfg; + bool in_reconfig; + OMX_NATIVE_WINDOWTYPE m_display_id; + h264_stream_parser *h264_parser; + OMX_U32 client_extradata; +#ifdef _ANDROID_ + bool m_debug_timestamp; + bool perf_flag; + OMX_U32 proc_frms, latency; + perf_metrics fps_metrics; + perf_metrics dec_time; + bool m_enable_android_native_buffers; + bool m_use_android_native_buffers; + bool m_debug_extradata; + bool m_debug_concealedmb; +#endif +#ifdef MAX_RES_1080P + MP4_Utils mp4_headerparser; +#endif + + struct h264_mv_buffer { + unsigned char* buffer; + int size; + int count; + int pmem_fd; + int offset; + }; + h264_mv_buffer h264_mv_buff; + + struct meta_buffer { + unsigned char* buffer; + int size; + int count; + int pmem_fd; + int pmem_fd_iommu; + int offset; + }; + meta_buffer meta_buff; + extra_data_handler extra_data_handle; + OMX_PARAM_PORTDEFINITIONTYPE m_port_def; + omx_time_stamp_reorder time_stamp_dts; + desc_buffer_hdr *m_desc_buffer_ptr; + bool secure_mode; + bool external_meta_buffer; + bool external_meta_buffer_iommu; + OMX_QCOM_EXTRADATA_FRAMEINFO *m_extradata; + bool codec_config_flag; +#ifdef _MSM8974_ + int capture_capability; + int output_capability; + bool streaming[MAX_PORT]; + OMX_CONFIG_RECTTYPE rectangle; +#endif + bool m_power_hinted; + OMX_ERRORTYPE power_module_register(); + OMX_ERRORTYPE power_module_deregister(); + bool msg_thread_created; + bool async_thread_created; + + unsigned int m_fill_output_msg; + class allocate_color_convert_buf + { + public: + allocate_color_convert_buf(); + ~allocate_color_convert_buf(); + void set_vdec_client(void *); + void update_client(); + bool set_color_format(OMX_COLOR_FORMATTYPE dest_color_format); + bool get_color_format(OMX_COLOR_FORMATTYPE &dest_color_format); + bool update_buffer_req(); + bool get_buffer_req(unsigned int &buffer_size); + OMX_BUFFERHEADERTYPE* get_il_buf_hdr(); + OMX_BUFFERHEADERTYPE* get_il_buf_hdr(OMX_BUFFERHEADERTYPE *input_hdr); + OMX_BUFFERHEADERTYPE* get_dr_buf_hdr(OMX_BUFFERHEADERTYPE *input_hdr); + OMX_BUFFERHEADERTYPE* convert(OMX_BUFFERHEADERTYPE *header); + OMX_BUFFERHEADERTYPE* queue_buffer(OMX_BUFFERHEADERTYPE *header); + OMX_ERRORTYPE allocate_buffers_color_convert(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr,OMX_U32 port,OMX_PTR appData, + OMX_U32 bytes); + OMX_ERRORTYPE free_output_buffer(OMX_BUFFERHEADERTYPE *bufferHdr); + private: +#define MAX_COUNT 32 + omx_vdec *omx; + bool enabled; + OMX_COLOR_FORMATTYPE ColorFormat; + void init_members(); + bool color_convert_mode; + ColorConvertFormat dest_format; + class omx_c2d_conv c2d; + unsigned int allocated_count; + unsigned int buffer_size_req; + unsigned int buffer_alignment_req; + OMX_QCOM_PLATFORM_PRIVATE_LIST m_platform_list_client[MAX_COUNT]; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY m_platform_entry_client[MAX_COUNT]; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO m_pmem_info_client[MAX_COUNT]; + OMX_BUFFERHEADERTYPE m_out_mem_ptr_client[MAX_COUNT]; +#ifdef USE_ION + struct vdec_ion op_buf_ion_info[MAX_COUNT]; +#endif + unsigned char *pmem_baseaddress[MAX_COUNT]; + int pmem_fd[MAX_COUNT]; + struct vidc_heap { + sp<MemoryHeapBase> video_heap_ptr; + }; + struct vidc_heap m_heap_ptr[MAX_COUNT]; + }; +#if defined (_MSM8960_) || defined (_MSM8974_) + allocate_color_convert_buf client_buffers; +#endif + HEVC_Utils mHEVCutils; +}; + +#ifdef _MSM8974_ +enum instance_state { + MSM_VIDC_CORE_UNINIT_DONE = 0x0001, + MSM_VIDC_CORE_INIT, + MSM_VIDC_CORE_INIT_DONE, + MSM_VIDC_OPEN, + MSM_VIDC_OPEN_DONE, + MSM_VIDC_LOAD_RESOURCES, + MSM_VIDC_LOAD_RESOURCES_DONE, + MSM_VIDC_START, + MSM_VIDC_START_DONE, + MSM_VIDC_STOP, + MSM_VIDC_STOP_DONE, + MSM_VIDC_RELEASE_RESOURCES, + MSM_VIDC_RELEASE_RESOURCES_DONE, + MSM_VIDC_CLOSE, + MSM_VIDC_CLOSE_DONE, + MSM_VIDC_CORE_UNINIT, +}; + +enum vidc_resposes_id { + MSM_VIDC_DECODER_FLUSH_DONE = 0x11, + MSM_VIDC_DECODER_EVENT_CHANGE, +}; + +#endif // _MSM8974_ + +#endif // __OMX_VDEC_H__ diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_vdec_hevc_swvdec.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_vdec_hevc_swvdec.h new file mode 100644 index 0000000..118e64b --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/omx_vdec_hevc_swvdec.h @@ -0,0 +1,1104 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2013-2016, 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. +--------------------------------------------------------------------------*/ +#ifndef __OMX_VDEC_HEVC_H__ +#define __OMX_VDEC_HEVC_H__ +/*============================================================================ + O p e n M A X Component + Video Decoder + +*//** @file comx_vdec_hevc.h + This module contains the class definition for openMAX decoder component. + +*//*========================================================================*/ + +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <cstddef> + +#include "SwVdecTypes.h" +#include "SwVdecAPI.h" + +static ptrdiff_t x; + +#ifdef _ANDROID_ +#ifdef MAX_RES_720P +#define LOG_TAG "OMX-VDEC-720P" +#elif MAX_RES_1080P +#define LOG_TAG "OMX-VDEC-1080P" +#else +#define LOG_TAG "OMX-VDEC" +#endif + +#ifdef USE_ION +#include <linux/msm_ion.h> +#endif +#include <binder/MemoryHeapBase.h> +#include <ui/ANativeObjectBase.h> +extern "C"{ +#include <utils/Log.h> +} +#include <linux/videodev2.h> +#include <poll.h> +#include "hevc_utils.h" +#define TIMEOUT 5000 + +#else //_ANDROID_ +#define DEBUG_PRINT_LOW(fmt, ...) printf(fmt "\n", ##__VA_ARGS__) +#define DEBUG_PRINT_HIGH(fmt, ...) printf(fmt "\n", ##__VA_ARGS__) +#define DEBUG_PRINT_ERROR(fmt, ...) printf(fmt "\n", ##__VA_ARGS__) +#endif // _ANDROID_ + + +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) +#include <media/hardware/HardwareAPI.h> +#endif + +#include <unistd.h> + +#if defined (_ANDROID_ICS_) +#include <gralloc_priv.h> +#endif + +#include <pthread.h> +#ifndef PC_DEBUG +#include <semaphore.h> +#endif +#include "OMX_Core.h" +#include "OMX_QCOMExtns.h" +#include "OMX_Video.h" +#include "qc_omx_component.h" +#include <linux/msm_vidc_dec.h> +#include <media/msm_vidc.h> +#include "frameparser.h" +#ifdef MAX_RES_1080P +#include "mp4_utils.h" +#endif +#include <linux/android_pmem.h> +#include "extra_data_handler.h" +#include "ts_parser.h" +#include "vidc_color_converter.h" +#include "vidc_debug.h" +#ifdef _ANDROID_ +#include <cutils/properties.h> +#else +#define PROPERTY_VALUE_MAX 92 +#endif +extern "C" { + OMX_API void * get_omx_component_factory_fn(void); +} + +#ifdef _ANDROID_ + using namespace android; +#ifdef USE_ION + class VideoHeap : public MemoryHeapBase + { + public: + VideoHeap(int devicefd, size_t size, void* base,ion_user_handle_t handle,int mapfd); + virtual ~VideoHeap() {} + private: + int m_ion_device_fd; + ion_user_handle_t m_ion_handle; + }; +#else + // local pmem heap object + class VideoHeap : public MemoryHeapBase + { + public: + VideoHeap(int fd, size_t size, void* base); + virtual ~VideoHeap() {} + }; +#endif +#endif // _ANDROID_ +////////////////////////////////////////////////////////////////////////////// +// Module specific globals +////////////////////////////////////////////////////////////////////////////// +#define OMX_SPEC_VERSION 0x00000101 + + +////////////////////////////////////////////////////////////////////////////// +// Macros +////////////////////////////////////////////////////////////////////////////// +#define PrintFrameHdr(bufHdr) DEBUG_PRINT("bufHdr %x buf %x size %d TS %d\n",\ + (unsigned) bufHdr,\ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->pBuffer,\ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFilledLen,\ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nTimeStamp) + +// BitMask Management logic +#define BITS_PER_BYTE 32 +#define BITMASK_SIZE(mIndex) (((mIndex) + BITS_PER_BYTE - 1)/BITS_PER_BYTE) +#define BITMASK_OFFSET(mIndex) ((mIndex)/BITS_PER_BYTE) +#define BITMASK_FLAG(mIndex) (1 << ((mIndex) % BITS_PER_BYTE)) +#define BITMASK_CLEAR(mArray,mIndex) (mArray)[BITMASK_OFFSET(mIndex)] \ + &= ~(BITMASK_FLAG(mIndex)) +#define BITMASK_SET(mArray,mIndex) (mArray)[BITMASK_OFFSET(mIndex)] \ + |= BITMASK_FLAG(mIndex) +#define BITMASK_PRESENT(mArray,mIndex) ((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) +#define BITMASK_ABSENT(mArray,mIndex) (((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) == 0x0) +#define BITMASK_PRESENT(mArray,mIndex) ((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) +#define BITMASK_ABSENT(mArray,mIndex) (((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) == 0x0) + +#define OMX_CORE_CONTROL_CMDQ_SIZE 100 +#define OMX_CORE_QCIF_HEIGHT 144 +#define OMX_CORE_QCIF_WIDTH 176 +#define OMX_CORE_VGA_HEIGHT 480 +#define OMX_CORE_VGA_WIDTH 640 +#define OMX_CORE_WVGA_HEIGHT 480 +#define OMX_CORE_WVGA_WIDTH 800 +#define OMX_CORE_FWVGA_HEIGHT 480 +#define OMX_CORE_FWVGA_WIDTH 864 + +#define DESC_BUFFER_SIZE (8192 * 16) + +#ifdef _ANDROID_ +#define MAX_NUM_INPUT_OUTPUT_BUFFERS 32 +#endif + +#define OMX_FRAMEINFO_EXTRADATA 0x00010000 +#define OMX_INTERLACE_EXTRADATA 0x00020000 +#define OMX_TIMEINFO_EXTRADATA 0x00040000 +#define OMX_PORTDEF_EXTRADATA 0x00080000 +#define OMX_EXTNUSER_EXTRADATA 0x00100000 +#define DRIVER_EXTRADATA_MASK 0x0000FFFF + +#define OMX_INTERLACE_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_STREAMINTERLACEFORMAT) + 3)&(~3)) +#define OMX_FRAMEINFO_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_QCOM_EXTRADATA_FRAMEINFO) + 3)&(~3)) +#define OMX_PORTDEF_EXTRADATA_SIZE ((sizeof(OMX_OTHER_EXTRADATATYPE) +\ + sizeof(OMX_PARAM_PORTDEFINITIONTYPE) + 3)&(~3)) + +// Define next macro with required values to enable default extradata, +// VDEC_EXTRADATA_MB_ERROR_MAP +// OMX_INTERLACE_EXTRADATA +// OMX_FRAMEINFO_EXTRADATA +// OMX_TIMEINFO_EXTRADATA + +//#define DEFAULT_EXTRADATA (OMX_FRAMEINFO_EXTRADATA|OMX_INTERLACE_EXTRADATA) + +enum port_indexes +{ + OMX_CORE_INPUT_PORT_INDEX =0, + OMX_CORE_OUTPUT_PORT_INDEX =1 +}; + +enum interm_buffer_state +{ + WITH_COMPONENT = 0, + WITH_SWVDEC, + WITH_DSP +}; + +#ifdef USE_ION +struct vdec_ion +{ + int ion_device_fd; + struct ion_fd_data fd_ion_data; + struct ion_allocation_data ion_alloc_data; +}; +#endif + +#ifdef _MSM8974_ +struct extradata_buffer_info { + int buffer_size; + char* uaddr; + int count; + int size; +#ifdef USE_ION + struct vdec_ion ion; +#endif +}; +#endif + +struct video_driver_context +{ + int video_driver_fd; + enum vdec_codec decoder_format; + enum vdec_output_fromat output_format; + enum vdec_interlaced_format interlace; + enum vdec_output_order picture_order; + struct vdec_picsize video_resolution; + struct vdec_allocatorproperty ip_buf; + struct vdec_allocatorproperty op_buf; + struct vdec_bufferpayload *ptr_inputbuffer; + struct vdec_bufferpayload *ptr_outputbuffer; + struct vdec_output_frameinfo *ptr_respbuffer; + + struct vdec_allocatorproperty interm_op_buf; + struct vdec_bufferpayload *ptr_interm_outputbuffer; + struct vdec_output_frameinfo *ptr_interm_respbuffer; + +#ifdef USE_ION + struct vdec_ion *ip_buf_ion_info; + struct vdec_ion *op_buf_ion_info; + struct vdec_ion *interm_op_buf_ion_info; + struct vdec_ion h264_mv; + struct vdec_ion meta_buffer; + struct vdec_ion meta_buffer_iommu; +#endif + struct vdec_framerate frame_rate; + unsigned extradata; + bool timestamp_adjust; + char kind[128]; + bool idr_only_decoding; + unsigned disable_dmx; +#ifdef _MSM8974_ + struct extradata_buffer_info extradata_info; + int num_planes; +#endif +}; + +struct video_decoder_capability { + unsigned int min_width; + unsigned int max_width; + unsigned int min_height; + unsigned int max_height; +}; + +struct debug_cap { + bool in_buffer_log; + bool out_buffer_log; + bool im_buffer_log; + char infile_name[PROPERTY_VALUE_MAX + 36]; + char outfile_name[PROPERTY_VALUE_MAX + 36]; + char imbfile_name[PROPERTY_VALUE_MAX + 36]; + char log_loc[PROPERTY_VALUE_MAX]; + FILE *infile; + FILE *outfile; + FILE *imbfile; +}; + +struct dynamic_buf_list { + OMX_U32 fd; + OMX_U32 dup_fd; + OMX_U32 offset; + OMX_U32 ref_count; +}; + +// OMX video decoder class +class omx_vdec: public qc_omx_component +{ + +public: + omx_vdec(); // constructor + virtual ~omx_vdec(); // destructor + + static int async_message_process (void *context, void* message); + static void process_event_cb(void *ctxt,unsigned char id); + + OMX_ERRORTYPE allocate_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes + ); + + + OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp); + + OMX_ERRORTYPE component_init(OMX_STRING role); + + OMX_ERRORTYPE component_role_enum( + OMX_HANDLETYPE hComp, + OMX_U8 *role, + OMX_U32 index + ); + + OMX_ERRORTYPE component_tunnel_request( + OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_HANDLETYPE peerComponent, + OMX_U32 peerPort, + OMX_TUNNELSETUPTYPE *tunnelSetup + ); + + OMX_ERRORTYPE empty_this_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ); + + + + OMX_ERRORTYPE fill_this_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ); + + + OMX_ERRORTYPE free_buffer( + OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_BUFFERHEADERTYPE *buffer + ); + + OMX_ERRORTYPE get_component_version( + OMX_HANDLETYPE hComp, + OMX_STRING componentName, + OMX_VERSIONTYPE *componentVersion, + OMX_VERSIONTYPE *specVersion, + OMX_UUIDTYPE *componentUUID + ); + + OMX_ERRORTYPE get_config( + OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData + ); + + OMX_ERRORTYPE get_extension_index( + OMX_HANDLETYPE hComp, + OMX_STRING paramName, + OMX_INDEXTYPE *indexType + ); + + OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE get_state(OMX_HANDLETYPE hComp, + OMX_STATETYPE *state); + + + + OMX_ERRORTYPE send_command(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + + + OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE hComp, + OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData); + + OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + + OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); + + OMX_ERRORTYPE use_input_heap_buffers( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8* buffer); + + OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + void * eglImage); + void complete_pending_buffer_done_cbs(); + struct video_driver_context drv_ctx; +#ifdef _MSM8974_ + OMX_ERRORTYPE allocate_extradata(); + void free_extradata(); + int update_resolution(int width, int height, int stride, int scan_lines); + OMX_ERRORTYPE is_video_session_supported(); +#endif + int m_pipe_in; + int m_pipe_out; + pthread_t msg_thread_id; + pthread_t async_thread_id; + bool is_component_secure(); + + void buf_ref_add(int index, OMX_U32 fd, OMX_U32 offset); + void buf_ref_remove(OMX_U32 fd, OMX_U32 offset); + + static SWVDEC_STATUS swvdec_input_buffer_done_cb(SWVDEC_HANDLE pSwDec, SWVDEC_IPBUFFER *pIpBuffer, void *pClientHandle); + static SWVDEC_STATUS swvdec_fill_buffer_done_cb(SWVDEC_HANDLE pSwDec, SWVDEC_OPBUFFER *pOpBuffer, void *pClientHandle); + static SWVDEC_STATUS swvdec_handle_event_cb (SWVDEC_HANDLE pSwDec, SWVDEC_EVENTHANDLER* pEventHandler, void *pClientHandle); + void swvdec_input_buffer_done(SWVDEC_IPBUFFER *pIpBuffer); + void swvdec_fill_buffer_done(SWVDEC_OPBUFFER *pOpBuffer); + void swvdec_handle_event(SWVDEC_EVENTHANDLER *pEvent); + +private: + // Bit Positions + enum flags_bit_positions + { + // Defer transition to IDLE + OMX_COMPONENT_IDLE_PENDING =0x1, + // Defer transition to LOADING + OMX_COMPONENT_LOADING_PENDING =0x2, + // First Buffer Pending + OMX_COMPONENT_FIRST_BUFFER_PENDING =0x3, + // Second Buffer Pending + OMX_COMPONENT_SECOND_BUFFER_PENDING =0x4, + // Defer transition to Enable + OMX_COMPONENT_INPUT_ENABLE_PENDING =0x5, + // Defer transition to Enable + OMX_COMPONENT_OUTPUT_ENABLE_PENDING =0x6, + // Defer transition to Disable + OMX_COMPONENT_INPUT_DISABLE_PENDING =0x7, + // Defer transition to Disable + OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x8, + //defer flush notification + OMX_COMPONENT_OUTPUT_FLUSH_PENDING =0x9, + OMX_COMPONENT_INPUT_FLUSH_PENDING =0xA, + OMX_COMPONENT_PAUSE_PENDING =0xB, + OMX_COMPONENT_EXECUTE_PENDING =0xC, + OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING =0xD, + OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED=0xE + }; + + // Deferred callback identifiers + enum + { + //Event Callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_EVENT = 0x1, + //Buffer Done callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_BUFFER_DONE = 0x2, + //Frame Done callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_FRAME_DONE = 0x3, + //Buffer Done callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_FTB = 0x4, + //Frame Done callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_ETB = 0x5, + //Command + OMX_COMPONENT_GENERATE_COMMAND = 0x6, + //Push-Pending Buffers + OMX_COMPONENT_PUSH_PENDING_BUFS = 0x7, + // Empty Buffer Done callbacks + OMX_COMPONENT_GENERATE_EBD = 0x8, + //Flush Event Callbacks from the vdec component thread context + OMX_COMPONENT_GENERATE_EVENT_FLUSH = 0x9, + OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH = 0x0A, + OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH = 0x0B, + OMX_COMPONENT_GENERATE_FBD = 0xc, + OMX_COMPONENT_GENERATE_START_DONE = 0xD, + OMX_COMPONENT_GENERATE_PAUSE_DONE = 0xE, + OMX_COMPONENT_GENERATE_RESUME_DONE = 0xF, + OMX_COMPONENT_GENERATE_STOP_DONE = 0x10, + OMX_COMPONENT_GENERATE_HARDWARE_ERROR = 0x11, + OMX_COMPONENT_GENERATE_ETB_ARBITRARY = 0x12, + OMX_COMPONENT_GENERATE_PORT_RECONFIG = 0x13, + OMX_COMPONENT_GENERATE_EOS_DONE = 0x14, + OMX_COMPONENT_GENERATE_INFO_PORT_RECONFIG = 0x15, + OMX_COMPONENT_GENERATE_INFO_FIELD_DROPPED = 0x16, + + // SWVDEC events + OMX_COMPONENT_GENERATE_ETB_SWVDEC = 0x17, + OMX_COMPONENT_GENERATE_EBD_SWVDEC = 0x18, + OMX_COMPONENT_GENERATE_FTB_DSP = 0x19, + OMX_COMPONENT_GENERATE_FBD_DSP = 0x1A, + OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH_DSP = 0x1C, + OMX_COMPONENT_GENERATE_STOP_DONE_SWVDEC = 0x1D, + OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING = 0x1E, + }; + + enum vc1_profile_type + { + VC1_SP_MP_RCV = 1, + VC1_AP = 2 + }; + +#ifdef _MSM8974_ + enum v4l2_ports + { + CAPTURE_PORT, + OUTPUT_PORT, + MAX_PORT + }; +#endif + + struct omx_event + { + unsigned long param1; + unsigned long param2; + unsigned id; + }; + + struct omx_cmd_queue + { + omx_event m_q[OMX_CORE_CONTROL_CMDQ_SIZE]; + unsigned m_read; + unsigned m_write; + unsigned m_size; + + omx_cmd_queue(); + ~omx_cmd_queue(); + bool insert_entry(unsigned long p1, unsigned long p2, unsigned long id); + bool pop_entry(unsigned long*p1,unsigned long*p2, unsigned long*id); + // get msgtype of the first ele from the queue + unsigned get_q_msg_type(); + + }; + +#ifdef _ANDROID_ + struct ts_entry + { + OMX_TICKS timestamp; + bool valid; + }; + + struct ts_arr_list + { + ts_entry m_ts_arr_list[MAX_NUM_INPUT_OUTPUT_BUFFERS]; + + ts_arr_list(); + ~ts_arr_list(); + + bool insert_ts(OMX_TICKS ts); + bool pop_min_ts(OMX_TICKS &ts); + bool reset_ts_list(); + }; +#endif + + struct desc_buffer_hdr + { + OMX_U8 *buf_addr; + OMX_U32 desc_data_size; + }; + bool allocate_done(void); + bool allocate_input_done(void); + bool allocate_output_done(void); + + OMX_ERRORTYPE free_input_buffer(OMX_BUFFERHEADERTYPE *bufferHdr); + OMX_ERRORTYPE free_input_buffer(unsigned int bufferindex, + OMX_BUFFERHEADERTYPE *pmem_bufferHdr); + OMX_ERRORTYPE free_output_buffer(OMX_BUFFERHEADERTYPE *bufferHdr); + void free_output_buffer_header(); + void free_input_buffer_header(); + + OMX_ERRORTYPE allocate_input_heap_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + + OMX_ERRORTYPE allocate_input_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); + + OMX_ERRORTYPE allocate_output_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port,OMX_PTR appData, + OMX_U32 bytes); + OMX_ERRORTYPE use_output_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); +#ifdef MAX_RES_720P + OMX_ERRORTYPE get_supported_profile_level_for_720p(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType); +#endif +#ifdef MAX_RES_1080P + OMX_ERRORTYPE get_supported_profile_level_for_1080p(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType); +#endif + + OMX_ERRORTYPE allocate_desc_buffer(OMX_U32 index); + OMX_ERRORTYPE allocate_output_headers(); + bool execute_omx_flush(OMX_U32); + bool execute_output_flush(); + bool execute_input_flush(); + bool execute_input_flush_swvdec(); + bool execute_output_flush_dsp(); + + OMX_ERRORTYPE empty_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer); + + OMX_ERRORTYPE fill_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer); + OMX_ERRORTYPE empty_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + OMX_ERRORTYPE empty_this_buffer_proxy_arbitrary(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ); + + OMX_ERRORTYPE push_input_buffer (OMX_HANDLETYPE hComp); + OMX_ERRORTYPE push_input_hevc (OMX_HANDLETYPE hComp); + + OMX_ERRORTYPE fill_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + + OMX_ERRORTYPE empty_this_buffer_proxy_swvdec(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer); + + OMX_ERRORTYPE empty_buffer_done_swvdec(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer); + + OMX_ERRORTYPE fill_all_buffers_proxy_dsp(OMX_HANDLETYPE hComp); + + OMX_ERRORTYPE fill_this_buffer_proxy_dsp( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* bufferAdd); + + OMX_ERRORTYPE fill_buffer_done_dsp(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer); + + + OMX_ERRORTYPE fill_this_buffer_proxy_swvdec( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* bufferAdd); + + // OMX_ERRORTYPE allocate_intermediate_buffer(OMX_HANDLETYPE, OMX_PTR, OMX_U32); + OMX_ERRORTYPE allocate_interm_buffer(OMX_IN OMX_U32 bytes); + + OMX_ERRORTYPE free_interm_buffers(); + + bool release_done(); + + bool release_output_done(); + bool release_input_done(); + bool release_interm_done(); + + OMX_ERRORTYPE get_buffer_req(vdec_allocatorproperty *buffer_prop); + OMX_ERRORTYPE get_buffer_req_swvdec(); + OMX_ERRORTYPE set_buffer_req(vdec_allocatorproperty *buffer_prop); + OMX_ERRORTYPE set_buffer_req_swvdec(vdec_allocatorproperty *buffer_prop); + + OMX_ERRORTYPE start_port_reconfig(); + OMX_ERRORTYPE update_picture_resolution(); + int stream_off(OMX_U32 port); + void adjust_timestamp(OMX_S64 &act_timestamp); + void set_frame_rate(OMX_S64 act_timestamp); + void handle_extradata_secure(OMX_BUFFERHEADERTYPE *p_buf_hdr); + void handle_extradata(OMX_BUFFERHEADERTYPE *p_buf_hdr); + void print_debug_extradata(OMX_OTHER_EXTRADATATYPE *extra); +#ifdef _MSM8974_ + void append_interlace_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 interlaced_format_type); + OMX_ERRORTYPE enable_extradata(OMX_U32 requested_extradata, bool is_internal, + bool enable = true); + void append_frame_info_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 num_conceal_mb, + OMX_U32 picture_type, + OMX_U32 frame_rate, + struct msm_vidc_panscan_window_payload *panscan_payload, + struct vdec_aspectratioinfo *aspect_ratio_info); +#else + void append_interlace_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 interlaced_format_type, OMX_U32 buf_index); + OMX_ERRORTYPE enable_extradata(OMX_U32 requested_extradata, bool enable = true); +#endif + void append_frame_info_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 num_conceal_mb, + OMX_U32 picture_type, + OMX_S64 timestamp, + OMX_U32 frame_rate, + struct vdec_aspectratioinfo *aspect_ratio_info); + void fill_aspect_ratio_info(struct vdec_aspectratioinfo *aspect_ratio_info, + OMX_QCOM_EXTRADATA_FRAMEINFO *frame_info); + void append_terminator_extradata(OMX_OTHER_EXTRADATATYPE *extra); + OMX_ERRORTYPE update_portdef(OMX_PARAM_PORTDEFINITIONTYPE *portDefn); + void append_portdef_extradata(OMX_OTHER_EXTRADATATYPE *extra); + void append_extn_extradata(OMX_OTHER_EXTRADATATYPE *extra, OMX_OTHER_EXTRADATATYPE *p_extn); + void append_user_extradata(OMX_OTHER_EXTRADATATYPE *extra, OMX_OTHER_EXTRADATATYPE *p_user); + void insert_demux_addr_offset(OMX_U32 address_offset); + void extract_demux_addr_offsets(OMX_BUFFERHEADERTYPE *buf_hdr); + OMX_ERRORTYPE handle_demux_data(OMX_BUFFERHEADERTYPE *buf_hdr); + OMX_U32 count_MB_in_extradata(OMX_OTHER_EXTRADATATYPE *extra); + + bool align_pmem_buffers(int pmem_fd, OMX_U32 buffer_size, + OMX_U32 alignment); +#ifdef USE_ION + int alloc_map_ion_memory(OMX_U32 buffer_size, + OMX_U32 alignment, struct ion_allocation_data *alloc_data, + struct ion_fd_data *fd_data,int flag, int heap_id = 0); + void free_ion_memory(struct vdec_ion *buf_ion_info); +#endif + + + OMX_ERRORTYPE send_command_proxy(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + bool post_event( unsigned long p1, + unsigned long p2, + unsigned long id + ); + inline int clip2(int x) + { + x = x -1; + x = x | x >> 1; + x = x | x >> 2; + x = x | x >> 4; + x = x | x >> 16; + x = x + 1; + return x; + } + +#ifdef MAX_RES_1080P + OMX_ERRORTYPE vdec_alloc_h264_mv(); + void vdec_dealloc_h264_mv(); + OMX_ERRORTYPE vdec_alloc_meta_buffers(); + void vdec_dealloc_meta_buffers(); +#endif + + inline void omx_report_error () + { + if (m_cb.EventHandler && !m_error_propogated) + { + DEBUG_PRINT_ERROR("\nERROR: Sending OMX_EventError to Client"); + m_error_propogated = true; + m_cb.EventHandler(&m_cmp,m_app_data, + OMX_EventError,OMX_ErrorHardware,0,NULL); + } + } + + inline void omx_report_unsupported_setting () + { + if (m_cb.EventHandler && !m_error_propogated) + { + DEBUG_PRINT_ERROR("ERROR: Sending OMX_ErrorUnsupportedSetting to Client"); + m_error_propogated = true; + m_cb.EventHandler(&m_cmp,m_app_data, + OMX_EventError,OMX_ErrorUnsupportedSetting,0,NULL); + } + } +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) + OMX_ERRORTYPE use_android_native_buffer(OMX_IN OMX_HANDLETYPE hComp, OMX_PTR data); +#endif +#if defined (_ANDROID_ICS_) + struct nativebuffer{ + native_handle_t *nativehandle; + private_handle_t *privatehandle; + int inuse; + }; + nativebuffer native_buffer[MAX_NUM_INPUT_OUTPUT_BUFFERS]; +#endif + + + //************************************************************* + //*******************MEMBER VARIABLES ************************* + //************************************************************* + pthread_mutex_t m_lock; + pthread_mutex_t c_lock; + //sem to handle the minimum procesing of commands + sem_t m_cmd_lock; + bool m_error_propogated; + // compression format + OMX_VIDEO_CODINGTYPE eCompressionFormat; + // OMX State + OMX_STATETYPE m_state; + // Application data + OMX_PTR m_app_data; + // Application callbacks + OMX_CALLBACKTYPE m_cb; + OMX_PRIORITYMGMTTYPE m_priority_mgm ; + OMX_PARAM_BUFFERSUPPLIERTYPE m_buffer_supplier; + // fill this buffer queue + omx_cmd_queue m_ftb_q; + // Command Q for rest of the events + omx_cmd_queue m_cmd_q; + omx_cmd_queue m_etb_q; + + omx_cmd_queue m_ftb_q_dsp; // ftb for dsp + omx_cmd_queue m_etb_q_swvdec; // etbs for swvdec + + // Input memory pointer + OMX_BUFFERHEADERTYPE *m_inp_mem_ptr; + // Output memory pointer + OMX_BUFFERHEADERTYPE *m_out_mem_ptr; + // number of input bitstream error frame count + unsigned int m_inp_err_count; +#ifdef _ANDROID_ + // Timestamp list + ts_arr_list m_timestamp_list; +#endif + + bool input_flush_progress; + bool output_flush_progress; + bool input_use_buffer; + bool output_use_buffer; + bool ouput_egl_buffers; + OMX_BOOL m_use_output_pmem; + OMX_BOOL m_out_mem_region_smi; + OMX_BOOL m_out_pvt_entry_pmem; + + int pending_input_buffers; + int pending_output_buffers; + // bitmask array size for output side + unsigned int m_out_bm_count; + // bitmask array size for input side + unsigned int m_inp_bm_count; + //Input port Populated + OMX_BOOL m_inp_bPopulated; + //Output port Populated + OMX_BOOL m_out_bPopulated; + // encapsulate the waiting states. + unsigned int m_flags; + +#ifdef _ANDROID_ + // Heap pointer to frame buffers + struct vidc_heap + { + sp<MemoryHeapBase> video_heap_ptr; + }; + struct vidc_heap *m_heap_ptr; + unsigned int m_heap_count; +#endif //_ANDROID_ + // store I/P PORT state + OMX_BOOL m_inp_bEnabled; + // store O/P PORT state + OMX_BOOL m_out_bEnabled; + OMX_U32 m_in_alloc_cnt; + OMX_U8 m_cRole[OMX_MAX_STRINGNAME_SIZE]; + // Platform specific details + OMX_QCOM_PLATFORM_PRIVATE_LIST *m_platform_list; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY *m_platform_entry; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *m_pmem_info; + + // for soft ARM codec + SWVDEC_INITPARAMS sSwVdecParameter; + SWVDEC_HANDLE m_pSwVdec; + SWVDEC_CALLBACK m_callBackInfo; + SWVDEC_IPBUFFER *m_pSwVdecIpBuffer; + SWVDEC_OPBUFFER *m_pSwVdecOpBuffer; + OMX_U32 m_nInputBuffer; + OMX_U32 m_nOutputBuffer; + + interm_buffer_state m_interm_buf_state[32]; + OMX_BUFFERHEADERTYPE* m_interm_mem_ptr; + bool m_interm_flush_dsp_progress; + bool m_interm_flush_swvdec_progress; + OMX_BOOL m_interm_bPopulated; + OMX_BOOL m_interm_bEnabled; + int m_swvdec_mode; + OMX_BOOL m_fill_internal_bufers; + + // SPS+PPS sent as part of set_config + OMX_VENDOR_EXTRADATATYPE m_vendor_config; + + /*Variables for arbitrary Byte parsing support*/ + frame_parse m_frame_parser; + omx_cmd_queue m_input_pending_q; + omx_cmd_queue m_input_free_q; + bool arbitrary_bytes; + OMX_BUFFERHEADERTYPE h264_scratch; + OMX_BUFFERHEADERTYPE *psource_frame; + OMX_BUFFERHEADERTYPE *pdest_frame; + OMX_BUFFERHEADERTYPE *m_inp_heap_ptr; + OMX_BUFFERHEADERTYPE **m_phdr_pmem_ptr; + unsigned int m_heap_inp_bm_count; + codec_type codec_type_parse; + bool first_frame_meta; + unsigned frame_count; + unsigned nal_count; + unsigned nal_length; + bool look_ahead_nal; + int first_frame; + unsigned char *first_buffer; + int first_frame_size; + unsigned char m_hwdevice_name[80]; + FILE *m_device_file_ptr; + enum vc1_profile_type m_vc1_profile; + OMX_S64 h264_last_au_ts; + OMX_U32 h264_last_au_flags; + OMX_U32 m_demux_offsets[8192]; + OMX_U32 m_demux_entries; + OMX_U32 m_disp_hor_size; + OMX_U32 m_disp_vert_size; + + OMX_S64 prev_ts; + bool rst_prev_ts; + OMX_U32 frm_int; + + struct vdec_allocatorproperty op_buf_rcnfg; + bool in_reconfig; + OMX_NATIVE_WINDOWTYPE m_display_id; + h264_stream_parser *h264_parser; + OMX_U32 client_extradata; +#ifdef _ANDROID_ + bool m_debug_timestamp; + bool perf_flag; + OMX_U32 proc_frms, latency; + perf_metrics fps_metrics; + perf_metrics dec_time; + bool m_enable_android_native_buffers; + bool m_use_android_native_buffers; + bool m_debug_extradata; + bool m_debug_concealedmb; + bool m_disable_dynamic_buf_mode; +#endif +#ifdef MAX_RES_1080P + MP4_Utils mp4_headerparser; +#endif + + struct h264_mv_buffer{ + unsigned char* buffer; + int size; + int count; + int pmem_fd; + int offset; + }; + h264_mv_buffer h264_mv_buff; + + struct meta_buffer{ + unsigned char* buffer; + int size; + int count; + int pmem_fd; + int pmem_fd_iommu; + int offset; + }; + meta_buffer meta_buff; + extra_data_handler extra_data_handle; + OMX_PARAM_PORTDEFINITIONTYPE m_port_def; + omx_time_stamp_reorder time_stamp_dts; + desc_buffer_hdr *m_desc_buffer_ptr; + bool secure_mode; + bool external_meta_buffer; + bool external_meta_buffer_iommu; + OMX_QCOM_EXTRADATA_FRAMEINFO *m_extradata; + bool codec_config_flag; +#ifdef _MSM8974_ + int capture_capability; + int output_capability; + bool streaming[MAX_PORT]; + OMX_CONFIG_RECTTYPE rectangle; + int prev_n_filled_len; +#endif + bool m_power_hinted; + OMX_ERRORTYPE power_module_register(); + OMX_ERRORTYPE power_module_deregister(); + bool msg_thread_created; + bool async_thread_created; + + bool dynamic_buf_mode; + struct dynamic_buf_list *out_dynamic_list; + + bool m_smoothstreaming_mode; + OMX_U32 m_smoothstreaming_width; + OMX_U32 m_smoothstreaming_height; + OMX_ERRORTYPE enable_smoothstreaming(); + + unsigned int m_fill_output_msg; + class allocate_color_convert_buf { + public: + allocate_color_convert_buf(); + ~allocate_color_convert_buf(); + void set_vdec_client(void *); + void update_client(); + bool set_color_format(OMX_COLOR_FORMATTYPE dest_color_format); + bool get_color_format(OMX_COLOR_FORMATTYPE &dest_color_format); + bool update_buffer_req(); + bool get_buffer_req(unsigned int &buffer_size); + OMX_BUFFERHEADERTYPE* get_il_buf_hdr(); + OMX_BUFFERHEADERTYPE* get_il_buf_hdr(OMX_BUFFERHEADERTYPE *input_hdr); + OMX_BUFFERHEADERTYPE* get_dr_buf_hdr(OMX_BUFFERHEADERTYPE *input_hdr); + OMX_BUFFERHEADERTYPE* convert(OMX_BUFFERHEADERTYPE *header); + OMX_BUFFERHEADERTYPE* queue_buffer(OMX_BUFFERHEADERTYPE *header); + OMX_ERRORTYPE allocate_buffers_color_convert(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr,OMX_U32 port,OMX_PTR appData, + OMX_U32 bytes); + OMX_ERRORTYPE free_output_buffer(OMX_BUFFERHEADERTYPE *bufferHdr); + private: + #define MAX_COUNT 32 + omx_vdec *omx; + bool enabled; + OMX_COLOR_FORMATTYPE ColorFormat; + void init_members(); + bool color_convert_mode; + ColorConvertFormat dest_format; + class omx_c2d_conv c2d; + unsigned int allocated_count; + unsigned int buffer_size_req; + unsigned int buffer_alignment_req; + OMX_QCOM_PLATFORM_PRIVATE_LIST m_platform_list_client[MAX_COUNT]; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY m_platform_entry_client[MAX_COUNT]; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO m_pmem_info_client[MAX_COUNT]; + OMX_BUFFERHEADERTYPE m_out_mem_ptr_client[MAX_COUNT]; +#ifdef USE_ION + struct vdec_ion op_buf_ion_info[MAX_COUNT]; +#endif + unsigned char *pmem_baseaddress[MAX_COUNT]; + int pmem_fd[MAX_COUNT]; + struct vidc_heap + { + sp<MemoryHeapBase> video_heap_ptr; + }; + struct vidc_heap m_heap_ptr[MAX_COUNT]; + }; +#if defined (_MSM8960_) || defined (_MSM8974_) + allocate_color_convert_buf client_buffers; +#endif + HEVC_Utils mHEVCutils; + struct video_decoder_capability m_decoder_capability; + struct debug_cap m_debug; + int log_input_buffers(const char *, int); + int log_output_buffers(OMX_BUFFERHEADERTYPE *); + int log_im_buffer(OMX_BUFFERHEADERTYPE * buffer); +}; + +#ifdef _MSM8974_ +enum instance_state { + MSM_VIDC_CORE_UNINIT_DONE = 0x0001, + MSM_VIDC_CORE_INIT, + MSM_VIDC_CORE_INIT_DONE, + MSM_VIDC_OPEN, + MSM_VIDC_OPEN_DONE, + MSM_VIDC_LOAD_RESOURCES, + MSM_VIDC_LOAD_RESOURCES_DONE, + MSM_VIDC_START, + MSM_VIDC_START_DONE, + MSM_VIDC_STOP, + MSM_VIDC_STOP_DONE, + MSM_VIDC_RELEASE_RESOURCES, + MSM_VIDC_RELEASE_RESOURCES_DONE, + MSM_VIDC_CLOSE, + MSM_VIDC_CLOSE_DONE, + MSM_VIDC_CORE_UNINIT, +}; + +enum vidc_resposes_id { + MSM_VIDC_DECODER_FLUSH_DONE = 0x11, + MSM_VIDC_DECODER_EVENT_CHANGE, +}; + +#endif // _MSM8974_ + +#endif // __OMX_VDEC_H__ diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/power_module.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/power_module.h new file mode 100644 index 0000000..ba47c2f --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/power_module.h @@ -0,0 +1,42 @@ +/*------------------------------------------------------------------------- +Copyright (c) 2012-2013, 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. +--------------------------------------------------------------------------*/ + +#include <hardware/power.h> + +class PowerModule +{ + public: + static PowerModule *getInstance(); + power_module_t *getPowerModuleHandle(); + private: + static PowerModule *mPowerModuleInstance; + power_module_t *mPowerModuleHandle; + PowerModule() {} +}; diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/qtypes.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/qtypes.h new file mode 100644 index 0000000..bef6e2d --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/qtypes.h @@ -0,0 +1,90 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010 - 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#ifndef QTYPES_H +#define QTYPES_H +/*=========================================================================== + + Data Declarations + +===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------------------------------------------------------------ +** Constants +** ------------------------------------------------------------------------ */ + +#ifdef TRUE +#undef TRUE +#endif + +#ifdef FALSE +#undef FALSE +#endif + +#define TRUE 1 /* Boolean true value. */ +#define FALSE 0 /* Boolean false value. */ + + + +/* ----------------------------------------------------------------------- +** Standard Types +** ----------------------------------------------------------------------- */ + + /* The following definitions are the same accross platforms. This first + ** group are the sanctioned types. + */ + + typedef unsigned char boolean; /* Boolean value type. */ + + typedef unsigned int uint32; /* Unsigned 32 bit value */ + typedef unsigned short uint16; /* Unsigned 16 bit value */ + typedef unsigned char uint8; /* Unsigned 8 bit value */ + + typedef int int32; /* Signed 32 bit value */ + typedef signed short int16; /* Signed 16 bit value */ + typedef signed char int8; /* Signed 8 bit value */ + + /* This group are the deprecated types. Their use should be + ** discontinued and new code should use the types above + */ + typedef unsigned char byte; /* Unsigned 8 bit value type. */ + typedef unsigned short word; /* Unsinged 16 bit value type. */ + typedef unsigned long dword; /* Unsigned 32 bit value type. */ + + typedef long long int64; + typedef unsigned long long uint64; + + +#ifdef __cplusplus +} +#endif + +#endif /* QTYPES_H */ diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/queue.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/queue.h new file mode 100644 index 0000000..f22e43c --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/queue.h @@ -0,0 +1,39 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2011, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#ifndef QUEUE_H +#define QUEUE_H + +typedef struct Queue Queue; + +Queue *alloc_queue(); +void free_queue(Queue *q); +void free_queue_and_qelement(Queue *q); +int push(Queue *q, void * element); +void *pop(Queue *q); + +#endif diff --git a/msm8998/mm-video-v4l2/vidc/vdec/inc/ts_parser.h b/msm8998/mm-video-v4l2/vidc/vdec/inc/ts_parser.h new file mode 100644 index 0000000..2d5d1a4 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/inc/ts_parser.h @@ -0,0 +1,106 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#ifndef __DTSPARSER_H +#define __DTSPARSER_H + +#include "OMX_Core.h" +#include "OMX_QCOMExtns.h" +#include "qc_omx_component.h" + +#include<stdlib.h> + +#include <stdio.h> +#include <inttypes.h> + +#ifdef _ANDROID_ +extern "C" { +#include<utils/Log.h> +} +#else +#define ALOGE(fmt, args...) fprintf(stderr, fmt, ##args) +#endif /* _ANDROID_ */ + +class omx_time_stamp_reorder +{ + class auto_lock { + public: + auto_lock(pthread_mutex_t *lock) + : mLock(lock) { + if (mLock) + pthread_mutex_lock(mLock); + } + ~auto_lock() { + if (mLock) + pthread_mutex_unlock(mLock); + } + private: + pthread_mutex_t *mLock; + }; + + public: + omx_time_stamp_reorder(); + ~omx_time_stamp_reorder(); + void set_timestamp_reorder_mode(bool flag); + void enable_debug_print(bool flag); + bool insert_timestamp(OMX_BUFFERHEADERTYPE *header); + bool get_next_timestamp(OMX_BUFFERHEADERTYPE *header, bool is_interlaced); + bool remove_time_stamp(OMX_TICKS ts, bool is_interlaced); + void flush_timestamp(); + + private: +#define TIME_SZ 64 + typedef struct timestamp { + OMX_TICKS timestamps; + bool in_use; + } timestamp; + typedef struct time_stamp_list { + timestamp input_timestamps[TIME_SZ]; + time_stamp_list *next; + time_stamp_list *prev; + unsigned int entries_filled; + } time_stamp_list; + bool error; + time_stamp_list *phead,*pcurrent; + bool get_current_list(); + bool add_new_list(); + bool update_head(); + void delete_list(); + void handle_error() { + ALOGE("Error handler called for TS Parser"); + + if (error) + return; + + error = true; + delete_list(); + } + bool reorder_ts; + bool print_debug; + pthread_mutex_t m_lock; +}; +#endif diff --git a/msm8998/mm-video-v4l2/vidc/vdec/src/frameparser.cpp b/msm8998/mm-video-v4l2/vidc/vdec/src/frameparser.cpp new file mode 100644 index 0000000..5e8e551 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/src/frameparser.cpp @@ -0,0 +1,638 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010 - 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <fcntl.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <pthread.h> +#include <ctype.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/poll.h> +#include <stdint.h> + +#include "frameparser.h" +#include "vidc_debug.h" + +#ifdef _ANDROID_ +extern "C" { +#include<utils/Log.h> +} +#endif//_ANDROID_ + +static unsigned char H264_mask_code[4] = {0xFF,0xFF,0xFF,0xFF}; +static unsigned char H264_start_code[4] = {0x00,0x00,0x00,0x01}; + +static unsigned char MPEG4_start_code[4] = {0x00,0x00,0x01,0xB6}; +static unsigned char MPEG4_mask_code[4] = {0xFF,0xFF,0xFF,0xFF}; + +static unsigned char H263_start_code[4] = {0x00,0x00,0x80,0x00}; +static unsigned char H263_mask_code[4] = {0xFF,0xFF,0xFC,0x00}; + +static unsigned char VC1_AP_start_code[4] = {0x00,0x00,0x01,0x0C}; +static unsigned char VC1_AP_mask_code[4] = {0xFF,0xFF,0xFF,0xFC}; + +static unsigned char MPEG2_start_code[4] = {0x00, 0x00, 0x01, 0x00}; +static unsigned char MPEG2_mask_code[4] = {0xFF, 0xFF, 0xFF, 0xFF}; + +frame_parse::frame_parse():mutils(NULL), + parse_state(A0), + start_code(NULL), + mask_code(NULL), + last_byte_h263(0), + last_byte(0), + header_found(false), + skip_frame_boundary(false), + state_nal(NAL_LENGTH_ACC), + nal_length(0), + accum_length(0), + bytes_tobeparsed(0) +{ +} + +frame_parse::~frame_parse () +{ + if (mutils) + delete mutils; + + mutils = NULL; +} + +int frame_parse::init_start_codes (codec_type codec_type_parse) +{ + /*Check if Codec Type is proper and we are in proper state*/ + if (codec_type_parse > CODEC_TYPE_MAX || parse_state != A0) { + return -1; + } + + switch (codec_type_parse) { + case CODEC_TYPE_MPEG4: + start_code = MPEG4_start_code; + mask_code = MPEG4_mask_code; + break; + case CODEC_TYPE_H263: + start_code = H263_start_code; + mask_code = H263_mask_code; + break; + case CODEC_TYPE_H264: + case CODEC_TYPE_HEVC: + start_code = H264_start_code; + mask_code = H264_mask_code; + break; + case CODEC_TYPE_VC1: + start_code = VC1_AP_start_code; + mask_code = VC1_AP_mask_code; + break; + case CODEC_TYPE_MPEG2: + start_code = MPEG2_start_code; + mask_code = MPEG2_mask_code; + break; +#ifdef _MSM8974_ + case CODEC_TYPE_VP8: + break; +#endif + default: + return -1; + } + + return 1; +} + + +int frame_parse::init_nal_length (unsigned int nal_len) +{ + if (nal_len == 0 || nal_len > 4 || state_nal != NAL_LENGTH_ACC) { + return -1; + } + + nal_length = nal_len; + + return 1; +} + +int frame_parse::parse_sc_frame ( OMX_BUFFERHEADERTYPE *source, + OMX_BUFFERHEADERTYPE *dest , + OMX_U32 *partialframe) +{ + OMX_U8 *pdest = NULL,*psource = NULL, match_found = FALSE, is_byte_match = 0; + OMX_U32 dest_len =0, source_len = 0, temp_len = 0; + OMX_U32 parsed_length = 0,i=0; + int residue_byte = 0; + + if (source == NULL || dest == NULL || partialframe == NULL) { + return -1; + } + + /*Calculate how many bytes are left in source and destination*/ + dest_len = dest->nAllocLen - (dest->nFilledLen + dest->nOffset); + psource = source->pBuffer + source->nOffset; + pdest = dest->pBuffer + (dest->nFilledLen + dest->nOffset); + source_len = source->nFilledLen; + + /*Need Minimum Start Code size for destination to copy atleast Start code*/ + if ((start_code == H263_start_code && dest_len < 3) || + (start_code != H263_start_code && dest_len < 4) || (source_len == 0)) { + DEBUG_PRINT_LOW("FrameParser: dest_len %u source_len %u",(unsigned int)dest_len, (unsigned int)source_len); + + if (source_len == 0 && (source->nFlags & 0x01)) { + DEBUG_PRINT_LOW("FrameParser: EOS rxd!! Notify it as a complete frame"); + *partialframe = 0; + return 1; + } + + DEBUG_PRINT_LOW("FrameParser: Bitstream Parsing error"); + return -1; + } + + /*Check if State of the previous find is a Start code*/ + if (parse_state == A4 || parse_state == A5) { + /*Check for minimun size should be 4*/ + dest->nFlags = source->nFlags; + dest->nTimeStamp = source->nTimeStamp; + + if (start_code == H263_start_code) { + memcpy (pdest,start_code,2); + pdest[2] = last_byte_h263; + dest->nFilledLen += 3; + pdest += 3; + } else { + memcpy (pdest,start_code,4); + + if (start_code == VC1_AP_start_code + || start_code == MPEG4_start_code + || start_code == MPEG2_start_code) { + pdest[3] = last_byte; + update_skip_frame(); + } + + dest->nFilledLen += 4; + pdest += 4; + } + + parse_state = A0; + } + + /*Entry State Machine*/ + while ( source->nFilledLen > 0 && parse_state != A0 + && parse_state != A4 && parse_state != A5 && dest_len > 0 + ) { + //printf ("In the Entry Loop"); + switch (parse_state) { + case A3: + parse_additional_start_code(psource,&parsed_length); + + if (parse_state == A4) { + source->nFilledLen--; + source->nOffset++; + psource++; + break; + } + + /*If fourth Byte is matching then start code is found*/ + if ((*psource & mask_code [3]) == start_code [3]) { + parse_state = A4; + last_byte = *psource; + source->nFilledLen--; + source->nOffset++; + psource++; + } else if ((start_code [1] == start_code [0]) && (start_code [2] == start_code [1])) { + parse_state = A2; + memcpy (pdest,start_code,1); + pdest++; + dest->nFilledLen++; + dest_len--; + } else if (start_code [2] == start_code [0]) { + parse_state = A1; + memcpy (pdest,start_code,2); + pdest += 2; + dest->nFilledLen += 2; + dest_len -= 2; + } else { + parse_state = A0; + memcpy (pdest,start_code,3); + pdest += 3; + dest->nFilledLen +=3; + dest_len -= 3; + } + + break; + + case A2: + is_byte_match = ((*psource & mask_code [2]) == start_code [2]); + match_found = FALSE; + + if (start_code == H263_start_code) { + if (is_byte_match) { + last_byte_h263 = *psource; + parse_state = A5; + match_found = TRUE; + } + } else if (start_code == H264_start_code && + (*psource & mask_code [3]) == start_code [3]) { + parse_state = A5; + match_found = TRUE; + } else { + if (is_byte_match) { + parse_state = A3; + match_found = TRUE; + } + } + + if (match_found) { + source->nFilledLen--; + source->nOffset++; + psource++; + } else if (start_code [1] == start_code [0]) { + parse_state = A1; + memcpy (pdest,start_code,1); + dest->nFilledLen +=1; + dest_len--; + pdest++; + } else { + parse_state = A0; + memcpy (pdest,start_code,2); + dest->nFilledLen +=2; + dest_len -= 2; + pdest += 2; + } + + break; + + case A1: + + if ((*psource & mask_code [1]) == start_code [1]) { + parse_state = A2; + source->nFilledLen--; + source->nOffset++; + psource++; + } else { + memcpy (pdest,start_code,1); + dest->nFilledLen +=1; + pdest++; + dest_len--; + parse_state = A0; + } + + break; + case A4: + case A0: + case A5: + break; + } + + dest_len = dest->nAllocLen - (dest->nFilledLen + dest->nOffset); + } + + if (parse_state == A4 || parse_state == A5) { + *partialframe = 0; + check_skip_frame_boundary(partialframe); + DEBUG_PRINT_LOW("FrameParser: Parsed Len = %u", (unsigned int)dest->nFilledLen); + return 1; + } + + /*Partial Frame is true*/ + *partialframe = 1; + + /*Calculate how many bytes are left in source and destination*/ + dest_len = dest->nAllocLen - (dest->nFilledLen + dest->nOffset); + psource = source->pBuffer + source->nOffset; + pdest = dest->pBuffer + (dest->nFilledLen + dest->nOffset); + source_len = source->nFilledLen; + + temp_len = (source_len < dest_len)?source_len:dest_len; + + /*Check if entry state machine consumed source or destination*/ + if (temp_len == 0) { + return 1; + } + + /*Parsing State Machine*/ + while (parsed_length < temp_len) { + switch (parse_state) { + case A0: + + if ((psource [parsed_length] & mask_code [0]) == start_code[0]) { + parse_state = A1; + } + + parsed_length++; + break; + case A1: + + if ((psource [parsed_length] & mask_code [1]) == start_code [1]) { + parsed_length++; + parse_state = A2; + } else { + parse_state = A0; + } + + break; + case A2: + is_byte_match = ((psource[parsed_length] & mask_code [2]) == start_code [2]); + match_found = FALSE; + + if (start_code == H263_start_code) { + if (is_byte_match) { + last_byte_h263 = psource[parsed_length]; + parse_state = A5; + match_found = TRUE; + } + } else if (start_code == H264_start_code && + (psource[parsed_length] & mask_code [3]) == start_code [3]) { + parse_state = A5; + match_found = TRUE; + } else { + if (is_byte_match) { + parse_state = A3; + match_found = TRUE; + } + } + + if (match_found) { + parsed_length++; + } else if (start_code [1] == start_code [0]) { + parse_state = A1; + } else { + parse_state = A0; + } + + break; + case A3: + parse_additional_start_code(psource,&parsed_length); + + if (parse_state == A4) break; + + if ((psource [parsed_length] & mask_code [3]) == start_code [3]) { + last_byte = psource [parsed_length]; + parsed_length++; + parse_state = A4; + } else if ((start_code [1] == start_code [0]) && (start_code [2] == start_code [1])) { + parse_state = A2; + } else if (start_code [2] == start_code [0]) { + parse_state = A1; + } else { + parse_state = A0; + } + + break; + case A4: + case A5: + break; + } + + /*Found the code break*/ + if (parse_state == A4 || parse_state == A5) { + break; + } + } + + /*Exit State Machine*/ + psource = source->pBuffer + source->nOffset; + OMX_U32 bytes_to_skip = 0; + switch (parse_state) { + case A5: + *partialframe = 0; + check_skip_frame_boundary(partialframe); + bytes_to_skip = 3; + break; + case A4: + *partialframe = 0; + check_skip_frame_boundary(partialframe); + bytes_to_skip = 4; + break; + case A3: + if (source->nFlags & OMX_BUFFERFLAG_EOS) { + bytes_to_skip = 0; + } else { + bytes_to_skip = 3; + } + break; + case A2: + if (source->nFlags & OMX_BUFFERFLAG_EOS) { + bytes_to_skip = 0; + } else { + bytes_to_skip = 2; + } + break; + case A1: + if (source->nFlags & OMX_BUFFERFLAG_EOS) { + bytes_to_skip = 0; + } else { + bytes_to_skip = 1; + } + break; + case A0: + bytes_to_skip = 0; + break; + } + + if (source->nFilledLen < parsed_length) { + DEBUG_PRINT_ERROR ("FATAL Error"); + return -1; + } + + if (parsed_length > bytes_to_skip) { + memcpy (pdest, psource, (parsed_length-bytes_to_skip)); + dest->nFilledLen += (parsed_length-bytes_to_skip); + } + + source->nFilledLen -= parsed_length; + source->nOffset += parsed_length; + + return 1; +} + + +int frame_parse::parse_h264_nallength (OMX_BUFFERHEADERTYPE *source, + OMX_BUFFERHEADERTYPE *dest , + OMX_U32 *partialframe) +{ + OMX_U8 *pdest = NULL,*psource = NULL; + OMX_U32 dest_len =0, source_len = 0, temp_len = 0,parsed_length = 0; + + if (source == NULL || dest == NULL || partialframe == NULL) { + return -1; + } + + /*Calculate the length's*/ + dest_len = dest->nAllocLen - (dest->nFilledLen + dest->nOffset); + source_len = source->nFilledLen; + + if (dest_len < 4 || nal_length == 0) { + DEBUG_PRINT_LOW("FrameParser: NAL Parsing Error! dest_len %u " + "nal_length %u", (unsigned int)dest_len, nal_length); + return -1; + } + + if (source_len == 0 ) { + if (source->nFlags & OMX_BUFFERFLAG_EOS) { + DEBUG_PRINT_LOW("FrameParser: EOS rxd for nallength!!" + " Notify it as a complete frame"); + *partialframe = 0; + return 1; + } else { + DEBUG_PRINT_ERROR("FrameParser: NAL Parsing Error!" + "Buffer recieved with source_len = %u and with" + "flags %u", (unsigned int)source_len, (unsigned int)source->nFlags); + return -1; + } + } + + *partialframe = 1; + temp_len = (source_len < dest_len)?source_len:dest_len; + psource = source->pBuffer + source->nOffset; + pdest = dest->pBuffer + (dest->nFilledLen + dest->nOffset); + + /* Find the Bytes to Accumalte*/ + if (state_nal == NAL_LENGTH_ACC) { + while (parsed_length < temp_len ) { + bytes_tobeparsed |= (((OMX_U32)(*psource))) << (((nal_length-accum_length-1) << 3)); + + /*COPY THE DATA FOR C-SIM TO BE REOMVED ON TARGET*/ + //*pdest = *psource; + accum_length++; + source->nFilledLen--; + source->nOffset++; + psource++; + //dest->nFilledLen++; + //pdest++; + parsed_length++; + + if (accum_length == nal_length) { + accum_length = 0; + state_nal = NAL_PARSING; + memcpy (pdest,H264_start_code,4); + dest->nFilledLen += 4; + break; + } + } + } + + dest_len = dest->nAllocLen - (dest->nFilledLen + dest->nOffset); + source_len = source->nFilledLen; + temp_len = (source_len < dest_len)?source_len:dest_len; + + psource = source->pBuffer + source->nOffset; + pdest = dest->pBuffer + (dest->nFilledLen + dest->nOffset); + + dest->nTimeStamp = source->nTimeStamp; + dest->nFlags = source->nFlags; + + /*Already in Parsing state go ahead and copy*/ + if (state_nal == NAL_PARSING && temp_len > 0) { + if (temp_len < bytes_tobeparsed) { + memcpy (pdest,psource,temp_len); + dest->nFilledLen += temp_len; + source->nOffset += temp_len; + source->nFilledLen -= temp_len; + bytes_tobeparsed -= temp_len; + } else { + memcpy (pdest,psource,bytes_tobeparsed); + temp_len -= bytes_tobeparsed; + dest->nFilledLen += bytes_tobeparsed; + source->nOffset += bytes_tobeparsed; + source->nFilledLen -= bytes_tobeparsed; + bytes_tobeparsed = 0; + } + } + + if (bytes_tobeparsed == 0 && state_nal == NAL_PARSING) { + *partialframe = 0; + state_nal = NAL_LENGTH_ACC; + } + + return 1; +} + +void frame_parse::flush () +{ + parse_state = A0; + state_nal = NAL_LENGTH_ACC; + accum_length = 0; + bytes_tobeparsed = 0; + header_found = false; + skip_frame_boundary = false; +} + +void frame_parse::parse_additional_start_code(OMX_U8 *psource, + OMX_U32 *parsed_length) +{ + + if (((start_code == MPEG4_start_code) || + (start_code == MPEG2_start_code)) && + psource && + parsed_length) { + OMX_U32 index = *parsed_length; + + if ((start_code == MPEG4_start_code && + (psource [index] & 0xF0) == 0x20) || + (start_code == MPEG2_start_code && + psource [index] == 0xB3)) { + if (header_found) { + last_byte = psource [index]; + index++; + parse_state = A4; + } else + header_found = true; + } + + *parsed_length = index; + } +} + +void frame_parse::check_skip_frame_boundary(OMX_U32 *partialframe) +{ + if ((start_code == MPEG4_start_code || + start_code == MPEG2_start_code) && + partialframe) { + + *partialframe = 1; + + if (!skip_frame_boundary) + *partialframe = 0; + + skip_frame_boundary = false; + } +} + +void frame_parse::update_skip_frame() +{ + if (((start_code == MPEG4_start_code) && + ((last_byte & 0xF0) == 0x20)) || + ((start_code == MPEG2_start_code) && + (last_byte == 0xB3))) { + + skip_frame_boundary = true; + } +} diff --git a/msm8998/mm-video-v4l2/vidc/vdec/src/h264_utils.cpp b/msm8998/mm-video-v4l2/vidc/vdec/src/h264_utils.cpp new file mode 100644 index 0000000..13d4eac --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/src/h264_utils.cpp @@ -0,0 +1,1587 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010 - 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +/*======================================================================== + + O p e n M M + V i d e o U t i l i t i e s + +*//** @file VideoUtils.cpp + This module contains utilities and helper routines. + +@par EXTERNALIZED FUNCTIONS + +@par INITIALIZATION AND SEQUENCING REQUIREMENTS + (none) + +*//*====================================================================== */ + +/* ======================================================================= + + INCLUDE FILES FOR MODULE + +========================================================================== */ +#include "h264_utils.h" +#include "extra_data_handler.h" +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#include <sys/time.h> +#ifdef _ANDROID_ +#include <cutils/properties.h> +extern "C" { +#include<utils/Log.h> +} + +#endif + +/* ======================================================================= + + DEFINITIONS AND DECLARATIONS FOR MODULE + + This section contains definitions for constants, macros, types, variables + and other items needed by this module. + + ========================================================================== */ + + +#define MAX_SUPPORTED_LEVEL 32 + + RbspParser::RbspParser (const uint8 *_begin, const uint8 *_end) +: begin (_begin), end(_end), pos (- 1), bit (0), + cursor (0xFFFFFF), advanceNeeded (true) +{ +} + +// Destructor +/*lint -e{1540} Pointer member neither freed nor zeroed by destructor + * No problem + */ +RbspParser::~RbspParser () {} + +// Return next RBSP byte as a word +uint32 RbspParser::next () +{ + if (advanceNeeded) advance (); + //return static_cast<uint32> (*pos); + return static_cast<uint32> (begin[pos]); +} + +// Advance RBSP decoder to next byte +void RbspParser::advance () +{ + ++pos; + //if (pos >= stop) + if (begin + pos == end) { + /*lint -e{730} Boolean argument to function + * I don't see a problem here + */ + //throw false; + ALOGV("H264Parser-->NEED TO THROW THE EXCEPTION..."); + } + cursor <<= 8; + //cursor |= static_cast<uint32> (*pos); + cursor |= static_cast<uint32> (begin[pos]); + if ((cursor & 0xFFFFFF) == 0x000003) { + advance (); + } + advanceNeeded = false; +} + +// Decode unsigned integer +uint32 RbspParser::u (uint32 n) +{ + uint32 i, s, x = 0; + for (i = 0; i < n; i += s) { + s = static_cast<uint32>STD_MIN(static_cast<int>(8 - bit), + static_cast<int>(n - i)); + x <<= s; + + x |= ((next () >> ((8 - static_cast<uint32>(bit)) - s)) & + ((1 << s) - 1)); + + bit = (bit + s) % 8; + if (!bit) { + advanceNeeded = true; + } + } + return x; +} + +// Decode unsigned integer Exp-Golomb-coded syntax element +uint32 RbspParser::ue () +{ + int leadingZeroBits = -1; + for (uint32 b = 0; !b; ++leadingZeroBits) { + b = u (1); + } + return ((1 << leadingZeroBits) - 1) + + u (static_cast<uint32>(leadingZeroBits)); +} + +// Decode signed integer Exp-Golomb-coded syntax element +int32 RbspParser::se () +{ + const uint32 x = ue (); + if (!x) return 0; + else if (x & 1) return static_cast<int32> ((x >> 1) + 1); + else return - static_cast<int32> (x >> 1); +} + +void H264_Utils::allocate_rbsp_buffer(uint32 inputBufferSize) +{ + m_rbspBytes = (byte *) calloc(1,inputBufferSize); + m_prv_nalu.nal_ref_idc = 0; + m_prv_nalu.nalu_type = NALU_TYPE_UNSPECIFIED; +} + +H264_Utils::H264_Utils(): m_height(0), + m_width(0), + m_rbspBytes(NULL), + m_au_data (false) +{ + initialize_frame_checking_environment(); +} + +H264_Utils::~H264_Utils() +{ + /* if(m_pbits) + { + delete(m_pbits); + m_pbits = NULL; + } + */ + if (m_rbspBytes) { + free(m_rbspBytes); + m_rbspBytes = NULL; + } +} + +/***********************************************************************/ +/* +FUNCTION: +H264_Utils::initialize_frame_checking_environment + +DESCRIPTION: +Extract RBSP data from a NAL + +INPUT/OUTPUT PARAMETERS: +None + +RETURN VALUE: +boolean + +SIDE EFFECTS: +None. + */ +/***********************************************************************/ +void H264_Utils::initialize_frame_checking_environment() +{ + m_forceToStichNextNAL = false; + m_au_data = false; + m_prv_nalu.nal_ref_idc = 0; + m_prv_nalu.nalu_type = NALU_TYPE_UNSPECIFIED; +} + +/***********************************************************************/ +/* +FUNCTION: +H264_Utils::extract_rbsp + +DESCRIPTION: +Extract RBSP data from a NAL + +INPUT/OUTPUT PARAMETERS: +<In> +buffer : buffer containing start code or nal length + NAL units +buffer_length : the length of the NAL buffer +start_code : If true, start code is detected, +otherwise size nal length is detected +size_of_nal_length_field: size of nal length field + +<Out> +rbsp_bistream : extracted RBSP bistream +rbsp_length : the length of the RBSP bitstream +nal_unit : decoded NAL header information + +RETURN VALUE: +boolean + +SIDE EFFECTS: +None. + */ +/***********************************************************************/ + +boolean H264_Utils::extract_rbsp(OMX_IN OMX_U8 *buffer, + OMX_IN OMX_U32 buffer_length, + OMX_IN OMX_U32 size_of_nal_length_field, + OMX_OUT OMX_U8 *rbsp_bistream, + OMX_OUT OMX_U32 *rbsp_length, + OMX_OUT NALU *nal_unit) +{ + byte coef1, coef2, coef3; + uint32 pos = 0; + uint32 nal_len = buffer_length; + uint32 sizeofNalLengthField = 0; + uint32 zero_count; + boolean eRet = true; + boolean start_code = (size_of_nal_length_field==0)?true:false; + + if (start_code) { + // Search start_code_prefix_one_3bytes (0x000001) + coef2 = buffer[pos++]; + coef3 = buffer[pos++]; + do { + if (pos >= buffer_length) { + ALOGE("ERROR: In %s() - line %d", __func__, __LINE__); + return false; + } + + coef1 = coef2; + coef2 = coef3; + coef3 = buffer[pos++]; + } while (coef1 || coef2 || coef3 != 1); + } else if (size_of_nal_length_field) { + /* This is the case to play multiple NAL units inside each access unit*/ + /* Extract the NAL length depending on sizeOfNALength field */ + sizeofNalLengthField = size_of_nal_length_field; + nal_len = 0; + while (size_of_nal_length_field--) { + nal_len |= buffer[pos++]<<(size_of_nal_length_field<<3); + } + if (nal_len >= buffer_length) { + ALOGE("ERROR: In %s() - line %d", __func__, __LINE__); + return false; + } + } + + if (nal_len > buffer_length) { + ALOGE("ERROR: In %s() - line %d", __func__, __LINE__); + return false; + } + if (pos + 1 > (nal_len + sizeofNalLengthField)) { + ALOGE("ERROR: In %s() - line %d", __func__, __LINE__); + return false; + } + if ((nal_unit->forbidden_zero_bit = (buffer[pos] & 0x80)) != 0) { + ALOGE("ERROR: In %s() - line %d", __func__, __LINE__); + } + nal_unit->nal_ref_idc = (buffer[pos] & 0x60) >> 5; + nal_unit->nalu_type = buffer[pos++] & 0x1f; + ALOGV("@#@# Pos = %x NalType = %x buflen = %d", + pos-1, nal_unit->nalu_type, buffer_length); + *rbsp_length = 0; + + + if ( nal_unit->nalu_type == NALU_TYPE_EOSEQ || + nal_unit->nalu_type == NALU_TYPE_EOSTREAM) + return (nal_len + sizeofNalLengthField); + + zero_count = 0; + while (pos < (nal_len+sizeofNalLengthField)) { //similar to for in p-42 + if ( zero_count == 2 ) { + if ( buffer[pos] == 0x03 ) { + pos ++; + zero_count = 0; + continue; + } + if ( buffer[pos] <= 0x01 ) { + if ( start_code ) { + *rbsp_length -= 2; + pos -= 2; + return pos; + } + } + zero_count = 0; + } + zero_count ++; + if ( buffer[pos] != 0 ) + zero_count = 0; + + rbsp_bistream[(*rbsp_length)++] = buffer[pos++]; + } + + return eRet; +} + +/*=========================================================================== +FUNCTION: +H264_Utils::iSNewFrame + +DESCRIPTION: +Returns true if NAL parsing successfull otherwise false. + +INPUT/OUTPUT PARAMETERS: +<In> +buffer : buffer containing start code or nal length + NAL units +buffer_length : the length of the NAL buffer +start_code : If true, start code is detected, +otherwise size nal length is detected +size_of_nal_length_field: size of nal length field +<out> +isNewFrame: true if the NAL belongs to a differenet frame +false if the NAL belongs to a current frame + +RETURN VALUE: +boolean true, if nal parsing is successful +false, if the nal parsing has errors + +SIDE EFFECTS: +None. +===========================================================================*/ +bool H264_Utils::isNewFrame(OMX_BUFFERHEADERTYPE *p_buf_hdr, + OMX_IN OMX_U32 size_of_nal_length_field, + OMX_OUT OMX_BOOL &isNewFrame) +{ + NALU nal_unit; + uint16 first_mb_in_slice = 0; + OMX_IN OMX_U32 numBytesInRBSP = 0; + OMX_IN OMX_U8 *buffer = p_buf_hdr->pBuffer; + OMX_IN OMX_U32 buffer_length = p_buf_hdr->nFilledLen; + bool eRet = true; + + ALOGV("isNewFrame: buffer %p buffer_length %d " + "size_of_nal_length_field %d", buffer, buffer_length, + size_of_nal_length_field); + + if ( false == extract_rbsp(buffer, buffer_length, size_of_nal_length_field, + m_rbspBytes, &numBytesInRBSP, &nal_unit) ) { + ALOGE("ERROR: In %s() - extract_rbsp() failed", __func__); + isNewFrame = OMX_FALSE; + eRet = false; + } else { + nalu_type = nal_unit.nalu_type; + switch (nal_unit.nalu_type) { + case NALU_TYPE_IDR: + case NALU_TYPE_NON_IDR: { + ALOGV("AU Boundary with NAL type %d ",nal_unit.nalu_type); + if (m_forceToStichNextNAL) { + isNewFrame = OMX_FALSE; + } else { + RbspParser rbsp_parser(m_rbspBytes, (m_rbspBytes+numBytesInRBSP)); + first_mb_in_slice = rbsp_parser.ue(); + + if ((!first_mb_in_slice) || /*(slice.prv_frame_num != slice.frame_num ) ||*/ + ( (m_prv_nalu.nal_ref_idc != nal_unit.nal_ref_idc) && ( nal_unit.nal_ref_idc * m_prv_nalu.nal_ref_idc == 0 ) ) || + /*( ((m_prv_nalu.nalu_type == NALU_TYPE_IDR) && (nal_unit.nalu_type == NALU_TYPE_IDR)) && (slice.idr_pic_id != slice.prv_idr_pic_id) ) || */ + ( (m_prv_nalu.nalu_type != nal_unit.nalu_type ) && ((m_prv_nalu.nalu_type == NALU_TYPE_IDR) || (nal_unit.nalu_type == NALU_TYPE_IDR)) ) ) { + //ALOGV("Found a New Frame due to NALU_TYPE_IDR/NALU_TYPE_NON_IDR"); + isNewFrame = OMX_TRUE; + } else { + isNewFrame = OMX_FALSE; + } + } + m_au_data = true; + m_forceToStichNextNAL = false; + break; + } + case NALU_TYPE_SPS: + case NALU_TYPE_PPS: + case NALU_TYPE_SEI: { + ALOGV("Non-AU boundary with NAL type %d", nal_unit.nalu_type); + if (m_au_data) { + isNewFrame = OMX_TRUE; + m_au_data = false; + } else { + isNewFrame = OMX_FALSE; + } + + m_forceToStichNextNAL = true; + break; + } + case NALU_TYPE_ACCESS_DELIM: + case NALU_TYPE_UNSPECIFIED: + case NALU_TYPE_EOSEQ: + case NALU_TYPE_EOSTREAM: + default: { + isNewFrame = OMX_FALSE; + // Do not update m_forceToStichNextNAL + break; + } + } // end of switch + } // end of if + m_prv_nalu = nal_unit; + ALOGV("get_h264_nal_type - newFrame value %d",isNewFrame); + return eRet; +} + +void perf_metrics::start() +{ + if (!active) { + start_time = get_act_time(); + active = true; + } +} + +void perf_metrics::stop() +{ + OMX_U64 stop_time = get_act_time(); + if (active) { + proc_time += (stop_time - start_time); + active = false; + } +} + +void perf_metrics::end(OMX_U32 units_cntr) +{ + stop(); + ALOGV("--> Processing time : [%.2f] Sec", (float)proc_time / 1e6); + if (units_cntr) { + ALOGV("--> Avrg proc time : [%.2f] mSec", proc_time / (float)(units_cntr * 1e3)); + } +} + +void perf_metrics::reset() +{ + start_time = 0; + proc_time = 0; + active = false; +} + +OMX_U64 perf_metrics::get_act_time() +{ + struct timeval act_time = {0, 0}; + gettimeofday(&act_time, NULL); + return (act_time.tv_usec + act_time.tv_sec * 1e6); +} + +OMX_U64 perf_metrics::processing_time_us() +{ + return proc_time; +} + +h264_stream_parser::h264_stream_parser() +{ + reset(); +#ifdef PANSCAN_HDLR + panscan_hdl = new panscan_handler(); + if (!panscan_hdl) { + ALOGE("ERROR: Panscan hdl was not allocated!"); + } else if (!panscan_hdl->initialize(10)) { + ALOGE("ERROR: Allocating memory for panscan!"); + delete panscan_hdl; + panscan_hdl = NULL; + } +#else + memset(&panscan_param, 0, sizeof(panscan_param)); + panscan_param.rect_id = NO_PAN_SCAN_BIT; +#endif +} + +h264_stream_parser::~h264_stream_parser() +{ +#ifdef PANSCAN_HDLR + if (panscan_hdl) { + delete panscan_hdl; + panscan_hdl = NULL; + } +#endif +} + +void h264_stream_parser::reset() +{ + curr_32_bit = 0; + bits_read = 0; + zero_cntr = 0; + emulation_code_skip_cntr = 0; + emulation_sc_enabled = true; + bitstream = NULL; + bitstream_bytes = 0; + memset(&vui_param, 0, sizeof(vui_param)); + vui_param.fixed_fps_prev_ts = LLONG_MAX; + memset(&sei_buf_period, 0, sizeof(sei_buf_period)); + memset(&sei_pic_timing, 0, sizeof(sei_pic_timing)); + memset(&frame_packing_arrangement,0,sizeof(frame_packing_arrangement)); + frame_packing_arrangement.cancel_flag = 1; + mbaff_flag = 0; +} + +void h264_stream_parser::init_bitstream(OMX_U8* data, OMX_U32 size) +{ + bitstream = data; + bitstream_bytes = size; + curr_32_bit = 0; + bits_read = 0; + zero_cntr = 0; + emulation_code_skip_cntr = 0; +} + +void h264_stream_parser::parse_vui(bool vui_in_extradata) +{ + OMX_U32 value = 0; + ALOGV("parse_vui: IN"); + if (vui_in_extradata) + while (!extract_bits(1) && more_bits()); // Discard VUI enable flag + if (!more_bits()) + return; + + vui_param.aspect_ratio_info_present_flag = extract_bits(1); //aspect_ratio_info_present_flag + if (vui_param.aspect_ratio_info_present_flag) { + ALOGV("Aspect Ratio Info present!"); + aspect_ratio_info(); + } + + if (extract_bits(1)) //overscan_info_present_flag + extract_bits(1); //overscan_appropriate_flag + if (extract_bits(1)) { //video_signal_type_present_flag + extract_bits(3); //video_format + extract_bits(1); //video_full_range_flag + if (extract_bits(1)) { //colour_description_present_flag + extract_bits(8); //colour_primaries + extract_bits(8); //transfer_characteristics + extract_bits(8); //matrix_coefficients + } + } + if (extract_bits(1)) { //chroma_location_info_present_flag + uev(); //chroma_sample_loc_type_top_field + uev(); //chroma_sample_loc_type_bottom_field + } + vui_param.timing_info_present_flag = extract_bits(1); + if (vui_param.timing_info_present_flag) { + vui_param.num_units_in_tick = extract_bits(32); + vui_param.time_scale = extract_bits(32); + vui_param.fixed_frame_rate_flag = extract_bits(1); + ALOGV("Timing info present in VUI!"); + ALOGV(" num units in tick : %u", vui_param.num_units_in_tick); + ALOGV(" time scale : %u", vui_param.time_scale); + ALOGV(" fixed frame rate : %u", vui_param.fixed_frame_rate_flag); + } + vui_param.nal_hrd_parameters_present_flag = extract_bits(1); + if (vui_param.nal_hrd_parameters_present_flag) { + ALOGV("nal hrd params present!"); + hrd_parameters(&vui_param.nal_hrd_parameters); + } + vui_param.vcl_hrd_parameters_present_flag = extract_bits(1); + if (vui_param.vcl_hrd_parameters_present_flag) { + ALOGV("vcl hrd params present!"); + hrd_parameters(&vui_param.vcl_hrd_parameters); + } + if (vui_param.nal_hrd_parameters_present_flag || + vui_param.vcl_hrd_parameters_present_flag) + vui_param.low_delay_hrd_flag = extract_bits(1); + vui_param.pic_struct_present_flag = extract_bits(1); + ALOGV("pic_struct_present_flag : %u", vui_param.pic_struct_present_flag); + if (extract_bits(1)) { //bitstream_restriction_flag + extract_bits(1); //motion_vectors_over_pic_boundaries_flag + uev(); //max_bytes_per_pic_denom + uev(); //max_bits_per_mb_denom + uev(); //log2_max_mv_length_vertical + uev(); //log2_max_mv_length_horizontal + uev(); //num_reorder_frames + uev(); //max_dec_frame_buffering + } + ALOGV("parse_vui: OUT"); +} + +void h264_stream_parser::aspect_ratio_info() +{ + ALOGV("aspect_ratio_info: IN"); + OMX_U32 aspect_ratio_idc = 0; + OMX_U32 aspect_ratio_x = 0; + OMX_U32 aspect_ratio_y = 0; + aspect_ratio_idc = extract_bits(8); //aspect_ratio_idc + switch (aspect_ratio_idc) { + case 1: + aspect_ratio_x = 1; + aspect_ratio_y = 1; + break; + case 2: + aspect_ratio_x = 12; + aspect_ratio_y = 11; + break; + case 3: + aspect_ratio_x = 10; + aspect_ratio_y = 11; + break; + case 4: + aspect_ratio_x = 16; + aspect_ratio_y = 11; + break; + case 5: + aspect_ratio_x = 40; + aspect_ratio_y = 33; + break; + case 6: + aspect_ratio_x = 24; + aspect_ratio_y = 11; + break; + case 7: + aspect_ratio_x = 20; + aspect_ratio_y = 11; + break; + case 8: + aspect_ratio_x = 32; + aspect_ratio_y = 11; + break; + case 9: + aspect_ratio_x = 80; + aspect_ratio_y = 33; + break; + case 10: + aspect_ratio_x = 18; + aspect_ratio_y = 11; + break; + case 11: + aspect_ratio_x = 15; + aspect_ratio_y = 11; + break; + case 12: + aspect_ratio_x = 64; + aspect_ratio_y = 33; + break; + case 13: + aspect_ratio_x = 160; + aspect_ratio_y = 99; + break; + case 14: + aspect_ratio_x = 4; + aspect_ratio_y = 3; + break; + case 15: + aspect_ratio_x = 3; + aspect_ratio_y = 2; + break; + case 16: + aspect_ratio_x = 2; + aspect_ratio_y = 1; + break; + case 255: + aspect_ratio_x = extract_bits(16); //sar_width + aspect_ratio_y = extract_bits(16); //sar_height + break; + default: + ALOGV("-->aspect_ratio_idc: Reserved Value "); + break; + } + ALOGV("-->aspect_ratio_idc : %u", aspect_ratio_idc); + ALOGV("-->aspect_ratio_x : %u", aspect_ratio_x); + ALOGV("-->aspect_ratio_y : %u", aspect_ratio_y); + vui_param.aspect_ratio_info.aspect_ratio_idc = aspect_ratio_idc; + vui_param.aspect_ratio_info.aspect_ratio_x = aspect_ratio_x; + vui_param.aspect_ratio_info.aspect_ratio_y = aspect_ratio_y; + ALOGV("aspect_ratio_info: OUT"); +} + +void h264_stream_parser::hrd_parameters(h264_hrd_param *hrd_param) +{ + OMX_U32 idx; + ALOGV("hrd_parameters: IN"); + hrd_param->cpb_cnt = uev() + 1; + hrd_param->bit_rate_scale = extract_bits(4); + hrd_param->cpb_size_scale = extract_bits(4); + ALOGV("-->cpb_cnt : %u", hrd_param->cpb_cnt); + ALOGV("-->bit_rate_scale : %u", hrd_param->bit_rate_scale); + ALOGV("-->cpb_size_scale : %u", hrd_param->cpb_size_scale); + if (hrd_param->cpb_cnt > MAX_CPB_COUNT) { + ALOGV("ERROR: Invalid hrd_param->cpb_cnt [%u]!", hrd_param->cpb_cnt); + return; + } + for (idx = 0; idx < hrd_param->cpb_cnt && more_bits(); idx++) { + hrd_param->bit_rate_value[idx] = uev() + 1; + hrd_param->cpb_size_value[idx] = uev() + 1; + hrd_param->cbr_flag[idx] = extract_bits(1); + ALOGV("-->bit_rate_value [%d] : %u", idx, hrd_param->bit_rate_value[idx]); + ALOGV("-->cpb_size_value [%d] : %u", idx, hrd_param->cpb_size_value[idx]); + ALOGV("-->cbr_flag [%d] : %u", idx, hrd_param->cbr_flag[idx]); + } + hrd_param->initial_cpb_removal_delay_length = extract_bits(5) + 1; + hrd_param->cpb_removal_delay_length = extract_bits(5) + 1; + hrd_param->dpb_output_delay_length = extract_bits(5) + 1; + hrd_param->time_offset_length = extract_bits(5); + ALOGV("-->initial_cpb_removal_delay_length : %u", hrd_param->initial_cpb_removal_delay_length); + ALOGV("-->cpb_removal_delay_length : %u", hrd_param->cpb_removal_delay_length); + ALOGV("-->dpb_output_delay_length : %u", hrd_param->dpb_output_delay_length); + ALOGV("-->time_offset_length : %u", hrd_param->time_offset_length); + ALOGV("hrd_parameters: OUT"); +} + +void h264_stream_parser::parse_sei() +{ + OMX_U32 value = 0, processed_bytes = 0; + OMX_U8 *sei_msg_start = bitstream; + OMX_U32 sei_unit_size = bitstream_bytes; + ALOGV("@@parse_sei: IN sei_unit_size(%u)", sei_unit_size); + while ((processed_bytes + 2) < sei_unit_size && more_bits()) { + init_bitstream(sei_msg_start + processed_bytes, sei_unit_size - processed_bytes); + ALOGV("-->NALU_TYPE_SEI"); + OMX_U32 payload_type = 0, payload_size = 0, aux = 0; + do { + value = extract_bits(8); + payload_type += value; + processed_bytes++; + } while (value == 0xFF); + ALOGV("-->payload_type : %u", payload_type); + do { + value = extract_bits(8); + payload_size += value; + processed_bytes++; + } while (value == 0xFF); + ALOGV("-->payload_size : %u", payload_size); + if (payload_size > 0) { + switch (payload_type) { + case BUFFERING_PERIOD: + sei_buffering_period(); + break; + case PIC_TIMING: + sei_picture_timing(); + break; + case PAN_SCAN_RECT: + sei_pan_scan(); + break; + case SEI_PAYLOAD_FRAME_PACKING_ARRANGEMENT: + parse_frame_pack(); + break; + default: + ALOGV("-->SEI payload type [%u] not implemented! size[%u]", payload_type, payload_size); + } + } + processed_bytes += (payload_size + emulation_code_skip_cntr); + ALOGV("-->SEI processed_bytes[%u]", processed_bytes); + } + ALOGV("@@parse_sei: OUT"); +} + +void h264_stream_parser::sei_buffering_period() +{ + OMX_U32 idx; + OMX_U32 value = 0; + h264_hrd_param *hrd_param = NULL; + ALOGV("@@sei_buffering_period: IN"); + value = uev(); // seq_parameter_set_id + ALOGV("-->seq_parameter_set_id : %u", value); + if (value > 31) { + ALOGV("ERROR: Invalid seq_parameter_set_id [%u]!", value); + return; + } + sei_buf_period.is_valid = false; + if (vui_param.nal_hrd_parameters_present_flag) { + hrd_param = &vui_param.nal_hrd_parameters; + if (hrd_param->cpb_cnt > MAX_CPB_COUNT) { + ALOGV("ERROR: Invalid hrd_param->cpb_cnt [%u]!", hrd_param->cpb_cnt); + return; + } + for (idx = 0; idx < hrd_param->cpb_cnt ; idx++) { + sei_buf_period.is_valid = true; + sei_buf_period.initial_cpb_removal_delay[idx] = extract_bits(hrd_param->initial_cpb_removal_delay_length); + sei_buf_period.initial_cpb_removal_delay_offset[idx] = extract_bits(hrd_param->initial_cpb_removal_delay_length); + ALOGV("-->initial_cpb_removal_delay : %u", sei_buf_period.initial_cpb_removal_delay[idx]); + ALOGV("-->initial_cpb_removal_delay_offset : %u", sei_buf_period.initial_cpb_removal_delay_offset[idx]); + } + } + if (vui_param.vcl_hrd_parameters_present_flag) { + hrd_param = &vui_param.vcl_hrd_parameters; + if (hrd_param->cpb_cnt > MAX_CPB_COUNT) { + ALOGV("ERROR: Invalid hrd_param->cpb_cnt [%u]!", hrd_param->cpb_cnt); + return; + } + for (idx = 0; idx < hrd_param->cpb_cnt ; idx++) { + sei_buf_period.is_valid = true; + sei_buf_period.initial_cpb_removal_delay[idx] = extract_bits(hrd_param->initial_cpb_removal_delay_length); + sei_buf_period.initial_cpb_removal_delay_offset[idx] = extract_bits(hrd_param->initial_cpb_removal_delay_length); + ALOGV("-->initial_cpb_removal_delay : %u", sei_buf_period.initial_cpb_removal_delay[idx]); + ALOGV("-->initial_cpb_removal_delay_offset : %u", sei_buf_period.initial_cpb_removal_delay_offset[idx]); + } + } + sei_buf_period.au_cntr = 0; + ALOGV("@@sei_buffering_period: OUT"); +} + +void h264_stream_parser::sei_picture_timing() +{ + ALOGV("@@sei_picture_timing: IN"); + OMX_U32 time_offset_len = 0, cpb_removal_len = 24, dpb_output_len = 24; + OMX_U8 cbr_flag = 0; + sei_pic_timing.is_valid = true; + if (vui_param.nal_hrd_parameters_present_flag) { + cpb_removal_len = vui_param.nal_hrd_parameters.cpb_removal_delay_length; + dpb_output_len = vui_param.nal_hrd_parameters.dpb_output_delay_length; + time_offset_len = vui_param.nal_hrd_parameters.time_offset_length; + cbr_flag = vui_param.nal_hrd_parameters.cbr_flag[0]; + } else if (vui_param.vcl_hrd_parameters_present_flag) { + cpb_removal_len = vui_param.vcl_hrd_parameters.cpb_removal_delay_length; + dpb_output_len = vui_param.vcl_hrd_parameters.dpb_output_delay_length; + time_offset_len = vui_param.vcl_hrd_parameters.time_offset_length; + cbr_flag = vui_param.vcl_hrd_parameters.cbr_flag[0]; + } + sei_pic_timing.cpb_removal_delay = extract_bits(cpb_removal_len); + sei_pic_timing.dpb_output_delay = extract_bits(dpb_output_len); + ALOGV("-->cpb_removal_len : %u", cpb_removal_len); + ALOGV("-->dpb_output_len : %u", dpb_output_len); + ALOGV("-->cpb_removal_delay : %u", sei_pic_timing.cpb_removal_delay); + ALOGV("-->dpb_output_delay : %u", sei_pic_timing.dpb_output_delay); + if (vui_param.pic_struct_present_flag) { + sei_pic_timing.pic_struct = extract_bits(4); + sei_pic_timing.num_clock_ts = 0; + switch (sei_pic_timing.pic_struct) { + case 0: + case 1: + case 2: + sei_pic_timing.num_clock_ts = 1; + break; + case 3: + case 4: + case 7: + sei_pic_timing.num_clock_ts = 2; + break; + case 5: + case 6: + case 8: + sei_pic_timing.num_clock_ts = 3; + break; + default: + ALOGE("sei_picture_timing: pic_struct invalid!"); + } + ALOGV("-->num_clock_ts : %u", sei_pic_timing.num_clock_ts); + for (OMX_U32 i = 0; i < sei_pic_timing.num_clock_ts && more_bits(); i++) { + sei_pic_timing.clock_ts_flag = extract_bits(1); + if (sei_pic_timing.clock_ts_flag) { + ALOGV("-->clock_timestamp present!"); + sei_pic_timing.ct_type = extract_bits(2); + sei_pic_timing.nuit_field_based_flag = extract_bits(1); + sei_pic_timing.counting_type = extract_bits(5); + sei_pic_timing.full_timestamp_flag = extract_bits(1); + sei_pic_timing.discontinuity_flag = extract_bits(1); + sei_pic_timing.cnt_dropped_flag = extract_bits(1); + sei_pic_timing.n_frames = extract_bits(8); + ALOGV("-->f_timestamp_flg : %u", sei_pic_timing.full_timestamp_flag); + ALOGV("-->n_frames : %u", sei_pic_timing.n_frames); + sei_pic_timing.seconds_value = 0; + sei_pic_timing.minutes_value = 0; + sei_pic_timing.hours_value = 0; + if (sei_pic_timing.full_timestamp_flag) { + sei_pic_timing.seconds_value = extract_bits(6); + sei_pic_timing.minutes_value = extract_bits(6); + sei_pic_timing.hours_value = extract_bits(5); + } else if (extract_bits(1)) { + ALOGV("-->seconds_flag enabled!"); + sei_pic_timing.seconds_value = extract_bits(6); + if (extract_bits(1)) { + ALOGV("-->minutes_flag enabled!"); + sei_pic_timing.minutes_value = extract_bits(6); + if (extract_bits(1)) { + ALOGV("-->hours_flag enabled!"); + sei_pic_timing.hours_value = extract_bits(5); + } + } + } + sei_pic_timing.time_offset = 0; + if (time_offset_len > 0) + sei_pic_timing.time_offset = iv(time_offset_len); + ALOGV("-->seconds_value : %u", sei_pic_timing.seconds_value); + ALOGV("-->minutes_value : %u", sei_pic_timing.minutes_value); + ALOGV("-->hours_value : %u", sei_pic_timing.hours_value); + ALOGV("-->time_offset : %d", sei_pic_timing.time_offset); + } + } + } + ALOGV("@@sei_picture_timing: OUT"); +} + +void h264_stream_parser::sei_pan_scan() +{ +#ifdef _ANDROID_ + char property_value[PROPERTY_VALUE_MAX] = {0}; + OMX_S32 enable_panscan_log = 0; + property_get("vidc.dec.debug.panframedata", property_value, "0"); + enable_panscan_log = atoi(property_value); +#endif +#ifdef PANSCAN_HDLR + h264_pan_scan *pan_scan_param = panscan_hdl->get_free(); +#else + h264_pan_scan *pan_scan_param = &panscan_param; +#endif + + if (!pan_scan_param) { + ALOGE("sei_pan_scan: ERROR: Invalid pointer!"); + return; + } + + pan_scan_param->rect_id = uev(); + if (pan_scan_param->rect_id > 0xFF) { + ALOGE("sei_pan_scan: ERROR: Invalid rect_id[%u]!", (unsigned int)pan_scan_param->rect_id); + pan_scan_param->rect_id = NO_PAN_SCAN_BIT; + return; + } + + pan_scan_param->rect_cancel_flag = extract_bits(1); + + if (pan_scan_param->rect_cancel_flag) + pan_scan_param->rect_id = NO_PAN_SCAN_BIT; + else { + pan_scan_param->cnt = uev() + 1; + if (pan_scan_param->cnt > MAX_PAN_SCAN_RECT) { + ALOGE("sei_pan_scan: ERROR: Invalid num of rect [%u]!", (unsigned int)pan_scan_param->cnt); + pan_scan_param->rect_id = NO_PAN_SCAN_BIT; + return; + } + + for (OMX_U32 i = 0; i < pan_scan_param->cnt; i++) { + pan_scan_param->rect_left_offset[i] = sev(); + pan_scan_param->rect_right_offset[i] = sev(); + pan_scan_param->rect_top_offset[i] = sev(); + pan_scan_param->rect_bottom_offset[i] = sev(); + + } + pan_scan_param->rect_repetition_period = uev(); +#ifdef PANSCAN_HDLR + if (pan_scan_param->rect_repetition_period > 1) + // Repetition period is decreased by 2 each time panscan data is used + pan_scan_param->rect_repetition_period *= 2; +#endif +#ifdef _ANDROID_ + if (enable_panscan_log) { + print_pan_data(pan_scan_param); + } +#endif + } +} + +void h264_stream_parser::print_pan_data(h264_pan_scan *pan_scan_param) +{ + ALOGE("@@print_pan_data: IN"); + + ALOGE("-->rect_id : %u", (unsigned int)pan_scan_param->rect_id); + ALOGE("-->rect_cancel_flag : %u", pan_scan_param->rect_cancel_flag); + + ALOGE("-->cnt : %u", (unsigned int)pan_scan_param->cnt); + + for (OMX_U32 i = 0; i < pan_scan_param->cnt; i++) { + ALOGE("-->rect_left_offset : %d", (int)pan_scan_param->rect_left_offset[i]); + ALOGE("-->rect_right_offset : %d", (int)pan_scan_param->rect_right_offset[i]); + ALOGE("-->rect_top_offset : %d", (int)pan_scan_param->rect_top_offset[i]); + ALOGE("-->rect_bottom_offset : %d", (int)pan_scan_param->rect_bottom_offset[i]); + } + ALOGE("-->repetition_period : %u", (unsigned int)pan_scan_param->rect_repetition_period); + + ALOGE("@@print_pan_data: OUT"); +} + +void h264_stream_parser::parse_sps() +{ + OMX_U32 value = 0, scaling_matrix_limit; + ALOGV("@@parse_sps: IN"); + value = extract_bits(8); //profile_idc + profile = value; + extract_bits(8); //constraint flags and reserved bits + extract_bits(8); //level_idc + uev(); //sps id + if (value == 100 || value == 110 || value == 122 || value == 244 || + value == 44 || value == 83 || value == 86 || value == 118) { + if (uev() == 3) { //chroma_format_idc + extract_bits(1); //separate_colour_plane_flag + scaling_matrix_limit = 12; + } else + scaling_matrix_limit = 12; + uev(); //bit_depth_luma_minus8 + uev(); //bit_depth_chroma_minus8 + extract_bits(1); //qpprime_y_zero_transform_bypass_flag + if (extract_bits(1)) { //seq_scaling_matrix_present_flag + for (unsigned int i = 0; i < scaling_matrix_limit && more_bits(); i++) { + if (extract_bits(1)) { ////seq_scaling_list_present_flag[ i ] + if (i < 6) + scaling_list(16); + else + scaling_list(64); + } + } + } + } + uev(); //log2_max_frame_num_minus4 + value = uev(); //pic_order_cnt_type + if (value == 0) + uev(); //log2_max_pic_order_cnt_lsb_minus4 + else if (value == 1) { + extract_bits(1); //delta_pic_order_always_zero_flag + sev(); //offset_for_non_ref_pic + sev(); //offset_for_top_to_bottom_field + value = uev(); // num_ref_frames_in_pic_order_cnt_cycle + for (unsigned int i = 0; i < value; i++) + sev(); //offset_for_ref_frame[ i ] + } + uev(); //max_num_ref_frames + extract_bits(1); //gaps_in_frame_num_value_allowed_flag + value = uev(); //pic_width_in_mbs_minus1 + value = uev(); //pic_height_in_map_units_minus1 + if (!extract_bits(1)) //frame_mbs_only_flag + mbaff_flag = extract_bits(1); //mb_adaptive_frame_field_flag + extract_bits(1); //direct_8x8_inference_flag + if (extract_bits(1)) { //frame_cropping_flag + uev(); //frame_crop_left_offset + uev(); //frame_crop_right_offset + uev(); //frame_crop_top_offset + uev(); //frame_crop_bottom_offset + } + if (extract_bits(1)) //vui_parameters_present_flag + parse_vui(false); + ALOGV("@@parse_sps: OUT"); +} + +void h264_stream_parser::scaling_list(OMX_U32 size_of_scaling_list) +{ + OMX_S32 last_scale = 8, next_scale = 8, delta_scale; + for (unsigned int j = 0; j < size_of_scaling_list; j++) { + if (next_scale != 0) { + delta_scale = sev(); + next_scale = (last_scale + delta_scale + 256) % 256; + } + last_scale = (next_scale == 0)? last_scale : next_scale; + } +} + +OMX_U32 h264_stream_parser::extract_bits(OMX_U32 n) +{ + OMX_U32 value = 0; + if (n > 32) { + ALOGE("ERROR: extract_bits limit to 32 bits!"); + return value; + } + value = curr_32_bit >> (32 - n); + if (bits_read < n) { + n -= bits_read; + read_word(); + value |= (curr_32_bit >> (32 - n)); + if (bits_read < n) { + ALOGV("ERROR: extract_bits underflow!"); + value >>= (n - bits_read); + n = bits_read; + } + } + bits_read -= n; + curr_32_bit <<= n; + return value; +} + +void h264_stream_parser::read_word() +{ + curr_32_bit = 0; + bits_read = 0; + while (bitstream_bytes && bits_read < 32) { + if (*bitstream == EMULATION_PREVENTION_THREE_BYTE && + zero_cntr >= 2 && emulation_sc_enabled) { + ALOGV("EMULATION_PREVENTION_THREE_BYTE: Skip 0x03 byte aligned!"); + emulation_code_skip_cntr++; + } else { + curr_32_bit <<= 8; + curr_32_bit |= *bitstream; + bits_read += 8; + } + if (*bitstream == 0) + zero_cntr++; + else + zero_cntr = 0; + bitstream++; + bitstream_bytes--; + } + curr_32_bit <<= (32 - bits_read); +} + +OMX_U32 h264_stream_parser::uev() +{ + OMX_U32 lead_zero_bits = 0, code_num = 0; + while (!extract_bits(1) && more_bits()) + lead_zero_bits++; + code_num = lead_zero_bits == 0 ? 0 : + (1 << lead_zero_bits) - 1 + extract_bits(lead_zero_bits); + return code_num; +} + +bool h264_stream_parser::more_bits() +{ + return (bitstream_bytes > 0 || bits_read > 0); +} + +OMX_S32 h264_stream_parser::sev() +{ + OMX_U32 code_num = uev(); + OMX_S32 ret; + ret = (code_num + 1) >> 1; + return ((code_num & 1) ? ret : -ret); +} + +OMX_S32 h264_stream_parser::iv(OMX_U32 n_bits) +{ + OMX_U32 code_num = extract_bits(n_bits); + OMX_S32 ret = (code_num >> (n_bits - 1))? (-1)*(~(code_num & ~(0x1 << (n_bits - 1))) + 1) : code_num; + return ret; +} + +OMX_U32 h264_stream_parser::get_nal_unit_type(OMX_U32 *nal_unit_type) +{ + OMX_U32 value = 0, consumed_bytes = 3; + *nal_unit_type = NALU_TYPE_UNSPECIFIED; + ALOGV("-->get_nal_unit_type: IN"); + value = extract_bits(24); + while (value != 0x00000001 && more_bits()) { + value <<= 8; + value |= extract_bits(8); + consumed_bytes++; + } + if (value != 0x00000001) { + ALOGE("ERROR in get_nal_unit_type: Start code not found!"); + } else { + if (extract_bits(1)) { // forbidden_zero_bit + ALOGE("WARNING: forbidden_zero_bit should be zero!"); + } + value = extract_bits(2); + ALOGV("-->nal_ref_idc : %x", value); + *nal_unit_type = extract_bits(5); + ALOGV("-->nal_unit_type : %x", *nal_unit_type); + consumed_bytes++; + if (consumed_bytes > 5) { + ALOGE("-->WARNING: Startcode was found after the first 4 bytes!"); + } + } + ALOGV("-->get_nal_unit_type: OUT"); + return consumed_bytes; +} + +OMX_U32 h264_stream_parser::get_profile() +{ + return profile; +} + +OMX_S64 h264_stream_parser::calculate_buf_period_ts(OMX_S64 timestamp) +{ + OMX_S64 clock_ts = timestamp; + ALOGV("calculate_ts(): IN"); + if (sei_buf_period.au_cntr == 0) + clock_ts = sei_buf_period.reference_ts = timestamp; + else if (sei_pic_timing.is_valid && VALID_TS(sei_buf_period.reference_ts)) { + clock_ts = sei_buf_period.reference_ts + sei_pic_timing.cpb_removal_delay * + 1e6 * vui_param.num_units_in_tick / vui_param.time_scale; + } + sei_buf_period.au_cntr++; + ALOGV("calculate_ts(): OUT"); + return clock_ts; +} + +OMX_S64 h264_stream_parser::calculate_fixed_fps_ts(OMX_S64 timestamp, OMX_U32 DeltaTfiDivisor) +{ + if (VALID_TS(timestamp)) + vui_param.fixed_fps_prev_ts = timestamp; + else if (VALID_TS(vui_param.fixed_fps_prev_ts)) + vui_param.fixed_fps_prev_ts += DeltaTfiDivisor * 1e6 * + vui_param.num_units_in_tick / vui_param.time_scale; + return vui_param.fixed_fps_prev_ts; +} + +void h264_stream_parser::parse_frame_pack() +{ +#ifdef _ANDROID_ + char property_value[PROPERTY_VALUE_MAX] = {0}; + OMX_S32 enable_framepack_log = 0; + + property_get("vidc.dec.debug.panframedata", property_value, "0"); + enable_framepack_log = atoi(property_value); +#endif + ALOGV("%s:%d parse_frame_pack", __func__, __LINE__); + + frame_packing_arrangement.id = uev(); + + frame_packing_arrangement.cancel_flag = extract_bits(1); + if (!frame_packing_arrangement.cancel_flag) { + frame_packing_arrangement.type = extract_bits(7); + frame_packing_arrangement.quincunx_sampling_flag = extract_bits(1); + frame_packing_arrangement.content_interpretation_type = extract_bits(6); + frame_packing_arrangement.spatial_flipping_flag = extract_bits(1); + frame_packing_arrangement.frame0_flipped_flag = extract_bits(1); + frame_packing_arrangement.field_views_flag = extract_bits(1); + frame_packing_arrangement.current_frame_is_frame0_flag = extract_bits(1); + frame_packing_arrangement.frame0_self_contained_flag = extract_bits(1); + frame_packing_arrangement.frame1_self_contained_flag = extract_bits(1); + + if (!frame_packing_arrangement.quincunx_sampling_flag && + frame_packing_arrangement.type != 5) { + frame_packing_arrangement.frame0_grid_position_x = extract_bits(4); + frame_packing_arrangement.frame0_grid_position_y = extract_bits(4); + frame_packing_arrangement.frame1_grid_position_x = extract_bits(4); + frame_packing_arrangement.frame1_grid_position_y = extract_bits(4); + } + frame_packing_arrangement.reserved_byte = extract_bits(8); + frame_packing_arrangement.repetition_period = uev(); + } + frame_packing_arrangement.extension_flag = extract_bits(1); + +#ifdef _ANDROID_ + if (enable_framepack_log) { + print_frame_pack(); + } +#endif +} + +void h264_stream_parser::print_frame_pack() +{ + ALOGV("## frame_packing_arrangement.id = %u", frame_packing_arrangement.id); + ALOGV("## frame_packing_arrangement.cancel_flag = %u", + frame_packing_arrangement.cancel_flag); + if (!frame_packing_arrangement.cancel_flag) { + ALOGV("## frame_packing_arrangement.type = %u", + frame_packing_arrangement.type); + ALOGV("## frame_packing_arrangement.quincunx_sampling_flag = %u", + frame_packing_arrangement.quincunx_sampling_flag); + ALOGV("## frame_packing_arrangement.content_interpretation_type = %u", + frame_packing_arrangement.content_interpretation_type); + ALOGV("## frame_packing_arrangement.spatial_flipping_flag = %u", + frame_packing_arrangement.spatial_flipping_flag); + ALOGV("## frame_packing_arrangement.frame0_flipped_flag = %u", + frame_packing_arrangement.frame0_flipped_flag); + ALOGV("## frame_packing_arrangement.field_views_flag = %u", + frame_packing_arrangement.field_views_flag); + ALOGV("## frame_packing_arrangement.current_frame_is_frame0_flag = %u", + frame_packing_arrangement.current_frame_is_frame0_flag); + ALOGV("## frame_packing_arrangement.frame0_self_contained_flag = %u", + frame_packing_arrangement.frame0_self_contained_flag); + ALOGV("## frame_packing_arrangement.frame1_self_contained_flag = %u", + frame_packing_arrangement.frame1_self_contained_flag); + ALOGV("## frame_packing_arrangement.reserved_byte = %u", + frame_packing_arrangement.reserved_byte); + ALOGV("## frame_packing_arrangement.repetition_period = %u", + frame_packing_arrangement.repetition_period); + ALOGV("## frame_packing_arrangement.extension_flag = %u", + frame_packing_arrangement.extension_flag); + } +} +/* API'S EXPOSED TO OMX COMPONENT */ + +void h264_stream_parser::get_frame_pack_data( + OMX_QCOM_FRAME_PACK_ARRANGEMENT *frame_pack) +{ + ALOGV("%s:%d get frame data", __func__, __LINE__); + memcpy(&frame_pack->id,&frame_packing_arrangement.id, + FRAME_PACK_SIZE*sizeof(OMX_U32)); + return; +} + + +bool h264_stream_parser::is_mbaff() +{ + ALOGV("%s:%d MBAFF flag=%d", __func__, __LINE__,mbaff_flag); + return mbaff_flag; +} + +void h264_stream_parser::get_frame_rate(OMX_U32 *frame_rate) +{ + if (vui_param.num_units_in_tick != 0) + *frame_rate = vui_param.time_scale / (2 * vui_param.num_units_in_tick); +} + +void h264_stream_parser::parse_nal(OMX_U8* data_ptr, OMX_U32 data_len, OMX_U32 nal_type, bool enable_emu_sc) +{ + OMX_U32 nal_unit_type = NALU_TYPE_UNSPECIFIED, cons_bytes = 0; + ALOGV("parse_nal(): IN nal_type(%u)", nal_type); + if (!data_len) + return; + init_bitstream(data_ptr, data_len); + emulation_sc_enabled = enable_emu_sc; + if (nal_type != NALU_TYPE_VUI) { + cons_bytes = get_nal_unit_type(&nal_unit_type); + if (nal_type != nal_unit_type && nal_type != NALU_TYPE_UNSPECIFIED) { + ALOGV("Unexpected nal_type(%x) expected(%x)", nal_unit_type, nal_type); + return; + } + } + switch (nal_type) { + case NALU_TYPE_SPS: + if (more_bits()) + parse_sps(); +#ifdef PANSCAN_HDLR + panscan_hdl->get_free(); +#endif + break; + case NALU_TYPE_SEI: + init_bitstream(data_ptr + cons_bytes, data_len - cons_bytes); + parse_sei(); + break; + case NALU_TYPE_VUI: + parse_vui(true); + break; + default: + ALOGV("nal_unit_type received : %u", nal_type); + } + ALOGV("parse_nal(): OUT"); +} + +#ifdef PANSCAN_HDLR +void h264_stream_parser::update_panscan_data(OMX_S64 timestamp) +{ + panscan_hdl->update_last(timestamp); +} +#endif + +void h264_stream_parser::fill_aspect_ratio_info(OMX_QCOM_ASPECT_RATIO *dest_aspect_ratio) +{ + if (dest_aspect_ratio && vui_param.aspect_ratio_info_present_flag) { + dest_aspect_ratio->aspectRatioX = vui_param.aspect_ratio_info.aspect_ratio_x; + dest_aspect_ratio->aspectRatioY = vui_param.aspect_ratio_info.aspect_ratio_y; + } +} + +void h264_stream_parser::fill_pan_scan_data(OMX_QCOM_PANSCAN *dest_pan_scan, OMX_S64 timestamp) +{ +#ifdef PANSCAN_HDLR + h264_pan_scan *pan_scan_param = panscan_hdl->get_populated(timestamp); +#else + h264_pan_scan *pan_scan_param = &panscan_param; +#endif + if (pan_scan_param) { + if (!(pan_scan_param->rect_id & NO_PAN_SCAN_BIT)) { + PRINT_PANSCAN_PARAM(*pan_scan_param); + dest_pan_scan->numWindows = pan_scan_param->cnt; + for (unsigned int i = 0; i < dest_pan_scan->numWindows; i++) { + dest_pan_scan->window[i].x = pan_scan_param->rect_left_offset[i]; + dest_pan_scan->window[i].y = pan_scan_param->rect_top_offset[i]; + dest_pan_scan->window[i].dx = pan_scan_param->rect_right_offset[i]; + dest_pan_scan->window[i].dy = pan_scan_param->rect_bottom_offset[i]; + } +#ifndef PANSCAN_HDLR + if (pan_scan_param->rect_repetition_period == 0) + pan_scan_param->rect_id = NO_PAN_SCAN_BIT; + else if (pan_scan_param->rect_repetition_period > 1) + pan_scan_param->rect_repetition_period = + (pan_scan_param->rect_repetition_period == 2)? 0 : + (pan_scan_param->rect_repetition_period - 1); +#endif + } else + pan_scan_param->rect_repetition_period = 0; + } +} + +OMX_S64 h264_stream_parser::process_ts_with_sei_vui(OMX_S64 timestamp) +{ + bool clock_ts_flag = false; + OMX_S64 clock_ts = timestamp; + OMX_U32 deltaTfiDivisor = 2; + if (vui_param.timing_info_present_flag) { + if (vui_param.pic_struct_present_flag) { + if (sei_pic_timing.clock_ts_flag) { + clock_ts = ((sei_pic_timing.hours_value * 60 + sei_pic_timing.minutes_value) * 60 + sei_pic_timing.seconds_value) * 1e6 + + (sei_pic_timing.n_frames * (vui_param.num_units_in_tick * (1 + sei_pic_timing.nuit_field_based_flag)) + sei_pic_timing.time_offset) * + 1e6 / vui_param.time_scale; + ALOGV("-->CLOCK TIMESTAMP : %lld", clock_ts); + clock_ts_flag = true; + } + if (vui_param.fixed_frame_rate_flag) { + switch (sei_pic_timing.pic_struct) { + case 1: + case 2: + deltaTfiDivisor = 1; + break; + case 0: + case 3: + case 4: + deltaTfiDivisor = 2; + break; + case 5: + case 6: + deltaTfiDivisor = 3; + break; + case 7: + deltaTfiDivisor = 4; + break; + case 8: + deltaTfiDivisor = 6; + break; + default: + ALOGE("process_ts_with_sei_vui: pic_struct invalid!"); + } + } + } + if (!clock_ts_flag) { + if (vui_param.fixed_frame_rate_flag) + clock_ts = calculate_fixed_fps_ts(timestamp, deltaTfiDivisor); + else if (sei_buf_period.is_valid) + clock_ts = calculate_buf_period_ts(timestamp); + } + } else { + ALOGV("NO TIMING information present in VUI!"); + } + sei_pic_timing.is_valid = false; // SEI data is valid only for current frame + return clock_ts; +} + +#ifdef PANSCAN_HDLR + +panscan_handler::panscan_handler() : panscan_data(NULL) {} + +panscan_handler::~panscan_handler() +{ + if (panscan_data) { + free(panscan_data); + panscan_data = NULL; + } +} + +bool panscan_handler::initialize(int num_data) +{ + bool ret = false; + if (!panscan_data) { + panscan_data = (PANSCAN_NODE *) malloc (sizeof(PANSCAN_NODE) * num_data); + if (panscan_data) { + panscan_free.add_multiple(panscan_data, num_data); + ret = true; + } + } else { + ALOGE("ERROR: Old panscan memory must be freed to allocate new"); + } + return ret; +} + +h264_pan_scan *panscan_handler::get_free() +{ + h264_pan_scan *data = NULL; + PANSCAN_NODE *panscan_node = panscan_used.watch_last(); + panscan_node = (!panscan_node || VALID_TS(panscan_node->start_ts))? + panscan_free.remove_first() : + panscan_used.remove_last(); + if (panscan_node) { + panscan_node->start_ts = LLONG_MAX; + panscan_node->end_ts = LLONG_MAX; + panscan_node->pan_scan_param.rect_id = NO_PAN_SCAN_BIT; + panscan_node->active = false; + panscan_used.add_last(panscan_node); + data = &panscan_node->pan_scan_param; + } + return data; +} + +h264_pan_scan *panscan_handler::get_populated(OMX_S64 frame_ts) +{ + h264_pan_scan *data = NULL; + PANSCAN_NODE *panscan_node = panscan_used.watch_first(); + while (panscan_node && !data) { + if (VALID_TS(panscan_node->start_ts)) { + if (panscan_node->active && frame_ts < panscan_node->start_ts) + panscan_node->start_ts = frame_ts; + if (frame_ts >= panscan_node->start_ts) + if (frame_ts < panscan_node->end_ts) { + data = &panscan_node->pan_scan_param; + panscan_node->active = true; + } else { + panscan_free.add_last(panscan_used.remove_first()); + panscan_node = panscan_used.watch_first(); + } + else + // Finish search if current timestamp has not reached + // start timestamp of first panscan data. + panscan_node = NULL; + } else { + // Only one panscan data is stored for clips + // with invalid timestamps in every frame + data = &panscan_node->pan_scan_param; + panscan_node->active = true; + } + } + if (data) { + if (data->rect_repetition_period == 0) + panscan_free.add_last(panscan_used.remove_first()); + else if (data->rect_repetition_period > 1) + data->rect_repetition_period -= 2; + } + PRINT_PANSCAN_DATA(panscan_node); + return data; +} + +void panscan_handler::update_last(OMX_S64 frame_ts) +{ + PANSCAN_NODE *panscan_node = panscan_used.watch_last(); + if (panscan_node && !VALID_TS(panscan_node->start_ts)) { + panscan_node->start_ts = frame_ts; + PRINT_PANSCAN_DATA(panscan_node); + if (panscan_node->prev) { + if (frame_ts < panscan_node->prev->end_ts) + panscan_node->prev->end_ts = frame_ts; + else if (!VALID_TS(frame_ts)) + panscan_node->prev->pan_scan_param.rect_repetition_period = 0; + PRINT_PANSCAN_DATA(panscan_node->prev); + } + } +} + + template <class NODE_STRUCT> +void omx_dl_list<NODE_STRUCT>::add_multiple(NODE_STRUCT *data_arr, int data_num) +{ + for (int idx = 0; idx < data_num; idx++) + add_last(&data_arr[idx]); +} + + template <class NODE_STRUCT> +NODE_STRUCT *omx_dl_list<NODE_STRUCT>::remove_first() +{ + NODE_STRUCT *data = head; + if (head) { + if (head->next) { + head = head->next; + head->prev = NULL; + } else + head = tail = NULL; + data->next = data->prev = NULL; + } + return data; +} + + template <class NODE_STRUCT> +NODE_STRUCT *omx_dl_list<NODE_STRUCT>::remove_last() +{ + NODE_STRUCT *data = tail; + if (tail) { + if (tail->prev) { + tail = tail->prev; + tail->next = NULL; + } else + head = tail = NULL; + data->next = data->prev = NULL; + } + return data; +} + + template <class NODE_STRUCT> +void omx_dl_list<NODE_STRUCT>::add_last(NODE_STRUCT* data_ptr) +{ + if (data_ptr) { + data_ptr->next = NULL; + data_ptr->prev = tail; + if (tail) { + tail->next = data_ptr; + tail = data_ptr; + } else + head = tail = data_ptr; + } +} + + template <class NODE_STRUCT> +NODE_STRUCT* omx_dl_list<NODE_STRUCT>::watch_first() +{ + return head; +} + + template <class NODE_STRUCT> +NODE_STRUCT* omx_dl_list<NODE_STRUCT>::watch_last() +{ + return tail; +} + +#endif diff --git a/msm8998/mm-video-v4l2/vidc/vdec/src/hevc_utils.cpp b/msm8998/mm-video-v4l2/vidc/vdec/src/hevc_utils.cpp new file mode 100644 index 0000000..198789a --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/src/hevc_utils.cpp @@ -0,0 +1,221 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ + +/*======================================================================== + + O p e n M M + V i d e o U t i l i t i e s + +*//** @file VideoUtils.cpp + This module contains utilities and helper routines. + +@par EXTERNALIZED FUNCTIONS + +@par INITIALIZATION AND SEQUENCING REQUIREMENTS + (none) + +*//*====================================================================== */ + +/* ======================================================================= + + INCLUDE FILES FOR MODULE + +========================================================================== */ +#include "hevc_utils.h" +#include "vidc_debug.h" +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#include <sys/time.h> +#ifdef _ANDROID_ +#include <cutils/properties.h> +#endif + + +/* ======================================================================= + + DEFINITIONS AND DECLARATIONS FOR MODULE + +This section contains definitions for constants, macros, types, variables +and other items needed by this module. + +========================================================================== */ + +HEVC_Utils::HEVC_Utils() +{ + initialize_frame_checking_environment(); +} + +HEVC_Utils::~HEVC_Utils() +{ +} + +/***********************************************************************/ +/* +FUNCTION: +HEVC_Utils::initialize_frame_checking_environment + +DESCRIPTION: +Extract RBSP data from a NAL + +INPUT/OUTPUT PARAMETERS: +None + +RETURN VALUE: +boolean + +SIDE EFFECTS: +None. + */ +/***********************************************************************/ +void HEVC_Utils::initialize_frame_checking_environment() +{ + m_forceToStichNextNAL = false; + m_au_data = false; + nalu_type = NAL_UNIT_INVALID; +} + +/*=========================================================================== +FUNCTION: +HEVC_Utils::iSNewFrame + +DESCRIPTION: +Returns true if NAL parsing successfull otherwise false. + +INPUT/OUTPUT PARAMETERS: +<In> +buffer : buffer containing start code or nal length + NAL units +buffer_length : the length of the NAL buffer +start_code : If true, start code is detected, +otherwise size nal length is detected +size_of_nal_length_field: size of nal length field +<out> +isNewFrame: true if the NAL belongs to a differenet frame +false if the NAL belongs to a current frame + +RETURN VALUE: +boolean true, if nal parsing is successful +false, if the nal parsing has errors + +SIDE EFFECTS: +None. +===========================================================================*/ +bool HEVC_Utils::isNewFrame(OMX_BUFFERHEADERTYPE *p_buf_hdr, + OMX_IN OMX_U32 size_of_nal_length_field, + OMX_OUT OMX_BOOL &isNewFrame) +{ + OMX_IN OMX_U8 *buffer = p_buf_hdr->pBuffer; + OMX_IN OMX_U32 buffer_length = p_buf_hdr->nFilledLen; + byte bFirstSliceInPic = 0; + + byte coef1=1, coef2=0, coef3=0; + uint32 pos = 0; + uint32 nal_len = buffer_length; + uint32 sizeofNalLengthField = 0; + uint32 zero_count; + boolean start_code = (size_of_nal_length_field==0)?true:false; + + if (start_code) { + // Search start_code_prefix_one_3bytes (0x000001) + coef2 = buffer[pos++]; + coef3 = buffer[pos++]; + + do { + if (pos >= buffer_length) { + DEBUG_PRINT_ERROR("ERROR: In %s() - line %d", __func__, __LINE__); + return false; + } + + coef1 = coef2; + coef2 = coef3; + coef3 = buffer[pos++]; + } while (coef1 || coef2 || coef3 != 1); + } else if (size_of_nal_length_field) { + /* This is the case to play multiple NAL units inside each access unit*/ + /* Extract the NAL length depending on sizeOfNALength field */ + sizeofNalLengthField = size_of_nal_length_field; + nal_len = 0; + + while (size_of_nal_length_field--) { + nal_len |= buffer[pos++]<<(size_of_nal_length_field<<3); + } + + if (nal_len >= buffer_length) { + DEBUG_PRINT_ERROR("ERROR: In %s() - line %d", __func__, __LINE__); + return false; + } + } + + if (nal_len > buffer_length) { + DEBUG_PRINT_ERROR("ERROR: In %s() - line %d", __func__, __LINE__); + return false; + } + + if (pos + 2 > (nal_len + sizeofNalLengthField)) { + DEBUG_PRINT_ERROR("ERROR: In %s() - line %d", __func__, __LINE__); + return false; + } + + nalu_type = (buffer[pos] & 0x7E)>>1 ; //=== nal_unit_type + + DEBUG_PRINT_LOW("@#@# Pos = %x NalType = %x buflen = %u", pos-1, nalu_type, (unsigned int) buffer_length); + + isNewFrame = OMX_FALSE; + + if (nalu_type == NAL_UNIT_VPS || + nalu_type == NAL_UNIT_SPS || + nalu_type == NAL_UNIT_PPS || + nalu_type == NAL_UNIT_SEI) { + DEBUG_PRINT_LOW("Non-AU boundary with NAL type %d", nalu_type); + + if (m_au_data) { + isNewFrame = OMX_TRUE; + m_au_data = false; + } + + m_forceToStichNextNAL = true; + } else if (nalu_type <= NAL_UNIT_RESERVED_23) { + DEBUG_PRINT_LOW("AU Boundary with NAL type %d ", nalu_type); + + if (!m_forceToStichNextNAL) { + bFirstSliceInPic = ((buffer[pos+2] & 0x80)>>7); + + if (bFirstSliceInPic) { //=== first_ctb_in_slice is only 1'b1 coded tree block + DEBUG_PRINT_LOW("Found a New Frame due to 1st coded tree block"); + isNewFrame = OMX_TRUE; + } + } + + m_au_data = true; + m_forceToStichNextNAL = false; + } + + DEBUG_PRINT_LOW("get_HEVC_nal_type - newFrame value %d",isNewFrame); + return true; +} + diff --git a/msm8998/mm-video-v4l2/vidc/vdec/src/message_queue.c b/msm8998/mm-video-v4l2/vidc/vdec/src/message_queue.c new file mode 100644 index 0000000..ced773a --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/src/message_queue.c @@ -0,0 +1,163 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#include "message_queue.h" + +int check_if_queue_empty ( unsigned int queuetocheck, void* queuecontext ) +{ + struct video_queue_context *ptr_q = NULL; + + /* + * queuetocheck - 0 command queue + * queuetocheck - 1 data queue + */ + if ( queuecontext == NULL || (queuetocheck > 1 ) ) { + return 1; + } + + ptr_q = (struct video_queue_context *)queuecontext; + + if (queuetocheck == 0) { + if (ptr_q->read_comq == ptr_q->write_comq) { + return 1; + } + } else if (queuetocheck == 1) { + if (ptr_q->write_dataq == ptr_q->read_dataq) { + return 1; + } + } + + return 0; +} + + + +struct video_msgq * queue_get_cmd (void* queuecontext ) { + struct video_queue_context *ptr_q = NULL; + struct video_msgq *pitem = NULL; + + if ( NULL == queuecontext ) { + printf("queue_get_cmd: Invalid Input parameter"); + return NULL; + } + + ptr_q = (struct video_queue_context *)queuecontext; + + /* Wait on the semaphore till it is released */ + sem_wait(&ptr_q->sem_message); + + /* Lock the mutex to protect the critical section */ + pthread_mutex_lock(&ptr_q->mutex); + + if (ptr_q->read_comq != ptr_q->write_comq) { + pitem = &ptr_q->ptr_cmdq [ptr_q->read_comq]; + ptr_q->read_comq = (ptr_q->read_comq + 1) % \ + ptr_q->commandq_size; + } else if (ptr_q->write_dataq != ptr_q->read_dataq) { + pitem = &ptr_q->ptr_dataq [ptr_q->read_dataq]; + ptr_q->read_dataq = (ptr_q->read_dataq + 1) % \ + ptr_q->dataq_size; + } + + /* Unlock the mutex to release the critical section */ + pthread_mutex_unlock(&ptr_q->mutex); + + return pitem; +} + + +int queue_post_cmdq ( void* queuecontext, + struct video_msgq *pitem + ) +{ + struct video_queue_context *ptr_q = NULL; + + if (pitem == NULL || queuecontext == NULL) { + return -1; + } + + ptr_q = (struct video_queue_context *)queuecontext; + + /* Lock the mutex to protect the critical section */ + pthread_mutex_lock(&ptr_q->mutex); + + if ((ptr_q->write_comq + 1) % ptr_q->commandq_size == ptr_q->read_comq) { + printf("QUEUE is FULL"); + /* Unlock the mutex to release the critical section */ + pthread_mutex_unlock(&ptr_q->mutex); + return 0; + } else { + /* Store the command in the Message Queue & increment write offset */ + memcpy ( &ptr_q->ptr_cmdq [ptr_q->write_comq],pitem, \ + sizeof (struct video_msgq)); + ptr_q->write_comq = (ptr_q->write_comq + 1) % ptr_q->commandq_size; + } + + /* Unlock the mutex to release the critical section */ + pthread_mutex_unlock(&ptr_q->mutex); + + /* Post the semaphore */ + sem_post(&ptr_q->sem_message); + return 1; +} + + +int queue_post_dataq ( void *queuecontext, + struct video_msgq *pitem + ) +{ + struct video_queue_context *ptr_q = NULL; + + if (pitem == NULL || queuecontext == NULL) { + return -1; + } + + ptr_q = (struct video_queue_context *)queuecontext; + + /* Lock the mutex to protect the critical section */ + pthread_mutex_lock(&ptr_q->mutex); + + if ((ptr_q->write_dataq + 1) % ptr_q->dataq_size == ptr_q->read_dataq) { + printf("QUEUE is FULL"); + /* Unlock the mutex to release the critical section */ + pthread_mutex_unlock(&ptr_q->mutex); + return 0; + } else { + /* Store the command in the Message Queue & increment write offset */ + memcpy ( &ptr_q->ptr_dataq [ptr_q->write_dataq],pitem, \ + sizeof (struct video_msgq)); + ptr_q->write_dataq = (ptr_q->write_dataq + 1) % ptr_q->dataq_size; + } + + /* Unlock the mutex to release the critical section */ + pthread_mutex_unlock(&ptr_q->mutex); + + /* Post the semaphore */ + sem_post(&ptr_q->sem_message); + return 1; + +} diff --git a/msm8998/mm-video-v4l2/vidc/vdec/src/mp4_utils.cpp b/msm8998/mm-video-v4l2/vidc/vdec/src/mp4_utils.cpp new file mode 100644 index 0000000..916f4e4 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/src/mp4_utils.cpp @@ -0,0 +1,340 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010 - 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#include "mp4_utils.h" +//#include "omx_vdec.h" +#include "vidc_debug.h" +# include <stdio.h> +#ifdef _ANDROID_ +extern "C" { +#include<utils/Log.h> +} +#endif//_ANDROID_ + +MP4_Utils::MP4_Utils() +{ + m_SrcWidth = 0; + m_SrcHeight = 0; + vop_time_resolution = 0; + vop_time_found = false; + +} +MP4_Utils::~MP4_Utils() +{ +} + +uint32 MP4_Utils::read_bit_field(posInfoType * posPtr, uint32 size) +{ + uint8 *bits = &posPtr->bytePtr[0]; + uint32 bitBuf = + (bits[0] << 24) | (bits[1] << 16) | (bits[2] << 8) | bits[3]; + + uint32 value = (bitBuf >> (32 - posPtr->bitPos - size)) & MASK(size); + + /* Update the offset in preparation for next field */ + posPtr->bitPos += size; + + while (posPtr->bitPos >= 8) { + posPtr->bitPos -= 8; + posPtr->bytePtr++; + } + + return value; +} + static uint8 *find_code +(uint8 * bytePtr, uint32 size, uint32 codeMask, uint32 referenceCode) +{ + uint32 code = 0xFFFFFFFF; + + for (uint32 i = 0; i < size; i++) { + code <<= 8; + code |= *bytePtr++; + + if ((code & codeMask) == referenceCode) { + return bytePtr; + } + } + + DEBUG_PRINT_LOW("Unable to find code 0x%x", referenceCode); + return NULL; +} +bool MP4_Utils::parseHeader(mp4StreamType * psBits) +{ + uint32 profile_and_level_indication = 0; + uint8 VerID = 1; /* default value */ + long hxw = 0; + + m_posInfo.bitPos = 0; + m_posInfo.bytePtr = psBits->data; + m_dataBeginPtr = psBits->data; + + m_posInfo.bytePtr = find_code(m_posInfo.bytePtr,4, + MASK(32),VOP_START_CODE); + + if (m_posInfo.bytePtr) { + return false; + } + + m_posInfo.bitPos = 0; + m_posInfo.bytePtr = psBits->data; + m_dataBeginPtr = psBits->data; + m_posInfo.bytePtr = find_code(m_posInfo.bytePtr,4, + MASK(32),GOV_START_CODE); + + if (m_posInfo.bytePtr) { + return false; + } + + m_posInfo.bitPos = 0; + m_posInfo.bytePtr = psBits->data; + m_dataBeginPtr = psBits->data; + /* parsing Visual Object Seqence(VOS) header */ + m_posInfo.bytePtr = find_code(m_posInfo.bytePtr, + psBits->numBytes, + MASK(32), + VISUAL_OBJECT_SEQUENCE_START_CODE); + + if ( m_posInfo.bytePtr == NULL ) { + m_posInfo.bitPos = 0; + m_posInfo.bytePtr = psBits->data; + } else { + uint32 profile_and_level_indication = read_bit_field (&m_posInfo, 8); + } + + /* parsing Visual Object(VO) header*/ + /* note: for now, we skip over the user_data */ + m_posInfo.bytePtr = find_code(m_posInfo.bytePtr,psBits->numBytes, + MASK(32),VISUAL_OBJECT_START_CODE); + + if (m_posInfo.bytePtr == NULL) { + m_posInfo.bitPos = 0; + m_posInfo.bytePtr = psBits->data; + } else { + uint32 is_visual_object_identifier = read_bit_field (&m_posInfo, 1); + + if ( is_visual_object_identifier ) { + /* visual_object_verid*/ + read_bit_field (&m_posInfo, 4); + /* visual_object_priority*/ + read_bit_field (&m_posInfo, 3); + } + + /* visual_object_type*/ + uint32 visual_object_type = read_bit_field (&m_posInfo, 4); + + if ( visual_object_type != VISUAL_OBJECT_TYPE_VIDEO_ID ) { + return false; + } + + /* skipping video_signal_type params*/ + /*parsing Video Object header*/ + m_posInfo.bytePtr = find_code(m_posInfo.bytePtr,psBits->numBytes, + VIDEO_OBJECT_START_CODE_MASK,VIDEO_OBJECT_START_CODE); + + if ( m_posInfo.bytePtr == NULL ) { + return false; + } + } + + /* parsing Video Object Layer(VOL) header */ + m_posInfo.bitPos = 0; + m_posInfo.bytePtr = find_code(m_posInfo.bytePtr, + psBits->numBytes, + VIDEO_OBJECT_LAYER_START_CODE_MASK, + VIDEO_OBJECT_LAYER_START_CODE); + + if ( m_posInfo.bytePtr == NULL ) { + m_posInfo.bitPos = 0; + m_posInfo.bytePtr = psBits->data; + } + + // 1 -> random accessible VOL + read_bit_field(&m_posInfo, 1); + + uint32 video_object_type_indication = read_bit_field (&m_posInfo, 8); + + if ( (video_object_type_indication != SIMPLE_OBJECT_TYPE) && + (video_object_type_indication != SIMPLE_SCALABLE_OBJECT_TYPE) && + (video_object_type_indication != CORE_OBJECT_TYPE) && + (video_object_type_indication != ADVANCED_SIMPLE) && + (video_object_type_indication != RESERVED_OBJECT_TYPE) && + (video_object_type_indication != MAIN_OBJECT_TYPE)) { + return false; + } + + /* is_object_layer_identifier*/ + uint32 is_object_layer_identifier = read_bit_field (&m_posInfo, 1); + + if (is_object_layer_identifier) { + uint32 video_object_layer_verid = read_bit_field (&m_posInfo, 4); + uint32 video_object_layer_priority = read_bit_field (&m_posInfo, 3); + VerID = (unsigned char)video_object_layer_verid; + } + + /* aspect_ratio_info*/ + uint32 aspect_ratio_info = read_bit_field (&m_posInfo, 4); + + if ( aspect_ratio_info == EXTENDED_PAR ) { + /* par_width*/ + read_bit_field (&m_posInfo, 8); + /* par_height*/ + read_bit_field (&m_posInfo, 8); + } + + /* vol_control_parameters */ + uint32 vol_control_parameters = read_bit_field (&m_posInfo, 1); + + if ( vol_control_parameters ) { + /* chroma_format*/ + uint32 chroma_format = read_bit_field (&m_posInfo, 2); + + if ( chroma_format != 1 ) { + return false; + } + + /* low_delay*/ + uint32 low_delay = read_bit_field (&m_posInfo, 1); + /* vbv_parameters (annex D)*/ + uint32 vbv_parameters = read_bit_field (&m_posInfo, 1); + + if ( vbv_parameters ) { + /* first_half_bitrate*/ + uint32 first_half_bitrate = read_bit_field (&m_posInfo, 15); + uint32 marker_bit = read_bit_field (&m_posInfo, 1); + + if ( marker_bit != 1) { + return false; + } + + /* latter_half_bitrate*/ + uint32 latter_half_bitrate = read_bit_field (&m_posInfo, 15); + marker_bit = read_bit_field (&m_posInfo, 1); + + if ( marker_bit != 1) { + return false; + } + + uint32 VBVPeakBitRate = (first_half_bitrate << 15) + latter_half_bitrate; + /* first_half_vbv_buffer_size*/ + uint32 first_half_vbv_buffer_size = read_bit_field (&m_posInfo, 15); + marker_bit = read_bit_field (&m_posInfo, 1); + + if ( marker_bit != 1) { + return false; + } + + /* latter_half_vbv_buffer_size*/ + uint32 latter_half_vbv_buffer_size = read_bit_field (&m_posInfo, 3); + uint32 VBVBufferSize = (first_half_vbv_buffer_size << 3) + latter_half_vbv_buffer_size; + /* first_half_vbv_occupancy*/ + uint32 first_half_vbv_occupancy = read_bit_field (&m_posInfo, 11); + marker_bit = read_bit_field (&m_posInfo, 1); + + if ( marker_bit != 1) { + return false; + } + + /* latter_half_vbv_occupancy*/ + uint32 latter_half_vbv_occupancy = read_bit_field (&m_posInfo, 15); + marker_bit = read_bit_field (&m_posInfo, 1); + + if ( marker_bit != 1) { + return false; + } + }/* vbv_parameters*/ + }/*vol_control_parameters*/ + + /* video_object_layer_shape*/ + uint32 video_object_layer_shape = read_bit_field (&m_posInfo, 2); + uint8 VOLShape = (unsigned char)video_object_layer_shape; + + if ( VOLShape != MPEG4_SHAPE_RECTANGULAR ) { + return false; + } + + /* marker_bit*/ + uint32 marker_bit = read_bit_field (&m_posInfo, 1); + + if ( marker_bit != 1 ) { + return false; + } + + /* vop_time_increment_resolution*/ + uint32 vop_time_increment_resolution = read_bit_field (&m_posInfo, 16); + vop_time_resolution = vop_time_increment_resolution; + vop_time_found = true; + return true; +} + +bool MP4_Utils::is_notcodec_vop(unsigned char *pbuffer, unsigned int len) +{ + unsigned int index = 4,vop_bits=0; + unsigned int temp = vop_time_resolution - 1; + unsigned char vop_type=0,modulo_bit=0,not_coded=0; + + if (!vop_time_found || !pbuffer || len < 5) { + return false; + } + + if ((pbuffer[0] == 0) && (pbuffer[1] == 0) && (pbuffer[2] == 1) && (pbuffer[3] == 0xB6)) { + while (temp) { + vop_bits++; + temp >>= 1; + } + + vop_type = (pbuffer[index] & 0xc0) >> 6; + unsigned bits_parsed = 2; + + do { + modulo_bit = pbuffer[index] & (1 << (7-bits_parsed)); + bits_parsed++; + index += bits_parsed/8; + bits_parsed = bits_parsed %8; + + if (index >= len) { + return false; + } + } while (modulo_bit); + + bits_parsed++; //skip marker bit + bits_parsed += vop_bits + 1;//Vop bit & Marker bits + index += bits_parsed/8; + + if (index >= len) { + return false; + } + + bits_parsed = bits_parsed % 8; + not_coded = pbuffer[index] & (1 << (7 - bits_parsed)); + + if (!not_coded) { + return true; + } + } + + return false; +} diff --git a/msm8998/mm-video-v4l2/vidc/vdec/src/omx_swvdec.cpp b/msm8998/mm-video-v4l2/vidc/vdec/src/omx_swvdec.cpp new file mode 100644 index 0000000..eda46e4 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/src/omx_swvdec.cpp @@ -0,0 +1,6419 @@ +/** + * @copyright + * + * Copyright (c) 2015-2016, 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 <cutils/properties.h> + +#include <media/hardware/HardwareAPI.h> +#include <gralloc_priv.h> + +#include "OMX_QCOMExtns.h" + +#include "omx_swvdec.h" + +#include "swvdec_api.h" + +static unsigned int split_buffer_mpeg4(unsigned int *offset_array, + OMX_BUFFERHEADERTYPE *p_buffer_hdr); + +/** + * ---------------- + * 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_disabled(false), + m_meta_buffer_mode(false), + m_adaptive_playback_mode(false), + m_arbitrary_bytes_mode(false), + m_port_reconfig_inprogress(false), + m_dimensions_update_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_dimensions, 0, sizeof(m_frame_dimensions)); + memset(&m_frame_attributes, 0, sizeof(m_frame_attributes)); + memset(&m_frame_dimensions_max, 0, sizeof(m_frame_dimensions_max)); + 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(); + + { + char property_value[PROPERTY_VALUE_MAX] = {0}; + + if (property_get("omx_swvdec.meta_buffer.disable", + property_value, + NULL)) + { + m_meta_buffer_mode_disabled = (bool) atoi(property_value); + + OMX_SWVDEC_LOG_LOW("omx_swvdec.meta_buffer.disable: %d", + m_meta_buffer_mode_disabled ? 1 : 0); + } + } + + 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; + } + + 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; + } + + { + SWVDEC_CALLBACK callback; + + SWVDEC_STATUS retval_swvdec; + + 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; + + if ((retval = set_frame_dimensions(DEFAULT_FRAME_WIDTH, + DEFAULT_FRAME_HEIGHT)) != + OMX_ErrorNone) + { + goto component_init_exit; + } + + m_omx_color_formattype = + ((OMX_COLOR_FORMATTYPE) + OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m); + + if ((retval = set_frame_attributes(m_omx_color_formattype)) != + OMX_ErrorNone) + { + goto component_init_exit; + } + } + + if ((retval = get_buffer_requirements_swvdec(OMX_CORE_PORT_INDEX_IP)) != + OMX_ErrorNone) + { + goto component_init_exit; + } + + if ((retval = get_buffer_requirements_swvdec(OMX_CORE_PORT_INDEX_OP)) != + OMX_ErrorNone) + { + goto component_init_exit; + } + + if ((retval = async_thread_create()) != OMX_ErrorNone) + { + goto component_init_exit; + } + + 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; + } + + 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; + } + + 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) + { + async_post_event(OMX_SWVDEC_EVENT_ERROR, retval, 0); + } + else + { + async_post_event(OMX_SWVDEC_EVENT_CMD, cmd, param); + + 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 index %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 index %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 index %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 index %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", + (OMX_QCOM_EXTN_INDEXTYPE) param_index); + + 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 index %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 index %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 index %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"); + + 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_API( + "OMX_QcomIndexParamVideoDecoderPictureOrder, " + "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", + p_picture_order->eOutputPictureOrder); + + 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 ? + "enable" : + "disable")); + + if (p_meta_data->nPortIndex == OMX_CORE_PORT_INDEX_OP) + { + if (p_meta_data->bStoreMetaData && m_meta_buffer_mode_disabled) + { + OMX_SWVDEC_LOG_ERROR("meta buffer mode disabled " + "via ADB setprop: " + "'omx_swvdec.meta_buffer.disable'"); + + retval = OMX_ErrorBadParameter; + } + else + { + 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; + } + + case OMX_QcomIndexParamVideoAdaptivePlaybackMode: + { + PrepareForAdaptivePlaybackParams *p_adaptive_playback_params = + (PrepareForAdaptivePlaybackParams *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_QcomIndexParamVideoAdaptivePlaybackMode, " + "port index %d, %s, max dimensions: %d x %d", + p_adaptive_playback_params->nPortIndex, + (p_adaptive_playback_params->bEnable ? + "enable" : + "disable"), + p_adaptive_playback_params->nMaxFrameWidth, + p_adaptive_playback_params->nMaxFrameHeight); + + if (p_adaptive_playback_params->nPortIndex == + OMX_CORE_PORT_INDEX_OP) + { + if (p_adaptive_playback_params->bEnable) + { + m_adaptive_playback_mode = true; + + retval = + set_adaptive_playback( + p_adaptive_playback_params->nMaxFrameWidth, + p_adaptive_playback_params->nMaxFrameHeight); + } + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_adaptive_playback_params->nPortIndex); + + retval = OMX_ErrorBadPortIndex; + } + + break; + } + + default: + { + OMX_SWVDEC_LOG_ERROR("param index '0x%08x' invalid", + (OMX_QCOM_EXTN_INDEXTYPE) param_index); + + 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; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + + retval = OMX_ErrorInvalidComponent; + } + else if (p_config_data == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_config_data = NULL"); + + retval = OMX_ErrorBadParameter; + } + + if (retval != OMX_ErrorNone) + { + 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) + { + if (m_dimensions_update_inprogress) + { + retval = get_frame_dimensions_swvdec(); + + m_dimensions_update_inprogress = false; + } + + if (retval == OMX_ErrorNone) + { + 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 '0x%08x' 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) p_config_data; + + OMX_SWVDEC_LOG_API("config index 0x%08x", config_index); + + 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 if (!strncmp(param_name, + "OMX.google.android.index.prepareForAdaptivePlayback", + OMX_MAX_STRINGNAME_SIZE)) + { + *p_index_type = + (OMX_INDEXTYPE) OMX_QcomIndexParamVideoAdaptivePlaybackMode; + } + 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)) + { + 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) + { + 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)) + { + 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) + { + 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; + + 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; + } + + 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); + + pthread_mutex_unlock(&m_meta_buffer_array_mutex); + + 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); + } + + meta_buffer_ref_add(ii, p_buffer_payload->pmem_fd); + + pthread_mutex_unlock(&m_meta_buffer_array_mutex); + } + + 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 & color format. + * + * @param[in] color_format: Color format. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::set_frame_attributes( + OMX_COLOR_FORMATTYPE color_format) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + 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; + + switch (color_format) + { + + case OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m: + { + /** + * alignment factors: + * + * - stride: 128 + * - scanlines_y: 32 + * - scanlines_uv: 16 + * - size: 4096 + */ + + m_frame_attributes.stride = ALIGN(width, 128); + m_frame_attributes.scanlines = ALIGN(height, 32); + + scanlines_uv = ALIGN(height / 2, 16); + + 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, 4096); + + OMX_SWVDEC_LOG_HIGH("'OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m': " + "stride %d, scanlines %d, size %d", + m_frame_attributes.stride, + m_frame_attributes.scanlines, + m_frame_attributes.size); + + break; + } + + case OMX_COLOR_FormatYUV420SemiPlanar: + { + /** + * alignment factors: + * + * - stride: 16 + * - scanlines_y: 16 + * - scanlines_uv: 16 + * - size: 4096 + */ + + m_frame_attributes.stride = ALIGN(width, 16); + m_frame_attributes.scanlines = ALIGN(height, 16); + + scanlines_uv = ALIGN(height / 2, 16); + + 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, 4096); + + OMX_SWVDEC_LOG_HIGH("'OMX_COLOR_FormatYUV420SemiPlanar': " + "stride %d, scanlines %d, size %d", + m_frame_attributes.stride, + m_frame_attributes.scanlines, + m_frame_attributes.size); + + break; + } + + default: + { + OMX_SWVDEC_LOG_ERROR("'0x%08x' color format invalid or unsupported", + color_format); + + retval = OMX_ErrorBadParameter; + break; + } + + } // switch (color_format) + + if (retval == OMX_ErrorNone) + { + m_omx_color_formattype = color_format; + + retval = set_frame_attributes_swvdec(); + } + + return retval; +} + +/** + * @brief Set maximum adaptive playback frame dimensions for OMX component & + * SwVdec core. + * + * @param[in] width: Max adaptive playback frame width. + * @param[in] height: Max adaptive playback frame height. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::set_adaptive_playback(unsigned int max_width, + unsigned int max_height) +{ + OMX_ERRORTYPE retval; + + m_frame_dimensions_max.width = max_width; + m_frame_dimensions_max.height = max_height; + + OMX_SWVDEC_LOG_HIGH("%d x %d", + m_frame_dimensions_max.width, + m_frame_dimensions_max.height); + + retval = set_adaptive_playback_swvdec(); + + if (retval == OMX_ErrorNone) + { + retval = set_frame_dimensions(max_width, max_height); + } + + if (retval == OMX_ErrorNone) + { + retval = set_frame_attributes(m_omx_color_formattype); + } + +set_adaptive_playback_exit: + 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); + } + 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) + { + OMX_SWVDEC_LOG_HIGH("OMX_IndexParamVideoPortFormat, port index 0; " + "doing nothing"); + } + else if (p_port_format->nPortIndex == OMX_CORE_PORT_INDEX_OP) + { + retval = set_frame_attributes(p_port_format->eColorFormat); + } + 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) + { + 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 (m_port_reconfig_inprogress) + { + if ((retval = set_frame_attributes(m_omx_color_formattype)) != + 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; + + if (m_omx_color_formattype == + OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m) + { + OMX_SWVDEC_LOG_HIGH( + "port index %d: color format '0x%08x': " + "OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m", + p_port_def->nPortIndex, + p_port_def->format.video.eColorFormat); + } + else if (m_omx_color_formattype == OMX_COLOR_FormatYUV420SemiPlanar) + { + OMX_SWVDEC_LOG_HIGH("port index %d: color format '0x%08x': " + "OMX_COLOR_FormatYUV420SemiPlanar", + p_port_def->nPortIndex, + p_port_def->format.video.eColorFormat); + } + else + { + assert(0); + retval = OMX_ErrorUndefined; + } + } + 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 component's output port nBufferSize is not updated based on what + * IL client sends; instead it is updated based on the possibly updated + * frame attributes. + * + * This is because set_parameter() for output port definition only has + * updates to buffer counts or frame dimensions. + */ + + m_port_op.def.nBufferCountActual = p_port_def->nBufferCountActual; + m_port_op.def.nBufferCountMin = p_port_def->nBufferCountMin; + + 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); + + /** + * Update frame dimensions & attributes if: + * + * 1. not in adaptive playback mode + * OR + * 2. new frame dimensions greater than adaptive playback mode's + * max frame dimensions + */ + + if ((m_adaptive_playback_mode == false) || + (p_port_def->format.video.nFrameWidth > + m_frame_dimensions_max.width) || + (p_port_def->format.video.nFrameHeight > + m_frame_dimensions_max.height)) + { + OMX_SWVDEC_LOG_HIGH("updating frame dimensions & attributes"); + + if ((retval = + set_frame_dimensions(p_port_def->format.video.nFrameWidth, + p_port_def->format.video.nFrameHeight)) != + OMX_ErrorNone) + { + goto set_port_definition_exit; + } + + if ((retval = set_frame_attributes(m_omx_color_formattype)) != + OMX_ErrorNone) + { + goto set_port_definition_exit; + } + + // nBufferSize updated based on (possibly new) frame attributes + + m_port_op.def.nBufferSize = m_frame_attributes.size; + } + else + { + OMX_SWVDEC_LOG_HIGH("not updating frame dimensions & attributes"); + } + } + 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 OMX_QCOM_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; + + /** + * alignment factors: + * + * - stride: 128 + * - scanlines: 32 + */ + stride = ALIGN(p_img->mWidth, 128); + scanlines = ALIGN(p_img->mHeight, 32); + + 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::U].mOffset = stride * scanlines; + p_img->mPlane[MediaImage::U].mColInc = 2; + p_img->mPlane[MediaImage::U].mRowInc = stride; + p_img->mPlane[MediaImage::U].mHorizSubsampling = 2; + p_img->mPlane[MediaImage::U].mVertSubsampling = 2; + + // plane 2 (V) + p_img->mPlane[MediaImage::V].mOffset = stride * scanlines + 1; + p_img->mPlane[MediaImage::V].mColInc = 2; + p_img->mPlane[MediaImage::V].mRowInc = stride; + p_img->mPlane[MediaImage::V].mHorizSubsampling = 2; + p_img->mPlane[MediaImage::V].mVertSubsampling = 2; + + break; + } + + case OMX_COLOR_FormatYUV420SemiPlanar: + { + // do nothing; standard OMX color formats should not be described + retval = OMX_ErrorUnsupportedSetting; + 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_HIGH("OMX_QCOM_FramePacking_Arbitrary"); + + m_arbitrary_bytes_mode = true; + + 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", + p_port_def->nFramePackingFormat); + + 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->stride = m_frame_attributes.stride; + p_frame_attributes->scanlines = 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 Set maximum adaptive playback frame dimensions for SwVdec core. + */ +OMX_ERRORTYPE omx_swvdec::set_adaptive_playback_swvdec() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + SWVDEC_PROPERTY property; + + SWVDEC_STATUS retval_swvdec; + + property.id = SWVDEC_PROPERTY_ID_ADAPTIVE_PLAYBACK; + + property.info.frame_dimensions.width = m_frame_dimensions_max.width; + property.info.frame_dimensions.height = m_frame_dimensions_max.height; + + 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.stride; + m_frame_attributes.scanlines = property.info.frame_attributes.scanlines; + 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_MIN); + 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) + { + 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 = MAX(p_buffer_req->mincount, + m_port_op.def.nBufferCountActual); + 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) + { + 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) + { + 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_info_array_exit; + } + + 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, %zu 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_info_array_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->nInputPortIndex = OMX_CORE_PORT_INDEX_IP; + p_buffer_hdr->pInputPortPrivate = + (void *) &(m_buffer_array_ip[ii].buffer_payload); + } + +buffer_allocate_ip_info_array_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_info_array_exit; + } + + 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, %zu 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_info_array_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_info_array_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) + { + 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)) + { + 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); + + for (ii = 0; ii < m_port_ip.def.nBufferCountActual; ii++) + { + if (m_buffer_array_ip[ii].buffer_populated) + { + break; + } + } + + 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) + { + if (m_meta_buffer_mode) + { + // do nothing; munmap() & FD reset 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 + { + 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); + } + + m_buffer_array_op[ii].buffer_populated = false; + + m_port_op.populated = OMX_FALSE; + + for (ii = 0; ii < m_port_op.def.nBufferCountActual; ii++) + { + if (m_buffer_array_op[ii].buffer_populated) + { + break; + } + } + + 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, %zu 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; + } + else + { + unsigned int ii; + + for (ii = 0; ii < m_port_op.def.nBufferCountActual; ii++) + { + m_meta_buffer_array[ii].fd = -1; + } + } + + 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: Buffer index. + * @param[in] fd: File descriptor. + */ +void omx_swvdec::meta_buffer_ref_add(unsigned int index, int fd) +{ + if (m_meta_buffer_array[index].ref_count == 0) + { + m_meta_buffer_array[index].fd = fd; + } + + m_meta_buffer_array[index].ref_count++; +} + +/** + * @brief Remove meta buffer reference. + * + * @param[in] index: Buffer index. + */ +void omx_swvdec::meta_buffer_ref_remove(unsigned int index) +{ + pthread_mutex_lock(&m_meta_buffer_array_mutex); + + m_meta_buffer_array[index].ref_count--; + + if (m_meta_buffer_array[index].ref_count == 0) + { + m_meta_buffer_array[index].fd = -1; + + munmap(m_buffer_array_op[index].buffer_payload.bufferaddr, + m_buffer_array_op[index].buffer_payload.mmaped_size); + + m_buffer_array_op[index].buffer_payload.bufferaddr = NULL; + m_buffer_array_op[index].buffer_payload.offset = 0; + m_buffer_array_op[index].buffer_payload.mmaped_size = 0; + + m_buffer_array_op[index].buffer_swvdec.p_buffer = NULL; + m_buffer_array_op[index].buffer_swvdec.size = 0; + } + + pthread_mutex_unlock(&m_meta_buffer_array_mutex); +} + +/** + * @brief Split MPEG-4 bitstream buffer into multiple frames (if they exist). + * + * @param[in,out] offset_array: Array of offsets to frame headers. + * @param[in] p_buffer_hdr: Pointer to buffer header. + * + * @retval Number of frames in buffer. + */ +unsigned int split_buffer_mpeg4(unsigned int *offset_array, + OMX_BUFFERHEADERTYPE *p_buffer_hdr) +{ + unsigned char *p_buffer = p_buffer_hdr->pBuffer; + + unsigned int byte_count = 0; + + unsigned int num_frame_headers = 0; + + unsigned int next_4bytes; + + while ((byte_count < p_buffer_hdr->nFilledLen) && + (num_frame_headers < OMX_SWVDEC_MAX_FRAMES_PER_ETB)) + { + next_4bytes = *((unsigned int *) p_buffer); + + next_4bytes = __builtin_bswap32(next_4bytes); + + if (next_4bytes == 0x000001B6) + { + OMX_SWVDEC_LOG_HIGH("%p, buffer %p: " + "frame header at %d bytes offset", + p_buffer_hdr, + p_buffer_hdr->pBuffer, + byte_count); + + offset_array[num_frame_headers] = byte_count; + + num_frame_headers++; + + p_buffer += 4; + byte_count += 4; + } + else + { + p_buffer++; + byte_count++; + } + } + + return num_frame_headers; +} + +/** + * @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 index %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 %zu, align %zu", + 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; +} + +/** + * @brief Flush cached ION output buffer. + * + * @param[in] index: Index of buffer in output buffer info array. + */ +void omx_swvdec::ion_flush_op(unsigned int index) +{ + if (index < m_port_op.def.nBufferCountActual) + { + struct vdec_bufferpayload *p_buffer_payload = + &m_buffer_array_op[index].buffer_payload; + + if(p_buffer_payload) + { + if(p_buffer_payload->bufferaddr != NULL) + { + __builtin___clear_cache(reinterpret_cast<char*>((size_t*)p_buffer_payload->bufferaddr), + reinterpret_cast<char*>((size_t*)p_buffer_payload->bufferaddr +p_buffer_payload->buffer_len)); + } + } + } + else + { + OMX_SWVDEC_LOG_ERROR("buffer index '%d' invalid", index); + } + + 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; + + m_buffer_array_ip[index].buffer_header.nFilledLen = + p_buffer_ip->filled_length; + + 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(index); + } + + break; + } + + case SWVDEC_EVENT_RECONFIG_REQUIRED: + { + async_post_event(OMX_SWVDEC_EVENT_PORT_RECONFIG, 0, 0); + + break; + } + + case SWVDEC_EVENT_DIMENSIONS_UPDATED: + { + async_post_event(OMX_SWVDEC_EVENT_DIMENSIONS_UPDATED, 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. + */ +void omx_swvdec::async_post_event(unsigned long event_id, + unsigned long event_param1, + unsigned long event_param2) +{ + OMX_SWVDEC_EVENT_INFO event_info; + + 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: + { + m_queue_port_ip.push(&event_info); + break; + } + + case OMX_SWVDEC_EVENT_FTB: + case OMX_SWVDEC_EVENT_FBD: + { + m_queue_port_op.push(&event_info); + break; + } + + default: + { + m_queue_command.push(&event_info); + break; + } + + } + + sem_post(&m_async_thread.sem_event); +} + +/** + * @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; + } + + case OMX_SWVDEC_EVENT_DIMENSIONS_UPDATED: + { + retval = p_omx_swvdec->async_process_event_dimensions_updated(); + 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; + + 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) + + 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); + } + + 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: + { + OMX_SWVDEC_LOG_HIGH("%s -> %s", + OMX_STATETYPE_STRING(m_state), + OMX_STATETYPE_STRING((OMX_STATETYPE) param)); + + 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) + { + OMX_SWVDEC_LOG_HIGH("%s -> OMX_StateInvalid", + OMX_STATETYPE_STRING(m_state)); + + 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)) + { + 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)) + { + 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 index %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 index %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", + port_index); + + 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 index %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", + port_index); + + 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_queue_timestamp.push(p_buffer_hdr->nTimeStamp); + } + + assert(p_buffer_swvdec->p_buffer == p_buffer_hdr->pBuffer); + + if (m_arbitrary_bytes_mode && + p_buffer_hdr->nFilledLen && + ((p_buffer_hdr->nFlags & OMX_BUFFERFLAG_CODECCONFIG) == 0)) + { + unsigned int offset_array[OMX_SWVDEC_MAX_FRAMES_PER_ETB] = {0}; + + unsigned int num_frame_headers = 1; + + if ((m_omx_video_codingtype == + ((OMX_VIDEO_CODINGTYPE) QOMX_VIDEO_CodingDivx)) || + (m_omx_video_codingtype == OMX_VIDEO_CodingMPEG4)) + { + num_frame_headers = split_buffer_mpeg4(offset_array, + p_buffer_hdr); + } + else + { + assert(0); + } + + if(num_frame_headers > 1) + { + m_buffer_array_ip[index].split_count = num_frame_headers - 1; + + for (unsigned int ii = 0; ii < num_frame_headers; ii++) + { + p_buffer_swvdec->flags = p_buffer_hdr->nFlags; + p_buffer_swvdec->timestamp = p_buffer_hdr->nTimeStamp; + + if (ii == 0) + { + p_buffer_swvdec->offset = 0; + p_buffer_swvdec->filled_length = (offset_array[ii + 1] ? + offset_array[ii + 1] : + p_buffer_hdr->nFilledLen); + } + else + { + p_buffer_swvdec->offset = offset_array[ii]; + p_buffer_swvdec->filled_length = + p_buffer_hdr->nFilledLen - offset_array[ii]; + } + + m_diag.dump_ip(p_buffer_swvdec->p_buffer + + p_buffer_swvdec->offset, + 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); + break; + } + } + } + else + { + OMX_SWVDEC_LOG_HIGH("No frame detected for Buffer %p, with TS %lld", + p_buffer_hdr->pBuffer, p_buffer_hdr->nTimeStamp ); + + p_buffer_swvdec->flags = p_buffer_hdr->nFlags; + p_buffer_swvdec->offset = 0; + 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->offset, + 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); + } + } + } + else + { + p_buffer_swvdec->flags = p_buffer_hdr->nFlags; + p_buffer_swvdec->offset = 0; + 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->offset, + 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) + { + if (m_arbitrary_bytes_mode && m_buffer_array_ip[index].split_count) + { + m_buffer_array_ip[index].split_count--; + } + else + { + m_port_ip.num_pending_buffers--; + + 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; + + static long long timestamp_prev = 0; + + 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) + { + OMX_SWVDEC_LOG_LOW("sync frame decoding mode; " + "setting timestamp to zero"); + + p_buffer_hdr->nTimeStamp = 0; + } + else + { + if (m_queue_timestamp.empty()) + { + OMX_SWVDEC_LOG_ERROR("timestamp queue empty; " + "re-using previous timestamp %lld", + timestamp_prev); + + p_buffer_hdr->nTimeStamp = timestamp_prev; + } + else + { + p_buffer_hdr->nTimeStamp = m_queue_timestamp.top(); + + m_queue_timestamp.pop(); + + timestamp_prev = p_buffer_hdr->nTimeStamp; + } + } + + ion_flush_op(index); + + if (m_meta_buffer_mode) + { + pthread_mutex_lock(&m_meta_buffer_array_mutex); + } + + m_diag.dump_op(p_buffer, + m_frame_dimensions.width, + m_frame_dimensions.height, + m_frame_attributes.stride, + m_frame_attributes.scanlines); + + if (m_meta_buffer_mode) + { + pthread_mutex_unlock(&m_meta_buffer_array_mutex); + } + } + else + { + OMX_SWVDEC_LOG_LOW("filled length zero; " + "setting timestamp to zero"); + + p_buffer_hdr->nTimeStamp = 0; + } + + if (p_buffer_hdr->nFlags & OMX_BUFFERFLAG_EOS) + { + async_post_event(OMX_SWVDEC_EVENT_EOS, 0, 0); + + OMX_SWVDEC_LOG_LOW("flushing %zu elements in timestamp queue", + m_queue_timestamp.size()); + + while (m_queue_timestamp.empty() == false) + { + m_queue_timestamp.pop(); + } + } + + if (m_meta_buffer_mode && + ((p_buffer_hdr->nFlags & OMX_BUFFERFLAG_READONLY)) == 0) + { + meta_buffer_ref_remove(index); + } + + OMX_SWVDEC_LOG_CALLBACK( + "FillBufferDone(): %p, buffer %p, " + "flags 0x%08x, filled length %d, timestamp %lld", + p_buffer_hdr, + p_buffer, + p_buffer_hdr->nFlags, + p_buffer_hdr->nFilledLen, + 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 index %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) + { + OMX_SWVDEC_LOG_LOW("flushing %zu elements in timestamp queue", + m_queue_timestamp.size()); + + while (m_queue_timestamp.empty() == false) + { + m_queue_timestamp.pop(); + } + } + + 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 already in progress"); + + retval = OMX_ErrorIncorrectStateOperation; + } + else + { + m_port_reconfig_inprogress = true; + + OMX_SWVDEC_LOG_CALLBACK("EventHandler(): " + "OMX_EventPortSettingsChanged, port index %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; +} + +/** + * @brief Process dimensions updated event. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_dimensions_updated() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (m_dimensions_update_inprogress) + { + OMX_SWVDEC_LOG_ERROR("dimensions update already in progress"); + + retval = OMX_ErrorIncorrectStateOperation; + } + else + { + m_dimensions_update_inprogress = true; + + OMX_SWVDEC_LOG_CALLBACK("EventHandler(): " + "OMX_EventPortSettingsChanged, port index %d, " + "OMX_IndexConfigCommonOutputCrop", + OMX_CORE_PORT_INDEX_OP); + + m_callback.EventHandler(&m_cmp, + m_app_data, + OMX_EventPortSettingsChanged, + OMX_CORE_PORT_INDEX_OP, + OMX_IndexConfigCommonOutputCrop, + NULL); + } + + return retval; +} diff --git a/msm8998/mm-video-v4l2/vidc/vdec/src/omx_swvdec_utils.cpp b/msm8998/mm-video-v4l2/vidc/vdec/src/omx_swvdec_utils.cpp new file mode 100644 index 0000000..d86d395 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/src/omx_swvdec_utils.cpp @@ -0,0 +1,350 @@ +/** + * @copyright + * + * Copyright (c) 2015-2016, 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 <time.h> +#include <errno.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_HIGH( + "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() +{ + 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. + */ +void omx_swvdec_queue::push(OMX_SWVDEC_EVENT_INFO *p_event_info) +{ + pthread_mutex_lock(&m_mutex); + + m_queue.push(*p_event_info); + + pthread_mutex_unlock(&m_mutex); +} + +/** + * @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_queue.empty()) + { + retval = false; + } + else + { + *p_event_info = m_queue.front(); + + m_queue.pop(); + } + + 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) +{ + time_t time_raw; + + struct tm *time_info; + + char time_string[16]; + + char filename_ip[PROPERTY_VALUE_MAX]; + char filename_op[PROPERTY_VALUE_MAX]; + + char property_value[PROPERTY_VALUE_MAX] = {0}; + + time_raw = time(NULL); + + time_info = localtime(&time_raw); + + if (time_info != NULL) + { + // time string: "YYYYmmddTHHMMSS" + strftime(time_string, sizeof(time_string), "%Y%m%dT%H%M%S", time_info); + } + else + { + // time string: "19700101T000000" + snprintf(time_string, sizeof(time_string), "19700101T000000"); + } + + // default ip filename: "/data/misc/media/omx_swvdec_YYYYmmddTHHMMSS_ip.bin" + snprintf(filename_ip, + sizeof(filename_ip), + "%s/omx_swvdec_%s_ip.bin", + DIAG_FILE_PATH, + time_string); + + // default op filename: "/data/misc/media/omx_swvdec_YYYYmmddTHHMMSS_op.yuv" + snprintf(filename_op, + sizeof(filename_op), + "%s/omx_swvdec_%s_op.yuv", + DIAG_FILE_PATH, + time_string); + + if (property_get("omx_swvdec.dump.ip", property_value, NULL)) + { + m_dump_ip = atoi(property_value); + + OMX_SWVDEC_LOG_HIGH("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_HIGH("omx_swvdec.dump.op: %d", m_dump_op); + } + + if (m_dump_ip && property_get("omx_swvdec.filename.ip", + property_value, + filename_ip) && (strlen(property_value) > 0 ) ) + { + size_t m_filename_ip_size = (strlen(property_value) + 1)*sizeof(char); + m_filename_ip = + (char *) malloc(m_filename_ip_size); + if (m_filename_ip == NULL) + { + OMX_SWVDEC_LOG_ERROR("failed to allocate %zu bytes for " + "input filename string", + m_filename_ip_size); + } + else + { + strlcpy(m_filename_ip, property_value,m_filename_ip_size); + OMX_SWVDEC_LOG_HIGH("omx_swvdec.filename.ip: %s", m_filename_ip); + if ((m_file_ip = fopen(m_filename_ip, "wb")) == NULL) + { + OMX_SWVDEC_LOG_ERROR("cannot open input file '%s' logging erro is : %d", + m_filename_ip,errno); + } + } + } + + if (m_dump_op && property_get("omx_swvdec.filename.op", + property_value, + filename_op) && (strlen(property_value) > 0 )) + { + size_t m_filename_op_size = (strlen(property_value) + 1)*sizeof(char); + m_filename_op = + (char *) malloc(m_filename_op_size); + if (m_filename_op == NULL) + { + OMX_SWVDEC_LOG_ERROR("failed to allocate %zu bytes for " + "output filename string", + m_filename_op_size); + } + else + { + strlcpy(m_filename_op, property_value,m_filename_op_size); + OMX_SWVDEC_LOG_HIGH("omx_swvdec.filename.op: %s", m_filename_op); + if ((m_file_op = fopen(m_filename_op, "wb")) == NULL) + { + OMX_SWVDEC_LOG_ERROR("cannot open output file '%s' logging error : %d", + m_filename_op,errno); + } + } + } +} + +/** + * @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 && (m_file_ip != NULL)) + { + 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 && (m_file_op != NULL)) + { + 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; + } + } +} diff --git a/msm8998/mm-video-v4l2/vidc/vdec/src/omx_vdec_hevc.cpp b/msm8998/mm-video-v4l2/vidc/vdec/src/omx_vdec_hevc.cpp new file mode 100644 index 0000000..9fc4014 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/src/omx_vdec_hevc.cpp @@ -0,0 +1,8435 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2013-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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ + +/*============================================================================ + O p e n M A X w r a p p e r s + O p e n M A X C o r e + +*//** @file omx_vdec.cpp + This module contains the implementation of the OpenMAX core & component. + +*//*========================================================================*/ + +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +#include <string.h> +#include <pthread.h> +#include <sys/prctl.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "omx_vdec_hevc.h" +#include <fcntl.h> +#include <limits.h> +#include <media/msm_media_info.h> +#include <qdMetaData.h> + +#ifndef _ANDROID_ +#include <sys/ioctl.h> +#include <sys/mman.h> +#endif //_ANDROID_ + +#ifdef _ANDROID_ +#include <cutils/properties.h> +#undef USE_EGL_IMAGE_GPU +#endif + +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) +#include <gralloc_priv.h> +#endif + +#ifdef USE_EGL_IMAGE_GPU +#include <EGL/egl.h> +#include <EGL/eglQCOM.h> +#define EGL_BUFFER_HANDLE_QCOM 0x4F00 +#define EGL_BUFFER_OFFSET_QCOM 0x4F01 +#endif + +#ifdef INPUT_BUFFER_LOG +#define INPUT_BUFFER_FILE_NAME "/data/input-bitstream.\0\0\0\0" +#define INPUT_BUFFER_FILE_NAME_LEN 30 +FILE *inputBufferFile1; +char inputfilename [INPUT_BUFFER_FILE_NAME_LEN] = "\0"; +#endif +#ifdef OUTPUT_BUFFER_LOG +FILE *outputBufferFile1; +char outputfilename [] = "/data/output.yuv"; +#endif +#ifdef OUTPUT_EXTRADATA_LOG +FILE *outputExtradataFile; +char ouputextradatafilename [] = "/data/extradata"; +#endif + +#ifdef VENUS_HEVC +#define DEVICE_NAME "/dev/video/venus_dec" +#else +#define DEVICE_NAME "/dev/video/q6_dec" +#endif + +#define DEFAULT_FPS 30 +#define MAX_INPUT_ERROR DEFAULT_FPS +#define MAX_SUPPORTED_FPS 120 + +#define VC1_SP_MP_START_CODE 0xC5000000 +#define VC1_SP_MP_START_CODE_MASK 0xFF000000 +#define VC1_AP_SEQ_START_CODE 0x0F010000 +#define VC1_STRUCT_C_PROFILE_MASK 0xF0 +#define VC1_STRUCT_B_LEVEL_MASK 0xE0000000 +#define VC1_SIMPLE_PROFILE 0 +#define VC1_MAIN_PROFILE 1 +#define VC1_ADVANCE_PROFILE 3 +#define VC1_SIMPLE_PROFILE_LOW_LEVEL 0 +#define VC1_SIMPLE_PROFILE_MED_LEVEL 2 +#define VC1_STRUCT_C_LEN 4 +#define VC1_STRUCT_C_POS 8 +#define VC1_STRUCT_A_POS 12 +#define VC1_STRUCT_B_POS 24 +#define VC1_SEQ_LAYER_SIZE 36 +#define POLL_TIMEOUT 0x7fffffff + +#define MEM_DEVICE "/dev/ion" +#define MEM_HEAP_ID ION_CP_MM_HEAP_ID + +#ifdef _ANDROID_ +extern "C" { +#include<utils/Log.h> +} +#endif//_ANDROID_ + +#define SZ_4K 0x1000 +#define SZ_1M 0x100000 + +#define Log2(number, power) { OMX_U32 temp = number; power = 0; while( (0 == (temp & 0x1)) && power < 16) { temp >>=0x1; power++; } } +#define Q16ToFraction(q,num,den) { OMX_U32 power; Log2(q,power); num = q >> power; den = 0x1 << (16 - power); } +#define EXTRADATA_IDX(__num_planes) ((__num_planes) ? (__num_planes) - 1 : 0) + +#define DEFAULT_EXTRADATA (OMX_INTERLACE_EXTRADATA) + +void* async_message_thread (void *input) +{ + OMX_BUFFERHEADERTYPE *buffer; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + struct pollfd pfd; + struct v4l2_buffer v4l2_buf; + memset((void *)&v4l2_buf,0,sizeof(v4l2_buf)); + struct v4l2_event dqevent; + omx_vdec *omx = reinterpret_cast<omx_vdec*>(input); + pfd.events = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLRDBAND | POLLPRI; + pfd.fd = omx->drv_ctx.video_driver_fd; + int error_code = 0,rc=0,bytes_read = 0,bytes_written = 0; + DEBUG_PRINT_HIGH("omx_vdec: Async thread start"); + prctl(PR_SET_NAME, (unsigned long)"VideoDecCallBackThread", 0, 0, 0); + while (1) { + rc = poll(&pfd, 1, POLL_TIMEOUT); + if (!rc) { + DEBUG_PRINT_ERROR("Poll timedout"); + break; + } else if (rc < 0) { + DEBUG_PRINT_ERROR("Error while polling: %d", rc); + break; + } + if ((pfd.revents & POLLIN) || (pfd.revents & POLLRDNORM)) { + struct vdec_msginfo vdec_msg; + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.length = omx->drv_ctx.num_planes; + v4l2_buf.m.planes = plane; + while (!ioctl(pfd.fd, VIDIOC_DQBUF, &v4l2_buf)) { + vdec_msg.msgcode=VDEC_MSG_RESP_OUTPUT_BUFFER_DONE; + vdec_msg.status_code=VDEC_S_SUCCESS; + vdec_msg.msgdata.output_frame.client_data=(void*)&v4l2_buf; + vdec_msg.msgdata.output_frame.len=plane[0].bytesused; + vdec_msg.msgdata.output_frame.bufferaddr=(void*)plane[0].m.userptr; + vdec_msg.msgdata.output_frame.time_stamp= ((uint64_t)v4l2_buf.timestamp.tv_sec * (uint64_t)1000000) + + (uint64_t)v4l2_buf.timestamp.tv_usec; + if (vdec_msg.msgdata.output_frame.len) { + vdec_msg.msgdata.output_frame.framesize.left = plane[0].reserved[2]; + vdec_msg.msgdata.output_frame.framesize.top = plane[0].reserved[3]; + vdec_msg.msgdata.output_frame.framesize.right = plane[0].reserved[4]; + vdec_msg.msgdata.output_frame.framesize.bottom = plane[0].reserved[5]; + } + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } + } + if ((pfd.revents & POLLOUT) || (pfd.revents & POLLWRNORM)) { + struct vdec_msginfo vdec_msg; + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.length = 1; + v4l2_buf.m.planes = plane; + while (!ioctl(pfd.fd, VIDIOC_DQBUF, &v4l2_buf)) { + vdec_msg.msgcode=VDEC_MSG_RESP_INPUT_BUFFER_DONE; + vdec_msg.status_code=VDEC_S_SUCCESS; + vdec_msg.msgdata.input_frame_clientdata=(void*)&v4l2_buf; + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } + } + if (pfd.revents & POLLPRI) { + rc = ioctl(pfd.fd, VIDIOC_DQEVENT, &dqevent); + if (dqevent.type == V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT ) { + struct vdec_msginfo vdec_msg; + vdec_msg.msgcode=VDEC_MSG_EVT_CONFIG_CHANGED; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_HIGH("VIDC Port Reconfig recieved"); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT ) { + struct vdec_msginfo vdec_msg; + vdec_msg.msgcode=VDEC_MSG_EVT_INFO_CONFIG_CHANGED; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_HIGH("VIDC Port Reconfig recieved"); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_FLUSH_DONE) { + struct vdec_msginfo vdec_msg; + vdec_msg.msgcode=VDEC_MSG_RESP_FLUSH_INPUT_DONE; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_HIGH("VIDC Flush Done Recieved"); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + vdec_msg.msgcode=VDEC_MSG_RESP_FLUSH_OUTPUT_DONE; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_HIGH("VIDC Flush Done Recieved"); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_CLOSE_DONE) { + DEBUG_PRINT_HIGH("VIDC Close Done Recieved and async_message_thread Exited"); + break; + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_SYS_ERROR) { + struct vdec_msginfo vdec_msg; + vdec_msg.msgcode=VDEC_MSG_EVT_HW_ERROR; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_HIGH("SYS Error Recieved"); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } else { + DEBUG_PRINT_HIGH("VIDC Some Event recieved"); + continue; + } + } + } + DEBUG_PRINT_HIGH("omx_vdec: Async thread stop"); + return NULL; +} + +void* message_thread(void *input) +{ + omx_vdec* omx = reinterpret_cast<omx_vdec*>(input); + unsigned char id; + int n; + if (omx == NULL) { + DEBUG_PRINT_ERROR("message thread null pointer rxd"); + return NULL; + } + + DEBUG_PRINT_HIGH("omx_vdec: message thread start"); + prctl(PR_SET_NAME, (unsigned long)"VideoDecMsgThread", 0, 0, 0); + while (1) { + + n = read(omx->m_pipe_in, &id, 1); + + if (0 == n) { + break; + } + + if (1 == n) { + omx->process_event_cb(omx, id); + } + if ((n < 0) && (errno != EINTR)) { + DEBUG_PRINT_LOW("ERROR: read from pipe failed, ret %d errno %d", n, errno); + break; + } + } + DEBUG_PRINT_HIGH("omx_vdec: message thread stop"); + return NULL; +} + +void post_message(omx_vdec *omx, unsigned char id) +{ + int ret_value; + + if (omx == NULL) { + DEBUG_PRINT_ERROR("message thread null pointer rxd"); + return; + } + DEBUG_PRINT_LOW("omx_vdec: post_message %d pipe out%d", id,omx->m_pipe_out); + ret_value = write(omx->m_pipe_out, &id, 1); + DEBUG_PRINT_LOW("post_message to pipe done %d",ret_value); +} + +// omx_cmd_queue destructor +omx_vdec::omx_cmd_queue::~omx_cmd_queue() +{ + // Nothing to do +} + +// omx cmd queue constructor +omx_vdec::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0) +{ + memset(m_q,0,sizeof(m_q)); +} + +// omx cmd queue insert +bool omx_vdec::omx_cmd_queue::insert_entry(unsigned p1, unsigned p2, unsigned id) +{ + bool ret = true; + if (m_size < OMX_CORE_CONTROL_CMDQ_SIZE) { + m_q[m_write].id = id; + m_q[m_write].param1 = p1; + m_q[m_write].param2 = p2; + m_write++; + m_size ++; + if (m_write >= OMX_CORE_CONTROL_CMDQ_SIZE) { + m_write = 0; + } + } else { + ret = false; + DEBUG_PRINT_ERROR("ERROR: %s()::Command Queue Full", __func__); + } + return ret; +} + +// omx cmd queue pop +bool omx_vdec::omx_cmd_queue::pop_entry(unsigned *p1, unsigned *p2, unsigned *id) +{ + bool ret = true; + if (m_size > 0) { + *id = m_q[m_read].id; + *p1 = m_q[m_read].param1; + *p2 = m_q[m_read].param2; + // Move the read pointer ahead + ++m_read; + --m_size; + if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE) { + m_read = 0; + } + } else { + ret = false; + } + return ret; +} + +// Retrieve the first mesg type in the queue +unsigned omx_vdec::omx_cmd_queue::get_q_msg_type() +{ + return m_q[m_read].id; +} + +#ifdef _ANDROID_ +omx_vdec::ts_arr_list::ts_arr_list() +{ + //initialize timestamps array + memset(m_ts_arr_list, 0, sizeof(m_ts_arr_list) ); +} +omx_vdec::ts_arr_list::~ts_arr_list() +{ + //free m_ts_arr_list? +} + +bool omx_vdec::ts_arr_list::insert_ts(OMX_TICKS ts) +{ + bool ret = true; + bool duplicate_ts = false; + int idx = 0; + + //insert at the first available empty location + for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) { + if (!m_ts_arr_list[idx].valid) { + //found invalid or empty entry, save timestamp + m_ts_arr_list[idx].valid = true; + m_ts_arr_list[idx].timestamp = ts; + DEBUG_PRINT_LOW("Insert_ts(): Inserting TIMESTAMP (%lld) at idx (%d)", + ts, idx); + break; + } + } + + if (idx == MAX_NUM_INPUT_OUTPUT_BUFFERS) { + DEBUG_PRINT_LOW("Timestamp array list is FULL. Unsuccessful insert"); + ret = false; + } + return ret; +} + +bool omx_vdec::ts_arr_list::pop_min_ts(OMX_TICKS &ts) +{ + bool ret = true; + int min_idx = -1; + OMX_TICKS min_ts = 0; + int idx = 0; + + for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) { + + if (m_ts_arr_list[idx].valid) { + //found valid entry, save index + if (min_idx < 0) { + //first valid entry + min_ts = m_ts_arr_list[idx].timestamp; + min_idx = idx; + } else if (m_ts_arr_list[idx].timestamp < min_ts) { + min_ts = m_ts_arr_list[idx].timestamp; + min_idx = idx; + } + } + + } + + if (min_idx < 0) { + //no valid entries found + DEBUG_PRINT_LOW("Timestamp array list is empty. Unsuccessful pop"); + ts = 0; + ret = false; + } else { + ts = m_ts_arr_list[min_idx].timestamp; + m_ts_arr_list[min_idx].valid = false; + DEBUG_PRINT_LOW("Pop_min_ts:Timestamp (%lld), index(%d)", + ts, min_idx); + } + + return ret; + +} + + +bool omx_vdec::ts_arr_list::reset_ts_list() +{ + bool ret = true; + int idx = 0; + + DEBUG_PRINT_LOW("reset_ts_list(): Resetting timestamp array list"); + for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) { + m_ts_arr_list[idx].valid = false; + } + return ret; +} +#endif + +// factory function executed by the core to create instances +void *get_omx_component_factory_fn(void) +{ + return (new omx_vdec); +} + +#ifdef _ANDROID_ +#ifdef USE_ION +VideoHeap::VideoHeap(int devicefd, size_t size, void* base, + ion_user_handle_t handle, int ionMapfd) +{ + // ionInit(devicefd, base, size, 0 , MEM_DEVICE,handle,ionMapfd); +} +#else +VideoHeap::VideoHeap(int fd, size_t size, void* base) +{ + // dup file descriptor, map once, use pmem + init(dup(fd), base, size, 0 , MEM_DEVICE); +} +#endif +#endif // _ANDROID_ +/* ====================================================================== + FUNCTION + omx_vdec::omx_vdec + + DESCRIPTION + Constructor + + PARAMETERS + None + + RETURN VALUE + None. + ========================================================================== */ +omx_vdec::omx_vdec(): m_error_propogated(false), + m_state(OMX_StateInvalid), + m_app_data(NULL), + m_inp_mem_ptr(NULL), + m_out_mem_ptr(NULL), + m_inp_err_count(0), + input_flush_progress (false), + output_flush_progress (false), + input_use_buffer (false), + output_use_buffer (false), + ouput_egl_buffers(false), + m_use_output_pmem(OMX_FALSE), + m_out_mem_region_smi(OMX_FALSE), + m_out_pvt_entry_pmem(OMX_FALSE), + pending_input_buffers(0), + pending_output_buffers(0), + m_out_bm_count(0), + m_inp_bm_count(0), + m_inp_bPopulated(OMX_FALSE), + m_out_bPopulated(OMX_FALSE), + m_flags(0), +#ifdef _ANDROID_ + m_heap_ptr(NULL), +#endif + m_inp_bEnabled(OMX_TRUE), + m_out_bEnabled(OMX_TRUE), + m_in_alloc_cnt(0), + m_platform_list(NULL), + m_platform_entry(NULL), + m_pmem_info(NULL), + arbitrary_bytes (true), + psource_frame (NULL), + pdest_frame (NULL), + m_inp_heap_ptr (NULL), + m_phdr_pmem_ptr(NULL), + m_heap_inp_bm_count (0), + codec_type_parse ((codec_type)0), + first_frame_meta (true), + frame_count (0), + nal_count (0), + nal_length(0), + look_ahead_nal (false), + first_frame(0), + first_buffer(NULL), + first_frame_size (0), + m_device_file_ptr(NULL), + m_vc1_profile((vc1_profile_type)0), + h264_last_au_ts(LLONG_MAX), + h264_last_au_flags(0), + prev_ts(LLONG_MAX), + rst_prev_ts(true), + frm_int(0), + in_reconfig(false), + m_display_id(NULL), + h264_parser(NULL), + client_extradata(0), +#ifdef _ANDROID_ + m_enable_android_native_buffers(OMX_FALSE), + m_use_android_native_buffers(OMX_FALSE), +#endif + m_desc_buffer_ptr(NULL), + secure_mode(false) +{ + /* Assumption is that , to begin with , we have all the frames with decoder */ + DEBUG_PRINT_HIGH("In OMX vdec Constructor"); +#ifdef _ANDROID_ + char property_value[PROPERTY_VALUE_MAX] = {0}; + property_get("vidc.debug.level", property_value, "1"); + debug_level = atoi(property_value); + property_value[0] = '\0'; + + property_get("vidc.dec.debug.perf", property_value, "0"); + perf_flag = atoi(property_value); + if (perf_flag) { + DEBUG_PRINT_HIGH("vidc.dec.debug.perf is %d", perf_flag); + dec_time.start(); + proc_frms = latency = 0; + } + property_value[0] = '\0'; + property_get("vidc.dec.debug.ts", property_value, "0"); + m_debug_timestamp = atoi(property_value); + DEBUG_PRINT_HIGH("vidc.dec.debug.ts value is %d",m_debug_timestamp); + if (m_debug_timestamp) { + time_stamp_dts.set_timestamp_reorder_mode(true); + time_stamp_dts.enable_debug_print(true); + } + + property_value[0] = '\0'; + property_get("vidc.dec.debug.concealedmb", property_value, "0"); + m_debug_concealedmb = atoi(property_value); + DEBUG_PRINT_HIGH("vidc.dec.debug.concealedmb value is %d",m_debug_concealedmb); + +#endif + memset(&m_cmp,0,sizeof(m_cmp)); + memset(&m_cb,0,sizeof(m_cb)); + memset (&drv_ctx,0,sizeof(drv_ctx)); + memset (&h264_scratch,0,sizeof (OMX_BUFFERHEADERTYPE)); + memset (m_hwdevice_name,0,sizeof(m_hwdevice_name)); + memset(m_demux_offsets, 0, sizeof(m_demux_offsets) ); + m_demux_entries = 0; +#ifdef _ANDROID_ICS_ + memset(&native_buffer, 0 ,(sizeof(struct nativebuffer) * MAX_NUM_INPUT_OUTPUT_BUFFERS)); +#endif + memset(&drv_ctx.extradata_info, 0, sizeof(drv_ctx.extradata_info)); + drv_ctx.timestamp_adjust = false; + drv_ctx.video_driver_fd = -1; + m_vendor_config.pData = NULL; + pthread_mutex_init(&m_lock, NULL); + pthread_mutex_init(&c_lock, NULL); + sem_init(&m_cmd_lock,0,0); + streaming[CAPTURE_PORT] = + streaming[OUTPUT_PORT] = false; +#ifdef _ANDROID_ + char extradata_value[PROPERTY_VALUE_MAX] = {0}; + property_get("vidc.dec.debug.extradata", extradata_value, "0"); + m_debug_extradata = atoi(extradata_value); + DEBUG_PRINT_HIGH("vidc.dec.debug.extradata value is %d",m_debug_extradata); +#endif + m_fill_output_msg = OMX_COMPONENT_GENERATE_FTB; + client_buffers.set_vdec_client(this); +} + +static const int event_type[] = { + V4L2_EVENT_MSM_VIDC_FLUSH_DONE, + V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT, + V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT, + V4L2_EVENT_MSM_VIDC_CLOSE_DONE, + V4L2_EVENT_MSM_VIDC_SYS_ERROR +}; + +static OMX_ERRORTYPE subscribe_to_events(int fd) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_event_subscription sub; + int array_sz = sizeof(event_type)/sizeof(int); + int i,rc; + if (fd < 0) { + DEBUG_PRINT_ERROR("Invalid input: %d", fd); + return OMX_ErrorBadParameter; + } + + for (i = 0; i < array_sz; ++i) { + memset(&sub, 0, sizeof(sub)); + sub.type = event_type[i]; + rc = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub); + if (rc) { + DEBUG_PRINT_ERROR("Failed to subscribe event: 0x%x", sub.type); + break; + } + } + if (i < array_sz) { + for (--i; i >=0 ; i--) { + memset(&sub, 0, sizeof(sub)); + sub.type = event_type[i]; + rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub); + if (rc) + DEBUG_PRINT_ERROR("Failed to unsubscribe event: 0x%x", sub.type); + } + eRet = OMX_ErrorNotImplemented; + } + return eRet; +} + + +static OMX_ERRORTYPE unsubscribe_to_events(int fd) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_event_subscription sub; + int array_sz = sizeof(event_type)/sizeof(int); + int i,rc; + if (fd < 0) { + DEBUG_PRINT_ERROR("Invalid input: %d", fd); + return OMX_ErrorBadParameter; + } + + for (i = 0; i < array_sz; ++i) { + memset(&sub, 0, sizeof(sub)); + sub.type = event_type[i]; + rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub); + if (rc) { + DEBUG_PRINT_ERROR("Failed to unsubscribe event: 0x%x", sub.type); + break; + } + } + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::~omx_vdec + + DESCRIPTION + Destructor + + PARAMETERS + None + + RETURN VALUE + None. + ========================================================================== */ +omx_vdec::~omx_vdec() +{ + m_pmem_info = NULL; + struct v4l2_decoder_cmd dec; + DEBUG_PRINT_HIGH("In OMX vdec Destructor"); + if (m_pipe_in) close(m_pipe_in); + if (m_pipe_out) close(m_pipe_out); + m_pipe_in = -1; + m_pipe_out = -1; + DEBUG_PRINT_HIGH("Waiting on OMX Msg Thread exit"); + pthread_join(msg_thread_id,NULL); + DEBUG_PRINT_HIGH("Waiting on OMX Async Thread exit"); + dec.cmd = V4L2_DEC_CMD_STOP; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_DECODER_CMD, &dec)) { + DEBUG_PRINT_ERROR("STOP Command failed"); + } + pthread_join(async_thread_id,NULL); + unsubscribe_to_events(drv_ctx.video_driver_fd); + close(drv_ctx.video_driver_fd); + pthread_mutex_destroy(&m_lock); + pthread_mutex_destroy(&c_lock); + sem_destroy(&m_cmd_lock); + if (perf_flag) { + DEBUG_PRINT_HIGH("--> TOTAL PROCESSING TIME"); + dec_time.end(); + } + DEBUG_PRINT_HIGH("Exit OMX vdec Destructor"); +} + +int release_buffers(omx_vdec* obj, enum vdec_buffer buffer_type) +{ + struct v4l2_requestbuffers bufreq; + int rc = 0; + if (buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = 0; + bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + rc = ioctl(obj->drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); + } + return rc; +} + +/* ====================================================================== + FUNCTION + omx_vdec::OMXCntrlProcessMsgCb + + DESCRIPTION + IL Client callbacks are generated through this routine. The decoder + provides the thread context for this routine. + + PARAMETERS + ctxt -- Context information related to the self. + id -- Event identifier. This could be any of the following: + 1. Command completion event + 2. Buffer done callback event + 3. Frame done callback event + + RETURN VALUE + None. + + ========================================================================== */ +void omx_vdec::process_event_cb(void *ctxt, unsigned char id) +{ + signed int p1; // Parameter - 1 + signed int p2; // Parameter - 2 + unsigned int ident; + unsigned int qsize=0; // qsize + omx_vdec *pThis = (omx_vdec *) ctxt; + + if (!pThis) { + DEBUG_PRINT_ERROR("ERROR: %s()::Context is incorrect, bailing out", + __func__); + return; + } + + // Protect the shared queue data structure + do { + /*Read the message id's from the queue*/ + pthread_mutex_lock(&pThis->m_lock); + qsize = pThis->m_cmd_q.m_size; + if (qsize) { + pThis->m_cmd_q.pop_entry((unsigned *)&p1, (unsigned *)&p2, &ident); + } + + if (qsize == 0 && pThis->m_state != OMX_StatePause) { + qsize = pThis->m_ftb_q.m_size; + if (qsize) { + pThis->m_ftb_q.pop_entry((unsigned *)&p1, (unsigned *)&p2, &ident); + } + } + + if (qsize == 0 && pThis->m_state != OMX_StatePause) { + qsize = pThis->m_etb_q.m_size; + if (qsize) { + pThis->m_etb_q.pop_entry((unsigned *)&p1, (unsigned *)&p2, &ident); + } + } + pthread_mutex_unlock(&pThis->m_lock); + + /*process message if we have one*/ + if (qsize > 0) { + id = ident; + switch (id) { + case OMX_COMPONENT_GENERATE_EVENT: + if (pThis->m_cb.EventHandler) { + switch (p1) { + case OMX_CommandStateSet: + pThis->m_state = (OMX_STATETYPE) p2; + DEBUG_PRINT_HIGH("OMX_CommandStateSet complete, m_state = %d", + pThis->m_state); + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete, p1, p2, NULL); + break; + + case OMX_EventError: + if (p2 == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("OMX_EventError: p2 is OMX_StateInvalid"); + pThis->m_state = (OMX_STATETYPE) p2; + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, p2, NULL); + } else if (p2 == OMX_ErrorHardware) { + pThis->omx_report_error(); + } else { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventError, p2, (OMX_U32)NULL, NULL ); + } + break; + + case OMX_CommandPortDisable: + DEBUG_PRINT_HIGH("OMX_CommandPortDisable complete for port [%d]", p2); + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING)) { + BITMASK_SET(&pThis->m_flags, OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED); + break; + } + if (p2 == OMX_CORE_OUTPUT_PORT_INDEX && pThis->in_reconfig) { + OMX_ERRORTYPE eRet = OMX_ErrorNone; + pThis->stream_off(OMX_CORE_OUTPUT_PORT_INDEX); + if (release_buffers(pThis, VDEC_BUFFER_TYPE_OUTPUT)) + DEBUG_PRINT_HIGH("Failed to release output buffers"); + OMX_ERRORTYPE eRet1 = pThis->get_buffer_req(&pThis->drv_ctx.op_buf); + pThis->in_reconfig = false; + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("set_buffer_req failed eRet = %d",eRet); + pThis->omx_report_error(); + break; + } + } + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete, p1, p2, NULL ); + break; + case OMX_CommandPortEnable: + DEBUG_PRINT_HIGH("OMX_CommandPortEnable complete for port [%d]", p2); + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,\ + OMX_EventCmdComplete, p1, p2, NULL ); + break; + + default: + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete, p1, p2, NULL ); + break; + + } + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + break; + case OMX_COMPONENT_GENERATE_ETB_ARBITRARY: + if (pThis->empty_this_buffer_proxy_arbitrary((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("empty_this_buffer_proxy_arbitrary failure"); + pThis->omx_report_error (); + } + break; + case OMX_COMPONENT_GENERATE_ETB: + if (pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("empty_this_buffer_proxy failure"); + pThis->omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_FTB: + if ( pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("fill_this_buffer_proxy failure"); + pThis->omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_COMMAND: + pThis->send_command_proxy(&pThis->m_cmp,(OMX_COMMANDTYPE)p1,\ + (OMX_U32)p2,(OMX_PTR)NULL); + break; + + case OMX_COMPONENT_GENERATE_EBD: + + if (p2 != VDEC_S_SUCCESS && p2 != VDEC_S_INPUT_BITSTREAM_ERR) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_EBD failure"); + pThis->omx_report_error (); + } else { + if (p2 == VDEC_S_INPUT_BITSTREAM_ERR && p1) { + pThis->m_inp_err_count++; + pThis->time_stamp_dts.remove_time_stamp( + ((OMX_BUFFERHEADERTYPE *)p1)->nTimeStamp, + (pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) + ?true:false); + } else { + pThis->m_inp_err_count = 0; + } + if ( pThis->empty_buffer_done(&pThis->m_cmp, + (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("empty_buffer_done failure"); + pThis->omx_report_error (); + } + if (pThis->m_inp_err_count >= MAX_INPUT_ERROR) { + DEBUG_PRINT_ERROR("Input bitstream error for consecutive %d frames.", MAX_INPUT_ERROR); + pThis->omx_report_error (); + } + } + break; + case OMX_COMPONENT_GENERATE_INFO_FIELD_DROPPED: + { + int64_t *timestamp = (int64_t *)p1; + if (p1) { + pThis->time_stamp_dts.remove_time_stamp(*timestamp, + (pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) + ?true:false); + free(timestamp); + } + } + break; + case OMX_COMPONENT_GENERATE_FBD: + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_FBD failure"); + pThis->omx_report_error (); + } else if ( pThis->fill_buffer_done(&pThis->m_cmp, + (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone ) { + DEBUG_PRINT_ERROR("fill_buffer_done failure"); + pThis->omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH: + DEBUG_PRINT_HIGH("Driver flush i/p Port complete"); + if (!pThis->input_flush_progress) { + DEBUG_PRINT_HIGH("WARNING: Unexpected flush from driver"); + } else { + pThis->execute_input_flush(); + if (pThis->m_cb.EventHandler) { + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH failure"); + pThis->omx_report_error (); + } else { + /*Check if we need generate event for Flush done*/ + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_INPUT_FLUSH_PENDING)) { + BITMASK_CLEAR (&pThis->m_flags,OMX_COMPONENT_INPUT_FLUSH_PENDING); + DEBUG_PRINT_LOW("Input Flush completed - Notify Client"); + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandFlush, + OMX_CORE_INPUT_PORT_INDEX,NULL ); + } + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_IDLE_PENDING)) { + if (pThis->stream_off(OMX_CORE_INPUT_PORT_INDEX)) { + DEBUG_PRINT_ERROR("Failed to call streamoff on OUTPUT Port"); + pThis->omx_report_error (); + } else { + pThis->streaming[OUTPUT_PORT] = false; + } + if (!pThis->output_flush_progress) { + DEBUG_PRINT_LOW("Input flush done hence issue stop"); + pThis->post_event ((unsigned int)NULL, VDEC_S_SUCCESS,\ + OMX_COMPONENT_GENERATE_STOP_DONE); + } + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + } + break; + + case OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH: + DEBUG_PRINT_HIGH("Driver flush o/p Port complete"); + if (!pThis->output_flush_progress) { + DEBUG_PRINT_HIGH("WARNING: Unexpected flush from driver"); + } else { + pThis->execute_output_flush(); + if (pThis->m_cb.EventHandler) { + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH failed"); + pThis->omx_report_error (); + } else { + /*Check if we need generate event for Flush done*/ + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_PENDING)) { + DEBUG_PRINT_LOW("Notify Output Flush done"); + BITMASK_CLEAR (&pThis->m_flags,OMX_COMPONENT_OUTPUT_FLUSH_PENDING); + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandFlush, + OMX_CORE_OUTPUT_PORT_INDEX,NULL ); + } + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING)) { + DEBUG_PRINT_LOW("Internal flush complete"); + BITMASK_CLEAR (&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING); + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED)) { + pThis->post_event(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + BITMASK_CLEAR (&pThis->m_flags, + OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED); + + } + } + + if (BITMASK_PRESENT(&pThis->m_flags ,OMX_COMPONENT_IDLE_PENDING)) { + if (pThis->stream_off(OMX_CORE_OUTPUT_PORT_INDEX)) { + DEBUG_PRINT_ERROR("Failed to call streamoff on CAPTURE Port"); + pThis->omx_report_error (); + break; + } + pThis->streaming[CAPTURE_PORT] = false; + if (!pThis->input_flush_progress) { + DEBUG_PRINT_LOW("Output flush done hence issue stop"); + pThis->post_event ((unsigned int)NULL, VDEC_S_SUCCESS,\ + OMX_COMPONENT_GENERATE_STOP_DONE); + } + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + } + break; + + case OMX_COMPONENT_GENERATE_START_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_START_DONE"); + + if (pThis->m_cb.EventHandler) { + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_START_DONE Failure"); + pThis->omx_report_error (); + } else { + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_START_DONE Success"); + if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_EXECUTE_PENDING)) { + DEBUG_PRINT_LOW("Move to executing"); + // Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_EXECUTE_PENDING); + pThis->m_state = OMX_StateExecuting; + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StateExecuting, NULL); + } else if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_PAUSE_PENDING)) { + if (/*ioctl (pThis->drv_ctx.video_driver_fd, + VDEC_IOCTL_CMD_PAUSE,NULL ) < */0) { + DEBUG_PRINT_ERROR("VDEC_IOCTL_CMD_PAUSE failed"); + pThis->omx_report_error (); + } + } + } + } else { + DEBUG_PRINT_LOW("Event Handler callback is NULL"); + } + break; + + case OMX_COMPONENT_GENERATE_PAUSE_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_PAUSE_DONE"); + if (pThis->m_cb.EventHandler) { + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_PAUSE_DONE ret failed"); + pThis->omx_report_error (); + } else { + pThis->complete_pending_buffer_done_cbs(); + if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_PAUSE_PENDING)) { + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_PAUSE_DONE nofity"); + //Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_PAUSE_PENDING); + pThis->m_state = OMX_StatePause; + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StatePause, NULL); + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + + break; + + case OMX_COMPONENT_GENERATE_RESUME_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_RESUME_DONE"); + if (pThis->m_cb.EventHandler) { + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_RESUME_DONE failed"); + pThis->omx_report_error (); + } else { + if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_EXECUTE_PENDING)) { + DEBUG_PRINT_LOW("Moving the decoder to execute state"); + // Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_EXECUTE_PENDING); + pThis->m_state = OMX_StateExecuting; + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StateExecuting,NULL); + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + + break; + + case OMX_COMPONENT_GENERATE_STOP_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_STOP_DONE"); + if (pThis->m_cb.EventHandler) { + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_STOP_DONE ret failed"); + pThis->omx_report_error (); + } else { + pThis->complete_pending_buffer_done_cbs(); + if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_IDLE_PENDING)) { + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_STOP_DONE Success"); + // Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_IDLE_PENDING); + pThis->m_state = OMX_StateIdle; + DEBUG_PRINT_LOW("Move to Idle State"); + pThis->m_cb.EventHandler(&pThis->m_cmp,pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StateIdle,NULL); + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + + break; + + case OMX_COMPONENT_GENERATE_PORT_RECONFIG: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_PORT_RECONFIG"); + + if (p2 == OMX_IndexParamPortDefinition) { + pThis->in_reconfig = true; + } + if (pThis->m_cb.EventHandler) { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventPortSettingsChanged, p1, p2, NULL ); + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + + if (pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) { + OMX_INTERLACETYPE format = (OMX_INTERLACETYPE)-1; + OMX_EVENTTYPE event = (OMX_EVENTTYPE)OMX_EventIndexsettingChanged; + if (pThis->drv_ctx.interlace == VDEC_InterlaceInterleaveFrameTopFieldFirst) + format = OMX_InterlaceInterleaveFrameTopFieldFirst; + else if (pThis->drv_ctx.interlace == VDEC_InterlaceInterleaveFrameBottomFieldFirst) + format = OMX_InterlaceInterleaveFrameBottomFieldFirst; + else //unsupported interlace format; raise a error + event = OMX_EventError; + if (pThis->m_cb.EventHandler) { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + event, format, 0, NULL ); + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + } + break; + + case OMX_COMPONENT_GENERATE_EOS_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_EOS_DONE"); + if (pThis->m_cb.EventHandler) { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, OMX_EventBufferFlag, + OMX_CORE_OUTPUT_PORT_INDEX, OMX_BUFFERFLAG_EOS, NULL ); + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + pThis->prev_ts = LLONG_MAX; + pThis->rst_prev_ts = true; + break; + + case OMX_COMPONENT_GENERATE_HARDWARE_ERROR: + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_HARDWARE_ERROR"); + pThis->omx_report_error (); + break; + case OMX_COMPONENT_GENERATE_INFO_PORT_RECONFIG: + { + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_INFO_PORT_RECONFIG"); + if (pThis->m_cb.EventHandler) { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + (OMX_EVENTTYPE)OMX_EventIndexsettingChanged, OMX_CORE_OUTPUT_PORT_INDEX, 0, NULL ); + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + } + default: + break; + } + } + pthread_mutex_lock(&pThis->m_lock); + qsize = pThis->m_cmd_q.m_size; + if (pThis->m_state != OMX_StatePause) + qsize += (pThis->m_ftb_q.m_size + pThis->m_etb_q.m_size); + pthread_mutex_unlock(&pThis->m_lock); + } while (qsize>0); + +} + +void omx_vdec::update_resolution(int width, int height) +{ + drv_ctx.video_resolution.frame_height = height; + drv_ctx.video_resolution.frame_width = width; + drv_ctx.video_resolution.scan_lines = height; + drv_ctx.video_resolution.stride = width; + rectangle.nLeft = 0; + rectangle.nTop = 0; + rectangle.nWidth = drv_ctx.video_resolution.frame_width; + rectangle.nHeight = drv_ctx.video_resolution.frame_height; +} + +/* ====================================================================== + FUNCTION + omx_vdec::ComponentInit + + DESCRIPTION + Initialize the component. + + PARAMETERS + ctxt -- Context information related to the self. + id -- Event identifier. This could be any of the following: + 1. Command completion event + 2. Buffer done callback event + 3. Frame done callback event + + RETURN VALUE + None. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::component_init(OMX_STRING role) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_fmtdesc fdesc; + struct v4l2_format fmt; + struct v4l2_requestbuffers bufreq; + struct v4l2_control control; + unsigned int alignment = 0,buffer_size = 0; + int fds[2]; + int r,ret=0; + bool codec_ambiguous = false; + OMX_STRING device_name = (OMX_STRING)DEVICE_NAME; + DEBUG_PRINT_LOW("Opening device %s", device_name); + drv_ctx.video_driver_fd = open(device_name, O_RDWR); + + DEBUG_PRINT_HIGH("omx_vdec::component_init(): Open device %s returned fd %d, errno %d", + device_name, drv_ctx.video_driver_fd, errno); + + if (drv_ctx.video_driver_fd == 0) { + drv_ctx.video_driver_fd = open(device_name, O_RDWR); + } + + if (drv_ctx.video_driver_fd < 0) { + DEBUG_PRINT_ERROR("Omx_vdec::Comp Init Returning failure, errno %d", errno); + return OMX_ErrorInsufficientResources; + } + drv_ctx.frame_rate.fps_numerator = DEFAULT_FPS; + drv_ctx.frame_rate.fps_denominator = 1; + + ret = pthread_create(&async_thread_id,0,async_message_thread,this); + if (ret < 0) { + close(drv_ctx.video_driver_fd); + DEBUG_PRINT_ERROR("Failed to create async_message_thread"); + return OMX_ErrorInsufficientResources; + } + +#ifdef INPUT_BUFFER_LOG + strcpy(inputfilename, INPUT_BUFFER_FILE_NAME); +#endif +#ifdef OUTPUT_BUFFER_LOG + outputBufferFile1 = fopen (outputfilename, "ab"); +#endif +#ifdef OUTPUT_EXTRADATA_LOG + outputExtradataFile = fopen (ouputextradatafilename, "ab"); +#endif + + // Copy the role information which provides the decoder kind + strlcpy(drv_ctx.kind,role,128); + + if (!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.mpeg4",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.mpeg4",\ + OMX_MAX_STRINGNAME_SIZE); + drv_ctx.timestamp_adjust = true; + drv_ctx.decoder_format = VDEC_CODECTYPE_MPEG4; + eCompressionFormat = OMX_VIDEO_CodingMPEG4; + output_capability=V4L2_PIX_FMT_MPEG4; + /*Initialize Start Code for MPEG4*/ + codec_type_parse = CODEC_TYPE_MPEG4; + m_frame_parser.init_start_codes (codec_type_parse); +#ifdef INPUT_BUFFER_LOG + strcat(inputfilename, "m4v"); +#endif + } else if (!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.mpeg2",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.mpeg2",\ + OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_MPEG2; + output_capability = V4L2_PIX_FMT_MPEG2; + eCompressionFormat = OMX_VIDEO_CodingMPEG2; + /*Initialize Start Code for MPEG2*/ + codec_type_parse = CODEC_TYPE_MPEG2; + m_frame_parser.init_start_codes (codec_type_parse); +#ifdef INPUT_BUFFER_LOG + strcat(inputfilename, "mpg"); +#endif + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.h263",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("H263 Decoder selected"); + drv_ctx.decoder_format = VDEC_CODECTYPE_H263; + eCompressionFormat = OMX_VIDEO_CodingH263; + output_capability = V4L2_PIX_FMT_H263; + codec_type_parse = CODEC_TYPE_H263; + m_frame_parser.init_start_codes (codec_type_parse); +#ifdef INPUT_BUFFER_LOG + strcat(inputfilename, "263"); +#endif + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx311",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW ("DIVX 311 Decoder selected"); + drv_ctx.decoder_format = VDEC_CODECTYPE_DIVX_3; + output_capability = V4L2_PIX_FMT_DIVX_311; + eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; + codec_type_parse = CODEC_TYPE_DIVX; + m_frame_parser.init_start_codes (codec_type_parse); + + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx4",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_ERROR ("DIVX 4 Decoder selected"); + drv_ctx.decoder_format = VDEC_CODECTYPE_DIVX_4; + output_capability = V4L2_PIX_FMT_DIVX; + eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; + codec_type_parse = CODEC_TYPE_DIVX; + codec_ambiguous = true; + m_frame_parser.init_start_codes (codec_type_parse); + + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_ERROR ("DIVX 5/6 Decoder selected"); + drv_ctx.decoder_format = VDEC_CODECTYPE_DIVX_6; + output_capability = V4L2_PIX_FMT_DIVX; + eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; + codec_type_parse = CODEC_TYPE_DIVX; + codec_ambiguous = true; + m_frame_parser.init_start_codes (codec_type_parse); + + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.avc",OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_H264; + output_capability=V4L2_PIX_FMT_H264; + eCompressionFormat = OMX_VIDEO_CodingAVC; + codec_type_parse = CODEC_TYPE_H264; + m_frame_parser.init_start_codes (codec_type_parse); + m_frame_parser.init_nal_length(nal_length); +#ifdef INPUT_BUFFER_LOG + strcat(inputfilename, "264"); +#endif + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.hevc",OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_HEVC; + output_capability=V4L2_PIX_FMT_HEVC; + eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc; + codec_type_parse = CODEC_TYPE_HEVC; + m_frame_parser.init_start_codes (codec_type_parse); + m_frame_parser.init_nal_length(nal_length); +#ifdef INPUT_BUFFER_LOG + strcat(inputfilename, "265"); +#endif + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vc1",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_VC1; + eCompressionFormat = OMX_VIDEO_CodingWMV; + codec_type_parse = CODEC_TYPE_VC1; + output_capability = V4L2_PIX_FMT_VC1_ANNEX_G; + m_frame_parser.init_start_codes (codec_type_parse); +#ifdef INPUT_BUFFER_LOG + strcat(inputfilename, "vc1"); +#endif + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.wmv",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_VC1_RCV; + eCompressionFormat = OMX_VIDEO_CodingWMV; + codec_type_parse = CODEC_TYPE_VC1; + output_capability = V4L2_PIX_FMT_VC1_ANNEX_L; + m_frame_parser.init_start_codes (codec_type_parse); +#ifdef INPUT_BUFFER_LOG + strcat(inputfilename, "vc1"); +#endif + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.vp8",OMX_MAX_STRINGNAME_SIZE); + output_capability=V4L2_PIX_FMT_VP8; + eCompressionFormat = OMX_VIDEO_CodingVP8; + codec_type_parse = CODEC_TYPE_VP8; + arbitrary_bytes = false; + } else { + DEBUG_PRINT_ERROR("ERROR:Unknown Component"); + eRet = OMX_ErrorInvalidComponentName; + } +#ifdef INPUT_BUFFER_LOG + inputBufferFile1 = fopen (inputfilename, "ab"); +#endif + if (eRet == OMX_ErrorNone) { + + drv_ctx.output_format = VDEC_YUV_FORMAT_NV12; + OMX_COLOR_FORMATTYPE dest_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + if (!client_buffers.set_color_format(dest_color_format)) { + DEBUG_PRINT_ERROR("Setting color format failed"); + eRet = OMX_ErrorInsufficientResources; + } + + capture_capability= V4L2_PIX_FMT_NV12; + ret = subscribe_to_events(drv_ctx.video_driver_fd); + if (ret) { + DEBUG_PRINT_ERROR("Subscribe Event Failed"); + return OMX_ErrorInsufficientResources; + } + + struct v4l2_capability cap; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_QUERYCAP, &cap); + if (ret) { + DEBUG_PRINT_ERROR("Failed to query capabilities"); + /*TODO: How to handle this case */ + } else { + DEBUG_PRINT_HIGH("Capabilities: driver_name = %s, card = %s, bus_info = %s," + " version = %d, capabilities = %x", cap.driver, cap.card, + cap.bus_info, cap.version, cap.capabilities); + } + ret=0; + fdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fdesc.index=0; + while (ioctl(drv_ctx.video_driver_fd, VIDIOC_ENUM_FMT, &fdesc) == 0) { + DEBUG_PRINT_HIGH("fmt: description: %s, fmt: %x, flags = %x", fdesc.description, + fdesc.pixelformat, fdesc.flags); + fdesc.index++; + } + fdesc.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fdesc.index=0; + while (ioctl(drv_ctx.video_driver_fd, VIDIOC_ENUM_FMT, &fdesc) == 0) { + + DEBUG_PRINT_HIGH("fmt: description: %s, fmt: %x, flags = %x", fdesc.description, + fdesc.pixelformat, fdesc.flags); + fdesc.index++; + } + update_resolution(320, 240); + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = output_capability; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to set format on output port"); + } + DEBUG_PRINT_HIGH("Set Format was successful"); + if (codec_ambiguous) { + if (output_capability == V4L2_PIX_FMT_DIVX) { + struct v4l2_control divx_ctrl; + + if (drv_ctx.decoder_format == VDEC_CODECTYPE_DIVX_4) { + divx_ctrl.value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4; + } else if (drv_ctx.decoder_format == VDEC_CODECTYPE_DIVX_5) { + divx_ctrl.value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5; + } else { + divx_ctrl.value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6; + } + + divx_ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &divx_ctrl); + if (ret) { + DEBUG_PRINT_ERROR("Failed to set divx version"); + } + } else { + DEBUG_PRINT_ERROR("Codec should not be ambiguous"); + } + } + + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = capture_capability; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to set format on capture port"); + } + DEBUG_PRINT_HIGH("Set Format was successful"); + if (secure_mode) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE; + control.value = 1; + DEBUG_PRINT_LOW("Omx_vdec:: calling to open secure device %d", ret); + ret=ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL,&control); + if (ret) { + DEBUG_PRINT_ERROR("Omx_vdec:: Unable to open secure device %d", ret); + close(drv_ctx.video_driver_fd); + return OMX_ErrorInsufficientResources; + } + } + + /*Get the Buffer requirements for input and output ports*/ + drv_ctx.ip_buf.buffer_type = VDEC_BUFFER_TYPE_INPUT; + drv_ctx.op_buf.buffer_type = VDEC_BUFFER_TYPE_OUTPUT; + if (secure_mode) { + drv_ctx.op_buf.alignment=SZ_1M; + drv_ctx.ip_buf.alignment=SZ_1M; + } else { + drv_ctx.op_buf.alignment=SZ_4K; + drv_ctx.ip_buf.alignment=SZ_4K; + } + drv_ctx.interlace = VDEC_InterlaceFrameProgressive; + drv_ctx.extradata = 0; + drv_ctx.picture_order = VDEC_ORDER_DISPLAY; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER; + control.value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + drv_ctx.idr_only_decoding = 0; + + m_state = OMX_StateLoaded; +#ifdef DEFAULT_EXTRADATA + if (eRet == OMX_ErrorNone && !secure_mode) + enable_extradata(DEFAULT_EXTRADATA, true, true); +#endif + eRet=get_buffer_req(&drv_ctx.ip_buf); + DEBUG_PRINT_HIGH("Input Buffer Size =%d",drv_ctx.ip_buf.buffer_size); + get_buffer_req(&drv_ctx.op_buf); + if (drv_ctx.decoder_format == VDEC_CODECTYPE_H264 || + drv_ctx.decoder_format == VDEC_CODECTYPE_HEVC) { + h264_scratch.nAllocLen = drv_ctx.ip_buf.buffer_size; + h264_scratch.pBuffer = (OMX_U8 *)malloc (drv_ctx.ip_buf.buffer_size); + h264_scratch.nFilledLen = 0; + h264_scratch.nOffset = 0; + + if (h264_scratch.pBuffer == NULL) { + DEBUG_PRINT_ERROR("h264_scratch.pBuffer Allocation failed "); + return OMX_ErrorInsufficientResources; + } + } + + if (drv_ctx.decoder_format == VDEC_CODECTYPE_H264) { + if (m_frame_parser.mutils == NULL) { + m_frame_parser.mutils = new H264_Utils(); + + if (m_frame_parser.mutils == NULL) { + DEBUG_PRINT_ERROR("parser utils Allocation failed "); + eRet = OMX_ErrorInsufficientResources; + } else { + m_frame_parser.mutils->initialize_frame_checking_environment(); + m_frame_parser.mutils->allocate_rbsp_buffer (drv_ctx.ip_buf.buffer_size); + } + } + + h264_parser = new h264_stream_parser(); + if (!h264_parser) { + DEBUG_PRINT_ERROR("ERROR: H264 parser allocation failed!"); + eRet = OMX_ErrorInsufficientResources; + } + } + + if (pipe(fds)) { + DEBUG_PRINT_ERROR("pipe creation failed"); + eRet = OMX_ErrorInsufficientResources; + } else { + int temp1[2]; + if (fds[0] == 0 || fds[1] == 0) { + if (pipe (temp1)) { + DEBUG_PRINT_ERROR("pipe creation failed"); + return OMX_ErrorInsufficientResources; + } + //close (fds[0]); + //close (fds[1]); + fds[0] = temp1 [0]; + fds[1] = temp1 [1]; + } + m_pipe_in = fds[0]; + m_pipe_out = fds[1]; + r = pthread_create(&msg_thread_id,0,message_thread,this); + + if (r < 0) { + DEBUG_PRINT_ERROR("component_init(): message_thread creation failed"); + eRet = OMX_ErrorInsufficientResources; + } + } + } + + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("Component Init Failed"); + DEBUG_PRINT_HIGH("Calling VDEC_IOCTL_STOP_NEXT_MSG"); + (void)ioctl(drv_ctx.video_driver_fd, VDEC_IOCTL_STOP_NEXT_MSG, + NULL); + DEBUG_PRINT_HIGH("Calling close() on Video Driver"); + close (drv_ctx.video_driver_fd); + drv_ctx.video_driver_fd = -1; + } else { + DEBUG_PRINT_HIGH("omx_vdec::component_init() success"); + } + //memset(&h264_mv_buff,0,sizeof(struct h264_mv_buffer)); + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::GetComponentVersion + + DESCRIPTION + Returns the component version. + + PARAMETERS + TBD. + + RETURN VALUE + OMX_ErrorNone. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_component_version +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STRING componentName, + OMX_OUT OMX_VERSIONTYPE* componentVersion, + OMX_OUT OMX_VERSIONTYPE* specVersion, + OMX_OUT OMX_UUIDTYPE* componentUUID + ) +{ + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Get Comp Version in Invalid State"); + return OMX_ErrorInvalidState; + } + /* TBD -- Return the proper version */ + if (specVersion) { + specVersion->nVersion = OMX_SPEC_VERSION; + } + return OMX_ErrorNone; +} +/* ====================================================================== + FUNCTION + omx_vdec::SendCommand + + DESCRIPTION + Returns zero if all the buffers released.. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::send_command(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData + ) +{ + DEBUG_PRINT_LOW("send_command: Recieved a Command from Client"); + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: Send Command in Invalid State"); + return OMX_ErrorInvalidState; + } + if (cmd == OMX_CommandFlush && param1 != OMX_CORE_INPUT_PORT_INDEX + && param1 != OMX_CORE_OUTPUT_PORT_INDEX && param1 != OMX_ALL) { + DEBUG_PRINT_ERROR("send_command(): ERROR OMX_CommandFlush " + "to invalid port: %lu", param1); + return OMX_ErrorBadPortIndex; + } + post_event((unsigned)cmd,(unsigned)param1,OMX_COMPONENT_GENERATE_COMMAND); + sem_wait(&m_cmd_lock); + DEBUG_PRINT_LOW("send_command: Command Processed"); + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::SendCommand + + DESCRIPTION + Returns zero if all the buffers released.. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData + ) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_STATETYPE eState = (OMX_STATETYPE) param1; + int bFlag = 1,sem_posted = 0,ret=0; + + DEBUG_PRINT_LOW("send_command_proxy(): cmd = %d", cmd); + DEBUG_PRINT_HIGH("send_command_proxy(): Current State %d, Expected State %d", + m_state, eState); + + if (cmd == OMX_CommandStateSet) { + DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandStateSet issued"); + DEBUG_PRINT_HIGH("Current State %d, Expected State %d", m_state, eState); + /***************************/ + /* Current State is Loaded */ + /***************************/ + if (m_state == OMX_StateLoaded) { + if (eState == OMX_StateIdle) { + //if all buffers are allocated or all ports disabled + if (allocate_done() || + (m_inp_bEnabled == OMX_FALSE && m_out_bEnabled == OMX_FALSE)) { + DEBUG_PRINT_LOW("send_command_proxy(): Loaded-->Idle"); + } else { + DEBUG_PRINT_LOW("send_command_proxy(): Loaded-->Idle-Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING); + // Skip the event notification + bFlag = 0; + } + } + /* Requesting transition from Loaded to Loaded */ + else if (eState == OMX_StateLoaded) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Loaded"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Loaded to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + /* Since error is None , we will post an event + at the end of this function definition */ + DEBUG_PRINT_LOW("send_command_proxy(): Loaded-->WaitForResources"); + } + /* Requesting transition from Loaded to Executing */ + else if (eState == OMX_StateExecuting) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Executing"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Loaded to Pause */ + else if (eState == OMX_StatePause) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Pause"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Loaded to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } else { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Invalid(%d Not Handled)",\ + eState); + eRet = OMX_ErrorBadParameter; + } + } + + /***************************/ + /* Current State is IDLE */ + /***************************/ + else if (m_state == OMX_StateIdle) { + if (eState == OMX_StateLoaded) { + if (release_done()) { + /* + Since error is None , we will post an event at the end + of this function definition + */ + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Loaded"); + } else { + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Loaded-Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING); + // Skip the event notification + bFlag = 0; + } + } + /* Requesting transition from Idle to Executing */ + else if (eState == OMX_StateExecuting) { + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing"); + //BITMASK_SET(&m_flags, OMX_COMPONENT_EXECUTE_PENDING); + bFlag = 1; + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing"); + m_state=OMX_StateExecuting; + DEBUG_PRINT_HIGH("Stream On CAPTURE Was successful"); + } + /* Requesting transition from Idle to Idle */ + else if (eState == OMX_StateIdle) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->Idle"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Idle to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->WaitForResources"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Idle to Pause */ + else if (eState == OMX_StatePause) { + /*To pause the Video core we need to start the driver*/ + if (/*ioctl (drv_ctx.video_driver_fd,VDEC_IOCTL_CMD_START, + NULL) < */0) { + DEBUG_PRINT_ERROR("VDEC_IOCTL_CMD_START FAILED"); + omx_report_error (); + eRet = OMX_ErrorHardware; + } else { + BITMASK_SET(&m_flags,OMX_COMPONENT_PAUSE_PENDING); + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Pause"); + bFlag = 0; + } + } + /* Requesting transition from Idle to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } else { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle --> %d Not Handled",eState); + eRet = OMX_ErrorBadParameter; + } + } + + /******************************/ + /* Current State is Executing */ + /******************************/ + else if (m_state == OMX_StateExecuting) { + DEBUG_PRINT_LOW("Command Recieved in OMX_StateExecuting"); + /* Requesting transition from Executing to Idle */ + if (eState == OMX_StateIdle) { + /* Since error is None , we will post an event + at the end of this function definition + */ + DEBUG_PRINT_LOW("send_command_proxy(): Executing --> Idle"); + BITMASK_SET(&m_flags,OMX_COMPONENT_IDLE_PENDING); + if (!sem_posted) { + sem_posted = 1; + sem_post (&m_cmd_lock); + execute_omx_flush(OMX_ALL); + } + bFlag = 0; + } + /* Requesting transition from Executing to Paused */ + else if (eState == OMX_StatePause) { + DEBUG_PRINT_LOW("PAUSE Command Issued"); + m_state = OMX_StatePause; + bFlag = 1; + } + /* Requesting transition from Executing to Loaded */ + else if (eState == OMX_StateLoaded) { + DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> Loaded"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Executing to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> WaitForResources"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Executing to Executing */ + else if (eState == OMX_StateExecuting) { + DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> Executing"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Executing to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } else { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Executing --> %d Not Handled",eState); + eRet = OMX_ErrorBadParameter; + } + } + /***************************/ + /* Current State is Pause */ + /***************************/ + else if (m_state == OMX_StatePause) { + /* Requesting transition from Pause to Executing */ + if (eState == OMX_StateExecuting) { + DEBUG_PRINT_LOW("Pause --> Executing"); + m_state = OMX_StateExecuting; + bFlag = 1; + } + /* Requesting transition from Pause to Idle */ + else if (eState == OMX_StateIdle) { + /* Since error is None , we will post an event + at the end of this function definition */ + DEBUG_PRINT_LOW("Pause --> Idle"); + BITMASK_SET(&m_flags,OMX_COMPONENT_IDLE_PENDING); + if (!sem_posted) { + sem_posted = 1; + sem_post (&m_cmd_lock); + execute_omx_flush(OMX_ALL); + } + bFlag = 0; + } + /* Requesting transition from Pause to loaded */ + else if (eState == OMX_StateLoaded) { + DEBUG_PRINT_ERROR("Pause --> loaded"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Pause to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + DEBUG_PRINT_ERROR("Pause --> WaitForResources"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Pause to Pause */ + else if (eState == OMX_StatePause) { + DEBUG_PRINT_ERROR("Pause --> Pause"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Pause to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Pause --> Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } else { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Paused --> %d Not Handled",eState); + eRet = OMX_ErrorBadParameter; + } + } + /***************************/ + /* Current State is WaitForResources */ + /***************************/ + else if (m_state == OMX_StateWaitForResources) { + /* Requesting transition from WaitForResources to Loaded */ + if (eState == OMX_StateLoaded) { + /* Since error is None , we will post an event + at the end of this function definition */ + DEBUG_PRINT_LOW("send_command_proxy(): WaitForResources-->Loaded"); + } + /* Requesting transition from WaitForResources to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->WaitForResources"); + post_event(OMX_EventError,OMX_ErrorSameState, + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from WaitForResources to Executing */ + else if (eState == OMX_StateExecuting) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->Executing"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from WaitForResources to Pause */ + else if (eState == OMX_StatePause) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->Pause"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from WaitForResources to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } + /* Requesting transition from WaitForResources to Loaded - + is NOT tested by Khronos TS */ + + } else { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): %d --> %d(Not Handled)",m_state,eState); + eRet = OMX_ErrorBadParameter; + } + } + /********************************/ + /* Current State is Invalid */ + /*******************************/ + else if (m_state == OMX_StateInvalid) { + /* State Transition from Inavlid to any state */ + if (eState == (OMX_StateLoaded || OMX_StateWaitForResources + || OMX_StateIdle || OMX_StateExecuting + || OMX_StatePause || OMX_StateInvalid)) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Invalid -->Loaded"); + post_event(OMX_EventError,OMX_ErrorInvalidState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } + } else if (cmd == OMX_CommandFlush) { + DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandFlush issued" + "with param1: %lu", param1); + if (OMX_CORE_INPUT_PORT_INDEX == param1 || OMX_ALL == param1) { + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_FLUSH_PENDING); + } + if (OMX_CORE_OUTPUT_PORT_INDEX == param1 || OMX_ALL == param1) { + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_FLUSH_PENDING); + } + if (!sem_posted) { + sem_posted = 1; + DEBUG_PRINT_LOW("Set the Semaphore"); + sem_post (&m_cmd_lock); + execute_omx_flush(param1); + } + bFlag = 0; + } else if ( cmd == OMX_CommandPortEnable) { + DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandPortEnable issued" + "with param1: %lu", param1); + if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) { + m_inp_bEnabled = OMX_TRUE; + + if ( (m_state == OMX_StateLoaded && + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || allocate_input_done()) { + post_event(OMX_CommandPortEnable,OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else { + DEBUG_PRINT_LOW("send_command_proxy(): Disabled-->Enabled Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING); + // Skip the event notification + bFlag = 0; + } + } + if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) { + DEBUG_PRINT_LOW("Enable output Port command recieved"); + m_out_bEnabled = OMX_TRUE; + + if ( (m_state == OMX_StateLoaded && + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (allocate_output_done())) { + post_event(OMX_CommandPortEnable,OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + } else { + DEBUG_PRINT_LOW("send_command_proxy(): Disabled-->Enabled Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + // Skip the event notification + bFlag = 0; + } + } + } else if (cmd == OMX_CommandPortDisable) { + DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandPortDisable issued" + "with param1: %lu", param1); + if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) { + m_inp_bEnabled = OMX_FALSE; + if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_input_done()) { + post_event(OMX_CommandPortDisable,OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else { + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING); + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) { + if (!sem_posted) { + sem_posted = 1; + sem_post (&m_cmd_lock); + } + execute_omx_flush(OMX_CORE_INPUT_PORT_INDEX); + } + + // Skip the event notification + bFlag = 0; + } + } + if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) { + m_out_bEnabled = OMX_FALSE; + DEBUG_PRINT_LOW("Disable output Port command recieved"); + if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_output_done()) { + post_event(OMX_CommandPortDisable,OMX_CORE_OUTPUT_PORT_INDEX,\ + OMX_COMPONENT_GENERATE_EVENT); + } else { + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) { + if (!sem_posted) { + sem_posted = 1; + sem_post (&m_cmd_lock); + } + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING); + execute_omx_flush(OMX_CORE_OUTPUT_PORT_INDEX); + } + // Skip the event notification + bFlag = 0; + + } + } + } else { + DEBUG_PRINT_ERROR("Error: Invalid Command other than StateSet (%d)",cmd); + eRet = OMX_ErrorNotImplemented; + } + if (eRet == OMX_ErrorNone && bFlag) { + post_event(cmd,eState,OMX_COMPONENT_GENERATE_EVENT); + } + if (!sem_posted) { + sem_post(&m_cmd_lock); + } + + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::ExecuteOmxFlush + + DESCRIPTION + Executes the OMX flush. + + PARAMETERS + flushtype - input flush(1)/output flush(0)/ both. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_vdec::execute_omx_flush(OMX_U32 flushType) +{ + bool bRet = false; + struct v4l2_plane plane; + struct v4l2_buffer v4l2_buf; + struct v4l2_decoder_cmd dec; + DEBUG_PRINT_LOW("in %s", __func__); + memset((void *)&v4l2_buf,0,sizeof(v4l2_buf)); + dec.cmd = V4L2_DEC_QCOM_CMD_FLUSH; + switch (flushType) { + case OMX_CORE_INPUT_PORT_INDEX: + input_flush_progress = true; + dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT; + break; + case OMX_CORE_OUTPUT_PORT_INDEX: + output_flush_progress = true; + dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE; + break; + default: + input_flush_progress = true; + output_flush_progress = true; + dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT | + V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE; + } + + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_DECODER_CMD, &dec)) { + DEBUG_PRINT_ERROR("Flush Port (%lu) Failed ", flushType); + bRet = false; + } + + return bRet; +} +/*========================================================================= +FUNCTION : execute_output_flush + +DESCRIPTION +Executes the OMX flush at OUTPUT PORT. + +PARAMETERS +None. + +RETURN VALUE +true/false +==========================================================================*/ +bool omx_vdec::execute_output_flush() +{ + unsigned p1 = 0; // Parameter - 1 + unsigned p2 = 0; // Parameter - 2 + unsigned ident = 0; + bool bRet = true; + + /*Generate FBD for all Buffers in the FTBq*/ + pthread_mutex_lock(&m_lock); + DEBUG_PRINT_LOW("Initiate Output Flush"); + while (m_ftb_q.m_size) { + DEBUG_PRINT_LOW("Buffer queue size %d pending buf cnt %d", + m_ftb_q.m_size,pending_output_buffers); + m_ftb_q.pop_entry(&p1,&p2,&ident); + DEBUG_PRINT_LOW("ID(%x) P1(%x) P2(%x)", ident, p1, p2); + if (ident == m_fill_output_msg ) { + m_cb.FillBufferDone(&m_cmp, m_app_data, (OMX_BUFFERHEADERTYPE *)p2); + } else if (ident == OMX_COMPONENT_GENERATE_FBD) { + fill_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1); + } + } + pthread_mutex_unlock(&m_lock); + output_flush_progress = false; + + if (arbitrary_bytes) { + prev_ts = LLONG_MAX; + rst_prev_ts = true; + } + DEBUG_PRINT_HIGH("OMX flush o/p Port complete PenBuf(%d)", pending_output_buffers); + return bRet; +} +/*========================================================================= +FUNCTION : execute_input_flush + +DESCRIPTION +Executes the OMX flush at INPUT PORT. + +PARAMETERS +None. + +RETURN VALUE +true/false +==========================================================================*/ +bool omx_vdec::execute_input_flush() +{ + unsigned i =0; + unsigned p1 = 0; // Parameter - 1 + unsigned p2 = 0; // Parameter - 2 + unsigned ident = 0; + bool bRet = true; + + /*Generate EBD for all Buffers in the ETBq*/ + DEBUG_PRINT_LOW("Initiate Input Flush"); + + pthread_mutex_lock(&m_lock); + DEBUG_PRINT_LOW("Check if the Queue is empty"); + while (m_etb_q.m_size) { + m_etb_q.pop_entry(&p1,&p2,&ident); + + if (ident == OMX_COMPONENT_GENERATE_ETB_ARBITRARY) { + DEBUG_PRINT_LOW("Flush Input Heap Buffer %p",(OMX_BUFFERHEADERTYPE *)p2); + m_cb.EmptyBufferDone(&m_cmp ,m_app_data, (OMX_BUFFERHEADERTYPE *)p2); + } else if (ident == OMX_COMPONENT_GENERATE_ETB) { + pending_input_buffers++; + DEBUG_PRINT_LOW("Flush Input OMX_COMPONENT_GENERATE_ETB %p, pending_input_buffers %d", + (OMX_BUFFERHEADERTYPE *)p2, pending_input_buffers); + empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p2); + } else if (ident == OMX_COMPONENT_GENERATE_EBD) { + DEBUG_PRINT_LOW("Flush Input OMX_COMPONENT_GENERATE_EBD %p", + (OMX_BUFFERHEADERTYPE *)p1); + empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1); + } + } + time_stamp_dts.flush_timestamp(); + /*Check if Heap Buffers are to be flushed*/ + if (arbitrary_bytes && !(codec_config_flag)) { + DEBUG_PRINT_LOW("Reset all the variables before flusing"); + h264_scratch.nFilledLen = 0; + nal_count = 0; + look_ahead_nal = false; + frame_count = 0; + h264_last_au_ts = LLONG_MAX; + h264_last_au_flags = 0; + memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) ); + m_demux_entries = 0; + DEBUG_PRINT_LOW("Initialize parser"); + if (m_frame_parser.mutils) { + m_frame_parser.mutils->initialize_frame_checking_environment(); + } + + while (m_input_pending_q.m_size) { + m_input_pending_q.pop_entry(&p1,&p2,&ident); + m_cb.EmptyBufferDone(&m_cmp ,m_app_data, (OMX_BUFFERHEADERTYPE *)p1); + } + + if (psource_frame) { + m_cb.EmptyBufferDone(&m_cmp ,m_app_data,psource_frame); + psource_frame = NULL; + } + + if (pdest_frame) { + pdest_frame->nFilledLen = 0; + m_input_free_q.insert_entry((unsigned) pdest_frame, (unsigned int)NULL, + (unsigned int)NULL); + pdest_frame = NULL; + } + m_frame_parser.flush(); + } else if (codec_config_flag) { + DEBUG_PRINT_HIGH("frame_parser flushing skipped due to codec config buffer " + "is not sent to the driver yet"); + } + pthread_mutex_unlock(&m_lock); + input_flush_progress = false; + if (!arbitrary_bytes) { + prev_ts = LLONG_MAX; + rst_prev_ts = true; + } +#ifdef _ANDROID_ + if (m_debug_timestamp) { + m_timestamp_list.reset_ts_list(); + } +#endif + DEBUG_PRINT_HIGH("OMX flush i/p Port complete PenBuf(%d)", pending_input_buffers); + return bRet; +} + + +/* ====================================================================== + FUNCTION + omx_vdec::SendCommandEvent + + DESCRIPTION + Send the event to decoder pipe. This is needed to generate the callbacks + in decoder thread context. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_vdec::post_event(unsigned int p1, + unsigned int p2, + unsigned int id) +{ + bool bRet = false; + + + pthread_mutex_lock(&m_lock); + + if (id == m_fill_output_msg || + id == OMX_COMPONENT_GENERATE_FBD) { + m_ftb_q.insert_entry(p1,p2,id); + } else if (id == OMX_COMPONENT_GENERATE_ETB || + id == OMX_COMPONENT_GENERATE_EBD || + id == OMX_COMPONENT_GENERATE_ETB_ARBITRARY) { + m_etb_q.insert_entry(p1,p2,id); + } else { + m_cmd_q.insert_entry(p1,p2,id); + } + + bRet = true; + DEBUG_PRINT_LOW("Value of this pointer in post_event %p",this); + post_message(this, id); + + pthread_mutex_unlock(&m_lock); + + return bRet; +} + +OMX_ERRORTYPE omx_vdec::get_supported_profile_level_for_1080p(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNoMore; + if (!profileLevelType) + return OMX_ErrorBadParameter; + + if (profileLevelType->nPortIndex == 0) { + if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc",OMX_MAX_STRINGNAME_SIZE)) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileBaseline; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel4; + + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileMain; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel4; + } else if (profileLevelType->nProfileIndex == 2) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileHigh; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel4; + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %d", + profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc",OMX_MAX_STRINGNAME_SIZE)) { + // TODO + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %d", + profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if ((!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263",OMX_MAX_STRINGNAME_SIZE))) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_H263ProfileBaseline; + profileLevelType->eLevel = OMX_VIDEO_H263Level70; + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %lu", profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE)) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_MPEG4ProfileSimple; + profileLevelType->eLevel = OMX_VIDEO_MPEG4Level5; + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple; + profileLevelType->eLevel = OMX_VIDEO_MPEG4Level5; + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %lu", profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8",OMX_MAX_STRINGNAME_SIZE)) { + eRet = OMX_ErrorNoMore; + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg2",OMX_MAX_STRINGNAME_SIZE)) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_MPEG2ProfileSimple; + profileLevelType->eLevel = OMX_VIDEO_MPEG2LevelHL; + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_MPEG2ProfileMain; + profileLevelType->eLevel = OMX_VIDEO_MPEG2LevelHL; + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %lu", profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } + } else { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported should be queries on Input port only %lu", profileLevelType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::GetParameter + + DESCRIPTION + OMX Get Parameter method implementation + + PARAMETERS + <TBD>. + + RETURN VALUE + Error None if successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_INOUT OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + DEBUG_PRINT_LOW("get_parameter:"); + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Get Param in Invalid State"); + return OMX_ErrorInvalidState; + } + if (paramData == NULL) { + DEBUG_PRINT_LOW("Get Param in Invalid paramData"); + return OMX_ErrorBadParameter; + } + switch ((unsigned long)paramIndex) { + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn = + (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamPortDefinition"); + eRet = update_portdef(portDefn); + if (eRet == OMX_ErrorNone) + m_port_def = *portDefn; + break; + } + case OMX_IndexParamVideoInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoInit"); + + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 2; + portParamType->nStartPortNumber = 0; + break; + } + case OMX_IndexParamVideoPortFormat: + { + OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoPortFormat"); + + portFmt->nVersion.nVersion = OMX_SPEC_VERSION; + portFmt->nSize = sizeof(portFmt); + + if (0 == portFmt->nPortIndex) { + if (0 == portFmt->nIndex) { + portFmt->eColorFormat = OMX_COLOR_FormatUnused; + portFmt->eCompressionFormat = eCompressionFormat; + } else { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoPortFormat:"\ + " NoMore compression formats"); + eRet = OMX_ErrorNoMore; + } + } else if (1 == portFmt->nPortIndex) { + portFmt->eCompressionFormat = OMX_VIDEO_CodingUnused; + + if (0 == portFmt->nIndex) + portFmt->eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + else if (1 == portFmt->nIndex) + portFmt->eColorFormat = OMX_COLOR_FormatYUV420Planar; + else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoPortFormat:"\ + " NoMore Color formats"); + eRet = OMX_ErrorNoMore; + } + DEBUG_PRINT_LOW("returning %d", portFmt->eColorFormat); + } else { + DEBUG_PRINT_ERROR("get_parameter: Bad port index %d", + (int)portFmt->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + /*Component should support this port definition*/ + case OMX_IndexParamAudioInit: + { + OMX_PORT_PARAM_TYPE *audioPortParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamAudioInit"); + audioPortParamType->nVersion.nVersion = OMX_SPEC_VERSION; + audioPortParamType->nSize = sizeof(audioPortParamType); + audioPortParamType->nPorts = 0; + audioPortParamType->nStartPortNumber = 0; + break; + } + /*Component should support this port definition*/ + case OMX_IndexParamImageInit: + { + OMX_PORT_PARAM_TYPE *imagePortParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamImageInit"); + imagePortParamType->nVersion.nVersion = OMX_SPEC_VERSION; + imagePortParamType->nSize = sizeof(imagePortParamType); + imagePortParamType->nPorts = 0; + imagePortParamType->nStartPortNumber = 0; + break; + + } + /*Component should support this port definition*/ + case OMX_IndexParamOtherInit: + { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamOtherInit %08x", + paramIndex); + eRet =OMX_ErrorUnsupportedIndex; + break; + } + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *comp_role; + comp_role = (OMX_PARAM_COMPONENTROLETYPE *) paramData; + comp_role->nVersion.nVersion = OMX_SPEC_VERSION; + comp_role->nSize = sizeof(*comp_role); + + DEBUG_PRINT_LOW("Getparameter: OMX_IndexParamStandardComponentRole %d", + paramIndex); + strlcpy((char*)comp_role->cRole,(const char*)m_cRole, + OMX_MAX_STRINGNAME_SIZE); + break; + } + /* Added for parameter test */ + case OMX_IndexParamPriorityMgmt: + { + + OMX_PRIORITYMGMTTYPE *priorityMgmType = + (OMX_PRIORITYMGMTTYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamPriorityMgmt"); + priorityMgmType->nVersion.nVersion = OMX_SPEC_VERSION; + priorityMgmType->nSize = sizeof(priorityMgmType); + + break; + } + /* Added for parameter test */ + case OMX_IndexParamCompBufferSupplier: + { + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType = + (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamCompBufferSupplier"); + + bufferSupplierType->nSize = sizeof(bufferSupplierType); + bufferSupplierType->nVersion.nVersion = OMX_SPEC_VERSION; + if (0 == bufferSupplierType->nPortIndex) + bufferSupplierType->nPortIndex = OMX_BufferSupplyUnspecified; + else if (1 == bufferSupplierType->nPortIndex) + bufferSupplierType->nPortIndex = OMX_BufferSupplyUnspecified; + else + eRet = OMX_ErrorBadPortIndex; + + + break; + } + case OMX_IndexParamVideoAvc: + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoAvc %08x", + paramIndex); + break; + } + case OMX_IndexParamVideoH263: + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoH263 %08x", + paramIndex); + break; + } + case OMX_IndexParamVideoMpeg4: + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoMpeg4 %08x", + paramIndex); + break; + } + case OMX_IndexParamVideoMpeg2: + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoMpeg2 %08x", + paramIndex); + break; + } + case OMX_IndexParamVideoProfileLevelQuerySupported: + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported %08x", paramIndex); + OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType = + (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)paramData; + eRet = get_supported_profile_level_for_1080p(profileLevelType); + break; + } +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) + case OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage: + { + DEBUG_PRINT_HIGH("get_parameter: OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage"); + GetAndroidNativeBufferUsageParams* nativeBuffersUsage = (GetAndroidNativeBufferUsageParams *) paramData; + if (nativeBuffersUsage->nPortIndex == OMX_CORE_OUTPUT_PORT_INDEX) { + + if (secure_mode) { + nativeBuffersUsage->nUsage = (GRALLOC_USAGE_PRIVATE_MM_HEAP | GRALLOC_USAGE_PROTECTED | + GRALLOC_USAGE_PRIVATE_UNCACHED); + } else { +#ifdef _HEVC_USE_ADSP_HEAP_ + nativeBuffersUsage->nUsage = (GRALLOC_USAGE_PRIVATE_ADSP_HEAP | GRALLOC_USAGE_PRIVATE_UNCACHED); +#else + nativeBuffersUsage->nUsage = GRALLOC_USAGE_PRIVATE_UNCACHED; +#endif + DEBUG_PRINT_HIGH("nativeBuffersUsage->nUsage %x", (unsigned int)nativeBuffersUsage->nUsage); + } + } else { + DEBUG_PRINT_HIGH("get_parameter: OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage failed!"); + eRet = OMX_ErrorBadParameter; + } + } + break; +#endif + + default: + { + DEBUG_PRINT_ERROR("get_parameter: unknown param %08x", paramIndex); + eRet =OMX_ErrorUnsupportedIndex; + } + + } + + DEBUG_PRINT_LOW("get_parameter returning WxH(%d x %d) SxSH(%d x %d)", + drv_ctx.video_resolution.frame_width, + drv_ctx.video_resolution.frame_height, + drv_ctx.video_resolution.stride, + drv_ctx.video_resolution.scan_lines); + + return eRet; +} + +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) +OMX_ERRORTYPE omx_vdec::use_android_native_buffer(OMX_IN OMX_HANDLETYPE hComp, OMX_PTR data) +{ + DEBUG_PRINT_LOW("Inside use_android_native_buffer"); + OMX_ERRORTYPE eRet = OMX_ErrorNone; + UseAndroidNativeBufferParams *params = (UseAndroidNativeBufferParams *)data; + + if ((params == NULL) || + (params->nativeBuffer == NULL) || + (params->nativeBuffer->handle == NULL) || + !m_enable_android_native_buffers) + return OMX_ErrorBadParameter; + m_use_android_native_buffers = OMX_TRUE; + sp<android_native_buffer_t> nBuf = params->nativeBuffer; + private_handle_t *handle = (private_handle_t *)nBuf->handle; + if (OMX_CORE_OUTPUT_PORT_INDEX == params->nPortIndex) { //android native buffers can be used only on Output port + OMX_U8 *buffer = NULL; + if (!secure_mode) { + buffer = (OMX_U8*)mmap(0, handle->size, + PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0); + if (buffer == MAP_FAILED) { + DEBUG_PRINT_ERROR("Failed to mmap pmem with fd = %d, size = %d", handle->fd, handle->size); + return OMX_ErrorInsufficientResources; + } + } + eRet = use_buffer(hComp,params->bufferHeader,params->nPortIndex,data,handle->size,buffer); + } else { + eRet = OMX_ErrorBadParameter; + } + return eRet; +} +#endif +/* ====================================================================== + FUNCTION + omx_vdec::Setparameter + + DESCRIPTION + OMX Set Parameter method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::set_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_IN OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + int ret=0; + struct v4l2_format fmt; + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Set Param in Invalid State"); + return OMX_ErrorInvalidState; + } + if (paramData == NULL) { + DEBUG_PRINT_ERROR("Get Param in Invalid paramData"); + return OMX_ErrorBadParameter; + } + if ((m_state != OMX_StateLoaded) && + BITMASK_ABSENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING) && + (m_out_bEnabled == OMX_TRUE) && + BITMASK_ABSENT(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING) && + (m_inp_bEnabled == OMX_TRUE)) { + DEBUG_PRINT_ERROR("Set Param in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + switch ((unsigned long)paramIndex) { + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + //TODO: Check if any allocate buffer/use buffer/useNativeBuffer has + //been called. + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition H= %d, W = %d", + (int)portDefn->format.video.nFrameHeight, + (int)portDefn->format.video.nFrameWidth); + if (OMX_DirOutput == portDefn->eDir) { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition OP port"); + m_display_id = portDefn->format.video.pNativeWindow; + unsigned int buffer_size; + if (!client_buffers.get_buffer_req(buffer_size)) { + DEBUG_PRINT_ERROR("Error in getting buffer requirements"); + eRet = OMX_ErrorBadParameter; + } else { + if ( portDefn->nBufferCountActual >= drv_ctx.op_buf.mincount && + portDefn->nBufferSize >= drv_ctx.op_buf.buffer_size ) { + drv_ctx.op_buf.actualcount = portDefn->nBufferCountActual; + drv_ctx.op_buf.buffer_size = portDefn->nBufferSize; + eRet = set_buffer_req(&drv_ctx.op_buf); + if (eRet == OMX_ErrorNone) + m_port_def = *portDefn; + } else { + DEBUG_PRINT_ERROR("ERROR: OP Requirements(#%d: %u) Requested(#%lu: %lu)", + drv_ctx.op_buf.mincount, drv_ctx.op_buf.buffer_size, + portDefn->nBufferCountActual, portDefn->nBufferSize); + eRet = OMX_ErrorBadParameter; + } + } + } else if (OMX_DirInput == portDefn->eDir) { + if ((portDefn->format.video.xFramerate >> 16) > 0 && + (portDefn->format.video.xFramerate >> 16) <= MAX_SUPPORTED_FPS) { + // Frame rate only should be set if this is a "known value" or to + // activate ts prediction logic (arbitrary mode only) sending input + // timestamps with max value (LLONG_MAX). + DEBUG_PRINT_HIGH("set_parameter: frame rate set by omx client : %lu", + portDefn->format.video.xFramerate >> 16); + Q16ToFraction(portDefn->format.video.xFramerate, drv_ctx.frame_rate.fps_numerator, + drv_ctx.frame_rate.fps_denominator); + if (!drv_ctx.frame_rate.fps_numerator) { + DEBUG_PRINT_ERROR("Numerator is zero setting to 30"); + drv_ctx.frame_rate.fps_numerator = 30; + } + if (drv_ctx.frame_rate.fps_denominator) + drv_ctx.frame_rate.fps_numerator = (int) + drv_ctx.frame_rate.fps_numerator / drv_ctx.frame_rate.fps_denominator; + drv_ctx.frame_rate.fps_denominator = 1; + frm_int = drv_ctx.frame_rate.fps_denominator * 1e6 / + drv_ctx.frame_rate.fps_numerator; + DEBUG_PRINT_LOW("set_parameter: frm_int(%u) fps(%.2f)", + frm_int, drv_ctx.frame_rate.fps_numerator / + (float)drv_ctx.frame_rate.fps_denominator); + } + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition IP port"); + if (drv_ctx.video_resolution.frame_height != + portDefn->format.video.nFrameHeight || + drv_ctx.video_resolution.frame_width != + portDefn->format.video.nFrameWidth) { + DEBUG_PRINT_LOW("SetParam IP: WxH(%d x %d)", + portDefn->format.video.nFrameWidth, + portDefn->format.video.nFrameHeight); + if (portDefn->format.video.nFrameHeight != 0x0 && + portDefn->format.video.nFrameWidth != 0x0) { + update_resolution(portDefn->format.video.nFrameWidth, + portDefn->format.video.nFrameHeight); + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = output_capability; + DEBUG_PRINT_LOW("fmt.fmt.pix_mp.height = %d , fmt.fmt.pix_mp.width = %d",fmt.fmt.pix_mp.height,fmt.fmt.pix_mp.width); + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + DEBUG_PRINT_ERROR("Set Resolution failed"); + eRet = OMX_ErrorUnsupportedSetting; + } else + eRet = get_buffer_req(&drv_ctx.op_buf); + } + } else if (portDefn->nBufferCountActual >= drv_ctx.ip_buf.mincount + || portDefn->nBufferSize != drv_ctx.ip_buf.buffer_size) { + vdec_allocatorproperty *buffer_prop = &drv_ctx.ip_buf; + drv_ctx.ip_buf.actualcount = portDefn->nBufferCountActual; + drv_ctx.ip_buf.buffer_size = (portDefn->nBufferSize + buffer_prop->alignment - 1) & + (~(buffer_prop->alignment - 1)); + eRet = set_buffer_req(buffer_prop); + } else { + DEBUG_PRINT_ERROR("ERROR: IP Requirements(#%d: %u) Requested(#%lu: %lu)", + drv_ctx.ip_buf.mincount, drv_ctx.ip_buf.buffer_size, + portDefn->nBufferCountActual, portDefn->nBufferSize); + eRet = OMX_ErrorBadParameter; + } + } else if (portDefn->eDir == OMX_DirMax) { + DEBUG_PRINT_ERROR(" Set_parameter: Bad Port idx %d", + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + } + break; + case OMX_IndexParamVideoPortFormat: + { + OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; + int ret=0; + struct v4l2_format fmt; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoPortFormat %d", + portFmt->eColorFormat); + + if (1 == portFmt->nPortIndex) { + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = capture_capability; + enum vdec_output_fromat op_format; + if ((portFmt->eColorFormat == (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m) || + (portFmt->eColorFormat == OMX_COLOR_FormatYUV420Planar)) + op_format = (enum vdec_output_fromat)VDEC_YUV_FORMAT_NV12; + else if (portFmt->eColorFormat == + (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka) + op_format = VDEC_YUV_FORMAT_TILE_4x2; + else + eRet = OMX_ErrorBadParameter; + + if (eRet == OMX_ErrorNone) { + drv_ctx.output_format = op_format; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + DEBUG_PRINT_ERROR("Set output format failed"); + eRet = OMX_ErrorUnsupportedSetting; + /*TODO: How to handle this case */ + } else { + eRet = get_buffer_req(&drv_ctx.op_buf); + } + } + if (eRet == OMX_ErrorNone) { + if (!client_buffers.set_color_format(portFmt->eColorFormat)) { + DEBUG_PRINT_ERROR("Set color format failed"); + eRet = OMX_ErrorBadParameter; + } + } + } + } + break; + + case OMX_QcomIndexPortDefn: + { + OMX_QCOM_PARAM_PORTDEFINITIONTYPE *portFmt = + (OMX_QCOM_PARAM_PORTDEFINITIONTYPE *) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexQcomParamPortDefinitionType %d", + portFmt->nFramePackingFormat); + + /* Input port */ + if (portFmt->nPortIndex == 0) { + if (portFmt->nFramePackingFormat == OMX_QCOM_FramePacking_Arbitrary) { + if (secure_mode) { + arbitrary_bytes = false; + DEBUG_PRINT_ERROR("setparameter: cannot set to arbitary bytes mode in secure session"); + eRet = OMX_ErrorUnsupportedSetting; + } else { + arbitrary_bytes = true; + } + } else if (portFmt->nFramePackingFormat == + OMX_QCOM_FramePacking_OnlyOneCompleteFrame) { + arbitrary_bytes = false; + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown FramePacking format %lu", + portFmt->nFramePackingFormat); + eRet = OMX_ErrorUnsupportedSetting; + } + } else if (portFmt->nPortIndex == OMX_CORE_OUTPUT_PORT_INDEX) { + DEBUG_PRINT_HIGH("set_parameter: OMX_IndexQcomParamPortDefinitionType OP Port"); + if ( (portFmt->nMemRegion > OMX_QCOM_MemRegionInvalid && + portFmt->nMemRegion < OMX_QCOM_MemRegionMax) && + portFmt->nCacheAttr == OMX_QCOM_CacheAttrNone) { + m_out_mem_region_smi = OMX_TRUE; + if ((m_out_mem_region_smi && m_out_pvt_entry_pmem)) { + DEBUG_PRINT_HIGH("set_parameter: OMX_IndexQcomParamPortDefinitionType OP Port: out pmem set"); + m_use_output_pmem = OMX_TRUE; + } + } + } + } + break; + + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *comp_role; + comp_role = (OMX_PARAM_COMPONENTROLETYPE *) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamStandardComponentRole %s", + comp_role->cRole); + + if ((m_state == OMX_StateLoaded)&& + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) { + DEBUG_PRINT_LOW("Set Parameter called in valid state"); + } else { + DEBUG_PRINT_ERROR("Set Parameter called in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + + if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((char*)comp_role->cRole,"video_decoder.avc",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_decoder.avc",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((char*)comp_role->cRole,"video_decoder.hevc",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_decoder.hevc",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole,"video_decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet = OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole,"video_decoder.h263",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_decoder.h263",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg2",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole,"video_decoder.mpeg2",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_decoder.mpeg2",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet = OMX_ErrorUnsupportedSetting; + } + } else if ((!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx",OMX_MAX_STRINGNAME_SIZE)) || + (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx311",OMX_MAX_STRINGNAME_SIZE)) + ) { + if (!strncmp((const char*)comp_role->cRole,"video_decoder.divx",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_decoder.divx",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } else if ( (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vc1",OMX_MAX_STRINGNAME_SIZE)) || + (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.wmv",OMX_MAX_STRINGNAME_SIZE)) + ) { + if (!strncmp((const char*)comp_role->cRole,"video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole,"video_decoder.vp8",OMX_MAX_STRINGNAME_SIZE) || + (!strncmp((const char*)comp_role->cRole,"video_decoder.vpx",OMX_MAX_STRINGNAME_SIZE))) { + strlcpy((char*)m_cRole,"video_decoder.vp8",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet = OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown param %s", drv_ctx.kind); + eRet = OMX_ErrorInvalidComponentName; + } + break; + } + + case OMX_IndexParamPriorityMgmt: + { + if (m_state != OMX_StateLoaded) { + DEBUG_PRINT_ERROR("Set Parameter called in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + OMX_PRIORITYMGMTTYPE *priorityMgmtype = (OMX_PRIORITYMGMTTYPE*) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPriorityMgmt %d", + priorityMgmtype->nGroupID); + + DEBUG_PRINT_LOW("set_parameter: priorityMgmtype %d", + priorityMgmtype->nGroupPriority); + + m_priority_mgm.nGroupID = priorityMgmtype->nGroupID; + m_priority_mgm.nGroupPriority = priorityMgmtype->nGroupPriority; + + break; + } + + case OMX_IndexParamCompBufferSupplier: + { + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamCompBufferSupplier %d", + bufferSupplierType->eBufferSupplier); + if (bufferSupplierType->nPortIndex == 0 || bufferSupplierType->nPortIndex ==1) + m_buffer_supplier.eBufferSupplier = bufferSupplierType->eBufferSupplier; + + else + + eRet = OMX_ErrorBadPortIndex; + + break; + + } + case OMX_IndexParamVideoAvc: + { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoAvc %d", + paramIndex); + break; + } + case OMX_IndexParamVideoH263: + { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoH263 %d", + paramIndex); + break; + } + case OMX_IndexParamVideoMpeg4: + { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoMpeg4 %d", + paramIndex); + break; + } + case OMX_IndexParamVideoMpeg2: + { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoMpeg2 %d", + paramIndex); + break; + } + case OMX_QcomIndexParamVideoDecoderPictureOrder: + { + QOMX_VIDEO_DECODER_PICTURE_ORDER *pictureOrder = + (QOMX_VIDEO_DECODER_PICTURE_ORDER *)paramData; + struct v4l2_control control; + int pic_order,rc=0; + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexParamVideoDecoderPictureOrder %d", + pictureOrder->eOutputPictureOrder); + if (pictureOrder->eOutputPictureOrder == QOMX_VIDEO_DISPLAY_ORDER) { + pic_order = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY; + } else if (pictureOrder->eOutputPictureOrder == QOMX_VIDEO_DECODE_ORDER) { + pic_order = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE; + time_stamp_dts.set_timestamp_reorder_mode(false); + } else + eRet = OMX_ErrorBadParameter; + if (eRet == OMX_ErrorNone) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER; + control.value = pic_order; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Set picture order failed"); + eRet = OMX_ErrorUnsupportedSetting; + } + } + break; + } + case OMX_QcomIndexParamConcealMBMapExtraData: + if (!secure_mode) + eRet = enable_extradata(VDEC_EXTRADATA_MB_ERROR_MAP, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + else { + DEBUG_PRINT_ERROR("secure mode setting not supported"); + eRet = OMX_ErrorUnsupportedSetting; + } + break; + case OMX_QcomIndexParamFrameInfoExtraData: + { + if (!secure_mode) + eRet = enable_extradata(OMX_FRAMEINFO_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + else { + DEBUG_PRINT_ERROR("secure mode setting not supported"); + eRet = OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QcomIndexParamInterlaceExtraData: + if (!secure_mode) + eRet = enable_extradata(OMX_INTERLACE_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + else { + DEBUG_PRINT_ERROR("secure mode setting not supported"); + eRet = OMX_ErrorUnsupportedSetting; + } + break; + case OMX_QcomIndexParamH264TimeInfo: + if (!secure_mode) + eRet = enable_extradata(OMX_TIMEINFO_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + else { + DEBUG_PRINT_ERROR("secure mode setting not supported"); + eRet = OMX_ErrorUnsupportedSetting; + } + break; + case OMX_QcomIndexParamVideoDivx: + { + QOMX_VIDEO_PARAM_DIVXTYPE* divXType = (QOMX_VIDEO_PARAM_DIVXTYPE *) paramData; + } + break; + case OMX_QcomIndexPlatformPvt: + { + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexPlatformPvt OP Port"); + OMX_QCOM_PLATFORMPRIVATE_EXTN* entryType = (OMX_QCOM_PLATFORMPRIVATE_EXTN *) paramData; + if (entryType->type != OMX_QCOM_PLATFORM_PRIVATE_PMEM) { + DEBUG_PRINT_HIGH("set_parameter: Platform Private entry type (%d) not supported.", entryType->type); + eRet = OMX_ErrorUnsupportedSetting; + } else { + m_out_pvt_entry_pmem = OMX_TRUE; + if ((m_out_mem_region_smi && m_out_pvt_entry_pmem)) { + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexPlatformPvt OP Port: out pmem set"); + m_use_output_pmem = OMX_TRUE; + } + } + + } + break; + case OMX_QcomIndexParamVideoSyncFrameDecodingMode: + { + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexParamVideoSyncFrameDecodingMode"); + DEBUG_PRINT_HIGH("set idr only decoding for thumbnail mode"); + struct v4l2_control control; + int rc; + drv_ctx.idr_only_decoding = 1; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER; + control.value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Set picture order failed"); + eRet = OMX_ErrorUnsupportedSetting; + } else { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE; + control.value = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Sync frame setting failed"); + eRet = OMX_ErrorUnsupportedSetting; + } + } + } + break; + + case OMX_QcomIndexParamIndexExtraDataType: + { + if (!secure_mode) { + QOMX_INDEXEXTRADATATYPE *extradataIndexType = (QOMX_INDEXEXTRADATATYPE *) paramData; + if ((extradataIndexType->nIndex == OMX_IndexParamPortDefinition) && + (extradataIndexType->bEnabled == OMX_TRUE) && + (extradataIndexType->nPortIndex == 1)) { + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexParamIndexExtraDataType SmoothStreaming"); + eRet = enable_extradata(OMX_PORTDEF_EXTRADATA, false, extradataIndexType->bEnabled); + + } + } + } + break; + case OMX_QcomIndexParamEnableSmoothStreaming: + { + struct v4l2_control control; + struct v4l2_format fmt; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER; + control.value = 1; + int rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL,&control); + if (rc < 0) { + DEBUG_PRINT_ERROR("Failed to enable Smooth Streaming on driver."); + eRet = OMX_ErrorHardware; + } + } + break; +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) + /* Need to allow following two set_parameters even in Idle + * state. This is ANDROID architecture which is not in sync + * with openmax standard. */ + case OMX_GoogleAndroidIndexEnableAndroidNativeBuffers: + { + EnableAndroidNativeBuffersParams* enableNativeBuffers = (EnableAndroidNativeBuffersParams *) paramData; + if (enableNativeBuffers) { + m_enable_android_native_buffers = enableNativeBuffers->enable; + } + } + break; + case OMX_GoogleAndroidIndexUseAndroidNativeBuffer: + { + eRet = use_android_native_buffer(hComp, paramData); + } + break; +#endif + case OMX_QcomIndexParamEnableTimeStampReorder: + { + QOMX_INDEXTIMESTAMPREORDER *reorder = (QOMX_INDEXTIMESTAMPREORDER *)paramData; + if (drv_ctx.picture_order == (vdec_output_order)QOMX_VIDEO_DISPLAY_ORDER) { + if (reorder->bEnable == OMX_TRUE) { + frm_int =0; + time_stamp_dts.set_timestamp_reorder_mode(true); + } else + time_stamp_dts.set_timestamp_reorder_mode(false); + } else { + time_stamp_dts.set_timestamp_reorder_mode(false); + if (reorder->bEnable == OMX_TRUE) { + eRet = OMX_ErrorUnsupportedSetting; + } + } + } + break; + default: + { + DEBUG_PRINT_ERROR("Setparameter: unknown param %d", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + } + } + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::GetConfig + + DESCRIPTION + OMX Get Config Method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_INOUT OMX_PTR configData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Get Config in Invalid State"); + return OMX_ErrorInvalidState; + } + + switch ((unsigned long)configIndex) { + case OMX_QcomIndexConfigInterlaced: + { + OMX_QCOM_CONFIG_INTERLACETYPE *configFmt = + (OMX_QCOM_CONFIG_INTERLACETYPE *) configData; + if (configFmt->nPortIndex == 1) { + if (configFmt->nIndex == 0) { + configFmt->eInterlaceType = OMX_QCOM_InterlaceFrameProgressive; + } else if (configFmt->nIndex == 1) { + configFmt->eInterlaceType = + OMX_QCOM_InterlaceInterleaveFrameTopFieldFirst; + } else if (configFmt->nIndex == 2) { + configFmt->eInterlaceType = + OMX_QCOM_InterlaceInterleaveFrameBottomFieldFirst; + } else { + DEBUG_PRINT_ERROR("get_config: OMX_QcomIndexConfigInterlaced:" + " NoMore Interlaced formats"); + eRet = OMX_ErrorNoMore; + } + + } else { + DEBUG_PRINT_ERROR("get_config: Bad port index %d queried on only o/p port", + (int)configFmt->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_QcomIndexQueryNumberOfVideoDecInstance: + { + QOMX_VIDEO_QUERY_DECODER_INSTANCES *decoderinstances = + (QOMX_VIDEO_QUERY_DECODER_INSTANCES*)configData; + decoderinstances->nNumOfInstances = 16; + /*TODO: How to handle this case */ + break; + } + case OMX_QcomIndexConfigVideoFramePackingArrangement: + { + if (drv_ctx.decoder_format == VDEC_CODECTYPE_H264) { + OMX_QCOM_FRAME_PACK_ARRANGEMENT *configFmt = + (OMX_QCOM_FRAME_PACK_ARRANGEMENT *) configData; + h264_parser->get_frame_pack_data(configFmt); + } else { + DEBUG_PRINT_ERROR("get_config: Framepack data not supported for non H264 codecs"); + } + break; + } + case OMX_IndexConfigCommonOutputCrop: + { + OMX_CONFIG_RECTTYPE *rect = (OMX_CONFIG_RECTTYPE *) configData; + memcpy(rect, &rectangle, sizeof(OMX_CONFIG_RECTTYPE)); + break; + } + default: + { + DEBUG_PRINT_ERROR("get_config: unknown param %d",configIndex); + eRet = OMX_ErrorBadParameter; + } + + } + + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::SetConfig + + DESCRIPTION + OMX Set Config method implementation + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if successful. + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::set_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_IN OMX_PTR configData) +{ + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Get Config in Invalid State"); + return OMX_ErrorInvalidState; + } + + OMX_ERRORTYPE ret = OMX_ErrorNone; + OMX_VIDEO_CONFIG_NALSIZE *pNal; + + DEBUG_PRINT_LOW("Set Config Called"); + + if (m_state == OMX_StateExecuting) { + DEBUG_PRINT_ERROR("set_config:Ignore in Exe state"); + return ret; + } + + if (configIndex == (OMX_INDEXTYPE)OMX_IndexVendorVideoExtraData) { + OMX_VENDOR_EXTRADATATYPE *config = (OMX_VENDOR_EXTRADATATYPE *) configData; + DEBUG_PRINT_LOW("Index OMX_IndexVendorVideoExtraData called"); + if (!strcmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc")) { + DEBUG_PRINT_LOW("Index OMX_IndexVendorVideoExtraData AVC"); + OMX_U32 extra_size; + // Parsing done here for the AVC atom is definitely not generic + // Currently this piece of code is working, but certainly + // not tested with all .mp4 files. + // Incase of failure, we might need to revisit this + // for a generic piece of code. + + // Retrieve size of NAL length field + // byte #4 contains the size of NAL lenght field + nal_length = (config->pData[4] & 0x03) + 1; + + extra_size = 0; + if (nal_length > 2) { + /* Presently we assume that only one SPS and one PPS in AvC1 Atom */ + extra_size = (nal_length - 2) * 2; + } + + // SPS starts from byte #6 + OMX_U8 *pSrcBuf = (OMX_U8 *) (&config->pData[6]); + OMX_U8 *pDestBuf; + m_vendor_config.nPortIndex = config->nPortIndex; + + // minus 6 --> SPS starts from byte #6 + // minus 1 --> picture param set byte to be ignored from avcatom + m_vendor_config.nDataSize = config->nDataSize - 6 - 1 + extra_size; + m_vendor_config.pData = (OMX_U8 *) malloc(m_vendor_config.nDataSize); + OMX_U32 len; + OMX_U8 index = 0; + // case where SPS+PPS is sent as part of set_config + pDestBuf = m_vendor_config.pData; + + DEBUG_PRINT_LOW("Rxd SPS+PPS nPortIndex[%d] len[%d] data[0x%x]", + m_vendor_config.nPortIndex, + m_vendor_config.nDataSize, + m_vendor_config.pData); + while (index < 2) { + uint8 *psize; + len = *pSrcBuf; + len = len << 8; + len |= *(pSrcBuf + 1); + psize = (uint8 *) & len; + memcpy(pDestBuf + nal_length, pSrcBuf + 2,len); + for (unsigned int i = 0; i < nal_length; i++) { + pDestBuf[i] = psize[nal_length - 1 - i]; + } + //memcpy(pDestBuf,pSrcBuf,(len+2)); + pDestBuf += len + nal_length; + pSrcBuf += len + 2; + index++; + pSrcBuf++; // skip picture param set + len = 0; + } + } else if (!strcmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg4") || + !strcmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg2")) { + m_vendor_config.nPortIndex = config->nPortIndex; + m_vendor_config.nDataSize = config->nDataSize; + m_vendor_config.pData = (OMX_U8 *) malloc((config->nDataSize)); + memcpy(m_vendor_config.pData, config->pData,config->nDataSize); + } else if (!strcmp(drv_ctx.kind, "OMX.qcom.video.decoder.vc1")) { + if (m_vendor_config.pData) { + free(m_vendor_config.pData); + m_vendor_config.pData = NULL; + m_vendor_config.nDataSize = 0; + } + + if (((*((OMX_U32 *) config->pData)) & + VC1_SP_MP_START_CODE_MASK) == + VC1_SP_MP_START_CODE) { + DEBUG_PRINT_LOW("set_config - VC1 simple/main profile"); + m_vendor_config.nPortIndex = config->nPortIndex; + m_vendor_config.nDataSize = config->nDataSize; + m_vendor_config.pData = + (OMX_U8 *) malloc(config->nDataSize); + memcpy(m_vendor_config.pData, config->pData, + config->nDataSize); + m_vc1_profile = VC1_SP_MP_RCV; + } else if (*((OMX_U32 *) config->pData) == VC1_AP_SEQ_START_CODE) { + DEBUG_PRINT_LOW("set_config - VC1 Advance profile"); + m_vendor_config.nPortIndex = config->nPortIndex; + m_vendor_config.nDataSize = config->nDataSize; + m_vendor_config.pData = + (OMX_U8 *) malloc((config->nDataSize)); + memcpy(m_vendor_config.pData, config->pData, + config->nDataSize); + m_vc1_profile = VC1_AP; + } else if ((config->nDataSize == VC1_STRUCT_C_LEN)) { + DEBUG_PRINT_LOW("set_config - VC1 Simple/Main profile struct C only"); + m_vendor_config.nPortIndex = config->nPortIndex; + m_vendor_config.nDataSize = config->nDataSize; + m_vendor_config.pData = (OMX_U8*)malloc(config->nDataSize); + memcpy(m_vendor_config.pData,config->pData,config->nDataSize); + m_vc1_profile = VC1_SP_MP_RCV; + } else { + DEBUG_PRINT_LOW("set_config - Error: Unknown VC1 profile"); + } + } + return ret; + } else if (configIndex == OMX_IndexConfigVideoNalSize) { + + pNal = reinterpret_cast < OMX_VIDEO_CONFIG_NALSIZE * >(configData); + nal_length = pNal->nNaluBytes; + m_frame_parser.init_nal_length(nal_length); + DEBUG_PRINT_LOW("OMX_IndexConfigVideoNalSize called with Size %d",nal_length); + return ret; + } + + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== + FUNCTION + omx_vdec::GetExtensionIndex + + DESCRIPTION + OMX GetExtensionIndex method implementaion. <TBD> + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_extension_index(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_STRING paramName, + OMX_OUT OMX_INDEXTYPE* indexType) +{ + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Get Extension Index in Invalid State"); + return OMX_ErrorInvalidState; + } else if (!strncmp(paramName, "OMX.QCOM.index.param.video.SyncFrameDecodingMode",sizeof("OMX.QCOM.index.param.video.SyncFrameDecodingMode") - 1)) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoSyncFrameDecodingMode; + } else if (!strncmp(paramName, "OMX.QCOM.index.param.IndexExtraData",sizeof("OMX.QCOM.index.param.IndexExtraData") - 1)) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamIndexExtraDataType; + } +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) + else if (!strncmp(paramName,"OMX.google.android.index.enableAndroidNativeBuffers", sizeof("OMX.google.android.index.enableAndroidNativeBuffers") - 1)) { + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexEnableAndroidNativeBuffers; + } else if (!strncmp(paramName,"OMX.google.android.index.useAndroidNativeBuffer2", sizeof("OMX.google.android.index.enableAndroidNativeBuffer2") - 1)) { + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexUseAndroidNativeBuffer2; + } else if (!strncmp(paramName,"OMX.google.android.index.useAndroidNativeBuffer", sizeof("OMX.google.android.index.enableAndroidNativeBuffer") - 1)) { + DEBUG_PRINT_ERROR("Extension: %s is supported", paramName); + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexUseAndroidNativeBuffer; + } else if (!strncmp(paramName,"OMX.google.android.index.getAndroidNativeBufferUsage", sizeof("OMX.google.android.index.getAndroidNativeBufferUsage") - 1)) { + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage; + } +#endif + else { + DEBUG_PRINT_ERROR("Extension: %s not implemented", paramName); + return OMX_ErrorNotImplemented; + } + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::GetState + + DESCRIPTION + Returns the state information back to the caller.<TBD> + + PARAMETERS + <TBD>. + + RETURN VALUE + Error None if everything is successful. + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_state(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STATETYPE* state) +{ + *state = m_state; + DEBUG_PRINT_LOW("get_state: Returning the state %d",*state); + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::ComponentTunnelRequest + + DESCRIPTION + OMX Component Tunnel Request method implementation. <TBD> + + PARAMETERS + None. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::component_tunnel_request(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_HANDLETYPE peerComponent, + OMX_IN OMX_U32 peerPort, + OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup) +{ + DEBUG_PRINT_ERROR("Error: component_tunnel_request Not Implemented"); + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== + FUNCTION + omx_vdec::UseOutputBuffer + + DESCRIPTION + Helper function for Use buffer in the input pin + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::allocate_extradata() +{ +#ifdef USE_ION + if (drv_ctx.extradata_info.buffer_size) { + if (drv_ctx.extradata_info.ion.ion_alloc_data.handle) { + munmap((void *)drv_ctx.extradata_info.uaddr, drv_ctx.extradata_info.size); + close(drv_ctx.extradata_info.ion.fd_ion_data.fd); + free_ion_memory(&drv_ctx.extradata_info.ion); + } + drv_ctx.extradata_info.size = (drv_ctx.extradata_info.size + 4095) & (~4095); + DEBUG_PRINT_HIGH("allocate extradata memory size %d", drv_ctx.extradata_info.size); + drv_ctx.extradata_info.ion.ion_device_fd = alloc_map_ion_memory( + drv_ctx.extradata_info.size, 4096, + &drv_ctx.extradata_info.ion.ion_alloc_data, + &drv_ctx.extradata_info.ion.fd_ion_data, 0); + if (drv_ctx.extradata_info.ion.ion_device_fd < 0) { + DEBUG_PRINT_ERROR("Failed to alloc extradata memory"); + return OMX_ErrorInsufficientResources; + } + drv_ctx.extradata_info.uaddr = (char *)mmap(NULL, + drv_ctx.extradata_info.size, + PROT_READ|PROT_WRITE, MAP_SHARED, + drv_ctx.extradata_info.ion.fd_ion_data.fd , 0); + if (drv_ctx.extradata_info.uaddr == MAP_FAILED) { + DEBUG_PRINT_ERROR("Failed to map extradata memory"); + close(drv_ctx.extradata_info.ion.fd_ion_data.fd); + free_ion_memory(&drv_ctx.extradata_info.ion); + return OMX_ErrorInsufficientResources; + } + memset(drv_ctx.extradata_info.uaddr, 0, drv_ctx.extradata_info.size); + } +#endif + return OMX_ErrorNone; +} + +void omx_vdec::free_extradata() +{ +#ifdef USE_ION + if (drv_ctx.extradata_info.uaddr) { + munmap((void *)drv_ctx.extradata_info.uaddr, drv_ctx.extradata_info.size); + close(drv_ctx.extradata_info.ion.fd_ion_data.fd); + free_ion_memory(&drv_ctx.extradata_info.ion); + } + memset(&drv_ctx.extradata_info, 0, sizeof(drv_ctx.extradata_info)); +#endif +} + +OMX_ERRORTYPE omx_vdec::use_output_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr= NULL; // buffer header + unsigned i= 0; // Temporary counter + struct vdec_setbuffer_cmd setbuffers; + OMX_PTR privateAppData = NULL; + private_handle_t *handle = NULL; + OMX_U8 *buff = buffer; + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + int extra_idx = 0; + + if (!m_out_mem_ptr) { + DEBUG_PRINT_HIGH("Use_op_buf:Allocating output headers"); + eRet = allocate_output_headers(); + if (eRet == OMX_ErrorNone) + eRet = allocate_extradata(); + } + + if (eRet == OMX_ErrorNone) { + for (i=0; i< drv_ctx.op_buf.actualcount; i++) { + if (BITMASK_ABSENT(&m_out_bm_count,i)) { + break; + } + } + } + + if (i >= drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("Already using %d o/p buffers", drv_ctx.op_buf.actualcount); + eRet = OMX_ErrorInsufficientResources; + } + + if (eRet == OMX_ErrorNone) { +#if defined(_ANDROID_HONEYCOMB_) || defined(_ANDROID_ICS_) + if (m_enable_android_native_buffers) { + if (m_use_android_native_buffers) { + UseAndroidNativeBufferParams *params = (UseAndroidNativeBufferParams *)appData; + sp<android_native_buffer_t> nBuf = params->nativeBuffer; + handle = (private_handle_t *)nBuf->handle; + privateAppData = params->pAppPrivate; + } else { + handle = (private_handle_t *)buff; + privateAppData = appData; + } + + if ((OMX_U32)handle->size < drv_ctx.op_buf.buffer_size) { + DEBUG_PRINT_ERROR("Insufficient sized buffer given for playback," + " expected %u, got %lu", + drv_ctx.op_buf.buffer_size, (OMX_U32)handle->size); + return OMX_ErrorBadParameter; + } + + drv_ctx.op_buf.buffer_size = (OMX_U32)handle->size; + if (!m_use_android_native_buffers) { + if (!secure_mode) { + buff = (OMX_U8*)mmap(0, handle->size, + PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0); + if (buff == MAP_FAILED) { + DEBUG_PRINT_ERROR("Failed to mmap pmem with fd = %d, size = %d", handle->fd, handle->size); + return OMX_ErrorInsufficientResources; + } + } + } +#if defined(_ANDROID_ICS_) + native_buffer[i].nativehandle = handle; + native_buffer[i].privatehandle = handle; +#endif + if (!handle) { + DEBUG_PRINT_ERROR("Native Buffer handle is NULL"); + return OMX_ErrorBadParameter; + } + drv_ctx.ptr_outputbuffer[i].pmem_fd = handle->fd; + drv_ctx.ptr_outputbuffer[i].offset = 0; + drv_ctx.ptr_outputbuffer[i].bufferaddr = buff; + drv_ctx.ptr_outputbuffer[i].mmaped_size = + drv_ctx.ptr_outputbuffer[i].buffer_len = drv_ctx.op_buf.buffer_size; + } else +#endif + + if (!ouput_egl_buffers && !m_use_output_pmem) { +#ifdef USE_ION + DEBUG_PRINT_HIGH("allocate output buffer memory size %d", drv_ctx.op_buf.buffer_size); + drv_ctx.op_buf_ion_info[i].ion_device_fd = alloc_map_ion_memory( + drv_ctx.op_buf.buffer_size,drv_ctx.op_buf.alignment, + &drv_ctx.op_buf_ion_info[i].ion_alloc_data, + &drv_ctx.op_buf_ion_info[i].fd_ion_data, secure_mode ? ION_SECURE : 0); + if (drv_ctx.op_buf_ion_info[i].ion_device_fd < 0) { + DEBUG_PRINT_ERROR("ION device fd is bad %d", drv_ctx.op_buf_ion_info[i].ion_device_fd); + return OMX_ErrorInsufficientResources; + } + drv_ctx.ptr_outputbuffer[i].pmem_fd = \ + drv_ctx.op_buf_ion_info[i].fd_ion_data.fd; +#else + drv_ctx.ptr_outputbuffer[i].pmem_fd = \ + open (MEM_DEVICE,O_RDWR); + + if (drv_ctx.ptr_outputbuffer[i].pmem_fd < 0) { + DEBUG_PRINT_ERROR("ION/pmem buffer fd is bad %d", drv_ctx.ptr_outputbuffer[i].pmem_fd); + return OMX_ErrorInsufficientResources; + } + + /* FIXME: why is this code even here? We already open MEM_DEVICE a few lines above */ + if (drv_ctx.ptr_outputbuffer[i].pmem_fd == 0) { + drv_ctx.ptr_outputbuffer[i].pmem_fd = \ + open (MEM_DEVICE,O_RDWR); + if (drv_ctx.ptr_outputbuffer[i].pmem_fd < 0) { + DEBUG_PRINT_ERROR("ION/pmem buffer fd is bad %d", drv_ctx.ptr_outputbuffer[i].pmem_fd); + return OMX_ErrorInsufficientResources; + } + } + + if (!align_pmem_buffers(drv_ctx.ptr_outputbuffer[i].pmem_fd, + drv_ctx.op_buf.buffer_size, + drv_ctx.op_buf.alignment)) { + DEBUG_PRINT_ERROR("align_pmem_buffers() failed"); + close(drv_ctx.ptr_outputbuffer[i].pmem_fd); + return OMX_ErrorInsufficientResources; + } +#endif + if (!secure_mode) { + drv_ctx.ptr_outputbuffer[i].bufferaddr = + (unsigned char *)mmap(NULL, drv_ctx.op_buf.buffer_size, + PROT_READ|PROT_WRITE, MAP_SHARED, + drv_ctx.ptr_outputbuffer[i].pmem_fd,0); + if (drv_ctx.ptr_outputbuffer[i].bufferaddr == MAP_FAILED) { + close(drv_ctx.ptr_outputbuffer[i].pmem_fd); +#ifdef USE_ION + free_ion_memory(&drv_ctx.op_buf_ion_info[i]); +#endif + DEBUG_PRINT_ERROR("Unable to mmap output buffer"); + return OMX_ErrorInsufficientResources; + } + } + drv_ctx.ptr_outputbuffer[i].offset = 0; + privateAppData = appData; + } else { + + DEBUG_PRINT_HIGH("Use_op_buf: out_pmem=%d",m_use_output_pmem); + if (!appData || !bytes ) { + if (!secure_mode && !buffer) { + DEBUG_PRINT_ERROR("Bad parameters for use buffer in EGL image case"); + return OMX_ErrorBadParameter; + } + } + + OMX_QCOM_PLATFORM_PRIVATE_LIST *pmem_list; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pmem_info; + pmem_list = (OMX_QCOM_PLATFORM_PRIVATE_LIST*) appData; + if (!pmem_list->entryList || !pmem_list->entryList->entry || + !pmem_list->nEntries || + pmem_list->entryList->type != OMX_QCOM_PLATFORM_PRIVATE_PMEM) { + DEBUG_PRINT_ERROR("Pmem info not valid in use buffer"); + return OMX_ErrorBadParameter; + } + pmem_info = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) + pmem_list->entryList->entry; + DEBUG_PRINT_LOW("vdec: use buf: pmem_fd=0x%x", + pmem_info->pmem_fd); + drv_ctx.ptr_outputbuffer[i].pmem_fd = pmem_info->pmem_fd; + drv_ctx.ptr_outputbuffer[i].offset = pmem_info->offset; + drv_ctx.ptr_outputbuffer[i].bufferaddr = buff; + drv_ctx.ptr_outputbuffer[i].mmaped_size = + drv_ctx.ptr_outputbuffer[i].buffer_len = drv_ctx.op_buf.buffer_size; + privateAppData = appData; + } + m_pmem_info[i].offset = drv_ctx.ptr_outputbuffer[i].offset; + m_pmem_info[i].pmem_fd = drv_ctx.ptr_outputbuffer[i].pmem_fd; + + *bufferHdr = (m_out_mem_ptr + i ); + if (secure_mode) + drv_ctx.ptr_outputbuffer[i].bufferaddr = *bufferHdr; + //setbuffers.buffer_type = VDEC_BUFFER_TYPE_OUTPUT; + memcpy (&setbuffers.buffer,&drv_ctx.ptr_outputbuffer[i], + sizeof (vdec_bufferpayload)); + + DEBUG_PRINT_HIGH("Set the Output Buffer Idx: %d Addr: %p, pmem_fd=0x%x", i, + drv_ctx.ptr_outputbuffer[i].bufferaddr, + drv_ctx.ptr_outputbuffer[i].pmem_fd ); + + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].length = drv_ctx.op_buf.buffer_size; + plane[0].m.userptr = (unsigned long)drv_ctx.ptr_outputbuffer[i].bufferaddr - + (unsigned long)drv_ctx.ptr_outputbuffer[i].offset; + plane[0].reserved[0] = drv_ctx.ptr_outputbuffer[i].pmem_fd; + plane[0].reserved[1] = drv_ctx.ptr_outputbuffer[i].offset; + plane[0].data_offset = 0; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].length = drv_ctx.extradata_info.buffer_size; + plane[extra_idx].m.userptr = (long unsigned int) (drv_ctx.extradata_info.uaddr + i * drv_ctx.extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = drv_ctx.extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = i * drv_ctx.extradata_info.buffer_size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index is more than allowed: %d", extra_idx); + return OMX_ErrorBadParameter; + } + buf.m.planes = plane; + buf.length = drv_ctx.num_planes; + + DEBUG_PRINT_LOW("Set the Output Buffer Idx: %d Addr: %x", i, drv_ctx.ptr_outputbuffer[i]); + + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_PREPARE_BUF, &buf)) { + DEBUG_PRINT_ERROR("Failed to prepare bufs"); + /*TODO: How to handle this case */ + return OMX_ErrorInsufficientResources; + } + + if (i == (drv_ctx.op_buf.actualcount -1) && !streaming[CAPTURE_PORT]) { + enum v4l2_buf_type buf_type; + buf_type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type)) { + return OMX_ErrorInsufficientResources; + } else { + streaming[CAPTURE_PORT] = true; + DEBUG_PRINT_LOW("STREAMON Successful"); + } + } + + (*bufferHdr)->nAllocLen = drv_ctx.op_buf.buffer_size; + if (m_enable_android_native_buffers) { + DEBUG_PRINT_LOW("setting pBuffer to private_handle_t %p", handle); + (*bufferHdr)->pBuffer = (OMX_U8 *)handle; + } else { + (*bufferHdr)->pBuffer = buff; + } + (*bufferHdr)->pAppPrivate = privateAppData; + BITMASK_SET(&m_out_bm_count,i); + } + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::use_input_heap_buffers + + DESCRIPTION + OMX Use Buffer Heap allocation method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None , if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::use_input_heap_buffers( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + DEBUG_PRINT_LOW("Inside %s, %p", __FUNCTION__, buffer); + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (!m_inp_heap_ptr) + m_inp_heap_ptr = (OMX_BUFFERHEADERTYPE*) + calloc( (sizeof(OMX_BUFFERHEADERTYPE)), + drv_ctx.ip_buf.actualcount); + if (!m_phdr_pmem_ptr) + m_phdr_pmem_ptr = (OMX_BUFFERHEADERTYPE**) + calloc( (sizeof(OMX_BUFFERHEADERTYPE*)), + drv_ctx.ip_buf.actualcount); + if (!m_inp_heap_ptr || !m_phdr_pmem_ptr) { + DEBUG_PRINT_ERROR("Insufficent memory"); + eRet = OMX_ErrorInsufficientResources; + } else if (m_in_alloc_cnt < drv_ctx.ip_buf.actualcount) { + input_use_buffer = true; + memset(&m_inp_heap_ptr[m_in_alloc_cnt], 0, sizeof(OMX_BUFFERHEADERTYPE)); + m_inp_heap_ptr[m_in_alloc_cnt].pBuffer = buffer; + m_inp_heap_ptr[m_in_alloc_cnt].nAllocLen = bytes; + m_inp_heap_ptr[m_in_alloc_cnt].pAppPrivate = appData; + m_inp_heap_ptr[m_in_alloc_cnt].nInputPortIndex = (OMX_U32) OMX_DirInput; + m_inp_heap_ptr[m_in_alloc_cnt].nOutputPortIndex = (OMX_U32) OMX_DirMax; + *bufferHdr = &m_inp_heap_ptr[m_in_alloc_cnt]; + eRet = allocate_input_buffer(hComp, &m_phdr_pmem_ptr[m_in_alloc_cnt], port, appData, bytes); + DEBUG_PRINT_HIGH("Heap buffer(%p) Pmem buffer(%p)", *bufferHdr, m_phdr_pmem_ptr[m_in_alloc_cnt]); + if (!m_input_free_q.insert_entry((unsigned)m_phdr_pmem_ptr[m_in_alloc_cnt], + (unsigned)NULL, (unsigned)NULL)) { + DEBUG_PRINT_ERROR("ERROR:Free_q is full"); + return OMX_ErrorInsufficientResources; + } + m_in_alloc_cnt++; + } else { + DEBUG_PRINT_ERROR("All i/p buffers have been set!"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::UseBuffer + + DESCRIPTION + OMX Use Buffer method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None , if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::use_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE error = OMX_ErrorNone; + struct vdec_setbuffer_cmd setbuffers; + + if (bufferHdr == NULL || bytes == 0) { + if (!secure_mode && buffer == NULL) { + DEBUG_PRINT_ERROR("bad param 0x%p %ld 0x%p",bufferHdr, bytes, buffer); + return OMX_ErrorBadParameter; + } + } + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Use Buffer in Invalid State"); + return OMX_ErrorInvalidState; + } + if (port == OMX_CORE_INPUT_PORT_INDEX) + error = use_input_heap_buffers(hComp, bufferHdr, port, appData, bytes, buffer); + else if (port == OMX_CORE_OUTPUT_PORT_INDEX) + error = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer); //not tested + else { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d",(int)port); + error = OMX_ErrorBadPortIndex; + } + DEBUG_PRINT_LOW("Use Buffer: port %u, buffer %p, eRet %d", port, *bufferHdr, error); + if (error == OMX_ErrorNone) { + if (allocate_done() && BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) { + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_IDLE_PENDING); + post_event(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + } + if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated && + BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated && + BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + return error; +} + +OMX_ERRORTYPE omx_vdec::free_input_buffer(unsigned int bufferindex, + OMX_BUFFERHEADERTYPE *pmem_bufferHdr) +{ + if (m_inp_heap_ptr && !input_use_buffer && arbitrary_bytes) { + if (m_inp_heap_ptr[bufferindex].pBuffer) + free(m_inp_heap_ptr[bufferindex].pBuffer); + m_inp_heap_ptr[bufferindex].pBuffer = NULL; + } + if (pmem_bufferHdr) + free_input_buffer(pmem_bufferHdr); + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::free_input_buffer(OMX_BUFFERHEADERTYPE *bufferHdr) +{ + unsigned int index = 0; + if (bufferHdr == NULL || m_inp_mem_ptr == NULL) { + return OMX_ErrorBadParameter; + } + + index = bufferHdr - m_inp_mem_ptr; + DEBUG_PRINT_LOW("Free Input Buffer index = %d",index); + + if (index < drv_ctx.ip_buf.actualcount && drv_ctx.ptr_inputbuffer) { + DEBUG_PRINT_LOW("Free Input Buffer index = %d",index); + if (drv_ctx.ptr_inputbuffer[index].pmem_fd > 0) { + struct vdec_setbuffer_cmd setbuffers; + setbuffers.buffer_type = VDEC_BUFFER_TYPE_INPUT; + memcpy (&setbuffers.buffer,&drv_ctx.ptr_inputbuffer[index], + sizeof (vdec_bufferpayload)); + DEBUG_PRINT_LOW("unmap the input buffer fd=%d", + drv_ctx.ptr_inputbuffer[index].pmem_fd); + DEBUG_PRINT_LOW("unmap the input buffer size=%d address = %d", + drv_ctx.ptr_inputbuffer[index].mmaped_size, + drv_ctx.ptr_inputbuffer[index].bufferaddr); + munmap (drv_ctx.ptr_inputbuffer[index].bufferaddr, + drv_ctx.ptr_inputbuffer[index].mmaped_size); + close (drv_ctx.ptr_inputbuffer[index].pmem_fd); + drv_ctx.ptr_inputbuffer[index].pmem_fd = -1; + if (m_desc_buffer_ptr && m_desc_buffer_ptr[index].buf_addr) { + free(m_desc_buffer_ptr[index].buf_addr); + m_desc_buffer_ptr[index].buf_addr = NULL; + m_desc_buffer_ptr[index].desc_data_size = 0; + } +#ifdef USE_ION + free_ion_memory(&drv_ctx.ip_buf_ion_info[index]); +#endif + } + } + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::free_output_buffer(OMX_BUFFERHEADERTYPE *bufferHdr) +{ + unsigned int index = 0; + + if (bufferHdr == NULL || m_out_mem_ptr == NULL) { + return OMX_ErrorBadParameter; + } + + index = bufferHdr - m_out_mem_ptr; + DEBUG_PRINT_LOW("Free ouput Buffer index = %d",index); + + if (index < drv_ctx.op_buf.actualcount + && drv_ctx.ptr_outputbuffer) { + DEBUG_PRINT_LOW("Free ouput Buffer index = %d addr = %x", index, + drv_ctx.ptr_outputbuffer[index].bufferaddr); + + struct vdec_setbuffer_cmd setbuffers; + setbuffers.buffer_type = VDEC_BUFFER_TYPE_OUTPUT; + memcpy (&setbuffers.buffer,&drv_ctx.ptr_outputbuffer[index], + sizeof (vdec_bufferpayload)); +#ifdef _ANDROID_ + if (m_enable_android_native_buffers) { + if (drv_ctx.ptr_outputbuffer[index].pmem_fd > 0) { + munmap(drv_ctx.ptr_outputbuffer[index].bufferaddr, + drv_ctx.ptr_outputbuffer[index].mmaped_size); + } + drv_ctx.ptr_outputbuffer[index].pmem_fd = -1; + } else { +#endif + if (drv_ctx.ptr_outputbuffer[0].pmem_fd > 0 && !ouput_egl_buffers && !m_use_output_pmem) { + DEBUG_PRINT_LOW("unmap the output buffer fd = %d", + drv_ctx.ptr_outputbuffer[0].pmem_fd); + DEBUG_PRINT_LOW("unmap the ouput buffer size=%d address = %d", + drv_ctx.ptr_outputbuffer[0].mmaped_size * drv_ctx.op_buf.actualcount, + drv_ctx.ptr_outputbuffer[0].bufferaddr); + munmap (drv_ctx.ptr_outputbuffer[0].bufferaddr, + drv_ctx.ptr_outputbuffer[0].mmaped_size * drv_ctx.op_buf.actualcount); + close (drv_ctx.ptr_outputbuffer[0].pmem_fd); + drv_ctx.ptr_outputbuffer[0].pmem_fd = -1; +#ifdef USE_ION + free_ion_memory(&drv_ctx.op_buf_ion_info[0]); +#endif + } +#ifdef _ANDROID_ + } +#endif + if (release_output_done()) { + free_extradata(); + } + } + + return OMX_ErrorNone; + +} + +OMX_ERRORTYPE omx_vdec::allocate_input_heap_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes) +{ + OMX_BUFFERHEADERTYPE *input = NULL; + unsigned char *buf_addr = NULL; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned i = 0; + + /* Sanity Check*/ + if (bufferHdr == NULL) { + return OMX_ErrorBadParameter; + } + + if (m_inp_heap_ptr == NULL) { + m_inp_heap_ptr = (OMX_BUFFERHEADERTYPE*) \ + calloc( (sizeof(OMX_BUFFERHEADERTYPE)), + drv_ctx.ip_buf.actualcount); + m_phdr_pmem_ptr = (OMX_BUFFERHEADERTYPE**) \ + calloc( (sizeof(OMX_BUFFERHEADERTYPE*)), + drv_ctx.ip_buf.actualcount); + + if (m_inp_heap_ptr == NULL) { + DEBUG_PRINT_ERROR("m_inp_heap_ptr Allocation failed "); + return OMX_ErrorInsufficientResources; + } + } + + /*Find a Free index*/ + for (i=0; i< drv_ctx.ip_buf.actualcount; i++) { + if (BITMASK_ABSENT(&m_heap_inp_bm_count,i)) { + DEBUG_PRINT_LOW("Free Input Buffer Index %d",i); + break; + } + } + + if (i < drv_ctx.ip_buf.actualcount) { + buf_addr = (unsigned char *)malloc (drv_ctx.ip_buf.buffer_size); + + if (buf_addr == NULL) { + return OMX_ErrorInsufficientResources; + } + + *bufferHdr = (m_inp_heap_ptr + i); + input = *bufferHdr; + BITMASK_SET(&m_heap_inp_bm_count,i); + + input->pBuffer = (OMX_U8 *)buf_addr; + input->nSize = sizeof(OMX_BUFFERHEADERTYPE); + input->nVersion.nVersion = OMX_SPEC_VERSION; + input->nAllocLen = drv_ctx.ip_buf.buffer_size; + input->pAppPrivate = appData; + input->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + DEBUG_PRINT_LOW("Address of Heap Buffer %p",*bufferHdr ); + eRet = allocate_input_buffer(hComp,&m_phdr_pmem_ptr [i],port,appData,bytes); + DEBUG_PRINT_LOW("Address of Pmem Buffer %p",m_phdr_pmem_ptr[i]); + /*Add the Buffers to freeq*/ + if (!m_input_free_q.insert_entry((unsigned)m_phdr_pmem_ptr[i], + (unsigned)NULL, (unsigned)NULL)) { + DEBUG_PRINT_ERROR("ERROR:Free_q is full"); + return OMX_ErrorInsufficientResources; + } + } else { + return OMX_ErrorBadParameter; + } + + return eRet; + +} + + +/* ====================================================================== + FUNCTION + omx_vdec::AllocateInputBuffer + + DESCRIPTION + Helper function for allocate buffer in the input pin + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::allocate_input_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct vdec_setbuffer_cmd setbuffers; + OMX_BUFFERHEADERTYPE *input = NULL; + unsigned i = 0; + unsigned char *buf_addr = NULL; + int pmem_fd = -1; + + if (bytes != drv_ctx.ip_buf.buffer_size) { + DEBUG_PRINT_LOW("Requested Size is wrong %d epected is %d", + bytes, drv_ctx.ip_buf.buffer_size); + return OMX_ErrorBadParameter; + } + + if (!m_inp_mem_ptr) { + DEBUG_PRINT_HIGH("Allocate i/p buffer Header: Cnt(%d) Sz(%d)", + drv_ctx.ip_buf.actualcount, + drv_ctx.ip_buf.buffer_size); + + m_inp_mem_ptr = (OMX_BUFFERHEADERTYPE*) \ + calloc( (sizeof(OMX_BUFFERHEADERTYPE)), drv_ctx.ip_buf.actualcount); + + if (m_inp_mem_ptr == NULL) { + return OMX_ErrorInsufficientResources; + } + + drv_ctx.ptr_inputbuffer = (struct vdec_bufferpayload *) \ + calloc ((sizeof (struct vdec_bufferpayload)),drv_ctx.ip_buf.actualcount); + + if (drv_ctx.ptr_inputbuffer == NULL) { + return OMX_ErrorInsufficientResources; + } +#ifdef USE_ION + drv_ctx.ip_buf_ion_info = (struct vdec_ion *) \ + calloc ((sizeof (struct vdec_ion)),drv_ctx.ip_buf.actualcount); + + if (drv_ctx.ip_buf_ion_info == NULL) { + return OMX_ErrorInsufficientResources; + } +#endif + + for (i=0; i < drv_ctx.ip_buf.actualcount; i++) { + drv_ctx.ptr_inputbuffer [i].pmem_fd = -1; +#ifdef USE_ION + drv_ctx.ip_buf_ion_info[i].ion_device_fd = -1; +#endif + } + } + + for (i=0; i< drv_ctx.ip_buf.actualcount; i++) { + if (BITMASK_ABSENT(&m_inp_bm_count,i)) { + DEBUG_PRINT_LOW("Free Input Buffer Index %d",i); + break; + } + } + + if (i < drv_ctx.ip_buf.actualcount) { + struct v4l2_buffer buf; + struct v4l2_plane plane; + int rc; + +#ifdef USE_ION + DEBUG_PRINT_HIGH("Allocate input Buffer size %d", drv_ctx.ip_buf.buffer_size); + drv_ctx.ip_buf_ion_info[i].ion_device_fd = alloc_map_ion_memory( + drv_ctx.ip_buf.buffer_size,drv_ctx.op_buf.alignment, + &drv_ctx.ip_buf_ion_info[i].ion_alloc_data, + &drv_ctx.ip_buf_ion_info[i].fd_ion_data, secure_mode ? ION_SECURE : 0); + if (drv_ctx.ip_buf_ion_info[i].ion_device_fd < 0) { + return OMX_ErrorInsufficientResources; + } + pmem_fd = drv_ctx.ip_buf_ion_info[i].fd_ion_data.fd; +#else + pmem_fd = open (MEM_DEVICE,O_RDWR); + + if (pmem_fd < 0) { + DEBUG_PRINT_ERROR("open failed for pmem/adsp for input buffer"); + return OMX_ErrorInsufficientResources; + } + + if (pmem_fd == 0) { + pmem_fd = open (MEM_DEVICE,O_RDWR); + + if (pmem_fd < 0) { + DEBUG_PRINT_ERROR("open failed for pmem/adsp for input buffer"); + return OMX_ErrorInsufficientResources; + } + } + + if (!align_pmem_buffers(pmem_fd, drv_ctx.ip_buf.buffer_size, + drv_ctx.ip_buf.alignment)) { + DEBUG_PRINT_ERROR("align_pmem_buffers() failed"); + close(pmem_fd); + return OMX_ErrorInsufficientResources; + } +#endif + if (!secure_mode) { + buf_addr = (unsigned char *)mmap(NULL, + drv_ctx.ip_buf.buffer_size, + PROT_READ|PROT_WRITE, MAP_SHARED, pmem_fd, 0); + + if (buf_addr == MAP_FAILED) { + close(pmem_fd); +#ifdef USE_ION + free_ion_memory(&drv_ctx.ip_buf_ion_info[i]); +#endif + DEBUG_PRINT_ERROR("Map Failed to allocate input buffer"); + return OMX_ErrorInsufficientResources; + } + } + *bufferHdr = (m_inp_mem_ptr + i); + if (secure_mode) + drv_ctx.ptr_inputbuffer [i].bufferaddr = *bufferHdr; + else + drv_ctx.ptr_inputbuffer [i].bufferaddr = buf_addr; + drv_ctx.ptr_inputbuffer [i].pmem_fd = pmem_fd; + drv_ctx.ptr_inputbuffer [i].buffer_len = drv_ctx.ip_buf.buffer_size; + drv_ctx.ptr_inputbuffer [i].mmaped_size = drv_ctx.ip_buf.buffer_size; + drv_ctx.ptr_inputbuffer [i].offset = 0; + + + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane.bytesused = 0; + plane.length = drv_ctx.ptr_inputbuffer [i].mmaped_size; + plane.m.userptr = (unsigned long)drv_ctx.ptr_inputbuffer[i].bufferaddr; + plane.reserved[0] =drv_ctx.ptr_inputbuffer [i].pmem_fd; + plane.reserved[1] = 0; + plane.data_offset = drv_ctx.ptr_inputbuffer[i].offset; + buf.m.planes = &plane; + buf.length = 1; + + DEBUG_PRINT_LOW("Set the input Buffer Idx: %d Addr: %x", i, drv_ctx.ptr_inputbuffer[i]); + + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_PREPARE_BUF, &buf); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to prepare bufs"); + /*TODO: How to handle this case */ + return OMX_ErrorInsufficientResources; + } + + input = *bufferHdr; + BITMASK_SET(&m_inp_bm_count,i); + DEBUG_PRINT_LOW("Buffer address %p of pmem",*bufferHdr); + if (secure_mode) + input->pBuffer = (OMX_U8 *)drv_ctx.ptr_inputbuffer [i].pmem_fd; + else + input->pBuffer = (OMX_U8 *)buf_addr; + input->nSize = sizeof(OMX_BUFFERHEADERTYPE); + input->nVersion.nVersion = OMX_SPEC_VERSION; + input->nAllocLen = drv_ctx.ip_buf.buffer_size; + input->pAppPrivate = appData; + input->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + input->pInputPortPrivate = (void *)&drv_ctx.ptr_inputbuffer [i]; + + if (drv_ctx.disable_dmx) { + eRet = allocate_desc_buffer(i); + } + } else { + DEBUG_PRINT_ERROR("ERROR:Input Buffer Index not found"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + + +/* ====================================================================== + FUNCTION + omx_vdec::AllocateOutputBuffer + + DESCRIPTION + Helper fn for AllocateBuffer in the output pin + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything went well. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::allocate_output_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr= NULL; // buffer header + unsigned i= 0; // Temporary counter + struct vdec_setbuffer_cmd setbuffers; + int extra_idx = 0; +#ifdef USE_ION + int ion_device_fd =-1; + struct ion_allocation_data ion_alloc_data; + struct ion_fd_data fd_ion_data; +#endif + if (!m_out_mem_ptr) { + DEBUG_PRINT_HIGH("Allocate o/p buffer Header: Cnt(%d) Sz(%d)", + drv_ctx.op_buf.actualcount, + drv_ctx.op_buf.buffer_size); + int nBufHdrSize = 0; + int nPlatformEntrySize = 0; + int nPlatformListSize = 0; + int nPMEMInfoSize = 0; + int pmem_fd = -1; + unsigned char *pmem_baseaddress = NULL; + + OMX_QCOM_PLATFORM_PRIVATE_LIST *pPlatformList; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY *pPlatformEntry; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo; + + DEBUG_PRINT_LOW("Allocating First Output Buffer(%d)", + drv_ctx.op_buf.actualcount); + nBufHdrSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_BUFFERHEADERTYPE); + + nPMEMInfoSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO); + nPlatformListSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_LIST); + nPlatformEntrySize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_ENTRY); + + DEBUG_PRINT_LOW("TotalBufHdr %d BufHdrSize %d PMEM %d PL %d",nBufHdrSize, + sizeof(OMX_BUFFERHEADERTYPE), + nPMEMInfoSize, + nPlatformListSize); + DEBUG_PRINT_LOW("PE %d OutputBuffer Count %d",nPlatformEntrySize, + drv_ctx.op_buf.actualcount); +#ifdef USE_ION + DEBUG_PRINT_HIGH("allocate outputBuffer size %d",drv_ctx.op_buf.buffer_size * drv_ctx.op_buf.actualcount); + ion_device_fd = alloc_map_ion_memory( + drv_ctx.op_buf.buffer_size * drv_ctx.op_buf.actualcount, + drv_ctx.op_buf.alignment, + &ion_alloc_data, &fd_ion_data, secure_mode ? ION_SECURE : 0); + if (ion_device_fd < 0) { + return OMX_ErrorInsufficientResources; + } + pmem_fd = fd_ion_data.fd; +#else + pmem_fd = open (MEM_DEVICE,O_RDWR); + + if (pmem_fd < 0) { + DEBUG_PRINT_ERROR("ERROR:pmem fd for output buffer %d", + drv_ctx.op_buf.buffer_size); + return OMX_ErrorInsufficientResources; + } + + if (pmem_fd == 0) { + pmem_fd = open (MEM_DEVICE,O_RDWR); + + if (pmem_fd < 0) { + DEBUG_PRINT_ERROR("ERROR:pmem fd for output buffer %d", + drv_ctx.op_buf.buffer_size); + return OMX_ErrorInsufficientResources; + } + } + + if (!align_pmem_buffers(pmem_fd, drv_ctx.op_buf.buffer_size * + drv_ctx.op_buf.actualcount, + drv_ctx.op_buf.alignment)) { + DEBUG_PRINT_ERROR("align_pmem_buffers() failed"); + close(pmem_fd); + return OMX_ErrorInsufficientResources; + } +#endif + if (!secure_mode) { + pmem_baseaddress = (unsigned char *)mmap(NULL, + (drv_ctx.op_buf.buffer_size * + drv_ctx.op_buf.actualcount), + PROT_READ|PROT_WRITE,MAP_SHARED,pmem_fd,0); + if (pmem_baseaddress == MAP_FAILED) { + DEBUG_PRINT_ERROR("MMAP failed for Size %d", + drv_ctx.op_buf.buffer_size); + close(pmem_fd); +#ifdef USE_ION + free_ion_memory(&drv_ctx.op_buf_ion_info[i]); +#endif + return OMX_ErrorInsufficientResources; + } + } + m_out_mem_ptr = (OMX_BUFFERHEADERTYPE *)calloc(nBufHdrSize,1); + // Alloc mem for platform specific info + char *pPtr=NULL; + pPtr = (char*) calloc(nPlatformListSize + nPlatformEntrySize + + nPMEMInfoSize,1); + drv_ctx.ptr_outputbuffer = (struct vdec_bufferpayload *)\ + calloc (sizeof(struct vdec_bufferpayload), + drv_ctx.op_buf.actualcount); + drv_ctx.ptr_respbuffer = (struct vdec_output_frameinfo *)\ + calloc (sizeof (struct vdec_output_frameinfo), + drv_ctx.op_buf.actualcount); +#ifdef USE_ION + drv_ctx.op_buf_ion_info = (struct vdec_ion *)\ + calloc (sizeof(struct vdec_ion), + drv_ctx.op_buf.actualcount); +#endif + + if (m_out_mem_ptr && pPtr && drv_ctx.ptr_outputbuffer + && drv_ctx.ptr_respbuffer) { + drv_ctx.ptr_outputbuffer[0].mmaped_size = + (drv_ctx.op_buf.buffer_size * + drv_ctx.op_buf.actualcount); + bufHdr = m_out_mem_ptr; + m_platform_list = (OMX_QCOM_PLATFORM_PRIVATE_LIST *)(pPtr); + m_platform_entry= (OMX_QCOM_PLATFORM_PRIVATE_ENTRY *) + (((char *) m_platform_list) + nPlatformListSize); + m_pmem_info = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) + (((char *) m_platform_entry) + nPlatformEntrySize); + pPlatformList = m_platform_list; + pPlatformEntry = m_platform_entry; + pPMEMInfo = m_pmem_info; + + DEBUG_PRINT_LOW("Memory Allocation Succeeded for OUT port%p",m_out_mem_ptr); + + // Settting the entire storage nicely + DEBUG_PRINT_LOW("bHdr %p OutMem %p PE %p",bufHdr, m_out_mem_ptr,pPlatformEntry); + DEBUG_PRINT_LOW(" Pmem Info = %p",pPMEMInfo); + for (i=0; i < drv_ctx.op_buf.actualcount ; i++) { + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + // Set the values when we determine the right HxW param + bufHdr->nAllocLen = bytes; + bufHdr->nFilledLen = 0; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + // Platform specific PMEM Information + // Initialize the Platform Entry + //DEBUG_PRINT_LOW("Initializing the Platform Entry for %d",i); + pPlatformEntry->type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; + pPlatformEntry->entry = pPMEMInfo; + // Initialize the Platform List + pPlatformList->nEntries = 1; + pPlatformList->entryList = pPlatformEntry; + // Keep pBuffer NULL till vdec is opened + bufHdr->pBuffer = NULL; + bufHdr->nOffset = 0; + + pPMEMInfo->offset = drv_ctx.op_buf.buffer_size*i; + pPMEMInfo->pmem_fd = 0; + bufHdr->pPlatformPrivate = pPlatformList; + + drv_ctx.ptr_outputbuffer[i].pmem_fd = pmem_fd; + m_pmem_info[i].pmem_fd = pmem_fd; +#ifdef USE_ION + drv_ctx.op_buf_ion_info[i].ion_device_fd = ion_device_fd; + drv_ctx.op_buf_ion_info[i].ion_alloc_data = ion_alloc_data; + drv_ctx.op_buf_ion_info[i].fd_ion_data = fd_ion_data; +#endif + + /*Create a mapping between buffers*/ + bufHdr->pOutputPortPrivate = &drv_ctx.ptr_respbuffer[i]; + drv_ctx.ptr_respbuffer[i].client_data = (void *)\ + &drv_ctx.ptr_outputbuffer[i]; + drv_ctx.ptr_outputbuffer[i].offset = drv_ctx.op_buf.buffer_size*i; + drv_ctx.ptr_outputbuffer[i].bufferaddr = + pmem_baseaddress + (drv_ctx.op_buf.buffer_size*i); + + DEBUG_PRINT_LOW("pmem_fd = %d offset = %d address = %p", + pmem_fd, drv_ctx.ptr_outputbuffer[i].offset, + drv_ctx.ptr_outputbuffer[i].bufferaddr); + // Move the buffer and buffer header pointers + bufHdr++; + pPMEMInfo++; + pPlatformEntry++; + pPlatformList++; + } + } else { + DEBUG_PRINT_ERROR("Output buf mem alloc failed[0x%p][0x%p]",\ + m_out_mem_ptr, pPtr); + if (m_out_mem_ptr) { + free(m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + if (pPtr) { + free(pPtr); + pPtr = NULL; + } + if (drv_ctx.ptr_outputbuffer) { + free(drv_ctx.ptr_outputbuffer); + drv_ctx.ptr_outputbuffer = NULL; + } + if (drv_ctx.ptr_respbuffer) { + free(drv_ctx.ptr_respbuffer); + drv_ctx.ptr_respbuffer = NULL; + } +#ifdef USE_ION + if (drv_ctx.op_buf_ion_info) { + DEBUG_PRINT_LOW("Free o/p ion context"); + free(drv_ctx.op_buf_ion_info); + drv_ctx.op_buf_ion_info = NULL; + } +#endif + eRet = OMX_ErrorInsufficientResources; + } + if (eRet == OMX_ErrorNone) + eRet = allocate_extradata(); + } + + for (i=0; i< drv_ctx.op_buf.actualcount; i++) { + if (BITMASK_ABSENT(&m_out_bm_count,i)) { + DEBUG_PRINT_LOW("Found a Free Output Buffer %d",i); + break; + } + } + + if (eRet == OMX_ErrorNone) { + if (i < drv_ctx.op_buf.actualcount) { + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + int rc; + m_pmem_info[i].offset = drv_ctx.ptr_outputbuffer[i].offset; + + drv_ctx.ptr_outputbuffer[i].buffer_len = + drv_ctx.op_buf.buffer_size; + + *bufferHdr = (m_out_mem_ptr + i ); + if (secure_mode) { + drv_ctx.ptr_outputbuffer[i].bufferaddr = *bufferHdr; + } + drv_ctx.ptr_outputbuffer[i].mmaped_size = drv_ctx.op_buf.buffer_size; + + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].length = drv_ctx.op_buf.buffer_size; + plane[0].m.userptr = (unsigned long)drv_ctx.ptr_outputbuffer[i].bufferaddr - + (unsigned long)drv_ctx.ptr_outputbuffer[i].offset; +#ifdef USE_ION + plane[0].reserved[0] = drv_ctx.op_buf_ion_info[i].fd_ion_data.fd; +#endif + plane[0].reserved[1] = drv_ctx.ptr_outputbuffer[i].offset; + plane[0].data_offset = 0; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].length = drv_ctx.extradata_info.buffer_size; + plane[extra_idx].m.userptr = (long unsigned int) (drv_ctx.extradata_info.uaddr + i * drv_ctx.extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = drv_ctx.extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = i * drv_ctx.extradata_info.buffer_size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index higher than allowed: %d", extra_idx); + return OMX_ErrorBadParameter; + } + buf.m.planes = plane; + buf.length = drv_ctx.num_planes; + DEBUG_PRINT_LOW("Set the Output Buffer Idx: %d Addr: %x", i, drv_ctx.ptr_outputbuffer[i]); + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_PREPARE_BUF, &buf); + if (rc) { + /*TODO: How to handle this case */ + return OMX_ErrorInsufficientResources; + } + + if (i == (drv_ctx.op_buf.actualcount -1 ) && !streaming[CAPTURE_PORT]) { + enum v4l2_buf_type buf_type; + buf_type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + rc=ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type); + if (rc) { + return OMX_ErrorInsufficientResources; + } else { + streaming[CAPTURE_PORT] = true; + DEBUG_PRINT_LOW("STREAMON Successful"); + } + } + + (*bufferHdr)->pBuffer = (OMX_U8*)drv_ctx.ptr_outputbuffer[i].bufferaddr; + (*bufferHdr)->pAppPrivate = appData; + BITMASK_SET(&m_out_bm_count,i); + } else { + DEBUG_PRINT_ERROR("All the Output Buffers have been Allocated ; Returning Insufficient"); + eRet = OMX_ErrorInsufficientResources; + } + } + + return eRet; +} + + +// AllocateBuffer -- API Call +/* ====================================================================== + FUNCTION + omx_vdec::AllocateBuffer + + DESCRIPTION + Returns zero if all the buffers released.. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::allocate_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + unsigned i = 0; + OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type + + DEBUG_PRINT_LOW("Allocate buffer on port %d", (int)port); + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Allocate Buf in Invalid State"); + return OMX_ErrorInvalidState; + } + + if (port == OMX_CORE_INPUT_PORT_INDEX) { + if (arbitrary_bytes) { + eRet = allocate_input_heap_buffer (hComp,bufferHdr,port,appData,bytes); + } else { + eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes); + } + } else if (port == OMX_CORE_OUTPUT_PORT_INDEX) { + eRet = client_buffers.allocate_buffers_color_convert(hComp,bufferHdr,port, + appData,bytes); + } else { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d",(int)port); + eRet = OMX_ErrorBadPortIndex; + } + DEBUG_PRINT_LOW("Checking for Output Allocate buffer Done"); + if (eRet == OMX_ErrorNone) { + if (allocate_done()) { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) { + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_IDLE_PENDING); + post_event(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated) { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated) { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + } + DEBUG_PRINT_LOW("Allocate Buffer exit with ret Code %d",eRet); + return eRet; +} + +// Free Buffer - API call +/* ====================================================================== + FUNCTION + omx_vdec::FreeBuffer + + DESCRIPTION + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::free_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned int nPortIndex; + DEBUG_PRINT_LOW("In for decoder free_buffer"); + + if (m_state == OMX_StateIdle && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) { + DEBUG_PRINT_LOW(" free buffer while Component in Loading pending"); + } else if ((m_inp_bEnabled == OMX_FALSE && port == OMX_CORE_INPUT_PORT_INDEX)|| + (m_out_bEnabled == OMX_FALSE && port == OMX_CORE_OUTPUT_PORT_INDEX)) { + DEBUG_PRINT_LOW("Free Buffer while port %d disabled", port); + } else if ((port == OMX_CORE_INPUT_PORT_INDEX && + BITMASK_PRESENT(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING)) || + (port == OMX_CORE_OUTPUT_PORT_INDEX && + BITMASK_PRESENT(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING))) { + DEBUG_PRINT_LOW("Free Buffer while port %d enable pending", port); + } else if (m_state == OMX_StateExecuting || m_state == OMX_StatePause) { + DEBUG_PRINT_ERROR("Invalid state to free buffer,ports need to be disabled"); + post_event(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + + return OMX_ErrorIncorrectStateOperation; + } else if (m_state != OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Invalid state to free buffer,port lost Buffers"); + post_event(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + } + + if (port == OMX_CORE_INPUT_PORT_INDEX) { + /*Check if arbitrary bytes*/ + if (!arbitrary_bytes && !input_use_buffer) + nPortIndex = buffer - m_inp_mem_ptr; + else + nPortIndex = buffer - m_inp_heap_ptr; + + DEBUG_PRINT_LOW("free_buffer on i/p port - Port idx %d", nPortIndex); + if (nPortIndex < drv_ctx.ip_buf.actualcount) { + // Clear the bit associated with it. + BITMASK_CLEAR(&m_inp_bm_count,nPortIndex); + BITMASK_CLEAR(&m_heap_inp_bm_count,nPortIndex); + if (input_use_buffer == true) { + + DEBUG_PRINT_LOW("Free pmem Buffer index %d",nPortIndex); + if (m_phdr_pmem_ptr) + free_input_buffer(m_phdr_pmem_ptr[nPortIndex]); + } else { + if (arbitrary_bytes) { + if (m_phdr_pmem_ptr) + free_input_buffer(nPortIndex,m_phdr_pmem_ptr[nPortIndex]); + else + free_input_buffer(nPortIndex,NULL); + } else + free_input_buffer(buffer); + } + m_inp_bPopulated = OMX_FALSE; + /*Free the Buffer Header*/ + if (release_input_done()) { + DEBUG_PRINT_HIGH("ALL input buffers are freed/released"); + free_input_buffer_header(); + } + } else { + DEBUG_PRINT_ERROR("Error: free_buffer ,Port Index Invalid"); + eRet = OMX_ErrorBadPortIndex; + } + + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING) + && release_input_done()) { + DEBUG_PRINT_LOW("MOVING TO DISABLED STATE"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING); + post_event(OMX_CommandPortDisable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } else if (port == OMX_CORE_OUTPUT_PORT_INDEX) { + // check if the buffer is valid + nPortIndex = buffer - client_buffers.get_il_buf_hdr(); + if (nPortIndex < drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_LOW("free_buffer on o/p port - Port idx %d", nPortIndex); + // Clear the bit associated with it. + BITMASK_CLEAR(&m_out_bm_count,nPortIndex); + m_out_bPopulated = OMX_FALSE; + client_buffers.free_output_buffer (buffer); + + if (release_output_done()) { + free_output_buffer_header(); + } + } else { + DEBUG_PRINT_ERROR("Error: free_buffer , Port Index Invalid"); + eRet = OMX_ErrorBadPortIndex; + } + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING) + && release_output_done()) { + DEBUG_PRINT_LOW("FreeBuffer : If any Disable event pending,post it"); + + DEBUG_PRINT_LOW("MOVING TO DISABLED STATE"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING); +#ifdef _ANDROID_ICS_ + if (m_enable_android_native_buffers) { + DEBUG_PRINT_LOW("FreeBuffer - outport disabled: reset native buffers"); + memset(&native_buffer, 0 ,(sizeof(struct nativebuffer) * MAX_NUM_INPUT_OUTPUT_BUFFERS)); + } +#endif + + post_event(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } else { + eRet = OMX_ErrorBadPortIndex; + } + if ((eRet == OMX_ErrorNone) && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) { + if (release_done()) { + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING); + post_event(OMX_CommandStateSet, OMX_StateLoaded, + OMX_COMPONENT_GENERATE_EVENT); + } + } + return eRet; +} + + +/* ====================================================================== + FUNCTION + omx_vdec::EmptyThisBuffer + + DESCRIPTION + This routine is used to push the encoded video frames to + the video decoder. + + PARAMETERS + None. + + RETURN VALUE + OMX Error None if everything went successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::empty_this_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE ret1 = OMX_ErrorNone; + unsigned int nBufferIndex = drv_ctx.ip_buf.actualcount; + + if (buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { + codec_config_flag = true; + DEBUG_PRINT_LOW("%s: codec_config buffer", __FUNCTION__); + } + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Empty this buffer in Invalid State"); + return OMX_ErrorInvalidState; + } + + if (buffer == NULL) { + DEBUG_PRINT_ERROR("ERROR:ETB Buffer is NULL"); + return OMX_ErrorBadParameter; + } + + if (!m_inp_bEnabled) { + DEBUG_PRINT_ERROR("ERROR:ETB incorrect state operation, input port is disabled."); + return OMX_ErrorIncorrectStateOperation; + } + + if (buffer->nInputPortIndex != OMX_CORE_INPUT_PORT_INDEX) { + DEBUG_PRINT_ERROR("ERROR:ETB invalid port in header %lu", buffer->nInputPortIndex); + return OMX_ErrorBadPortIndex; + } + + if (perf_flag) { + if (!latency) { + dec_time.stop(); + latency = dec_time.processing_time_us(); + dec_time.start(); + } + } + + if (arbitrary_bytes) { + nBufferIndex = buffer - m_inp_heap_ptr; + } else { + if (input_use_buffer == true) { + nBufferIndex = buffer - m_inp_heap_ptr; + m_inp_mem_ptr[nBufferIndex].nFilledLen = m_inp_heap_ptr[nBufferIndex].nFilledLen; + m_inp_mem_ptr[nBufferIndex].nTimeStamp = m_inp_heap_ptr[nBufferIndex].nTimeStamp; + m_inp_mem_ptr[nBufferIndex].nFlags = m_inp_heap_ptr[nBufferIndex].nFlags; + buffer = &m_inp_mem_ptr[nBufferIndex]; + DEBUG_PRINT_LOW("Non-Arbitrary mode - buffer address is: malloc %p, pmem%p in Index %d, buffer %p of size %d", + &m_inp_heap_ptr[nBufferIndex], &m_inp_mem_ptr[nBufferIndex],nBufferIndex, buffer, buffer->nFilledLen); + } else { + nBufferIndex = buffer - m_inp_mem_ptr; + } + } + + if (nBufferIndex > drv_ctx.ip_buf.actualcount ) { + DEBUG_PRINT_ERROR("ERROR:ETB nBufferIndex is invalid"); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("[ETB] BHdr(%p) pBuf(%p) nTS(%lld) nFL(%lu)", + buffer, buffer->pBuffer, buffer->nTimeStamp, buffer->nFilledLen); + if (arbitrary_bytes) { + post_event ((unsigned)hComp,(unsigned)buffer, + OMX_COMPONENT_GENERATE_ETB_ARBITRARY); + } else { + if (!(client_extradata & OMX_TIMEINFO_EXTRADATA)) + set_frame_rate(buffer->nTimeStamp); + post_event ((unsigned)hComp,(unsigned)buffer,OMX_COMPONENT_GENERATE_ETB); + } + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::empty_this_buffer_proxy + + DESCRIPTION + This routine is used to push the encoded video frames to + the video decoder. + + PARAMETERS + None. + + RETURN VALUE + OMX Error None if everything went successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::empty_this_buffer_proxy(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + int push_cnt = 0,i=0; + unsigned nPortIndex = 0; + OMX_ERRORTYPE ret = OMX_ErrorNone; + struct vdec_input_frameinfo frameinfo; + struct vdec_bufferpayload *temp_buffer; + struct vdec_seqheader seq_header; + bool port_setting_changed = true; + bool not_coded_vop = false; + + /*Should we generate a Aync error event*/ + if (buffer == NULL || buffer->pInputPortPrivate == NULL) { + DEBUG_PRINT_ERROR("ERROR:empty_this_buffer_proxy is invalid"); + return OMX_ErrorBadParameter; + } + + nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)m_inp_mem_ptr); + + if (nPortIndex > drv_ctx.ip_buf.actualcount) { + DEBUG_PRINT_ERROR("ERROR:empty_this_buffer_proxy invalid nPortIndex[%u]", + nPortIndex); + return OMX_ErrorBadParameter; + } + + pending_input_buffers++; + + /* return zero length and not an EOS buffer */ + if (!arbitrary_bytes && (buffer->nFilledLen == 0) && + ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == 0)) { + DEBUG_PRINT_HIGH("return zero legth buffer"); + post_event ((unsigned int)buffer,VDEC_S_SUCCESS, + OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorNone; + } + + + if (codec_type_parse == CODEC_TYPE_MPEG4 || codec_type_parse == CODEC_TYPE_DIVX) { + mp4StreamType psBits; + psBits.data = (unsigned char *)(buffer->pBuffer + buffer->nOffset); + psBits.numBytes = buffer->nFilledLen; + mp4_headerparser.parseHeader(&psBits); + not_coded_vop = mp4_headerparser.is_notcodec_vop( + (buffer->pBuffer + buffer->nOffset),buffer->nFilledLen); + if (not_coded_vop) { + DEBUG_PRINT_HIGH("Found Not coded vop len %lu frame number %u", + buffer->nFilledLen,frame_count); + if (buffer->nFlags & OMX_BUFFERFLAG_EOS) { + DEBUG_PRINT_HIGH("Eos and Not coded Vop set len to zero"); + not_coded_vop = false; + buffer->nFilledLen = 0; + } + } + } + + if (input_flush_progress == true + + || not_coded_vop + + ) { + DEBUG_PRINT_LOW("Flush in progress return buffer "); + post_event ((unsigned int)buffer,VDEC_S_SUCCESS, + OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorNone; + } + + temp_buffer = (struct vdec_bufferpayload *)buffer->pInputPortPrivate; + + if ((temp_buffer - drv_ctx.ptr_inputbuffer) > drv_ctx.ip_buf.actualcount) { + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("ETBProxy: bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer); + /*for use buffer we need to memcpy the data*/ + temp_buffer->buffer_len = buffer->nFilledLen; + + if (input_use_buffer) { + if (buffer->nFilledLen <= temp_buffer->buffer_len) { + if (arbitrary_bytes) { + memcpy (temp_buffer->bufferaddr, (buffer->pBuffer + buffer->nOffset),buffer->nFilledLen); + } else { + memcpy (temp_buffer->bufferaddr, (m_inp_heap_ptr[nPortIndex].pBuffer + m_inp_heap_ptr[nPortIndex].nOffset), + buffer->nFilledLen); + } + } else { + return OMX_ErrorBadParameter; + } + + } + + frameinfo.bufferaddr = temp_buffer->bufferaddr; + frameinfo.client_data = (void *) buffer; + frameinfo.datalen = temp_buffer->buffer_len; + frameinfo.flags = 0; + frameinfo.offset = buffer->nOffset; + frameinfo.pmem_fd = temp_buffer->pmem_fd; + frameinfo.pmem_offset = temp_buffer->offset; + frameinfo.timestamp = buffer->nTimeStamp; + if (drv_ctx.disable_dmx && m_desc_buffer_ptr && m_desc_buffer_ptr[nPortIndex].buf_addr) { + DEBUG_PRINT_LOW("ETB: dmx enabled"); + if (m_demux_entries == 0) { + extract_demux_addr_offsets(buffer); + } + + DEBUG_PRINT_LOW("ETB: handle_demux_data - entries=%d",m_demux_entries); + handle_demux_data(buffer); + frameinfo.desc_addr = (OMX_U8 *)m_desc_buffer_ptr[nPortIndex].buf_addr; + frameinfo.desc_size = m_desc_buffer_ptr[nPortIndex].desc_data_size; + } else { + frameinfo.desc_addr = NULL; + frameinfo.desc_size = 0; + } + if (!arbitrary_bytes) { + frameinfo.flags |= buffer->nFlags; + } + +#ifdef _ANDROID_ + if (m_debug_timestamp) { + if (arbitrary_bytes) { + DEBUG_PRINT_LOW("Inserting TIMESTAMP (%lld) into queue", buffer->nTimeStamp); + m_timestamp_list.insert_ts(buffer->nTimeStamp); + } else if (!arbitrary_bytes && !(buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { + DEBUG_PRINT_LOW("Inserting TIMESTAMP (%lld) into queue", buffer->nTimeStamp); + m_timestamp_list.insert_ts(buffer->nTimeStamp); + } + } +#endif + +#ifdef INPUT_BUFFER_LOG + if (inputBufferFile1) { + fwrite((const char *)temp_buffer->bufferaddr, + temp_buffer->buffer_len,1,inputBufferFile1); + } +#endif + + if (buffer->nFlags & QOMX_VIDEO_BUFFERFLAG_EOSEQ) { + frameinfo.flags |= QOMX_VIDEO_BUFFERFLAG_EOSEQ; + buffer->nFlags &= ~QOMX_VIDEO_BUFFERFLAG_EOSEQ; + } + + if (temp_buffer->buffer_len == 0 || (buffer->nFlags & OMX_BUFFERFLAG_EOS)) { + DEBUG_PRINT_HIGH("Rxd i/p EOS, Notify Driver that EOS has been reached"); + frameinfo.flags |= VDEC_BUFFERFLAG_EOS; + h264_scratch.nFilledLen = 0; + nal_count = 0; + look_ahead_nal = false; + frame_count = 0; + if (m_frame_parser.mutils) + m_frame_parser.mutils->initialize_frame_checking_environment(); + m_frame_parser.flush(); + h264_last_au_ts = LLONG_MAX; + h264_last_au_flags = 0; + memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) ); + m_demux_entries = 0; + } + struct v4l2_buffer buf; + struct v4l2_plane plane; + memset( (void *)&buf, 0, sizeof(buf)); + memset( (void *)&plane, 0, sizeof(plane)); + int rc; + unsigned long print_count; + if (temp_buffer->buffer_len == 0 || (buffer->nFlags & OMX_BUFFERFLAG_EOS)) { + buf.flags = V4L2_QCOM_BUF_FLAG_EOS; + DEBUG_PRINT_HIGH("INPUT EOS reached") ; + } + OMX_ERRORTYPE eRet = OMX_ErrorNone; + buf.index = nPortIndex; + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane.bytesused = temp_buffer->buffer_len; + plane.length = drv_ctx.ip_buf.buffer_size; + plane.m.userptr = (unsigned long)temp_buffer->bufferaddr - + (unsigned long)temp_buffer->offset; + plane.reserved[0] = temp_buffer->pmem_fd; + plane.reserved[1] = temp_buffer->offset; + plane.data_offset = 0; + buf.m.planes = &plane; + buf.length = 1; + if (frameinfo.timestamp >= LLONG_MAX) { + buf.flags |= V4L2_QCOM_BUF_TIMESTAMP_INVALID; + } + //assumption is that timestamp is in milliseconds + buf.timestamp.tv_sec = frameinfo.timestamp / 1000000; + buf.timestamp.tv_usec = (frameinfo.timestamp % 1000000); + buf.flags |= (buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) ? V4L2_QCOM_BUF_FLAG_CODECCONFIG: 0; + + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_QBUF, &buf); + if (rc) { + DEBUG_PRINT_ERROR("Failed to qbuf Input buffer to driver"); + return OMX_ErrorHardware; + } + codec_config_flag = false; + DEBUG_PRINT_LOW("%s: codec_config cleared", __FUNCTION__); + + if (!streaming[OUTPUT_PORT]) { + enum v4l2_buf_type buf_type; + int ret,r; + + buf_type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing"); + ret=ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type); + if (!ret) { + DEBUG_PRINT_HIGH("Streamon on OUTPUT Plane was successful"); + streaming[OUTPUT_PORT] = true; + } else { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to call streamon on OUTPUT"); + DEBUG_PRINT_LOW("If Stream on failed no buffer should be queued"); + post_event ((unsigned int)buffer,VDEC_S_SUCCESS, + OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorBadParameter; + } + } + DEBUG_PRINT_LOW("[ETBP] pBuf(%p) nTS(%lld) Sz(%d)", + frameinfo.bufferaddr, frameinfo.timestamp, frameinfo.datalen); + time_stamp_dts.insert_timestamp(buffer); + + return ret; +} + +/* ====================================================================== + FUNCTION + omx_vdec::FillThisBuffer + + DESCRIPTION + IL client uses this method to release the frame buffer + after displaying them. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::fill_this_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + unsigned nPortIndex = buffer - client_buffers.get_il_buf_hdr(); + + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("FTB in Invalid State"); + return OMX_ErrorInvalidState; + } + + if (!m_out_bEnabled) { + DEBUG_PRINT_ERROR("ERROR:FTB incorrect state operation, output port is disabled."); + return OMX_ErrorIncorrectStateOperation; + } + + if (buffer == NULL || + (nPortIndex >= drv_ctx.op_buf.actualcount)) { + DEBUG_PRINT_ERROR("FTB: ERROR: invalid buffer index, nPortIndex %u bufCount %u", + nPortIndex, drv_ctx.op_buf.actualcount); + return OMX_ErrorBadParameter; + } + + if (buffer->nOutputPortIndex != OMX_CORE_OUTPUT_PORT_INDEX) { + DEBUG_PRINT_ERROR("ERROR:FTB invalid port in header %lu", buffer->nOutputPortIndex); + return OMX_ErrorBadPortIndex; + } + + DEBUG_PRINT_LOW("[FTB] bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer); + post_event((unsigned) hComp, (unsigned)buffer, m_fill_output_msg); + return OMX_ErrorNone; +} +/* ====================================================================== + FUNCTION + omx_vdec::fill_this_buffer_proxy + + DESCRIPTION + IL client uses this method to release the frame buffer + after displaying them. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::fill_this_buffer_proxy( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* bufferAdd) +{ + OMX_ERRORTYPE nRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *buffer = bufferAdd; + unsigned nPortIndex = 0; + struct vdec_fillbuffer_cmd fillbuffer; + struct vdec_bufferpayload *ptr_outputbuffer = NULL; + struct vdec_output_frameinfo *ptr_respbuffer = NULL; + + nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)client_buffers.get_il_buf_hdr()); + + if (bufferAdd == NULL || nPortIndex > drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("FTBProxy: ERROR: invalid buffer index, nPortIndex %u bufCount %u", + nPortIndex, drv_ctx.op_buf.actualcount); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("FTBProxy: bufhdr = %p, bufhdr->pBuffer = %p", + bufferAdd, bufferAdd->pBuffer); + /*Return back the output buffer to client*/ + if (m_out_bEnabled != OMX_TRUE || output_flush_progress == true) { + DEBUG_PRINT_LOW("Output Buffers return flush/disable condition"); + buffer->nFilledLen = 0; + m_cb.FillBufferDone (hComp,m_app_data,buffer); + return OMX_ErrorNone; + } + pending_output_buffers++; + buffer = client_buffers.get_dr_buf_hdr(bufferAdd); + ptr_respbuffer = (struct vdec_output_frameinfo*)buffer->pOutputPortPrivate; + if (ptr_respbuffer) { + ptr_outputbuffer = (struct vdec_bufferpayload*)ptr_respbuffer->client_data; + } + + if (ptr_respbuffer == NULL || ptr_outputbuffer == NULL) { + DEBUG_PRINT_ERROR("resp buffer or outputbuffer is NULL"); + buffer->nFilledLen = 0; + m_cb.FillBufferDone (hComp,m_app_data,buffer); + pending_output_buffers--; + return OMX_ErrorBadParameter; + } + + int rc = 0; + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + memset( (void *)&buf, 0, sizeof(buf)); + memset( (void *)plane, 0, (sizeof(struct v4l2_plane)*VIDEO_MAX_PLANES)); + int extra_idx = 0; + + buf.index = nPortIndex; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].bytesused = buffer->nFilledLen; + plane[0].length = drv_ctx.op_buf.buffer_size; + plane[0].m.userptr = + (unsigned long)drv_ctx.ptr_outputbuffer[nPortIndex].bufferaddr - + (unsigned long)drv_ctx.ptr_outputbuffer[nPortIndex].offset; + plane[0].reserved[0] = drv_ctx.ptr_outputbuffer[nPortIndex].pmem_fd; + plane[0].reserved[1] = drv_ctx.ptr_outputbuffer[nPortIndex].offset; + plane[0].data_offset = 0; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].bytesused = 0; + plane[extra_idx].length = drv_ctx.extradata_info.buffer_size; + plane[extra_idx].m.userptr = (long unsigned int) (drv_ctx.extradata_info.uaddr + nPortIndex * drv_ctx.extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = drv_ctx.extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = nPortIndex * drv_ctx.extradata_info.buffer_size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index higher than expected: %d", extra_idx); + return OMX_ErrorBadParameter; + } + buf.m.planes = plane; + buf.length = drv_ctx.num_planes; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_QBUF, &buf); + if (rc) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to qbuf to driver"); + } +return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::SetCallbacks + + DESCRIPTION + Set the callbacks. + + PARAMETERS + None. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::set_callbacks(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_CALLBACKTYPE* callbacks, + OMX_IN OMX_PTR appData) +{ + + m_cb = *callbacks; + DEBUG_PRINT_LOW("Callbacks Set %p %p %p",m_cb.EmptyBufferDone,\ + m_cb.EventHandler,m_cb.FillBufferDone); + m_app_data = appData; + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== + FUNCTION + omx_vdec::ComponentDeInit + + DESCRIPTION + Destroys the component and release memory allocated to the heap. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::component_deinit(OMX_IN OMX_HANDLETYPE hComp) +{ + + unsigned i = 0; + if (OMX_StateLoaded != m_state) { + DEBUG_PRINT_ERROR("WARNING:Rxd DeInit,OMX not in LOADED state %d",\ + m_state); + DEBUG_PRINT_ERROR("Playback Ended - FAILED"); + } else { + DEBUG_PRINT_HIGH("Playback Ended - PASSED"); + } + + /*Check if the output buffers have to be cleaned up*/ + if (m_out_mem_ptr) { + DEBUG_PRINT_LOW("Freeing the Output Memory"); + for (i = 0; i < drv_ctx.op_buf.actualcount; i++ ) { + free_output_buffer (&m_out_mem_ptr[i]); + } +#ifdef _ANDROID_ICS_ + memset(&native_buffer, 0, (sizeof(nativebuffer) * MAX_NUM_INPUT_OUTPUT_BUFFERS)); +#endif + } + + /*Check if the input buffers have to be cleaned up*/ + if (m_inp_mem_ptr || m_inp_heap_ptr) { + DEBUG_PRINT_LOW("Freeing the Input Memory"); + for (i = 0; i<drv_ctx.ip_buf.actualcount; i++ ) { + if (m_inp_mem_ptr) + free_input_buffer (i,&m_inp_mem_ptr[i]); + else + free_input_buffer (i,NULL); + } + } + free_input_buffer_header(); + free_output_buffer_header(); + if (h264_scratch.pBuffer) { + free(h264_scratch.pBuffer); + h264_scratch.pBuffer = NULL; + } + + if (h264_parser) { + delete h264_parser; + h264_parser = NULL; + } + + if (m_platform_list) { + free(m_platform_list); + m_platform_list = NULL; + } + if (m_vendor_config.pData) { + free(m_vendor_config.pData); + m_vendor_config.pData = NULL; + } + + // Reset counters in mesg queues + m_ftb_q.m_size=0; + m_cmd_q.m_size=0; + m_etb_q.m_size=0; + m_ftb_q.m_read = m_ftb_q.m_write =0; + m_cmd_q.m_read = m_cmd_q.m_write =0; + m_etb_q.m_read = m_etb_q.m_write =0; +#ifdef _ANDROID_ + if (m_debug_timestamp) { + m_timestamp_list.reset_ts_list(); + } +#endif + + DEBUG_PRINT_LOW("Calling VDEC_IOCTL_STOP_NEXT_MSG"); + //(void)ioctl(drv_ctx.video_driver_fd, VDEC_IOCTL_STOP_NEXT_MSG, + // NULL); + DEBUG_PRINT_HIGH("Close the driver instance"); + +#ifdef INPUT_BUFFER_LOG + fclose (inputBufferFile1); +#endif +#ifdef OUTPUT_BUFFER_LOG + if (outputBufferFile1) + fclose (outputBufferFile1); +#endif +#ifdef OUTPUT_EXTRADATA_LOG + fclose (outputExtradataFile); +#endif + DEBUG_PRINT_HIGH("omx_vdec::component_deinit() complete"); + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::UseEGLImage + + DESCRIPTION + OMX Use EGL Image method implementation <TBD>. + + PARAMETERS + <TBD>. + + RETURN VALUE + Not Implemented error. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::use_EGL_image(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN void* eglImage) +{ + OMX_QCOM_PLATFORM_PRIVATE_LIST pmem_list; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY pmem_entry; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO pmem_info; + +#ifdef USE_EGL_IMAGE_GPU + PFNEGLQUERYIMAGEQUALCOMMPROC egl_queryfunc; + EGLint fd = -1, offset = 0,pmemPtr = 0; +#else + int fd = -1, offset = 0; +#endif + DEBUG_PRINT_HIGH("use EGL image support for decoder"); + if (!bufferHdr || !eglImage|| port != OMX_CORE_OUTPUT_PORT_INDEX) { + DEBUG_PRINT_ERROR(""); + } +#ifdef USE_EGL_IMAGE_GPU + if (m_display_id == NULL) { + DEBUG_PRINT_ERROR("Display ID is not set by IL client"); + return OMX_ErrorInsufficientResources; + } + egl_queryfunc = (PFNEGLQUERYIMAGEQUALCOMMPROC) + eglGetProcAddress("eglQueryImageKHR"); + egl_queryfunc(m_display_id, eglImage, EGL_BUFFER_HANDLE_QCOM,&fd); + egl_queryfunc(m_display_id, eglImage, EGL_BUFFER_OFFSET_QCOM,&offset); + egl_queryfunc(m_display_id, eglImage, EGL_BITMAP_POINTER_KHR,&pmemPtr); +#else //with OMX test app + struct temp_egl { + int pmem_fd; + int offset; + }; + struct temp_egl *temp_egl_id = NULL; + void * pmemPtr = (void *) eglImage; + temp_egl_id = (struct temp_egl *)eglImage; + if (temp_egl_id != NULL) { + fd = temp_egl_id->pmem_fd; + offset = temp_egl_id->offset; + } +#endif + if (fd < 0) { + DEBUG_PRINT_ERROR("Improper pmem fd by EGL client %d",fd); + return OMX_ErrorInsufficientResources; + } + pmem_info.pmem_fd = (OMX_U32) fd; + pmem_info.offset = (OMX_U32) offset; + pmem_entry.entry = (void *) &pmem_info; + pmem_entry.type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; + pmem_list.entryList = &pmem_entry; + pmem_list.nEntries = 1; + ouput_egl_buffers = true; + if (OMX_ErrorNone != use_buffer(hComp,bufferHdr, port, + (void *)&pmem_list, drv_ctx.op_buf.buffer_size, + (OMX_U8 *)pmemPtr)) { + DEBUG_PRINT_ERROR("use buffer call failed for egl image"); + return OMX_ErrorInsufficientResources; + } + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::ComponentRoleEnum + + DESCRIPTION + OMX Component Role Enum method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything is successful. + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::component_role_enum(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_U8* role, + OMX_IN OMX_U32 index) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + eRet = OMX_ErrorNoMore; + } + } + if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg2",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.mpeg2",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.h263",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } + + else if ((!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx",OMX_MAX_STRINGNAME_SIZE)) || + (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx311",OMX_MAX_STRINGNAME_SIZE)) ) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.avc",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.hevc",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if ( (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vc1",OMX_MAX_STRINGNAME_SIZE)) || + (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.wmv",OMX_MAX_STRINGNAME_SIZE)) + ) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.vp8",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } else { + DEBUG_PRINT_ERROR("ERROR:Querying Role on Unknown Component"); + eRet = OMX_ErrorInvalidComponentName; + } + return eRet; +} + + + + +/* ====================================================================== + FUNCTION + omx_vdec::AllocateDone + + DESCRIPTION + Checks if entire buffer pool is allocated by IL Client or not. + Need this to move to IDLE state. + + PARAMETERS + None. + + RETURN VALUE + true/false. + + ========================================================================== */ +bool omx_vdec::allocate_done(void) +{ + bool bRet = false; + bool bRet_In = false; + bool bRet_Out = false; + + bRet_In = allocate_input_done(); + bRet_Out = allocate_output_done(); + + if (bRet_In && bRet_Out) { + bRet = true; + } + + return bRet; +} +/* ====================================================================== + FUNCTION + omx_vdec::AllocateInputDone + + DESCRIPTION + Checks if I/P buffer pool is allocated by IL Client or not. + + PARAMETERS + None. + + RETURN VALUE + true/false. + + ========================================================================== */ +bool omx_vdec::allocate_input_done(void) +{ + bool bRet = false; + unsigned i=0; + + if (m_inp_mem_ptr == NULL) { + return bRet; + } + if (m_inp_mem_ptr ) { + for (; i<drv_ctx.ip_buf.actualcount; i++) { + if (BITMASK_ABSENT(&m_inp_bm_count,i)) { + break; + } + } + } + if (i == drv_ctx.ip_buf.actualcount) { + bRet = true; + DEBUG_PRINT_HIGH("Allocate done for all i/p buffers"); + } + if (i==drv_ctx.ip_buf.actualcount && m_inp_bEnabled) { + m_inp_bPopulated = OMX_TRUE; + } + return bRet; +} +/* ====================================================================== + FUNCTION + omx_vdec::AllocateOutputDone + + DESCRIPTION + Checks if entire O/P buffer pool is allocated by IL Client or not. + + PARAMETERS + None. + + RETURN VALUE + true/false. + + ========================================================================== */ +bool omx_vdec::allocate_output_done(void) +{ + bool bRet = false; + unsigned j=0; + + if (m_out_mem_ptr == NULL) { + return bRet; + } + + if (m_out_mem_ptr) { + for (; j < drv_ctx.op_buf.actualcount; j++) { + if (BITMASK_ABSENT(&m_out_bm_count,j)) { + break; + } + } + } + + if (j == drv_ctx.op_buf.actualcount) { + bRet = true; + DEBUG_PRINT_HIGH("Allocate done for all o/p buffers"); + if (m_out_bEnabled) + m_out_bPopulated = OMX_TRUE; + } + + return bRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::ReleaseDone + + DESCRIPTION + Checks if IL client has released all the buffers. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_vdec::release_done(void) +{ + bool bRet = false; + + if (release_input_done()) { + if (release_output_done()) { + bRet = true; + } + } + return bRet; +} + + +/* ====================================================================== + FUNCTION + omx_vdec::ReleaseOutputDone + + DESCRIPTION + Checks if IL client has released all the buffers. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_vdec::release_output_done(void) +{ + bool bRet = false; + unsigned i=0,j=0; + + DEBUG_PRINT_LOW("Value of m_out_mem_ptr %p",m_inp_mem_ptr); + if (m_out_mem_ptr) { + for (; j < drv_ctx.op_buf.actualcount ; j++) { + if (BITMASK_PRESENT(&m_out_bm_count,j)) { + break; + } + } + if (j == drv_ctx.op_buf.actualcount) { + m_out_bm_count = 0; + bRet = true; + } + } else { + m_out_bm_count = 0; + bRet = true; + } + return bRet; +} +/* ====================================================================== + FUNCTION + omx_vdec::ReleaseInputDone + + DESCRIPTION + Checks if IL client has released all the buffers. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_vdec::release_input_done(void) +{ + bool bRet = false; + unsigned i=0,j=0; + + DEBUG_PRINT_LOW("Value of m_inp_mem_ptr %p",m_inp_mem_ptr); + if (m_inp_mem_ptr) { + for (; j<drv_ctx.ip_buf.actualcount; j++) { + if ( BITMASK_PRESENT(&m_inp_bm_count,j)) { + break; + } + } + if (j==drv_ctx.ip_buf.actualcount) { + bRet = true; + } + } else { + bRet = true; + } + return bRet; +} + +OMX_ERRORTYPE omx_vdec::fill_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer) +{ + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo = NULL; + if (!buffer || (buffer - m_out_mem_ptr) >= drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("[FBD] ERROR in ptr(%p)", buffer); + return OMX_ErrorBadParameter; + } else if (output_flush_progress) { + DEBUG_PRINT_LOW("FBD: Buffer (%p) flushed", buffer); + buffer->nFilledLen = 0; + buffer->nTimeStamp = 0; + buffer->nFlags &= ~OMX_BUFFERFLAG_EXTRADATA; + buffer->nFlags &= ~QOMX_VIDEO_BUFFERFLAG_EOSEQ; + buffer->nFlags &= ~OMX_BUFFERFLAG_DATACORRUPT; + } + + DEBUG_PRINT_LOW("fill_buffer_done: bufhdr = %p, bufhdr->pBuffer = %p", + buffer, buffer->pBuffer); + pending_output_buffers --; + + if (buffer->nFlags & OMX_BUFFERFLAG_EOS) { + DEBUG_PRINT_HIGH("Output EOS has been reached"); + if (!output_flush_progress) + post_event((unsigned)NULL, (unsigned)NULL, + OMX_COMPONENT_GENERATE_EOS_DONE); + + if (psource_frame) { + m_cb.EmptyBufferDone(&m_cmp, m_app_data, psource_frame); + psource_frame = NULL; + } + if (pdest_frame) { + pdest_frame->nFilledLen = 0; + m_input_free_q.insert_entry((unsigned) pdest_frame,(unsigned)NULL, + (unsigned)NULL); + pdest_frame = NULL; + } + } + + DEBUG_PRINT_LOW("In fill Buffer done call address %p ",buffer); +#ifdef OUTPUT_BUFFER_LOG + if (outputBufferFile1 && buffer->nFilledLen) { + int buf_index = buffer - m_out_mem_ptr; + int stride = drv_ctx.video_resolution.stride; + int scanlines = drv_ctx.video_resolution.scan_lines; + char *temp = (char *)drv_ctx.ptr_outputbuffer[buf_index].bufferaddr; + int i; + int bytes_written = 0; + for (i = 0; i < drv_ctx.video_resolution.frame_height; i++) { + bytes_written = fwrite(temp, drv_ctx.video_resolution.frame_width, 1, outputBufferFile1); + temp += stride; + } + temp = (char *)drv_ctx.ptr_outputbuffer[buf_index].bufferaddr + stride * scanlines; + int stride_c = stride; + for (i = 0; i < drv_ctx.video_resolution.frame_height/2; i++) { + bytes_written += fwrite(temp, drv_ctx.video_resolution.frame_width, 1, outputBufferFile1); + temp += stride_c; + } + } +#endif + + /* For use buffer we need to copy the data */ + if (!output_flush_progress) { + time_stamp_dts.get_next_timestamp(buffer, + (drv_ctx.interlace != VDEC_InterlaceFrameProgressive) + ?true:false); + if (m_debug_timestamp) { + { + OMX_TICKS expected_ts = 0; + m_timestamp_list.pop_min_ts(expected_ts); + DEBUG_PRINT_LOW("Current timestamp (%lld),Popped TIMESTAMP (%lld) from list", + buffer->nTimeStamp, expected_ts); + + if (buffer->nTimeStamp != expected_ts) { + DEBUG_PRINT_ERROR("ERROR in omx_vdec::async_message_process timestamp Check"); + } + } + } + } + if (m_cb.FillBufferDone) { + if (buffer->nFilledLen > 0) { + handle_extradata(buffer); + if (client_extradata & OMX_TIMEINFO_EXTRADATA) + // Keep min timestamp interval to handle corrupted bit stream scenario + set_frame_rate(buffer->nTimeStamp); + else if (arbitrary_bytes) + adjust_timestamp(buffer->nTimeStamp); + if (perf_flag) { + if (!proc_frms) { + dec_time.stop(); + latency = dec_time.processing_time_us() - latency; + DEBUG_PRINT_HIGH(">>> FBD Metrics: Latency(%.2f)mS", latency / 1e3); + dec_time.start(); + fps_metrics.start(); + } + proc_frms++; + if (buffer->nFlags & OMX_BUFFERFLAG_EOS) { + OMX_U64 proc_time = 0; + fps_metrics.stop(); + proc_time = fps_metrics.processing_time_us(); + DEBUG_PRINT_HIGH(">>> FBD Metrics: proc_frms(%lu) proc_time(%.2f)S fps(%.2f)", + proc_frms, (float)proc_time / 1e6, + (float)(1e6 * proc_frms) / proc_time); + proc_frms = 0; + } + } + +#ifdef OUTPUT_EXTRADATA_LOG + if (outputExtradataFile) { + + OMX_OTHER_EXTRADATATYPE *p_extra = NULL; + p_extra = (OMX_OTHER_EXTRADATATYPE *) + ((unsigned)(buffer->pBuffer + buffer->nOffset + + buffer->nFilledLen + 3)&(~3)); + while (p_extra && + (OMX_U8*)p_extra < (buffer->pBuffer + buffer->nAllocLen) ) { + DEBUG_PRINT_LOW("WRITING extradata, size=%d,type=%d",p_extra->nSize, p_extra->eType); + fwrite (p_extra,1,p_extra->nSize,outputExtradataFile); + if (p_extra->eType == OMX_ExtraDataNone) { + break; + } + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + p_extra->nSize); + } + } +#endif + } + if (buffer->nFlags & OMX_BUFFERFLAG_EOS) { + prev_ts = LLONG_MAX; + rst_prev_ts = true; + } + + pPMEMInfo = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) + ((OMX_QCOM_PLATFORM_PRIVATE_LIST *) + buffer->pPlatformPrivate)->entryList->entry; + DEBUG_PRINT_LOW("Before FBD callback Accessed Pmeminfo %d",pPMEMInfo->pmem_fd); + OMX_BUFFERHEADERTYPE *il_buffer; + il_buffer = client_buffers.get_il_buf_hdr(buffer); + if (il_buffer) + m_cb.FillBufferDone (hComp,m_app_data,il_buffer); + else { + DEBUG_PRINT_ERROR("Invalid buffer address from get_il_buf_hdr"); + return OMX_ErrorBadParameter; + } + DEBUG_PRINT_LOW("After Fill Buffer Done callback %d",pPMEMInfo->pmem_fd); + } else { + return OMX_ErrorBadParameter; + } + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::empty_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + + if (buffer == NULL || ((buffer - m_inp_mem_ptr) > drv_ctx.ip_buf.actualcount)) { + DEBUG_PRINT_ERROR("empty_buffer_done: ERROR bufhdr = %p", buffer); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("empty_buffer_done: bufhdr = %p, bufhdr->pBuffer = %p", + buffer, buffer->pBuffer); + pending_input_buffers--; + + if (arbitrary_bytes) { + if (pdest_frame == NULL && input_flush_progress == false) { + DEBUG_PRINT_LOW("Push input from buffer done address of Buffer %p",buffer); + pdest_frame = buffer; + buffer->nFilledLen = 0; + buffer->nTimeStamp = LLONG_MAX; + push_input_buffer (hComp); + } else { + DEBUG_PRINT_LOW("Push buffer into freeq address of Buffer %p",buffer); + buffer->nFilledLen = 0; + if (!m_input_free_q.insert_entry((unsigned)buffer, + (unsigned)NULL, (unsigned)NULL)) { + DEBUG_PRINT_ERROR("ERROR:i/p free Queue is FULL Error"); + } + } + } else if (m_cb.EmptyBufferDone) { + buffer->nFilledLen = 0; + if (input_use_buffer == true) { + buffer = &m_inp_heap_ptr[buffer-m_inp_mem_ptr]; + } + m_cb.EmptyBufferDone(hComp ,m_app_data, buffer); + } + return OMX_ErrorNone; +} + +int omx_vdec::async_message_process (void *context, void* message) +{ + omx_vdec* omx = NULL; + struct vdec_msginfo *vdec_msg = NULL; + OMX_BUFFERHEADERTYPE* omxhdr = NULL; + struct v4l2_buffer *v4l2_buf_ptr = NULL; + struct vdec_output_frameinfo *output_respbuf = NULL; + int rc=1; + if (context == NULL || message == NULL) { + DEBUG_PRINT_ERROR("FATAL ERROR in omx_vdec::async_message_process NULL Check"); + return -1; + } + vdec_msg = (struct vdec_msginfo *)message; + + omx = reinterpret_cast<omx_vdec*>(context); + + switch (vdec_msg->msgcode) { + + case VDEC_MSG_EVT_HW_ERROR: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_HARDWARE_ERROR); + break; + + case VDEC_MSG_RESP_START_DONE: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_START_DONE); + break; + + case VDEC_MSG_RESP_STOP_DONE: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_STOP_DONE); + break; + + case VDEC_MSG_RESP_RESUME_DONE: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_RESUME_DONE); + break; + + case VDEC_MSG_RESP_PAUSE_DONE: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_PAUSE_DONE); + break; + + case VDEC_MSG_RESP_FLUSH_INPUT_DONE: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH); + break; + case VDEC_MSG_RESP_FLUSH_OUTPUT_DONE: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH); + break; + case VDEC_MSG_RESP_INPUT_FLUSHED: + case VDEC_MSG_RESP_INPUT_BUFFER_DONE: + + /* omxhdr = (OMX_BUFFERHEADERTYPE* ) + vdec_msg->msgdata.input_frame_clientdata; */ + + v4l2_buf_ptr = (v4l2_buffer*)vdec_msg->msgdata.input_frame_clientdata; + omxhdr=omx->m_inp_mem_ptr+v4l2_buf_ptr->index; + if (omxhdr == NULL || + ((omxhdr - omx->m_inp_mem_ptr) > omx->drv_ctx.ip_buf.actualcount) ) { + omxhdr = NULL; + vdec_msg->status_code = VDEC_S_EFATAL; + } + + omx->post_event ((unsigned int)omxhdr,vdec_msg->status_code, + OMX_COMPONENT_GENERATE_EBD); + break; + case VDEC_MSG_EVT_INFO_FIELD_DROPPED: + int64_t *timestamp; + timestamp = (int64_t *) malloc(sizeof(int64_t)); + if (timestamp) { + *timestamp = vdec_msg->msgdata.output_frame.time_stamp; + omx->post_event ((unsigned int)timestamp, vdec_msg->status_code, + OMX_COMPONENT_GENERATE_INFO_FIELD_DROPPED); + DEBUG_PRINT_HIGH("Field dropped time stamp is %lld", + vdec_msg->msgdata.output_frame.time_stamp); + } + break; + case VDEC_MSG_RESP_OUTPUT_FLUSHED: + case VDEC_MSG_RESP_OUTPUT_BUFFER_DONE: + + v4l2_buf_ptr = (v4l2_buffer*)vdec_msg->msgdata.output_frame.client_data; + omxhdr=omx->m_out_mem_ptr+v4l2_buf_ptr->index; + DEBUG_PRINT_LOW("[RespBufDone] Buf(%p) Ts(%lld) Pic_type(%u)", + omxhdr, vdec_msg->msgdata.output_frame.time_stamp, + vdec_msg->msgdata.output_frame.pic_type); + + if (omxhdr && omxhdr->pOutputPortPrivate && + ((omxhdr - omx->m_out_mem_ptr) < omx->drv_ctx.op_buf.actualcount) && + (((struct vdec_output_frameinfo *)omxhdr->pOutputPortPrivate + - omx->drv_ctx.ptr_respbuffer) < omx->drv_ctx.op_buf.actualcount)) { + if ( vdec_msg->msgdata.output_frame.len <= omxhdr->nAllocLen) { + omxhdr->nFilledLen = vdec_msg->msgdata.output_frame.len; + omxhdr->nOffset = vdec_msg->msgdata.output_frame.offset; + omxhdr->nTimeStamp = vdec_msg->msgdata.output_frame.time_stamp; + omxhdr->nFlags = omx->m_out_mem_ptr[v4l2_buf_ptr->index].nFlags; + + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_EOS) { + omxhdr->nFlags |= OMX_BUFFERFLAG_EOS; + //rc = -1; + } + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_EOSEQ) { + omxhdr->nFlags |= QOMX_VIDEO_BUFFERFLAG_EOSEQ; + } + vdec_msg->msgdata.output_frame.bufferaddr = + omx->drv_ctx.ptr_outputbuffer[v4l2_buf_ptr->index].bufferaddr; + if (omxhdr->nFilledLen && (((unsigned)omx->rectangle.nLeft != + vdec_msg->msgdata.output_frame.framesize.left) + || ((unsigned)omx->rectangle.nTop != vdec_msg->msgdata.output_frame.framesize.top) + || (omx->rectangle.nWidth != vdec_msg->msgdata.output_frame.framesize.right) + || (omx->rectangle.nHeight != vdec_msg->msgdata.output_frame.framesize.bottom))) { + omx->rectangle.nLeft = vdec_msg->msgdata.output_frame.framesize.left; + omx->rectangle.nTop = vdec_msg->msgdata.output_frame.framesize.top; + omx->rectangle.nWidth = vdec_msg->msgdata.output_frame.framesize.right; + omx->rectangle.nHeight = vdec_msg->msgdata.output_frame.framesize.bottom; + DEBUG_PRINT_HIGH("Crop information has changed"); + omx->post_event (OMX_CORE_OUTPUT_PORT_INDEX, OMX_IndexConfigCommonOutputCrop, + OMX_COMPONENT_GENERATE_PORT_RECONFIG); + } + output_respbuf = (struct vdec_output_frameinfo *)\ + omxhdr->pOutputPortPrivate; + output_respbuf->len = vdec_msg->msgdata.output_frame.len; + output_respbuf->offset = vdec_msg->msgdata.output_frame.offset; + if (v4l2_buf_ptr->flags & V4L2_BUF_FLAG_KEYFRAME) { + output_respbuf->pic_type = PICTURE_TYPE_I; + } + if (v4l2_buf_ptr->flags & V4L2_BUF_FLAG_PFRAME) { + output_respbuf->pic_type = PICTURE_TYPE_P; + } + if (v4l2_buf_ptr->flags & V4L2_BUF_FLAG_BFRAME) { + output_respbuf->pic_type = PICTURE_TYPE_B; + } + + if (omx->output_use_buffer) + memcpy ( omxhdr->pBuffer, (void *) + ((unsigned long)vdec_msg->msgdata.output_frame.bufferaddr + + (unsigned long)vdec_msg->msgdata.output_frame.offset), + vdec_msg->msgdata.output_frame.len); + } else + omxhdr->nFilledLen = 0; + omx->post_event ((unsigned int)omxhdr, vdec_msg->status_code, + OMX_COMPONENT_GENERATE_FBD); + } else if (vdec_msg->msgdata.output_frame.flags & OMX_BUFFERFLAG_EOS) + omx->post_event ((unsigned int)NULL, vdec_msg->status_code, + OMX_COMPONENT_GENERATE_EOS_DONE); + else + omx->post_event ((unsigned int)NULL, vdec_msg->status_code, + OMX_COMPONENT_GENERATE_HARDWARE_ERROR); + break; + case VDEC_MSG_EVT_CONFIG_CHANGED: + DEBUG_PRINT_HIGH("Port settings changed"); + omx->post_event (OMX_CORE_OUTPUT_PORT_INDEX, OMX_IndexParamPortDefinition, + OMX_COMPONENT_GENERATE_PORT_RECONFIG); + break; + case VDEC_MSG_EVT_INFO_CONFIG_CHANGED: + { + DEBUG_PRINT_HIGH("Port settings changed info"); + // get_buffer_req and populate port defn structure + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_format fmt; + int ret; + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + ret = ioctl(omx->drv_ctx.video_driver_fd, VIDIOC_G_FMT, &fmt); + omx->update_resolution(fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height); + omx->drv_ctx.video_resolution.stride = fmt.fmt.pix_mp.plane_fmt[0].bytesperline; + omx->drv_ctx.video_resolution.scan_lines = fmt.fmt.pix_mp.plane_fmt[0].reserved[0]; + omx->m_port_def.nPortIndex = 1; + eRet = omx->update_portdef(&(omx->m_port_def)); + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_INFO_PORT_RECONFIG); + break; + } + default: + break; + } + return rc; +} + +OMX_ERRORTYPE omx_vdec::empty_this_buffer_proxy_arbitrary ( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ) +{ + unsigned address,p2,id; + DEBUG_PRINT_LOW("Empty this arbitrary"); + + if (buffer == NULL) { + return OMX_ErrorBadParameter; + } + DEBUG_PRINT_LOW("ETBProxyArb: bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer); + DEBUG_PRINT_LOW("ETBProxyArb: nFilledLen %u, flags %d, timestamp %u", + buffer->nFilledLen, buffer->nFlags, (unsigned)buffer->nTimeStamp); + + /* return zero length and not an EOS buffer */ + /* return buffer if input flush in progress */ + if ((input_flush_progress == true) || ((buffer->nFilledLen == 0) && + ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == 0))) { + DEBUG_PRINT_HIGH("return zero legth buffer or flush in progress"); + m_cb.EmptyBufferDone (hComp,m_app_data,buffer); + return OMX_ErrorNone; + } + + if (psource_frame == NULL) { + DEBUG_PRINT_LOW("Set Buffer as source Buffer %p time stamp %d",buffer,buffer->nTimeStamp); + psource_frame = buffer; + DEBUG_PRINT_LOW("Try to Push One Input Buffer "); + push_input_buffer (hComp); + } else { + DEBUG_PRINT_LOW("Push the source buffer into pendingq %p",buffer); + if (!m_input_pending_q.insert_entry((unsigned)buffer, (unsigned)NULL, + (unsigned)NULL)) { + return OMX_ErrorBadParameter; + } + } + + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::push_input_buffer (OMX_HANDLETYPE hComp) +{ + unsigned address,p2,id; + OMX_ERRORTYPE ret = OMX_ErrorNone; + + if (pdest_frame == NULL || psource_frame == NULL) { + /*Check if we have a destination buffer*/ + if (pdest_frame == NULL) { + DEBUG_PRINT_LOW("Get a Destination buffer from the queue"); + if (m_input_free_q.m_size) { + m_input_free_q.pop_entry(&address,&p2,&id); + pdest_frame = (OMX_BUFFERHEADERTYPE *)address; + pdest_frame->nFilledLen = 0; + pdest_frame->nTimeStamp = LLONG_MAX; + DEBUG_PRINT_LOW("Address of Pmem Buffer %p",pdest_frame); + } + } + + /*Check if we have a destination buffer*/ + if (psource_frame == NULL) { + DEBUG_PRINT_LOW("Get a source buffer from the queue"); + if (m_input_pending_q.m_size) { + m_input_pending_q.pop_entry(&address,&p2,&id); + psource_frame = (OMX_BUFFERHEADERTYPE *)address; + DEBUG_PRINT_LOW("Next source Buffer %p time stamp %d",psource_frame, + psource_frame->nTimeStamp); + DEBUG_PRINT_LOW("Next source Buffer flag %d length %d", + psource_frame->nFlags,psource_frame->nFilledLen); + + } + } + + } + + while ((pdest_frame != NULL) && (psource_frame != NULL)) { + switch (codec_type_parse) { + case CODEC_TYPE_MPEG4: + case CODEC_TYPE_H263: + case CODEC_TYPE_MPEG2: + ret = push_input_sc_codec(hComp); + break; + case CODEC_TYPE_H264: + ret = push_input_h264(hComp); + break; + case CODEC_TYPE_HEVC: + ret = push_input_hevc(hComp); + break; + case CODEC_TYPE_VC1: + ret = push_input_vc1(hComp); + break; + default: + break; + } + if (ret != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("Pushing input Buffer Failed"); + omx_report_error (); + break; + } + } + + return ret; +} + +OMX_ERRORTYPE omx_vdec::push_input_sc_codec(OMX_HANDLETYPE hComp) +{ + OMX_U32 partial_frame = 1; + OMX_BOOL generate_ebd = OMX_TRUE; + unsigned address,p2,id; + + DEBUG_PRINT_LOW("Start Parsing the bit stream address %p TimeStamp %d", + psource_frame,psource_frame->nTimeStamp); + if (m_frame_parser.parse_sc_frame(psource_frame, + pdest_frame,&partial_frame) == -1) { + DEBUG_PRINT_ERROR("Error In Parsing Return Error"); + return OMX_ErrorBadParameter; + } + + if (partial_frame == 0) { + DEBUG_PRINT_LOW("Frame size %d source %p frame count %d", + pdest_frame->nFilledLen,psource_frame,frame_count); + + + DEBUG_PRINT_LOW("TimeStamp updated %d",pdest_frame->nTimeStamp); + /*First Parsed buffer will have only header Hence skip*/ + if (frame_count == 0) { + DEBUG_PRINT_LOW("H263/MPEG4 Codec First Frame "); + + if (codec_type_parse == CODEC_TYPE_MPEG4 || + codec_type_parse == CODEC_TYPE_DIVX) { + mp4StreamType psBits; + psBits.data = pdest_frame->pBuffer + pdest_frame->nOffset; + psBits.numBytes = pdest_frame->nFilledLen; + mp4_headerparser.parseHeader(&psBits); + } + + frame_count++; + } else { + pdest_frame->nFlags &= ~OMX_BUFFERFLAG_EOS; + if (pdest_frame->nFilledLen) { + /*Push the frame to the Decoder*/ + if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + frame_count++; + pdest_frame = NULL; + + if (m_input_free_q.m_size) { + m_input_free_q.pop_entry(&address,&p2,&id); + pdest_frame = (OMX_BUFFERHEADERTYPE *) address; + pdest_frame->nFilledLen = 0; + } + } else if (!(psource_frame->nFlags & OMX_BUFFERFLAG_EOS)) { + DEBUG_PRINT_ERROR("Zero len buffer return back to POOL"); + m_input_free_q.insert_entry((unsigned) pdest_frame, (unsigned)NULL, + (unsigned)NULL); + pdest_frame = NULL; + } + } + } else { + DEBUG_PRINT_LOW("Not a Complete Frame %d",pdest_frame->nFilledLen); + /*Check if Destination Buffer is full*/ + if (pdest_frame->nAllocLen == + pdest_frame->nFilledLen + pdest_frame->nOffset) { + DEBUG_PRINT_ERROR("ERROR:Frame Not found though Destination Filled"); + return OMX_ErrorStreamCorrupt; + } + } + + if (psource_frame->nFilledLen == 0) { + if (psource_frame->nFlags & OMX_BUFFERFLAG_EOS) { + if (pdest_frame) { + pdest_frame->nFlags |= psource_frame->nFlags; + DEBUG_PRINT_LOW("Frame Found start Decoding Size =%d TimeStamp = %x", + pdest_frame->nFilledLen,pdest_frame->nTimeStamp); + DEBUG_PRINT_LOW("Found a frame size = %d number = %d", + pdest_frame->nFilledLen,frame_count++); + /*Push the frame to the Decoder*/ + if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + frame_count++; + pdest_frame = NULL; + } else { + DEBUG_PRINT_LOW("Last frame in else dest addr") ; + generate_ebd = OMX_FALSE; + } + } + if (generate_ebd) { + DEBUG_PRINT_LOW("Buffer Consumed return back to client %p",psource_frame); + m_cb.EmptyBufferDone (hComp,m_app_data,psource_frame); + psource_frame = NULL; + + if (m_input_pending_q.m_size) { + DEBUG_PRINT_LOW("Pull Next source Buffer %p",psource_frame); + m_input_pending_q.pop_entry(&address,&p2,&id); + psource_frame = (OMX_BUFFERHEADERTYPE *) address; + DEBUG_PRINT_LOW("Next source Buffer %p time stamp %d",psource_frame, + psource_frame->nTimeStamp); + DEBUG_PRINT_LOW("Next source Buffer flag %d length %d", + psource_frame->nFlags,psource_frame->nFilledLen); + } + } + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::push_input_h264 (OMX_HANDLETYPE hComp) +{ + OMX_U32 partial_frame = 1; + unsigned address,p2,id; + OMX_BOOL isNewFrame = OMX_FALSE; + OMX_BOOL generate_ebd = OMX_TRUE; + + if (h264_scratch.pBuffer == NULL) { + DEBUG_PRINT_ERROR("ERROR:H.264 Scratch Buffer not allocated"); + return OMX_ErrorBadParameter; + } + DEBUG_PRINT_LOW("Pending h264_scratch.nFilledLen %d " + "look_ahead_nal %d", h264_scratch.nFilledLen, look_ahead_nal); + DEBUG_PRINT_LOW("Pending pdest_frame->nFilledLen %d",pdest_frame->nFilledLen); + if (h264_scratch.nFilledLen && look_ahead_nal) { + look_ahead_nal = false; + if ((pdest_frame->nAllocLen - pdest_frame->nFilledLen) >= + h264_scratch.nFilledLen) { + memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen), + h264_scratch.pBuffer,h264_scratch.nFilledLen); + pdest_frame->nFilledLen += h264_scratch.nFilledLen; + DEBUG_PRINT_LOW("Copy the previous NAL (h264 scratch) into Dest frame"); + h264_scratch.nFilledLen = 0; + } else { + DEBUG_PRINT_ERROR("Error:1: Destination buffer overflow for H264"); + return OMX_ErrorBadParameter; + } + } + if (nal_length == 0) { + DEBUG_PRINT_LOW("Zero NAL, hence parse using start code"); + if (m_frame_parser.parse_sc_frame(psource_frame, + &h264_scratch,&partial_frame) == -1) { + DEBUG_PRINT_ERROR("Error In Parsing Return Error"); + return OMX_ErrorBadParameter; + } + } else { + DEBUG_PRINT_LOW("Non-zero NAL length clip, hence parse with NAL size %d ",nal_length); + if (m_frame_parser.parse_h264_nallength(psource_frame, + &h264_scratch,&partial_frame) == -1) { + DEBUG_PRINT_ERROR("Error In Parsing NAL size, Return Error"); + return OMX_ErrorBadParameter; + } + } + + if (partial_frame == 0) { + if (nal_count == 0 && h264_scratch.nFilledLen == 0) { + DEBUG_PRINT_LOW("First NAL with Zero Length, hence Skip"); + nal_count++; + h264_scratch.nTimeStamp = psource_frame->nTimeStamp; + h264_scratch.nFlags = psource_frame->nFlags; + } else { + DEBUG_PRINT_LOW("Parsed New NAL Length = %d",h264_scratch.nFilledLen); + if (h264_scratch.nFilledLen) { + h264_parser->parse_nal((OMX_U8*)h264_scratch.pBuffer, h264_scratch.nFilledLen, + NALU_TYPE_SPS); +#ifndef PROCESS_EXTRADATA_IN_OUTPUT_PORT + if (client_extradata & OMX_TIMEINFO_EXTRADATA) + h264_parser->parse_nal((OMX_U8*)h264_scratch.pBuffer, + h264_scratch.nFilledLen, NALU_TYPE_SEI); + else if (client_extradata & OMX_FRAMEINFO_EXTRADATA) + // If timeinfo is present frame info from SEI is already processed + h264_parser->parse_nal((OMX_U8*)h264_scratch.pBuffer, + h264_scratch.nFilledLen, NALU_TYPE_SEI); +#endif + m_frame_parser.mutils->isNewFrame(&h264_scratch, 0, isNewFrame); + nal_count++; + if (VALID_TS(h264_last_au_ts) && !VALID_TS(pdest_frame->nTimeStamp)) { + pdest_frame->nTimeStamp = h264_last_au_ts; + pdest_frame->nFlags = h264_last_au_flags; +#ifdef PANSCAN_HDLR + if (client_extradata & OMX_FRAMEINFO_EXTRADATA) + h264_parser->update_panscan_data(h264_last_au_ts); +#endif + } + if (m_frame_parser.mutils->nalu_type == NALU_TYPE_NON_IDR || + m_frame_parser.mutils->nalu_type == NALU_TYPE_IDR) { + h264_last_au_ts = h264_scratch.nTimeStamp; + h264_last_au_flags = h264_scratch.nFlags; +#ifndef PROCESS_EXTRADATA_IN_OUTPUT_PORT + if (client_extradata & OMX_TIMEINFO_EXTRADATA) { + OMX_S64 ts_in_sei = h264_parser->process_ts_with_sei_vui(h264_last_au_ts); + if (!VALID_TS(h264_last_au_ts)) + h264_last_au_ts = ts_in_sei; + } +#endif + } else + h264_last_au_ts = LLONG_MAX; + } + + if (!isNewFrame) { + if ( (pdest_frame->nAllocLen - pdest_frame->nFilledLen) >= + h264_scratch.nFilledLen) { + DEBUG_PRINT_LOW("Not a NewFrame Copy into Dest len %d", + h264_scratch.nFilledLen); + memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen), + h264_scratch.pBuffer,h264_scratch.nFilledLen); + pdest_frame->nFilledLen += h264_scratch.nFilledLen; + if (m_frame_parser.mutils->nalu_type == NALU_TYPE_EOSEQ) + pdest_frame->nFlags |= QOMX_VIDEO_BUFFERFLAG_EOSEQ; + h264_scratch.nFilledLen = 0; + } else { + DEBUG_PRINT_LOW("Error:2: Destination buffer overflow for H264"); + return OMX_ErrorBadParameter; + } + } else { + look_ahead_nal = true; + DEBUG_PRINT_LOW("Frame Found start Decoding Size =%d TimeStamp = %x", + pdest_frame->nFilledLen,pdest_frame->nTimeStamp); + DEBUG_PRINT_LOW("Found a frame size = %d number = %d", + pdest_frame->nFilledLen,frame_count++); + + if (pdest_frame->nFilledLen == 0) { + DEBUG_PRINT_LOW("Copy the Current Frame since and push it"); + look_ahead_nal = false; + if ( (pdest_frame->nAllocLen - pdest_frame->nFilledLen) >= + h264_scratch.nFilledLen) { + memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen), + h264_scratch.pBuffer,h264_scratch.nFilledLen); + pdest_frame->nFilledLen += h264_scratch.nFilledLen; + h264_scratch.nFilledLen = 0; + } else { + DEBUG_PRINT_ERROR("Error:3: Destination buffer overflow for H264"); + return OMX_ErrorBadParameter; + } + } else { + if (psource_frame->nFilledLen || h264_scratch.nFilledLen) { + DEBUG_PRINT_LOW("Reset the EOS Flag"); + pdest_frame->nFlags &= ~OMX_BUFFERFLAG_EOS; + } + /*Push the frame to the Decoder*/ + if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + //frame_count++; + pdest_frame = NULL; + if (m_input_free_q.m_size) { + m_input_free_q.pop_entry(&address,&p2,&id); + pdest_frame = (OMX_BUFFERHEADERTYPE *) address; + DEBUG_PRINT_LOW("Pop the next pdest_buffer %p",pdest_frame); + pdest_frame->nFilledLen = 0; + pdest_frame->nFlags = 0; + pdest_frame->nTimeStamp = LLONG_MAX; + } + } + } + } + } else { + DEBUG_PRINT_LOW("Not a Complete Frame, pdest_frame->nFilledLen %d",pdest_frame->nFilledLen); + /*Check if Destination Buffer is full*/ + if (h264_scratch.nAllocLen == + h264_scratch.nFilledLen + h264_scratch.nOffset) { + DEBUG_PRINT_ERROR("ERROR: Frame Not found though Destination Filled"); + return OMX_ErrorStreamCorrupt; + } + } + + if (!psource_frame->nFilledLen) { + DEBUG_PRINT_LOW("Buffer Consumed return source %p back to client",psource_frame); + + if (psource_frame->nFlags & OMX_BUFFERFLAG_EOS) { + if (pdest_frame) { + DEBUG_PRINT_LOW("EOS Reached Pass Last Buffer"); + if ( (pdest_frame->nAllocLen - pdest_frame->nFilledLen) >= + h264_scratch.nFilledLen) { + memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen), + h264_scratch.pBuffer,h264_scratch.nFilledLen); + pdest_frame->nFilledLen += h264_scratch.nFilledLen; + h264_scratch.nFilledLen = 0; + } else { + DEBUG_PRINT_ERROR("ERROR:4: Destination buffer overflow for H264"); + return OMX_ErrorBadParameter; + } + pdest_frame->nTimeStamp = h264_scratch.nTimeStamp; + pdest_frame->nFlags = h264_scratch.nFlags | psource_frame->nFlags; + + DEBUG_PRINT_LOW("pdest_frame->nFilledLen =%d TimeStamp = %x", + pdest_frame->nFilledLen,pdest_frame->nTimeStamp); + DEBUG_PRINT_LOW("Push AU frame number %d to driver", frame_count++); +#ifndef PROCESS_EXTRADATA_IN_OUTPUT_PORT + if (client_extradata & OMX_TIMEINFO_EXTRADATA) { + OMX_S64 ts_in_sei = h264_parser->process_ts_with_sei_vui(pdest_frame->nTimeStamp); + if (!VALID_TS(pdest_frame->nTimeStamp)) + pdest_frame->nTimeStamp = ts_in_sei; + } +#endif + /*Push the frame to the Decoder*/ + if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + frame_count++; + pdest_frame = NULL; + } else { + DEBUG_PRINT_LOW("Last frame in else dest addr %p size %d", + pdest_frame,h264_scratch.nFilledLen); + generate_ebd = OMX_FALSE; + } + } + } + if (generate_ebd && !psource_frame->nFilledLen) { + m_cb.EmptyBufferDone (hComp,m_app_data,psource_frame); + psource_frame = NULL; + if (m_input_pending_q.m_size) { + DEBUG_PRINT_LOW("Pull Next source Buffer %p",psource_frame); + m_input_pending_q.pop_entry(&address,&p2,&id); + psource_frame = (OMX_BUFFERHEADERTYPE *) address; + DEBUG_PRINT_LOW("Next source Buffer flag %d src length %d", + psource_frame->nFlags,psource_frame->nFilledLen); + } + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE copy_buffer(OMX_BUFFERHEADERTYPE* pDst, OMX_BUFFERHEADERTYPE* pSrc) +{ + OMX_ERRORTYPE rc = OMX_ErrorNone; + if ((pDst->nAllocLen - pDst->nFilledLen) >= pSrc->nFilledLen) { + memcpy ((pDst->pBuffer + pDst->nFilledLen), pSrc->pBuffer, pSrc->nFilledLen); + if (pDst->nTimeStamp == LLONG_MAX) { + pDst->nTimeStamp = pSrc->nTimeStamp; + DEBUG_PRINT_LOW("Assign Dst nTimeStamp=%lld", pDst->nTimeStamp); + } + pDst->nFilledLen += pSrc->nFilledLen; + pSrc->nFilledLen = 0; + } else { + DEBUG_PRINT_ERROR("Error: Destination buffer overflow"); + rc = OMX_ErrorBadParameter; + } + return rc; +} + +OMX_ERRORTYPE omx_vdec::push_input_hevc (OMX_HANDLETYPE hComp) +{ + OMX_U32 partial_frame = 1; + unsigned address,p2,id; + OMX_BOOL isNewFrame = OMX_FALSE; + OMX_BOOL generate_ebd = OMX_TRUE; + OMX_ERRORTYPE rc = OMX_ErrorNone; + + if (h264_scratch.pBuffer == NULL) { + DEBUG_PRINT_ERROR("ERROR:Hevc Scratch Buffer not allocated"); + return OMX_ErrorBadParameter; + } + + + DEBUG_PRINT_LOW("h264_scratch.nFilledLen %d has look_ahead_nal %d pdest_frame nFilledLen %d nTimeStamp %lld", + h264_scratch.nFilledLen, look_ahead_nal, pdest_frame->nFilledLen, pdest_frame->nTimeStamp); + + if (h264_scratch.nFilledLen && look_ahead_nal) { + look_ahead_nal = false; + + // copy the lookahead buffer in the scratch + rc = copy_buffer(pdest_frame, &h264_scratch); + if (rc != OMX_ErrorNone) { + return rc; + } + } + if (nal_length == 0) { + if (m_frame_parser.parse_sc_frame(psource_frame, + &h264_scratch,&partial_frame) == -1) { + DEBUG_PRINT_ERROR("Error In Parsing Return Error"); + return OMX_ErrorBadParameter; + } + } else { + DEBUG_PRINT_LOW("Non-zero NAL length clip, hence parse with NAL size %d",nal_length); + if (m_frame_parser.parse_h264_nallength(psource_frame, + &h264_scratch,&partial_frame) == -1) { + DEBUG_PRINT_ERROR("Error In Parsing NAL size, Return Error"); + return OMX_ErrorBadParameter; + } + } + + if (partial_frame == 0) { + if (nal_count == 0 && h264_scratch.nFilledLen == 0) { + DEBUG_PRINT_LOW("First NAL with Zero Length, hence Skip"); + nal_count++; + h264_scratch.nTimeStamp = psource_frame->nTimeStamp; + h264_scratch.nFlags = psource_frame->nFlags; + } else { + DEBUG_PRINT_LOW("Parsed New NAL Length = %d",h264_scratch.nFilledLen); + if (h264_scratch.nFilledLen) { + mHEVCutils.isNewFrame(&h264_scratch, 0, isNewFrame); + nal_count++; + } + + if (!isNewFrame) { + DEBUG_PRINT_LOW("Not a new frame, copy h264_scratch nFilledLen %d nTimestamp %lld, pdest_frame nFilledLen %d nTimestamp %lld", + h264_scratch.nFilledLen, h264_scratch.nTimeStamp, pdest_frame->nFilledLen, pdest_frame->nTimeStamp); + rc = copy_buffer(pdest_frame, &h264_scratch); + if ( rc != OMX_ErrorNone) { + return rc; + } + } else { + look_ahead_nal = true; + if (pdest_frame->nFilledLen == 0) { + look_ahead_nal = false; + DEBUG_PRINT_LOW("dest nation buffer empty, copy scratch buffer"); + rc = copy_buffer(pdest_frame, &h264_scratch); + if ( rc != OMX_ErrorNone ) { + return OMX_ErrorBadParameter; + } + } else { + if (psource_frame->nFilledLen || h264_scratch.nFilledLen) { + pdest_frame->nFlags &= ~OMX_BUFFERFLAG_EOS; + } + + DEBUG_PRINT_LOW("FrameDetecetd # %d pdest_frame nFilledLen %d nTimeStamp %lld, look_ahead_nal in h264_scratch nFilledLen %d nTimeStamp %lld", + frame_count++, pdest_frame->nFilledLen, pdest_frame->nTimeStamp, h264_scratch.nFilledLen, h264_scratch.nTimeStamp); + if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + pdest_frame = NULL; + if (m_input_free_q.m_size) { + m_input_free_q.pop_entry(&address,&p2,&id); + pdest_frame = (OMX_BUFFERHEADERTYPE *) address; + DEBUG_PRINT_LOW("pop the next pdest_buffer %p",pdest_frame); + pdest_frame->nFilledLen = 0; + pdest_frame->nFlags = 0; + pdest_frame->nTimeStamp = LLONG_MAX; + } + } + } + } + } else { + DEBUG_PRINT_LOW("psource_frame is partial nFilledLen %d nTimeStamp %lld, pdest_frame nFilledLen %d nTimeStamp %lld, h264_scratch nFilledLen %d nTimeStamp %lld", + psource_frame->nFilledLen, psource_frame->nTimeStamp, pdest_frame->nFilledLen, pdest_frame->nTimeStamp, h264_scratch.nFilledLen, h264_scratch.nTimeStamp); + + /*Check if Destination Buffer is full*/ + if (h264_scratch.nAllocLen == + h264_scratch.nFilledLen + h264_scratch.nOffset) { + DEBUG_PRINT_ERROR("ERROR: Frame Not found though Destination Filled"); + return OMX_ErrorStreamCorrupt; + } + } + + if (!psource_frame->nFilledLen) { + DEBUG_PRINT_LOW("Buffer Consumed return source %p back to client",psource_frame); + + if (psource_frame->nFlags & OMX_BUFFERFLAG_EOS) { + if (pdest_frame) { + DEBUG_PRINT_LOW("EOS Reached Pass Last Buffer"); + rc = copy_buffer(pdest_frame, &h264_scratch); + if ( rc != OMX_ErrorNone ) { + return rc; + } + pdest_frame->nTimeStamp = h264_scratch.nTimeStamp; + pdest_frame->nFlags = h264_scratch.nFlags | psource_frame->nFlags; + + DEBUG_PRINT_LOW("Push EOS frame number:%d nFilledLen =%d TimeStamp = %lld", + frame_count, pdest_frame->nFilledLen,pdest_frame->nTimeStamp); + + /*Push the frame to the Decoder*/ + if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + frame_count++; + pdest_frame = NULL; + } else { + DEBUG_PRINT_LOW("Last frame in else dest addr %p size %d", + pdest_frame,h264_scratch.nFilledLen); + generate_ebd = OMX_FALSE; + } + } + } + if (generate_ebd && !psource_frame->nFilledLen) { + m_cb.EmptyBufferDone (hComp,m_app_data,psource_frame); + psource_frame = NULL; + if (m_input_pending_q.m_size) { + m_input_pending_q.pop_entry(&address,&p2,&id); + psource_frame = (OMX_BUFFERHEADERTYPE *) address; + DEBUG_PRINT_LOW("Next source Buffer flag %d nFilledLen %d, nTimeStamp %lld", + psource_frame->nFlags,psource_frame->nFilledLen, psource_frame->nTimeStamp); + } + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::push_input_vc1 (OMX_HANDLETYPE hComp) +{ + OMX_U8 *buf, *pdest; + OMX_U32 partial_frame = 1; + OMX_U32 buf_len, dest_len; + + if (first_frame == 0) { + first_frame = 1; + DEBUG_PRINT_LOW("First i/p buffer for VC1 arbitrary bytes"); + if (!m_vendor_config.pData) { + DEBUG_PRINT_LOW("Check profile type in 1st source buffer"); + buf = psource_frame->pBuffer; + buf_len = psource_frame->nFilledLen; + + if ((*((OMX_U32 *) buf) & VC1_SP_MP_START_CODE_MASK) == + VC1_SP_MP_START_CODE) { + m_vc1_profile = VC1_SP_MP_RCV; + } else if (*((OMX_U32 *) buf) & VC1_AP_SEQ_START_CODE) { + m_vc1_profile = VC1_AP; + } else { + DEBUG_PRINT_ERROR("Invalid sequence layer in first buffer"); + return OMX_ErrorStreamCorrupt; + } + } else { + pdest = pdest_frame->pBuffer + pdest_frame->nFilledLen + + pdest_frame->nOffset; + dest_len = pdest_frame->nAllocLen - (pdest_frame->nFilledLen + + pdest_frame->nOffset); + + if (dest_len < m_vendor_config.nDataSize) { + DEBUG_PRINT_ERROR("Destination buffer full"); + return OMX_ErrorBadParameter; + } else { + memcpy(pdest, m_vendor_config.pData, m_vendor_config.nDataSize); + pdest_frame->nFilledLen += m_vendor_config.nDataSize; + } + } + } + + switch (m_vc1_profile) { + case VC1_AP: + DEBUG_PRINT_LOW("VC1 AP, hence parse using frame start code"); + if (push_input_sc_codec(hComp) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("Error In Parsing VC1 AP start code"); + return OMX_ErrorBadParameter; + } + break; + + case VC1_SP_MP_RCV: + default: + DEBUG_PRINT_ERROR("Unsupported VC1 profile in ArbitraryBytes Mode"); + return OMX_ErrorBadParameter; + } + return OMX_ErrorNone; +} + +bool omx_vdec::align_pmem_buffers(int pmem_fd, OMX_U32 buffer_size, + OMX_U32 alignment) +{ + struct pmem_allocation allocation; + allocation.size = buffer_size; + allocation.align = clip2(alignment); + if (allocation.align < 4096) { + allocation.align = 4096; + } + if (ioctl(pmem_fd, PMEM_ALLOCATE_ALIGNED, &allocation) < 0) { + DEBUG_PRINT_ERROR("Aligment(%u) failed with pmem driver Sz(%lu)", + allocation.align, allocation.size); + return false; + } + return true; +} +#ifdef USE_ION +int omx_vdec::alloc_map_ion_memory(OMX_U32 buffer_size, + OMX_U32 alignment, struct ion_allocation_data *alloc_data, + struct ion_fd_data *fd_data, int flag) +{ + int fd = -EINVAL; + int rc = -EINVAL; + int ion_dev_flag; + struct vdec_ion ion_buf_info; + if (!alloc_data || buffer_size <= 0 || !fd_data) { + DEBUG_PRINT_ERROR("Invalid arguments to alloc_map_ion_memory"); + return -EINVAL; + } + ion_dev_flag = O_RDONLY; + fd = open (MEM_DEVICE, ion_dev_flag); + if (fd < 0) { + DEBUG_PRINT_ERROR("opening ion device failed with fd = %d", fd); + return fd; + } + alloc_data->flags = 0; + if (!secure_mode && (flag & ION_FLAG_CACHED)) { + alloc_data->flags |= ION_FLAG_CACHED; + } + alloc_data->len = buffer_size; + alloc_data->align = clip2(alignment); + if (alloc_data->align < 4096) { + alloc_data->align = 4096; + } + if ((secure_mode) && (flag & ION_SECURE)) + alloc_data->flags |= ION_SECURE; + +#ifdef _HEVC_USE_ADSP_HEAP_ + alloc_data->heap_id_mask = ION_HEAP(ION_ADSP_HEAP_ID); +#else + alloc_data->heap_id_mask = ION_HEAP(ION_IOMMU_HEAP_ID); +#endif + if (secure_mode) { + alloc_data->heap_id_mask = ION_HEAP(MEM_HEAP_ID); + } + rc = ioctl(fd,ION_IOC_ALLOC,alloc_data); + if (rc || !alloc_data->handle) { + DEBUG_PRINT_ERROR("ION ALLOC memory failed "); + alloc_data->handle = NULL; + close(fd); + fd = -ENOMEM; + return fd; + } + fd_data->handle = alloc_data->handle; + rc = ioctl(fd,ION_IOC_MAP,fd_data); + if (rc) { + DEBUG_PRINT_ERROR("ION MAP failed "); + ion_buf_info.ion_alloc_data = *alloc_data; + ion_buf_info.ion_device_fd = fd; + ion_buf_info.fd_ion_data = *fd_data; + free_ion_memory(&ion_buf_info); + fd_data->fd =-1; + fd = -ENOMEM; + } + + return fd; +} + +void omx_vdec::free_ion_memory(struct vdec_ion *buf_ion_info) +{ + + if (!buf_ion_info) { + DEBUG_PRINT_ERROR("ION: free called with invalid fd/allocdata"); + return; + } + if (ioctl(buf_ion_info->ion_device_fd,ION_IOC_FREE, + &buf_ion_info->ion_alloc_data.handle)) { + DEBUG_PRINT_ERROR("ION: free failed" ); + } + close(buf_ion_info->ion_device_fd); + buf_ion_info->ion_device_fd = -1; + buf_ion_info->ion_alloc_data.handle = NULL; + buf_ion_info->fd_ion_data.fd = -1; +} +#endif +void omx_vdec::free_output_buffer_header() +{ + DEBUG_PRINT_HIGH("ALL output buffers are freed/released"); + output_use_buffer = false; + ouput_egl_buffers = false; + + if (m_out_mem_ptr) { + free (m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + + if (m_platform_list) { + free(m_platform_list); + m_platform_list = NULL; + } + + if (drv_ctx.ptr_respbuffer) { + free (drv_ctx.ptr_respbuffer); + drv_ctx.ptr_respbuffer = NULL; + } + if (drv_ctx.ptr_outputbuffer) { + free (drv_ctx.ptr_outputbuffer); + drv_ctx.ptr_outputbuffer = NULL; + } +#ifdef USE_ION + if (drv_ctx.op_buf_ion_info) { + DEBUG_PRINT_LOW("Free o/p ion context"); + free(drv_ctx.op_buf_ion_info); + drv_ctx.op_buf_ion_info = NULL; + } +#endif +} + +void omx_vdec::free_input_buffer_header() +{ + input_use_buffer = false; + if (arbitrary_bytes) { + if (m_frame_parser.mutils) { + DEBUG_PRINT_LOW("Free utils parser"); + delete (m_frame_parser.mutils); + m_frame_parser.mutils = NULL; + } + + if (m_inp_heap_ptr) { + DEBUG_PRINT_LOW("Free input Heap Pointer"); + free (m_inp_heap_ptr); + m_inp_heap_ptr = NULL; + } + + if (m_phdr_pmem_ptr) { + DEBUG_PRINT_LOW("Free input pmem header Pointer"); + free (m_phdr_pmem_ptr); + m_phdr_pmem_ptr = NULL; + } + } + if (m_inp_mem_ptr) { + DEBUG_PRINT_LOW("Free input pmem Pointer area"); + free (m_inp_mem_ptr); + m_inp_mem_ptr = NULL; + } + if (drv_ctx.ptr_inputbuffer) { + DEBUG_PRINT_LOW("Free Driver Context pointer"); + free (drv_ctx.ptr_inputbuffer); + drv_ctx.ptr_inputbuffer = NULL; + } +#ifdef USE_ION + if (drv_ctx.ip_buf_ion_info) { + DEBUG_PRINT_LOW("Free ion context"); + free(drv_ctx.ip_buf_ion_info); + drv_ctx.ip_buf_ion_info = NULL; + } +#endif +} + +int omx_vdec::stream_off(OMX_U32 port) +{ + enum v4l2_buf_type btype; + int rc = 0; + enum v4l2_ports v4l2_port = OUTPUT_PORT; + + if (port == OMX_CORE_INPUT_PORT_INDEX) { + btype = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + v4l2_port = OUTPUT_PORT; + } else if (port == OMX_CORE_OUTPUT_PORT_INDEX) { + btype = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_port = CAPTURE_PORT; + } else if (port == OMX_ALL) { + int rc_input = stream_off(OMX_CORE_INPUT_PORT_INDEX); + int rc_output = stream_off(OMX_CORE_OUTPUT_PORT_INDEX); + + if (!rc_input) + return rc_input; + else + return rc_output; + } + + if (!streaming[v4l2_port]) { + // already streamed off, warn and move on + DEBUG_PRINT_HIGH("Warning: Attempting to stream off on %d port," + " which is already streamed off", v4l2_port); + return 0; + } + + DEBUG_PRINT_HIGH("Streaming off %d port", v4l2_port); + + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMOFF, &btype); + if (rc) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to call streamoff on %d Port", v4l2_port); + } else { + streaming[v4l2_port] = false; + } + + return rc; +} + +OMX_ERRORTYPE omx_vdec::get_buffer_req(vdec_allocatorproperty *buffer_prop) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_requestbuffers bufreq; + unsigned int buf_size = 0, extra_data_size = 0, client_extra_data_size = 0; + struct v4l2_format fmt; + int ret = 0; + + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = 1; + if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_INPUT) { + bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.type =V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.pixelformat = output_capability; + } else if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { + bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.type =V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = capture_capability; + } else { + eRet = OMX_ErrorBadParameter; + } + if (eRet==OMX_ErrorNone) { + ret = ioctl(drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); + } + if (ret) { + DEBUG_PRINT_ERROR("Requesting buffer requirements failed"); + /*TODO: How to handle this case */ + eRet = OMX_ErrorInsufficientResources; + return eRet; + } else { + buffer_prop->actualcount = bufreq.count; + buffer_prop->mincount = bufreq.count; + DEBUG_PRINT_HIGH("Count = %d",bufreq.count); + } + DEBUG_PRINT_HIGH("GetBufReq: ActCnt(%d) Size(%d), BufType(%d)", + buffer_prop->actualcount, buffer_prop->buffer_size, buffer_prop->buffer_type); + + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_G_FMT, &fmt); + + update_resolution(fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height); + if (fmt.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + drv_ctx.num_planes = fmt.fmt.pix_mp.num_planes; + DEBUG_PRINT_HIGH("Buffer Size (plane[0].sizeimage) = %d",fmt.fmt.pix_mp.plane_fmt[0].sizeimage); + + if (ret) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Requesting buffer requirements failed"); + eRet = OMX_ErrorInsufficientResources; + } else { + int extra_idx = 0; + buffer_prop->buffer_size = fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + buf_size = buffer_prop->buffer_size; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + extra_data_size = fmt.fmt.pix_mp.plane_fmt[extra_idx].sizeimage; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index is more than allowed: %d", extra_idx); + return OMX_ErrorBadParameter; + } + if (client_extradata & OMX_FRAMEINFO_EXTRADATA) { + DEBUG_PRINT_HIGH("Frame info extra data enabled!"); + client_extra_data_size += OMX_FRAMEINFO_EXTRADATA_SIZE; + } + if (client_extradata & OMX_INTERLACE_EXTRADATA) { + client_extra_data_size += OMX_INTERLACE_EXTRADATA_SIZE; + } + if (client_extradata & OMX_PORTDEF_EXTRADATA) { + client_extra_data_size += OMX_PORTDEF_EXTRADATA_SIZE; + DEBUG_PRINT_HIGH("Smooth streaming enabled extra_data_size=%d", + client_extra_data_size); + } + if (client_extra_data_size) { + client_extra_data_size += sizeof(OMX_OTHER_EXTRADATATYPE); //Space for terminator + buf_size = ((buf_size + 3)&(~3)); //Align extradata start address to 64Bit + } + drv_ctx.extradata_info.size = buffer_prop->actualcount * extra_data_size; + drv_ctx.extradata_info.count = buffer_prop->actualcount; + drv_ctx.extradata_info.buffer_size = extra_data_size; + buf_size += client_extra_data_size; + buf_size = (buf_size + buffer_prop->alignment - 1)&(~(buffer_prop->alignment - 1)); + DEBUG_PRINT_HIGH("GetBufReq UPDATE: ActCnt(%d) Size(%d) BufSize(%d) BufType(%d)", + buffer_prop->actualcount, buffer_prop->buffer_size, buf_size, buffer_prop->buffer_type); + if (in_reconfig) // BufReq will be set to driver when port is disabled + buffer_prop->buffer_size = buf_size; + else if (buf_size != buffer_prop->buffer_size) { + buffer_prop->buffer_size = buf_size; + eRet = set_buffer_req(buffer_prop); + } + } + DEBUG_PRINT_HIGH("GetBufReq OUT: ActCnt(%d) Size(%d), BufType(%d)", + buffer_prop->actualcount, buffer_prop->buffer_size, buffer_prop->buffer_type); + return eRet; +} + +OMX_ERRORTYPE omx_vdec::set_buffer_req(vdec_allocatorproperty *buffer_prop) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned buf_size = 0; + struct v4l2_format fmt; + struct v4l2_requestbuffers bufreq; + int ret; + DEBUG_PRINT_LOW("SetBufReq IN: ActCnt(%d) Size(%d)", + buffer_prop->actualcount, buffer_prop->buffer_size); + buf_size = (buffer_prop->buffer_size + buffer_prop->alignment - 1)&(~(buffer_prop->alignment - 1)); + if (buf_size != buffer_prop->buffer_size) { + DEBUG_PRINT_ERROR("Buffer size alignment error: Requested(%d) Required(%d)", + buffer_prop->buffer_size, buf_size); + eRet = OMX_ErrorBadParameter; + } else { + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + + if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_INPUT) { + fmt.type =V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.pixelformat = output_capability; + } else if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { + fmt.type =V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = capture_capability; + } else { + eRet = OMX_ErrorBadParameter; + } + + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Setting buffer requirements (format) failed %d", ret); + eRet = OMX_ErrorInsufficientResources; + } + + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = buffer_prop->actualcount; + if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_INPUT) { + bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + } else if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { + bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + } else { + eRet = OMX_ErrorBadParameter; + } + + if (eRet==OMX_ErrorNone) { + ret = ioctl(drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); + } + + if (ret) { + DEBUG_PRINT_ERROR("Setting buffer requirements (reqbufs) failed %d", ret); + /*TODO: How to handle this case */ + eRet = OMX_ErrorInsufficientResources; + } else if (bufreq.count < buffer_prop->actualcount) { + DEBUG_PRINT_ERROR("Driver refused to change the number of buffers" + " on v4l2 port %d to %d (prefers %d)", bufreq.type, + buffer_prop->actualcount, bufreq.count); + eRet = OMX_ErrorInsufficientResources; + } else { + if (!client_buffers.update_buffer_req()) { + DEBUG_PRINT_ERROR("Setting c2D buffer requirements failed"); + eRet = OMX_ErrorInsufficientResources; + } + } + } + if (!eRet && buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { + // need to update extradata buffers also + drv_ctx.extradata_info.size = buffer_prop->actualcount * drv_ctx.extradata_info.buffer_size; + drv_ctx.extradata_info.count = buffer_prop->actualcount; + } + return eRet; +} + +OMX_ERRORTYPE omx_vdec::update_picture_resolution() +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + return eRet; +} + +OMX_ERRORTYPE omx_vdec::update_portdef(OMX_PARAM_PORTDEFINITIONTYPE *portDefn) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (!portDefn) { + return OMX_ErrorBadParameter; + } + DEBUG_PRINT_LOW("omx_vdec::update_portdef"); + portDefn->nVersion.nVersion = OMX_SPEC_VERSION; + portDefn->nSize = sizeof(portDefn); + portDefn->eDomain = OMX_PortDomainVideo; + if (drv_ctx.frame_rate.fps_denominator > 0) + portDefn->format.video.xFramerate = drv_ctx.frame_rate.fps_numerator / + drv_ctx.frame_rate.fps_denominator; + else { + DEBUG_PRINT_ERROR("Error: Divide by zero"); + return OMX_ErrorBadParameter; + } + if (0 == portDefn->nPortIndex) { + portDefn->eDir = OMX_DirInput; + portDefn->nBufferCountActual = drv_ctx.ip_buf.actualcount; + portDefn->nBufferCountMin = drv_ctx.ip_buf.mincount; + portDefn->nBufferSize = drv_ctx.ip_buf.buffer_size; + portDefn->format.video.eColorFormat = OMX_COLOR_FormatUnused; + portDefn->format.video.eCompressionFormat = eCompressionFormat; + portDefn->bEnabled = m_inp_bEnabled; + portDefn->bPopulated = m_inp_bPopulated; + } else if (1 == portDefn->nPortIndex) { + unsigned int buf_size = 0; + if (!client_buffers.update_buffer_req()) { + DEBUG_PRINT_ERROR("client_buffers.update_buffer_req Failed"); + return OMX_ErrorHardware; + } + if (!client_buffers.get_buffer_req(buf_size)) { + DEBUG_PRINT_ERROR("update buffer requirements"); + return OMX_ErrorHardware; + } + portDefn->nBufferSize = buf_size; + portDefn->eDir = OMX_DirOutput; + portDefn->nBufferCountActual = drv_ctx.op_buf.actualcount; + portDefn->nBufferCountMin = drv_ctx.op_buf.mincount; + portDefn->format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; + portDefn->bEnabled = m_out_bEnabled; + portDefn->bPopulated = m_out_bPopulated; + if (!client_buffers.get_color_format(portDefn->format.video.eColorFormat)) { + DEBUG_PRINT_ERROR("Error in getting color format"); + return OMX_ErrorHardware; + } + } else { + portDefn->eDir = OMX_DirMax; + DEBUG_PRINT_LOW(" get_parameter: Bad Port idx %d", + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + portDefn->format.video.nFrameHeight = drv_ctx.video_resolution.frame_height; + portDefn->format.video.nFrameWidth = drv_ctx.video_resolution.frame_width; + portDefn->format.video.nStride = drv_ctx.video_resolution.stride; + portDefn->format.video.nSliceHeight = drv_ctx.video_resolution.scan_lines; + DEBUG_PRINT_HIGH("update_portdef Width = %lu Height = %lu Stride = %ld" + " SliceHeight = %lu", portDefn->format.video.nFrameWidth, + portDefn->format.video.nFrameHeight, + portDefn->format.video.nStride, + portDefn->format.video.nSliceHeight); + return eRet; + +} + +OMX_ERRORTYPE omx_vdec::allocate_output_headers() +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr = NULL; + unsigned i= 0; + + if (!m_out_mem_ptr) { + DEBUG_PRINT_HIGH("Use o/p buffer case - Header List allocation"); + int nBufHdrSize = 0; + int nPlatformEntrySize = 0; + int nPlatformListSize = 0; + int nPMEMInfoSize = 0; + OMX_QCOM_PLATFORM_PRIVATE_LIST *pPlatformList; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY *pPlatformEntry; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo; + + DEBUG_PRINT_LOW("Setting First Output Buffer(%d)", + drv_ctx.op_buf.actualcount); + nBufHdrSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_BUFFERHEADERTYPE); + + nPMEMInfoSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO); + nPlatformListSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_LIST); + nPlatformEntrySize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_ENTRY); + + DEBUG_PRINT_LOW("TotalBufHdr %d BufHdrSize %d PMEM %d PL %d",nBufHdrSize, + sizeof(OMX_BUFFERHEADERTYPE), + nPMEMInfoSize, + nPlatformListSize); + DEBUG_PRINT_LOW("PE %d bmSize %d",nPlatformEntrySize, + m_out_bm_count); + m_out_mem_ptr = (OMX_BUFFERHEADERTYPE *)calloc(nBufHdrSize,1); + // Alloc mem for platform specific info + char *pPtr=NULL; + pPtr = (char*) calloc(nPlatformListSize + nPlatformEntrySize + + nPMEMInfoSize,1); + drv_ctx.ptr_outputbuffer = (struct vdec_bufferpayload *) \ + calloc (sizeof(struct vdec_bufferpayload), + drv_ctx.op_buf.actualcount); + drv_ctx.ptr_respbuffer = (struct vdec_output_frameinfo *)\ + calloc (sizeof (struct vdec_output_frameinfo), + drv_ctx.op_buf.actualcount); +#ifdef USE_ION + drv_ctx.op_buf_ion_info = (struct vdec_ion * ) \ + calloc (sizeof(struct vdec_ion),drv_ctx.op_buf.actualcount); +#endif + + if (m_out_mem_ptr && pPtr && drv_ctx.ptr_outputbuffer + && drv_ctx.ptr_respbuffer) { + bufHdr = m_out_mem_ptr; + m_platform_list = (OMX_QCOM_PLATFORM_PRIVATE_LIST *)(pPtr); + m_platform_entry= (OMX_QCOM_PLATFORM_PRIVATE_ENTRY *) + (((char *) m_platform_list) + nPlatformListSize); + m_pmem_info = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) + (((char *) m_platform_entry) + nPlatformEntrySize); + pPlatformList = m_platform_list; + pPlatformEntry = m_platform_entry; + pPMEMInfo = m_pmem_info; + + DEBUG_PRINT_LOW("Memory Allocation Succeeded for OUT port%p",m_out_mem_ptr); + + // Settting the entire storage nicely + DEBUG_PRINT_LOW("bHdr %p OutMem %p PE %p",bufHdr, + m_out_mem_ptr,pPlatformEntry); + DEBUG_PRINT_LOW(" Pmem Info = %p",pPMEMInfo); + for (i=0; i < drv_ctx.op_buf.actualcount ; i++) { + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + // Set the values when we determine the right HxW param + bufHdr->nAllocLen = 0; + bufHdr->nFilledLen = 0; + bufHdr->pAppPrivate = NULL; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + pPlatformEntry->type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; + pPlatformEntry->entry = pPMEMInfo; + // Initialize the Platform List + pPlatformList->nEntries = 1; + pPlatformList->entryList = pPlatformEntry; + // Keep pBuffer NULL till vdec is opened + bufHdr->pBuffer = NULL; + pPMEMInfo->offset = 0; + pPMEMInfo->pmem_fd = 0; + bufHdr->pPlatformPrivate = pPlatformList; + drv_ctx.ptr_outputbuffer[i].pmem_fd = -1; +#ifdef USE_ION + drv_ctx.op_buf_ion_info[i].ion_device_fd =-1; +#endif + /*Create a mapping between buffers*/ + bufHdr->pOutputPortPrivate = &drv_ctx.ptr_respbuffer[i]; + drv_ctx.ptr_respbuffer[i].client_data = (void *) \ + &drv_ctx.ptr_outputbuffer[i]; + // Move the buffer and buffer header pointers + bufHdr++; + pPMEMInfo++; + pPlatformEntry++; + pPlatformList++; + } + } else { + DEBUG_PRINT_ERROR("Output buf mem alloc failed[0x%p][0x%p]",\ + m_out_mem_ptr, pPtr); + if (m_out_mem_ptr) { + free(m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + if (pPtr) { + free(pPtr); + pPtr = NULL; + } + if (drv_ctx.ptr_outputbuffer) { + free(drv_ctx.ptr_outputbuffer); + drv_ctx.ptr_outputbuffer = NULL; + } + if (drv_ctx.ptr_respbuffer) { + free(drv_ctx.ptr_respbuffer); + drv_ctx.ptr_respbuffer = NULL; + } +#ifdef USE_ION + if (drv_ctx.op_buf_ion_info) { + DEBUG_PRINT_LOW("Free o/p ion context"); + free(drv_ctx.op_buf_ion_info); + drv_ctx.op_buf_ion_info = NULL; + } +#endif + eRet = OMX_ErrorInsufficientResources; + } + } else { + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +void omx_vdec::complete_pending_buffer_done_cbs() +{ + unsigned p1; + unsigned p2; + unsigned ident; + omx_cmd_queue tmp_q, pending_bd_q; + pthread_mutex_lock(&m_lock); + // pop all pending GENERATE FDB from ftb queue + while (m_ftb_q.m_size) { + m_ftb_q.pop_entry(&p1,&p2,&ident); + if (ident == OMX_COMPONENT_GENERATE_FBD) { + pending_bd_q.insert_entry(p1,p2,ident); + } else { + tmp_q.insert_entry(p1,p2,ident); + } + } + //return all non GENERATE FDB to ftb queue + while (tmp_q.m_size) { + tmp_q.pop_entry(&p1,&p2,&ident); + m_ftb_q.insert_entry(p1,p2,ident); + } + // pop all pending GENERATE EDB from etb queue + while (m_etb_q.m_size) { + m_etb_q.pop_entry(&p1,&p2,&ident); + if (ident == OMX_COMPONENT_GENERATE_EBD) { + pending_bd_q.insert_entry(p1,p2,ident); + } else { + tmp_q.insert_entry(p1,p2,ident); + } + } + //return all non GENERATE FDB to etb queue + while (tmp_q.m_size) { + tmp_q.pop_entry(&p1,&p2,&ident); + m_etb_q.insert_entry(p1,p2,ident); + } + pthread_mutex_unlock(&m_lock); + // process all pending buffer dones + while (pending_bd_q.m_size) { + pending_bd_q.pop_entry(&p1,&p2,&ident); + switch (ident) { + case OMX_COMPONENT_GENERATE_EBD: + if (empty_buffer_done(&m_cmp, (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("ERROR: empty_buffer_done() failed!"); + omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_FBD: + if (fill_buffer_done(&m_cmp, (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone ) { + DEBUG_PRINT_ERROR("ERROR: fill_buffer_done() failed!"); + omx_report_error (); + } + break; + } + } +} + +void omx_vdec::set_frame_rate(OMX_S64 act_timestamp) +{ + OMX_U32 new_frame_interval = 0; + if (VALID_TS(act_timestamp) && VALID_TS(prev_ts) && act_timestamp != prev_ts + && (((act_timestamp > prev_ts )? act_timestamp - prev_ts: prev_ts-act_timestamp)>2000)) { + new_frame_interval = (act_timestamp > prev_ts)? + act_timestamp - prev_ts : + prev_ts - act_timestamp; + if (new_frame_interval < frm_int || frm_int == 0) { + frm_int = new_frame_interval; + if (frm_int) { + drv_ctx.frame_rate.fps_numerator = 1e6; + drv_ctx.frame_rate.fps_denominator = frm_int; + DEBUG_PRINT_LOW("set_frame_rate: frm_int(%u) fps(%f)", + frm_int, drv_ctx.frame_rate.fps_numerator / + (float)drv_ctx.frame_rate.fps_denominator); + } + } + } + prev_ts = act_timestamp; +} + +void omx_vdec::adjust_timestamp(OMX_S64 &act_timestamp) +{ + if (rst_prev_ts && VALID_TS(act_timestamp)) { + prev_ts = act_timestamp; + rst_prev_ts = false; + } else if (VALID_TS(prev_ts)) { + bool codec_cond = (drv_ctx.timestamp_adjust)? + (!VALID_TS(act_timestamp) || (((act_timestamp > prev_ts)? + (act_timestamp - prev_ts):(prev_ts - act_timestamp)) <= 2000)): + (!VALID_TS(act_timestamp) || act_timestamp == prev_ts); + if (frm_int > 0 && codec_cond) { + DEBUG_PRINT_LOW("adjust_timestamp: original ts[%lld]", act_timestamp); + act_timestamp = prev_ts + frm_int; + DEBUG_PRINT_LOW("adjust_timestamp: predicted ts[%lld]", act_timestamp); + prev_ts = act_timestamp; + } else + set_frame_rate(act_timestamp); + } else if (frm_int > 0) // In this case the frame rate was set along + { // with the port definition, start ts with 0 + act_timestamp = prev_ts = 0; // and correct if a valid ts is received. + rst_prev_ts = true; + } +} + +void omx_vdec::handle_extradata(OMX_BUFFERHEADERTYPE *p_buf_hdr) +{ + OMX_OTHER_EXTRADATATYPE *p_extra = NULL, *p_sei = NULL, *p_vui = NULL; + OMX_U32 num_conceal_MB = 0; + OMX_U32 frame_rate = 0; + int consumed_len = 0; + OMX_U32 num_MB_in_frame; + OMX_U32 recovery_sei_flags = 1; + int buf_index = p_buf_hdr - m_out_mem_ptr; + struct msm_vidc_panscan_window_payload *panscan_payload = NULL; + OMX_U8 *pBuffer = (OMX_U8 *)(drv_ctx.ptr_outputbuffer[buf_index].bufferaddr) + + p_buf_hdr->nOffset; + if (!drv_ctx.extradata_info.uaddr) { + return; + } + p_extra = (OMX_OTHER_EXTRADATATYPE *) + ((unsigned)(pBuffer + p_buf_hdr->nOffset + p_buf_hdr->nFilledLen + 3)&(~3)); + char *p_extradata = drv_ctx.extradata_info.uaddr + buf_index * drv_ctx.extradata_info.buffer_size; + if ((OMX_U8*)p_extra > (pBuffer + p_buf_hdr->nAllocLen)) + p_extra = NULL; + OMX_OTHER_EXTRADATATYPE *data = (struct OMX_OTHER_EXTRADATATYPE *)p_extradata; + if (data) { + while ((consumed_len < drv_ctx.extradata_info.buffer_size) + && (data->eType != (OMX_EXTRADATATYPE)MSM_VIDC_EXTRADATA_NONE)) { + if ((consumed_len + data->nSize) > drv_ctx.extradata_info.buffer_size) { + DEBUG_PRINT_LOW("Invalid extra data size"); + break; + } + switch ((unsigned long)data->eType) { + case MSM_VIDC_EXTRADATA_INTERLACE_VIDEO: + struct msm_vidc_interlace_payload *payload; + payload = (struct msm_vidc_interlace_payload *)data->data; + if (payload->format != MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE) { + int enable = 1; + OMX_U32 mbaff = 0; + mbaff = (h264_parser)? (h264_parser->is_mbaff()): false; + if ((payload->format == MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE) && !mbaff) + drv_ctx.interlace = VDEC_InterlaceFrameProgressive; + else + drv_ctx.interlace = VDEC_InterlaceInterleaveFrameTopFieldFirst; + if (m_enable_android_native_buffers) + setMetaData((private_handle_t *)native_buffer[buf_index].privatehandle, + PP_PARAM_INTERLACED, (void*)&enable); + } + if (!secure_mode && (client_extradata & OMX_INTERLACE_EXTRADATA)) { + append_interlace_extradata(p_extra, payload->format); + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + p_extra->nSize); + } + break; + case MSM_VIDC_EXTRADATA_FRAME_RATE: + struct msm_vidc_framerate_payload *frame_rate_payload; + frame_rate_payload = (struct msm_vidc_framerate_payload *)data->data; + frame_rate = frame_rate_payload->frame_rate; + break; + case MSM_VIDC_EXTRADATA_TIMESTAMP: + struct msm_vidc_ts_payload *time_stamp_payload; + time_stamp_payload = (struct msm_vidc_ts_payload *)data->data; + p_buf_hdr->nTimeStamp = time_stamp_payload->timestamp_lo; + p_buf_hdr->nTimeStamp |= ((unsigned long long)time_stamp_payload->timestamp_hi << 32); + break; + case MSM_VIDC_EXTRADATA_NUM_CONCEALED_MB: + struct msm_vidc_concealmb_payload *conceal_mb_payload; + conceal_mb_payload = (struct msm_vidc_concealmb_payload *)data->data; + num_MB_in_frame = ((drv_ctx.video_resolution.frame_width + 15) * + (drv_ctx.video_resolution.frame_height + 15)) >> 8; + num_conceal_MB = ((num_MB_in_frame > 0)?(conceal_mb_payload->num_mbs * 100 / num_MB_in_frame) : 0); + break; + case MSM_VIDC_EXTRADATA_ASPECT_RATIO: + struct msm_vidc_aspect_ratio_payload *aspect_ratio_payload; + aspect_ratio_payload = (struct msm_vidc_aspect_ratio_payload *)data->data; + ((struct vdec_output_frameinfo *) + p_buf_hdr->pOutputPortPrivate)->aspect_ratio_info.par_width = aspect_ratio_payload->aspect_width; + ((struct vdec_output_frameinfo *) + p_buf_hdr->pOutputPortPrivate)->aspect_ratio_info.par_height = aspect_ratio_payload->aspect_height; + break; + case MSM_VIDC_EXTRADATA_RECOVERY_POINT_SEI: + struct msm_vidc_recoverysei_payload *recovery_sei_payload; + recovery_sei_payload = (struct msm_vidc_recoverysei_payload *)data->data; + recovery_sei_flags = recovery_sei_payload->flags; + if (recovery_sei_flags != MSM_VIDC_FRAME_RECONSTRUCTION_CORRECT) { + p_buf_hdr->nFlags |= OMX_BUFFERFLAG_DATACORRUPT; + DEBUG_PRINT_HIGH("Extradata: OMX_BUFFERFLAG_DATACORRUPT Received"); + } + break; + case MSM_VIDC_EXTRADATA_PANSCAN_WINDOW: + panscan_payload = (struct msm_vidc_panscan_window_payload *)data->data; + break; + default: + goto unrecognized_extradata; + } + consumed_len += data->nSize; + data = (OMX_OTHER_EXTRADATATYPE *)((char *)data + data->nSize); + } + if (!secure_mode && (client_extradata & OMX_FRAMEINFO_EXTRADATA)) { + p_buf_hdr->nFlags |= OMX_BUFFERFLAG_EXTRADATA; + append_frame_info_extradata(p_extra, + num_conceal_MB, ((struct vdec_output_frameinfo *)p_buf_hdr->pOutputPortPrivate)->pic_type, frame_rate, + panscan_payload,&((struct vdec_output_frameinfo *) + p_buf_hdr->pOutputPortPrivate)->aspect_ratio_info); + } + } +unrecognized_extradata: + if (!secure_mode && client_extradata) + append_terminator_extradata(p_extra); + return; +} + +OMX_ERRORTYPE omx_vdec::enable_extradata(OMX_U32 requested_extradata, + bool is_internal, bool enable) +{ + OMX_ERRORTYPE ret = OMX_ErrorNone; + struct v4l2_control control; + if (m_state != OMX_StateLoaded) { + DEBUG_PRINT_ERROR("ERROR: enable extradata allowed in Loaded state only"); + return OMX_ErrorIncorrectStateOperation; + } + DEBUG_PRINT_HIGH("NOTE: enable_extradata: actual[%lu] requested[%lu] enable[%d], is_internal: %d", + client_extradata, requested_extradata, enable, is_internal); + + if (!is_internal) { + if (enable) + client_extradata |= requested_extradata; + else + client_extradata = client_extradata & ~requested_extradata; + } + + if (enable) { + if (requested_extradata & OMX_INTERLACE_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set interlaced extradata." + " Quality of interlaced clips might be impacted."); + } + } else if (requested_extradata & OMX_FRAMEINFO_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set framerate extradata"); + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set concealed MB extradata"); + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set recovery point SEI extradata"); + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set panscan extradata"); + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set panscan extradata"); + } + } else if (requested_extradata & OMX_TIMEINFO_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set timeinfo extradata"); + } + } + } + ret = get_buffer_req(&drv_ctx.op_buf); + return ret; +} + +OMX_U32 omx_vdec::count_MB_in_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + OMX_U32 num_MB = 0, byte_count = 0, num_MB_in_frame = 0; + OMX_U8 *data_ptr = extra->data, data = 0; + while (byte_count < extra->nDataSize) { + data = *data_ptr; + while (data) { + num_MB += (data&0x01); + data >>= 1; + } + data_ptr++; + byte_count++; + } + num_MB_in_frame = ((drv_ctx.video_resolution.frame_width + 15) * + (drv_ctx.video_resolution.frame_height + 15)) >> 8; + return ((num_MB_in_frame > 0)?(num_MB * 100 / num_MB_in_frame) : 0); +} + +void omx_vdec::print_debug_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + if (!m_debug_extradata) + return; + + DEBUG_PRINT_HIGH( + "============== Extra Data ==============\n" + " Size: %lu\n" + " Version: %lu\n" + " PortIndex: %lu\n" + " Type: %x\n" + " DataSize: %lu", + extra->nSize, extra->nVersion.nVersion, + extra->nPortIndex, extra->eType, extra->nDataSize); + + if (extra->eType == (OMX_EXTRADATATYPE)OMX_ExtraDataInterlaceFormat) { + OMX_STREAMINTERLACEFORMAT *intfmt = (OMX_STREAMINTERLACEFORMAT *)extra->data; + DEBUG_PRINT_HIGH( + "------ Interlace Format ------\n" + " Size: %lu\n" + " Version: %lu\n" + " PortIndex: %lu\n" + " Is Interlace Format: %d\n" + " Interlace Formats: %lu\n" + "=========== End of Interlace ===========", + intfmt->nSize, intfmt->nVersion.nVersion, intfmt->nPortIndex, + intfmt->bInterlaceFormat, intfmt->nInterlaceFormats); + } else if (extra->eType == (OMX_EXTRADATATYPE)OMX_ExtraDataFrameInfo) { + OMX_QCOM_EXTRADATA_FRAMEINFO *fminfo = (OMX_QCOM_EXTRADATA_FRAMEINFO *)extra->data; + + DEBUG_PRINT_HIGH( + "-------- Frame Format --------\n" + " Picture Type: %d\n" + " Interlace Type: %d\n" + " Pan Scan Total Frame Num: %lu\n" + " Concealed Macro Blocks: %lu\n" + " frame rate: %lu\n" + " Aspect Ratio X: %lu\n" + " Aspect Ratio Y: %lu", + fminfo->ePicType, + fminfo->interlaceType, + fminfo->panScan.numWindows, + fminfo->nConcealedMacroblocks, + fminfo->nFrameRate, + fminfo->aspectRatio.aspectRatioX, + fminfo->aspectRatio.aspectRatioY); + + for (OMX_U32 i = 0; i < fminfo->panScan.numWindows; i++) { + DEBUG_PRINT_HIGH( + "------------------------------\n" + " Pan Scan Frame Num: %lu\n" + " Rectangle x: %ld\n" + " Rectangle y: %ld\n" + " Rectangle dx: %ld\n" + " Rectangle dy: %ld", + i, fminfo->panScan.window[i].x, fminfo->panScan.window[i].y, + fminfo->panScan.window[i].dx, fminfo->panScan.window[i].dy); + } + + DEBUG_PRINT_HIGH("========= End of Frame Format =========="); + } else if (extra->eType == OMX_ExtraDataNone) { + DEBUG_PRINT_HIGH("========== End of Terminator ==========="); + } else { + DEBUG_PRINT_HIGH("======= End of Driver Extradata ========"); + } +} + +void omx_vdec::append_interlace_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 interlaced_format_type) +{ + OMX_STREAMINTERLACEFORMAT *interlace_format; + OMX_U32 mbaff = 0; + if (!(client_extradata & OMX_INTERLACE_EXTRADATA)) { + return; + } + extra->nSize = OMX_INTERLACE_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataInterlaceFormat; + extra->nDataSize = sizeof(OMX_STREAMINTERLACEFORMAT); + interlace_format = (OMX_STREAMINTERLACEFORMAT *)extra->data; + interlace_format->nSize = sizeof(OMX_STREAMINTERLACEFORMAT); + interlace_format->nVersion.nVersion = OMX_SPEC_VERSION; + interlace_format->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + mbaff = (h264_parser)? (h264_parser->is_mbaff()): false; + if ((interlaced_format_type == MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE) && !mbaff) { + interlace_format->bInterlaceFormat = OMX_FALSE; + interlace_format->nInterlaceFormats = OMX_InterlaceFrameProgressive; + drv_ctx.interlace = VDEC_InterlaceFrameProgressive; + } else { + interlace_format->bInterlaceFormat = OMX_TRUE; + interlace_format->nInterlaceFormats = OMX_InterlaceInterleaveFrameTopFieldFirst; + drv_ctx.interlace = VDEC_InterlaceInterleaveFrameTopFieldFirst; + } + print_debug_extradata(extra); +} + +void omx_vdec::fill_aspect_ratio_info( + struct vdec_aspectratioinfo *aspect_ratio_info, + OMX_QCOM_EXTRADATA_FRAMEINFO *frame_info) +{ + m_extradata = frame_info; + m_extradata->aspectRatio.aspectRatioX = aspect_ratio_info->par_width; + m_extradata->aspectRatio.aspectRatioY = aspect_ratio_info->par_height; + DEBUG_PRINT_LOW("aspectRatioX %d aspectRatioX %d", m_extradata->aspectRatio.aspectRatioX, + m_extradata->aspectRatio.aspectRatioY); +} + +void omx_vdec::append_frame_info_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 num_conceal_mb, OMX_U32 picture_type, OMX_U32 frame_rate, + struct msm_vidc_panscan_window_payload *panscan_payload, + struct vdec_aspectratioinfo *aspect_ratio_info) +{ + OMX_QCOM_EXTRADATA_FRAMEINFO *frame_info = NULL; + struct msm_vidc_panscan_window *panscan_window; + if (!(client_extradata & OMX_FRAMEINFO_EXTRADATA)) { + return; + } + extra->nSize = OMX_FRAMEINFO_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataFrameInfo; + extra->nDataSize = sizeof(OMX_QCOM_EXTRADATA_FRAMEINFO); + frame_info = (OMX_QCOM_EXTRADATA_FRAMEINFO *)extra->data; + switch (picture_type) { + case PICTURE_TYPE_I: + frame_info->ePicType = OMX_VIDEO_PictureTypeI; + break; + case PICTURE_TYPE_P: + frame_info->ePicType = OMX_VIDEO_PictureTypeP; + break; + case PICTURE_TYPE_B: + frame_info->ePicType = OMX_VIDEO_PictureTypeB; + break; + default: + frame_info->ePicType = (OMX_VIDEO_PICTURETYPE)0; + } + if (drv_ctx.interlace == VDEC_InterlaceInterleaveFrameTopFieldFirst) + frame_info->interlaceType = OMX_QCOM_InterlaceInterleaveFrameTopFieldFirst; + else if (drv_ctx.interlace == VDEC_InterlaceInterleaveFrameBottomFieldFirst) + frame_info->interlaceType = OMX_QCOM_InterlaceInterleaveFrameBottomFieldFirst; + else + frame_info->interlaceType = OMX_QCOM_InterlaceFrameProgressive; + memset(&frame_info->aspectRatio, 0, sizeof(frame_info->aspectRatio)); + frame_info->nConcealedMacroblocks = num_conceal_mb; + frame_info->nFrameRate = frame_rate; + frame_info->panScan.numWindows = 0; + if (panscan_payload) { + frame_info->panScan.numWindows = panscan_payload->num_panscan_windows; + panscan_window = &panscan_payload->wnd[0]; + for (OMX_U32 i = 0; i < frame_info->panScan.numWindows; i++) { + frame_info->panScan.window[i].x = panscan_window->panscan_window_width; + frame_info->panScan.window[i].y = panscan_window->panscan_window_height; + frame_info->panScan.window[i].dx = panscan_window->panscan_width_offset; + frame_info->panScan.window[i].dy = panscan_window->panscan_height_offset; + panscan_window++; + } + } + fill_aspect_ratio_info(aspect_ratio_info, frame_info); + print_debug_extradata(extra); +} + +void omx_vdec::append_portdef_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + OMX_PARAM_PORTDEFINITIONTYPE *portDefn = NULL; + extra->nSize = OMX_PORTDEF_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataPortDef; + extra->nDataSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *)extra->data; + *portDefn = m_port_def; + DEBUG_PRINT_LOW("append_portdef_extradata height = %u width = %u stride = %u" + "sliceheight = %u",portDefn->format.video.nFrameHeight, + portDefn->format.video.nFrameWidth, + portDefn->format.video.nStride, + portDefn->format.video.nSliceHeight); +} + +void omx_vdec::append_terminator_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + if (!client_extradata) { + return; + } + extra->nSize = sizeof(OMX_OTHER_EXTRADATATYPE); + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->eType = OMX_ExtraDataNone; + extra->nDataSize = 0; + extra->data[0] = 0; + + print_debug_extradata(extra); +} + +OMX_ERRORTYPE omx_vdec::allocate_desc_buffer(OMX_U32 index) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (index >= drv_ctx.ip_buf.actualcount) { + DEBUG_PRINT_ERROR("ERROR:Desc Buffer Index not found"); + return OMX_ErrorInsufficientResources; + } + if (m_desc_buffer_ptr == NULL) { + m_desc_buffer_ptr = (desc_buffer_hdr*) \ + calloc( (sizeof(desc_buffer_hdr)), + drv_ctx.ip_buf.actualcount); + if (m_desc_buffer_ptr == NULL) { + DEBUG_PRINT_ERROR("m_desc_buffer_ptr Allocation failed "); + return OMX_ErrorInsufficientResources; + } + } + + m_desc_buffer_ptr[index].buf_addr = (unsigned char *)malloc (DESC_BUFFER_SIZE * sizeof(OMX_U8)); + if (m_desc_buffer_ptr[index].buf_addr == NULL) { + DEBUG_PRINT_ERROR("desc buffer Allocation failed "); + return OMX_ErrorInsufficientResources; + } + + return eRet; +} + +void omx_vdec::insert_demux_addr_offset(OMX_U32 address_offset) +{ + DEBUG_PRINT_LOW("Inserting address offset (%d) at idx (%d)", address_offset,m_demux_entries); + if (m_demux_entries < 8192) { + m_demux_offsets[m_demux_entries++] = address_offset; + } + return; +} + +void omx_vdec::extract_demux_addr_offsets(OMX_BUFFERHEADERTYPE *buf_hdr) +{ + OMX_U32 bytes_to_parse = buf_hdr->nFilledLen; + OMX_U8 *buf = buf_hdr->pBuffer + buf_hdr->nOffset; + OMX_U32 index = 0; + + m_demux_entries = 0; + + while (index < bytes_to_parse) { + if ( ((buf[index] == 0x00) && (buf[index+1] == 0x00) && + (buf[index+2] == 0x00) && (buf[index+3] == 0x01)) || + ((buf[index] == 0x00) && (buf[index+1] == 0x00) && + (buf[index+2] == 0x01)) ) { + //Found start code, insert address offset + insert_demux_addr_offset(index); + if (buf[index+2] == 0x01) // 3 byte start code + index += 3; + else //4 byte start code + index += 4; + } else + index++; + } + DEBUG_PRINT_LOW("Extracted (%d) demux entry offsets",m_demux_entries); + return; +} + +OMX_ERRORTYPE omx_vdec::handle_demux_data(OMX_BUFFERHEADERTYPE *p_buf_hdr) +{ + //fix this, handle 3 byte start code, vc1 terminator entry + OMX_U8 *p_demux_data = NULL; + OMX_U32 desc_data = 0; + OMX_U32 start_addr = 0; + OMX_U32 nal_size = 0; + OMX_U32 suffix_byte = 0; + OMX_U32 demux_index = 0; + OMX_U32 buffer_index = 0; + + if (m_desc_buffer_ptr == NULL) { + DEBUG_PRINT_ERROR("m_desc_buffer_ptr is NULL. Cannot append demux entries."); + return OMX_ErrorBadParameter; + } + + buffer_index = p_buf_hdr - ((OMX_BUFFERHEADERTYPE *)m_inp_mem_ptr); + if (buffer_index > drv_ctx.ip_buf.actualcount) { + DEBUG_PRINT_ERROR("handle_demux_data:Buffer index is incorrect (%lu)", buffer_index); + return OMX_ErrorBadParameter; + } + + p_demux_data = (OMX_U8 *) m_desc_buffer_ptr[buffer_index].buf_addr; + + if ( ((OMX_U8*)p_demux_data == NULL) || + ((m_demux_entries * 16) + 1) > DESC_BUFFER_SIZE) { + DEBUG_PRINT_ERROR("Insufficient buffer. Cannot append demux entries."); + return OMX_ErrorBadParameter; + } else { + for (; demux_index < m_demux_entries; demux_index++) { + desc_data = 0; + start_addr = m_demux_offsets[demux_index]; + if (p_buf_hdr->pBuffer[m_demux_offsets[demux_index] + 2] == 0x01) { + suffix_byte = p_buf_hdr->pBuffer[m_demux_offsets[demux_index] + 3]; + } else { + suffix_byte = p_buf_hdr->pBuffer[m_demux_offsets[demux_index] + 4]; + } + if (demux_index < (m_demux_entries - 1)) { + nal_size = m_demux_offsets[demux_index + 1] - m_demux_offsets[demux_index] - 2; + } else { + nal_size = p_buf_hdr->nFilledLen - m_demux_offsets[demux_index] - 2; + } + DEBUG_PRINT_LOW("Start_addr(%p), suffix_byte(0x%x),nal_size(%d),demux_index(%d)", + start_addr, + suffix_byte, + nal_size, + demux_index); + desc_data = (start_addr >> 3) << 1; + desc_data |= (start_addr & 7) << 21; + desc_data |= suffix_byte << 24; + + memcpy(p_demux_data, &desc_data, sizeof(OMX_U32)); + memcpy(p_demux_data + 4, &nal_size, sizeof(OMX_U32)); + memset(p_demux_data + 8, 0, sizeof(OMX_U32)); + memset(p_demux_data + 12, 0, sizeof(OMX_U32)); + + p_demux_data += 16; + } + if (codec_type_parse == CODEC_TYPE_VC1) { + DEBUG_PRINT_LOW("VC1 terminator entry"); + desc_data = 0; + desc_data = 0x82 << 24; + memcpy(p_demux_data, &desc_data, sizeof(OMX_U32)); + memset(p_demux_data + 4, 0, sizeof(OMX_U32)); + memset(p_demux_data + 8, 0, sizeof(OMX_U32)); + memset(p_demux_data + 12, 0, sizeof(OMX_U32)); + p_demux_data += 16; + m_demux_entries++; + } + //Add zero word to indicate end of descriptors + memset(p_demux_data, 0, sizeof(OMX_U32)); + + m_desc_buffer_ptr[buffer_index].desc_data_size = (m_demux_entries * 16) + sizeof(OMX_U32); + DEBUG_PRINT_LOW("desc table data size=%d", m_desc_buffer_ptr[buffer_index].desc_data_size); + } + memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) ); + m_demux_entries = 0; + DEBUG_PRINT_LOW("Demux table complete!"); + return OMX_ErrorNone; +} + +omx_vdec::allocate_color_convert_buf::allocate_color_convert_buf() +{ + enabled = false; + omx = NULL; + init_members(); + ColorFormat = OMX_COLOR_FormatMax; +} + +void omx_vdec::allocate_color_convert_buf::set_vdec_client(void *client) +{ + omx = reinterpret_cast<omx_vdec*>(client); +} + +void omx_vdec::allocate_color_convert_buf::init_members() +{ + allocated_count = 0; + buffer_size_req = 0; + buffer_alignment_req = 0; + memset(m_platform_list_client,0,sizeof(m_platform_list_client)); + memset(m_platform_entry_client,0,sizeof(m_platform_entry_client)); + memset(m_pmem_info_client,0,sizeof(m_pmem_info_client)); + memset(m_out_mem_ptr_client,0,sizeof(m_out_mem_ptr_client)); +#ifdef USE_ION + memset(op_buf_ion_info,0,sizeof(m_platform_entry_client)); +#endif + for (int i = 0; i < MAX_COUNT; i++) + pmem_fd[i] = -1; +} + +omx_vdec::allocate_color_convert_buf::~allocate_color_convert_buf() +{ + c2d.destroy(); +} + +bool omx_vdec::allocate_color_convert_buf::update_buffer_req() +{ + bool status = true; + unsigned int src_size = 0, destination_size = 0; + OMX_COLOR_FORMATTYPE drv_color_format; + if (!omx) { + DEBUG_PRINT_ERROR("Invalid client in color convert"); + return false; + } + if (!enabled) { + DEBUG_PRINT_HIGH("No color conversion required"); + return status; + } + pthread_mutex_lock(&omx->c_lock); + if (omx->drv_ctx.output_format != VDEC_YUV_FORMAT_NV12 && + ColorFormat != OMX_COLOR_FormatYUV420Planar) { + DEBUG_PRINT_ERROR("update_buffer_req: Unsupported color conversion"); + status = false; + goto fail_update_buf_req; + } + c2d.close(); + status = c2d.open(omx->drv_ctx.video_resolution.frame_height, + omx->drv_ctx.video_resolution.frame_width, + NV12_128m,YCbCr420P); + if (status) { + status = c2d.get_buffer_size(C2D_INPUT,src_size); + if (status) + status = c2d.get_buffer_size(C2D_OUTPUT,destination_size); + } + if (status) { + if (!src_size || src_size > omx->drv_ctx.op_buf.buffer_size || + !destination_size) { + DEBUG_PRINT_ERROR("ERROR: Size mismatch in C2D src_size %d" + "driver size %d destination size %d", + src_size,omx->drv_ctx.op_buf.buffer_size,destination_size); + status = false; + c2d.close(); + buffer_size_req = 0; + } else { + buffer_size_req = destination_size; + if (buffer_size_req < omx->drv_ctx.op_buf.buffer_size) + buffer_size_req = omx->drv_ctx.op_buf.buffer_size; + if (buffer_alignment_req < omx->drv_ctx.op_buf.alignment) + buffer_alignment_req = omx->drv_ctx.op_buf.alignment; + } + } +fail_update_buf_req: + pthread_mutex_unlock(&omx->c_lock); + return status; +} + +bool omx_vdec::allocate_color_convert_buf::set_color_format( + OMX_COLOR_FORMATTYPE dest_color_format) +{ + bool status = true; + OMX_COLOR_FORMATTYPE drv_color_format; + if (!omx) { + DEBUG_PRINT_ERROR("Invalid client in color convert"); + return false; + } + pthread_mutex_lock(&omx->c_lock); + if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12) + drv_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + else { + DEBUG_PRINT_ERROR("Incorrect color format"); + status = false; + } + if (status && (drv_color_format != dest_color_format)) { + DEBUG_PRINT_LOW("Enabling C2D"); + if (dest_color_format != OMX_COLOR_FormatYUV420Planar) { + DEBUG_PRINT_ERROR("Unsupported color format for c2d"); + status = false; + } else { + ColorFormat = OMX_COLOR_FormatYUV420Planar; + if (enabled) + c2d.destroy(); + enabled = false; + if (!c2d.init()) { + DEBUG_PRINT_ERROR("open failed for c2d"); + status = false; + } else + enabled = true; + } + } else { + if (enabled) + c2d.destroy(); + enabled = false; + } + pthread_mutex_unlock(&omx->c_lock); + return status; +} + +OMX_BUFFERHEADERTYPE* omx_vdec::allocate_color_convert_buf::get_il_buf_hdr() +{ + if (!omx) { + DEBUG_PRINT_ERROR("Invalid param get_buf_hdr"); + return NULL; + } + if (!enabled) + return omx->m_out_mem_ptr; + return m_out_mem_ptr_client; +} + + OMX_BUFFERHEADERTYPE* omx_vdec::allocate_color_convert_buf::get_il_buf_hdr +(OMX_BUFFERHEADERTYPE *bufadd) +{ + if (!omx) { + DEBUG_PRINT_ERROR("Invalid param get_buf_hdr"); + return NULL; + } + if (!enabled) + return bufadd; + + unsigned index = 0; + index = bufadd - omx->m_out_mem_ptr; + if (index < omx->drv_ctx.op_buf.actualcount) { + m_out_mem_ptr_client[index].nFlags = (bufadd->nFlags & OMX_BUFFERFLAG_EOS); + m_out_mem_ptr_client[index].nTimeStamp = bufadd->nTimeStamp; + bool status; + if (!omx->in_reconfig && !omx->output_flush_progress && bufadd->nFilledLen) { + pthread_mutex_lock(&omx->c_lock); + status = c2d.convert(omx->drv_ctx.ptr_outputbuffer[index].pmem_fd, + omx->m_out_mem_ptr->pBuffer, bufadd->pBuffer,pmem_fd[index], + pmem_baseaddress[index], pmem_baseaddress[index]); + pthread_mutex_unlock(&omx->c_lock); + m_out_mem_ptr_client[index].nFilledLen = buffer_size_req; + if (!status) { + DEBUG_PRINT_ERROR("Failed color conversion %d", status); + m_out_mem_ptr_client[index].nFilledLen = 0; + return &m_out_mem_ptr_client[index]; + } + } else + m_out_mem_ptr_client[index].nFilledLen = 0; + return &m_out_mem_ptr_client[index]; + } + DEBUG_PRINT_ERROR("Index messed up in the get_il_buf_hdr"); + return NULL; +} + + OMX_BUFFERHEADERTYPE* omx_vdec::allocate_color_convert_buf::get_dr_buf_hdr +(OMX_BUFFERHEADERTYPE *bufadd) +{ + if (!omx) { + DEBUG_PRINT_ERROR("Invalid param get_buf_hdr"); + return NULL; + } + if (!enabled) + return bufadd; + unsigned index = 0; + index = bufadd - m_out_mem_ptr_client; + if (index < omx->drv_ctx.op_buf.actualcount) { + return &omx->m_out_mem_ptr[index]; + } + DEBUG_PRINT_ERROR("Index messed up in the get_dr_buf_hdr"); + return NULL; +} + bool omx_vdec::allocate_color_convert_buf::get_buffer_req +(unsigned int &buffer_size) +{ + bool status = true; + pthread_mutex_lock(&omx->c_lock); + if (!enabled) + buffer_size = omx->drv_ctx.op_buf.buffer_size; + else { + if (!c2d.get_buffer_size(C2D_OUTPUT,buffer_size)) { + DEBUG_PRINT_ERROR("Get buffer size failed"); + status = false; + goto fail_get_buffer_size; + } + } + if (buffer_size < omx->drv_ctx.op_buf.buffer_size) + buffer_size = omx->drv_ctx.op_buf.buffer_size; + if (buffer_alignment_req < omx->drv_ctx.op_buf.alignment) + buffer_alignment_req = omx->drv_ctx.op_buf.alignment; +fail_get_buffer_size: + pthread_mutex_unlock(&omx->c_lock); + return status; +} +OMX_ERRORTYPE omx_vdec::allocate_color_convert_buf::free_output_buffer( + OMX_BUFFERHEADERTYPE *bufhdr) +{ + unsigned int index = 0; + + if (!enabled) + return omx->free_output_buffer(bufhdr); + if (enabled && omx->is_component_secure()) + return OMX_ErrorNone; + if (!allocated_count || !bufhdr) { + DEBUG_PRINT_ERROR("Color convert no buffer to be freed %p",bufhdr); + return OMX_ErrorBadParameter; + } + index = bufhdr - m_out_mem_ptr_client; + if (index >= omx->drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("Incorrect index color convert free_output_buffer"); + return OMX_ErrorBadParameter; + } + if (pmem_fd[index] > 0) { + munmap(pmem_baseaddress[index], buffer_size_req); + close(pmem_fd[index]); + } + pmem_fd[index] = -1; +#ifdef USE_ION + omx->free_ion_memory(&op_buf_ion_info[index]); +#endif + m_heap_ptr[index].video_heap_ptr = NULL; + if (allocated_count > 0) + allocated_count--; + else + allocated_count = 0; + if (!allocated_count) { + pthread_mutex_lock(&omx->c_lock); + c2d.close(); + init_members(); + pthread_mutex_unlock(&omx->c_lock); + } + return omx->free_output_buffer(&omx->m_out_mem_ptr[index]); +} + +OMX_ERRORTYPE omx_vdec::allocate_color_convert_buf::allocate_buffers_color_convert(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr,OMX_U32 port,OMX_PTR appData,OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (!enabled) { + eRet = omx->allocate_output_buffer(hComp,bufferHdr,port,appData,bytes); + return eRet; + } + if (enabled && omx->is_component_secure()) { + DEBUG_PRINT_ERROR("Notin color convert mode secure_mode %d", + omx->is_component_secure()); + return OMX_ErrorUnsupportedSetting; + } + if (!bufferHdr || bytes > buffer_size_req) { + DEBUG_PRINT_ERROR("Invalid params allocate_buffers_color_convert %p", bufferHdr); + DEBUG_PRINT_ERROR("color_convert buffer_size_req %d bytes %lu", + buffer_size_req,bytes); + return OMX_ErrorBadParameter; + } + if (allocated_count >= omx->drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("Actual count err in allocate_buffers_color_convert"); + return OMX_ErrorInsufficientResources; + } + OMX_BUFFERHEADERTYPE *temp_bufferHdr = NULL; + eRet = omx->allocate_output_buffer(hComp,&temp_bufferHdr, + port,appData,omx->drv_ctx.op_buf.buffer_size); + if (eRet != OMX_ErrorNone || !temp_bufferHdr) { + DEBUG_PRINT_ERROR("Buffer allocation failed color_convert"); + return eRet; + } + if ((temp_bufferHdr - omx->m_out_mem_ptr) >= + omx->drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("Invalid header index %d", + (temp_bufferHdr - omx->m_out_mem_ptr)); + return OMX_ErrorUndefined; + } + unsigned int i = allocated_count; +#ifdef USE_ION + op_buf_ion_info[i].ion_device_fd = omx->alloc_map_ion_memory( + buffer_size_req,buffer_alignment_req, + &op_buf_ion_info[i].ion_alloc_data,&op_buf_ion_info[i].fd_ion_data, + 0); + pmem_fd[i] = op_buf_ion_info[i].fd_ion_data.fd; + if (op_buf_ion_info[i].ion_device_fd < 0) { + DEBUG_PRINT_ERROR("alloc_map_ion failed in color_convert"); + return OMX_ErrorInsufficientResources; + } + pmem_baseaddress[i] = (unsigned char *)mmap(NULL,buffer_size_req, + PROT_READ|PROT_WRITE,MAP_SHARED,pmem_fd[i],0); + + if (pmem_baseaddress[i] == MAP_FAILED) { + DEBUG_PRINT_ERROR("MMAP failed for Size %d",buffer_size_req); + close(pmem_fd[i]); + omx->free_ion_memory(&op_buf_ion_info[i]); + return OMX_ErrorInsufficientResources; + } + m_heap_ptr[i].video_heap_ptr = new VideoHeap ( + op_buf_ion_info[i].ion_device_fd,buffer_size_req, + pmem_baseaddress[i],op_buf_ion_info[i].ion_alloc_data.handle,pmem_fd[i]); +#endif + m_pmem_info_client[i].pmem_fd = (OMX_U32)m_heap_ptr[i].video_heap_ptr.get(); + m_pmem_info_client[i].offset = 0; + m_platform_entry_client[i].entry = (void *)&m_pmem_info_client[i]; + m_platform_entry_client[i].type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; + m_platform_list_client[i].nEntries = 1; + m_platform_list_client[i].entryList = &m_platform_entry_client[i]; + m_out_mem_ptr_client[i].pOutputPortPrivate = NULL; + m_out_mem_ptr_client[i].nAllocLen = buffer_size_req; + m_out_mem_ptr_client[i].nFilledLen = 0; + m_out_mem_ptr_client[i].nFlags = 0; + m_out_mem_ptr_client[i].nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + m_out_mem_ptr_client[i].nSize = sizeof(OMX_BUFFERHEADERTYPE); + m_out_mem_ptr_client[i].nVersion.nVersion = OMX_SPEC_VERSION; + m_out_mem_ptr_client[i].pPlatformPrivate = &m_platform_list_client[i]; + m_out_mem_ptr_client[i].pBuffer = pmem_baseaddress[i]; + m_out_mem_ptr_client[i].pAppPrivate = appData; + *bufferHdr = &m_out_mem_ptr_client[i]; + DEBUG_PRINT_ERROR("IL client buffer header %p", *bufferHdr); + allocated_count++; + return eRet; +} + +bool omx_vdec::is_component_secure() +{ + return secure_mode; +} + +bool omx_vdec::allocate_color_convert_buf::get_color_format(OMX_COLOR_FORMATTYPE &dest_color_format) +{ + bool status = true; + if (!enabled) { + if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12) + dest_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + else + status = false; + } else { + if (ColorFormat != OMX_COLOR_FormatYUV420Planar) { + status = false; + } else + dest_color_format = OMX_COLOR_FormatYUV420Planar; + } + return status; +} diff --git a/msm8998/mm-video-v4l2/vidc/vdec/src/omx_vdec_hevc_swvdec.cpp b/msm8998/mm-video-v4l2/vidc/vdec/src/omx_vdec_hevc_swvdec.cpp new file mode 100644 index 0000000..4f73bed --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/src/omx_vdec_hevc_swvdec.cpp @@ -0,0 +1,10961 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2013-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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ + +/*============================================================================ +O p e n M A X w r a p p e r s +O p e n M A X C o r e + +*//** @file omx_vdec.cpp +This module contains the implementation of the OpenMAX core & component. + +*//*========================================================================*/ + +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +#include <string.h> +#include <pthread.h> +#include <sys/prctl.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "omx_vdec_hevc_swvdec.h" +#include <fcntl.h> +#include <limits.h> +#include <stdlib.h> +#include <media/hardware/HardwareAPI.h> +#include <media/msm_media_info.h> + +#ifndef _ANDROID_ +#include <sys/ioctl.h> +#include <sys/mman.h> +#endif //_ANDROID_ + +#ifdef _ANDROID_ +#include <cutils/properties.h> +#undef USE_EGL_IMAGE_GPU +#endif + +#include <qdMetaData.h> + +#ifdef USE_EGL_IMAGE_GPU +#include <EGL/egl.h> +#include <EGL/eglQCOM.h> +#define EGL_BUFFER_HANDLE_QCOM 0x4F00 +#define EGL_BUFFER_OFFSET_QCOM 0x4F01 +#endif + +#define BUFFER_LOG_LOC "/data/misc/media" + +#ifdef OUTPUT_EXTRADATA_LOG +FILE *outputExtradataFile; +char ouputextradatafilename [] = "/data/extradata"; +#endif + +#define DEFAULT_FPS 30 +#define MAX_INPUT_ERROR DEFAULT_FPS +#define MAX_SUPPORTED_FPS 120 +#define DEFAULT_WIDTH_ALIGNMENT 128 +#define DEFAULT_HEIGHT_ALIGNMENT 32 + +#define VC1_SP_MP_START_CODE 0xC5000000 +#define VC1_SP_MP_START_CODE_MASK 0xFF000000 +#define VC1_AP_SEQ_START_CODE 0x0F010000 +#define VC1_STRUCT_C_PROFILE_MASK 0xF0 +#define VC1_STRUCT_B_LEVEL_MASK 0xE0000000 +#define VC1_SIMPLE_PROFILE 0 +#define VC1_MAIN_PROFILE 1 +#define VC1_ADVANCE_PROFILE 3 +#define VC1_SIMPLE_PROFILE_LOW_LEVEL 0 +#define VC1_SIMPLE_PROFILE_MED_LEVEL 2 +#define VC1_STRUCT_C_LEN 4 +#define VC1_STRUCT_C_POS 8 +#define VC1_STRUCT_A_POS 12 +#define VC1_STRUCT_B_POS 24 +#define VC1_SEQ_LAYER_SIZE 36 +#define POLL_TIMEOUT 0x7fffffff + +#define MEM_DEVICE "/dev/ion" +#define MEM_HEAP_ID ION_CP_MM_HEAP_ID + +#ifdef _ANDROID_ +extern "C"{ +#include<utils/Log.h> +} +#endif//_ANDROID_ + +#define SZ_4K 0x1000 +#define SZ_1M 0x100000 + +#define Log2(number, power) { OMX_U32 temp = number; power = 0; while( (0 == (temp & 0x1)) && power < 16) { temp >>=0x1; power++; } } +#define Q16ToFraction(q,num,den) { OMX_U32 power; Log2(q,power); num = q >> power; den = 0x1 << (16 - power); } +#define EXTRADATA_IDX(__num_planes) ((__num_planes) ? (__num_planes) - 1 : 0) + +#define DEFAULT_EXTRADATA (OMX_INTERLACE_EXTRADATA) + +static OMX_U32 maxSmoothStreamingWidth = 1920; +static OMX_U32 maxSmoothStreamingHeight = 1088; +void* async_message_thread (void *input) +{ + OMX_BUFFERHEADERTYPE *buffer; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + struct pollfd pfd; + struct v4l2_buffer v4l2_buf; + memset((void *)&v4l2_buf,0,sizeof(v4l2_buf)); + struct v4l2_event dqevent; + omx_vdec *omx = reinterpret_cast<omx_vdec*>(input); + pfd.events = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLRDBAND | POLLPRI; + pfd.fd = omx->drv_ctx.video_driver_fd; + int error_code = 0,rc=0,bytes_read = 0,bytes_written = 0; + DEBUG_PRINT_HIGH("omx_vdec: Async thread start"); + prctl(PR_SET_NAME, (unsigned long)"VideoDecCallBackThread", 0, 0, 0); + while (1) + { + rc = poll(&pfd, 1, POLL_TIMEOUT); + if (!rc) { + DEBUG_PRINT_ERROR("Poll timedout"); + break; + } else if (rc < 0) { + DEBUG_PRINT_ERROR("Error while polling: %d", rc); + break; + } + if ((pfd.revents & POLLIN) || (pfd.revents & POLLRDNORM)) { + struct vdec_msginfo vdec_msg; + memset(&vdec_msg, 0, sizeof(vdec_msg)); + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.length = omx->drv_ctx.num_planes; + v4l2_buf.m.planes = plane; + while(!ioctl(pfd.fd, VIDIOC_DQBUF, &v4l2_buf)) { + vdec_msg.msgcode=VDEC_MSG_RESP_OUTPUT_BUFFER_DONE; + vdec_msg.status_code=VDEC_S_SUCCESS; + vdec_msg.msgdata.output_frame.client_data=(void*)&v4l2_buf; + vdec_msg.msgdata.output_frame.len=plane[0].bytesused; + vdec_msg.msgdata.output_frame.bufferaddr=(void*)plane[0].m.userptr; + vdec_msg.msgdata.output_frame.time_stamp= ((uint64_t)v4l2_buf.timestamp.tv_sec * (uint64_t)1000000) + + (uint64_t)v4l2_buf.timestamp.tv_usec; + if (vdec_msg.msgdata.output_frame.len) { + vdec_msg.msgdata.output_frame.framesize.left = plane[0].reserved[2]; + vdec_msg.msgdata.output_frame.framesize.top = plane[0].reserved[3]; + vdec_msg.msgdata.output_frame.framesize.right = plane[0].reserved[4]; + vdec_msg.msgdata.output_frame.framesize.bottom = plane[0].reserved[5]; + } + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } + } + if((pfd.revents & POLLOUT) || (pfd.revents & POLLWRNORM)) { + struct vdec_msginfo vdec_msg; + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.length = 1; + v4l2_buf.m.planes = plane; + while(!ioctl(pfd.fd, VIDIOC_DQBUF, &v4l2_buf)) { + vdec_msg.msgcode=VDEC_MSG_RESP_INPUT_BUFFER_DONE; + vdec_msg.status_code=VDEC_S_SUCCESS; + vdec_msg.msgdata.input_frame_clientdata=(void*)&v4l2_buf; + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } + } + if (pfd.revents & POLLPRI){ + rc = ioctl(pfd.fd, VIDIOC_DQEVENT, &dqevent); + if(dqevent.type == V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT ) { + struct vdec_msginfo vdec_msg; + vdec_msg.msgcode=VDEC_MSG_EVT_CONFIG_CHANGED; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_HIGH("VIDC Port Reconfig recieved insufficient"); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_FLUSH_DONE) { + struct vdec_msginfo vdec_msg; + vdec_msg.msgcode=VDEC_MSG_RESP_FLUSH_INPUT_DONE; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_HIGH("VIDC Input Flush Done Recieved "); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + vdec_msg.msgcode=VDEC_MSG_RESP_FLUSH_OUTPUT_DONE; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_HIGH("VIDC Output Flush Done Recieved "); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_CLOSE_DONE) { + DEBUG_PRINT_HIGH("VIDC Close Done Recieved and async_message_thread Exited"); + break; + } else if(dqevent.type == V4L2_EVENT_MSM_VIDC_SYS_ERROR) { + struct vdec_msginfo vdec_msg; + vdec_msg.msgcode=VDEC_MSG_EVT_HW_ERROR; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_HIGH("SYS Error Recieved"); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE) { + unsigned char *tmp = dqevent.u.data; + unsigned int *ptr = (unsigned int *)tmp; + DEBUG_PRINT_LOW("REFERENCE RELEASE EVENT RECVD fd = %d offset = %d", ptr[0], ptr[1]); + omx->buf_ref_remove(ptr[0], ptr[1]); + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER) { + unsigned char *tmp = dqevent.u.data; + unsigned int *ptr = (unsigned int *)tmp; + + struct vdec_msginfo vdec_msg; + + DEBUG_PRINT_LOW("Release unqueued buffer event recvd fd = %d offset = %d", ptr[0], ptr[1]); + + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.length = omx->drv_ctx.num_planes; + v4l2_buf.m.planes = plane; + v4l2_buf.index = ptr[5]; + v4l2_buf.flags = 0; + + vdec_msg.msgcode = VDEC_MSG_RESP_OUTPUT_BUFFER_DONE; + vdec_msg.status_code = VDEC_S_SUCCESS; + vdec_msg.msgdata.output_frame.client_data = (void*)&v4l2_buf; + vdec_msg.msgdata.output_frame.len = 0; + vdec_msg.msgdata.output_frame.bufferaddr = (void*)(intptr_t)ptr[2]; + vdec_msg.msgdata.output_frame.time_stamp = ((uint64_t)ptr[3] * (uint64_t)1000000) + + (uint64_t)ptr[4]; + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited "); + break; + } + } else { + DEBUG_PRINT_HIGH("VIDC Some Event recieved"); + continue; + } + } + } + DEBUG_PRINT_HIGH("omx_vdec: Async thread stop"); + return NULL; +} + +void* message_thread(void *input) +{ + omx_vdec* omx = reinterpret_cast<omx_vdec*>(input); + unsigned char id; + int n; + if (omx == NULL) + { + DEBUG_PRINT_ERROR("message thread null pointer rxd"); + return NULL; + } + + DEBUG_PRINT_HIGH("omx_vdec: message thread start"); + prctl(PR_SET_NAME, (unsigned long)"VideoDecMsgThread", 0, 0, 0); + while (1) + { + + n = read(omx->m_pipe_in, &id, 1); + + if(0 == n) + { + break; + } + + if (1 == n) + { + omx->process_event_cb(omx, id); + } + if ((n < 0) && (errno != EINTR)) + { + DEBUG_PRINT_ERROR("ERROR: read from pipe failed, ret %d errno %d", n, errno); + break; + } + } + DEBUG_PRINT_HIGH("omx_vdec: message thread stop"); + return NULL; +} + +void post_message(omx_vdec *omx, unsigned char id) +{ + int ret_value; + + if (omx == NULL) + { + DEBUG_PRINT_ERROR("message thread null pointer rxd"); + return; + } + DEBUG_PRINT_LOW("omx_vdec: post_message %d pipe out%d", id,omx->m_pipe_out); + ret_value = write(omx->m_pipe_out, &id, 1); + DEBUG_PRINT_LOW("post_message to pipe done %d",ret_value); +} + +// omx_cmd_queue destructor +omx_vdec::omx_cmd_queue::~omx_cmd_queue() +{ + // Nothing to do +} + +// omx cmd queue constructor +omx_vdec::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0) +{ + memset(m_q,0,sizeof(m_q)); +} + +// omx cmd queue insert +bool omx_vdec::omx_cmd_queue::insert_entry(unsigned long p1, unsigned long p2, unsigned long id) +{ + bool ret = true; + if(m_size < OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_q[m_write].id = id; + m_q[m_write].param1 = p1; + m_q[m_write].param2 = p2; + m_write++; + m_size ++; + if(m_write >= OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_write = 0; + } + } + else + { + ret = false; + DEBUG_PRINT_ERROR("ERROR: %s()::Command Queue Full", __func__); + } + return ret; +} + +// omx cmd queue pop +bool omx_vdec::omx_cmd_queue::pop_entry(unsigned long *p1, unsigned long *p2, unsigned long*id) +{ + bool ret = true; + if (m_size > 0) + { + *id = m_q[m_read].id; + *p1 = m_q[m_read].param1; + *p2 = m_q[m_read].param2; + // Move the read pointer ahead + ++m_read; + --m_size; + if(m_read >= OMX_CORE_CONTROL_CMDQ_SIZE) + { + m_read = 0; + } + } + else + { + ret = false; + } + return ret; +} + +// Retrieve the first mesg type in the queue +unsigned omx_vdec::omx_cmd_queue::get_q_msg_type() +{ + return m_q[m_read].id; +} + +#ifdef _ANDROID_ +omx_vdec::ts_arr_list::ts_arr_list() +{ + //initialize timestamps array + memset(m_ts_arr_list, 0, sizeof(m_ts_arr_list) ); +} +omx_vdec::ts_arr_list::~ts_arr_list() +{ + //free m_ts_arr_list? +} + +bool omx_vdec::ts_arr_list::insert_ts(OMX_TICKS ts) +{ + bool ret = true; + bool duplicate_ts = false; + int idx = 0; + + //insert at the first available empty location + for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) + { + if (!m_ts_arr_list[idx].valid) + { + //found invalid or empty entry, save timestamp + m_ts_arr_list[idx].valid = true; + m_ts_arr_list[idx].timestamp = ts; + DEBUG_PRINT_LOW("Insert_ts(): Inserting TIMESTAMP (%lld) at idx (%d)", + ts, idx); + break; + } + } + + if (idx == MAX_NUM_INPUT_OUTPUT_BUFFERS) + { + DEBUG_PRINT_LOW("Timestamp array list is FULL. Unsuccessful insert"); + ret = false; + } + return ret; +} + +bool omx_vdec::ts_arr_list::pop_min_ts(OMX_TICKS &ts) +{ + bool ret = true; + int min_idx = -1; + OMX_TICKS min_ts = 0; + int idx = 0; + + for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) + { + + if (m_ts_arr_list[idx].valid) + { + //found valid entry, save index + if (min_idx < 0) + { + //first valid entry + min_ts = m_ts_arr_list[idx].timestamp; + min_idx = idx; + } + else if (m_ts_arr_list[idx].timestamp < min_ts) + { + min_ts = m_ts_arr_list[idx].timestamp; + min_idx = idx; + } + } + + } + + if (min_idx < 0) + { + //no valid entries found + DEBUG_PRINT_LOW("Timestamp array list is empty. Unsuccessful pop"); + ts = 0; + ret = false; + } + else + { + ts = m_ts_arr_list[min_idx].timestamp; + m_ts_arr_list[min_idx].valid = false; + DEBUG_PRINT_LOW("Pop_min_ts:Timestamp (%lld), index(%d)", + ts, min_idx); + } + + return ret; + +} + + +bool omx_vdec::ts_arr_list::reset_ts_list() +{ + bool ret = true; + int idx = 0; + + DEBUG_PRINT_LOW("reset_ts_list(): Resetting timestamp array list"); + for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) + { + m_ts_arr_list[idx].valid = false; + } + return ret; +} +#endif + +// factory function executed by the core to create instances +void *get_omx_component_factory_fn(void) +{ + return (new omx_vdec); +} + +#ifdef _ANDROID_ +#ifdef USE_ION +VideoHeap::VideoHeap(int devicefd, size_t size, void* base, +ion_user_handle_t handle, int ionMapfd) +{ + (void) devicefd; + (void) size; + (void) base; + (void) handle; + (void) ionMapfd; + // ionInit(devicefd, base, size, 0 , MEM_DEVICE,handle,ionMapfd); +} +#else +VideoHeap::VideoHeap(int fd, size_t size, void* base) +{ + // dup file descriptor, map once, use pmem + init(dup(fd), base, size, 0 , MEM_DEVICE); +} +#endif +#endif // _ANDROID_ +/* ====================================================================== +FUNCTION +omx_vdec::omx_vdec + +DESCRIPTION +Constructor + +PARAMETERS +None + +RETURN VALUE +None. +========================================================================== */ +omx_vdec::omx_vdec(): + m_error_propogated(false), + m_state(OMX_StateInvalid), + m_app_data(NULL), + m_inp_mem_ptr(NULL), + m_out_mem_ptr(NULL), + m_inp_err_count(0), + input_flush_progress (false), + output_flush_progress (false), + input_use_buffer (false), + output_use_buffer (false), + ouput_egl_buffers(false), + m_use_output_pmem(OMX_FALSE), + m_out_mem_region_smi(OMX_FALSE), + m_out_pvt_entry_pmem(OMX_FALSE), + pending_input_buffers(0), + pending_output_buffers(0), + m_out_bm_count(0), + m_inp_bm_count(0), + m_inp_bPopulated(OMX_FALSE), + m_out_bPopulated(OMX_FALSE), + m_flags(0), +#ifdef _ANDROID_ + m_heap_ptr(NULL), +#endif + m_inp_bEnabled(OMX_TRUE), + m_out_bEnabled(OMX_TRUE), + m_in_alloc_cnt(0), + m_platform_list(NULL), + m_platform_entry(NULL), + m_pmem_info(NULL), + m_pSwVdec(NULL), + m_pSwVdecIpBuffer(NULL), + m_pSwVdecOpBuffer(NULL), + m_nInputBuffer(0), + m_nOutputBuffer(0), + m_interm_mem_ptr(NULL), + m_interm_flush_dsp_progress(OMX_FALSE), + m_interm_flush_swvdec_progress(OMX_FALSE), + m_interm_bPopulated(OMX_FALSE), + m_interm_bEnabled(OMX_TRUE), + m_swvdec_mode(-1), + m_fill_internal_bufers(OMX_TRUE), + arbitrary_bytes (true), + psource_frame (NULL), + pdest_frame (NULL), + m_inp_heap_ptr (NULL), + m_phdr_pmem_ptr(NULL), + m_heap_inp_bm_count (0), + codec_type_parse ((codec_type)0), + first_frame_meta (true), + frame_count (0), + nal_count (0), + nal_length(0), + look_ahead_nal (false), + first_frame(0), + first_buffer(NULL), + first_frame_size (0), + m_device_file_ptr(NULL), + m_vc1_profile((vc1_profile_type)0), + h264_last_au_ts(LLONG_MAX), + h264_last_au_flags(0), + prev_ts(LLONG_MAX), + rst_prev_ts(true), + frm_int(0), + in_reconfig(false), + m_display_id(NULL), + h264_parser(NULL), + client_extradata(0), +#ifdef _ANDROID_ + m_enable_android_native_buffers(OMX_FALSE), + m_use_android_native_buffers(OMX_FALSE), +#endif + m_desc_buffer_ptr(NULL), + secure_mode(false), + codec_config_flag(false) +{ + /* Assumption is that , to begin with , we have all the frames with decoder */ + DEBUG_PRINT_HIGH("In OMX vdec Constructor"); +#ifdef _ANDROID_ + char property_value[PROPERTY_VALUE_MAX] = {0}; + property_get("vidc.debug.level", property_value, "1"); + debug_level = atoi(property_value); + + DEBUG_PRINT_HIGH("In OMX vdec Constructor"); + + property_value[0] = '\0'; + property_get("vidc.dec.debug.perf", property_value, "0"); + perf_flag = atoi(property_value); + if (perf_flag) + { + DEBUG_PRINT_HIGH("vidc.dec.debug.perf is %d", perf_flag); + dec_time.start(); + proc_frms = latency = 0; + } + prev_n_filled_len = 0; + property_value[0] = '\0'; + property_get("vidc.dec.debug.ts", property_value, "0"); + m_debug_timestamp = atoi(property_value); + DEBUG_PRINT_HIGH("vidc.dec.debug.ts value is %d",m_debug_timestamp); + if (m_debug_timestamp) + { + time_stamp_dts.set_timestamp_reorder_mode(true); + time_stamp_dts.enable_debug_print(true); + } + memset(&m_debug, 0, sizeof(m_debug)); + property_value[0] = '\0'; + property_get("vidc.dec.debug.concealedmb", property_value, "0"); + m_debug_concealedmb = atoi(property_value); + DEBUG_PRINT_HIGH("vidc.dec.debug.concealedmb value is %d",m_debug_concealedmb); + + property_value[0] = '\0'; + property_get("vidc.dec.log.in", property_value, "0"); + m_debug.in_buffer_log = atoi(property_value); + + property_value[0] = '\0'; + property_get("vidc.dec.log.out", property_value, "0"); + m_debug.out_buffer_log = atoi(property_value); + + property_value[0] = '\0'; + property_get("vidc.dec.log.imb", property_value, "0"); + m_debug.im_buffer_log = atoi(property_value); + + sprintf(m_debug.log_loc, "%s", BUFFER_LOG_LOC); + property_value[0] = '\0'; + property_get("vidc.log.loc", property_value, ""); + if (*property_value) + strlcpy(m_debug.log_loc, property_value, PROPERTY_VALUE_MAX); + + property_value[0] = '\0'; + property_get("vidc.dec.debug.dyn.disabled", property_value, "0"); + m_disable_dynamic_buf_mode = atoi(property_value); +#endif + memset(&m_cmp,0,sizeof(m_cmp)); + memset(&m_cb,0,sizeof(m_cb)); + memset (&drv_ctx,0,sizeof(drv_ctx)); + memset (&h264_scratch,0,sizeof (OMX_BUFFERHEADERTYPE)); + memset (m_hwdevice_name,0,sizeof(m_hwdevice_name)); + memset(m_demux_offsets, 0, sizeof(m_demux_offsets) ); + m_demux_entries = 0; + msg_thread_id = 0; + async_thread_id = 0; + msg_thread_created = false; + async_thread_created = false; +#ifdef _ANDROID_ICS_ + memset(&native_buffer, 0 ,(sizeof(struct nativebuffer) * MAX_NUM_INPUT_OUTPUT_BUFFERS)); +#endif + memset(&drv_ctx.extradata_info, 0, sizeof(drv_ctx.extradata_info)); + drv_ctx.timestamp_adjust = false; + drv_ctx.video_driver_fd = -1; + m_vendor_config.pData = NULL; + pthread_mutexattr_t attr; + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&m_lock, &attr); + pthread_mutex_init(&c_lock, &attr); + sem_init(&m_cmd_lock,0,0); + streaming[CAPTURE_PORT] = + streaming[OUTPUT_PORT] = false; +#ifdef _ANDROID_ + char extradata_value[PROPERTY_VALUE_MAX] = {0}; + property_get("vidc.dec.debug.extradata", extradata_value, "0"); + m_debug_extradata = atoi(extradata_value); + DEBUG_PRINT_HIGH("vidc.dec.debug.extradata value is %d",m_debug_extradata); +#endif + m_fill_output_msg = OMX_COMPONENT_GENERATE_FTB; + client_buffers.set_vdec_client(this); + + dynamic_buf_mode = false; + out_dynamic_list = NULL; + m_smoothstreaming_mode = false; + m_smoothstreaming_width = 0; + m_smoothstreaming_height = 0; +} + +static const int event_type[] = { + V4L2_EVENT_MSM_VIDC_FLUSH_DONE, + V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT, + V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT, + V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE, + V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER, + V4L2_EVENT_MSM_VIDC_CLOSE_DONE, + V4L2_EVENT_MSM_VIDC_SYS_ERROR +}; + +static OMX_ERRORTYPE subscribe_to_events(int fd) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_event_subscription sub; + int array_sz = sizeof(event_type)/sizeof(int); + int i,rc; + if (fd < 0) { + DEBUG_PRINT_ERROR("Invalid input: %d", fd); + return OMX_ErrorBadParameter; + } + + for (i = 0; i < array_sz; ++i) { + memset(&sub, 0, sizeof(sub)); + sub.type = event_type[i]; + rc = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub); + if (rc) { + DEBUG_PRINT_ERROR("Failed to subscribe event: 0x%x", sub.type); + break; + } + } + if (i < array_sz) { + for (--i; i >=0 ; i--) { + memset(&sub, 0, sizeof(sub)); + sub.type = event_type[i]; + rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub); + if (rc) + DEBUG_PRINT_ERROR("Failed to unsubscribe event: 0x%x", sub.type); + } + eRet = OMX_ErrorNotImplemented; + } + return eRet; +} + + +static OMX_ERRORTYPE unsubscribe_to_events(int fd) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_event_subscription sub; + int array_sz = sizeof(event_type)/sizeof(int); + int i,rc; + if (fd < 0) { + DEBUG_PRINT_ERROR("Invalid input: %d", fd); + return OMX_ErrorBadParameter; + } + + for (i = 0; i < array_sz; ++i) { + memset(&sub, 0, sizeof(sub)); + sub.type = event_type[i]; + rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub); + if (rc) { + DEBUG_PRINT_ERROR("Failed to unsubscribe event: 0x%x", sub.type); + break; + } + } + return eRet; +} + +/* ====================================================================== +FUNCTION +omx_vdec::~omx_vdec + +DESCRIPTION +Destructor + +PARAMETERS +None + +RETURN VALUE +None. +========================================================================== */ +omx_vdec::~omx_vdec() +{ + m_pmem_info = NULL; + struct v4l2_decoder_cmd dec; + DEBUG_PRINT_HIGH("In OMX vdec Destructor"); + if(m_pipe_in) close(m_pipe_in); + if(m_pipe_out) close(m_pipe_out); + m_pipe_in = -1; + m_pipe_out = -1; + DEBUG_PRINT_HIGH("Waiting on OMX Msg Thread exit"); + + if (msg_thread_created) + pthread_join(msg_thread_id,NULL); + if ((!m_pSwVdec || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) && + (m_swvdec_mode != SWVDEC_MODE_PARSE_DECODE)) + { + DEBUG_PRINT_HIGH("Waiting on OMX Async Thread exit driver id %d", drv_ctx.video_driver_fd); + dec.cmd = V4L2_DEC_CMD_STOP; + if (drv_ctx.video_driver_fd >=0 ) + { + DEBUG_PRINT_HIGH("Stop decoder driver instance"); + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_DECODER_CMD, &dec)) + { + DEBUG_PRINT_ERROR("STOP Command failed"); + } + } + + if (async_thread_created) + pthread_join(async_thread_id,NULL); + + unsubscribe_to_events(drv_ctx.video_driver_fd); + close(drv_ctx.video_driver_fd); + } + + if (m_pSwVdec) + { + DEBUG_PRINT_HIGH("SwVdec_Stop"); + if (SWVDEC_S_SUCCESS != SwVdec_Stop(m_pSwVdec)) + { + DEBUG_PRINT_ERROR("SwVdec_Stop Command failed in vdec destructor"); + SwVdec_DeInit(m_pSwVdec); + m_pSwVdec = NULL; + } + } + + pthread_mutex_destroy(&m_lock); + pthread_mutex_destroy(&c_lock); + sem_destroy(&m_cmd_lock); + if (perf_flag) + { + DEBUG_PRINT_HIGH("--> TOTAL PROCESSING TIME"); + dec_time.end(); + } + DEBUG_PRINT_HIGH("Exit OMX vdec Destructor"); +} + +int release_buffers(omx_vdec* obj, enum vdec_buffer buffer_type) +{ + struct v4l2_requestbuffers bufreq; + int rc = 0; + if (buffer_type == VDEC_BUFFER_TYPE_OUTPUT){ + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = 0; + bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + rc = ioctl(obj->drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); + } else if(buffer_type == VDEC_BUFFER_TYPE_INPUT) { + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = 0; + bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + rc = ioctl(obj->drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); + } + return rc; +} + +/* ====================================================================== +FUNCTION +omx_vdec::OMXCntrlProcessMsgCb + +DESCRIPTION +IL Client callbacks are generated through this routine. The decoder +provides the thread context for this routine. + +PARAMETERS +ctxt -- Context information related to the self. +id -- Event identifier. This could be any of the following: +1. Command completion event +2. Buffer done callback event +3. Frame done callback event + +RETURN VALUE +None. + +========================================================================== */ +void omx_vdec::process_event_cb(void *ctxt, unsigned char id) +{ + unsigned long p1; // Parameter - 1 + unsigned long p2; // Parameter - 2 + unsigned long ident; + unsigned int qsize=0; // qsize + omx_vdec *pThis = (omx_vdec *) ctxt; + + if(!pThis) + { + DEBUG_PRINT_ERROR("ERROR: %s()::Context is incorrect, bailing out", + __func__); + return; + } + + // Protect the shared queue data structure + do + { + /*Read the message id's from the queue*/ + pthread_mutex_lock(&pThis->m_lock); + qsize = pThis->m_cmd_q.m_size; + if(qsize) + { + pThis->m_cmd_q.pop_entry(&p1, &p2, &ident); + } + + if (qsize == 0 && pThis->m_state != OMX_StatePause) + { + qsize = pThis->m_ftb_q.m_size; + if (qsize) + { + pThis->m_ftb_q.pop_entry(&p1, &p2, &ident); + } + } + + if (qsize == 0 && pThis->m_state != OMX_StatePause) + { + qsize = pThis->m_ftb_q_dsp.m_size; + if (qsize) + { + pThis->m_ftb_q_dsp.pop_entry(&p1, &p2, &ident); + } + } + + if (qsize == 0 && pThis->m_state != OMX_StatePause) + { + qsize = pThis->m_etb_q.m_size; + if (qsize) + { + pThis->m_etb_q.pop_entry(&p1, &p2, &ident); + } + } + + if (qsize == 0 && pThis->m_state != OMX_StatePause) + { + qsize = pThis->m_etb_q_swvdec.m_size; + if (qsize) + { + pThis->m_etb_q_swvdec.pop_entry(&p1, &p2, &ident); + } + } + + pthread_mutex_unlock(&pThis->m_lock); + + /*process message if we have one*/ + if(qsize > 0) + { + id = ident; + switch (id) + { + case OMX_COMPONENT_GENERATE_EVENT: + if (pThis->m_cb.EventHandler) + { + switch (p1) + { + case OMX_CommandStateSet: + pThis->m_state = (OMX_STATETYPE) p2; + DEBUG_PRINT_HIGH("OMX_CommandStateSet complete, m_state = %d", + pThis->m_state); + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete, p1, p2, NULL); + break; + + case OMX_EventError: + if(p2 == (unsigned long)OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("OMX_EventError: p2 is OMX_StateInvalid"); + pThis->m_state = (OMX_STATETYPE) p2; + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, p2, NULL); + } + else if (p2 == (unsigned long)OMX_ErrorHardware) + { + pThis->omx_report_error(); + } + else + { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventError, p2, (OMX_U32)NULL, NULL ); + } + break; + + case OMX_CommandPortDisable: + DEBUG_PRINT_HIGH("OMX_CommandPortDisable complete for port [%lu]", p2); + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING)) + { + BITMASK_SET(&pThis->m_flags, OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED); + break; + } + if (p2 == OMX_CORE_OUTPUT_PORT_INDEX && pThis->in_reconfig) + { + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (!pThis->m_pSwVdec || pThis->m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + pThis->stream_off(OMX_CORE_OUTPUT_PORT_INDEX); + if(release_buffers(pThis, VDEC_BUFFER_TYPE_OUTPUT)) + DEBUG_PRINT_HIGH("Failed to release output buffers"); + } + + if (pThis->m_pSwVdec) + { + SWVDEC_STATUS SwStatus; + DEBUG_PRINT_HIGH("In port reconfig, SwVdec_Stop"); + SwStatus = SwVdec_Stop(pThis->m_pSwVdec); + if (SWVDEC_S_SUCCESS != SwStatus) + { + DEBUG_PRINT_ERROR("SwVdec_Stop failed (%d)",SwStatus); + pThis->omx_report_error(); + break; + } + } + + OMX_ERRORTYPE eRet1 = pThis->get_buffer_req_swvdec(); + pThis->in_reconfig = false; + if(eRet != OMX_ErrorNone) + { + DEBUG_PRINT_ERROR("get_buffer_req_swvdec failed eRet = %d",eRet); + pThis->omx_report_error(); + break; + } + } + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete, p1, p2, NULL ); + break; + case OMX_CommandPortEnable: + DEBUG_PRINT_HIGH("OMX_CommandPortEnable complete for port [%d]", p2); + if (p2 == OMX_CORE_OUTPUT_PORT_INDEX && + pThis->m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + DEBUG_PRINT_LOW("send all interm buffers to dsp after port enabled"); + pThis->fill_all_buffers_proxy_dsp(&pThis->m_cmp); + } + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,\ + OMX_EventCmdComplete, p1, p2, NULL ); + break; + + default: + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete, p1, p2, NULL ); + break; + + } + } + else + { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + break; + case OMX_COMPONENT_GENERATE_ETB_ARBITRARY: + if (pThis->empty_this_buffer_proxy_arbitrary((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) + { + DEBUG_PRINT_ERROR("empty_this_buffer_proxy_arbitrary failure"); + pThis->omx_report_error (); + } + break; + case OMX_COMPONENT_GENERATE_ETB: + if (pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) + { + DEBUG_PRINT_ERROR("empty_this_buffer_proxy failure"); + pThis->omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_FTB: + if ( pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) + { + DEBUG_PRINT_ERROR("fill_this_buffer_proxy failure"); + pThis->omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_COMMAND: + pThis->send_command_proxy(&pThis->m_cmp,(OMX_COMMANDTYPE)p1,\ + (OMX_U32)p2,(OMX_PTR)NULL); + break; + + case OMX_COMPONENT_GENERATE_EBD: + + if (p2 != VDEC_S_SUCCESS && p2 != VDEC_S_INPUT_BITSTREAM_ERR) + { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_EBD failure"); + pThis->omx_report_error (); + } + else + { + if (p2 == VDEC_S_INPUT_BITSTREAM_ERR && p1) + { + pThis->m_inp_err_count++; + pThis->time_stamp_dts.remove_time_stamp( + ((OMX_BUFFERHEADERTYPE *)p1)->nTimeStamp, + (pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) + ?true:false); + } + else + { + pThis->m_inp_err_count = 0; + } + if ( pThis->empty_buffer_done(&pThis->m_cmp, + (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone) + { + DEBUG_PRINT_ERROR("empty_buffer_done failure"); + pThis->omx_report_error (); + } + if(pThis->m_inp_err_count >= MAX_INPUT_ERROR) + { + DEBUG_PRINT_ERROR("Input bitstream error for consecutive %d frames.", MAX_INPUT_ERROR); + pThis->omx_report_error (); + } + } + break; + case OMX_COMPONENT_GENERATE_INFO_FIELD_DROPPED: + { + int64_t *timestamp = (int64_t *)p1; + if (p1) + { + pThis->time_stamp_dts.remove_time_stamp(*timestamp, + (pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) + ?true:false); + free(timestamp); + } + } + break; + case OMX_COMPONENT_GENERATE_FBD: + if (p2 != VDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_FBD failure"); + pThis->omx_report_error (); + } + else if ( pThis->fill_buffer_done(&pThis->m_cmp, + (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone ) + { + DEBUG_PRINT_ERROR("fill_buffer_done failure"); + pThis->omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH: + if (!pThis->input_flush_progress) + { + DEBUG_PRINT_ERROR("WARNING: Unexpected INPUT_FLUSH from driver"); + } + else + { + pThis->execute_input_flush(); + if (pThis->m_cb.EventHandler) + { + if (p2 != VDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH failure"); + pThis->omx_report_error (); + } + else + { + /*Check if we need generate event for Flush done*/ + if(BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_INPUT_FLUSH_PENDING)) + { + BITMASK_CLEAR (&pThis->m_flags,OMX_COMPONENT_INPUT_FLUSH_PENDING); + DEBUG_PRINT_LOW("Input Flush completed - Notify Client"); + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandFlush, + OMX_CORE_INPUT_PORT_INDEX,NULL ); + } + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_IDLE_PENDING)) + { + if (!pThis->m_pSwVdec || pThis->m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + if(pThis->stream_off(OMX_CORE_INPUT_PORT_INDEX)) { + DEBUG_PRINT_ERROR("Failed to call streamoff on OUTPUT Port"); + pThis->omx_report_error (); + } else { + pThis->streaming[OUTPUT_PORT] = false; + } + } + } + } + } + else + { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + } + break; + + case OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH: + DEBUG_PRINT_HIGH("Driver flush o/p Port complete"); + if (!pThis->output_flush_progress) + { + DEBUG_PRINT_ERROR("WARNING: Unexpected OUTPUT_FLUSH from driver"); + } + else + { + pThis->execute_output_flush(); + if (pThis->m_interm_flush_dsp_progress) + { + pThis->execute_output_flush_dsp(); + } + if (pThis->m_interm_flush_swvdec_progress) + { + pThis->execute_input_flush_swvdec(); + } + if (pThis->m_cb.EventHandler) + { + if (p2 != VDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH failed"); + pThis->omx_report_error (); + } + else + { + /*Check if we need generate event for Flush done*/ + if(BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_PENDING)) + { + if (pThis->release_interm_done() == false) + { + DEBUG_PRINT_ERROR("OMX_COMPONENT_OUTPUT_FLUSH failed not all interm buffers are returned"); + pThis->omx_report_error (); + break; + } + pThis->m_fill_internal_bufers = OMX_TRUE; + DEBUG_PRINT_HIGH("Notify Output Flush done"); + BITMASK_CLEAR (&pThis->m_flags,OMX_COMPONENT_OUTPUT_FLUSH_PENDING); + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandFlush, + OMX_CORE_OUTPUT_PORT_INDEX,NULL ); + } + if(BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING)) + { + DEBUG_PRINT_LOW("Internal flush complete"); + BITMASK_CLEAR (&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING); + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED)) + { + pThis->post_event((unsigned long)OMX_CommandPortDisable, + (unsigned long)OMX_CORE_OUTPUT_PORT_INDEX, + (unsigned long)OMX_COMPONENT_GENERATE_EVENT); + BITMASK_CLEAR (&pThis->m_flags, + OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED); + BITMASK_CLEAR (&pThis->m_flags, + OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + + } + } + + if (BITMASK_PRESENT(&pThis->m_flags ,OMX_COMPONENT_IDLE_PENDING)) + { + if (!pThis->m_pSwVdec || pThis->m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + if(pThis->stream_off(OMX_CORE_OUTPUT_PORT_INDEX)) { + DEBUG_PRINT_ERROR("Failed to call streamoff on CAPTURE Port"); + pThis->omx_report_error (); + break; + } + pThis->streaming[CAPTURE_PORT] = false; + } + if (!pThis->input_flush_progress) + { + DEBUG_PRINT_LOW("Output flush done hence issue stop"); + pThis->post_event ((unsigned long)NULL, (unsigned long)VDEC_S_SUCCESS,\ + (unsigned long)OMX_COMPONENT_GENERATE_STOP_DONE); + } + } + } + } + else + { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + } + break; + + case OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH_DSP: + DEBUG_PRINT_HIGH("Dsp Driver flush o/p Port complete"); + if (!pThis->m_interm_flush_dsp_progress) + { + DEBUG_PRINT_ERROR("WARNING: Unexpected OUTPUT_FLUSH_DSP from driver"); + } + else + { + // check if we need to flush swvdec + bool bFlushSwVdec = false; + SWVDEC_BUFFER_FLUSH_TYPE aFlushType = SWVDEC_FLUSH_ALL; + if (pThis->m_interm_flush_swvdec_progress) + { + aFlushType = SWVDEC_FLUSH_ALL; + bFlushSwVdec = true; + } + else if (pThis->output_flush_progress) + { + DEBUG_PRINT_HIGH("Flush swvdec output only "); + aFlushType = SWVDEC_FLUSH_OUTPUT; + bFlushSwVdec = true; + } + + DEBUG_PRINT_HIGH("Flush swvdec %d, interm flush %d output flush %d swvdec flushType %d", + bFlushSwVdec, pThis->m_interm_flush_swvdec_progress, pThis->output_flush_progress, aFlushType); + + if (bFlushSwVdec) + { + if (SwVdec_Flush(pThis->m_pSwVdec, aFlushType) != SWVDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("Flush swvdec Failed "); + } + } + else + { + pThis->execute_output_flush_dsp(); + } + } + break; + + case OMX_COMPONENT_GENERATE_START_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_START_DONE"); + + if (pThis->m_cb.EventHandler) + { + if (p2 != VDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_START_DONE Failure"); + pThis->omx_report_error (); + } + else + { + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_START_DONE Success"); + if(BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_EXECUTE_PENDING)) + { + DEBUG_PRINT_LOW("Move to executing"); + // Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_EXECUTE_PENDING); + pThis->m_state = OMX_StateExecuting; + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StateExecuting, NULL); + } + else if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_PAUSE_PENDING)) + { + if (/*ioctl (pThis->drv_ctx.video_driver_fd, + VDEC_IOCTL_CMD_PAUSE,NULL ) < */0) + { + DEBUG_PRINT_ERROR("VDEC_IOCTL_CMD_PAUSE failed"); + pThis->omx_report_error (); + } + } + } + } + else + { + DEBUG_PRINT_LOW("Event Handler callback is NULL"); + } + break; + + case OMX_COMPONENT_GENERATE_PAUSE_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_PAUSE_DONE"); + if (pThis->m_cb.EventHandler) + { + if (p2 != VDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_PAUSE_DONE ret failed"); + pThis->omx_report_error (); + } + else + { + pThis->complete_pending_buffer_done_cbs(); + if(BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_PAUSE_PENDING)) + { + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_PAUSE_DONE nofity"); + //Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_PAUSE_PENDING); + pThis->m_state = OMX_StatePause; + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StatePause, NULL); + } + } + } + else + { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + + break; + + case OMX_COMPONENT_GENERATE_RESUME_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_RESUME_DONE"); + if (pThis->m_cb.EventHandler) + { + if (p2 != VDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_RESUME_DONE failed"); + pThis->omx_report_error (); + } + else + { + if(BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_EXECUTE_PENDING)) + { + DEBUG_PRINT_LOW("Moving the decoder to execute state"); + // Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_EXECUTE_PENDING); + pThis->m_state = OMX_StateExecuting; + if (pThis->m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + pThis->fill_all_buffers_proxy_dsp(&pThis->m_cmp); + } + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StateExecuting,NULL); + } + } + } + else + { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + + break; + + case OMX_COMPONENT_GENERATE_STOP_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_STOP_DONE"); + if (pThis->m_cb.EventHandler) + { + if (p2 != VDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_STOP_DONE ret failed"); + pThis->omx_report_error (); + } + else + { + pThis->complete_pending_buffer_done_cbs(); + if(BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_STOP_DONE Success"); + // Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_IDLE_PENDING); + pThis->m_state = OMX_StateIdle; + DEBUG_PRINT_LOW("Move to Idle State"); + pThis->m_cb.EventHandler(&pThis->m_cmp,pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StateIdle,NULL); + } + } + } + else + { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + + break; + + case OMX_COMPONENT_GENERATE_PORT_RECONFIG: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_PORT_RECONFIG"); + + if (p2 == OMX_IndexParamPortDefinition) { + pThis->in_reconfig = true; + } + if (pThis->m_cb.EventHandler) { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventPortSettingsChanged, p1, p2, NULL ); + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + + if (pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) + { + OMX_INTERLACETYPE format = (OMX_INTERLACETYPE)-1; + OMX_EVENTTYPE event = (OMX_EVENTTYPE)OMX_EventIndexsettingChanged; + if (pThis->drv_ctx.interlace == VDEC_InterlaceInterleaveFrameTopFieldFirst) + format = OMX_InterlaceInterleaveFrameTopFieldFirst; + else if (pThis->drv_ctx.interlace == VDEC_InterlaceInterleaveFrameBottomFieldFirst) + format = OMX_InterlaceInterleaveFrameBottomFieldFirst; + else //unsupported interlace format; raise a error + event = OMX_EventError; + if (pThis->m_cb.EventHandler) { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + event, format, 0, NULL ); + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + } + break; + + case OMX_COMPONENT_GENERATE_EOS_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_EOS_DONE"); + if (pThis->m_cb.EventHandler) { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, OMX_EventBufferFlag, + OMX_CORE_OUTPUT_PORT_INDEX, OMX_BUFFERFLAG_EOS, NULL ); + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + pThis->prev_ts = LLONG_MAX; + pThis->rst_prev_ts = true; + break; + + case OMX_COMPONENT_GENERATE_HARDWARE_ERROR: + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_HARDWARE_ERROR"); + pThis->omx_report_error (); + break; + + case OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING: + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING"); + pThis->omx_report_unsupported_setting(); + break; + + case OMX_COMPONENT_GENERATE_INFO_PORT_RECONFIG: + { + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_INFO_PORT_RECONFIG"); + if (pThis->m_cb.EventHandler) { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + (OMX_EVENTTYPE)OMX_EventIndexsettingChanged, OMX_CORE_OUTPUT_PORT_INDEX, 0, NULL ); + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + } + break; + + case OMX_COMPONENT_GENERATE_ETB_SWVDEC: + { + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_ETB_SWVDEC"); + if (pThis->empty_this_buffer_proxy_swvdec((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) + { + DEBUG_PRINT_ERROR("empty_this_buffer_proxy_swvdec failure"); + pThis->omx_report_error (); + } + } + break; + + case OMX_COMPONENT_GENERATE_EBD_SWVDEC: + { + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_EBD_SWVDEC"); + if (p2 != VDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_EBD_SWVDEC failure"); + pThis->omx_report_error (); + } + else if ( pThis->empty_buffer_done_swvdec(&pThis->m_cmp, + (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone) + { + DEBUG_PRINT_ERROR("empty_buffer_done_swvdec failure"); + pThis->omx_report_error (); + } + } + break; + + case OMX_COMPONENT_GENERATE_FTB_DSP: + { + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_FTB_DSP"); + if ( pThis->fill_this_buffer_proxy_dsp((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) + { + DEBUG_PRINT_ERROR("fill_this_buffer_proxy_dsp failure"); + pThis->omx_report_error (); + } + } + break; + + case OMX_COMPONENT_GENERATE_FBD_DSP: + { + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_FBD_DSP"); + if (p2 != VDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_FBD_DSP failure"); + pThis->omx_report_error (); + } + else if ( pThis->fill_buffer_done_dsp(&pThis->m_cmp, + (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone ) + { + DEBUG_PRINT_ERROR("fill_buffer_done failure"); + pThis->omx_report_error (); + } + + + } + break; + + default: + break; + } + } + pthread_mutex_lock(&pThis->m_lock); + qsize = pThis->m_cmd_q.m_size; + if (pThis->m_state != OMX_StatePause) + qsize += (pThis->m_ftb_q.m_size + pThis->m_etb_q.m_size + + pThis->m_ftb_q_dsp.m_size + pThis->m_etb_q_swvdec.m_size); + pthread_mutex_unlock(&pThis->m_lock); + } + while(qsize>0); + +} + +int omx_vdec::update_resolution(int width, int height, int stride, int scan_lines) +{ + int format_changed = 0; + if ((height != (int)drv_ctx.video_resolution.frame_height) || + (width != (int)drv_ctx.video_resolution.frame_width)) { + DEBUG_PRINT_HIGH("NOTE_CIF: W/H %d (%d), %d (%d)", + width, drv_ctx.video_resolution.frame_width, + height,drv_ctx.video_resolution.frame_height); + format_changed = 1; + } + drv_ctx.video_resolution.frame_height = height; + drv_ctx.video_resolution.frame_width = width; + drv_ctx.video_resolution.scan_lines = scan_lines; + drv_ctx.video_resolution.stride = stride; + rectangle.nLeft = 0; + rectangle.nTop = 0; + rectangle.nWidth = drv_ctx.video_resolution.frame_width; + rectangle.nHeight = drv_ctx.video_resolution.frame_height; + return format_changed; +} + +OMX_ERRORTYPE omx_vdec::is_video_session_supported() +{ + if ((drv_ctx.video_resolution.frame_width * drv_ctx.video_resolution.frame_height > + m_decoder_capability.max_width * m_decoder_capability.max_height) || + (drv_ctx.video_resolution.frame_width* drv_ctx.video_resolution.frame_height < + m_decoder_capability.min_width * m_decoder_capability.min_height)) + { + DEBUG_PRINT_ERROR( + "Unsupported WxH = (%u)x(%u) supported range is min(%u)x(%u) - max(%u)x(%u)", + drv_ctx.video_resolution.frame_width, + drv_ctx.video_resolution.frame_height, + m_decoder_capability.min_width, + m_decoder_capability.min_height, + m_decoder_capability.max_width, + m_decoder_capability.max_height); + return OMX_ErrorUnsupportedSetting; + } + DEBUG_PRINT_HIGH("video session supported"); + return OMX_ErrorNone; +} + +int omx_vdec::log_input_buffers(const char *buffer_addr, int buffer_len) +{ + if (m_debug.in_buffer_log && !m_debug.infile) { + if(!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.hevc", OMX_MAX_STRINGNAME_SIZE) || + !strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.hevchybrid", OMX_MAX_STRINGNAME_SIZE) || + !strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.hevcswvdec", OMX_MAX_STRINGNAME_SIZE)) { + sprintf(m_debug.infile_name, "%s/input_dec_%d_%d_%p.hevc", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + } + m_debug.infile = fopen (m_debug.infile_name, "ab"); + if (!m_debug.infile) { + DEBUG_PRINT_HIGH("Failed to open input file: %s for logging", m_debug.infile_name); + m_debug.infile_name[0] = '\0'; + return -1; + } + } + if (m_debug.infile && buffer_addr && buffer_len) { + fwrite(buffer_addr, buffer_len, 1, m_debug.infile); + } + return 0; +} + +int omx_vdec::log_output_buffers(OMX_BUFFERHEADERTYPE *buffer) +{ + if (m_debug.out_buffer_log && !m_debug.outfile) { + sprintf(m_debug.outfile_name, "%s/output_%d_%d_%p.yuv", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + m_debug.outfile = fopen (m_debug.outfile_name, "ab"); + if (!m_debug.outfile) { + DEBUG_PRINT_HIGH("Failed to open output file: %s for logging", m_debug.log_loc); + m_debug.outfile_name[0] = '\0'; + return -1; + } + } + if (m_debug.outfile && buffer && buffer->nFilledLen) { + int buf_index = buffer - m_out_mem_ptr; + int stride = drv_ctx.video_resolution.stride; + int scanlines = drv_ctx.video_resolution.scan_lines; + if (m_smoothstreaming_mode) { + stride = drv_ctx.video_resolution.frame_width; + scanlines = drv_ctx.video_resolution.frame_height; + stride = (stride + DEFAULT_WIDTH_ALIGNMENT - 1) & (~(DEFAULT_WIDTH_ALIGNMENT - 1)); + scanlines = (scanlines + DEFAULT_HEIGHT_ALIGNMENT - 1) & (~(DEFAULT_HEIGHT_ALIGNMENT - 1)); + } + char *temp = (char *)drv_ctx.ptr_outputbuffer[buf_index].bufferaddr; + unsigned i; + int bytes_written = 0; + DEBUG_PRINT_LOW("Logging width/height(%u/%u) stride/scanlines(%u/%u)", + drv_ctx.video_resolution.frame_width, + drv_ctx.video_resolution.frame_height, stride, scanlines); + for (i = 0; i < drv_ctx.video_resolution.frame_height; i++) { + bytes_written = fwrite(temp, drv_ctx.video_resolution.frame_width, 1, m_debug.outfile); + temp += stride; + } + temp = (char *)drv_ctx.ptr_outputbuffer[buf_index].bufferaddr + stride * scanlines; + int stride_c = stride; + for(i = 0; i < drv_ctx.video_resolution.frame_height/2; i++) { + bytes_written += fwrite(temp, drv_ctx.video_resolution.frame_width, 1, m_debug.outfile); + temp += stride_c; + } + } + return 0; +} + +int omx_vdec::log_im_buffer(OMX_BUFFERHEADERTYPE * buffer) +{ + if (m_debug.im_buffer_log && !m_debug.imbfile) { + sprintf(m_debug.imbfile_name, "%s/imb_%d_%d_%p.bin", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + m_debug.imbfile = fopen (m_debug.imbfile_name, "ab"); + if (!m_debug.imbfile) { + DEBUG_PRINT_HIGH("Failed to open intermediate file: %s for logging", m_debug.log_loc); + m_debug.imbfile_name[0] = '\0'; + return -1; + } + } + + if (buffer && buffer->nFilledLen) + { + fwrite(&buffer->nFilledLen, sizeof(buffer->nFilledLen), 1, m_debug.imbfile); + fwrite(buffer->pBuffer, sizeof(uint8), buffer->nFilledLen, m_debug.imbfile); + } + return 0; +} + +/* ====================================================================== +FUNCTION +omx_vdec::ComponentInit + +DESCRIPTION +Initialize the component. + +PARAMETERS +ctxt -- Context information related to the self. +id -- Event identifier. This could be any of the following: +1. Command completion event +2. Buffer done callback event +3. Frame done callback event + +RETURN VALUE +None. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::component_init(OMX_STRING role) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_fmtdesc fdesc; + struct v4l2_format fmt; + struct v4l2_requestbuffers bufreq; + struct v4l2_control control; + struct v4l2_frmsizeenum frmsize; + unsigned int alignment = 0,buffer_size = 0; + int fds[2]; + int r,ret=0; + bool codec_ambiguous = false; + + m_decoder_capability.min_width = 16; + m_decoder_capability.min_height = 16; + m_decoder_capability.max_width = 1920; + m_decoder_capability.max_height = 1080; + strlcpy(drv_ctx.kind,role,128); + OMX_STRING device_name = (OMX_STRING)"/dev/video/q6_dec"; + if((!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc", + OMX_MAX_STRINGNAME_SIZE)) || + (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevchybrid", + OMX_MAX_STRINGNAME_SIZE))) + { + drv_ctx.video_driver_fd = open(device_name, O_RDWR); + if(drv_ctx.video_driver_fd == 0){ + drv_ctx.video_driver_fd = open(device_name, O_RDWR); + } + if(drv_ctx.video_driver_fd < 0) + { + DEBUG_PRINT_ERROR("Omx_vdec::Comp Init Returning failure, errno %d", errno); + return OMX_ErrorInsufficientResources; + } + DEBUG_PRINT_HIGH("omx_vdec::component_init(%s): Open device %s returned fd %d", + role, device_name, drv_ctx.video_driver_fd); + } + else + DEBUG_PRINT_HIGH("Omx_vdec::Comp Init for full SW hence skip Q6 open"); + + // Copy the role information which provides the decoder kind + strlcpy(drv_ctx.kind,role,128); + strlcpy((char *)m_cRole, "video_decoder.hevc",OMX_MAX_STRINGNAME_SIZE); + if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevchybrid", + OMX_MAX_STRINGNAME_SIZE)) + { + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.width = 320; + fmt.fmt.pix_mp.height = 240; + fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_HEVC_HYBRID; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + DEBUG_PRINT_HIGH("Failed to set format(V4L2_PIX_FMT_HEVC_HYBRID)"); + DEBUG_PRINT_HIGH("Switch to HEVC fullDSP as HYBRID is not supported"); + strlcpy(drv_ctx.kind, "OMX.qcom.video.decoder.hevc", 128); + } + else { + DEBUG_PRINT_HIGH("HEVC HYBRID is supported"); + } + } + + if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevchybrid", + OMX_MAX_STRINGNAME_SIZE)) + { + DEBUG_PRINT_ERROR("HEVC Hybrid mode"); + m_swvdec_mode = SWVDEC_MODE_DECODE_ONLY; + } + else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevcswvdec", + OMX_MAX_STRINGNAME_SIZE)) + { + DEBUG_PRINT_ERROR("HEVC Full SW mode"); + maxSmoothStreamingWidth = 1280; + maxSmoothStreamingHeight = 720; + m_decoder_capability.max_width = 1280; + m_decoder_capability.max_height = 720; + m_swvdec_mode = SWVDEC_MODE_PARSE_DECODE; + } + else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc", + OMX_MAX_STRINGNAME_SIZE)) + { + DEBUG_PRINT_ERROR("Full DSP mode"); + maxSmoothStreamingWidth = 1280; + maxSmoothStreamingHeight = 720; + m_decoder_capability.max_width = 1280; + m_decoder_capability.max_height = 720; + m_swvdec_mode = -1; + } + else { + DEBUG_PRINT_ERROR("ERROR:Unknown Component"); + return OMX_ErrorInvalidComponentName; + } + + drv_ctx.decoder_format = VDEC_CODECTYPE_HEVC; + eCompressionFormat = OMX_VIDEO_CodingHEVC; + codec_type_parse = CODEC_TYPE_HEVC; + m_frame_parser.init_start_codes (codec_type_parse); + m_frame_parser.init_nal_length(nal_length); + + update_resolution(1280, 720, 1280, 720); + drv_ctx.output_format = VDEC_YUV_FORMAT_NV12; + OMX_COLOR_FORMATTYPE dest_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + if (!client_buffers.set_color_format(dest_color_format)) { + DEBUG_PRINT_ERROR("Setting color format failed"); + eRet = OMX_ErrorInsufficientResources; + } + + drv_ctx.frame_rate.fps_numerator = DEFAULT_FPS; + drv_ctx.frame_rate.fps_denominator = 1; + drv_ctx.ip_buf.buffer_type = VDEC_BUFFER_TYPE_INPUT; + drv_ctx.interm_op_buf.buffer_type = VDEC_BUFFER_TYPE_OUTPUT; + drv_ctx.op_buf.buffer_type = VDEC_BUFFER_TYPE_OUTPUT; + if (secure_mode) { + drv_ctx.interm_op_buf.alignment=SZ_1M; + drv_ctx.op_buf.alignment=SZ_1M; + drv_ctx.ip_buf.alignment=SZ_1M; + } else { + drv_ctx.op_buf.alignment=SZ_4K; + drv_ctx.interm_op_buf.alignment=SZ_4K; + drv_ctx.ip_buf.alignment=SZ_4K; + } + drv_ctx.interlace = VDEC_InterlaceFrameProgressive; + drv_ctx.extradata = 0; + drv_ctx.picture_order = VDEC_ORDER_DISPLAY; + + if (m_swvdec_mode >= 0) + { + // Init for SWCodec + DEBUG_PRINT_HIGH(":Initializing SwVdec mode %d", m_swvdec_mode); + memset(&sSwVdecParameter, 0, sizeof(SWVDEC_INITPARAMS)); + sSwVdecParameter.sDimensions.nWidth = 1280; + sSwVdecParameter.sDimensions.nHeight = 720; + sSwVdecParameter.eDecType = SWVDEC_DECODER_HEVC; + sSwVdecParameter.eColorFormat = SWVDEC_FORMAT_NV12; + sSwVdecParameter.uProfile.eHevcProfile = SWVDEC_HEVC_MAIN_PROFILE; + sSwVdecParameter.sMode.eMode = (SWVDEC_MODE_TYPE)m_swvdec_mode; + + //SWVDEC_CALLBACK m_callBackInfo; + m_callBackInfo.FillBufferDone = swvdec_fill_buffer_done_cb; + m_callBackInfo.EmptyBufferDone = swvdec_input_buffer_done_cb; + m_callBackInfo.HandleEvent = swvdec_handle_event_cb; + m_callBackInfo.pClientHandle = this; + SWVDEC_STATUS sRet = SwVdec_Init(&sSwVdecParameter, &m_callBackInfo, &m_pSwVdec); + if (sRet != SWVDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("SwVdec_Init returned %d, ret insufficient resources", sRet); + return OMX_ErrorInsufficientResources; + } + } + + if (!m_pSwVdec || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + ret = pthread_create(&async_thread_id,0,async_message_thread,this); + if(ret < 0) { + close(drv_ctx.video_driver_fd); + DEBUG_PRINT_ERROR("Failed to create async_message_thread"); + return OMX_ErrorInsufficientResources; + } + async_thread_created = true; + + capture_capability= V4L2_PIX_FMT_NV12; + ret = subscribe_to_events(drv_ctx.video_driver_fd); + if (ret) { + DEBUG_PRINT_ERROR("Subscribe Event Failed"); + return OMX_ErrorInsufficientResources; + } + + struct v4l2_capability cap; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_QUERYCAP, &cap); + if (ret) { + DEBUG_PRINT_ERROR("Failed to query capabilities"); + /*TODO: How to handle this case */ + } else { + DEBUG_PRINT_HIGH("Capabilities: driver_name = %s, card = %s, bus_info = %s," + " version = %d, capabilities = %x", cap.driver, cap.card, + cap.bus_info, cap.version, cap.capabilities); + } + ret=0; + fdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fdesc.index=0; + while (ioctl(drv_ctx.video_driver_fd, VIDIOC_ENUM_FMT, &fdesc) == 0) { + DEBUG_PRINT_HIGH("fmt: description: %s, fmt: %x, flags = %x", fdesc.description, + fdesc.pixelformat, fdesc.flags); + fdesc.index++; + } + fdesc.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fdesc.index=0; + while (ioctl(drv_ctx.video_driver_fd, VIDIOC_ENUM_FMT, &fdesc) == 0) { + + DEBUG_PRINT_HIGH("fmt: description: %s, fmt: %x, flags = %x", fdesc.description, + fdesc.pixelformat, fdesc.flags); + fdesc.index++; + } + + output_capability = V4L2_PIX_FMT_HEVC; + if (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + output_capability = V4L2_PIX_FMT_HEVC_HYBRID; + } + DEBUG_PRINT_HIGH("output_capability %d, V4L2_PIX_FMT_HEVC_HYBRID %d", output_capability, V4L2_PIX_FMT_HEVC_HYBRID); + + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = output_capability; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to set format on output port"); + return OMX_ErrorInsufficientResources; + } + DEBUG_PRINT_HIGH("Set Format was successful"); + //Get the hardware capabilities + memset((void *)&frmsize,0,sizeof(frmsize)); + frmsize.index = 0; + frmsize.pixel_format = output_capability; + ret = ioctl(drv_ctx.video_driver_fd, + VIDIOC_ENUM_FRAMESIZES, &frmsize); + if (ret || frmsize.type != V4L2_FRMSIZE_TYPE_STEPWISE) { + DEBUG_PRINT_ERROR("Failed to get framesizes"); + return OMX_ErrorHardware; + } + + if (frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) { + m_decoder_capability.min_width = frmsize.stepwise.min_width; + m_decoder_capability.max_width = frmsize.stepwise.max_width; + m_decoder_capability.min_height = frmsize.stepwise.min_height; + m_decoder_capability.max_height = frmsize.stepwise.max_height; + } + + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = capture_capability; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to set format on capture port"); + } + DEBUG_PRINT_HIGH("Set Format was successful"); + if(secure_mode){ + control.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE; + control.value = 1; + DEBUG_PRINT_LOW("Omx_vdec:: calling to open secure device %d", ret); + ret=ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL,&control); + if (ret) { + DEBUG_PRINT_ERROR("Omx_vdec:: Unable to open secure device %d", ret); + close(drv_ctx.video_driver_fd); + return OMX_ErrorInsufficientResources; + } + } + + /*Get the Buffer requirements for input(input buffer) and output ports(intermediate buffer) from Q6*/ + control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER; + control.value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + drv_ctx.idr_only_decoding = 0; + eRet=get_buffer_req(&drv_ctx.ip_buf); + DEBUG_PRINT_HIGH("Input Buffer Size =%d",drv_ctx.ip_buf.buffer_size); + } + else if (m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) + { + SWVDEC_PROP prop_dimen, prop_attr; + + capture_capability = V4L2_PIX_FMT_NV12; + output_capability = V4L2_PIX_FMT_HEVC; + + prop_dimen.ePropId = SWVDEC_PROP_ID_DIMENSIONS; + prop_dimen.uProperty.sDimensions.nWidth = drv_ctx.video_resolution.frame_width; + prop_dimen.uProperty.sDimensions.nHeight = drv_ctx.video_resolution.frame_height; + ret = SwVdec_SetProperty(m_pSwVdec,&prop_dimen); + if (ret) { + DEBUG_PRINT_ERROR("Failed to set dimensions to SwVdec in full SW"); + return OMX_ErrorInsufficientResources; + } + DEBUG_PRINT_LOW("Set dimensions to SwVdec in full SW successful"); + prop_attr.ePropId = SWVDEC_PROP_ID_FRAME_ATTR; + prop_attr.uProperty.sFrameAttr.eColorFormat = SWVDEC_FORMAT_NV12; + ret = SwVdec_SetProperty(m_pSwVdec,&prop_attr); + if (ret) { + DEBUG_PRINT_ERROR("Failed to set color fmt to SwVdec in full SW"); + return OMX_ErrorInsufficientResources; + } + DEBUG_PRINT_HIGH("Set dimensions and color format successful"); + + //TODO: Get the supported min/max dimensions of full SW solution + + drv_ctx.idr_only_decoding = 0; + } + + m_state = OMX_StateLoaded; +#ifdef DEFAULT_EXTRADATA + if (eRet == OMX_ErrorNone && !secure_mode) + enable_extradata(DEFAULT_EXTRADATA, true, true); +#endif + + get_buffer_req_swvdec(); + DEBUG_PRINT_HIGH("Input Buffer Size %d Interm Buffer Size %d Output Buffer Size =%d", + drv_ctx.ip_buf.buffer_size, drv_ctx.interm_op_buf.buffer_size, + drv_ctx.op_buf.buffer_size); + + h264_scratch.nAllocLen = drv_ctx.ip_buf.buffer_size; + h264_scratch.pBuffer = (OMX_U8 *)malloc (drv_ctx.ip_buf.buffer_size); + h264_scratch.nFilledLen = 0; + h264_scratch.nOffset = 0; + + if (h264_scratch.pBuffer == NULL) + { + DEBUG_PRINT_ERROR("h264_scratch.pBuffer Allocation failed "); + return OMX_ErrorInsufficientResources; + } + + if(pipe(fds)) + { + DEBUG_PRINT_ERROR("pipe creation failed"); + eRet = OMX_ErrorInsufficientResources; + } + else + { + if(fds[0] == 0 || fds[1] == 0) + { + if (pipe (fds)) + { + DEBUG_PRINT_ERROR("pipe creation failed"); + return OMX_ErrorInsufficientResources; + } + } + m_pipe_in = fds[0]; + m_pipe_out = fds[1]; + r = pthread_create(&msg_thread_id,0,message_thread,this); + + if(r < 0) + { + DEBUG_PRINT_ERROR("component_init(): message_thread creation failed"); + return OMX_ErrorInsufficientResources; + } + msg_thread_created = true; + } + + if (eRet != OMX_ErrorNone && ( (!m_pSwVdec) || (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) )) + { + DEBUG_PRINT_ERROR("Component Init Failed eRet %d m_pSwVdec %p m_swvdec_mode %d", eRet, m_pSwVdec, m_swvdec_mode); + } + else + { + DEBUG_PRINT_HIGH("omx_vdec::component_init() success"); + } + //memset(&h264_mv_buff,0,sizeof(struct h264_mv_buffer)); + return eRet; +} + +/* ====================================================================== +FUNCTION +omx_vdec::GetComponentVersion + +DESCRIPTION +Returns the component version. + +PARAMETERS +TBD. + +RETURN VALUE +OMX_ErrorNone. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_component_version( + OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STRING componentName, + OMX_OUT OMX_VERSIONTYPE* componentVersion, + OMX_OUT OMX_VERSIONTYPE* specVersion, + OMX_OUT OMX_UUIDTYPE* componentUUID + ) +{ + (void) hComp; + (void) componentName; + (void) componentVersion; + (void) componentUUID; + if(m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Comp Version in Invalid State"); + return OMX_ErrorInvalidState; + } + /* TBD -- Return the proper version */ + if (specVersion) + { + specVersion->nVersion = OMX_SPEC_VERSION; + } + return OMX_ErrorNone; +} +/* ====================================================================== +FUNCTION +omx_vdec::SendCommand + +DESCRIPTION +Returns zero if all the buffers released.. + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::send_command(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData + ) +{ + (void) hComp; + (void) cmdData; + DEBUG_PRINT_LOW("send_command: Recieved a Command from Client"); + if(m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("ERROR: Send Command in Invalid State"); + return OMX_ErrorInvalidState; + } + if (cmd == OMX_CommandFlush && param1 != OMX_CORE_INPUT_PORT_INDEX + && param1 != OMX_CORE_OUTPUT_PORT_INDEX && param1 != OMX_ALL) + { + DEBUG_PRINT_ERROR("send_command(): ERROR OMX_CommandFlush " + "to invalid port: %lu", param1); + return OMX_ErrorBadPortIndex; + } + post_event((unsigned long)cmd,(unsigned long)param1,(unsigned long)OMX_COMPONENT_GENERATE_COMMAND); + sem_wait(&m_cmd_lock); + DEBUG_PRINT_LOW("send_command: Command Processed"); + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION +omx_vdec::SendCommand + +DESCRIPTION +Returns zero if all the buffers released.. + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData + ) +{ + (void) hComp; + (void) cmdData; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_STATETYPE eState = (OMX_STATETYPE) param1; + int bFlag = 1,sem_posted = 0,ret=0; + + DEBUG_PRINT_LOW("send_command_proxy(): cmd = %d", cmd); + DEBUG_PRINT_HIGH("send_command_proxy(): Current State %d, Expected State %d", + m_state, eState); + + if(cmd == OMX_CommandStateSet) + { + DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandStateSet issued"); + DEBUG_PRINT_HIGH("Current State %d, Expected State %d", m_state, eState); + /***************************/ + /* Current State is Loaded */ + /***************************/ + if(m_state == OMX_StateLoaded) + { + if(eState == OMX_StateIdle) + { + //if all buffers are allocated or all ports disabled + if(allocate_done() || + (m_inp_bEnabled == OMX_FALSE && m_out_bEnabled == OMX_FALSE)) + { + if (m_pSwVdec && SWVDEC_S_SUCCESS != SwVdec_Start(m_pSwVdec)) + { + DEBUG_PRINT_ERROR("SWVDEC failed to start in allocate_done"); + return OMX_ErrorInvalidState; + } + DEBUG_PRINT_LOW("SwVdec start successful: send_command_proxy(): Loaded-->Idle"); + } + else + { + DEBUG_PRINT_LOW("send_command_proxy(): Loaded-->Idle-Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING); + // Skip the event notification + bFlag = 0; + } + } + /* Requesting transition from Loaded to Loaded */ + else if(eState == OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Loaded"); + post_event((unsigned long)OMX_EventError,(unsigned long)OMX_ErrorSameState,\ + (unsigned long)OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Loaded to WaitForResources */ + else if(eState == OMX_StateWaitForResources) + { + /* Since error is None , we will post an event + at the end of this function definition */ + DEBUG_PRINT_LOW("send_command_proxy(): Loaded-->WaitForResources"); + } + /* Requesting transition from Loaded to Executing */ + else if(eState == OMX_StateExecuting) + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Executing"); + post_event((unsigned long)OMX_EventError,(unsigned long)OMX_ErrorIncorrectStateTransition,\ + (unsigned long)OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Loaded to Pause */ + else if(eState == OMX_StatePause) + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Pause"); + post_event((unsigned long)OMX_EventError,(unsigned long)OMX_ErrorIncorrectStateTransition,\ + (unsigned long)OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Loaded to Invalid */ + else if(eState == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Invalid"); + post_event((unsigned long)OMX_EventError,(unsigned long)eState,(unsigned long)OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } + else + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Invalid(%d Not Handled)",\ + eState); + eRet = OMX_ErrorBadParameter; + } + } + + /***************************/ + /* Current State is IDLE */ + /***************************/ + else if(m_state == OMX_StateIdle) + { + if(eState == OMX_StateLoaded) + { + if(release_done()) + { + /* + Since error is None , we will post an event at the end + of this function definition + */ + if (m_pSwVdec) + { + SwVdec_Stop(m_pSwVdec); + } + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Loaded"); + } + else + { + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Loaded-Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING); + // Skip the event notification + bFlag = 0; + } + } + /* Requesting transition from Idle to Executing */ + else if(eState == OMX_StateExecuting) + { + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing"); + //BITMASK_SET(&m_flags, OMX_COMPONENT_EXECUTE_PENDING); + bFlag = 1; + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing"); + m_state=OMX_StateExecuting; + if (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + fill_all_buffers_proxy_dsp(hComp); + } + DEBUG_PRINT_HIGH("Stream On CAPTURE Was successful"); + } + /* Requesting transition from Idle to Idle */ + else if(eState == OMX_StateIdle) + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->Idle"); + post_event((unsigned long)OMX_EventError,(unsigned long)OMX_ErrorSameState,\ + (unsigned long)OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Idle to WaitForResources */ + else if(eState == OMX_StateWaitForResources) + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->WaitForResources"); + post_event((unsigned long)OMX_EventError,(unsigned long)OMX_ErrorIncorrectStateTransition,\ + (unsigned long)OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Idle to Pause */ + else if(eState == OMX_StatePause) + { + /*To pause the Video core we need to start the driver*/ + if (/*ioctl (drv_ctx.video_driver_fd,VDEC_IOCTL_CMD_START, + NULL) < */0) + { + DEBUG_PRINT_ERROR("VDEC_IOCTL_CMD_START FAILED"); + omx_report_error (); + eRet = OMX_ErrorHardware; + } + else + { + BITMASK_SET(&m_flags,OMX_COMPONENT_PAUSE_PENDING); + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Pause"); + bFlag = 0; + } + } + /* Requesting transition from Idle to Invalid */ + else if(eState == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->Invalid"); + post_event((unsigned long)OMX_EventError,(unsigned long)eState,(unsigned long)OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } + else + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle --> %d Not Handled",eState); + eRet = OMX_ErrorBadParameter; + } + } + + /******************************/ + /* Current State is Executing */ + /******************************/ + else if(m_state == OMX_StateExecuting) + { + DEBUG_PRINT_LOW("Command Recieved in OMX_StateExecuting"); + /* Requesting transition from Executing to Idle */ + if(eState == OMX_StateIdle) + { + /* Since error is None , we will post an event + at the end of this function definition + */ + DEBUG_PRINT_LOW("send_command_proxy(): Executing --> Idle"); + BITMASK_SET(&m_flags,OMX_COMPONENT_IDLE_PENDING); + if(!sem_posted) + { + sem_posted = 1; + sem_post (&m_cmd_lock); + execute_omx_flush(OMX_ALL); + } + bFlag = 0; + } + /* Requesting transition from Executing to Paused */ + else if(eState == OMX_StatePause) + { + DEBUG_PRINT_LOW("PAUSE Command Issued"); + m_state = OMX_StatePause; + bFlag = 1; + } + /* Requesting transition from Executing to Loaded */ + else if(eState == OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> Loaded"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Executing to WaitForResources */ + else if(eState == OMX_StateWaitForResources) + { + DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> WaitForResources"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Executing to Executing */ + else if(eState == OMX_StateExecuting) + { + DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> Executing"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Executing to Invalid */ + else if(eState == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } + else + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Executing --> %d Not Handled",eState); + eRet = OMX_ErrorBadParameter; + } + } + /***************************/ + /* Current State is Pause */ + /***************************/ + else if(m_state == OMX_StatePause) + { + /* Requesting transition from Pause to Executing */ + if(eState == OMX_StateExecuting) + { + DEBUG_PRINT_LOW("Pause --> Executing"); + m_state = OMX_StateExecuting; + if (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + fill_all_buffers_proxy_dsp(hComp); + } + bFlag = 1; + } + /* Requesting transition from Pause to Idle */ + else if(eState == OMX_StateIdle) + { + /* Since error is None , we will post an event + at the end of this function definition */ + DEBUG_PRINT_LOW("Pause --> Idle"); + BITMASK_SET(&m_flags,OMX_COMPONENT_IDLE_PENDING); + if(!sem_posted) + { + sem_posted = 1; + sem_post (&m_cmd_lock); + execute_omx_flush(OMX_ALL); + } + bFlag = 0; + } + /* Requesting transition from Pause to loaded */ + else if(eState == OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("Pause --> loaded"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Pause to WaitForResources */ + else if(eState == OMX_StateWaitForResources) + { + DEBUG_PRINT_ERROR("Pause --> WaitForResources"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Pause to Pause */ + else if(eState == OMX_StatePause) + { + DEBUG_PRINT_ERROR("Pause --> Pause"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Pause to Invalid */ + else if(eState == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Pause --> Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } + else + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Paused --> %d Not Handled",eState); + eRet = OMX_ErrorBadParameter; + } + } + /***************************/ + /* Current State is WaitForResources */ + /***************************/ + else if(m_state == OMX_StateWaitForResources) + { + /* Requesting transition from WaitForResources to Loaded */ + if(eState == OMX_StateLoaded) + { + /* Since error is None , we will post an event + at the end of this function definition */ + DEBUG_PRINT_LOW("send_command_proxy(): WaitForResources-->Loaded"); + } + /* Requesting transition from WaitForResources to WaitForResources */ + else if (eState == OMX_StateWaitForResources) + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->WaitForResources"); + post_event(OMX_EventError,OMX_ErrorSameState, + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from WaitForResources to Executing */ + else if(eState == OMX_StateExecuting) + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->Executing"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from WaitForResources to Pause */ + else if(eState == OMX_StatePause) + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->Pause"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from WaitForResources to Invalid */ + else if(eState == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } + /* Requesting transition from WaitForResources to Loaded - + is NOT tested by Khronos TS */ + + } + else + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): %d --> %d(Not Handled)",m_state,eState); + eRet = OMX_ErrorBadParameter; + } + } + /********************************/ + /* Current State is Invalid */ + /*******************************/ + else if(m_state == OMX_StateInvalid) + { + /* State Transition from Inavlid to any state */ + if(eState == (OMX_StateLoaded || OMX_StateWaitForResources + || OMX_StateIdle || OMX_StateExecuting + || OMX_StatePause || OMX_StateInvalid)) + { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Invalid -->Loaded"); + post_event(OMX_EventError,OMX_ErrorInvalidState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } + } + else if (cmd == OMX_CommandFlush) + { + DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandFlush issued" + "with param1: %lu", param1); + if(OMX_CORE_INPUT_PORT_INDEX == param1 || OMX_ALL == param1) + { + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_FLUSH_PENDING); + } + if(OMX_CORE_OUTPUT_PORT_INDEX == param1 || OMX_ALL == param1) + { + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_FLUSH_PENDING); + } + if (!sem_posted){ + sem_posted = 1; + DEBUG_PRINT_LOW("Set the Semaphore"); + sem_post (&m_cmd_lock); + execute_omx_flush(param1); + } + bFlag = 0; + } + else if ( cmd == OMX_CommandPortEnable) + { + DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandPortEnable issued" + "with param1: %lu", param1); + if(param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) + { + m_inp_bEnabled = OMX_TRUE; + + if( (m_state == OMX_StateLoaded && + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || allocate_input_done()) + { + post_event(OMX_CommandPortEnable,OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + else + { + DEBUG_PRINT_LOW("send_command_proxy(): Disabled-->Enabled Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING); + // Skip the event notification + bFlag = 0; + } + } + if(param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) + { + DEBUG_PRINT_LOW("Enable output Port command recieved"); + m_out_bEnabled = OMX_TRUE; + if( (m_state == OMX_StateLoaded && + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (allocate_output_done())) + { + post_event(OMX_CommandPortEnable,OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + else + { + DEBUG_PRINT_LOW("send_command_proxy(): Disabled-->Enabled Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + // Skip the event notification + bFlag = 0; + } + } + } + else if (cmd == OMX_CommandPortDisable) + { + DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandPortDisable issued" + "with param1: %lu", param1); + if(param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) + { + m_inp_bEnabled = OMX_FALSE; + if((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_input_done()) + { + post_event(OMX_CommandPortDisable,OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + else + { + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING); + if(m_state == OMX_StatePause ||m_state == OMX_StateExecuting) + { + if(!sem_posted) + { + sem_posted = 1; + sem_post (&m_cmd_lock); + } + execute_omx_flush(OMX_CORE_INPUT_PORT_INDEX); + } + + // Skip the event notification + bFlag = 0; + } + } + if(param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) + { + m_out_bEnabled = OMX_FALSE; + DEBUG_PRINT_LOW("Disable output Port command recieved"); + if((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_output_done()) + { + post_event(OMX_CommandPortDisable,OMX_CORE_OUTPUT_PORT_INDEX,\ + OMX_COMPONENT_GENERATE_EVENT); + } + else + { + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + if(m_state == OMX_StatePause ||m_state == OMX_StateExecuting) + { + if (!sem_posted) + { + sem_posted = 1; + sem_post (&m_cmd_lock); + } + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING); + execute_omx_flush(OMX_CORE_OUTPUT_PORT_INDEX); + } + // Skip the event notification + bFlag = 0; + + } + } + } + else + { + DEBUG_PRINT_ERROR("Error: Invalid Command other than StateSet (%d)",cmd); + eRet = OMX_ErrorNotImplemented; + } + if(eRet == OMX_ErrorNone && bFlag) + { + post_event(cmd,eState,OMX_COMPONENT_GENERATE_EVENT); + } + if(!sem_posted) + { + sem_post(&m_cmd_lock); + } + + return eRet; +} + +/* ====================================================================== +FUNCTION +omx_vdec::ExecuteOmxFlush + +DESCRIPTION +Executes the OMX flush. + +PARAMETERS +flushtype - input flush(1)/output flush(0)/ both. + +RETURN VALUE +true/false + +========================================================================== */ +bool omx_vdec::execute_omx_flush(OMX_U32 flushType) +{ + bool bRet = false; + struct v4l2_plane plane; + struct v4l2_buffer v4l2_buf; + struct v4l2_decoder_cmd dec; + DEBUG_PRINT_LOW("in %s flushType %d", __func__, (int)flushType); + memset((void *)&v4l2_buf,0,sizeof(v4l2_buf)); + dec.cmd = V4L2_DEC_QCOM_CMD_FLUSH; + switch (flushType) + { + case OMX_CORE_INPUT_PORT_INDEX: + input_flush_progress = true; + dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT; + break; + case OMX_CORE_OUTPUT_PORT_INDEX: + output_flush_progress = true; + dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE; + if (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + m_interm_flush_swvdec_progress = true; + m_interm_flush_dsp_progress = true; + } + break; + default: + input_flush_progress = true; + output_flush_progress = true; + if (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + m_interm_flush_swvdec_progress = true; + m_interm_flush_dsp_progress = true; + } + dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT | + V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE; + } + + if (!m_pSwVdec || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + DEBUG_PRINT_LOW("flush dsp %d %d %d", dec.flags, V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT, V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE); + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_DECODER_CMD, &dec)) + { + DEBUG_PRINT_ERROR("Flush dsp Failed "); + bRet = false; + } + } + if (flushType == OMX_CORE_INPUT_PORT_INDEX) + { + // no input flush independently, wait for output flush + return bRet; + } + if (m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) + { + // for hybrid mode, swvdec flush will hapeen when dsp flush done is received + SWVDEC_BUFFER_FLUSH_TYPE aFlushType = SWVDEC_FLUSH_OUTPUT; + if (m_interm_flush_swvdec_progress || input_flush_progress) + { + aFlushType = SWVDEC_FLUSH_ALL; + } + DEBUG_PRINT_HIGH("Flush swvdec type %d", aFlushType); + if (SwVdec_Flush(m_pSwVdec, aFlushType) != SWVDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("Flush swvdec Failed "); + } + DEBUG_PRINT_LOW("Flush swvdec type %d successful", aFlushType); + } + return bRet; +} +/*========================================================================= +FUNCTION : execute_output_flush + +DESCRIPTION +Executes the OMX flush at OUTPUT PORT. + +PARAMETERS +None. + +RETURN VALUE +true/false +==========================================================================*/ +bool omx_vdec::execute_output_flush() +{ + unsigned long p1 = 0; // Parameter - 1 + unsigned long p2 = 0; // Parameter - 2 + unsigned long ident = 0; + bool bRet = true; + + /*Generate FBD for all Buffers in the FTBq*/ + pthread_mutex_lock(&m_lock); + DEBUG_PRINT_LOW("Initiate Output Flush"); + while (m_ftb_q.m_size) + { + DEBUG_PRINT_LOW("Buffer queue size %d pending buf cnt %d", + m_ftb_q.m_size,pending_output_buffers); + m_ftb_q.pop_entry(&p1,&p2,&ident); + DEBUG_PRINT_LOW("ID(%lx) P1(%lx) P2(%lx)", ident, p1, p2); + if(ident == m_fill_output_msg ) + { + m_cb.FillBufferDone(&m_cmp, m_app_data, (OMX_BUFFERHEADERTYPE *)p2); + } + else if (ident == OMX_COMPONENT_GENERATE_FBD) + { + fill_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1); + } + } + pthread_mutex_unlock(&m_lock); + output_flush_progress = false; + + if (arbitrary_bytes) + { + prev_ts = LLONG_MAX; + rst_prev_ts = true; + } + DEBUG_PRINT_HIGH("OMX flush o/p Port complete PenBuf(%d)", pending_output_buffers); + return bRet; +} +/*========================================================================= +FUNCTION : execute_input_flush + +DESCRIPTION +Executes the OMX flush at INPUT PORT. + +PARAMETERS +None. + +RETURN VALUE +true/false +==========================================================================*/ +bool omx_vdec::execute_input_flush() +{ + unsigned int i =0; + unsigned long p1 = 0; // Parameter - 1 + unsigned long p2 = 0; // Parameter - 2 + unsigned long ident = 0; + bool bRet = true; + + /*Generate EBD for all Buffers in the ETBq*/ + DEBUG_PRINT_LOW("Initiate Input Flush"); + + pthread_mutex_lock(&m_lock); + DEBUG_PRINT_LOW("Check if the Queue is empty"); + while (m_etb_q.m_size) + { + m_etb_q.pop_entry(&p1,&p2,&ident); + + if (ident == OMX_COMPONENT_GENERATE_ETB_ARBITRARY) + { + DEBUG_PRINT_LOW("Flush Input Heap Buffer %p",(OMX_BUFFERHEADERTYPE *)p2); + m_cb.EmptyBufferDone(&m_cmp ,m_app_data, (OMX_BUFFERHEADERTYPE *)p2); + } + else if(ident == OMX_COMPONENT_GENERATE_ETB) + { + pending_input_buffers++; + DEBUG_PRINT_LOW("Flush Input OMX_COMPONENT_GENERATE_ETB %p, pending_input_buffers %d", + (OMX_BUFFERHEADERTYPE *)p2, pending_input_buffers); + empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p2); + } + else if (ident == OMX_COMPONENT_GENERATE_EBD) + { + DEBUG_PRINT_LOW("Flush Input OMX_COMPONENT_GENERATE_EBD %p", + (OMX_BUFFERHEADERTYPE *)p1); + empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1); + } + } + time_stamp_dts.flush_timestamp(); + /*Check if Heap Buffers are to be flushed*/ + if (arbitrary_bytes && !(codec_config_flag)) + { + DEBUG_PRINT_LOW("Reset all the variables before flusing"); + h264_scratch.nFilledLen = 0; + nal_count = 0; + look_ahead_nal = false; + frame_count = 0; + h264_last_au_ts = LLONG_MAX; + h264_last_au_flags = 0; + memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) ); + m_demux_entries = 0; + DEBUG_PRINT_LOW("Initialize parser"); + if (m_frame_parser.mutils) + { + m_frame_parser.mutils->initialize_frame_checking_environment(); + } + + while (m_input_pending_q.m_size) + { + m_input_pending_q.pop_entry(&p1,&p2,&ident); + m_cb.EmptyBufferDone(&m_cmp ,m_app_data, (OMX_BUFFERHEADERTYPE *)p1); + } + + if (psource_frame) + { + m_cb.EmptyBufferDone(&m_cmp ,m_app_data,psource_frame); + psource_frame = NULL; + } + + if (pdest_frame) + { + pdest_frame->nFilledLen = 0; + m_input_free_q.insert_entry((unsigned long) pdest_frame, (unsigned long)NULL, + (unsigned long)NULL); + pdest_frame = NULL; + } + m_frame_parser.flush(); + } + else if (codec_config_flag) + { + DEBUG_PRINT_HIGH("frame_parser flushing skipped due to codec config buffer " + "is not sent to the driver yet"); + } + pthread_mutex_unlock(&m_lock); + input_flush_progress = false; + if (!arbitrary_bytes) + { + prev_ts = LLONG_MAX; + rst_prev_ts = true; + } +#ifdef _ANDROID_ + if (m_debug_timestamp) + { + m_timestamp_list.reset_ts_list(); + } +#endif + DEBUG_PRINT_HIGH("OMX flush i/p Port complete PenBuf(%d)", pending_input_buffers); + return bRet; +} + + +/* ====================================================================== +FUNCTION +omx_vdec::SendCommandEvent + +DESCRIPTION +Send the event to decoder pipe. This is needed to generate the callbacks +in decoder thread context. + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +bool omx_vdec::post_event(unsigned long p1, + unsigned long p2, + unsigned long id) +{ + bool bRet = false; + OMX_BUFFERHEADERTYPE* bufHdr = NULL; + + pthread_mutex_lock(&m_lock); + + if (id == OMX_COMPONENT_GENERATE_FTB || + id == OMX_COMPONENT_GENERATE_FBD) + { + m_ftb_q.insert_entry(p1,p2,id); + } + else if (id == OMX_COMPONENT_GENERATE_ETB || + id == OMX_COMPONENT_GENERATE_EBD || + id == OMX_COMPONENT_GENERATE_ETB_ARBITRARY) + { + m_etb_q.insert_entry(p1,p2,id); + } + else if (id == OMX_COMPONENT_GENERATE_FTB_DSP) + { + bufHdr = (OMX_BUFFERHEADERTYPE*)p2; + m_ftb_q_dsp.insert_entry(p1,p2,id); + } + else if (id == OMX_COMPONENT_GENERATE_ETB_SWVDEC) + { + bufHdr = (OMX_BUFFERHEADERTYPE*)p2; + m_etb_q_swvdec.insert_entry(p1,p2,id); + } + else if (id == OMX_COMPONENT_GENERATE_FBD_DSP) + { + bufHdr = (OMX_BUFFERHEADERTYPE*)p1; + m_ftb_q_dsp.insert_entry(p1,p2,id); + } + else if (id == OMX_COMPONENT_GENERATE_EBD_SWVDEC) + { + bufHdr = (OMX_BUFFERHEADERTYPE*)p1; + m_etb_q_swvdec.insert_entry(p1,p2,id); + } + else + { + m_cmd_q.insert_entry(p1,p2,id); + } + + bRet = true; + post_message(this, id); + pthread_mutex_unlock(&m_lock); + + return bRet; +} + +OMX_ERRORTYPE omx_vdec::get_supported_profile_level_for_1080p(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNoMore; + if(!profileLevelType) + return OMX_ErrorBadParameter; + + if(profileLevelType->nPortIndex == 0) { + if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevchybrid",OMX_MAX_STRINGNAME_SIZE) || + !strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevcswvdec",OMX_MAX_STRINGNAME_SIZE) || + !strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc",OMX_MAX_STRINGNAME_SIZE) ) + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %d", + (int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + else + { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %lu", profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } + else + { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported should be queries on Input port only %lu", profileLevelType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + return eRet; +} + +/* ====================================================================== +FUNCTION +omx_vdec::GetParameter + +DESCRIPTION +OMX Get Parameter method implementation + +PARAMETERS +<TBD>. + +RETURN VALUE +Error None if successful. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_INOUT OMX_PTR paramData) +{ + (void) hComp; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + DEBUG_PRINT_LOW("get_parameter:"); + if(m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Param in Invalid State"); + return OMX_ErrorInvalidState; + } + if(paramData == NULL) + { + DEBUG_PRINT_LOW("Get Param in Invalid paramData"); + return OMX_ErrorBadParameter; + } + switch((unsigned long)paramIndex) + { + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn = + (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamPortDefinition"); + eRet = update_portdef(portDefn); + if (eRet == OMX_ErrorNone) + m_port_def = *portDefn; + break; + } + case OMX_IndexParamVideoInit: + { + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoInit"); + + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(portParamType); + portParamType->nPorts = 2; + portParamType->nStartPortNumber = 0; + break; + } + case OMX_IndexParamVideoPortFormat: + { + OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoPortFormat"); + + portFmt->nVersion.nVersion = OMX_SPEC_VERSION; + portFmt->nSize = sizeof(portFmt); + + if (0 == portFmt->nPortIndex) + { + if (0 == portFmt->nIndex) + { + portFmt->eColorFormat = OMX_COLOR_FormatUnused; + portFmt->eCompressionFormat = eCompressionFormat; + } + else + { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoPortFormat:"\ + " NoMore compression formats"); + eRet = OMX_ErrorNoMore; + } + } + else if (1 == portFmt->nPortIndex) + { + portFmt->eCompressionFormat = OMX_VIDEO_CodingUnused; + + if(0 == portFmt->nIndex) + portFmt->eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + else if (1 == portFmt->nIndex) + portFmt->eColorFormat = OMX_COLOR_FormatYUV420Planar; + else + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoPortFormat:"\ + " NoMore Color formats"); + eRet = OMX_ErrorNoMore; + } + } + else + { + DEBUG_PRINT_ERROR("get_parameter: Bad port index %d", + (int)portFmt->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + /*Component should support this port definition*/ + case OMX_IndexParamAudioInit: + { + OMX_PORT_PARAM_TYPE *audioPortParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamAudioInit"); + audioPortParamType->nVersion.nVersion = OMX_SPEC_VERSION; + audioPortParamType->nSize = sizeof(audioPortParamType); + audioPortParamType->nPorts = 0; + audioPortParamType->nStartPortNumber = 0; + break; + } + /*Component should support this port definition*/ + case OMX_IndexParamImageInit: + { + OMX_PORT_PARAM_TYPE *imagePortParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamImageInit"); + imagePortParamType->nVersion.nVersion = OMX_SPEC_VERSION; + imagePortParamType->nSize = sizeof(imagePortParamType); + imagePortParamType->nPorts = 0; + imagePortParamType->nStartPortNumber = 0; + break; + + } + /*Component should support this port definition*/ + case OMX_IndexParamOtherInit: + { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamOtherInit %08x", + paramIndex); + eRet =OMX_ErrorUnsupportedIndex; + break; + } + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *comp_role; + comp_role = (OMX_PARAM_COMPONENTROLETYPE *) paramData; + comp_role->nVersion.nVersion = OMX_SPEC_VERSION; + comp_role->nSize = sizeof(*comp_role); + + DEBUG_PRINT_LOW("Getparameter: OMX_IndexParamStandardComponentRole %d", + paramIndex); + strlcpy((char*)comp_role->cRole,(const char*)m_cRole, + OMX_MAX_STRINGNAME_SIZE); + break; + } + /* Added for parameter test */ + case OMX_IndexParamPriorityMgmt: + { + + OMX_PRIORITYMGMTTYPE *priorityMgmType = + (OMX_PRIORITYMGMTTYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamPriorityMgmt"); + priorityMgmType->nVersion.nVersion = OMX_SPEC_VERSION; + priorityMgmType->nSize = sizeof(priorityMgmType); + + break; + } + /* Added for parameter test */ + case OMX_IndexParamCompBufferSupplier: + { + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType = + (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamCompBufferSupplier"); + + bufferSupplierType->nSize = sizeof(bufferSupplierType); + bufferSupplierType->nVersion.nVersion = OMX_SPEC_VERSION; + if(0 == bufferSupplierType->nPortIndex) + bufferSupplierType->nPortIndex = OMX_BufferSupplyUnspecified; + else if (1 == bufferSupplierType->nPortIndex) + bufferSupplierType->nPortIndex = OMX_BufferSupplyUnspecified; + else + eRet = OMX_ErrorBadPortIndex; + + + break; + } + case OMX_IndexParamVideoAvc: + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoAvc %08x", + paramIndex); + break; + } + case OMX_IndexParamVideoH263: + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoH263 %08x", + paramIndex); + break; + } + case OMX_IndexParamVideoMpeg4: + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoMpeg4 %08x", + paramIndex); + break; + } + case OMX_IndexParamVideoMpeg2: + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoMpeg2 %08x", + paramIndex); + break; + } + case OMX_IndexParamVideoProfileLevelQuerySupported: + { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported %08x", paramIndex); + OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType = + (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)paramData; + eRet = get_supported_profile_level_for_1080p(profileLevelType); + break; + } +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) + case OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage: + { + DEBUG_PRINT_HIGH("get_parameter: OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage"); + GetAndroidNativeBufferUsageParams* nativeBuffersUsage = (GetAndroidNativeBufferUsageParams *) paramData; + if(nativeBuffersUsage->nPortIndex == OMX_CORE_OUTPUT_PORT_INDEX) { + + if(secure_mode) { + nativeBuffersUsage->nUsage = (GRALLOC_USAGE_PRIVATE_MM_HEAP | GRALLOC_USAGE_PROTECTED | + GRALLOC_USAGE_PRIVATE_UNCACHED); + } else { + if (!m_pSwVdec) { +#ifdef _HEVC_USE_ADSP_HEAP_ + nativeBuffersUsage->nUsage = (GRALLOC_USAGE_PRIVATE_ADSP_HEAP | GRALLOC_USAGE_PRIVATE_UNCACHED); +#else + nativeBuffersUsage->nUsage = GRALLOC_USAGE_PRIVATE_UNCACHED; +#endif + } + else { + // for swvdec use cached buffer + DEBUG_PRINT_HIGH("get_parameter: OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage using output buffer cached"); + // nativeBuffersUsage->nUsage = GRALLOC_USAGE_PRIVATE_UNCACHED; + nativeBuffersUsage->nUsage = (GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN); + } + DEBUG_PRINT_HIGH("nativeBuffersUsage->nUsage %x", (unsigned int)nativeBuffersUsage->nUsage); + } + } else { + DEBUG_PRINT_HIGH("get_parameter: OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage failed!"); + eRet = OMX_ErrorBadParameter; + } + } + break; +#endif + + default: + { + DEBUG_PRINT_ERROR("get_parameter: unknown param %08x", paramIndex); + eRet =OMX_ErrorUnsupportedIndex; + } + + } + + DEBUG_PRINT_LOW("get_parameter returning WxH(%d x %d) SxSH(%d x %d)", + drv_ctx.video_resolution.frame_width, + drv_ctx.video_resolution.frame_height, + drv_ctx.video_resolution.stride, + drv_ctx.video_resolution.scan_lines); + + return eRet; +} + +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) +OMX_ERRORTYPE omx_vdec::use_android_native_buffer(OMX_IN OMX_HANDLETYPE hComp, OMX_PTR data) +{ + DEBUG_PRINT_LOW("Inside use_android_native_buffer"); + OMX_ERRORTYPE eRet = OMX_ErrorNone; + UseAndroidNativeBufferParams *params = (UseAndroidNativeBufferParams *)data; + + if((params == NULL) || + (params->nativeBuffer == NULL) || + (params->nativeBuffer->handle == NULL) || + !m_enable_android_native_buffers) + return OMX_ErrorBadParameter; + m_use_android_native_buffers = OMX_TRUE; + sp<android_native_buffer_t> nBuf = params->nativeBuffer; + private_handle_t *handle = (private_handle_t *)nBuf->handle; + if(OMX_CORE_OUTPUT_PORT_INDEX == params->nPortIndex) { //android native buffers can be used only on Output port + OMX_U8 *buffer = NULL; + if(!secure_mode) { + buffer = (OMX_U8*)mmap(0, handle->size, + PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0); + if(buffer == MAP_FAILED) { + DEBUG_PRINT_ERROR("Failed to mmap pmem with fd = %d, size = %d", handle->fd, handle->size); + return OMX_ErrorInsufficientResources; + } + } + eRet = use_buffer(hComp,params->bufferHeader,params->nPortIndex,data,handle->size,buffer); + } else { + eRet = OMX_ErrorBadParameter; + } + return eRet; +} +#endif + +OMX_ERRORTYPE omx_vdec::enable_smoothstreaming() { + if (!m_pSwVdec || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + struct v4l2_control control; + struct v4l2_format fmt; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER; + control.value = 1; + int rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL,&control); + if (rc < 0) { + DEBUG_PRINT_ERROR("Failed to enable Smooth Streaming on driver."); + return OMX_ErrorHardware; + } + } + else if (m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) + { + /* Full SW solution */ + SWVDEC_PROP prop; + prop.ePropId = SWVDEC_PROP_ID_SMOOTH_STREAMING; + prop.uProperty.sSmoothStreaming.bEnableSmoothStreaming = TRUE; + if (SwVdec_SetProperty(m_pSwVdec, &prop)) + { + DEBUG_PRINT_ERROR( + "OMX_QcomIndexParamVideoAdaptivePlaybackMode not supported"); + return OMX_ErrorUnsupportedSetting; + } + } + DEBUG_PRINT_LOW("Smooth Streaming enabled."); + m_smoothstreaming_mode = true; + return OMX_ErrorNone; +} + + +/* ====================================================================== +FUNCTION +omx_vdec::Setparameter + +DESCRIPTION +OMX Set Parameter method implementation. + +PARAMETERS +<TBD>. + +RETURN VALUE +OMX Error None if successful. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::set_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_IN OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + int ret=0; + struct v4l2_format fmt; + if(m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Set Param in Invalid State"); + return OMX_ErrorInvalidState; + } + if(paramData == NULL) + { + DEBUG_PRINT_ERROR("Get Param in Invalid paramData"); + return OMX_ErrorBadParameter; + } + if((m_state != OMX_StateLoaded) && + BITMASK_ABSENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING) && + (m_out_bEnabled == OMX_TRUE) && + BITMASK_ABSENT(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING) && + (m_inp_bEnabled == OMX_TRUE)) { + DEBUG_PRINT_ERROR("Set Param in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + switch((unsigned long)paramIndex) + { + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + //TODO: Check if any allocate buffer/use buffer/useNativeBuffer has + //been called. + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition H= %d, W = %d", + (int)portDefn->format.video.nFrameHeight, + (int)portDefn->format.video.nFrameWidth); + + // for pure dsp mode, if the dimension exceeds 720p, reject it + // so that the stagefright can try the hybrid component + if (!m_pSwVdec && + (portDefn->format.video.nFrameHeight > 720 || + portDefn->format.video.nFrameWidth > 1280)) + { + DEBUG_PRINT_ERROR("Full DSP mode only support up to 720p"); + return OMX_ErrorBadParameter; + } + + if(OMX_DirOutput == portDefn->eDir) + { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition OP port"); + m_display_id = portDefn->format.video.pNativeWindow; + unsigned int buffer_size; + if (m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) { + SWVDEC_PROP prop; + SWVDEC_STATUS sRet; + prop.ePropId = SWVDEC_PROP_ID_DIMENSIONS; + prop.uProperty.sDimensions.nWidth = + portDefn->format.video.nFrameWidth; + prop.uProperty.sDimensions.nHeight = + portDefn->format.video.nFrameHeight; + sRet = SwVdec_SetProperty(m_pSwVdec,&prop); + if(sRet!=SWVDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("set_parameter: SwVdec_SetProperty():Failed to set dimensions to SwVdec in full SW"); + return OMX_ErrorUnsupportedSetting; + } + } + if (!client_buffers.get_buffer_req(buffer_size)) { + DEBUG_PRINT_ERROR("Error in getting buffer requirements"); + eRet = OMX_ErrorBadParameter; + } else { + if ( portDefn->nBufferCountActual >= drv_ctx.op_buf.mincount && + portDefn->nBufferSize >= drv_ctx.op_buf.buffer_size ) + { + drv_ctx.op_buf.actualcount = portDefn->nBufferCountActual; + drv_ctx.op_buf.buffer_size = portDefn->nBufferSize; + eRet = set_buffer_req_swvdec(&drv_ctx.op_buf); + if (eRet == OMX_ErrorNone) + m_port_def = *portDefn; + } + else + { + DEBUG_PRINT_ERROR("ERROR: OP Requirements(#%d: %u) Requested(#%lu: %lu)", + drv_ctx.op_buf.mincount, drv_ctx.op_buf.buffer_size, + portDefn->nBufferCountActual, portDefn->nBufferSize); + eRet = OMX_ErrorBadParameter; + } + } + } + else if(OMX_DirInput == portDefn->eDir) + { + bool port_format_changed = false; + if((portDefn->format.video.xFramerate >> 16) > 0 && + (portDefn->format.video.xFramerate >> 16) <= MAX_SUPPORTED_FPS) + { + // Frame rate only should be set if this is a "known value" or to + // activate ts prediction logic (arbitrary mode only) sending input + // timestamps with max value (LLONG_MAX). + DEBUG_PRINT_HIGH("set_parameter: frame rate set by omx client : %lu", + portDefn->format.video.xFramerate >> 16); + Q16ToFraction(portDefn->format.video.xFramerate, drv_ctx.frame_rate.fps_numerator, + drv_ctx.frame_rate.fps_denominator); + if(!drv_ctx.frame_rate.fps_numerator) + { + DEBUG_PRINT_ERROR("Numerator is zero setting to 30"); + drv_ctx.frame_rate.fps_numerator = 30; + } + if(drv_ctx.frame_rate.fps_denominator) + drv_ctx.frame_rate.fps_numerator = (int) + drv_ctx.frame_rate.fps_numerator / drv_ctx.frame_rate.fps_denominator; + drv_ctx.frame_rate.fps_denominator = 1; + frm_int = drv_ctx.frame_rate.fps_denominator * 1e6 / + drv_ctx.frame_rate.fps_numerator; + DEBUG_PRINT_LOW("set_parameter: frm_int(%u) fps(%.2f)", + (unsigned int)frm_int, drv_ctx.frame_rate.fps_numerator / + (float)drv_ctx.frame_rate.fps_denominator); + } + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition IP port"); + if(drv_ctx.video_resolution.frame_height != + portDefn->format.video.nFrameHeight || + drv_ctx.video_resolution.frame_width != + portDefn->format.video.nFrameWidth) + { + DEBUG_PRINT_LOW("SetParam IP: WxH(%d x %d)", + (int)portDefn->format.video.nFrameWidth, + (int)portDefn->format.video.nFrameHeight); + port_format_changed = true; + OMX_U32 frameWidth = portDefn->format.video.nFrameWidth; + OMX_U32 frameHeight = portDefn->format.video.nFrameHeight; + if (frameHeight != 0x0 && frameWidth != 0x0) + { + if (m_smoothstreaming_mode && + ((frameWidth * frameHeight) < + (m_smoothstreaming_width * m_smoothstreaming_height))) { + frameWidth = m_smoothstreaming_width; + frameHeight = m_smoothstreaming_height; + DEBUG_PRINT_LOW("NOTE: Setting resolution %lu x %lu for adaptive-playback/smooth-streaming", + frameWidth, frameHeight); + } + update_resolution(frameWidth, frameHeight, + frameWidth, frameHeight); + if (m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) + { + /* update the stride info */ + drv_ctx.video_resolution.stride = + (frameWidth + DEFAULT_WIDTH_ALIGNMENT - 1) & (~(DEFAULT_WIDTH_ALIGNMENT - 1)); + drv_ctx.video_resolution.scan_lines = + (frameHeight + DEFAULT_HEIGHT_ALIGNMENT - 1) & (~(DEFAULT_HEIGHT_ALIGNMENT - 1)); + } + + eRet = is_video_session_supported(); + if (eRet) + break; + if (!m_pSwVdec || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = output_capability; + DEBUG_PRINT_LOW("fmt.fmt.pix_mp.height = %d , fmt.fmt.pix_mp.width = %d", + fmt.fmt.pix_mp.height,fmt.fmt.pix_mp.width); + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) + { + DEBUG_PRINT_ERROR("Set Resolution failed h %d w %d", fmt.fmt.pix_mp.height, fmt.fmt.pix_mp.width); + eRet = OMX_ErrorUnsupportedSetting; + break; + } + } + if (m_pSwVdec) + { + SWVDEC_PROP prop; + prop.ePropId = SWVDEC_PROP_ID_DIMENSIONS; + prop.uProperty.sDimensions.nWidth = drv_ctx.video_resolution.frame_width; + prop.uProperty.sDimensions.nHeight= drv_ctx.video_resolution.frame_height; + SwVdec_SetProperty(m_pSwVdec,&prop); + prop.ePropId = SWVDEC_PROP_ID_FRAME_ATTR; + prop.uProperty.sFrameAttr.eColorFormat = SWVDEC_FORMAT_NV12; + ret = SwVdec_SetProperty(m_pSwVdec,&prop); + if (ret) { + DEBUG_PRINT_ERROR("Failed to set color fmt to SwVdec in full SW"); + return OMX_ErrorInsufficientResources; + } + } + eRet = get_buffer_req_swvdec(); + } + } + else if (portDefn->nBufferCountActual >= drv_ctx.ip_buf.mincount + || portDefn->nBufferSize != drv_ctx.ip_buf.buffer_size) + { + port_format_changed = true; + vdec_allocatorproperty *buffer_prop = &drv_ctx.ip_buf; + drv_ctx.ip_buf.actualcount = portDefn->nBufferCountActual; + drv_ctx.ip_buf.buffer_size = (portDefn->nBufferSize + buffer_prop->alignment - 1) & + (~(buffer_prop->alignment - 1)); + DEBUG_PRINT_LOW("IP Requirements(#%d: %u) Requested(#%lu: %lu)", + drv_ctx.ip_buf.mincount, drv_ctx.ip_buf.buffer_size, + portDefn->nBufferCountActual, portDefn->nBufferSize); + if (!m_pSwVdec || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + eRet = set_buffer_req(buffer_prop); + } + if (!port_format_changed) + { + DEBUG_PRINT_ERROR("ERROR: IP Requirements(#%d: %u) Requested(#%lu: %lu)", + drv_ctx.ip_buf.mincount, drv_ctx.ip_buf.buffer_size, + portDefn->nBufferCountActual, portDefn->nBufferSize); + eRet = OMX_ErrorBadParameter; + } + } + else if (portDefn->eDir == OMX_DirMax) + { + DEBUG_PRINT_ERROR(" Set_parameter: Bad Port idx %d", + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + } + break; + case OMX_IndexParamVideoPortFormat: + { + OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; + int ret=0; + struct v4l2_format fmt; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoPortFormat %d", + portFmt->eColorFormat); + + if(1 == portFmt->nPortIndex) + { + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = capture_capability; + enum vdec_output_fromat op_format; + if((portFmt->eColorFormat == (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m) || + (portFmt->eColorFormat == OMX_COLOR_FormatYUV420Planar)) + op_format = (enum vdec_output_fromat)VDEC_YUV_FORMAT_NV12; + else if(portFmt->eColorFormat == + (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka) + op_format = VDEC_YUV_FORMAT_TILE_4x2; + else + eRet = OMX_ErrorBadParameter; + + if(eRet == OMX_ErrorNone) + { + drv_ctx.output_format = op_format; + if (!m_pSwVdec) + { + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + } + else if ((m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) || + (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY)) + { + SWVDEC_PROP prop; + prop.ePropId = SWVDEC_PROP_ID_DIMENSIONS; + prop.uProperty.sDimensions.nWidth = fmt.fmt.pix_mp.width; + prop.uProperty.sDimensions.nHeight= fmt.fmt.pix_mp.height; + SwVdec_SetProperty(m_pSwVdec,&prop); + prop.ePropId = SWVDEC_PROP_ID_FRAME_ATTR; + prop.uProperty.sFrameAttr.eColorFormat = SWVDEC_FORMAT_NV12; + SwVdec_SetProperty(m_pSwVdec,&prop); + } + // need to set output format to swvdec + if(ret) + { + DEBUG_PRINT_ERROR("Set output format failed"); + eRet = OMX_ErrorUnsupportedSetting; + /*TODO: How to handle this case */ + } + else + { + eRet = get_buffer_req_swvdec(); + } + } + if (eRet == OMX_ErrorNone){ + if (!client_buffers.set_color_format(portFmt->eColorFormat)) { + DEBUG_PRINT_ERROR("Set color format failed"); + eRet = OMX_ErrorBadParameter; + } + } + } + } + break; + + case OMX_QcomIndexPortDefn: + { + OMX_QCOM_PARAM_PORTDEFINITIONTYPE *portFmt = + (OMX_QCOM_PARAM_PORTDEFINITIONTYPE *) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexQcomParamPortDefinitionType %d", + (int)portFmt->nFramePackingFormat); + + /* Input port */ + if (portFmt->nPortIndex == 0) + { + if (portFmt->nFramePackingFormat == OMX_QCOM_FramePacking_Arbitrary) + { + if(secure_mode) { + arbitrary_bytes = false; + DEBUG_PRINT_ERROR("setparameter: cannot set to arbitary bytes mode in secure session"); + eRet = OMX_ErrorUnsupportedSetting; + } else { + arbitrary_bytes = true; + } + } + else if (portFmt->nFramePackingFormat == + OMX_QCOM_FramePacking_OnlyOneCompleteFrame) + { + arbitrary_bytes = false; + } + else + { + DEBUG_PRINT_ERROR("Setparameter: unknown FramePacking format %lu", + portFmt->nFramePackingFormat); + eRet = OMX_ErrorUnsupportedSetting; + } + } + else if (portFmt->nPortIndex == OMX_CORE_OUTPUT_PORT_INDEX) + { + DEBUG_PRINT_HIGH("set_parameter: OMX_IndexQcomParamPortDefinitionType OP Port"); + if( (portFmt->nMemRegion > OMX_QCOM_MemRegionInvalid && + portFmt->nMemRegion < OMX_QCOM_MemRegionMax) && + portFmt->nCacheAttr == OMX_QCOM_CacheAttrNone) + { + m_out_mem_region_smi = OMX_TRUE; + if ((m_out_mem_region_smi && m_out_pvt_entry_pmem)) + { + DEBUG_PRINT_HIGH("set_parameter: OMX_IndexQcomParamPortDefinitionType OP Port: out pmem set"); + m_use_output_pmem = OMX_TRUE; + } + } + } + } + break; + + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *comp_role; + comp_role = (OMX_PARAM_COMPONENTROLETYPE *) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamStandardComponentRole %s", + comp_role->cRole); + + if((m_state == OMX_StateLoaded)&& + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + DEBUG_PRINT_LOW("Set Parameter called in valid state"); + } + else + { + DEBUG_PRINT_ERROR("Set Parameter called in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + + if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevchybrid",OMX_MAX_STRINGNAME_SIZE) || + !strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevcswvdec",OMX_MAX_STRINGNAME_SIZE) || + !strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc",OMX_MAX_STRINGNAME_SIZE)) + { + if(!strncmp((char*)comp_role->cRole,"video_decoder.hevc",OMX_MAX_STRINGNAME_SIZE)) + { + strlcpy((char*)m_cRole,"video_decoder.hevc",OMX_MAX_STRINGNAME_SIZE); + } + else + { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } + else + { + DEBUG_PRINT_ERROR("Setparameter: unknown param %s", drv_ctx.kind); + eRet = OMX_ErrorInvalidComponentName; + } + break; + } + + case OMX_IndexParamPriorityMgmt: + { + if(m_state != OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("Set Parameter called in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + OMX_PRIORITYMGMTTYPE *priorityMgmtype = (OMX_PRIORITYMGMTTYPE*) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPriorityMgmt %d", + (int)priorityMgmtype->nGroupID); + + DEBUG_PRINT_LOW("set_parameter: priorityMgmtype %d", + (int)priorityMgmtype->nGroupPriority); + + m_priority_mgm.nGroupID = priorityMgmtype->nGroupID; + m_priority_mgm.nGroupPriority = priorityMgmtype->nGroupPriority; + + break; + } + + case OMX_IndexParamCompBufferSupplier: + { + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamCompBufferSupplier %d", + bufferSupplierType->eBufferSupplier); + if(bufferSupplierType->nPortIndex == 0 || bufferSupplierType->nPortIndex ==1) + m_buffer_supplier.eBufferSupplier = bufferSupplierType->eBufferSupplier; + + else + + eRet = OMX_ErrorBadPortIndex; + + break; + + } + case OMX_IndexParamVideoAvc: + case OMX_IndexParamVideoH263: + case OMX_IndexParamVideoMpeg4: + case OMX_IndexParamVideoMpeg2: + { + eRet = OMX_ErrorUnsupportedSetting; + break; + } + case OMX_QcomIndexParamVideoDecoderPictureOrder: + { + QOMX_VIDEO_DECODER_PICTURE_ORDER *pictureOrder = + (QOMX_VIDEO_DECODER_PICTURE_ORDER *)paramData; + struct v4l2_control control; + int pic_order,rc=0; + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexParamVideoDecoderPictureOrder %d", + pictureOrder->eOutputPictureOrder); + if (pictureOrder->eOutputPictureOrder == QOMX_VIDEO_DISPLAY_ORDER) { + pic_order = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY; + } + else if (pictureOrder->eOutputPictureOrder == QOMX_VIDEO_DECODE_ORDER){ + pic_order = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE; + time_stamp_dts.set_timestamp_reorder_mode(false); + } + else + eRet = OMX_ErrorBadParameter; + if (eRet == OMX_ErrorNone) + { + if (!m_pSwVdec || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER; + control.value = pic_order; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if(rc) + { + DEBUG_PRINT_ERROR("Set picture order failed"); + eRet = OMX_ErrorUnsupportedSetting; + } + } + // if (m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) + { + // TODO + } + } + break; + } + case OMX_QcomIndexParamConcealMBMapExtraData: + if(!secure_mode) + eRet = enable_extradata(VDEC_EXTRADATA_MB_ERROR_MAP, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + else { + DEBUG_PRINT_ERROR("secure mode setting not supported"); + eRet = OMX_ErrorUnsupportedSetting; + } + break; + case OMX_QcomIndexParamFrameInfoExtraData: + { + if(!secure_mode) + eRet = enable_extradata(OMX_FRAMEINFO_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + else { + DEBUG_PRINT_ERROR("secure mode setting not supported"); + eRet = OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QcomIndexParamInterlaceExtraData: + if(!secure_mode) + eRet = enable_extradata(OMX_INTERLACE_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + else { + DEBUG_PRINT_ERROR("secure mode setting not supported"); + eRet = OMX_ErrorUnsupportedSetting; + } + break; + case OMX_QcomIndexParamH264TimeInfo: + if(!secure_mode) + eRet = enable_extradata(OMX_TIMEINFO_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + else { + DEBUG_PRINT_ERROR("secure mode setting not supported"); + eRet = OMX_ErrorUnsupportedSetting; + } + break; + case OMX_QcomIndexParamVideoDivx: + { + QOMX_VIDEO_PARAM_DIVXTYPE* divXType = (QOMX_VIDEO_PARAM_DIVXTYPE *) paramData; + } + break; + case OMX_QcomIndexPlatformPvt: + { + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexPlatformPvt OP Port"); + OMX_QCOM_PLATFORMPRIVATE_EXTN* entryType = (OMX_QCOM_PLATFORMPRIVATE_EXTN *) paramData; + if (entryType->type != OMX_QCOM_PLATFORM_PRIVATE_PMEM) + { + DEBUG_PRINT_HIGH("set_parameter: Platform Private entry type (%d) not supported.", entryType->type); + eRet = OMX_ErrorUnsupportedSetting; + } + else + { + m_out_pvt_entry_pmem = OMX_TRUE; + if ((m_out_mem_region_smi && m_out_pvt_entry_pmem)) + { + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexPlatformPvt OP Port: out pmem set"); + m_use_output_pmem = OMX_TRUE; + } + } + + } + break; + case OMX_QcomIndexParamVideoSyncFrameDecodingMode: + { + if (!m_pSwVdec || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) { + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexParamVideoSyncFrameDecodingMode"); + DEBUG_PRINT_HIGH("set idr only decoding for thumbnail mode"); + struct v4l2_control control; + int rc; + drv_ctx.idr_only_decoding = 1; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER; + control.value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if(rc) + { + DEBUG_PRINT_ERROR("Set picture order failed"); + eRet = OMX_ErrorUnsupportedSetting; + } else { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE; + control.value = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if(rc) + { + DEBUG_PRINT_ERROR("Sync frame setting failed"); + eRet = OMX_ErrorUnsupportedSetting; + } + /* Setting sync frame decoding on driver might change + * buffer requirements so update them here*/ + if (get_buffer_req(&drv_ctx.ip_buf)) { + DEBUG_PRINT_ERROR("Sync frame setting failed: falied to get buffer i/p requirements"); + eRet = OMX_ErrorUnsupportedSetting; + } + if (!m_pSwVdec) { // for full dsp mode + if (get_buffer_req(&drv_ctx.op_buf)) { + DEBUG_PRINT_ERROR("Sync frame setting failed: falied to get buffer o/p requirements"); + eRet = OMX_ErrorUnsupportedSetting; + } + } else if (get_buffer_req(&drv_ctx.interm_op_buf)) { // for hybrid + DEBUG_PRINT_ERROR("Sync frame setting failed: falied to get buffer o/p requirements"); + eRet = OMX_ErrorUnsupportedSetting; + } + } + } + } + break; + + case OMX_QcomIndexParamIndexExtraDataType: + { + if(!secure_mode) { + QOMX_INDEXEXTRADATATYPE *extradataIndexType = (QOMX_INDEXEXTRADATATYPE *) paramData; + if ((extradataIndexType->nIndex == OMX_IndexParamPortDefinition) && + (extradataIndexType->bEnabled == OMX_TRUE) && + (extradataIndexType->nPortIndex == 1)) + { + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexParamIndexExtraDataType SmoothStreaming"); + eRet = enable_extradata(OMX_PORTDEF_EXTRADATA, false, extradataIndexType->bEnabled); + + } + } + } + break; + case OMX_QcomIndexParamEnableSmoothStreaming: + { +#ifndef SMOOTH_STREAMING_DISABLED + if (!m_pSwVdec || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) { + eRet = enable_smoothstreaming(); + } +#else + eRet = OMX_ErrorUnsupportedSetting; +#endif + } + break; +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) + /* Need to allow following two set_parameters even in Idle + * state. This is ANDROID architecture which is not in sync + * with openmax standard. */ + case OMX_GoogleAndroidIndexEnableAndroidNativeBuffers: + { + EnableAndroidNativeBuffersParams* enableNativeBuffers = (EnableAndroidNativeBuffersParams *) paramData; + if(enableNativeBuffers) { + m_enable_android_native_buffers = enableNativeBuffers->enable; + } + } + break; + case OMX_GoogleAndroidIndexUseAndroidNativeBuffer: + { + eRet = use_android_native_buffer(hComp, paramData); + } + break; +#endif + case OMX_QcomIndexParamEnableTimeStampReorder: + { + QOMX_INDEXTIMESTAMPREORDER *reorder = (QOMX_INDEXTIMESTAMPREORDER *)paramData; + if (drv_ctx.picture_order == (vdec_output_order)QOMX_VIDEO_DISPLAY_ORDER) { + if (reorder->bEnable == OMX_TRUE) { + frm_int =0; + time_stamp_dts.set_timestamp_reorder_mode(true); + } + else + time_stamp_dts.set_timestamp_reorder_mode(false); + } else { + time_stamp_dts.set_timestamp_reorder_mode(false); + if (reorder->bEnable == OMX_TRUE) + { + eRet = OMX_ErrorUnsupportedSetting; + } + } + } + break; + case OMX_QcomIndexParamVideoMetaBufferMode: + { + DEBUG_PRINT_LOW("set_parameter: OMX_QcomIndexParamVideoMetaBufferMode"); + if (m_disable_dynamic_buf_mode) { + DEBUG_PRINT_HIGH("Dynamic buffer mode disabled by setprop"); + eRet = OMX_ErrorUnsupportedSetting; + break; + } + StoreMetaDataInBuffersParams *metabuffer = + (StoreMetaDataInBuffersParams *)paramData; + if (!metabuffer) { + DEBUG_PRINT_ERROR("Invalid param: %p", metabuffer); + eRet = OMX_ErrorBadParameter; + break; + } + if (metabuffer->nPortIndex == OMX_CORE_OUTPUT_PORT_INDEX) { + if (m_pSwVdec == NULL) { + //set property dynamic buffer mode to driver. + struct v4l2_control control; + struct v4l2_format fmt; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT; + if (metabuffer->bStoreMetaData == true) { + control.value = V4L2_MPEG_VIDC_VIDEO_DYNAMIC; + } else { + control.value = V4L2_MPEG_VIDC_VIDEO_STATIC; + } + int rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL,&control); + if (!rc) { + DEBUG_PRINT_HIGH(" %s buffer mode", + (metabuffer->bStoreMetaData == true)? "Enabled dynamic" : "Disabled dynamic"); + dynamic_buf_mode = metabuffer->bStoreMetaData; + } else { + DEBUG_PRINT_ERROR("Failed to %s buffer mode", + (metabuffer->bStoreMetaData == true)? "enable dynamic" : "disable dynamic"); + dynamic_buf_mode = false; + eRet = OMX_ErrorUnsupportedSetting; + } + } else { // for hybrid codec + DEBUG_PRINT_HIGH(" %s buffer mode", + (metabuffer->bStoreMetaData == true)? "Enabled dynamic" : "Disabled dynamic"); + dynamic_buf_mode = metabuffer->bStoreMetaData; + if (dynamic_buf_mode) { + SWVDEC_PROP prop; + prop.ePropId = SWVDEC_PROP_ID_BUFFER_ALLOC_MODE; + prop.uProperty.sBufAllocMode.eBufAllocMode = SWVDEC_BUF_ALLOC_MODE_DYNAMIC; + if (SwVdec_SetProperty(m_pSwVdec, &prop)) + { + DEBUG_PRINT_ERROR( + "OMX_QcomIndexParamVideoMetaBufferMode not supported for port: %lu", + metabuffer->nPortIndex); + eRet = OMX_ErrorUnsupportedSetting; + } + else + { + DEBUG_PRINT_LOW( + "OMX_QcomIndexParamVideoMetaBufferMode supported for port: %lu", + metabuffer->nPortIndex); + } + } + } + } else { + DEBUG_PRINT_ERROR( + "OMX_QcomIndexParamVideoMetaBufferMode not supported for port: %lu", + metabuffer->nPortIndex); + eRet = OMX_ErrorUnsupportedSetting; + } + } + break; +#ifdef ADAPTIVE_PLAYBACK_SUPPORTED + case OMX_QcomIndexParamVideoAdaptivePlaybackMode: + { + DEBUG_PRINT_LOW("set_parameter: OMX_GoogleAndroidIndexPrepareForAdaptivePlayback"); + PrepareForAdaptivePlaybackParams* pParams = + (PrepareForAdaptivePlaybackParams *) paramData; + if (pParams->nPortIndex == OMX_CORE_OUTPUT_PORT_INDEX) { + if (!pParams->bEnable) { + return OMX_ErrorNone; + } + if (pParams->nMaxFrameWidth > maxSmoothStreamingWidth + || pParams->nMaxFrameHeight > maxSmoothStreamingHeight) { + DEBUG_PRINT_ERROR( + "Adaptive playback request exceeds max supported resolution : [%lu x %lu] vs [%lu x %lu]", + pParams->nMaxFrameWidth, pParams->nMaxFrameHeight, + maxSmoothStreamingWidth, maxSmoothStreamingHeight); + eRet = OMX_ErrorBadParameter; + } else + { + eRet = enable_smoothstreaming(); + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("Failed to enable Adaptive Playback on driver."); + eRet = OMX_ErrorHardware; + } else { + DEBUG_PRINT_HIGH("Enabling Adaptive playback for %lu x %lu", + pParams->nMaxFrameWidth, pParams->nMaxFrameHeight); + m_smoothstreaming_mode = true; + m_smoothstreaming_width = pParams->nMaxFrameWidth; + m_smoothstreaming_height = pParams->nMaxFrameHeight; + } + struct v4l2_format fmt; + update_resolution(m_smoothstreaming_width, m_smoothstreaming_height, + m_smoothstreaming_width, m_smoothstreaming_height); + if (!m_pSwVdec || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = output_capability; + DEBUG_PRINT_LOW("fmt.fmt.pix_mp.height = %d , fmt.fmt.pix_mp.width = %d", + fmt.fmt.pix_mp.height,fmt.fmt.pix_mp.width); + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + DEBUG_PRINT_ERROR("Set Resolution failed"); + eRet = OMX_ErrorUnsupportedSetting; + } else + eRet = get_buffer_req(&drv_ctx.op_buf); + } + else if (SWVDEC_MODE_PARSE_DECODE == m_swvdec_mode) + { + SWVDEC_PROP prop; + SWVDEC_STATUS sRet; + /* set QCIF resolution to get UpperLimit_bufferCount */ + prop.ePropId = SWVDEC_PROP_ID_DIMENSIONS; + prop.uProperty.sDimensions.nWidth = 176; + prop.uProperty.sDimensions.nHeight= 144; + sRet = SwVdec_SetProperty(m_pSwVdec,&prop); + if (SWVDEC_S_SUCCESS != sRet) + { + DEBUG_PRINT_ERROR("SwVdec_SetProperty failed (%d)", sRet); + eRet = OMX_ErrorUndefined; + break; + } + + prop.ePropId = SWVDEC_PROP_ID_OPBUFFREQ; + sRet = SwVdec_GetProperty(m_pSwVdec, &prop); + if (SWVDEC_S_SUCCESS == sRet) + { + drv_ctx.op_buf.actualcount = prop.uProperty.sOpBuffReq.nMinCount; + drv_ctx.op_buf.mincount = prop.uProperty.sOpBuffReq.nMinCount; + } + else + { + DEBUG_PRINT_ERROR("SwVdec_GetProperty failed (%d)", sRet); + eRet = OMX_ErrorUndefined; + break; + } + + /* set the max smooth-streaming resolution to get the buffer size */ + prop.ePropId = SWVDEC_PROP_ID_DIMENSIONS; + prop.uProperty.sDimensions.nWidth = m_smoothstreaming_width; + prop.uProperty.sDimensions.nHeight= m_smoothstreaming_height; + SwVdec_SetProperty(m_pSwVdec,&prop); + if (SWVDEC_S_SUCCESS != sRet) + { + DEBUG_PRINT_ERROR("SwVdec_SetProperty failed (%d)", sRet); + eRet = OMX_ErrorUndefined; + break; + } + + prop.ePropId = SWVDEC_PROP_ID_OPBUFFREQ; + sRet = SwVdec_GetProperty(m_pSwVdec, &prop); + if (SWVDEC_S_SUCCESS == sRet) + { + int client_extra_data_size = 0; + if (client_extradata & OMX_FRAMEINFO_EXTRADATA) + { + DEBUG_PRINT_HIGH("Frame info extra data enabled!"); + client_extra_data_size += OMX_FRAMEINFO_EXTRADATA_SIZE; + } + if (client_extradata & OMX_INTERLACE_EXTRADATA) + { + DEBUG_PRINT_HIGH("OMX_INTERLACE_EXTRADATA!"); + client_extra_data_size += OMX_INTERLACE_EXTRADATA_SIZE; + } + if (client_extradata & OMX_PORTDEF_EXTRADATA) + { + client_extra_data_size += OMX_PORTDEF_EXTRADATA_SIZE; + DEBUG_PRINT_HIGH("Smooth streaming enabled extra_data_size=%d", + client_extra_data_size); + } + if (client_extra_data_size) + { + client_extra_data_size += sizeof(OMX_OTHER_EXTRADATATYPE); //Space for terminator + } + drv_ctx.op_buf.buffer_size = prop.uProperty.sOpBuffReq.nSize + client_extra_data_size; + } + else + { + DEBUG_PRINT_ERROR("SwVdec_GetProperty failed (%d)", sRet); + eRet = OMX_ErrorUndefined; + break; + } + + /* set the buffer requirement to sw vdec */ + prop.uProperty.sOpBuffReq.nSize = drv_ctx.op_buf.buffer_size; + prop.uProperty.sOpBuffReq.nMaxCount = drv_ctx.op_buf.actualcount; + prop.uProperty.sOpBuffReq.nMinCount = drv_ctx.op_buf.mincount; + + prop.ePropId = SWVDEC_PROP_ID_OPBUFFREQ; + sRet = SwVdec_SetProperty(m_pSwVdec, &prop); + if (SWVDEC_S_SUCCESS != sRet) + { + DEBUG_PRINT_ERROR("SwVdec_SetProperty failed (%d)", sRet); + eRet = OMX_ErrorUndefined; + break; + } + } + } + } + else + { + DEBUG_PRINT_ERROR( + "Prepare for adaptive playback supported only on output port"); + eRet = OMX_ErrorBadParameter; + } + break; + } +#endif + default: + { + DEBUG_PRINT_ERROR("Setparameter: unknown param %d", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + } + } + return eRet; +} + +/* ====================================================================== +FUNCTION +omx_vdec::GetConfig + +DESCRIPTION +OMX Get Config Method implementation. + +PARAMETERS +<TBD>. + +RETURN VALUE +OMX Error None if successful. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_INOUT OMX_PTR configData) +{ + (void) hComp; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Config in Invalid State"); + return OMX_ErrorInvalidState; + } + + switch ((unsigned long)configIndex) + { + case OMX_QcomIndexConfigInterlaced: + { + OMX_QCOM_CONFIG_INTERLACETYPE *configFmt = + (OMX_QCOM_CONFIG_INTERLACETYPE *) configData; + if (configFmt->nPortIndex == 1) + { + if (configFmt->nIndex == 0) + { + configFmt->eInterlaceType = OMX_QCOM_InterlaceFrameProgressive; + } + else if (configFmt->nIndex == 1) + { + configFmt->eInterlaceType = + OMX_QCOM_InterlaceInterleaveFrameTopFieldFirst; + } + else if (configFmt->nIndex == 2) + { + configFmt->eInterlaceType = + OMX_QCOM_InterlaceInterleaveFrameBottomFieldFirst; + } + else + { + DEBUG_PRINT_ERROR("get_config: OMX_QcomIndexConfigInterlaced:" + " NoMore Interlaced formats"); + eRet = OMX_ErrorNoMore; + } + + } + else + { + DEBUG_PRINT_ERROR("get_config: Bad port index %d queried on only o/p port", + (int)configFmt->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_QcomIndexQueryNumberOfVideoDecInstance: + { + QOMX_VIDEO_QUERY_DECODER_INSTANCES *decoderinstances = + (QOMX_VIDEO_QUERY_DECODER_INSTANCES*)configData; + decoderinstances->nNumOfInstances = 16; + /*TODO: How to handle this case */ + break; + } + case OMX_QcomIndexConfigVideoFramePackingArrangement: + { + DEBUG_PRINT_ERROR("get_config: Framepack data not supported for non H264 codecs"); + break; + } + case OMX_IndexConfigCommonOutputCrop: + { + OMX_CONFIG_RECTTYPE *rect = (OMX_CONFIG_RECTTYPE *) configData; + memcpy(rect, &rectangle, sizeof(OMX_CONFIG_RECTTYPE)); + break; + } + default: + { + DEBUG_PRINT_ERROR("get_config: unknown param %d",configIndex); + eRet = OMX_ErrorBadParameter; + } + + } + + return eRet; +} + +/* ====================================================================== +FUNCTION +omx_vdec::SetConfig + +DESCRIPTION +OMX Set Config method implementation + +PARAMETERS +<TBD>. + +RETURN VALUE +OMX Error None if successful. +========================================================================== */ +OMX_ERRORTYPE omx_vdec::set_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_IN OMX_PTR configData) +{ + (void) hComp; + if(m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Config in Invalid State"); + return OMX_ErrorInvalidState; + } + + OMX_ERRORTYPE ret = OMX_ErrorNone; + OMX_VIDEO_CONFIG_NALSIZE *pNal; + + DEBUG_PRINT_LOW("Set Config Called"); + + if (m_state == OMX_StateExecuting) + { + DEBUG_PRINT_ERROR("set_config:Ignore in Exe state"); + return ret; + } + + if (configIndex == (OMX_INDEXTYPE)OMX_IndexVendorVideoExtraData) + { + OMX_VENDOR_EXTRADATATYPE *config = (OMX_VENDOR_EXTRADATATYPE *) configData; + DEBUG_PRINT_LOW("Index OMX_IndexVendorVideoExtraData called"); + return ret; + } + else if (configIndex == OMX_IndexConfigVideoNalSize) + { + + pNal = reinterpret_cast < OMX_VIDEO_CONFIG_NALSIZE * >(configData); + nal_length = pNal->nNaluBytes; + m_frame_parser.init_nal_length(nal_length); + DEBUG_PRINT_LOW("OMX_IndexConfigVideoNalSize called with Size %d",nal_length); + return ret; + } + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== +FUNCTION +omx_vdec::GetExtensionIndex + +DESCRIPTION +OMX GetExtensionIndex method implementaion. <TBD> + +PARAMETERS +<TBD>. + +RETURN VALUE +OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_extension_index(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_STRING paramName, + OMX_OUT OMX_INDEXTYPE* indexType) +{ + (void) hComp; + if(m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Get Extension Index in Invalid State"); + return OMX_ErrorInvalidState; + } + else if (!strncmp(paramName, "OMX.QCOM.index.param.video.SyncFrameDecodingMode",sizeof("OMX.QCOM.index.param.video.SyncFrameDecodingMode") - 1)) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoSyncFrameDecodingMode; + } + else if (!strncmp(paramName, "OMX.QCOM.index.param.IndexExtraData",sizeof("OMX.QCOM.index.param.IndexExtraData") - 1)) + { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamIndexExtraDataType; + } +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) + else if(!strncmp(paramName,"OMX.google.android.index.enableAndroidNativeBuffers", sizeof("OMX.google.android.index.enableAndroidNativeBuffers") - 1)) { + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexEnableAndroidNativeBuffers; + } + else if(!strncmp(paramName,"OMX.google.android.index.useAndroidNativeBuffer2", sizeof("OMX.google.android.index.enableAndroidNativeBuffer2") - 1)) { + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexUseAndroidNativeBuffer2; + } + else if(!strncmp(paramName,"OMX.google.android.index.useAndroidNativeBuffer", sizeof("OMX.google.android.index.enableAndroidNativeBuffer") - 1)) { + DEBUG_PRINT_ERROR("Extension: %s is supported", paramName); + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexUseAndroidNativeBuffer; + } + else if(!strncmp(paramName,"OMX.google.android.index.getAndroidNativeBufferUsage", sizeof("OMX.google.android.index.getAndroidNativeBufferUsage") - 1)) { + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage; + } +#endif + else if (!strncmp(paramName, "OMX.google.android.index.storeMetaDataInBuffers", sizeof("OMX.google.android.index.storeMetaDataInBuffers") - 1)) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoMetaBufferMode; + } +#if ADAPTIVE_PLAYBACK_SUPPORTED + else if (!strncmp(paramName, "OMX.google.android.index.prepareForAdaptivePlayback", sizeof("OMX.google.android.index.prepareForAdaptivePlayback") -1)) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoAdaptivePlaybackMode; + } +#endif + else { + DEBUG_PRINT_ERROR("Extension: %s not implemented", paramName); + return OMX_ErrorNotImplemented; + } + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION +omx_vdec::GetState + +DESCRIPTION +Returns the state information back to the caller.<TBD> + +PARAMETERS +<TBD>. + +RETURN VALUE +Error None if everything is successful. +========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_state(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STATETYPE* state) +{ + (void) hComp; + *state = m_state; + DEBUG_PRINT_LOW("get_state: Returning the state %d",*state); + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION +omx_vdec::ComponentTunnelRequest + +DESCRIPTION +OMX Component Tunnel Request method implementation. <TBD> + +PARAMETERS +None. + +RETURN VALUE +OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::component_tunnel_request(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_HANDLETYPE peerComponent, + OMX_IN OMX_U32 peerPort, + OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup) +{ + (void) hComp; + (void) port; + (void) peerComponent; + (void) peerPort; + (void) tunnelSetup; + DEBUG_PRINT_ERROR("Error: component_tunnel_request Not Implemented"); + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== +FUNCTION +omx_vdec::UseOutputBuffer + +DESCRIPTION +Helper function for Use buffer in the input pin + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::allocate_extradata() +{ +#ifdef USE_ION + if (drv_ctx.extradata_info.buffer_size) { + if (drv_ctx.extradata_info.ion.ion_alloc_data.handle) { + munmap((void *)drv_ctx.extradata_info.uaddr, drv_ctx.extradata_info.size); + close(drv_ctx.extradata_info.ion.fd_ion_data.fd); + free_ion_memory(&drv_ctx.extradata_info.ion); + } + drv_ctx.extradata_info.size = (drv_ctx.extradata_info.size + 4095) & (~4095); + DEBUG_PRINT_HIGH("allocate extradata memory size %d", drv_ctx.extradata_info.size); + int heap = 0; +#ifdef _HEVC_USE_ADSP_HEAP_ + heap = ION_ADSP_HEAP_ID; +#else + heap = ION_IOMMU_HEAP_ID; +#endif + drv_ctx.extradata_info.ion.ion_device_fd = alloc_map_ion_memory( + drv_ctx.extradata_info.size, 4096, + &drv_ctx.extradata_info.ion.ion_alloc_data, + &drv_ctx.extradata_info.ion.fd_ion_data, 0, heap); + if (drv_ctx.extradata_info.ion.ion_device_fd < 0) { + DEBUG_PRINT_ERROR("Failed to alloc extradata memory"); + return OMX_ErrorInsufficientResources; + } + drv_ctx.extradata_info.uaddr = (char *)mmap(NULL, + drv_ctx.extradata_info.size, + PROT_READ|PROT_WRITE, MAP_SHARED, + drv_ctx.extradata_info.ion.fd_ion_data.fd , 0); + if (drv_ctx.extradata_info.uaddr == MAP_FAILED) { + DEBUG_PRINT_ERROR("Failed to map extradata memory"); + close(drv_ctx.extradata_info.ion.fd_ion_data.fd); + free_ion_memory(&drv_ctx.extradata_info.ion); + return OMX_ErrorInsufficientResources; + } + memset(drv_ctx.extradata_info.uaddr, 0, drv_ctx.extradata_info.size); + } +#endif + return OMX_ErrorNone; +} + +void omx_vdec::free_extradata() { +#ifdef USE_ION + if (drv_ctx.extradata_info.uaddr) { + munmap((void *)drv_ctx.extradata_info.uaddr, drv_ctx.extradata_info.size); + close(drv_ctx.extradata_info.ion.fd_ion_data.fd); + free_ion_memory(&drv_ctx.extradata_info.ion); + } + memset(&drv_ctx.extradata_info, 0, sizeof(drv_ctx.extradata_info)); +#endif +} + +OMX_ERRORTYPE omx_vdec::use_output_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr= NULL; // buffer header + unsigned i= 0; // Temporary counter + struct vdec_setbuffer_cmd setbuffers; + OMX_PTR privateAppData = NULL; + private_handle_t *handle = NULL; + OMX_U8 *buff = buffer; + (void) hComp; + (void) port; + + if (!m_out_mem_ptr) { + DEBUG_PRINT_HIGH("Use_op_buf:Allocating output headers"); + eRet = allocate_output_headers(); + if (!m_pSwVdec && eRet == OMX_ErrorNone) + eRet = allocate_extradata(); + } + + if (eRet == OMX_ErrorNone) { + for(i=0; i< drv_ctx.op_buf.actualcount; i++) { + if(BITMASK_ABSENT(&m_out_bm_count,i)) + { + break; + } + } + } + + if(i >= drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("Already using %d o/p buffers", drv_ctx.op_buf.actualcount); + eRet = OMX_ErrorInsufficientResources; + } + + if (dynamic_buf_mode) { + if (m_pSwVdec && !m_pSwVdecOpBuffer) + { + SWVDEC_PROP prop; + DEBUG_PRINT_HIGH("allocating m_pSwVdecOpBuffer %d", drv_ctx.op_buf.actualcount); + m_pSwVdecOpBuffer = (SWVDEC_OPBUFFER*)calloc(sizeof(SWVDEC_OPBUFFER), drv_ctx.op_buf.actualcount); + } + + *bufferHdr = (m_out_mem_ptr + i ); + (*bufferHdr)->pBuffer = NULL; + // for full dsp mode + if (!m_pSwVdec && i == (drv_ctx.op_buf.actualcount -1) && !streaming[CAPTURE_PORT]) { + enum v4l2_buf_type buf_type; + int rr = 0; + buf_type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (rr = ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type)) { + DEBUG_PRINT_ERROR("STREAMON FAILED : %d", rr); + return OMX_ErrorInsufficientResources; + } else { + streaming[CAPTURE_PORT] = true; + DEBUG_PRINT_LOW("STREAMON Successful"); + } + } + BITMASK_SET(&m_out_bm_count,i); + (*bufferHdr)->pAppPrivate = appData; + (*bufferHdr)->pBuffer = buffer; + (*bufferHdr)->nAllocLen = sizeof(struct VideoDecoderOutputMetaData); + + // SWVdec memory allocation and set the output buffer + if (m_pSwVdecOpBuffer) { + m_pSwVdecOpBuffer[i].nSize = sizeof(struct VideoDecoderOutputMetaData); + m_pSwVdecOpBuffer[i].pBuffer = buffer; + m_pSwVdecOpBuffer[i].pClientBufferData = (void*)(unsigned long)i; + } + + return eRet; + } + + if (eRet == OMX_ErrorNone) { +#if defined(_ANDROID_HONEYCOMB_) || defined(_ANDROID_ICS_) + if(m_enable_android_native_buffers) { + if (m_use_android_native_buffers) { + UseAndroidNativeBufferParams *params = (UseAndroidNativeBufferParams *)appData; + sp<android_native_buffer_t> nBuf = params->nativeBuffer; + handle = (private_handle_t *)nBuf->handle; + privateAppData = params->pAppPrivate; + } else { + handle = (private_handle_t *)buff; + privateAppData = appData; + } + + if ((OMX_U32)handle->size < drv_ctx.op_buf.buffer_size) { + DEBUG_PRINT_ERROR("Insufficient sized buffer given for playback," + " expected %u, got %lu", + drv_ctx.op_buf.buffer_size, (OMX_U32)handle->size); + return OMX_ErrorBadParameter; + } + + drv_ctx.op_buf.buffer_size = (OMX_U32)handle->size; + if (!m_use_android_native_buffers) { + if (!secure_mode) { + buff = (OMX_U8*)mmap(0, handle->size, + PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0); + if (buff == MAP_FAILED) { + DEBUG_PRINT_ERROR("Failed to mmap pmem with fd = %d, size = %d", handle->fd, handle->size); + return OMX_ErrorInsufficientResources; + } + } + } +#if defined(_ANDROID_ICS_) + native_buffer[i].nativehandle = handle; + native_buffer[i].privatehandle = handle; +#endif + if(!handle) { + DEBUG_PRINT_ERROR("Native Buffer handle is NULL"); + return OMX_ErrorBadParameter; + } + drv_ctx.ptr_outputbuffer[i].pmem_fd = handle->fd; + drv_ctx.ptr_outputbuffer[i].offset = 0; + drv_ctx.ptr_outputbuffer[i].bufferaddr = buff; + drv_ctx.ptr_outputbuffer[i].mmaped_size = + drv_ctx.ptr_outputbuffer[i].buffer_len = drv_ctx.op_buf.buffer_size; + drv_ctx.op_buf_ion_info[i].fd_ion_data.fd = handle->fd; + //drv_ctx.op_buf_ion_info[i].fd_ion_data.handle = (ion_user_handle_t)handle; + DEBUG_PRINT_HIGH("Native Buffer vaddr %p, idx %d fd %d len %d", buff,i, handle->fd , drv_ctx.op_buf.buffer_size); + } else +#endif + + if (!ouput_egl_buffers && !m_use_output_pmem) { +#ifdef USE_ION + DEBUG_PRINT_HIGH("allocate output buffer memory size %d", drv_ctx.op_buf.buffer_size); + drv_ctx.op_buf_ion_info[i].ion_device_fd = alloc_map_ion_memory( + drv_ctx.op_buf.buffer_size,drv_ctx.op_buf.alignment, + &drv_ctx.op_buf_ion_info[i].ion_alloc_data, + &drv_ctx.op_buf_ion_info[i].fd_ion_data, secure_mode ? ION_SECURE : 0); + if(drv_ctx.op_buf_ion_info[i].ion_device_fd < 0) { + DEBUG_PRINT_ERROR("ION device fd is bad %d", drv_ctx.op_buf_ion_info[i].ion_device_fd); + return OMX_ErrorInsufficientResources; + } + drv_ctx.ptr_outputbuffer[i].pmem_fd = \ + drv_ctx.op_buf_ion_info[i].fd_ion_data.fd; +#else + drv_ctx.ptr_outputbuffer[i].pmem_fd = \ + open (MEM_DEVICE,O_RDWR); + + if (drv_ctx.ptr_outputbuffer[i].pmem_fd < 0) { + DEBUG_PRINT_ERROR("ION/pmem buffer fd is bad %d", drv_ctx.ptr_outputbuffer[i].pmem_fd); + return OMX_ErrorInsufficientResources; + } + + /* FIXME: why is this code even here? We already open MEM_DEVICE a few lines above */ + if(drv_ctx.ptr_outputbuffer[i].pmem_fd == 0) + { + drv_ctx.ptr_outputbuffer[i].pmem_fd = \ + open (MEM_DEVICE,O_RDWR); + if (drv_ctx.ptr_outputbuffer[i].pmem_fd < 0) { + DEBUG_PRINT_ERROR("ION/pmem buffer fd is bad %d", drv_ctx.ptr_outputbuffer[i].pmem_fd); + return OMX_ErrorInsufficientResources; + } + } + + if(!align_pmem_buffers(drv_ctx.ptr_outputbuffer[i].pmem_fd, + drv_ctx.op_buf.buffer_size, + drv_ctx.op_buf.alignment)) + { + DEBUG_PRINT_ERROR("align_pmem_buffers() failed"); + close(drv_ctx.ptr_outputbuffer[i].pmem_fd); + return OMX_ErrorInsufficientResources; + } +#endif + + if(!secure_mode) { + drv_ctx.ptr_outputbuffer[i].bufferaddr = + (unsigned char *)mmap(NULL, drv_ctx.op_buf.buffer_size, + PROT_READ|PROT_WRITE, MAP_SHARED, + drv_ctx.ptr_outputbuffer[i].pmem_fd,0); + if (drv_ctx.ptr_outputbuffer[i].bufferaddr == MAP_FAILED) { + close(drv_ctx.ptr_outputbuffer[i].pmem_fd); +#ifdef USE_ION + free_ion_memory(&drv_ctx.op_buf_ion_info[i]); +#endif + DEBUG_PRINT_ERROR("Unable to mmap output buffer"); + return OMX_ErrorInsufficientResources; + } + } + drv_ctx.ptr_outputbuffer[i].offset = 0; + privateAppData = appData; + } + else { + + DEBUG_PRINT_HIGH("Use_op_buf: out_pmem=%d",m_use_output_pmem); + if (!appData || !bytes ) { + if(!secure_mode && !buffer) { + DEBUG_PRINT_ERROR("Bad parameters for use buffer in EGL image case"); + return OMX_ErrorBadParameter; + } + } + + OMX_QCOM_PLATFORM_PRIVATE_LIST *pmem_list; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pmem_info; + pmem_list = (OMX_QCOM_PLATFORM_PRIVATE_LIST*) appData; + if (!pmem_list->entryList || !pmem_list->entryList->entry || + !pmem_list->nEntries || + pmem_list->entryList->type != OMX_QCOM_PLATFORM_PRIVATE_PMEM) { + DEBUG_PRINT_ERROR("Pmem info not valid in use buffer"); + return OMX_ErrorBadParameter; + } + pmem_info = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) + pmem_list->entryList->entry; + DEBUG_PRINT_LOW("vdec: use buf: pmem_fd=0x%x", + (unsigned int)pmem_info->pmem_fd); + drv_ctx.ptr_outputbuffer[i].pmem_fd = pmem_info->pmem_fd; + drv_ctx.ptr_outputbuffer[i].offset = pmem_info->offset; + drv_ctx.ptr_outputbuffer[i].bufferaddr = buff; + drv_ctx.ptr_outputbuffer[i].mmaped_size = + drv_ctx.ptr_outputbuffer[i].buffer_len = drv_ctx.op_buf.buffer_size; + privateAppData = appData; + } + m_pmem_info[i].offset = drv_ctx.ptr_outputbuffer[i].offset; + m_pmem_info[i].pmem_fd = drv_ctx.ptr_outputbuffer[i].pmem_fd; + + *bufferHdr = (m_out_mem_ptr + i ); + if(secure_mode) + drv_ctx.ptr_outputbuffer[i].bufferaddr = *bufferHdr; + //setbuffers.buffer_type = VDEC_BUFFER_TYPE_OUTPUT; + memcpy (&setbuffers.buffer,&drv_ctx.ptr_outputbuffer[i], + sizeof (vdec_bufferpayload)); + + DEBUG_PRINT_HIGH("Set the Output Buffer Idx: %d Addr: %p, pmem_fd=0x%x", i, + drv_ctx.ptr_outputbuffer[i].bufferaddr, + drv_ctx.ptr_outputbuffer[i].pmem_fd ); + + if (m_pSwVdec) + { + if (m_pSwVdecOpBuffer == NULL) + { + DEBUG_PRINT_HIGH("allocating m_pSwVdecOpBuffer %d", drv_ctx.op_buf.actualcount); + m_pSwVdecOpBuffer = (SWVDEC_OPBUFFER*)calloc(sizeof(SWVDEC_OPBUFFER), drv_ctx.op_buf.actualcount); + } + + // SWVdec memory allocation and set the output buffer + m_pSwVdecOpBuffer[i].nSize = drv_ctx.ptr_outputbuffer[i].mmaped_size; + m_pSwVdecOpBuffer[i].pBuffer = (uint8*)drv_ctx.ptr_outputbuffer[i].bufferaddr; + m_pSwVdecOpBuffer[i].pClientBufferData = (void*)(unsigned long)i; + if (SWVDEC_S_SUCCESS !=SwVdec_SetOutputBuffer(m_pSwVdec, &m_pSwVdecOpBuffer[i])) + { + DEBUG_PRINT_HIGH("SwVdec_SetOutputBuffer failed in use_output_buffer"); + return OMX_ErrorInsufficientResources; + } + } + else + { + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + int extra_idx = 0; + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].length = drv_ctx.op_buf.buffer_size; + plane[0].m.userptr = (unsigned long)drv_ctx.ptr_outputbuffer[i].bufferaddr - + (unsigned long)drv_ctx.ptr_outputbuffer[i].offset; + plane[0].reserved[0] = drv_ctx.ptr_outputbuffer[i].pmem_fd; + plane[0].reserved[1] = drv_ctx.ptr_outputbuffer[i].offset; + plane[0].data_offset = 0; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].length = drv_ctx.extradata_info.buffer_size; + plane[extra_idx].m.userptr = (long unsigned int) (drv_ctx.extradata_info.uaddr + i * drv_ctx.extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = drv_ctx.extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = i * drv_ctx.extradata_info.buffer_size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index is more than allowed: %d", extra_idx); + return OMX_ErrorBadParameter; + } + buf.m.planes = plane; + buf.length = drv_ctx.num_planes; + + DEBUG_PRINT_LOW("Set the Output Buffer Idx: %d Addr: %p", i, drv_ctx.ptr_outputbuffer[i].bufferaddr); + + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_PREPARE_BUF, &buf)) { + DEBUG_PRINT_ERROR("Failed to prepare bufs"); + /*TODO: How to handle this case */ + return OMX_ErrorInsufficientResources; + } + + if (i == (drv_ctx.op_buf.actualcount -1) && !streaming[CAPTURE_PORT]) { + enum v4l2_buf_type buf_type; + buf_type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type)) { + return OMX_ErrorInsufficientResources; + } else { + streaming[CAPTURE_PORT] = true; + DEBUG_PRINT_LOW("STREAMON Successful"); + } + } + } + + (*bufferHdr)->nAllocLen = drv_ctx.op_buf.buffer_size; + if (m_enable_android_native_buffers) { + DEBUG_PRINT_LOW("setting pBuffer to private_handle_t %p", handle); + (*bufferHdr)->pBuffer = (OMX_U8 *)handle; + } else { + (*bufferHdr)->pBuffer = buff; + } + (*bufferHdr)->pAppPrivate = privateAppData; + BITMASK_SET(&m_out_bm_count,i); + } + return eRet; +} + +/* ====================================================================== +FUNCTION +omx_vdec::use_input_heap_buffers + +DESCRIPTION +OMX Use Buffer Heap allocation method implementation. + +PARAMETERS +<TBD>. + +RETURN VALUE +OMX Error None , if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::use_input_heap_buffers( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + DEBUG_PRINT_LOW("Inside %s, %p", __FUNCTION__, buffer); + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if(!m_inp_heap_ptr) + m_inp_heap_ptr = (OMX_BUFFERHEADERTYPE*) + calloc( (sizeof(OMX_BUFFERHEADERTYPE)), + drv_ctx.ip_buf.actualcount); + if(!m_phdr_pmem_ptr) + m_phdr_pmem_ptr = (OMX_BUFFERHEADERTYPE**) + calloc( (sizeof(OMX_BUFFERHEADERTYPE*)), + drv_ctx.ip_buf.actualcount); + if(!m_inp_heap_ptr || !m_phdr_pmem_ptr) + { + DEBUG_PRINT_ERROR("Insufficent memory"); + eRet = OMX_ErrorInsufficientResources; + } + else if (m_in_alloc_cnt < drv_ctx.ip_buf.actualcount) + { + input_use_buffer = true; + memset(&m_inp_heap_ptr[m_in_alloc_cnt], 0, sizeof(OMX_BUFFERHEADERTYPE)); + m_inp_heap_ptr[m_in_alloc_cnt].pBuffer = buffer; + m_inp_heap_ptr[m_in_alloc_cnt].nAllocLen = bytes; + m_inp_heap_ptr[m_in_alloc_cnt].pAppPrivate = appData; + m_inp_heap_ptr[m_in_alloc_cnt].nInputPortIndex = (OMX_U32) OMX_DirInput; + m_inp_heap_ptr[m_in_alloc_cnt].nOutputPortIndex = (OMX_U32) OMX_DirMax; + *bufferHdr = &m_inp_heap_ptr[m_in_alloc_cnt]; + eRet = + allocate_input_buffer(hComp, &m_phdr_pmem_ptr[m_in_alloc_cnt], port, appData, bytes); + DEBUG_PRINT_HIGH("Heap buffer(%p) Pmem buffer(%p)", *bufferHdr, m_phdr_pmem_ptr[m_in_alloc_cnt]); + if (!m_input_free_q.insert_entry((unsigned long)m_phdr_pmem_ptr[m_in_alloc_cnt], + (unsigned long)NULL, (unsigned long)NULL)) + { + DEBUG_PRINT_ERROR("ERROR:Free_q is full"); + return OMX_ErrorInsufficientResources; + } + m_in_alloc_cnt++; + } + else + { + DEBUG_PRINT_ERROR("All i/p buffers have been set!"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +/* ====================================================================== +FUNCTION +omx_vdec::UseBuffer + +DESCRIPTION +OMX Use Buffer method implementation. + +PARAMETERS +<TBD>. + +RETURN VALUE +OMX Error None , if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::use_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE error = OMX_ErrorNone; + struct vdec_setbuffer_cmd setbuffers; + + if (bufferHdr == NULL || bytes == 0) + { + if(!secure_mode && buffer == NULL) { + DEBUG_PRINT_ERROR("bad param 0x%p %ld 0x%p",bufferHdr, bytes, buffer); + return OMX_ErrorBadParameter; + } + } + if(m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Use Buffer in Invalid State"); + return OMX_ErrorInvalidState; + } + if(port == OMX_CORE_INPUT_PORT_INDEX) + error = use_input_heap_buffers(hComp, bufferHdr, port, appData, bytes, buffer); + else if(port == OMX_CORE_OUTPUT_PORT_INDEX) + error = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer); //not tested + else + { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d",(int)port); + error = OMX_ErrorBadPortIndex; + } + DEBUG_PRINT_LOW("Use Buffer: port %u, buffer %p, eRet %d", (unsigned int)port, *bufferHdr, error); + if(error == OMX_ErrorNone) + { + if(allocate_done()) + { + DEBUG_PRINT_LOW("Use Buffer: allocate_done"); + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_IDLE_PENDING); + post_event(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + } + if (m_pSwVdec) + { + DEBUG_PRINT_LOW("Use Buffer: SwVdec_Start"); + SwVdec_Start(m_pSwVdec); + } + } + if(port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated && + BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + else if(port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated && + BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + return error; +} + +OMX_ERRORTYPE omx_vdec::free_input_buffer(unsigned int bufferindex, + OMX_BUFFERHEADERTYPE *pmem_bufferHdr) +{ + if (m_inp_heap_ptr && !input_use_buffer && arbitrary_bytes) + { + if(m_inp_heap_ptr[bufferindex].pBuffer) + free(m_inp_heap_ptr[bufferindex].pBuffer); + m_inp_heap_ptr[bufferindex].pBuffer = NULL; + } + if (pmem_bufferHdr) + free_input_buffer(pmem_bufferHdr); + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::free_input_buffer(OMX_BUFFERHEADERTYPE *bufferHdr) +{ + unsigned int index = 0; + if (bufferHdr == NULL || m_inp_mem_ptr == NULL) + { + return OMX_ErrorBadParameter; + } + + index = bufferHdr - m_inp_mem_ptr; + DEBUG_PRINT_LOW("Free Input Buffer index = %d",index); + + if (index < drv_ctx.ip_buf.actualcount && drv_ctx.ptr_inputbuffer) + { + DEBUG_PRINT_LOW("Free Input Buffer index = %d",index); + if (drv_ctx.ptr_inputbuffer[index].pmem_fd > 0) + { + struct vdec_setbuffer_cmd setbuffers; + setbuffers.buffer_type = VDEC_BUFFER_TYPE_INPUT; + memcpy (&setbuffers.buffer,&drv_ctx.ptr_inputbuffer[index], + sizeof (vdec_bufferpayload)); + DEBUG_PRINT_LOW("unmap the input buffer fd=%d", + drv_ctx.ptr_inputbuffer[index].pmem_fd); + DEBUG_PRINT_LOW("unmap the input buffer size=%d address = %p", + drv_ctx.ptr_inputbuffer[index].mmaped_size, + drv_ctx.ptr_inputbuffer[index].bufferaddr); + munmap (drv_ctx.ptr_inputbuffer[index].bufferaddr, + drv_ctx.ptr_inputbuffer[index].mmaped_size); + close (drv_ctx.ptr_inputbuffer[index].pmem_fd); + drv_ctx.ptr_inputbuffer[index].pmem_fd = -1; + if (m_desc_buffer_ptr && m_desc_buffer_ptr[index].buf_addr) + { + free(m_desc_buffer_ptr[index].buf_addr); + m_desc_buffer_ptr[index].buf_addr = NULL; + m_desc_buffer_ptr[index].desc_data_size = 0; + } +#ifdef USE_ION + free_ion_memory(&drv_ctx.ip_buf_ion_info[index]); +#endif + } + } + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::free_output_buffer(OMX_BUFFERHEADERTYPE *bufferHdr) +{ + unsigned int index = 0; + + if (bufferHdr == NULL || m_out_mem_ptr == NULL) + { + return OMX_ErrorBadParameter; + } + + index = bufferHdr - m_out_mem_ptr; + DEBUG_PRINT_LOW("Free ouput Buffer index = %d",index); + + if (index < drv_ctx.op_buf.actualcount + && drv_ctx.ptr_outputbuffer) + { + DEBUG_PRINT_LOW("Free ouput Buffer index = %d addr = %p", index, + drv_ctx.ptr_outputbuffer[index].bufferaddr); + + struct vdec_setbuffer_cmd setbuffers; + setbuffers.buffer_type = VDEC_BUFFER_TYPE_OUTPUT; + memcpy (&setbuffers.buffer,&drv_ctx.ptr_outputbuffer[index], + sizeof (vdec_bufferpayload)); +#ifdef _ANDROID_ + if(m_enable_android_native_buffers) { + if(drv_ctx.ptr_outputbuffer[index].pmem_fd > 0) { + munmap(drv_ctx.ptr_outputbuffer[index].bufferaddr, + drv_ctx.ptr_outputbuffer[index].mmaped_size); + } + drv_ctx.ptr_outputbuffer[index].pmem_fd = -1; + } else { +#endif + if (drv_ctx.ptr_outputbuffer[0].pmem_fd > 0 && !ouput_egl_buffers && !m_use_output_pmem) + { + DEBUG_PRINT_LOW("unmap the output buffer fd = %d", + drv_ctx.ptr_outputbuffer[0].pmem_fd); + DEBUG_PRINT_LOW("unmap the ouput buffer size=%d address = %p", + drv_ctx.ptr_outputbuffer[0].mmaped_size * drv_ctx.op_buf.actualcount, + drv_ctx.ptr_outputbuffer[0].bufferaddr); + munmap (drv_ctx.ptr_outputbuffer[0].bufferaddr, + drv_ctx.ptr_outputbuffer[0].mmaped_size * drv_ctx.op_buf.actualcount); + close (drv_ctx.ptr_outputbuffer[0].pmem_fd); + drv_ctx.ptr_outputbuffer[0].pmem_fd = -1; +#ifdef USE_ION + free_ion_memory(&drv_ctx.op_buf_ion_info[0]); +#endif + } +#ifdef _ANDROID_ + } +#endif + if (release_output_done()) { + free_extradata(); + } + } + + return OMX_ErrorNone; + +} + +OMX_ERRORTYPE omx_vdec::allocate_input_heap_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes) +{ + OMX_BUFFERHEADERTYPE *input = NULL; + unsigned char *buf_addr = NULL; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned i = 0; + + /* Sanity Check*/ + if (bufferHdr == NULL) + { + return OMX_ErrorBadParameter; + } + + if (m_inp_heap_ptr == NULL) + { + m_inp_heap_ptr = (OMX_BUFFERHEADERTYPE*) \ + calloc( (sizeof(OMX_BUFFERHEADERTYPE)), + drv_ctx.ip_buf.actualcount); + m_phdr_pmem_ptr = (OMX_BUFFERHEADERTYPE**) \ + calloc( (sizeof(OMX_BUFFERHEADERTYPE*)), + drv_ctx.ip_buf.actualcount); + + if (m_inp_heap_ptr == NULL) + { + DEBUG_PRINT_ERROR("m_inp_heap_ptr Allocation failed "); + return OMX_ErrorInsufficientResources; + } + } + + /*Find a Free index*/ + for(i=0; i< drv_ctx.ip_buf.actualcount; i++) + { + if(BITMASK_ABSENT(&m_heap_inp_bm_count,i)) + { + DEBUG_PRINT_LOW("Free Input Buffer Index %d",i); + break; + } + } + + if (i < drv_ctx.ip_buf.actualcount) + { + buf_addr = (unsigned char *)malloc (drv_ctx.ip_buf.buffer_size); + + if (buf_addr == NULL) + { + return OMX_ErrorInsufficientResources; + } + + *bufferHdr = (m_inp_heap_ptr + i); + input = *bufferHdr; + BITMASK_SET(&m_heap_inp_bm_count,i); + + input->pBuffer = (OMX_U8 *)buf_addr; + input->nSize = sizeof(OMX_BUFFERHEADERTYPE); + input->nVersion.nVersion = OMX_SPEC_VERSION; + input->nAllocLen = drv_ctx.ip_buf.buffer_size; + input->pAppPrivate = appData; + input->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + DEBUG_PRINT_LOW("Address of Heap Buffer %p",*bufferHdr ); + eRet = allocate_input_buffer(hComp,&m_phdr_pmem_ptr [i],port,appData,bytes); + DEBUG_PRINT_LOW("Address of Pmem Buffer %p",m_phdr_pmem_ptr[i]); + /*Add the Buffers to freeq*/ + if (!m_input_free_q.insert_entry((unsigned long)m_phdr_pmem_ptr[i], + (unsigned long)NULL, (unsigned long)NULL)) + { + DEBUG_PRINT_ERROR("ERROR:Free_q is full"); + return OMX_ErrorInsufficientResources; + } + } + else + { + return OMX_ErrorBadParameter; + } + + return eRet; + +} + + +/* ====================================================================== +FUNCTION +omx_vdec::AllocateInputBuffer + +DESCRIPTION +Helper function for allocate buffer in the input pin + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::allocate_input_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct vdec_setbuffer_cmd setbuffers; + OMX_BUFFERHEADERTYPE *input = NULL; + unsigned i = 0; + unsigned char *buf_addr = NULL; + int pmem_fd = -1; + (void) hComp; + (void) port; + + if(bytes != drv_ctx.ip_buf.buffer_size) + { + DEBUG_PRINT_LOW("Requested Size is wrong %d epected is %d", + (int)bytes, drv_ctx.ip_buf.buffer_size); + return OMX_ErrorBadParameter; + } + + if(!m_inp_mem_ptr) + { + DEBUG_PRINT_HIGH("Allocate i/p buffer Header: Cnt(%d) Sz(%d)", + drv_ctx.ip_buf.actualcount, + drv_ctx.ip_buf.buffer_size); + + m_inp_mem_ptr = (OMX_BUFFERHEADERTYPE*) \ + calloc( (sizeof(OMX_BUFFERHEADERTYPE)), drv_ctx.ip_buf.actualcount); + + if (m_inp_mem_ptr == NULL) + { + return OMX_ErrorInsufficientResources; + } + + drv_ctx.ptr_inputbuffer = (struct vdec_bufferpayload *) \ + calloc ((sizeof (struct vdec_bufferpayload)),drv_ctx.ip_buf.actualcount); + + if (drv_ctx.ptr_inputbuffer == NULL) + { + return OMX_ErrorInsufficientResources; + } +#ifdef USE_ION + drv_ctx.ip_buf_ion_info = (struct vdec_ion *) \ + calloc ((sizeof (struct vdec_ion)),drv_ctx.ip_buf.actualcount); + + if (drv_ctx.ip_buf_ion_info == NULL) + { + return OMX_ErrorInsufficientResources; + } +#endif + + for (i=0; i < drv_ctx.ip_buf.actualcount; i++) + { + drv_ctx.ptr_inputbuffer [i].pmem_fd = -1; +#ifdef USE_ION + drv_ctx.ip_buf_ion_info[i].ion_device_fd = -1; +#endif + } + + if (m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) + { + // allocate swvdec input buffers + m_pSwVdecIpBuffer = (SWVDEC_IPBUFFER *)calloc(sizeof(SWVDEC_IPBUFFER), drv_ctx.ip_buf.actualcount); + if (m_pSwVdecIpBuffer == NULL) { + eRet = OMX_ErrorInsufficientResources; + } + } + } + + for(i=0; i< drv_ctx.ip_buf.actualcount; i++) + { + if(BITMASK_ABSENT(&m_inp_bm_count,i)) + { + DEBUG_PRINT_LOW("Free Input Buffer Index %d",i); + break; + } + } + + if(i < drv_ctx.ip_buf.actualcount) + { +#ifdef USE_ION + int heap = 0; +#ifdef _HEVC_USE_ADSP_HEAP_ + heap = ION_ADSP_HEAP_ID; +#else + heap = ION_IOMMU_HEAP_ID; +#endif + DEBUG_PRINT_HIGH("Allocate ion input Buffer size %d", drv_ctx.ip_buf.buffer_size); + drv_ctx.ip_buf_ion_info[i].ion_device_fd = alloc_map_ion_memory( + drv_ctx.ip_buf.buffer_size,drv_ctx.op_buf.alignment, + &drv_ctx.ip_buf_ion_info[i].ion_alloc_data, + &drv_ctx.ip_buf_ion_info[i].fd_ion_data, secure_mode ? ION_SECURE : 0, heap); + if(drv_ctx.ip_buf_ion_info[i].ion_device_fd < 0) { + return OMX_ErrorInsufficientResources; + } + pmem_fd = drv_ctx.ip_buf_ion_info[i].fd_ion_data.fd; +#else + pmem_fd = open (MEM_DEVICE,O_RDWR); + + if (pmem_fd < 0) + { + DEBUG_PRINT_ERROR("open failed for pmem/adsp for input buffer"); + return OMX_ErrorInsufficientResources; + } + + if (pmem_fd == 0) + { + pmem_fd = open (MEM_DEVICE,O_RDWR); + + if (pmem_fd < 0) + { + DEBUG_PRINT_ERROR("open failed for pmem/adsp for input buffer"); + return OMX_ErrorInsufficientResources; + } + } + + if(!align_pmem_buffers(pmem_fd, drv_ctx.ip_buf.buffer_size, + drv_ctx.ip_buf.alignment)) + { + DEBUG_PRINT_ERROR("align_pmem_buffers() failed"); + close(pmem_fd); + return OMX_ErrorInsufficientResources; + } +#endif + if (!secure_mode) { + buf_addr = (unsigned char *)mmap(NULL, + drv_ctx.ip_buf.buffer_size, + PROT_READ|PROT_WRITE, MAP_SHARED, pmem_fd, 0); + + if (buf_addr == MAP_FAILED) + { + close(pmem_fd); +#ifdef USE_ION + free_ion_memory(&drv_ctx.ip_buf_ion_info[i]); +#endif + DEBUG_PRINT_ERROR("Map Failed to allocate input buffer"); + return OMX_ErrorInsufficientResources; + } + } + *bufferHdr = (m_inp_mem_ptr + i); + if (secure_mode) + drv_ctx.ptr_inputbuffer [i].bufferaddr = *bufferHdr; + else + drv_ctx.ptr_inputbuffer [i].bufferaddr = buf_addr; + drv_ctx.ptr_inputbuffer [i].pmem_fd = pmem_fd; + drv_ctx.ptr_inputbuffer [i].buffer_len = drv_ctx.ip_buf.buffer_size; + drv_ctx.ptr_inputbuffer [i].mmaped_size = drv_ctx.ip_buf.buffer_size; + drv_ctx.ptr_inputbuffer [i].offset = 0; + + if (!m_pSwVdec || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + struct v4l2_buffer buf; + struct v4l2_plane plane; + int rc; + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane.bytesused = 0; + plane.length = drv_ctx.ptr_inputbuffer [i].mmaped_size; + plane.m.userptr = (unsigned long)drv_ctx.ptr_inputbuffer[i].bufferaddr; + plane.reserved[0] =drv_ctx.ptr_inputbuffer [i].pmem_fd; + plane.reserved[1] = 0; + plane.data_offset = drv_ctx.ptr_inputbuffer[i].offset; + buf.m.planes = &plane; + buf.length = 1; + + DEBUG_PRINT_LOW("Set the input Buffer Idx: %d Addr: %p", i, drv_ctx.ptr_inputbuffer[i].bufferaddr); + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_PREPARE_BUF, &buf); + if (rc) { + DEBUG_PRINT_ERROR("Failed to prepare bufs"); + /*TODO: How to handle this case */ + return OMX_ErrorInsufficientResources; + } + } + else if (m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) + { + m_pSwVdecIpBuffer[i].pBuffer = buf_addr; + m_pSwVdecIpBuffer[i].pClientBufferData = (void*)(unsigned long)i; + } + + input = *bufferHdr; + BITMASK_SET(&m_inp_bm_count,i); + DEBUG_PRINT_LOW("Buffer address %p of pmem idx %d",*bufferHdr, i); + if (secure_mode) + input->pBuffer = (OMX_U8 *)(unsigned long)drv_ctx.ptr_inputbuffer [i].pmem_fd; + else + input->pBuffer = (OMX_U8 *)buf_addr; + input->nSize = sizeof(OMX_BUFFERHEADERTYPE); + input->nVersion.nVersion = OMX_SPEC_VERSION; + input->nAllocLen = drv_ctx.ip_buf.buffer_size; + input->pAppPrivate = appData; + input->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + input->pInputPortPrivate = (void *)&drv_ctx.ptr_inputbuffer [i]; + + if (drv_ctx.disable_dmx) + { + eRet = allocate_desc_buffer(i); + } + } + else + { + DEBUG_PRINT_ERROR("ERROR:Input Buffer Index not found"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + + +/* ====================================================================== +FUNCTION +omx_vdec::AllocateOutputBuffer + +DESCRIPTION +Helper fn for AllocateBuffer in the output pin + +PARAMETERS +<TBD>. + +RETURN VALUE +OMX Error None if everything went well. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::allocate_output_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + (void)hComp; + (void)port; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr= NULL; // buffer header + unsigned i= 0; // Temporary counter + struct vdec_setbuffer_cmd setbuffers; + int extra_idx = 0; +#ifdef USE_ION + int ion_device_fd =-1; + struct ion_allocation_data ion_alloc_data; + struct ion_fd_data fd_ion_data; +#endif + if(!m_out_mem_ptr) + { + DEBUG_PRINT_HIGH("Allocate o/p buffer Header: Cnt(%d) Sz(%d)", + drv_ctx.op_buf.actualcount, + drv_ctx.op_buf.buffer_size); + int nBufHdrSize = 0; + int nPlatformEntrySize = 0; + int nPlatformListSize = 0; + int nPMEMInfoSize = 0; + int pmem_fd = -1; + unsigned char *pmem_baseaddress = NULL; + + OMX_QCOM_PLATFORM_PRIVATE_LIST *pPlatformList; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY *pPlatformEntry; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo; + + DEBUG_PRINT_LOW("Allocating First Output Buffer(%d)", + drv_ctx.op_buf.actualcount); + nBufHdrSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_BUFFERHEADERTYPE); + + nPMEMInfoSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO); + nPlatformListSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_LIST); + nPlatformEntrySize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_ENTRY); + + DEBUG_PRINT_LOW("TotalBufHdr %d BufHdrSize %d PMEM %d PL %d",nBufHdrSize, + sizeof(OMX_BUFFERHEADERTYPE), + nPMEMInfoSize, + nPlatformListSize); + DEBUG_PRINT_LOW("PE %d OutputBuffer Count %d",nPlatformEntrySize, + drv_ctx.op_buf.actualcount); +#ifdef USE_ION + DEBUG_PRINT_HIGH("allocate outputBuffer size %d",drv_ctx.op_buf.buffer_size * drv_ctx.op_buf.actualcount); + int heap_id = 0; + int flags = secure_mode ? ION_SECURE : 0; + if (!m_pSwVdec) { +#ifdef _HEVC_USE_ADSP_HEAP_ + heap_id = ION_ADSP_HEAP_ID; +#else + heap_id = ION_IOMMU_HEAP_ID; +#endif + } + ion_device_fd = alloc_map_ion_memory( + drv_ctx.op_buf.buffer_size * drv_ctx.op_buf.actualcount, + drv_ctx.op_buf.alignment, + &ion_alloc_data, &fd_ion_data,flags, heap_id); + if (ion_device_fd < 0) { + return OMX_ErrorInsufficientResources; + } + pmem_fd = fd_ion_data.fd; +#else + pmem_fd = open (MEM_DEVICE,O_RDWR); + + if (pmem_fd < 0) + { + DEBUG_PRINT_ERROR("ERROR:pmem fd for output buffer %d", + drv_ctx.op_buf.buffer_size); + return OMX_ErrorInsufficientResources; + } + + if(pmem_fd == 0) + { + pmem_fd = open (MEM_DEVICE,O_RDWR); + + if (pmem_fd < 0) + { + DEBUG_PRINT_ERROR("ERROR:pmem fd for output buffer %d", + drv_ctx.op_buf.buffer_size); + return OMX_ErrorInsufficientResources; + } + } + + if(!align_pmem_buffers(pmem_fd, drv_ctx.op_buf.buffer_size * + drv_ctx.op_buf.actualcount, + drv_ctx.op_buf.alignment)) + { + DEBUG_PRINT_ERROR("align_pmem_buffers() failed"); + close(pmem_fd); + return OMX_ErrorInsufficientResources; + } +#endif + if (!secure_mode) { + pmem_baseaddress = (unsigned char *)mmap(NULL, + (drv_ctx.op_buf.buffer_size * + drv_ctx.op_buf.actualcount), + PROT_READ|PROT_WRITE,MAP_SHARED,pmem_fd,0); + if (pmem_baseaddress == MAP_FAILED) + { + DEBUG_PRINT_ERROR("MMAP failed for Size %d", + drv_ctx.op_buf.buffer_size); + close(pmem_fd); +#ifdef USE_ION + free_ion_memory(&drv_ctx.op_buf_ion_info[i]); +#endif + return OMX_ErrorInsufficientResources; + } + } + m_out_mem_ptr = (OMX_BUFFERHEADERTYPE *)calloc(nBufHdrSize,1); + // Alloc mem for platform specific info + char *pPtr=NULL; + pPtr = (char*) calloc(nPlatformListSize + nPlatformEntrySize + + nPMEMInfoSize,1); + drv_ctx.ptr_outputbuffer = (struct vdec_bufferpayload *)\ + calloc (sizeof(struct vdec_bufferpayload), + drv_ctx.op_buf.actualcount); + drv_ctx.ptr_respbuffer = (struct vdec_output_frameinfo *)\ + calloc (sizeof (struct vdec_output_frameinfo), + drv_ctx.op_buf.actualcount); +#ifdef USE_ION + drv_ctx.op_buf_ion_info = (struct vdec_ion *)\ + calloc (sizeof(struct vdec_ion), + drv_ctx.op_buf.actualcount); +#endif + + if (m_pSwVdec && m_pSwVdecOpBuffer == NULL) + { + m_pSwVdecOpBuffer = (SWVDEC_OPBUFFER*)calloc(sizeof(SWVDEC_OPBUFFER), drv_ctx.op_buf.actualcount); + } + if(m_out_mem_ptr && pPtr && drv_ctx.ptr_outputbuffer && drv_ctx.ptr_respbuffer + && ((m_pSwVdec && m_pSwVdecOpBuffer) || (!m_pSwVdec)) ) + { + drv_ctx.ptr_outputbuffer[0].mmaped_size = + (drv_ctx.op_buf.buffer_size * + drv_ctx.op_buf.actualcount); + bufHdr = m_out_mem_ptr; + m_platform_list = (OMX_QCOM_PLATFORM_PRIVATE_LIST *)(pPtr); + m_platform_entry= (OMX_QCOM_PLATFORM_PRIVATE_ENTRY *) + (((char *) m_platform_list) + nPlatformListSize); + m_pmem_info = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) + (((char *) m_platform_entry) + nPlatformEntrySize); + pPlatformList = m_platform_list; + pPlatformEntry = m_platform_entry; + pPMEMInfo = m_pmem_info; + + DEBUG_PRINT_LOW("Memory Allocation Succeeded for OUT port%p",m_out_mem_ptr); + + // Settting the entire storage nicely + DEBUG_PRINT_LOW("bHdr %p OutMem %p PE %p",bufHdr, m_out_mem_ptr,pPlatformEntry); + DEBUG_PRINT_LOW(" Pmem Info = %p",pPMEMInfo); + for(i=0; i < drv_ctx.op_buf.actualcount ; i++) + { + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + // Set the values when we determine the right HxW param + bufHdr->nAllocLen = bytes; + bufHdr->nFilledLen = 0; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + // Platform specific PMEM Information + // Initialize the Platform Entry + //DEBUG_PRINT_LOW("Initializing the Platform Entry for %d",i); + pPlatformEntry->type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; + pPlatformEntry->entry = pPMEMInfo; + // Initialize the Platform List + pPlatformList->nEntries = 1; + pPlatformList->entryList = pPlatformEntry; + // Keep pBuffer NULL till vdec is opened + bufHdr->pBuffer = NULL; + bufHdr->nOffset = 0; + + pPMEMInfo->offset = drv_ctx.op_buf.buffer_size*i; + pPMEMInfo->pmem_fd = 0; + bufHdr->pPlatformPrivate = pPlatformList; + + drv_ctx.ptr_outputbuffer[i].pmem_fd = pmem_fd; + m_pmem_info[i].pmem_fd = pmem_fd; +#ifdef USE_ION + drv_ctx.op_buf_ion_info[i].ion_device_fd = ion_device_fd; + drv_ctx.op_buf_ion_info[i].ion_alloc_data = ion_alloc_data; + drv_ctx.op_buf_ion_info[i].fd_ion_data = fd_ion_data; +#endif + + /*Create a mapping between buffers*/ + bufHdr->pOutputPortPrivate = &drv_ctx.ptr_respbuffer[i]; + drv_ctx.ptr_respbuffer[i].client_data = (void *)\ + &drv_ctx.ptr_outputbuffer[i]; + drv_ctx.ptr_outputbuffer[i].offset = drv_ctx.op_buf.buffer_size*i; + drv_ctx.ptr_outputbuffer[i].bufferaddr = + pmem_baseaddress + (drv_ctx.op_buf.buffer_size*i); + + DEBUG_PRINT_LOW("pmem_fd = %d offset = %d address = %p", + pmem_fd, drv_ctx.ptr_outputbuffer[i].offset, + drv_ctx.ptr_outputbuffer[i].bufferaddr); + // Move the buffer and buffer header pointers + bufHdr++; + pPMEMInfo++; + pPlatformEntry++; + pPlatformList++; + } + } + else + { + DEBUG_PRINT_ERROR("Output buf mem alloc failed[0x%p][0x%p]",\ + m_out_mem_ptr, pPtr); + if(m_out_mem_ptr) + { + free(m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + if(pPtr) + { + free(pPtr); + pPtr = NULL; + } + if(drv_ctx.ptr_outputbuffer) + { + free(drv_ctx.ptr_outputbuffer); + drv_ctx.ptr_outputbuffer = NULL; + } + if(drv_ctx.ptr_respbuffer) + { + free(drv_ctx.ptr_respbuffer); + drv_ctx.ptr_respbuffer = NULL; + } +#ifdef USE_ION + if (drv_ctx.op_buf_ion_info) { + DEBUG_PRINT_LOW("Free o/p ion context"); + free(drv_ctx.op_buf_ion_info); + drv_ctx.op_buf_ion_info = NULL; + } +#endif + eRet = OMX_ErrorInsufficientResources; + } + if ( (!m_pSwVdec) && (eRet == OMX_ErrorNone) ) + eRet = allocate_extradata(); + } + + for(i=0; i< drv_ctx.op_buf.actualcount; i++) + { + if(BITMASK_ABSENT(&m_out_bm_count,i)) + { + DEBUG_PRINT_LOW("Found a Free Output Buffer %d",i); + break; + } + } + + if (eRet == OMX_ErrorNone) + { + if(i < drv_ctx.op_buf.actualcount) + { + int rc; + m_pmem_info[i].offset = drv_ctx.ptr_outputbuffer[i].offset; + drv_ctx.ptr_outputbuffer[i].buffer_len = drv_ctx.op_buf.buffer_size; + + *bufferHdr = (m_out_mem_ptr + i ); + if (secure_mode) { + drv_ctx.ptr_outputbuffer[i].bufferaddr = *bufferHdr; + } + drv_ctx.ptr_outputbuffer[i].mmaped_size = drv_ctx.op_buf.buffer_size; + + if (m_pSwVdec) + { + (*bufferHdr)->pBuffer = (OMX_U8*)drv_ctx.ptr_outputbuffer[i].bufferaddr; + (*bufferHdr)->pAppPrivate = appData; + m_pSwVdecOpBuffer[i].nSize = drv_ctx.ptr_outputbuffer[i].mmaped_size; + m_pSwVdecOpBuffer[i].pBuffer = (*bufferHdr)->pBuffer; + m_pSwVdecOpBuffer[i].pClientBufferData = (void*)(unsigned long)i; + SwVdec_SetOutputBuffer(m_pSwVdec, &m_pSwVdecOpBuffer[i]); + } + else + { + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].length = drv_ctx.op_buf.buffer_size; + plane[0].m.userptr = (unsigned long)drv_ctx.ptr_outputbuffer[i].bufferaddr - + (unsigned long)drv_ctx.ptr_outputbuffer[i].offset; +#ifdef USE_ION + plane[0].reserved[0] = drv_ctx.op_buf_ion_info[i].fd_ion_data.fd; +#endif + plane[0].reserved[1] = drv_ctx.ptr_outputbuffer[i].offset; + plane[0].data_offset = 0; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].length = drv_ctx.extradata_info.buffer_size; + plane[extra_idx].m.userptr = (long unsigned int) (drv_ctx.extradata_info.uaddr + i * drv_ctx.extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = drv_ctx.extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = i * drv_ctx.extradata_info.buffer_size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index higher than allowed: %d", extra_idx); + return OMX_ErrorBadParameter; + } + buf.m.planes = plane; + buf.length = drv_ctx.num_planes; + DEBUG_PRINT_LOW("Set the Output Buffer Idx: %d Addr: %p", i, drv_ctx.ptr_outputbuffer[i].bufferaddr); + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_PREPARE_BUF, &buf); + if (rc) { + /*TODO: How to handle this case */ + return OMX_ErrorInsufficientResources; + } + + if (i == (drv_ctx.op_buf.actualcount -1 ) && !streaming[CAPTURE_PORT]) { + enum v4l2_buf_type buf_type; + buf_type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + rc=ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type); + if (rc) { + return OMX_ErrorInsufficientResources; + } else { + streaming[CAPTURE_PORT] = true; + DEBUG_PRINT_LOW("STREAMON Successful"); + } + } + } + (*bufferHdr)->pBuffer = (OMX_U8*)drv_ctx.ptr_outputbuffer[i].bufferaddr; + (*bufferHdr)->pAppPrivate = appData; + BITMASK_SET(&m_out_bm_count,i); + } + else + { + DEBUG_PRINT_ERROR("All the Output Buffers have been Allocated ; Returning Insufficient"); + eRet = OMX_ErrorInsufficientResources; + } + } + + return eRet; +} + + +// AllocateBuffer -- API Call +/* ====================================================================== +FUNCTION +omx_vdec::AllocateBuffer + +DESCRIPTION +Returns zero if all the buffers released.. + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::allocate_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + unsigned i = 0; + OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type + + DEBUG_PRINT_LOW("Allocate buffer on port %d", (int)port); + if(m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Allocate Buf in Invalid State"); + return OMX_ErrorInvalidState; + } + + if(port == OMX_CORE_INPUT_PORT_INDEX) + { + if (arbitrary_bytes) + { + eRet = allocate_input_heap_buffer (hComp,bufferHdr,port,appData,bytes); + } + else + { + eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes); + } + } + else if(port == OMX_CORE_OUTPUT_PORT_INDEX) + { + eRet = client_buffers.allocate_buffers_color_convert(hComp,bufferHdr,port, + appData,bytes); + } + else + { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d",(int)port); + eRet = OMX_ErrorBadPortIndex; + } + DEBUG_PRINT_LOW("Checking for Output Allocate buffer Done"); + if(eRet == OMX_ErrorNone) + { + if(allocate_done()) + { + if(BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_IDLE_PENDING); + post_event(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + } + if (m_pSwVdec) + { + DEBUG_PRINT_LOW("allocate_buffer: SwVdec_Start"); + SwVdec_Start(m_pSwVdec); + } + } + if(port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated) + { + if(BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if(port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated) + { + if(BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) + { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + } + DEBUG_PRINT_LOW("Allocate Buffer exit with ret Code %d",eRet); + return eRet; +} + +// Free Buffer - API call +/* ====================================================================== +FUNCTION +omx_vdec::FreeBuffer + +DESCRIPTION + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::free_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned int nPortIndex; + (void) hComp; + + if(m_state == OMX_StateIdle && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) + { + DEBUG_PRINT_LOW(" free buffer while Component in Loading pending"); + } + else if((m_inp_bEnabled == OMX_FALSE && port == OMX_CORE_INPUT_PORT_INDEX)|| + (m_out_bEnabled == OMX_FALSE && port == OMX_CORE_OUTPUT_PORT_INDEX)) + { + DEBUG_PRINT_LOW("Free Buffer while port %d disabled", (int)port); + } + else if ((port == OMX_CORE_INPUT_PORT_INDEX && + BITMASK_PRESENT(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING)) || + (port == OMX_CORE_OUTPUT_PORT_INDEX && + BITMASK_PRESENT(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING))) + { + DEBUG_PRINT_LOW("Free Buffer while port %d enable pending", (int)port); + } + else if(m_state == OMX_StateExecuting || m_state == OMX_StatePause) + { + DEBUG_PRINT_ERROR("Invalid state to free buffer,ports need to be disabled"); + post_event(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + + return OMX_ErrorIncorrectStateOperation; + } + else if (m_state != OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Invalid state %d to free buffer,port %d lost Buffers", m_state, (int)port); + post_event(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + } + + if(port == OMX_CORE_INPUT_PORT_INDEX) + { + /*Check if arbitrary bytes*/ + if(!arbitrary_bytes && !input_use_buffer) + nPortIndex = buffer - m_inp_mem_ptr; + else + nPortIndex = buffer - m_inp_heap_ptr; + + DEBUG_PRINT_LOW("free_buffer on i/p port - Port idx %d", nPortIndex); + if(nPortIndex < drv_ctx.ip_buf.actualcount) + { + // Clear the bit associated with it. + BITMASK_CLEAR(&m_inp_bm_count,nPortIndex); + BITMASK_CLEAR(&m_heap_inp_bm_count,nPortIndex); + if (input_use_buffer == true) + { + + DEBUG_PRINT_LOW("Free pmem Buffer index %d",nPortIndex); + if(m_phdr_pmem_ptr) + free_input_buffer(m_phdr_pmem_ptr[nPortIndex]); + } + else + { + if (arbitrary_bytes) + { + if(m_phdr_pmem_ptr) + free_input_buffer(nPortIndex,m_phdr_pmem_ptr[nPortIndex]); + else + free_input_buffer(nPortIndex,NULL); + } + else + free_input_buffer(buffer); + } + m_inp_bPopulated = OMX_FALSE; + /*Free the Buffer Header*/ + if (release_input_done()) + { + DEBUG_PRINT_HIGH("ALL input buffers are freed/released"); + free_input_buffer_header(); + } + } + else + { + DEBUG_PRINT_ERROR("Error: free_buffer ,Port Index Invalid"); + eRet = OMX_ErrorBadPortIndex; + } + + if(BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING) + && release_input_done()) + { + DEBUG_PRINT_LOW("MOVING TO INPUT DISABLED STATE"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING); + post_event(OMX_CommandPortDisable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + else if(port == OMX_CORE_OUTPUT_PORT_INDEX) + { + // check if the buffer is valid + nPortIndex = buffer - client_buffers.get_il_buf_hdr(); + if(nPortIndex < drv_ctx.op_buf.actualcount) + { + DEBUG_PRINT_LOW("free_buffer on o/p port - Port idx %d", nPortIndex); + // Clear the bit associated with it. + BITMASK_CLEAR(&m_out_bm_count,nPortIndex); + m_out_bPopulated = OMX_FALSE; + client_buffers.free_output_buffer (buffer); + + if (release_output_done()) + { + free_output_buffer_header(); + if (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + DEBUG_PRINT_LOW("release_output_done: start free_interm_buffers"); + free_interm_buffers(); + } + else if (m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) + { + DEBUG_PRINT_LOW("free m_pSwVdecOpBuffer"); + if (m_pSwVdecOpBuffer) + { + free(m_pSwVdecOpBuffer); + m_pSwVdecOpBuffer = NULL; + } + } + } + } + else + { + DEBUG_PRINT_ERROR("Error: free_buffer , Port Index Invalid"); + eRet = OMX_ErrorBadPortIndex; + } + if(BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING) + && release_output_done()) + { + DEBUG_PRINT_LOW("MOVING TO OUTPUT DISABLED STATE"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING); +#ifdef _ANDROID_ICS_ + if (m_enable_android_native_buffers) + { + DEBUG_PRINT_LOW("FreeBuffer - outport disabled: reset native buffers"); + memset(&native_buffer, 0 ,(sizeof(struct nativebuffer) * MAX_NUM_INPUT_OUTPUT_BUFFERS)); + } +#endif + + post_event(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + else + { + eRet = OMX_ErrorBadPortIndex; + } + if((eRet == OMX_ErrorNone) && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) + { + if(release_done()) + { + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING); + if (m_pSwVdec) + { + SwVdec_Stop(m_pSwVdec); + } + post_event(OMX_CommandStateSet, OMX_StateLoaded, + OMX_COMPONENT_GENERATE_EVENT); + } + } + return eRet; +} + + +/* ====================================================================== +FUNCTION +omx_vdec::EmptyThisBuffer + +DESCRIPTION +This routine is used to push the encoded video frames to +the video decoder. + +PARAMETERS +None. + +RETURN VALUE +OMX Error None if everything went successful. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::empty_this_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE ret1 = OMX_ErrorNone; + unsigned int nBufferIndex = drv_ctx.ip_buf.actualcount; + + if(m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("Empty this buffer in Invalid State"); + return OMX_ErrorInvalidState; + } + + if (buffer == NULL) + { + DEBUG_PRINT_ERROR("ERROR:ETB Buffer is NULL"); + return OMX_ErrorBadParameter; + } + + if (!m_inp_bEnabled) + { + DEBUG_PRINT_ERROR("ERROR:ETB incorrect state operation, input port is disabled."); + return OMX_ErrorIncorrectStateOperation; + } + + if (buffer->nInputPortIndex != OMX_CORE_INPUT_PORT_INDEX) + { + DEBUG_PRINT_ERROR("ERROR:ETB invalid port in header %lu", buffer->nInputPortIndex); + return OMX_ErrorBadPortIndex; + } + + if (buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) + { + codec_config_flag = true; + DEBUG_PRINT_LOW("%s: codec_config buffer", __FUNCTION__); + } + + if (perf_flag) + { + if (!latency) + { + dec_time.stop(); + latency = dec_time.processing_time_us(); + dec_time.start(); + } + } + + if (arbitrary_bytes) + { + nBufferIndex = buffer - m_inp_heap_ptr; + } + else + { + if (input_use_buffer == true) + { + nBufferIndex = buffer - m_inp_heap_ptr; + m_inp_mem_ptr[nBufferIndex].nFilledLen = m_inp_heap_ptr[nBufferIndex].nFilledLen; + m_inp_mem_ptr[nBufferIndex].nTimeStamp = m_inp_heap_ptr[nBufferIndex].nTimeStamp; + m_inp_mem_ptr[nBufferIndex].nFlags = m_inp_heap_ptr[nBufferIndex].nFlags; + buffer = &m_inp_mem_ptr[nBufferIndex]; + DEBUG_PRINT_LOW("Non-Arbitrary mode - buffer address is: malloc %p, pmem%p in Index %d, buffer %p of size %lu", + &m_inp_heap_ptr[nBufferIndex], &m_inp_mem_ptr[nBufferIndex],nBufferIndex, buffer, buffer->nFilledLen); + } + else{ + nBufferIndex = buffer - m_inp_mem_ptr; + } + } + + if (nBufferIndex > drv_ctx.ip_buf.actualcount ) + { + DEBUG_PRINT_ERROR("ERROR:ETB nBufferIndex is invalid"); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("[ETB] BHdr(%p) pBuf(%p) nTS(%lld) nFL(%lu) nFlags(%lu)", + buffer, buffer->pBuffer, buffer->nTimeStamp, buffer->nFilledLen, buffer->nFlags); + if (arbitrary_bytes) + { + post_event ((unsigned long)hComp,(unsigned long)buffer, + (unsigned long)OMX_COMPONENT_GENERATE_ETB_ARBITRARY); + } + else + { + if (!(client_extradata & OMX_TIMEINFO_EXTRADATA)) + set_frame_rate(buffer->nTimeStamp); + post_event ((unsigned long)hComp,(unsigned long)buffer, + (unsigned long)OMX_COMPONENT_GENERATE_ETB); + } + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION +omx_vdec::empty_this_buffer_proxy + +DESCRIPTION +This routine is used to push the encoded video frames to +the video decoder. + +PARAMETERS +None. + +RETURN VALUE +OMX Error None if everything went successful. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::empty_this_buffer_proxy(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + int push_cnt = 0,i=0; + unsigned nPortIndex = 0; + OMX_ERRORTYPE ret = OMX_ErrorNone; + struct vdec_input_frameinfo frameinfo; + struct vdec_bufferpayload *temp_buffer; + struct vdec_seqheader seq_header; + bool port_setting_changed = true; + bool not_coded_vop = false; + + /*Should we generate a Aync error event*/ + if (buffer == NULL || buffer->pInputPortPrivate == NULL) + { + DEBUG_PRINT_ERROR("ERROR:empty_this_buffer_proxy is invalid"); + return OMX_ErrorBadParameter; + } + + nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)m_inp_mem_ptr); + + if (nPortIndex > drv_ctx.ip_buf.actualcount) + { + DEBUG_PRINT_ERROR("ERROR:empty_this_buffer_proxy invalid nPortIndex[%u]", + nPortIndex); + return OMX_ErrorBadParameter; + } + + if (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY && m_fill_internal_bufers) + { + fill_all_buffers_proxy_dsp(hComp); + } + + pending_input_buffers++; + + /* return zero length and not an EOS buffer */ + if (!arbitrary_bytes && (buffer->nFilledLen == 0) && + ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == 0)) + { + DEBUG_PRINT_HIGH("return zero legth buffer"); + post_event ((unsigned long)buffer,(unsigned long)VDEC_S_SUCCESS, + (unsigned long)OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorNone; + } + + if(input_flush_progress == true + + || not_coded_vop + + ) + { + DEBUG_PRINT_LOW("Flush in progress return buffer "); + post_event ((unsigned long)buffer, (unsigned long)VDEC_S_SUCCESS, + (unsigned long)OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorNone; + } + + temp_buffer = (struct vdec_bufferpayload *)buffer->pInputPortPrivate; + + if ((temp_buffer - drv_ctx.ptr_inputbuffer) > (int)drv_ctx.ip_buf.actualcount) + { + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("ETBProxy: bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer); + /*for use buffer we need to memcpy the data*/ + temp_buffer->buffer_len = buffer->nFilledLen; + + if (input_use_buffer) + { + if (buffer->nFilledLen <= temp_buffer->buffer_len) + { + if(arbitrary_bytes) + { + memcpy (temp_buffer->bufferaddr, (buffer->pBuffer + buffer->nOffset),buffer->nFilledLen); + } + else + { + memcpy (temp_buffer->bufferaddr, (m_inp_heap_ptr[nPortIndex].pBuffer + m_inp_heap_ptr[nPortIndex].nOffset), + buffer->nFilledLen); + } + } + else + { + return OMX_ErrorBadParameter; + } + + } + + frameinfo.bufferaddr = temp_buffer->bufferaddr; + frameinfo.client_data = (void *) buffer; + frameinfo.datalen = temp_buffer->buffer_len; + frameinfo.flags = 0; + frameinfo.offset = buffer->nOffset; + frameinfo.pmem_fd = temp_buffer->pmem_fd; + frameinfo.pmem_offset = temp_buffer->offset; + frameinfo.timestamp = buffer->nTimeStamp; + if (drv_ctx.disable_dmx && m_desc_buffer_ptr && m_desc_buffer_ptr[nPortIndex].buf_addr) + { + DEBUG_PRINT_LOW("ETB: dmx enabled"); + if (m_demux_entries == 0) + { + extract_demux_addr_offsets(buffer); + } + + DEBUG_PRINT_LOW("ETB: handle_demux_data - entries=%d", (int)m_demux_entries); + handle_demux_data(buffer); + frameinfo.desc_addr = (OMX_U8 *)m_desc_buffer_ptr[nPortIndex].buf_addr; + frameinfo.desc_size = m_desc_buffer_ptr[nPortIndex].desc_data_size; + } + else + { + frameinfo.desc_addr = NULL; + frameinfo.desc_size = 0; + } + if(!arbitrary_bytes) + { + frameinfo.flags |= buffer->nFlags; + } + +#ifdef _ANDROID_ + if (m_debug_timestamp) + { + if(arbitrary_bytes) + { + DEBUG_PRINT_LOW("Inserting TIMESTAMP (%lld) into queue", buffer->nTimeStamp); + m_timestamp_list.insert_ts(buffer->nTimeStamp); + } + else if(!arbitrary_bytes && !(buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) + { + DEBUG_PRINT_LOW("Inserting TIMESTAMP (%lld) into queue", buffer->nTimeStamp); + m_timestamp_list.insert_ts(buffer->nTimeStamp); + } + } +#endif + + if (m_debug.in_buffer_log) + { + log_input_buffers((const char *)temp_buffer->bufferaddr, temp_buffer->buffer_len); + } + + if(buffer->nFlags & QOMX_VIDEO_BUFFERFLAG_EOSEQ) + { + frameinfo.flags |= QOMX_VIDEO_BUFFERFLAG_EOSEQ; + buffer->nFlags &= ~QOMX_VIDEO_BUFFERFLAG_EOSEQ; + } + + if (temp_buffer->buffer_len == 0 || (buffer->nFlags & OMX_BUFFERFLAG_EOS)) + { + DEBUG_PRINT_HIGH("Rxd i/p EOS, Notify Driver that EOS has been reached"); + frameinfo.flags |= VDEC_BUFFERFLAG_EOS; + h264_scratch.nFilledLen = 0; + nal_count = 0; + look_ahead_nal = false; + frame_count = 0; + if (m_frame_parser.mutils) + m_frame_parser.mutils->initialize_frame_checking_environment(); + m_frame_parser.flush(); + h264_last_au_ts = LLONG_MAX; + h264_last_au_flags = 0; + memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) ); + m_demux_entries = 0; + } + + if ( (!m_pSwVdec) || (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) ) + { + struct v4l2_buffer buf; + struct v4l2_plane plane; + memset( (void *)&buf, 0, sizeof(buf)); + memset( (void *)&plane, 0, sizeof(plane)); + int rc; + unsigned long print_count; + if (temp_buffer->buffer_len == 0 || (buffer->nFlags & OMX_BUFFERFLAG_EOS)) + { + buf.flags = V4L2_QCOM_BUF_FLAG_EOS; + DEBUG_PRINT_HIGH("INPUT EOS reached") ; + } + OMX_ERRORTYPE eRet = OMX_ErrorNone; + buf.index = nPortIndex; + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane.bytesused = temp_buffer->buffer_len; + plane.length = drv_ctx.ip_buf.buffer_size; + plane.m.userptr = (unsigned long)temp_buffer->bufferaddr - + (unsigned long)temp_buffer->offset; + plane.reserved[0] = temp_buffer->pmem_fd; + plane.reserved[1] = temp_buffer->offset; + plane.data_offset = 0; + buf.m.planes = &plane; + buf.length = 1; + if (frameinfo.timestamp >= LLONG_MAX) { + buf.flags |= V4L2_QCOM_BUF_TIMESTAMP_INVALID; + } + //assumption is that timestamp is in milliseconds + buf.timestamp.tv_sec = frameinfo.timestamp / 1000000; + buf.timestamp.tv_usec = (frameinfo.timestamp % 1000000); + buf.flags |= (buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) ? V4L2_QCOM_BUF_FLAG_CODECCONFIG: 0; + + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_QBUF, &buf); + if(rc) + { + DEBUG_PRINT_ERROR("Failed to qbuf Input buffer to driver"); + return OMX_ErrorHardware; + } + codec_config_flag = false; + DEBUG_PRINT_LOW("%s: codec_config cleared", __FUNCTION__); + if(!streaming[OUTPUT_PORT]) + { + enum v4l2_buf_type buf_type; + int ret,r; + + buf_type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing"); + ret=ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type); + if(!ret) { + DEBUG_PRINT_HIGH("Streamon on OUTPUT Plane was successful"); + streaming[OUTPUT_PORT] = true; + } else { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to call streamon on OUTPUT"); + DEBUG_PRINT_LOW("If Stream on failed no buffer should be queued"); + post_event ((unsigned long)buffer,(unsigned long)VDEC_S_SUCCESS, + (unsigned long)OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorBadParameter; + } + } + } + else if (m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) + { + // send this to the swvdec + DEBUG_PRINT_HIGH("empty_this_buffer_proxy bufHdr %p pBuffer %p nFilledLen %lu m_pSwVdecIpBuffer %p, idx %d", + buffer, buffer->pBuffer, buffer->nFilledLen, m_pSwVdecIpBuffer, nPortIndex); + m_pSwVdecIpBuffer[nPortIndex].nFlags = buffer->nFlags; + m_pSwVdecIpBuffer[nPortIndex].nFilledLen = buffer->nFilledLen; + m_pSwVdecIpBuffer[nPortIndex].nIpTimestamp = buffer->nTimeStamp; + + if (SwVdec_EmptyThisBuffer(m_pSwVdec, &m_pSwVdecIpBuffer[nPortIndex]) != SWVDEC_S_SUCCESS) { + ret = OMX_ErrorBadParameter; + } + codec_config_flag = false; + DEBUG_PRINT_LOW("%s: codec_config cleared", __FUNCTION__); + } + + DEBUG_PRINT_LOW("[ETBP] pBuf(%p) nTS(%lld) Sz(%d)", + frameinfo.bufferaddr, frameinfo.timestamp, frameinfo.datalen); + time_stamp_dts.insert_timestamp(buffer); + return ret; +} + +/* ====================================================================== +FUNCTION +omx_vdec::FillThisBuffer + +DESCRIPTION +IL client uses this method to release the frame buffer +after displaying them. + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::fill_this_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + unsigned int nPortIndex = (unsigned int)(buffer - client_buffers.get_il_buf_hdr()); + if(m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("FTB in Invalid State"); + return OMX_ErrorInvalidState; + } + + if (!m_out_bEnabled) + { + DEBUG_PRINT_ERROR("ERROR:FTB incorrect state operation, output port is disabled."); + return OMX_ErrorIncorrectStateOperation; + } + + if (!buffer || !buffer->pBuffer || nPortIndex >= drv_ctx.op_buf.actualcount) + { + DEBUG_PRINT_ERROR("ERROR:FTB invalid bufHdr %p, nPortIndex %u", buffer, nPortIndex); + return OMX_ErrorBadParameter; + } + + if (buffer->nOutputPortIndex != OMX_CORE_OUTPUT_PORT_INDEX) + { + DEBUG_PRINT_ERROR("ERROR:FTB invalid port in header %lu", buffer->nOutputPortIndex); + return OMX_ErrorBadPortIndex; + } + + if (dynamic_buf_mode) { + private_handle_t *handle = NULL; + struct VideoDecoderOutputMetaData *meta; + OMX_U8 *buff = NULL; + + //get the buffer type and fd info + meta = (struct VideoDecoderOutputMetaData *)buffer->pBuffer; + handle = (private_handle_t *)meta->pHandle; + DEBUG_PRINT_LOW("FTB: buftype: %d bufhndl: %p", meta->eType, meta->pHandle); + + pthread_mutex_lock(&m_lock); + if (out_dynamic_list[nPortIndex].ref_count == 0) { + + //map the buffer handle based on the size set on output port definition. + if (!secure_mode) { + buff = (OMX_U8*)mmap(0, drv_ctx.op_buf.buffer_size, + PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0); + } else { + buff = (OMX_U8*) buffer; + } + + drv_ctx.ptr_outputbuffer[nPortIndex].pmem_fd = handle->fd; + drv_ctx.ptr_outputbuffer[nPortIndex].offset = 0; + drv_ctx.ptr_outputbuffer[nPortIndex].bufferaddr = buff; + drv_ctx.ptr_outputbuffer[nPortIndex].buffer_len = drv_ctx.op_buf.buffer_size; + drv_ctx.ptr_outputbuffer[nPortIndex].mmaped_size = drv_ctx.op_buf.buffer_size; + DEBUG_PRINT_LOW("fill_this_buffer: bufHdr %p idx %d mapped pBuffer %p size %u", buffer, nPortIndex, buff, drv_ctx.op_buf.buffer_size); + if (m_pSwVdecOpBuffer) { + m_pSwVdecOpBuffer[nPortIndex].nSize = drv_ctx.op_buf.buffer_size; + m_pSwVdecOpBuffer[nPortIndex].pBuffer = buff; + } + } + pthread_mutex_unlock(&m_lock); + buf_ref_add(nPortIndex, drv_ctx.ptr_outputbuffer[nPortIndex].pmem_fd, + drv_ctx.ptr_outputbuffer[nPortIndex].offset); + } + + DEBUG_PRINT_LOW("[FTB] bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer); + post_event((unsigned long) hComp, (unsigned long)buffer, (unsigned long)m_fill_output_msg); + return OMX_ErrorNone; +} +/* ====================================================================== +FUNCTION +omx_vdec::fill_this_buffer_proxy + +DESCRIPTION +IL client uses this method to release the frame buffer +after displaying them. + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::fill_this_buffer_proxy( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* bufferAdd) +{ + (void)hComp; + OMX_ERRORTYPE nRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *buffer = bufferAdd; + unsigned nPortIndex = 0; + struct vdec_fillbuffer_cmd fillbuffer; + struct vdec_bufferpayload *ptr_outputbuffer = NULL; + struct vdec_output_frameinfo *ptr_respbuffer = NULL; + + nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)client_buffers.get_il_buf_hdr()); + + if (bufferAdd == NULL || nPortIndex >= drv_ctx.op_buf.actualcount) + { + DEBUG_PRINT_ERROR("FTBProxy: bufhdr = %p, il = %p, nPortIndex %u bufCount %u", + bufferAdd, ((OMX_BUFFERHEADERTYPE *)client_buffers.get_il_buf_hdr()),nPortIndex, drv_ctx.op_buf.actualcount); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("FTBProxy: bufhdr = %p, bufhdr->pBuffer = %p", + bufferAdd, bufferAdd->pBuffer); + /*Return back the output buffer to client*/ + if(m_out_bEnabled != OMX_TRUE || output_flush_progress == true) + { + DEBUG_PRINT_LOW("Output Buffers return flush/disable condition"); + buffer->nFilledLen = 0; + m_cb.FillBufferDone (hComp,m_app_data,buffer); + return OMX_ErrorNone; + } + pending_output_buffers++; + buffer = client_buffers.get_dr_buf_hdr(bufferAdd); + ptr_respbuffer = (struct vdec_output_frameinfo*)buffer->pOutputPortPrivate; + if (ptr_respbuffer) + { + ptr_outputbuffer = (struct vdec_bufferpayload*)ptr_respbuffer->client_data; + } + + if (ptr_respbuffer == NULL || ptr_outputbuffer == NULL) + { + DEBUG_PRINT_ERROR("resp buffer or outputbuffer is NULL"); + buffer->nFilledLen = 0; + m_cb.FillBufferDone (hComp,m_app_data,buffer); + pending_output_buffers--; + return OMX_ErrorBadParameter; + } + + if (m_pSwVdec) + { + DEBUG_PRINT_HIGH("SwVdec_FillThisBuffer idx %d, bufHdr %p pBuffer %p", nPortIndex, + bufferAdd, m_pSwVdecOpBuffer[nPortIndex].pBuffer); + if (SWVDEC_S_SUCCESS != SwVdec_FillThisBuffer(m_pSwVdec, &m_pSwVdecOpBuffer[nPortIndex])) + { + DEBUG_PRINT_ERROR("SwVdec_FillThisBuffer failed"); + } + } + else + { + int rc = 0; + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + memset( (void *)&buf, 0, sizeof(buf)); + memset( (void *)plane, 0, (sizeof(struct v4l2_plane)*VIDEO_MAX_PLANES)); + int extra_idx = 0; + + buf.index = nPortIndex; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].bytesused = buffer->nFilledLen; + plane[0].length = drv_ctx.op_buf.buffer_size; + plane[0].m.userptr = + (unsigned long)drv_ctx.ptr_outputbuffer[nPortIndex].bufferaddr - + (unsigned long)drv_ctx.ptr_outputbuffer[nPortIndex].offset; + plane[0].reserved[0] = drv_ctx.ptr_outputbuffer[nPortIndex].pmem_fd; + plane[0].reserved[1] = drv_ctx.ptr_outputbuffer[nPortIndex].offset; + plane[0].data_offset = 0; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].bytesused = 0; + plane[extra_idx].length = drv_ctx.extradata_info.buffer_size; + plane[extra_idx].m.userptr = (long unsigned int) (drv_ctx.extradata_info.uaddr + nPortIndex * drv_ctx.extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = drv_ctx.extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = nPortIndex * drv_ctx.extradata_info.buffer_size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index higher than expected: %d", extra_idx); + return OMX_ErrorBadParameter; + } + buf.m.planes = plane; + buf.length = drv_ctx.num_planes; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_QBUF, &buf); + if (rc) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to qbuf to driver"); + } + } + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION +omx_vdec::SetCallbacks + +DESCRIPTION +Set the callbacks. + +PARAMETERS +None. + +RETURN VALUE +OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::set_callbacks(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_CALLBACKTYPE* callbacks, + OMX_IN OMX_PTR appData) +{ + (void)hComp; + m_cb = *callbacks; + DEBUG_PRINT_LOW("Callbacks Set %p %p %p",m_cb.EmptyBufferDone,\ + m_cb.EventHandler,m_cb.FillBufferDone); + m_app_data = appData; + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== +FUNCTION +omx_vdec::ComponentDeInit + +DESCRIPTION +Destroys the component and release memory allocated to the heap. + +PARAMETERS +<TBD>. + +RETURN VALUE +OMX Error None if everything successful. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::component_deinit(OMX_IN OMX_HANDLETYPE hComp) +{ + (void)hComp; + + unsigned i = 0; + if (OMX_StateLoaded != m_state) + { + DEBUG_PRINT_ERROR("WARNING:Rxd DeInit,OMX not in LOADED state %d",\ + m_state); + DEBUG_PRINT_ERROR("Playback Ended - FAILED"); + } + else + { + DEBUG_PRINT_HIGH("Playback Ended - PASSED"); + } + + /*Check if the output buffers have to be cleaned up*/ + if(m_out_mem_ptr) + { + DEBUG_PRINT_LOW("Freeing the Output Memory"); + for (i = 0; i < drv_ctx.op_buf.actualcount; i++ ) + { + free_output_buffer (&m_out_mem_ptr[i]); + } +#ifdef _ANDROID_ICS_ + memset(&native_buffer, 0, (sizeof(nativebuffer) * MAX_NUM_INPUT_OUTPUT_BUFFERS)); +#endif + } + + /*Check if the input buffers have to be cleaned up*/ + if(m_inp_mem_ptr || m_inp_heap_ptr) + { + DEBUG_PRINT_LOW("Freeing the Input Memory"); + for (i = 0; i<drv_ctx.ip_buf.actualcount; i++ ) + { + if (m_inp_mem_ptr) + free_input_buffer (i,&m_inp_mem_ptr[i]); + else + free_input_buffer (i,NULL); + } + } + free_input_buffer_header(); + free_output_buffer_header(); + if(h264_scratch.pBuffer) + { + free(h264_scratch.pBuffer); + h264_scratch.pBuffer = NULL; + } + + if (h264_parser) + { + delete h264_parser; + h264_parser = NULL; + } + + if(m_platform_list) + { + free(m_platform_list); + m_platform_list = NULL; + } + if(m_vendor_config.pData) + { + free(m_vendor_config.pData); + m_vendor_config.pData = NULL; + } + + // Reset counters in mesg queues + m_ftb_q.m_size=0; + m_cmd_q.m_size=0; + m_etb_q.m_size=0; + m_ftb_q.m_read = m_ftb_q.m_write =0; + m_cmd_q.m_read = m_cmd_q.m_write =0; + m_etb_q.m_read = m_etb_q.m_write =0; + m_ftb_q_dsp.m_size=0; + m_etb_q_swvdec.m_size=0; + m_ftb_q_dsp.m_read = m_ftb_q_dsp.m_write =0; + m_etb_q_swvdec.m_read = m_etb_q_swvdec.m_write =0; +#ifdef _ANDROID_ + if (m_debug_timestamp) + { + m_timestamp_list.reset_ts_list(); + } +#endif + + if (m_debug.infile) { + fclose(m_debug.infile); + m_debug.infile = NULL; + } + if (m_debug.outfile) { + fclose(m_debug.outfile); + m_debug.outfile = NULL; + } + if (m_debug.imbfile) { + fclose(m_debug.imbfile); + m_debug.imbfile = NULL; + } + + if (m_pSwVdec) + { + SwVdec_DeInit(m_pSwVdec); + m_pSwVdec = NULL; + } + DEBUG_PRINT_HIGH("omx_vdec::component_deinit() complete"); + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION +omx_vdec::UseEGLImage + +DESCRIPTION +OMX Use EGL Image method implementation <TBD>. + +PARAMETERS +<TBD>. + +RETURN VALUE +Not Implemented error. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::use_EGL_image(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN void* eglImage) +{ + OMX_QCOM_PLATFORM_PRIVATE_LIST pmem_list; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY pmem_entry; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO pmem_info; + (void)appData; + +#ifdef USE_EGL_IMAGE_GPU + PFNEGLQUERYIMAGEQUALCOMMPROC egl_queryfunc; + EGLint fd = -1, offset = 0,pmemPtr = 0; +#else + int fd = -1, offset = 0; +#endif + DEBUG_PRINT_HIGH("use EGL image support for decoder"); + if (!bufferHdr || !eglImage|| port != OMX_CORE_OUTPUT_PORT_INDEX) { + DEBUG_PRINT_ERROR("use_EGL_image: Invalid param"); + } +#ifdef USE_EGL_IMAGE_GPU + if(m_display_id == NULL) { + DEBUG_PRINT_ERROR("Display ID is not set by IL client"); + return OMX_ErrorInsufficientResources; + } + egl_queryfunc = (PFNEGLQUERYIMAGEQUALCOMMPROC) + eglGetProcAddress("eglQueryImageKHR"); + egl_queryfunc(m_display_id, eglImage, EGL_BUFFER_HANDLE_QCOM,&fd); + egl_queryfunc(m_display_id, eglImage, EGL_BUFFER_OFFSET_QCOM,&offset); + egl_queryfunc(m_display_id, eglImage, EGL_BITMAP_POINTER_KHR,&pmemPtr); +#else //with OMX test app + struct temp_egl { + int pmem_fd; + int offset; + }; + struct temp_egl *temp_egl_id = NULL; + void * pmemPtr = (void *) eglImage; + temp_egl_id = (struct temp_egl *)eglImage; + if (temp_egl_id != NULL) + { + fd = temp_egl_id->pmem_fd; + offset = temp_egl_id->offset; + } +#endif + if (fd < 0) { + DEBUG_PRINT_ERROR("Improper pmem fd by EGL client %d",fd); + return OMX_ErrorInsufficientResources; + } + pmem_info.pmem_fd = (OMX_U32) fd; + pmem_info.offset = (OMX_U32) offset; + pmem_entry.entry = (void *) &pmem_info; + pmem_entry.type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; + pmem_list.entryList = &pmem_entry; + pmem_list.nEntries = 1; + ouput_egl_buffers = true; + if (OMX_ErrorNone != use_buffer(hComp,bufferHdr, port, + (void *)&pmem_list, drv_ctx.op_buf.buffer_size, + (OMX_U8 *)pmemPtr)) { + DEBUG_PRINT_ERROR("use buffer call failed for egl image"); + return OMX_ErrorInsufficientResources; + } + return OMX_ErrorNone; +} + +/* ====================================================================== +FUNCTION +omx_vdec::ComponentRoleEnum + +DESCRIPTION +OMX Component Role Enum method implementation. + +PARAMETERS +<TBD>. + +RETURN VALUE +OMX Error None if everything is successful. +========================================================================== */ +OMX_ERRORTYPE omx_vdec::component_role_enum(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_U8* role, + OMX_IN OMX_U32 index) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + (void)hComp; + + if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevchybrid",OMX_MAX_STRINGNAME_SIZE) || + !strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevcswvdec",OMX_MAX_STRINGNAME_SIZE) || + !strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc",OMX_MAX_STRINGNAME_SIZE)) + { + if((0 == index) && role) + { + strlcpy((char *)role, "video_decoder.hevc",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } + else + { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } + else + { + DEBUG_PRINT_ERROR("ERROR:Querying Role on Unknown Component"); + eRet = OMX_ErrorInvalidComponentName; + } + return eRet; +} + + + + +/* ====================================================================== +FUNCTION +omx_vdec::AllocateDone + +DESCRIPTION +Checks if entire buffer pool is allocated by IL Client or not. +Need this to move to IDLE state. + +PARAMETERS +None. + +RETURN VALUE +true/false. + +========================================================================== */ +bool omx_vdec::allocate_done(void) +{ + bool bRet = false; + bool bRet_In = false; + bool bRet_Out = false; + + bRet_In = allocate_input_done(); + bRet_Out = allocate_output_done(); + + if(bRet_In && bRet_Out) + { + bRet = true; + if (m_pSwVdec && m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + if (allocate_interm_buffer(drv_ctx.interm_op_buf.buffer_size) != OMX_ErrorNone) + { + omx_report_error(); + bRet = false; + } + } + } + + return bRet; +} +/* ====================================================================== +FUNCTION +omx_vdec::AllocateInputDone + +DESCRIPTION +Checks if I/P buffer pool is allocated by IL Client or not. + +PARAMETERS +None. + +RETURN VALUE +true/false. + +========================================================================== */ +bool omx_vdec::allocate_input_done(void) +{ + bool bRet = false; + unsigned i=0; + + if (m_inp_mem_ptr == NULL) + { + return bRet; + } + if(m_inp_mem_ptr ) + { + for(;i<drv_ctx.ip_buf.actualcount;i++) + { + if(BITMASK_ABSENT(&m_inp_bm_count,i)) + { + break; + } + } + } + if(i == drv_ctx.ip_buf.actualcount) + { + bRet = true; + DEBUG_PRINT_HIGH("Allocate done for all i/p buffers"); + } + if(i==drv_ctx.ip_buf.actualcount && m_inp_bEnabled) + { + m_inp_bPopulated = OMX_TRUE; + } + return bRet; +} +/* ====================================================================== +FUNCTION +omx_vdec::AllocateOutputDone + +DESCRIPTION +Checks if entire O/P buffer pool is allocated by IL Client or not. + +PARAMETERS +None. + +RETURN VALUE +true/false. + +========================================================================== */ +bool omx_vdec::allocate_output_done(void) +{ + bool bRet = false; + unsigned j=0; + + if (m_out_mem_ptr == NULL) + { + return bRet; + } + + if (m_out_mem_ptr) + { + for(;j < drv_ctx.op_buf.actualcount;j++) + { + if(BITMASK_ABSENT(&m_out_bm_count,j)) + { + break; + } + } + } + + if(j == drv_ctx.op_buf.actualcount) + { + bRet = true; + DEBUG_PRINT_HIGH("Allocate done for all o/p buffers"); + if(m_out_bEnabled) + m_out_bPopulated = OMX_TRUE; + } + + return bRet; +} + +/* ====================================================================== +FUNCTION +omx_vdec::ReleaseDone + +DESCRIPTION +Checks if IL client has released all the buffers. + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +bool omx_vdec::release_done(void) +{ + bool bRet = false; + + if(release_input_done()) + { + if(release_output_done()) + { + bRet = true; + } + } + + if (bRet && m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + bRet = release_interm_done(); + } + return bRet; +} + +bool omx_vdec::release_interm_done(void) +{ + bool bRet = true; + unsigned int i=0; + + if (!drv_ctx.ptr_interm_outputbuffer) return bRet; + + pthread_mutex_lock(&m_lock); + for(; (i<drv_ctx.interm_op_buf.actualcount) && drv_ctx.ptr_interm_outputbuffer[i].pmem_fd ; i++) + { + if(m_interm_buf_state[i] != WITH_COMPONENT) + { + bRet = false; + DEBUG_PRINT_ERROR("interm buffer i %d state %d",i, m_interm_buf_state[i]); + break; + } + } + pthread_mutex_unlock(&m_lock); + + DEBUG_PRINT_LOW("release_interm_done %d",bRet); + return bRet; +} + + +/* ====================================================================== +FUNCTION +omx_vdec::ReleaseOutputDone + +DESCRIPTION +Checks if IL client has released all the buffers. + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +bool omx_vdec::release_output_done(void) +{ + bool bRet = false; + unsigned i=0,j=0; + + DEBUG_PRINT_LOW("Value of m_out_mem_ptr %p",m_out_mem_ptr); + if(m_out_mem_ptr) + { + for(;j < drv_ctx.op_buf.actualcount ; j++) + { + if(BITMASK_PRESENT(&m_out_bm_count,j)) + { + break; + } + } + if(j == drv_ctx.op_buf.actualcount) + { + m_out_bm_count = 0; + bRet = true; + } + } + else + { + m_out_bm_count = 0; + bRet = true; + } + return bRet; +} +/* ====================================================================== +FUNCTION +omx_vdec::ReleaseInputDone + +DESCRIPTION +Checks if IL client has released all the buffers. + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +bool omx_vdec::release_input_done(void) +{ + bool bRet = false; + unsigned i=0,j=0; + + DEBUG_PRINT_LOW("Value of m_inp_mem_ptr %p",m_inp_mem_ptr); + if(m_inp_mem_ptr) + { + for(;j<drv_ctx.ip_buf.actualcount;j++) + { + if( BITMASK_PRESENT(&m_inp_bm_count,j)) + { + break; + } + } + if(j==drv_ctx.ip_buf.actualcount) + { + bRet = true; + } + } + else + { + bRet = true; + } + return bRet; +} + +OMX_ERRORTYPE omx_vdec::fill_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer) +{ + if (!buffer) + { + DEBUG_PRINT_ERROR("[FBD] ERROR in ptr(%p)", buffer); + return OMX_ErrorBadParameter; + } + unsigned long int nPortIndex = buffer - m_out_mem_ptr; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo = NULL; + if (nPortIndex >= drv_ctx.op_buf.actualcount) + { + DEBUG_PRINT_ERROR("[FBD] ERROR in port idx(%ld), act cnt(%d)", + nPortIndex, (int)drv_ctx.op_buf.actualcount); + return OMX_ErrorBadParameter; + } + else if (output_flush_progress) + { + DEBUG_PRINT_LOW("FBD: Buffer (%p) flushed", buffer); + buffer->nFilledLen = 0; + buffer->nTimeStamp = 0; + buffer->nFlags &= ~OMX_BUFFERFLAG_EXTRADATA; + buffer->nFlags &= ~QOMX_VIDEO_BUFFERFLAG_EOSEQ; + buffer->nFlags &= ~OMX_BUFFERFLAG_DATACORRUPT; + } + + DEBUG_PRINT_LOW("fill_buffer_done: bufhdr = %p, bufhdr->pBuffer = %p idx %d, TS %lld nFlags %lu", + buffer, buffer->pBuffer, buffer - m_out_mem_ptr, buffer->nTimeStamp, buffer->nFlags ); + pending_output_buffers --; + + if (buffer->nFlags & OMX_BUFFERFLAG_EOS) + { + DEBUG_PRINT_HIGH("Output EOS has been reached"); + if (!output_flush_progress) + post_event((unsigned)NULL, (unsigned)NULL, + OMX_COMPONENT_GENERATE_EOS_DONE); + + if (psource_frame) + { + m_cb.EmptyBufferDone(&m_cmp, m_app_data, psource_frame); + psource_frame = NULL; + } + if (pdest_frame) + { + pdest_frame->nFilledLen = 0; + m_input_free_q.insert_entry((unsigned long) pdest_frame,(unsigned long)NULL, + (unsigned long)NULL); + pdest_frame = NULL; + } + } + + if (m_debug.out_buffer_log) + { + log_output_buffers(buffer); + } + + /* For use buffer we need to copy the data */ + if (!output_flush_progress) + { + time_stamp_dts.get_next_timestamp(buffer, + (drv_ctx.interlace != VDEC_InterlaceFrameProgressive) + ?true:false); + if (m_debug_timestamp) + { + { + OMX_TICKS expected_ts = 0; + m_timestamp_list.pop_min_ts(expected_ts); + DEBUG_PRINT_LOW("Current timestamp (%lld),Popped TIMESTAMP (%lld) from list", + buffer->nTimeStamp, expected_ts); + + if (buffer->nTimeStamp != expected_ts) + { + DEBUG_PRINT_ERROR("ERROR in omx_vdec::async_message_process timestamp Check"); + } + } + } + } + if (m_cb.FillBufferDone) + { + if (buffer->nFilledLen > 0) + { + handle_extradata(buffer); + if (client_extradata & OMX_TIMEINFO_EXTRADATA) + // Keep min timestamp interval to handle corrupted bit stream scenario + set_frame_rate(buffer->nTimeStamp); + else if (arbitrary_bytes) + adjust_timestamp(buffer->nTimeStamp); + if (perf_flag) + { + if (!proc_frms) + { + dec_time.stop(); + latency = dec_time.processing_time_us() - latency; + DEBUG_PRINT_HIGH(">>> FBD Metrics: Latency(%.2f)mS", latency / 1e3); + dec_time.start(); + fps_metrics.start(); + } + proc_frms++; + if (buffer->nFlags & OMX_BUFFERFLAG_EOS) + { + OMX_U64 proc_time = 0; + fps_metrics.stop(); + proc_time = fps_metrics.processing_time_us(); + DEBUG_PRINT_HIGH(">>> FBD Metrics: proc_frms(%lu) proc_time(%.2f)S fps(%.2f)", + proc_frms, (float)proc_time / 1e6, + (float)(1e6 * proc_frms) / proc_time); + proc_frms = 0; + } + } + +#ifdef OUTPUT_EXTRADATA_LOG + if (outputExtradataFile) + { + + OMX_OTHER_EXTRADATATYPE *p_extra = NULL; + p_extra = (OMX_OTHER_EXTRADATATYPE *) + ((unsigned)(buffer->pBuffer + buffer->nOffset + + buffer->nFilledLen + 3)&(~3)); + while(p_extra && + (OMX_U8*)p_extra < (buffer->pBuffer + buffer->nAllocLen) ) + { + DEBUG_PRINT_LOW("WRITING extradata, size=%d,type=%d",p_extra->nSize, p_extra->eType); + fwrite (p_extra,1,p_extra->nSize,outputExtradataFile); + if (p_extra->eType == OMX_ExtraDataNone) + { + break; + } + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + p_extra->nSize); + } + } +#endif + } + if (buffer->nFlags & OMX_BUFFERFLAG_EOS){ + prev_ts = LLONG_MAX; + rst_prev_ts = true; + } + + pPMEMInfo = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) + ((OMX_QCOM_PLATFORM_PRIVATE_LIST *) + buffer->pPlatformPrivate)->entryList->entry; + DEBUG_PRINT_LOW("Before FBD callback Accessed Pmeminfo %lu", pPMEMInfo->pmem_fd); + OMX_BUFFERHEADERTYPE *il_buffer; + il_buffer = client_buffers.get_il_buf_hdr(buffer); + + if (dynamic_buf_mode && !secure_mode && + !(buffer->nFlags & OMX_BUFFERFLAG_READONLY)) + { + DEBUG_PRINT_LOW("swvdec_fill_buffer_done rmd ref frame"); + buf_ref_remove(drv_ctx.ptr_outputbuffer[nPortIndex].pmem_fd, + drv_ctx.ptr_outputbuffer[nPortIndex].offset); + } + if (il_buffer) + m_cb.FillBufferDone (hComp,m_app_data,il_buffer); + else { + DEBUG_PRINT_ERROR("Invalid buffer address from get_il_buf_hdr"); + return OMX_ErrorBadParameter; + } + DEBUG_PRINT_LOW("After Fill Buffer Done callback %lu",pPMEMInfo->pmem_fd); + } + else + { + return OMX_ErrorBadParameter; + } +#ifdef ADAPTIVE_PLAYBACK_SUPPORTED + if (m_swvdec_mode != SWVDEC_MODE_PARSE_DECODE) + { + /* in full sw solution stride doesn't get change with change of + resolution, so don't update geomatry in case of full sw */ + if (m_smoothstreaming_mode && m_out_mem_ptr) { + OMX_U32 buf_index = buffer - m_out_mem_ptr; + BufferDim_t dim; + private_handle_t *private_handle = NULL; + dim.sliceWidth = drv_ctx.video_resolution.frame_width; + dim.sliceHeight = drv_ctx.video_resolution.frame_height; + if (native_buffer[buf_index].privatehandle) + private_handle = native_buffer[buf_index].privatehandle; + if (private_handle) { + DEBUG_PRINT_LOW("set metadata: update buf-geometry with stride %d slice %d", + dim.sliceWidth, dim.sliceHeight); + setMetaData(private_handle, UPDATE_BUFFER_GEOMETRY, (void*)&dim); + } + } + } +#endif + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::empty_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + + if (buffer == NULL || ((buffer - m_inp_mem_ptr) > (int)drv_ctx.ip_buf.actualcount)) + { + DEBUG_PRINT_ERROR("empty_buffer_done: ERROR bufhdr = %p", buffer); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("empty_buffer_done: bufhdr = %p, bufhdr->pBuffer = %p", + buffer, buffer->pBuffer); + pending_input_buffers--; + + if (arbitrary_bytes) + { + if (pdest_frame == NULL && input_flush_progress == false) + { + DEBUG_PRINT_LOW("Push input from buffer done address of Buffer %p",buffer); + pdest_frame = buffer; + buffer->nFilledLen = 0; + buffer->nTimeStamp = LLONG_MAX; + push_input_buffer (hComp); + } + else + { + DEBUG_PRINT_LOW("Push buffer into freeq address of Buffer %p",buffer); + buffer->nFilledLen = 0; + if (!m_input_free_q.insert_entry((unsigned long)buffer, + (unsigned long)NULL, (unsigned long)NULL)) + { + DEBUG_PRINT_ERROR("ERROR:i/p free Queue is FULL Error"); + } + } + } + else if(m_cb.EmptyBufferDone) + { + buffer->nFilledLen = 0; + if (input_use_buffer == true){ + buffer = &m_inp_heap_ptr[buffer-m_inp_mem_ptr]; + } + m_cb.EmptyBufferDone(hComp ,m_app_data, buffer); + } + return OMX_ErrorNone; +} + + +void dump_buffer(FILE* pFile, char* buffer, int stride, int scanlines, int width, int height) +{ + if (buffer) + { + char *temp = (char *)buffer; + int i; + int bytes_written = 0; + int bytes = 0; + + for (i = 0; i < height; i++) { + bytes_written = fwrite(temp, width, 1, pFile); + temp += stride; + if (bytes_written >0) + bytes += bytes_written * width; + } + temp = (char *)buffer + stride * scanlines; + int stride_c = stride; + for(i = 0; i < height/2; i++) { + bytes_written = fwrite(temp, width, 1, pFile); + temp += stride_c; + if (bytes_written >0) + bytes += bytes_written * width; + } + + DEBUG_PRINT_ERROR("stride %d, scanlines %d, frame_height %d bytes_written %d", + stride, scanlines, height, bytes); + } +} + +int omx_vdec::async_message_process (void *context, void* message) +{ + omx_vdec* omx = NULL; + struct vdec_msginfo *vdec_msg = NULL; + OMX_BUFFERHEADERTYPE* omxhdr = NULL; + struct v4l2_buffer *v4l2_buf_ptr = NULL; + struct vdec_output_frameinfo *output_respbuf = NULL; + int rc=1; + if (context == NULL || message == NULL) + { + DEBUG_PRINT_ERROR("FATAL ERROR in omx_vdec::async_message_process NULL Check"); + return -1; + } + vdec_msg = (struct vdec_msginfo *)message; + + omx = reinterpret_cast<omx_vdec*>(context); + + switch (vdec_msg->msgcode) + { + + case VDEC_MSG_EVT_HW_ERROR: + omx->post_event ((unsigned long)NULL, (unsigned long)vdec_msg->status_code,\ + (unsigned long)OMX_COMPONENT_GENERATE_HARDWARE_ERROR); + break; + + case VDEC_MSG_RESP_START_DONE: + omx->post_event ((unsigned long)NULL, (unsigned long)vdec_msg->status_code,\ + (unsigned long)OMX_COMPONENT_GENERATE_START_DONE); + break; + + case VDEC_MSG_RESP_STOP_DONE: + omx->post_event ((unsigned long)NULL, (unsigned long)vdec_msg->status_code,\ + (unsigned long)OMX_COMPONENT_GENERATE_STOP_DONE); + break; + + case VDEC_MSG_RESP_RESUME_DONE: + omx->post_event ((unsigned long)NULL, (unsigned long)vdec_msg->status_code,\ + (unsigned long)OMX_COMPONENT_GENERATE_RESUME_DONE); + break; + + case VDEC_MSG_RESP_PAUSE_DONE: + omx->post_event ((unsigned long)NULL, (unsigned long)vdec_msg->status_code,\ + (unsigned long)OMX_COMPONENT_GENERATE_PAUSE_DONE); + break; + + case VDEC_MSG_RESP_FLUSH_INPUT_DONE: + omx->post_event ((unsigned long)NULL, (unsigned long)vdec_msg->status_code,\ + (unsigned long)OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH); + break; + case VDEC_MSG_RESP_FLUSH_OUTPUT_DONE: + if (!omx->m_pSwVdec) + { + omx->post_event ((unsigned)NULL, (unsigned long)vdec_msg->status_code,\ + (unsigned long)OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH); + } + else + { + omx->post_event ((unsigned)NULL, (unsigned long)vdec_msg->status_code,\ + (unsigned long)OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH_DSP); + } + break; + case VDEC_MSG_RESP_INPUT_FLUSHED: + case VDEC_MSG_RESP_INPUT_BUFFER_DONE: + + /* omxhdr = (OMX_BUFFERHEADERTYPE* ) + vdec_msg->msgdata.input_frame_clientdata; */ + + v4l2_buf_ptr = (v4l2_buffer*)vdec_msg->msgdata.input_frame_clientdata; + omxhdr=omx->m_inp_mem_ptr+v4l2_buf_ptr->index; + if (omxhdr == NULL || + ((omxhdr - omx->m_inp_mem_ptr) > (int)omx->drv_ctx.ip_buf.actualcount) ) + { + omxhdr = NULL; + vdec_msg->status_code = VDEC_S_EFATAL; + } + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_INPUT_UNSUPPORTED) { + DEBUG_PRINT_HIGH("Unsupported input"); + omx->omx_report_error (); + } + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_DATA_CORRUPT) { + vdec_msg->status_code = VDEC_S_INPUT_BITSTREAM_ERR; + } + omx->post_event ((unsigned long)omxhdr, (unsigned long)vdec_msg->status_code, + (unsigned long)OMX_COMPONENT_GENERATE_EBD); + break; + case VDEC_MSG_EVT_INFO_FIELD_DROPPED: + int64_t *timestamp; + timestamp = (int64_t *) malloc(sizeof(int64_t)); + if (timestamp) { + *timestamp = vdec_msg->msgdata.output_frame.time_stamp; + omx->post_event ((unsigned long)timestamp, (unsigned long)vdec_msg->status_code, + (unsigned long)OMX_COMPONENT_GENERATE_INFO_FIELD_DROPPED); + DEBUG_PRINT_HIGH("Field dropped time stamp is %lld", + vdec_msg->msgdata.output_frame.time_stamp); + } + break; + case VDEC_MSG_RESP_OUTPUT_FLUSHED: + case VDEC_MSG_RESP_OUTPUT_BUFFER_DONE: + { + int actualcount = omx->drv_ctx.op_buf.actualcount; + OMX_BUFFERHEADERTYPE* p_mem_ptr = omx->m_out_mem_ptr; + vdec_output_frameinfo* ptr_respbuffer = omx->drv_ctx.ptr_respbuffer; + if (omx->m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + actualcount = omx->drv_ctx.interm_op_buf.actualcount; + p_mem_ptr = omx->m_interm_mem_ptr; + ptr_respbuffer = omx->drv_ctx.ptr_interm_respbuffer; + } + v4l2_buf_ptr = (v4l2_buffer*)vdec_msg->msgdata.output_frame.client_data; + omxhdr=p_mem_ptr+v4l2_buf_ptr->index; + DEBUG_PRINT_LOW("[RespBufDone] Buf(%p) pBuffer (%p) idx %d Ts(%lld) Pic_type(%u) frame.len(%d)", + omxhdr, omxhdr->pBuffer, v4l2_buf_ptr->index, vdec_msg->msgdata.output_frame.time_stamp, + vdec_msg->msgdata.output_frame.pic_type, vdec_msg->msgdata.output_frame.len); + + if (omxhdr && omxhdr->pOutputPortPrivate && + ((omxhdr - p_mem_ptr) < actualcount) && + (((struct vdec_output_frameinfo *)omxhdr->pOutputPortPrivate + - ptr_respbuffer) < actualcount)) + { + if ((omx->m_pSwVdec == NULL) && + omx->dynamic_buf_mode && + vdec_msg->msgdata.output_frame.len) + { + vdec_msg->msgdata.output_frame.len = omxhdr->nAllocLen; + } + if ( vdec_msg->msgdata.output_frame.len <= omxhdr->nAllocLen) + { + omxhdr->nFilledLen = vdec_msg->msgdata.output_frame.len; + omxhdr->nOffset = vdec_msg->msgdata.output_frame.offset; + omxhdr->nTimeStamp = vdec_msg->msgdata.output_frame.time_stamp; + omxhdr->nFlags = 0; + + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_EOS) { + omxhdr->nFlags |= OMX_BUFFERFLAG_EOS; + //rc = -1; + } + if (omxhdr->nFilledLen) { + omxhdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; + } + if (v4l2_buf_ptr->flags & V4L2_BUF_FLAG_KEYFRAME || v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_IDRFRAME) { + omxhdr->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; + } else { + omxhdr->nFlags &= ~OMX_BUFFERFLAG_SYNCFRAME; + } + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_EOSEQ) { + omxhdr->nFlags |= QOMX_VIDEO_BUFFERFLAG_EOSEQ; + } + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_DECODEONLY) { + omxhdr->nFlags |= OMX_BUFFERFLAG_DECODEONLY; + } + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_READONLY) + { + omxhdr->nFlags |= OMX_BUFFERFLAG_READONLY; + } + if (omxhdr && (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_DROP_FRAME) && + !(v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_DECODEONLY) && + !(v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_EOS)) { + omx->time_stamp_dts.remove_time_stamp( + omxhdr->nTimeStamp, + (omx->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) + ?true:false); + omx->post_event ((unsigned long)NULL,(unsigned long)omxhdr, + (unsigned long)OMX_COMPONENT_GENERATE_FTB); + break; + } + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_DATA_CORRUPT) { + omxhdr->nFlags |= OMX_BUFFERFLAG_DATACORRUPT; + } + vdec_msg->msgdata.output_frame.bufferaddr = + omx->drv_ctx.ptr_outputbuffer[v4l2_buf_ptr->index].bufferaddr; + int format_notably_changed = 0; + if (omxhdr->nFilledLen && + (omxhdr->nFilledLen != (unsigned)omx->prev_n_filled_len)) { + if ((vdec_msg->msgdata.output_frame.framesize.bottom != omx->drv_ctx.video_resolution.frame_height) || + (vdec_msg->msgdata.output_frame.framesize.right != omx->drv_ctx.video_resolution.frame_width)) { + DEBUG_PRINT_HIGH("Height/Width information has changed"); + omx->drv_ctx.video_resolution.frame_height = vdec_msg->msgdata.output_frame.framesize.bottom; + omx->drv_ctx.video_resolution.frame_width = vdec_msg->msgdata.output_frame.framesize.right; + format_notably_changed = 1; + } + } + if (omxhdr->nFilledLen && (((unsigned)omx->rectangle.nLeft != + vdec_msg->msgdata.output_frame.framesize.left) + || ((unsigned)omx->rectangle.nTop != vdec_msg->msgdata.output_frame.framesize.top) + || (omx->rectangle.nWidth != vdec_msg->msgdata.output_frame.framesize.right) + || (omx->rectangle.nHeight != vdec_msg->msgdata.output_frame.framesize.bottom))) { + if ((vdec_msg->msgdata.output_frame.framesize.bottom != omx->drv_ctx.video_resolution.frame_height) || + (vdec_msg->msgdata.output_frame.framesize.right != omx->drv_ctx.video_resolution.frame_width)) { + omx->drv_ctx.video_resolution.frame_height = vdec_msg->msgdata.output_frame.framesize.bottom; + omx->drv_ctx.video_resolution.frame_width = vdec_msg->msgdata.output_frame.framesize.right; + DEBUG_PRINT_HIGH("Height/Width information has changed. W: %d --> %d, H: %d --> %d", + omx->drv_ctx.video_resolution.frame_width, vdec_msg->msgdata.output_frame.framesize.right, + omx->drv_ctx.video_resolution.frame_height, vdec_msg->msgdata.output_frame.framesize.bottom); + } + DEBUG_PRINT_HIGH("Crop information changed. W: %lu --> %d, H: %lu -> %d", + omx->rectangle.nWidth, vdec_msg->msgdata.output_frame.framesize.right, + omx->rectangle.nHeight, vdec_msg->msgdata.output_frame.framesize.bottom); + if (vdec_msg->msgdata.output_frame.framesize.left + vdec_msg->msgdata.output_frame.framesize.right >= + omx->drv_ctx.video_resolution.frame_width) { + vdec_msg->msgdata.output_frame.framesize.left = 0; + if (vdec_msg->msgdata.output_frame.framesize.right > omx->drv_ctx.video_resolution.frame_width) { + vdec_msg->msgdata.output_frame.framesize.right = omx->drv_ctx.video_resolution.frame_width; + } + } + if (vdec_msg->msgdata.output_frame.framesize.top + vdec_msg->msgdata.output_frame.framesize.bottom >= + omx->drv_ctx.video_resolution.frame_height) { + vdec_msg->msgdata.output_frame.framesize.top = 0; + if (vdec_msg->msgdata.output_frame.framesize.bottom > omx->drv_ctx.video_resolution.frame_height) { + vdec_msg->msgdata.output_frame.framesize.bottom = omx->drv_ctx.video_resolution.frame_height; + } + } + DEBUG_PRINT_LOW("omx_vdec: Adjusted Dim L: %d, T: %d, R: %d, B: %d, W: %d, H: %d", + vdec_msg->msgdata.output_frame.framesize.left, + vdec_msg->msgdata.output_frame.framesize.top, + vdec_msg->msgdata.output_frame.framesize.right, + vdec_msg->msgdata.output_frame.framesize.bottom, + omx->drv_ctx.video_resolution.frame_width, + omx->drv_ctx.video_resolution.frame_height); + omx->rectangle.nLeft = vdec_msg->msgdata.output_frame.framesize.left; + omx->rectangle.nTop = vdec_msg->msgdata.output_frame.framesize.top; + omx->rectangle.nWidth = vdec_msg->msgdata.output_frame.framesize.right; + omx->rectangle.nHeight = vdec_msg->msgdata.output_frame.framesize.bottom; + format_notably_changed = 1; + } + DEBUG_PRINT_HIGH("Left: %d, Right: %d, top: %d, Bottom: %d", + vdec_msg->msgdata.output_frame.framesize.left,vdec_msg->msgdata.output_frame.framesize.right, + vdec_msg->msgdata.output_frame.framesize.top, vdec_msg->msgdata.output_frame.framesize.bottom); + if (format_notably_changed) { + if (omx->is_video_session_supported()) { + omx->post_event ((unsigned long)0, (unsigned long)vdec_msg->status_code, + (unsigned long)OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING); + } else { + if (!omx->client_buffers.update_buffer_req()) { + DEBUG_PRINT_ERROR("Setting c2D buffer requirements failed"); + } + omx->post_event ((unsigned long)OMX_CORE_OUTPUT_PORT_INDEX, (unsigned long)OMX_IndexConfigCommonOutputCrop, + (unsigned long)OMX_COMPONENT_GENERATE_PORT_RECONFIG); + } + } + if (omxhdr->nFilledLen) + omx->prev_n_filled_len = omxhdr->nFilledLen; + + output_respbuf = (struct vdec_output_frameinfo *)\ + omxhdr->pOutputPortPrivate; + output_respbuf->len = vdec_msg->msgdata.output_frame.len; + output_respbuf->offset = vdec_msg->msgdata.output_frame.offset; + if (v4l2_buf_ptr->flags & V4L2_BUF_FLAG_KEYFRAME) { + output_respbuf->pic_type = PICTURE_TYPE_I; + } + if (v4l2_buf_ptr->flags & V4L2_BUF_FLAG_PFRAME) { + output_respbuf->pic_type = PICTURE_TYPE_P; + } + if (v4l2_buf_ptr->flags & V4L2_BUF_FLAG_BFRAME) { + output_respbuf->pic_type = PICTURE_TYPE_B; + } + + if (omx->output_use_buffer) + memcpy ( omxhdr->pBuffer, (void *) + ((unsigned long)vdec_msg->msgdata.output_frame.bufferaddr + + (unsigned long)vdec_msg->msgdata.output_frame.offset), + vdec_msg->msgdata.output_frame.len); + } else + omxhdr->nFilledLen = 0; + if (!omx->m_pSwVdec) + { + omx->post_event ((unsigned long)omxhdr, (unsigned long)vdec_msg->status_code, + (unsigned long)OMX_COMPONENT_GENERATE_FBD); + } + else + { + omx->post_event ((unsigned long)omxhdr, (unsigned long)vdec_msg->status_code, + (unsigned long)OMX_COMPONENT_GENERATE_FBD_DSP); + } + } + else if (vdec_msg->msgdata.output_frame.flags & OMX_BUFFERFLAG_EOS) + omx->post_event ((unsigned long)NULL, (unsigned long)vdec_msg->status_code, + OMX_COMPONENT_GENERATE_EOS_DONE); + else + omx->post_event ((unsigned long)NULL, (unsigned long)vdec_msg->status_code, + (unsigned long)OMX_COMPONENT_GENERATE_HARDWARE_ERROR); + } + break; + case VDEC_MSG_EVT_CONFIG_CHANGED: + if (!omx->m_pSwVdec) + { + DEBUG_PRINT_HIGH("Port settings changed"); + omx->post_event ((unsigned long)OMX_CORE_OUTPUT_PORT_INDEX, (unsigned long)OMX_IndexParamPortDefinition, + (unsigned long)OMX_COMPONENT_GENERATE_PORT_RECONFIG); + } + break; + default: + break; + } + return rc; +} + +OMX_ERRORTYPE omx_vdec::empty_this_buffer_proxy_arbitrary ( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ) +{ + unsigned address,p2,id; + DEBUG_PRINT_LOW("Empty this arbitrary"); + + if (buffer == NULL) + { + return OMX_ErrorBadParameter; + } + DEBUG_PRINT_LOW("ETBProxyArb: bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer); + DEBUG_PRINT_LOW("ETBProxyArb: nFilledLen %lu, flags %lu, timestamp %u", + buffer->nFilledLen, buffer->nFlags, (unsigned)buffer->nTimeStamp); + + /* return zero length and not an EOS buffer */ + /* return buffer if input flush in progress */ + if ((input_flush_progress == true) || ((buffer->nFilledLen == 0) && + ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == 0))) + { + DEBUG_PRINT_HIGH("return zero legth buffer or flush in progress"); + m_cb.EmptyBufferDone (hComp,m_app_data,buffer); + return OMX_ErrorNone; + } + + if (psource_frame == NULL) + { + DEBUG_PRINT_LOW("Set Buffer as source Buffer %p time stamp %lld",buffer,buffer->nTimeStamp); + psource_frame = buffer; + DEBUG_PRINT_LOW("Try to Push One Input Buffer "); + push_input_buffer (hComp); + } + else + { + DEBUG_PRINT_LOW("Push the source buffer into pendingq %p",buffer); + if (!m_input_pending_q.insert_entry((unsigned long)buffer, (unsigned long)NULL, + (unsigned long)NULL)) + { + return OMX_ErrorBadParameter; + } + } + + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::push_input_buffer (OMX_HANDLETYPE hComp) +{ + unsigned long address,p2,id; + OMX_ERRORTYPE ret = OMX_ErrorNone; + + if (pdest_frame == NULL || psource_frame == NULL) + { + /*Check if we have a destination buffer*/ + if (pdest_frame == NULL) + { + DEBUG_PRINT_LOW("Get a Destination buffer from the queue"); + if (m_input_free_q.m_size) + { + m_input_free_q.pop_entry(&address,&p2,&id); + pdest_frame = (OMX_BUFFERHEADERTYPE *)address; + pdest_frame->nFilledLen = 0; + pdest_frame->nTimeStamp = LLONG_MAX; + DEBUG_PRINT_LOW("Address of Pmem Buffer %p",pdest_frame); + } + } + + /*Check if we have a destination buffer*/ + if (psource_frame == NULL) + { + DEBUG_PRINT_LOW("Get a source buffer from the queue"); + if (m_input_pending_q.m_size) + { + m_input_pending_q.pop_entry(&address,&p2,&id); + psource_frame = (OMX_BUFFERHEADERTYPE *)address; + DEBUG_PRINT_LOW("Next source Buffer %p time stamp %lld",psource_frame, + psource_frame->nTimeStamp); + DEBUG_PRINT_LOW("Next source Buffer flag %lu length %lu", + psource_frame->nFlags,psource_frame->nFilledLen); + + } + } + + } + + while ((pdest_frame != NULL) && (psource_frame != NULL)) + { + switch (codec_type_parse) + { + case CODEC_TYPE_HEVC: + ret = push_input_hevc(hComp); + break; + default: + break; + } + if (ret != OMX_ErrorNone) + { + DEBUG_PRINT_ERROR("Pushing input Buffer Failed"); + omx_report_error (); + break; + } + } + + return ret; +} + +OMX_ERRORTYPE copy_buffer(OMX_BUFFERHEADERTYPE* pDst, OMX_BUFFERHEADERTYPE* pSrc) +{ + OMX_ERRORTYPE rc = OMX_ErrorNone; + if ((pDst->nAllocLen - pDst->nFilledLen) >= pSrc->nFilledLen) + { + memcpy ((pDst->pBuffer + pDst->nFilledLen), pSrc->pBuffer, pSrc->nFilledLen); + if (pDst->nTimeStamp == LLONG_MAX) + { + pDst->nTimeStamp = pSrc->nTimeStamp; + DEBUG_PRINT_LOW("Assign Dst nTimeStamp=%lld", pDst->nTimeStamp); + } + pDst->nFilledLen += pSrc->nFilledLen; + pSrc->nFilledLen = 0; + } + else + { + DEBUG_PRINT_ERROR("Error: Destination buffer overflow"); + rc = OMX_ErrorBadParameter; + } + return rc; +} + +OMX_ERRORTYPE omx_vdec::push_input_hevc (OMX_HANDLETYPE hComp) +{ + OMX_U32 partial_frame = 1; + unsigned long address,p2,id; + OMX_BOOL isNewFrame = OMX_FALSE; + OMX_BOOL generate_ebd = OMX_TRUE; + OMX_ERRORTYPE rc = OMX_ErrorNone; + + if (h264_scratch.pBuffer == NULL) + { + DEBUG_PRINT_ERROR("ERROR:Hevc Scratch Buffer not allocated"); + return OMX_ErrorBadParameter; + } + + + DEBUG_PRINT_LOW("h264_scratch.nFilledLen %lu has look_ahead_nal %d pdest_frame nFilledLen %lu nTimeStamp %lld", + h264_scratch.nFilledLen, look_ahead_nal, pdest_frame->nFilledLen, pdest_frame->nTimeStamp); + + if (h264_scratch.nFilledLen && look_ahead_nal) + { + look_ahead_nal = false; + + // copy the lookahead buffer in the scratch + rc = copy_buffer(pdest_frame, &h264_scratch); + if (rc != OMX_ErrorNone) + { + return rc; + } + } + if (nal_length == 0) + { + if (m_frame_parser.parse_sc_frame(psource_frame, + &h264_scratch,&partial_frame) == -1) + { + DEBUG_PRINT_ERROR("Error In Parsing Return Error"); + return OMX_ErrorBadParameter; + } + } + else + { + DEBUG_PRINT_LOW("Non-zero NAL length clip, hence parse with NAL size %d",nal_length); + if (m_frame_parser.parse_h264_nallength(psource_frame, + &h264_scratch,&partial_frame) == -1) + { + DEBUG_PRINT_ERROR("Error In Parsing NAL size, Return Error"); + return OMX_ErrorBadParameter; + } + } + + if (partial_frame == 0) + { + if (nal_count == 0 && h264_scratch.nFilledLen == 0) + { + DEBUG_PRINT_LOW("First NAL with Zero Length, hence Skip"); + nal_count++; + h264_scratch.nTimeStamp = psource_frame->nTimeStamp; + h264_scratch.nFlags = psource_frame->nFlags; + } + else + { + DEBUG_PRINT_LOW("Parsed New NAL Length = %lu",h264_scratch.nFilledLen); + if(h264_scratch.nFilledLen) + { + mHEVCutils.isNewFrame(&h264_scratch, 0, isNewFrame); + nal_count++; + } + + if (!isNewFrame) + { + DEBUG_PRINT_LOW("Not a new frame, copy h264_scratch nFilledLen %lu nTimestamp %lld, pdest_frame nFilledLen %lu nTimestamp %lld", + h264_scratch.nFilledLen, h264_scratch.nTimeStamp, pdest_frame->nFilledLen, pdest_frame->nTimeStamp); + rc = copy_buffer(pdest_frame, &h264_scratch); + if ( rc != OMX_ErrorNone) + { + return rc; + } + } + else + { + look_ahead_nal = true; + if (pdest_frame->nFilledLen == 0) + { + look_ahead_nal = false; + DEBUG_PRINT_LOW("dest nation buffer empty, copy scratch buffer"); + rc = copy_buffer(pdest_frame, &h264_scratch); + if ( rc != OMX_ErrorNone ) + { + return OMX_ErrorBadParameter; + } + } + else + { + if(psource_frame->nFilledLen || h264_scratch.nFilledLen) + { + pdest_frame->nFlags &= ~OMX_BUFFERFLAG_EOS; + } + + DEBUG_PRINT_LOW("FrameDetecetd # %d pdest_frame nFilledLen %lu nTimeStamp %lld, look_ahead_nal in h264_scratch nFilledLen %lu nTimeStamp %lld", + frame_count++, pdest_frame->nFilledLen, pdest_frame->nTimeStamp, h264_scratch.nFilledLen, h264_scratch.nTimeStamp); + if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone) + { + return OMX_ErrorBadParameter; + } + pdest_frame = NULL; + if (m_input_free_q.m_size) + { + m_input_free_q.pop_entry(&address,&p2,&id); + pdest_frame = (OMX_BUFFERHEADERTYPE *) address; + DEBUG_PRINT_LOW("pop the next pdest_buffer %p",pdest_frame); + pdest_frame->nFilledLen = 0; + pdest_frame->nFlags = 0; + pdest_frame->nTimeStamp = LLONG_MAX; + } + } + } + } + } + else + { + DEBUG_PRINT_LOW("psource_frame is partial nFilledLen %lu nTimeStamp %lld, pdest_frame nFilledLen %lu nTimeStamp %lld, h264_scratch nFilledLen %lu nTimeStamp %lld", + psource_frame->nFilledLen, psource_frame->nTimeStamp, pdest_frame->nFilledLen, pdest_frame->nTimeStamp, h264_scratch.nFilledLen, h264_scratch.nTimeStamp); + + /*Check if Destination Buffer is full*/ + if (h264_scratch.nAllocLen == + h264_scratch.nFilledLen + h264_scratch.nOffset) + { + DEBUG_PRINT_ERROR("ERROR: Frame Not found though Destination Filled"); + return OMX_ErrorStreamCorrupt; + } + } + + if (!psource_frame->nFilledLen) + { + DEBUG_PRINT_LOW("Buffer Consumed return source %p back to client",psource_frame); + + if (psource_frame->nFlags & OMX_BUFFERFLAG_EOS) + { + if (pdest_frame) + { + DEBUG_PRINT_LOW("EOS Reached Pass Last Buffer"); + rc = copy_buffer(pdest_frame, &h264_scratch); + if ( rc != OMX_ErrorNone ) + { + return rc; + } + pdest_frame->nTimeStamp = h264_scratch.nTimeStamp; + pdest_frame->nFlags = h264_scratch.nFlags | psource_frame->nFlags; + + + DEBUG_PRINT_ERROR("Push EOS frame number:%d nFilledLen =%lu TimeStamp = %lld nFlags %lu", + frame_count++, pdest_frame->nFilledLen,pdest_frame->nTimeStamp, pdest_frame->nFlags); + + /*Push the frame to the Decoder*/ + if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone) + { + return OMX_ErrorBadParameter; + } + pdest_frame = NULL; + } + else + { + DEBUG_PRINT_LOW("Last frame in else dest addr %p size %lu frame_count %d", + pdest_frame,h264_scratch.nFilledLen, frame_count); + generate_ebd = OMX_FALSE; + } + } + } + if(generate_ebd && !psource_frame->nFilledLen) + { + m_cb.EmptyBufferDone (hComp,m_app_data,psource_frame); + psource_frame = NULL; + if (m_input_pending_q.m_size) + { + m_input_pending_q.pop_entry(&address,&p2,&id); + psource_frame = (OMX_BUFFERHEADERTYPE *) address; + DEBUG_PRINT_LOW("Next source Buffer flag %lu nFilledLen %lu, nTimeStamp %lld", + psource_frame->nFlags,psource_frame->nFilledLen, psource_frame->nTimeStamp); + } + } + return OMX_ErrorNone; +} + +bool omx_vdec::align_pmem_buffers(int pmem_fd, OMX_U32 buffer_size, + OMX_U32 alignment) +{ + struct pmem_allocation allocation; + allocation.size = buffer_size; + allocation.align = clip2(alignment); + if (allocation.align < 4096) + { + allocation.align = 4096; + } + if (ioctl(pmem_fd, PMEM_ALLOCATE_ALIGNED, &allocation) < 0) + { + DEBUG_PRINT_ERROR("Aligment(%u) failed with pmem driver Sz(%lu)", + allocation.align, allocation.size); + return false; + } + return true; +} +#ifdef USE_ION +int omx_vdec::alloc_map_ion_memory(OMX_U32 buffer_size, + OMX_U32 alignment, struct ion_allocation_data *alloc_data, +struct ion_fd_data *fd_data, int flag, int heap_id) +{ + int fd = -EINVAL; + int rc = -EINVAL; + int ion_dev_flag; + struct vdec_ion ion_buf_info; + if (!alloc_data || buffer_size <= 0 || !fd_data) { + DEBUG_PRINT_ERROR("Invalid arguments to alloc_map_ion_memory"); + return -EINVAL; + } + ion_dev_flag = O_RDONLY; + fd = open (MEM_DEVICE, ion_dev_flag); + if (fd < 0) { + DEBUG_PRINT_ERROR("opening ion device failed with fd = %d", fd); + return fd; + } + alloc_data->flags = 0; + if(!secure_mode && (flag & ION_FLAG_CACHED)) + { + alloc_data->flags |= ION_FLAG_CACHED; + } + alloc_data->len = buffer_size; + alloc_data->align = clip2(alignment); + if (alloc_data->align < 4096) + { + alloc_data->align = 4096; + } + if ((secure_mode) && (flag & ION_SECURE)) + alloc_data->flags |= ION_SECURE; + + alloc_data->heap_id_mask = ION_HEAP(ION_IOMMU_HEAP_ID); + if (!secure_mode && heap_id) + alloc_data->heap_id_mask = ION_HEAP(heap_id); + + DEBUG_PRINT_LOW("ION ALLOC memory heap_id %d mask %0xx size %d align %d", + heap_id, (unsigned int)alloc_data->heap_id_mask, alloc_data->len, alloc_data->align); + rc = ioctl(fd,ION_IOC_ALLOC,alloc_data); + if (rc || !alloc_data->handle) { + DEBUG_PRINT_ERROR("ION ALLOC memory failed "); + alloc_data->handle = 0; + close(fd); + fd = -ENOMEM; + return fd; + } + fd_data->handle = alloc_data->handle; + rc = ioctl(fd,ION_IOC_MAP,fd_data); + if (rc) { + DEBUG_PRINT_ERROR("ION MAP failed "); + ion_buf_info.ion_alloc_data = *alloc_data; + ion_buf_info.ion_device_fd = fd; + ion_buf_info.fd_ion_data = *fd_data; + free_ion_memory(&ion_buf_info); + fd_data->fd =-1; + close(fd); + fd = -ENOMEM; + } + + return fd; +} + +void omx_vdec::free_ion_memory(struct vdec_ion *buf_ion_info) { + + if(!buf_ion_info) { + DEBUG_PRINT_ERROR("ION: free called with invalid fd/allocdata"); + return; + } + if(ioctl(buf_ion_info->ion_device_fd,ION_IOC_FREE, + &buf_ion_info->ion_alloc_data.handle)) { + DEBUG_PRINT_ERROR("ION: free failed" ); + } + + close(buf_ion_info->ion_device_fd); + buf_ion_info->ion_device_fd = -1; + buf_ion_info->ion_alloc_data.handle = 0; + buf_ion_info->fd_ion_data.fd = -1; +} +#endif +void omx_vdec::free_output_buffer_header() +{ + DEBUG_PRINT_HIGH("ALL output buffers are freed/released"); + output_use_buffer = false; + ouput_egl_buffers = false; + + if (m_out_mem_ptr) + { + free (m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + + if(m_platform_list) + { + free(m_platform_list); + m_platform_list = NULL; + } + + if (drv_ctx.ptr_respbuffer) + { + free (drv_ctx.ptr_respbuffer); + drv_ctx.ptr_respbuffer = NULL; + } + if (drv_ctx.ptr_outputbuffer) + { + free (drv_ctx.ptr_outputbuffer); + drv_ctx.ptr_outputbuffer = NULL; + } +#ifdef USE_ION + if (drv_ctx.op_buf_ion_info) { + DEBUG_PRINT_LOW("Free o/p ion context"); + free(drv_ctx.op_buf_ion_info); + drv_ctx.op_buf_ion_info = NULL; + } +#endif + if (out_dynamic_list) { + free(out_dynamic_list); + out_dynamic_list = NULL; + } +} + +void omx_vdec::free_input_buffer_header() +{ + input_use_buffer = false; + if (arbitrary_bytes) + { + if (m_frame_parser.mutils) + { + DEBUG_PRINT_LOW("Free utils parser"); + delete (m_frame_parser.mutils); + m_frame_parser.mutils = NULL; + } + + if (m_inp_heap_ptr) + { + DEBUG_PRINT_LOW("Free input Heap Pointer"); + free (m_inp_heap_ptr); + m_inp_heap_ptr = NULL; + } + + if (m_phdr_pmem_ptr) + { + DEBUG_PRINT_LOW("Free input pmem header Pointer"); + free (m_phdr_pmem_ptr); + m_phdr_pmem_ptr = NULL; + } + } + if (m_inp_mem_ptr) + { + DEBUG_PRINT_LOW("Free input pmem Pointer area"); + free (m_inp_mem_ptr); + m_inp_mem_ptr = NULL; + } + while (m_input_free_q.m_size) { + unsigned long address, p2, id; + m_input_free_q.pop_entry(&address, &p2, &id); + } + if (drv_ctx.ptr_inputbuffer) + { + DEBUG_PRINT_LOW("Free Driver Context pointer"); + free (drv_ctx.ptr_inputbuffer); + drv_ctx.ptr_inputbuffer = NULL; + } +#ifdef USE_ION + if (drv_ctx.ip_buf_ion_info) { + DEBUG_PRINT_LOW("Free ion context"); + free(drv_ctx.ip_buf_ion_info); + drv_ctx.ip_buf_ion_info = NULL; + } +#endif +} + +int omx_vdec::stream_off(OMX_U32 port) +{ + enum v4l2_buf_type btype; + int rc = 0; + enum v4l2_ports v4l2_port = OUTPUT_PORT; + + if (port == OMX_CORE_INPUT_PORT_INDEX) { + btype = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + v4l2_port = OUTPUT_PORT; + } else if (port == OMX_CORE_OUTPUT_PORT_INDEX) { + btype = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_port = CAPTURE_PORT; + } else if (port == OMX_ALL) { + int rc_input = stream_off(OMX_CORE_INPUT_PORT_INDEX); + int rc_output = stream_off(OMX_CORE_OUTPUT_PORT_INDEX); + + if (!rc_input) + return rc_input; + else + return rc_output; + } + + if (!streaming[v4l2_port]) { + // already streamed off, warn and move on + DEBUG_PRINT_HIGH("Warning: Attempting to stream off on %d port," + " which is already streamed off", v4l2_port); + return 0; + } + + DEBUG_PRINT_HIGH("Streaming off %d port", v4l2_port); + + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMOFF, &btype); + if (rc) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to call streamoff on %d Port", v4l2_port); + } else { + streaming[v4l2_port] = false; + } + + return rc; +} + +OMX_ERRORTYPE omx_vdec::get_buffer_req(vdec_allocatorproperty *buffer_prop) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_requestbuffers bufreq; + unsigned int buf_size = 0, extra_data_size = 0, client_extra_data_size = 0; + struct v4l2_format fmt; + int ret = 0; + + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = 1; + if(buffer_prop->buffer_type == VDEC_BUFFER_TYPE_INPUT){ + bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.type =V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.pixelformat = output_capability; + }else if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT){ + bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.type =V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = capture_capability; + }else {eRet = OMX_ErrorBadParameter;} + if(eRet==OMX_ErrorNone){ + ret = ioctl(drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); + } + if(ret) + { + DEBUG_PRINT_ERROR("Requesting buffer requirements failed"); + /*TODO: How to handle this case */ + eRet = OMX_ErrorInsufficientResources; + return eRet; + } + else + { + buffer_prop->actualcount = bufreq.count; + buffer_prop->mincount = bufreq.count; + DEBUG_PRINT_HIGH("Count = %d",bufreq.count); + } + DEBUG_PRINT_HIGH("GetBufReq: ActCnt(%d) Size(%d), BufType(%d)", + buffer_prop->actualcount, buffer_prop->buffer_size, buffer_prop->buffer_type); + + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_G_FMT, &fmt); + + update_resolution(fmt.fmt.pix_mp.width, + fmt.fmt.pix_mp.height, + fmt.fmt.pix_mp.plane_fmt[0].bytesperline, + fmt.fmt.pix_mp.plane_fmt[0].reserved[0]); + if (fmt.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + drv_ctx.num_planes = fmt.fmt.pix_mp.num_planes; + DEBUG_PRINT_HIGH("Buffer Size (plane[0].sizeimage) = %d",fmt.fmt.pix_mp.plane_fmt[0].sizeimage); + + if(ret) + { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Requesting buffer requirements failed"); + eRet = OMX_ErrorInsufficientResources; + } + else + { + int extra_idx = 0; + + eRet = is_video_session_supported(); + if (eRet) + return eRet; + + buffer_prop->buffer_size = fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + buf_size = buffer_prop->buffer_size; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + extra_data_size = fmt.fmt.pix_mp.plane_fmt[extra_idx].sizeimage; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index is more than allowed: %d", extra_idx); + return OMX_ErrorBadParameter; + } + if (client_extradata & OMX_FRAMEINFO_EXTRADATA) + { + DEBUG_PRINT_HIGH("Frame info extra data enabled!"); + client_extra_data_size += OMX_FRAMEINFO_EXTRADATA_SIZE; + } + if (client_extradata & OMX_INTERLACE_EXTRADATA) + { + client_extra_data_size += OMX_INTERLACE_EXTRADATA_SIZE; + } + if (client_extradata & OMX_PORTDEF_EXTRADATA) + { + client_extra_data_size += OMX_PORTDEF_EXTRADATA_SIZE; + DEBUG_PRINT_HIGH("Smooth streaming enabled extra_data_size=%d", + client_extra_data_size); + } + if (client_extra_data_size) + { + client_extra_data_size += sizeof(OMX_OTHER_EXTRADATATYPE); //Space for terminator + buf_size = ((buf_size + 3)&(~3)); //Align extradata start address to 64Bit + } + drv_ctx.extradata_info.size = buffer_prop->actualcount * extra_data_size; + drv_ctx.extradata_info.count = buffer_prop->actualcount; + drv_ctx.extradata_info.buffer_size = extra_data_size; + buf_size += client_extra_data_size; + buf_size = (buf_size + buffer_prop->alignment - 1)&(~(buffer_prop->alignment - 1)); + DEBUG_PRINT_HIGH("GetBufReq UPDATE: ActCnt(%d) Size(%d) BufSize(%d) BufType(%d), extradata size %d", + buffer_prop->actualcount, buffer_prop->buffer_size, buf_size, buffer_prop->buffer_type, client_extra_data_size); + if (in_reconfig) // BufReq will be set to driver when port is disabled + buffer_prop->buffer_size = buf_size; + else if (buf_size != buffer_prop->buffer_size) + { + buffer_prop->buffer_size = buf_size; + eRet = set_buffer_req(buffer_prop); + } + } + DEBUG_PRINT_HIGH("GetBufReq OUT: ActCnt(%d) Size(%d), BufType(%d)", + buffer_prop->actualcount, buffer_prop->buffer_size, buffer_prop->buffer_type); + return eRet; +} + +OMX_ERRORTYPE omx_vdec::set_buffer_req(vdec_allocatorproperty *buffer_prop) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned buf_size = 0; + struct v4l2_format fmt; + struct v4l2_requestbuffers bufreq; + int ret; + DEBUG_PRINT_LOW("SetBufReq IN: ActCnt(%d) Size(%d)", + buffer_prop->actualcount, buffer_prop->buffer_size); + buf_size = (buffer_prop->buffer_size + buffer_prop->alignment - 1)&(~(buffer_prop->alignment - 1)); + if (buf_size != buffer_prop->buffer_size) + { + DEBUG_PRINT_ERROR("Buffer size alignment error: Requested(%d) Required(%d)", + buffer_prop->buffer_size, buf_size); + eRet = OMX_ErrorBadParameter; + } + else + { + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + + if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_INPUT){ + fmt.type =V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.pixelformat = output_capability; + } else if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { + fmt.type =V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = capture_capability; + } else { + eRet = OMX_ErrorBadParameter; + } + + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) + { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Setting buffer requirements (format) failed %d", ret); + eRet = OMX_ErrorInsufficientResources; + } + + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = buffer_prop->actualcount; + if(buffer_prop->buffer_type == VDEC_BUFFER_TYPE_INPUT) { + bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + } else if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { + bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + } else { + eRet = OMX_ErrorBadParameter; + } + + if (eRet==OMX_ErrorNone) { + ret = ioctl(drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); + } + + if (ret) + { + DEBUG_PRINT_ERROR("Setting buffer requirements (reqbufs) failed %d", ret); + /*TODO: How to handle this case */ + eRet = OMX_ErrorInsufficientResources; + } else if (bufreq.count < buffer_prop->actualcount) { + DEBUG_PRINT_ERROR("Driver refused to change the number of buffers" + " on v4l2 port %d to %d (prefers %d)", bufreq.type, + buffer_prop->actualcount, bufreq.count); + eRet = OMX_ErrorInsufficientResources; + } else if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { + if (!client_buffers.update_buffer_req()) { + DEBUG_PRINT_ERROR("Setting c2D buffer requirements failed"); + eRet = OMX_ErrorInsufficientResources; + } + } + } + if (!eRet && !m_pSwVdec && buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) + { + // need to update extradata buffers also in pure dsp mode + drv_ctx.extradata_info.size = buffer_prop->actualcount * drv_ctx.extradata_info.buffer_size; + drv_ctx.extradata_info.count = buffer_prop->actualcount; + } + return eRet; +} + +OMX_ERRORTYPE omx_vdec::update_picture_resolution() +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + return eRet; +} + +OMX_ERRORTYPE omx_vdec::update_portdef(OMX_PARAM_PORTDEFINITIONTYPE *portDefn) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (!portDefn) + { + return OMX_ErrorBadParameter; + } + DEBUG_PRINT_LOW("omx_vdec::update_portdef"); + portDefn->nVersion.nVersion = OMX_SPEC_VERSION; + portDefn->nSize = sizeof(portDefn); + portDefn->eDomain = OMX_PortDomainVideo; + if (drv_ctx.frame_rate.fps_denominator > 0) + portDefn->format.video.xFramerate = drv_ctx.frame_rate.fps_numerator / + drv_ctx.frame_rate.fps_denominator; + else { + DEBUG_PRINT_ERROR("Error: Divide by zero"); + return OMX_ErrorBadParameter; + } + if (0 == portDefn->nPortIndex) + { + portDefn->eDir = OMX_DirInput; + portDefn->nBufferCountActual = drv_ctx.ip_buf.actualcount; + portDefn->nBufferCountMin = drv_ctx.ip_buf.mincount; + portDefn->nBufferSize = drv_ctx.ip_buf.buffer_size; + portDefn->format.video.eColorFormat = OMX_COLOR_FormatUnused; + portDefn->format.video.eCompressionFormat = eCompressionFormat; + portDefn->bEnabled = m_inp_bEnabled; + portDefn->bPopulated = m_inp_bPopulated; + } + else if (1 == portDefn->nPortIndex) + { + unsigned int buf_size = 0; + if (!client_buffers.update_buffer_req()) { + DEBUG_PRINT_ERROR("client_buffers.update_buffer_req Failed"); + return OMX_ErrorHardware; + } + if (!client_buffers.get_buffer_req(buf_size)) { + DEBUG_PRINT_ERROR("update buffer requirements"); + return OMX_ErrorHardware; + } + portDefn->nBufferSize = buf_size; + portDefn->eDir = OMX_DirOutput; + portDefn->nBufferCountActual = drv_ctx.op_buf.actualcount; + portDefn->nBufferCountMin = drv_ctx.op_buf.mincount; + portDefn->format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; + portDefn->bEnabled = m_out_bEnabled; + portDefn->bPopulated = m_out_bPopulated; + if (!client_buffers.get_color_format(portDefn->format.video.eColorFormat)) { + DEBUG_PRINT_ERROR("Error in getting color format"); + return OMX_ErrorHardware; + } + } + else + { + portDefn->eDir = OMX_DirMax; + DEBUG_PRINT_LOW(" get_parameter: Bad Port idx %d", + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + portDefn->format.video.nFrameHeight = drv_ctx.video_resolution.frame_height; + portDefn->format.video.nFrameWidth = drv_ctx.video_resolution.frame_width; + portDefn->format.video.nStride = drv_ctx.video_resolution.stride; + portDefn->format.video.nSliceHeight = drv_ctx.video_resolution.scan_lines; + DEBUG_PRINT_HIGH("update_portdef Width = %lu Height = %lu Stride = %ld" + " SliceHeight = %lu", portDefn->format.video.nFrameWidth, + portDefn->format.video.nFrameHeight, + portDefn->format.video.nStride, + portDefn->format.video.nSliceHeight); + return eRet; + +} + +OMX_ERRORTYPE omx_vdec::allocate_output_headers() +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr = NULL; + unsigned i= 0; + + if(!m_out_mem_ptr) { + DEBUG_PRINT_HIGH("Use o/p buffer case - Header List allocation"); + int nBufHdrSize = 0; + int nPlatformEntrySize = 0; + int nPlatformListSize = 0; + int nPMEMInfoSize = 0; + OMX_QCOM_PLATFORM_PRIVATE_LIST *pPlatformList; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY *pPlatformEntry; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo; + + DEBUG_PRINT_LOW("Setting First Output Buffer(%d)", + drv_ctx.op_buf.actualcount); + nBufHdrSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_BUFFERHEADERTYPE); + + nPMEMInfoSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO); + nPlatformListSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_LIST); + nPlatformEntrySize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_ENTRY); + + DEBUG_PRINT_LOW("TotalBufHdr %d BufHdrSize %d PMEM %d PL %d",nBufHdrSize, + sizeof(OMX_BUFFERHEADERTYPE), + nPMEMInfoSize, + nPlatformListSize); + DEBUG_PRINT_LOW("PE %d bmSize %d",nPlatformEntrySize, + m_out_bm_count); + m_out_mem_ptr = (OMX_BUFFERHEADERTYPE *)calloc(nBufHdrSize,1); + // Alloc mem for platform specific info + char *pPtr=NULL; + pPtr = (char*) calloc(nPlatformListSize + nPlatformEntrySize + + nPMEMInfoSize,1); + drv_ctx.ptr_outputbuffer = (struct vdec_bufferpayload *) \ + calloc (sizeof(struct vdec_bufferpayload), + drv_ctx.op_buf.actualcount); + drv_ctx.ptr_respbuffer = (struct vdec_output_frameinfo *)\ + calloc (sizeof (struct vdec_output_frameinfo), + drv_ctx.op_buf.actualcount); +#ifdef USE_ION + drv_ctx.op_buf_ion_info = (struct vdec_ion * ) \ + calloc (sizeof(struct vdec_ion),drv_ctx.op_buf.actualcount); +#endif + if (dynamic_buf_mode) { + out_dynamic_list = (struct dynamic_buf_list *) \ + calloc (sizeof(struct dynamic_buf_list), drv_ctx.op_buf.actualcount); + } + if(m_out_mem_ptr && pPtr && drv_ctx.ptr_outputbuffer + && drv_ctx.ptr_respbuffer) + { + bufHdr = m_out_mem_ptr; + m_platform_list = (OMX_QCOM_PLATFORM_PRIVATE_LIST *)(pPtr); + m_platform_entry= (OMX_QCOM_PLATFORM_PRIVATE_ENTRY *) + (((char *) m_platform_list) + nPlatformListSize); + m_pmem_info = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) + (((char *) m_platform_entry) + nPlatformEntrySize); + pPlatformList = m_platform_list; + pPlatformEntry = m_platform_entry; + pPMEMInfo = m_pmem_info; + + DEBUG_PRINT_LOW("Memory Allocation Succeeded for OUT port%p",m_out_mem_ptr); + + // Settting the entire storage nicely + DEBUG_PRINT_LOW("bHdr %p OutMem %p PE %p",bufHdr, + m_out_mem_ptr,pPlatformEntry); + DEBUG_PRINT_LOW(" Pmem Info = %p",pPMEMInfo); + for(i=0; i < drv_ctx.op_buf.actualcount ; i++) + { + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + // Set the values when we determine the right HxW param + bufHdr->nAllocLen = 0; + bufHdr->nFilledLen = 0; + bufHdr->pAppPrivate = NULL; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + pPlatformEntry->type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; + pPlatformEntry->entry = pPMEMInfo; + // Initialize the Platform List + pPlatformList->nEntries = 1; + pPlatformList->entryList = pPlatformEntry; + // Keep pBuffer NULL till vdec is opened + bufHdr->pBuffer = NULL; + pPMEMInfo->offset = 0; + pPMEMInfo->pmem_fd = 0; + bufHdr->pPlatformPrivate = pPlatformList; + drv_ctx.ptr_outputbuffer[i].pmem_fd = -1; +#ifdef USE_ION + drv_ctx.op_buf_ion_info[i].ion_device_fd =-1; +#endif + /*Create a mapping between buffers*/ + bufHdr->pOutputPortPrivate = &drv_ctx.ptr_respbuffer[i]; + drv_ctx.ptr_respbuffer[i].client_data = (void *) \ + &drv_ctx.ptr_outputbuffer[i]; + // Move the buffer and buffer header pointers + bufHdr++; + pPMEMInfo++; + pPlatformEntry++; + pPlatformList++; + } + } + else + { + DEBUG_PRINT_ERROR("Output buf mem alloc failed[0x%p][0x%p]",\ + m_out_mem_ptr, pPtr); + if(m_out_mem_ptr) + { + free(m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + if(pPtr) + { + free(pPtr); + pPtr = NULL; + } + if(drv_ctx.ptr_outputbuffer) + { + free(drv_ctx.ptr_outputbuffer); + drv_ctx.ptr_outputbuffer = NULL; + } + if(drv_ctx.ptr_respbuffer) + { + free(drv_ctx.ptr_respbuffer); + drv_ctx.ptr_respbuffer = NULL; + } +#ifdef USE_ION + if (drv_ctx.op_buf_ion_info) { + DEBUG_PRINT_LOW("Free o/p ion context"); + free(drv_ctx.op_buf_ion_info); + drv_ctx.op_buf_ion_info = NULL; + } +#endif + eRet = OMX_ErrorInsufficientResources; + } + } else { + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +void omx_vdec::complete_pending_buffer_done_cbs() +{ + unsigned long p1; + unsigned long p2; + unsigned long ident; + omx_cmd_queue tmp_q, pending_bd_q; + pthread_mutex_lock(&m_lock); + // pop all pending GENERATE FDB from ftb queue + while (m_ftb_q.m_size) + { + m_ftb_q.pop_entry(&p1,&p2,&ident); + if(ident == OMX_COMPONENT_GENERATE_FBD) + { + pending_bd_q.insert_entry(p1,p2,ident); + } + else + { + tmp_q.insert_entry(p1,p2,ident); + } + } + //return all non GENERATE FDB to ftb queue + while(tmp_q.m_size) + { + tmp_q.pop_entry(&p1,&p2,&ident); + m_ftb_q.insert_entry(p1,p2,ident); + } + // pop all pending GENERATE EDB from etb queue + while (m_etb_q.m_size) + { + m_etb_q.pop_entry(&p1,&p2,&ident); + if(ident == OMX_COMPONENT_GENERATE_EBD) + { + pending_bd_q.insert_entry(p1,p2,ident); + } + else + { + tmp_q.insert_entry(p1,p2,ident); + } + } + //return all non GENERATE FDB to etb queue + while(tmp_q.m_size) + { + tmp_q.pop_entry(&p1,&p2,&ident); + m_etb_q.insert_entry(p1,p2,ident); + } + pthread_mutex_unlock(&m_lock); + // process all pending buffer dones + while(pending_bd_q.m_size) + { + pending_bd_q.pop_entry(&p1,&p2,&ident); + switch(ident) + { + case OMX_COMPONENT_GENERATE_EBD: + if(empty_buffer_done(&m_cmp, (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone) + { + DEBUG_PRINT_ERROR("ERROR: empty_buffer_done() failed!"); + omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_FBD: + if(fill_buffer_done(&m_cmp, (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone ) + { + DEBUG_PRINT_ERROR("ERROR: fill_buffer_done() failed!"); + omx_report_error (); + } + break; + } + } +} + +void omx_vdec::set_frame_rate(OMX_S64 act_timestamp) +{ + OMX_U32 new_frame_interval = 0; + if (VALID_TS(act_timestamp) && VALID_TS(prev_ts) && act_timestamp != prev_ts + && (((act_timestamp > prev_ts )? act_timestamp - prev_ts: prev_ts-act_timestamp)>2000)) + { + new_frame_interval = (act_timestamp > prev_ts)? + act_timestamp - prev_ts : + prev_ts - act_timestamp; + if (new_frame_interval < frm_int || frm_int == 0) + { + frm_int = new_frame_interval; + if(frm_int) + { + drv_ctx.frame_rate.fps_numerator = 1e6; + drv_ctx.frame_rate.fps_denominator = frm_int; + DEBUG_PRINT_LOW("set_frame_rate: frm_int(%lu) fps(%f)", + frm_int, drv_ctx.frame_rate.fps_numerator / + (float)drv_ctx.frame_rate.fps_denominator); + } + } + } + prev_ts = act_timestamp; +} + +void omx_vdec::adjust_timestamp(OMX_S64 &act_timestamp) +{ + if (rst_prev_ts && VALID_TS(act_timestamp)) + { + prev_ts = act_timestamp; + rst_prev_ts = false; + } + else if (VALID_TS(prev_ts)) + { + bool codec_cond = (drv_ctx.timestamp_adjust)? + (!VALID_TS(act_timestamp) || (((act_timestamp > prev_ts)? + (act_timestamp - prev_ts):(prev_ts - act_timestamp)) <= 2000)): + (!VALID_TS(act_timestamp) || act_timestamp == prev_ts); + if(frm_int > 0 && codec_cond) + { + DEBUG_PRINT_LOW("adjust_timestamp: original ts[%lld]", act_timestamp); + act_timestamp = prev_ts + frm_int; + DEBUG_PRINT_LOW("adjust_timestamp: predicted ts[%lld]", act_timestamp); + prev_ts = act_timestamp; + } + else + set_frame_rate(act_timestamp); + } + else if (frm_int > 0) // In this case the frame rate was set along + { // with the port definition, start ts with 0 + act_timestamp = prev_ts = 0; // and correct if a valid ts is received. + rst_prev_ts = true; + } +} + +void omx_vdec::handle_extradata(OMX_BUFFERHEADERTYPE *p_buf_hdr) +{ + OMX_OTHER_EXTRADATATYPE *p_extra = NULL, *p_sei = NULL, *p_vui = NULL; + OMX_U32 num_conceal_MB = 0; + OMX_U32 frame_rate = 0; + int consumed_len = 0; + OMX_U32 num_MB_in_frame; + OMX_U32 recovery_sei_flags = 1; + int buf_index = p_buf_hdr - m_out_mem_ptr; + struct msm_vidc_panscan_window_payload *panscan_payload = NULL; + OMX_U8 *pBuffer = (OMX_U8 *)(drv_ctx.ptr_outputbuffer[buf_index].bufferaddr) + + p_buf_hdr->nOffset; + if (!drv_ctx.extradata_info.uaddr) { + return; + } + p_extra = (OMX_OTHER_EXTRADATATYPE *) + ((unsigned long)(pBuffer + p_buf_hdr->nOffset + p_buf_hdr->nFilledLen + 3)&(~3)); + if (!client_extradata) + p_extra = NULL; + char *p_extradata = drv_ctx.extradata_info.uaddr + buf_index * drv_ctx.extradata_info.buffer_size; + if ((OMX_U8*)p_extra >= (pBuffer + p_buf_hdr->nAllocLen)) + p_extra = NULL; + OMX_OTHER_EXTRADATATYPE *data = (struct OMX_OTHER_EXTRADATATYPE *)p_extradata; + if (data) { + while((consumed_len < drv_ctx.extradata_info.buffer_size) + && (data->eType != (OMX_EXTRADATATYPE)MSM_VIDC_EXTRADATA_NONE)) { + if ((consumed_len + data->nSize) > (OMX_U32)drv_ctx.extradata_info.buffer_size) { + DEBUG_PRINT_LOW("Invalid extra data size"); + break; + } + unsigned char* tmp = data->data; + switch((unsigned long)data->eType) { +case MSM_VIDC_EXTRADATA_INTERLACE_VIDEO: + struct msm_vidc_interlace_payload *payload; + payload = (struct msm_vidc_interlace_payload *)tmp; + if (payload->format != MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE) { + int enable = 1; + OMX_U32 mbaff = 0; + mbaff = (h264_parser)? (h264_parser->is_mbaff()): false; + if ((payload->format == MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE) && !mbaff) + drv_ctx.interlace = VDEC_InterlaceFrameProgressive; + else + drv_ctx.interlace = VDEC_InterlaceInterleaveFrameTopFieldFirst; + if(m_enable_android_native_buffers) + setMetaData((private_handle_t *)native_buffer[buf_index].privatehandle, + PP_PARAM_INTERLACED, (void*)&enable); + } + if (!secure_mode && (client_extradata & OMX_INTERLACE_EXTRADATA)) { + append_interlace_extradata(p_extra, payload->format); + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + p_extra->nSize); + } + break; +case MSM_VIDC_EXTRADATA_FRAME_RATE: + struct msm_vidc_framerate_payload *frame_rate_payload; + frame_rate_payload = (struct msm_vidc_framerate_payload *)tmp; + frame_rate = frame_rate_payload->frame_rate; + break; +case MSM_VIDC_EXTRADATA_TIMESTAMP: + struct msm_vidc_ts_payload *time_stamp_payload; + time_stamp_payload = (struct msm_vidc_ts_payload *)tmp; + p_buf_hdr->nTimeStamp = time_stamp_payload->timestamp_lo; + p_buf_hdr->nTimeStamp |= ((unsigned long long)time_stamp_payload->timestamp_hi << 32); + break; +case MSM_VIDC_EXTRADATA_NUM_CONCEALED_MB: + struct msm_vidc_concealmb_payload *conceal_mb_payload; + conceal_mb_payload = (struct msm_vidc_concealmb_payload *)tmp; + num_MB_in_frame = ((drv_ctx.video_resolution.frame_width + 15) * + (drv_ctx.video_resolution.frame_height + 15)) >> 8; + num_conceal_MB = ((num_MB_in_frame > 0)?(conceal_mb_payload->num_mbs * 100 / num_MB_in_frame) : 0); + break; +case MSM_VIDC_EXTRADATA_ASPECT_RATIO: + struct msm_vidc_aspect_ratio_payload *aspect_ratio_payload; + aspect_ratio_payload = (struct msm_vidc_aspect_ratio_payload *)tmp; + ((struct vdec_output_frameinfo *) + p_buf_hdr->pOutputPortPrivate)->aspect_ratio_info.par_width = aspect_ratio_payload->aspect_width; + ((struct vdec_output_frameinfo *) + p_buf_hdr->pOutputPortPrivate)->aspect_ratio_info.par_height = aspect_ratio_payload->aspect_height; + break; +case MSM_VIDC_EXTRADATA_RECOVERY_POINT_SEI: + struct msm_vidc_recoverysei_payload *recovery_sei_payload; + recovery_sei_payload = (struct msm_vidc_recoverysei_payload *)tmp; + recovery_sei_flags = recovery_sei_payload->flags; + if (recovery_sei_flags != MSM_VIDC_FRAME_RECONSTRUCTION_CORRECT) { + p_buf_hdr->nFlags |= OMX_BUFFERFLAG_DATACORRUPT; + DEBUG_PRINT_HIGH("Extradata: OMX_BUFFERFLAG_DATACORRUPT Received"); + } + break; +case MSM_VIDC_EXTRADATA_PANSCAN_WINDOW: + panscan_payload = (struct msm_vidc_panscan_window_payload *)tmp; + break; +default: + goto unrecognized_extradata; + } + consumed_len += data->nSize; + data = (OMX_OTHER_EXTRADATATYPE *)((char *)data + data->nSize); + } + if (!secure_mode && (client_extradata & OMX_FRAMEINFO_EXTRADATA)) { + p_buf_hdr->nFlags |= OMX_BUFFERFLAG_EXTRADATA; + append_frame_info_extradata(p_extra, + num_conceal_MB, ((struct vdec_output_frameinfo *)p_buf_hdr->pOutputPortPrivate)->pic_type, frame_rate, + panscan_payload,&((struct vdec_output_frameinfo *) + p_buf_hdr->pOutputPortPrivate)->aspect_ratio_info);} + } +unrecognized_extradata: + if(!secure_mode && client_extradata) + append_terminator_extradata(p_extra); + return; +} + +OMX_ERRORTYPE omx_vdec::enable_extradata(OMX_U32 requested_extradata, + bool is_internal, bool enable) +{ + OMX_ERRORTYPE ret = OMX_ErrorNone; + struct v4l2_control control; + if(m_state != OMX_StateLoaded) + { + DEBUG_PRINT_ERROR("ERROR: enable extradata allowed in Loaded state only"); + return OMX_ErrorIncorrectStateOperation; + } + DEBUG_PRINT_ERROR("NOTE: enable_extradata: actual[%lx] requested[%lx] enable[%d], is_internal: %d swvdec mode %d", + client_extradata, requested_extradata, enable, is_internal, m_swvdec_mode); + + if (!is_internal) { + if (enable) + client_extradata |= requested_extradata; + else + client_extradata = client_extradata & ~requested_extradata; + } + + if (enable) { + if (m_pSwVdec == NULL || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) { + if (requested_extradata & OMX_INTERLACE_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO; + if(ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set interlaced extradata." + " Quality of interlaced clips might be impacted."); + } + } else if (requested_extradata & OMX_FRAMEINFO_EXTRADATA) + { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE; + if(ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set framerate extradata"); + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB; + if(ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set concealed MB extradata"); + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI; + if(ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set recovery point SEI extradata"); + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW; + if(ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set panscan extradata"); + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO; + if(ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set panscan extradata"); + } + } else if (requested_extradata & OMX_TIMEINFO_EXTRADATA){ + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP; + if(ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set timeinfo extradata"); + } + } + } + } + return ret; +} + +OMX_U32 omx_vdec::count_MB_in_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + OMX_U32 num_MB = 0, byte_count = 0, num_MB_in_frame = 0; + OMX_U8 *data_ptr = extra->data, data = 0; + while (byte_count < extra->nDataSize) + { + data = *data_ptr; + while (data) + { + num_MB += (data&0x01); + data >>= 1; + } + data_ptr++; + byte_count++; + } + num_MB_in_frame = ((drv_ctx.video_resolution.frame_width + 15) * + (drv_ctx.video_resolution.frame_height + 15)) >> 8; + return ((num_MB_in_frame > 0)?(num_MB * 100 / num_MB_in_frame) : 0); +} + +void omx_vdec::print_debug_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + if (!m_debug_extradata) + return; + + unsigned char* tmp = extra->data; + + DEBUG_PRINT_HIGH( + "============== Extra Data ==============\n" + " Size: %lu\n" + " Version: %lu\n" + " PortIndex: %lu\n" + " Type: %x\n" + " DataSize: %lu", + extra->nSize, extra->nVersion.nVersion, + extra->nPortIndex, extra->eType, extra->nDataSize); + + if (extra->eType == (OMX_EXTRADATATYPE)OMX_ExtraDataInterlaceFormat) + { + OMX_STREAMINTERLACEFORMAT *intfmt = (OMX_STREAMINTERLACEFORMAT *)tmp; + DEBUG_PRINT_HIGH( + "------ Interlace Format ------\n" + " Size: %lu\n" + " Version: %lu\n" + " PortIndex: %lu\n" + " Is Interlace Format: %d\n" + " Interlace Formats: %lu\n" + "=========== End of Interlace ===========", + intfmt->nSize, intfmt->nVersion.nVersion, intfmt->nPortIndex, + intfmt->bInterlaceFormat, intfmt->nInterlaceFormats); + } + else if (extra->eType == (OMX_EXTRADATATYPE)OMX_ExtraDataFrameInfo) + { + OMX_QCOM_EXTRADATA_FRAMEINFO *fminfo = (OMX_QCOM_EXTRADATA_FRAMEINFO *)tmp; + + DEBUG_PRINT_HIGH( + "-------- Frame Format --------\n" + " Picture Type: %d\n" + " Interlace Type: %d\n" + " Pan Scan Total Frame Num: %lu\n" + " Concealed Macro Blocks: %lu\n" + " frame rate: %lu\n" + " Aspect Ratio X: %lu\n" + " Aspect Ratio Y: %lu", + fminfo->ePicType, + fminfo->interlaceType, + fminfo->panScan.numWindows, + fminfo->nConcealedMacroblocks, + fminfo->nFrameRate, + fminfo->aspectRatio.aspectRatioX, + fminfo->aspectRatio.aspectRatioY); + + for (OMX_U32 i = 0; i < fminfo->panScan.numWindows; i++) + { + DEBUG_PRINT_HIGH( + "------------------------------\n" + " Pan Scan Frame Num: %lu\n" + " Rectangle x: %ld\n" + " Rectangle y: %ld\n" + " Rectangle dx: %ld\n" + " Rectangle dy: %ld", + i, fminfo->panScan.window[i].x, fminfo->panScan.window[i].y, + fminfo->panScan.window[i].dx, fminfo->panScan.window[i].dy); + } + + DEBUG_PRINT_HIGH("========= End of Frame Format =========="); + } + else if (extra->eType == OMX_ExtraDataNone) + { + DEBUG_PRINT_HIGH("========== End of Terminator ==========="); + } + else + { + DEBUG_PRINT_HIGH("======= End of Driver Extradata ========"); + } +} + +void omx_vdec::append_interlace_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 interlaced_format_type) +{ + OMX_STREAMINTERLACEFORMAT *interlace_format; + OMX_U32 mbaff = 0; + if (!(client_extradata & OMX_INTERLACE_EXTRADATA) || !extra) { + return; + } + extra->nSize = OMX_INTERLACE_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataInterlaceFormat; + extra->nDataSize = sizeof(OMX_STREAMINTERLACEFORMAT); + unsigned char* tmp = extra->data; + interlace_format = (OMX_STREAMINTERLACEFORMAT *)tmp; + interlace_format->nSize = sizeof(OMX_STREAMINTERLACEFORMAT); + interlace_format->nVersion.nVersion = OMX_SPEC_VERSION; + interlace_format->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + mbaff = (h264_parser)? (h264_parser->is_mbaff()): false; + if ((interlaced_format_type == MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE) && !mbaff) + { + interlace_format->bInterlaceFormat = OMX_FALSE; + interlace_format->nInterlaceFormats = OMX_InterlaceFrameProgressive; + drv_ctx.interlace = VDEC_InterlaceFrameProgressive; + } + else + { + interlace_format->bInterlaceFormat = OMX_TRUE; + interlace_format->nInterlaceFormats = OMX_InterlaceInterleaveFrameTopFieldFirst; + drv_ctx.interlace = VDEC_InterlaceInterleaveFrameTopFieldFirst; + } + print_debug_extradata(extra); +} + +void omx_vdec::fill_aspect_ratio_info( +struct vdec_aspectratioinfo *aspect_ratio_info, + OMX_QCOM_EXTRADATA_FRAMEINFO *frame_info) +{ + m_extradata = frame_info; + m_extradata->aspectRatio.aspectRatioX = aspect_ratio_info->par_width; + m_extradata->aspectRatio.aspectRatioY = aspect_ratio_info->par_height; + DEBUG_PRINT_LOW("aspectRatioX %lu aspectRatioX %lu", m_extradata->aspectRatio.aspectRatioX, + m_extradata->aspectRatio.aspectRatioY); +} + +void omx_vdec::append_frame_info_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 num_conceal_mb, OMX_U32 picture_type, OMX_U32 frame_rate, +struct msm_vidc_panscan_window_payload *panscan_payload, +struct vdec_aspectratioinfo *aspect_ratio_info) +{ + OMX_QCOM_EXTRADATA_FRAMEINFO *frame_info = NULL; + struct msm_vidc_panscan_window *panscan_window; + if (!(client_extradata & OMX_FRAMEINFO_EXTRADATA) || !extra) { + return; + } + extra->nSize = OMX_FRAMEINFO_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataFrameInfo; + extra->nDataSize = sizeof(OMX_QCOM_EXTRADATA_FRAMEINFO); + unsigned char* tmp = extra->data; + frame_info = (OMX_QCOM_EXTRADATA_FRAMEINFO *)tmp; + switch (picture_type) + { + case PICTURE_TYPE_I: + frame_info->ePicType = OMX_VIDEO_PictureTypeI; + break; + case PICTURE_TYPE_P: + frame_info->ePicType = OMX_VIDEO_PictureTypeP; + break; + case PICTURE_TYPE_B: + frame_info->ePicType = OMX_VIDEO_PictureTypeB; + break; + default: + frame_info->ePicType = (OMX_VIDEO_PICTURETYPE)0; + } + if (drv_ctx.interlace == VDEC_InterlaceInterleaveFrameTopFieldFirst) + frame_info->interlaceType = OMX_QCOM_InterlaceInterleaveFrameTopFieldFirst; + else if (drv_ctx.interlace == VDEC_InterlaceInterleaveFrameBottomFieldFirst) + frame_info->interlaceType = OMX_QCOM_InterlaceInterleaveFrameBottomFieldFirst; + else + frame_info->interlaceType = OMX_QCOM_InterlaceFrameProgressive; + memset(&frame_info->aspectRatio, 0, sizeof(frame_info->aspectRatio)); + frame_info->nConcealedMacroblocks = num_conceal_mb; + frame_info->nFrameRate = frame_rate; + frame_info->panScan.numWindows = 0; + if(panscan_payload) { + frame_info->panScan.numWindows = panscan_payload->num_panscan_windows; + panscan_window = &panscan_payload->wnd[0]; + for (OMX_U32 i = 0; i < frame_info->panScan.numWindows; i++) + { + frame_info->panScan.window[i].x = panscan_window->panscan_window_width; + frame_info->panScan.window[i].y = panscan_window->panscan_window_height; + frame_info->panScan.window[i].dx = panscan_window->panscan_width_offset; + frame_info->panScan.window[i].dy = panscan_window->panscan_height_offset; + panscan_window++; + } + } + fill_aspect_ratio_info(aspect_ratio_info, frame_info); + print_debug_extradata(extra); +} + +void omx_vdec::append_portdef_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + if (!client_extradata || !extra) { + return; + } + + OMX_PARAM_PORTDEFINITIONTYPE *portDefn = NULL; + extra->nSize = OMX_PORTDEF_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataPortDef; + extra->nDataSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); + unsigned char* tmp = extra->data; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *)tmp; + *portDefn = m_port_def; + DEBUG_PRINT_LOW("append_portdef_extradata height = %lu width = %lu stride = %lu" + "sliceheight = %lu",portDefn->format.video.nFrameHeight, + portDefn->format.video.nFrameWidth, + portDefn->format.video.nStride, + portDefn->format.video.nSliceHeight); +} + +void omx_vdec::append_terminator_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + if (!client_extradata || !extra) { + return; + } + extra->nSize = sizeof(OMX_OTHER_EXTRADATATYPE); + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->eType = OMX_ExtraDataNone; + extra->nDataSize = 0; + extra->data[0] = 0; + + print_debug_extradata(extra); +} + +OMX_ERRORTYPE omx_vdec::allocate_desc_buffer(OMX_U32 index) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (index >= drv_ctx.ip_buf.actualcount) + { + DEBUG_PRINT_ERROR("ERROR:Desc Buffer Index not found"); + return OMX_ErrorInsufficientResources; + } + if (m_desc_buffer_ptr == NULL) + { + m_desc_buffer_ptr = (desc_buffer_hdr*) \ + calloc( (sizeof(desc_buffer_hdr)), + drv_ctx.ip_buf.actualcount); + if (m_desc_buffer_ptr == NULL) + { + DEBUG_PRINT_ERROR("m_desc_buffer_ptr Allocation failed "); + return OMX_ErrorInsufficientResources; + } + } + + m_desc_buffer_ptr[index].buf_addr = (unsigned char *)malloc (DESC_BUFFER_SIZE * sizeof(OMX_U8)); + if (m_desc_buffer_ptr[index].buf_addr == NULL) + { + DEBUG_PRINT_ERROR("desc buffer Allocation failed "); + return OMX_ErrorInsufficientResources; + } + + return eRet; +} + +void omx_vdec::insert_demux_addr_offset(OMX_U32 address_offset) +{ + DEBUG_PRINT_LOW("Inserting address offset (%lu) at idx (%lu)", address_offset,m_demux_entries); + if (m_demux_entries < 8192) + { + m_demux_offsets[m_demux_entries++] = address_offset; + } + return; +} + +void omx_vdec::extract_demux_addr_offsets(OMX_BUFFERHEADERTYPE *buf_hdr) +{ + OMX_U32 bytes_to_parse = buf_hdr->nFilledLen; + OMX_U8 *buf = buf_hdr->pBuffer + buf_hdr->nOffset; + OMX_U32 index = 0; + + m_demux_entries = 0; + + while (index < bytes_to_parse) + { + if ( ((buf[index] == 0x00) && (buf[index+1] == 0x00) && + (buf[index+2] == 0x00) && (buf[index+3] == 0x01)) || + ((buf[index] == 0x00) && (buf[index+1] == 0x00) && + (buf[index+2] == 0x01)) ) + { + //Found start code, insert address offset + insert_demux_addr_offset(index); + if (buf[index+2] == 0x01) // 3 byte start code + index += 3; + else //4 byte start code + index += 4; + } + else + index++; + } + DEBUG_PRINT_LOW("Extracted (%lu) demux entry offsets",m_demux_entries); + return; +} + +OMX_ERRORTYPE omx_vdec::handle_demux_data(OMX_BUFFERHEADERTYPE *p_buf_hdr) +{ + //fix this, handle 3 byte start code, vc1 terminator entry + OMX_U8 *p_demux_data = NULL; + OMX_U32 desc_data = 0; + OMX_U32 start_addr = 0; + OMX_U32 nal_size = 0; + OMX_U32 suffix_byte = 0; + OMX_U32 demux_index = 0; + OMX_U32 buffer_index = 0; + + if (m_desc_buffer_ptr == NULL) + { + DEBUG_PRINT_ERROR("m_desc_buffer_ptr is NULL. Cannot append demux entries."); + return OMX_ErrorBadParameter; + } + + buffer_index = p_buf_hdr - ((OMX_BUFFERHEADERTYPE *)m_inp_mem_ptr); + if (buffer_index > drv_ctx.ip_buf.actualcount) + { + DEBUG_PRINT_ERROR("handle_demux_data:Buffer index is incorrect (%lu)", buffer_index); + return OMX_ErrorBadParameter; + } + + p_demux_data = (OMX_U8 *) m_desc_buffer_ptr[buffer_index].buf_addr; + + if ( ((OMX_U8*)p_demux_data == NULL) || + ((m_demux_entries * 16) + 1) > DESC_BUFFER_SIZE) + { + DEBUG_PRINT_ERROR("Insufficient buffer. Cannot append demux entries."); + return OMX_ErrorBadParameter; + } + else + { + for (; demux_index < m_demux_entries; demux_index++) + { + desc_data = 0; + start_addr = m_demux_offsets[demux_index]; + if (p_buf_hdr->pBuffer[m_demux_offsets[demux_index] + 2] == 0x01) + { + suffix_byte = p_buf_hdr->pBuffer[m_demux_offsets[demux_index] + 3]; + } + else + { + suffix_byte = p_buf_hdr->pBuffer[m_demux_offsets[demux_index] + 4]; + } + if (demux_index < (m_demux_entries - 1)) + { + nal_size = m_demux_offsets[demux_index + 1] - m_demux_offsets[demux_index] - 2; + } + else + { + nal_size = p_buf_hdr->nFilledLen - m_demux_offsets[demux_index] - 2; + } + DEBUG_PRINT_LOW("Start_addr(%d), suffix_byte(0x%x),nal_size(%lu),demux_index(%lu)", + start_addr, + (unsigned int)suffix_byte, + nal_size, + demux_index); + desc_data = (start_addr >> 3) << 1; + desc_data |= (start_addr & 7) << 21; + desc_data |= suffix_byte << 24; + + memcpy(p_demux_data, &desc_data, sizeof(OMX_U32)); + memcpy(p_demux_data + 4, &nal_size, sizeof(OMX_U32)); + memset(p_demux_data + 8, 0, sizeof(OMX_U32)); + memset(p_demux_data + 12, 0, sizeof(OMX_U32)); + + p_demux_data += 16; + } + if (codec_type_parse == CODEC_TYPE_VC1) + { + DEBUG_PRINT_LOW("VC1 terminator entry"); + desc_data = 0; + desc_data = 0x82 << 24; + memcpy(p_demux_data, &desc_data, sizeof(OMX_U32)); + memset(p_demux_data + 4, 0, sizeof(OMX_U32)); + memset(p_demux_data + 8, 0, sizeof(OMX_U32)); + memset(p_demux_data + 12, 0, sizeof(OMX_U32)); + p_demux_data += 16; + m_demux_entries++; + } + //Add zero word to indicate end of descriptors + memset(p_demux_data, 0, sizeof(OMX_U32)); + + m_desc_buffer_ptr[buffer_index].desc_data_size = (m_demux_entries * 16) + sizeof(OMX_U32); + DEBUG_PRINT_LOW("desc table data size=%lu", m_desc_buffer_ptr[buffer_index].desc_data_size); + } + memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) ); + m_demux_entries = 0; + DEBUG_PRINT_LOW("Demux table complete!"); + return OMX_ErrorNone; +} + +omx_vdec::allocate_color_convert_buf::allocate_color_convert_buf() +{ + enabled = false; + omx = NULL; + init_members(); + ColorFormat = OMX_COLOR_FormatMax; +} + +void omx_vdec::allocate_color_convert_buf::set_vdec_client(void *client) +{ + omx = reinterpret_cast<omx_vdec*>(client); +} + +void omx_vdec::allocate_color_convert_buf::init_members() { + allocated_count = 0; + buffer_size_req = 0; + buffer_alignment_req = 0; + memset(m_platform_list_client,0,sizeof(m_platform_list_client)); + memset(m_platform_entry_client,0,sizeof(m_platform_entry_client)); + memset(m_pmem_info_client,0,sizeof(m_pmem_info_client)); + memset(m_out_mem_ptr_client,0,sizeof(m_out_mem_ptr_client)); +#ifdef USE_ION + memset(op_buf_ion_info,0,sizeof(m_platform_entry_client)); +#endif + for (int i = 0; i < MAX_COUNT;i++) + pmem_fd[i] = -1; +} + +omx_vdec::allocate_color_convert_buf::~allocate_color_convert_buf() { + c2d.destroy(); +} + +bool omx_vdec::allocate_color_convert_buf::update_buffer_req() +{ + bool status = true; + unsigned int src_size = 0, destination_size = 0; + OMX_COLOR_FORMATTYPE drv_color_format; + if (!omx){ + DEBUG_PRINT_ERROR("Invalid client in color convert"); + return false; + } + if (!enabled){ + DEBUG_PRINT_ERROR("No color conversion required"); + return status; + } + pthread_mutex_lock(&omx->c_lock); + if (omx->drv_ctx.output_format != VDEC_YUV_FORMAT_NV12 && + ColorFormat != OMX_COLOR_FormatYUV420Planar) { + DEBUG_PRINT_ERROR("update_buffer_req: Unsupported color conversion"); + status = false; + goto fail_update_buf_req; + } + c2d.close(); + status = c2d.open(omx->drv_ctx.video_resolution.frame_height, + omx->drv_ctx.video_resolution.frame_width, + NV12_128m,YCbCr420P); + if (status) { + status = c2d.get_buffer_size(C2D_INPUT,src_size); + if (status) + status = c2d.get_buffer_size(C2D_OUTPUT,destination_size); + } + if (status) { + if (!src_size || src_size > omx->drv_ctx.op_buf.buffer_size || + !destination_size) { + DEBUG_PRINT_ERROR("ERROR: Size mismatch in C2D src_size %d" + "driver size %d destination size %d", + src_size,omx->drv_ctx.op_buf.buffer_size,destination_size); + status = false; + c2d.close(); + buffer_size_req = 0; + } else { + buffer_size_req = destination_size; + if (buffer_size_req < omx->drv_ctx.op_buf.buffer_size) + buffer_size_req = omx->drv_ctx.op_buf.buffer_size; + if (buffer_alignment_req < omx->drv_ctx.op_buf.alignment) + buffer_alignment_req = omx->drv_ctx.op_buf.alignment; + } + } +fail_update_buf_req: + pthread_mutex_unlock(&omx->c_lock); + return status; +} + +bool omx_vdec::allocate_color_convert_buf::set_color_format( + OMX_COLOR_FORMATTYPE dest_color_format) +{ + bool status = true; + OMX_COLOR_FORMATTYPE drv_color_format; + if (!omx){ + DEBUG_PRINT_ERROR("Invalid client in color convert"); + return false; + } + pthread_mutex_lock(&omx->c_lock); + if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12) + drv_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + else { + DEBUG_PRINT_ERROR("Incorrect color format"); + status = false; + } + if (status && (drv_color_format != dest_color_format)) { + DEBUG_PRINT_LOW("Enabling C2D"); + if (dest_color_format != OMX_COLOR_FormatYUV420Planar) { + DEBUG_PRINT_ERROR("Unsupported color format for c2d"); + status = false; + } else { + ColorFormat = OMX_COLOR_FormatYUV420Planar; + if (enabled) + c2d.destroy(); + enabled = false; + if (!c2d.init()) { + DEBUG_PRINT_ERROR("open failed for c2d"); + status = false; + } else + enabled = true; + } + } else { + if (enabled) + c2d.destroy(); + enabled = false; + } + pthread_mutex_unlock(&omx->c_lock); + return status; +} + +OMX_BUFFERHEADERTYPE* omx_vdec::allocate_color_convert_buf::get_il_buf_hdr() +{ + if (!omx){ + DEBUG_PRINT_ERROR("Invalid param get_buf_hdr"); + return NULL; + } + if (!enabled) + return omx->m_out_mem_ptr; + return m_out_mem_ptr_client; +} + +OMX_BUFFERHEADERTYPE* omx_vdec::allocate_color_convert_buf::get_il_buf_hdr +(OMX_BUFFERHEADERTYPE *bufadd) +{ + if (!omx){ + DEBUG_PRINT_ERROR("Invalid param get_buf_hdr"); + return NULL; + } + if (!enabled) + return bufadd; + + unsigned index = 0; + index = bufadd - omx->m_out_mem_ptr; + if (index < omx->drv_ctx.op_buf.actualcount) { + m_out_mem_ptr_client[index].nFlags = (bufadd->nFlags & OMX_BUFFERFLAG_EOS); + m_out_mem_ptr_client[index].nTimeStamp = bufadd->nTimeStamp; + bool status; + if (!omx->in_reconfig && !omx->output_flush_progress && bufadd->nFilledLen) { + pthread_mutex_lock(&omx->c_lock); + status = c2d.convert(omx->drv_ctx.ptr_outputbuffer[index].pmem_fd, + omx->m_out_mem_ptr->pBuffer, bufadd->pBuffer,pmem_fd[index], + pmem_baseaddress[index], pmem_baseaddress[index]); + pthread_mutex_unlock(&omx->c_lock); + m_out_mem_ptr_client[index].nFilledLen = buffer_size_req; + if (!status){ + DEBUG_PRINT_ERROR("Failed color conversion %d", status); + m_out_mem_ptr_client[index].nFilledLen = 0; + return &m_out_mem_ptr_client[index]; + } + } else + m_out_mem_ptr_client[index].nFilledLen = 0; + return &m_out_mem_ptr_client[index]; + } + DEBUG_PRINT_ERROR("Index messed up in the get_il_buf_hdr"); + return NULL; +} + +OMX_BUFFERHEADERTYPE* omx_vdec::allocate_color_convert_buf::get_dr_buf_hdr +(OMX_BUFFERHEADERTYPE *bufadd) +{ + if (!omx){ + DEBUG_PRINT_ERROR("Invalid param get_buf_hdr"); + return NULL; + } + if (!enabled) + return bufadd; + unsigned index = 0; + index = bufadd - m_out_mem_ptr_client; + if (index < omx->drv_ctx.op_buf.actualcount) { + return &omx->m_out_mem_ptr[index]; + } + DEBUG_PRINT_ERROR("Index messed up in the get_dr_buf_hdr"); + return NULL; +} +bool omx_vdec::allocate_color_convert_buf::get_buffer_req(unsigned int &buffer_size) +{ + bool status = true; + pthread_mutex_lock(&omx->c_lock); + if (!enabled) + buffer_size = omx->drv_ctx.op_buf.buffer_size; + else { + if (!c2d.get_buffer_size(C2D_OUTPUT,buffer_size)) { + DEBUG_PRINT_ERROR("Get buffer size failed"); + status = false; + goto fail_get_buffer_size; + } + } + if (buffer_size < omx->drv_ctx.op_buf.buffer_size) + buffer_size = omx->drv_ctx.op_buf.buffer_size; + if (buffer_alignment_req < omx->drv_ctx.op_buf.alignment) + buffer_alignment_req = omx->drv_ctx.op_buf.alignment; +fail_get_buffer_size: + pthread_mutex_unlock(&omx->c_lock); + return status; +} +OMX_ERRORTYPE omx_vdec::allocate_color_convert_buf::free_output_buffer( + OMX_BUFFERHEADERTYPE *bufhdr) +{ + unsigned int index = 0; + + if (!enabled) + return omx->free_output_buffer(bufhdr); + if (enabled && omx->is_component_secure()) + return OMX_ErrorNone; + if (!allocated_count || !bufhdr) { + DEBUG_PRINT_ERROR("Color convert no buffer to be freed %p",bufhdr); + return OMX_ErrorBadParameter; + } + index = bufhdr - m_out_mem_ptr_client; + if (index >= omx->drv_ctx.op_buf.actualcount){ + DEBUG_PRINT_ERROR("Incorrect index color convert free_output_buffer"); + return OMX_ErrorBadParameter; + } + if (pmem_fd[index] > 0) { + munmap(pmem_baseaddress[index], buffer_size_req); + close(pmem_fd[index]); + } + pmem_fd[index] = -1; +#ifdef USE_ION + omx->free_ion_memory(&op_buf_ion_info[index]); +#endif + m_heap_ptr[index].video_heap_ptr = NULL; + if (allocated_count > 0) + allocated_count--; + else + allocated_count = 0; + if (!allocated_count) { + pthread_mutex_lock(&omx->c_lock); + c2d.close(); + init_members(); + pthread_mutex_unlock(&omx->c_lock); + } + return omx->free_output_buffer(&omx->m_out_mem_ptr[index]); +} + +OMX_ERRORTYPE omx_vdec::allocate_color_convert_buf::allocate_buffers_color_convert(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr,OMX_U32 port,OMX_PTR appData,OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (!enabled){ + eRet = omx->allocate_output_buffer(hComp,bufferHdr,port,appData,bytes); + return eRet; + } + if (enabled && omx->is_component_secure()) { + DEBUG_PRINT_ERROR("Notin color convert mode secure_mode %d", + omx->is_component_secure()); + return OMX_ErrorUnsupportedSetting; + } + if (!bufferHdr || bytes > buffer_size_req) { + DEBUG_PRINT_ERROR("Invalid params allocate_buffers_color_convert %p", bufferHdr); + DEBUG_PRINT_ERROR("color_convert buffer_size_req %d bytes %lu", + buffer_size_req,bytes); + return OMX_ErrorBadParameter; + } + if (allocated_count >= omx->drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("Actual count err in allocate_buffers_color_convert"); + return OMX_ErrorInsufficientResources; + } + OMX_BUFFERHEADERTYPE *temp_bufferHdr = NULL; + eRet = omx->allocate_output_buffer(hComp,&temp_bufferHdr, + port,appData,omx->drv_ctx.op_buf.buffer_size); + if (eRet != OMX_ErrorNone || !temp_bufferHdr){ + DEBUG_PRINT_ERROR("Buffer allocation failed color_convert"); + return eRet; + } + if ((temp_bufferHdr - omx->m_out_mem_ptr) >= + (int)omx->drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("Invalid header index %d", + (temp_bufferHdr - omx->m_out_mem_ptr)); + return OMX_ErrorUndefined; + } + unsigned int i = allocated_count; +#ifdef USE_ION + op_buf_ion_info[i].ion_device_fd = omx->alloc_map_ion_memory( + buffer_size_req,buffer_alignment_req, + &op_buf_ion_info[i].ion_alloc_data,&op_buf_ion_info[i].fd_ion_data, + 0); + pmem_fd[i] = op_buf_ion_info[i].fd_ion_data.fd; + if (op_buf_ion_info[i].ion_device_fd < 0) { + DEBUG_PRINT_ERROR("alloc_map_ion failed in color_convert"); + return OMX_ErrorInsufficientResources; + } + pmem_baseaddress[i] = (unsigned char *)mmap(NULL,buffer_size_req, + PROT_READ|PROT_WRITE,MAP_SHARED,pmem_fd[i],0); + + if (pmem_baseaddress[i] == MAP_FAILED) { + DEBUG_PRINT_ERROR("MMAP failed for Size %d",buffer_size_req); + close(pmem_fd[i]); + omx->free_ion_memory(&op_buf_ion_info[i]); + return OMX_ErrorInsufficientResources; + } + m_heap_ptr[i].video_heap_ptr = new VideoHeap ( + op_buf_ion_info[i].ion_device_fd,buffer_size_req, + pmem_baseaddress[i],op_buf_ion_info[i].ion_alloc_data.handle,pmem_fd[i]); +#endif + m_pmem_info_client[i].pmem_fd = (unsigned long)m_heap_ptr[i].video_heap_ptr.get(); + m_pmem_info_client[i].offset = 0; + m_platform_entry_client[i].entry = (void *)&m_pmem_info_client[i]; + m_platform_entry_client[i].type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; + m_platform_list_client[i].nEntries = 1; + m_platform_list_client[i].entryList = &m_platform_entry_client[i]; + m_out_mem_ptr_client[i].pOutputPortPrivate = NULL; + m_out_mem_ptr_client[i].nAllocLen = buffer_size_req; + m_out_mem_ptr_client[i].nFilledLen = 0; + m_out_mem_ptr_client[i].nFlags = 0; + m_out_mem_ptr_client[i].nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + m_out_mem_ptr_client[i].nSize = sizeof(OMX_BUFFERHEADERTYPE); + m_out_mem_ptr_client[i].nVersion.nVersion = OMX_SPEC_VERSION; + m_out_mem_ptr_client[i].pPlatformPrivate = &m_platform_list_client[i]; + m_out_mem_ptr_client[i].pBuffer = pmem_baseaddress[i]; + m_out_mem_ptr_client[i].pAppPrivate = appData; + *bufferHdr = &m_out_mem_ptr_client[i]; + DEBUG_PRINT_ERROR("IL client buffer header %p", *bufferHdr); + allocated_count++; + return eRet; +} + +bool omx_vdec::is_component_secure() +{ + return secure_mode; +} + +bool omx_vdec::allocate_color_convert_buf::get_color_format(OMX_COLOR_FORMATTYPE &dest_color_format) +{ + bool status = true; + if (!enabled) { + if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12) + dest_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + else + status = false; + } else { + if (ColorFormat != OMX_COLOR_FormatYUV420Planar) { + status = false; + } else + dest_color_format = OMX_COLOR_FormatYUV420Planar; + } + return status; +} + +void omx_vdec::buf_ref_add(int index, OMX_U32 fd, OMX_U32 offset) +{ + int i = 0; + bool buf_present = false; + + pthread_mutex_lock(&m_lock); + if (out_dynamic_list[index].dup_fd && + (out_dynamic_list[index].fd != fd) && + (out_dynamic_list[index].offset != offset)) + { + DEBUG_PRINT_LOW("buf_ref_add error: index %d taken by fd = %lu offset = %lu, new fd %lu offset %lu", + index, out_dynamic_list[index].fd, out_dynamic_list[index].offset, fd, offset); + pthread_mutex_unlock(&m_lock); + return; + } + + if (out_dynamic_list[index].dup_fd == 0) + { + out_dynamic_list[index].fd = fd; + out_dynamic_list[index].offset = offset; + out_dynamic_list[index].dup_fd = dup(fd); + } + out_dynamic_list[index].ref_count++; + DEBUG_PRINT_LOW("buf_ref_add: [ADDED] fd = %lu ref_count = %lu", + out_dynamic_list[index].fd, out_dynamic_list[index].ref_count); + pthread_mutex_unlock(&m_lock); +} + +void omx_vdec::buf_ref_remove(OMX_U32 fd, OMX_U32 offset) +{ + unsigned long i = 0; + pthread_mutex_lock(&m_lock); + for (i = 0; i < drv_ctx.op_buf.actualcount; i++) { + //check the buffer fd, offset, uv addr with list contents + //If present decrement reference. + if ((out_dynamic_list[i].fd == fd) && + (out_dynamic_list[i].offset == offset)) { + out_dynamic_list[i].ref_count--; + if (out_dynamic_list[i].ref_count == 0) { + close(out_dynamic_list[i].dup_fd); + DEBUG_PRINT_LOW("buf_ref_remove: [REMOVED] fd = %lu ref_count = %lu", + out_dynamic_list[i].fd, out_dynamic_list[i].ref_count); + out_dynamic_list[i].dup_fd = 0; + out_dynamic_list[i].fd = 0; + out_dynamic_list[i].offset = 0; + + munmap(drv_ctx.ptr_outputbuffer[i].bufferaddr, + drv_ctx.ptr_outputbuffer[i].mmaped_size); + DEBUG_PRINT_LOW("unmapped dynamic buffer idx %lu pBuffer %p", + i, drv_ctx.ptr_outputbuffer[i].bufferaddr); + + drv_ctx.ptr_outputbuffer[i].bufferaddr = NULL; + drv_ctx.ptr_outputbuffer[i].offset = 0; + drv_ctx.ptr_outputbuffer[i].mmaped_size = 0; + if (m_pSwVdecOpBuffer) + { + m_pSwVdecOpBuffer[i].pBuffer = NULL; + m_pSwVdecOpBuffer[i].nSize = 0; + } + } + break; + } + } + if (i >= drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("Error - could not remove ref, no match with any entry in list"); + } + pthread_mutex_unlock(&m_lock); +} + +OMX_ERRORTYPE omx_vdec::get_buffer_req_swvdec() +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if (!m_pSwVdec) + { + eRet=get_buffer_req(&drv_ctx.ip_buf); + eRet=get_buffer_req(&drv_ctx.op_buf); + return eRet; + } + + SWVDEC_PROP property; + if (m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) + { + property.ePropId = SWVDEC_PROP_ID_IPBUFFREQ; + SWVDEC_STATUS sRet = SwVdec_GetProperty(m_pSwVdec, &property); + if (sRet != SWVDEC_S_SUCCESS) + { + return OMX_ErrorUndefined; + } + else + { + drv_ctx.ip_buf.buffer_size = property.uProperty.sIpBuffReq.nSize; + drv_ctx.ip_buf.mincount = property.uProperty.sIpBuffReq.nMinCount; + drv_ctx.ip_buf.actualcount = property.uProperty.sIpBuffReq.nMinCount; + DEBUG_PRINT_ERROR("swvdec input buf size %d count %d",drv_ctx.op_buf.buffer_size,drv_ctx.op_buf.actualcount); + } + } + + /* buffer requirement for out*/ + if ( (false == m_smoothstreaming_mode) || + ((drv_ctx.video_resolution.frame_height > m_smoothstreaming_width) && + (drv_ctx.video_resolution.frame_width > m_smoothstreaming_height)) + ) + { + property.ePropId = SWVDEC_PROP_ID_OPBUFFREQ; + SWVDEC_STATUS sRet = SwVdec_GetProperty(m_pSwVdec, &property); + if (sRet != SWVDEC_S_SUCCESS) + { + return OMX_ErrorUndefined; + } + else + { + int client_extra_data_size = 0; + if (client_extradata & OMX_FRAMEINFO_EXTRADATA) + { + DEBUG_PRINT_HIGH("Frame info extra data enabled!"); + client_extra_data_size += OMX_FRAMEINFO_EXTRADATA_SIZE; + } + if (client_extradata & OMX_INTERLACE_EXTRADATA) + { + DEBUG_PRINT_HIGH("OMX_INTERLACE_EXTRADATA!"); + client_extra_data_size += OMX_INTERLACE_EXTRADATA_SIZE; + } + if (client_extradata & OMX_PORTDEF_EXTRADATA) + { + client_extra_data_size += OMX_PORTDEF_EXTRADATA_SIZE; + DEBUG_PRINT_HIGH("Smooth streaming enabled extra_data_size=%d", + client_extra_data_size); + } + if (client_extra_data_size) + { + client_extra_data_size += sizeof(OMX_OTHER_EXTRADATATYPE); //Space for terminator + } + drv_ctx.op_buf.buffer_size = property.uProperty.sOpBuffReq.nSize + client_extra_data_size; + drv_ctx.op_buf.mincount = property.uProperty.sOpBuffReq.nMinCount; + drv_ctx.op_buf.actualcount = property.uProperty.sOpBuffReq.nMinCount; + DEBUG_PRINT_HIGH("swvdec opbuf size %lu extradata size %d total size %d count %d", + property.uProperty.sOpBuffReq.nSize, client_extra_data_size, + drv_ctx.op_buf.buffer_size,drv_ctx.op_buf.actualcount); + } + } + + if (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + return get_buffer_req(&drv_ctx.interm_op_buf); + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::set_buffer_req_swvdec(vdec_allocatorproperty *buffer_prop) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if (!m_pSwVdec) + { + eRet = set_buffer_req(buffer_prop); + return eRet; + } + + unsigned buf_size = 0; + SWVDEC_PROP property; + SWVDEC_STATUS sRet = SWVDEC_S_SUCCESS; + + DEBUG_PRINT_HIGH("set_buffer_req_swvdec IN: ActCnt(%d) Size(%d), buffer type %d", + buffer_prop->actualcount, buffer_prop->buffer_size, buffer_prop->buffer_type); + + buf_size = (buffer_prop->buffer_size + buffer_prop->alignment - 1)&(~(buffer_prop->alignment - 1)); + if (buf_size != buffer_prop->buffer_size) + { + DEBUG_PRINT_ERROR("Buffer size alignment error: Requested(%d) Required(%d)", + buffer_prop->buffer_size, buf_size); + eRet = OMX_ErrorBadParameter; + } + else + { + property.uProperty.sIpBuffReq.nSize = buffer_prop->buffer_size; + property.uProperty.sIpBuffReq.nMaxCount = buffer_prop->actualcount; + property.uProperty.sIpBuffReq.nMinCount = buffer_prop->actualcount; + + if(buffer_prop->buffer_type == VDEC_BUFFER_TYPE_INPUT) + { + property.ePropId = SWVDEC_PROP_ID_IPBUFFREQ; + DEBUG_PRINT_HIGH("swvdec input Buffer Size = %lu Count = %d",property.uProperty.sIpBuffReq.nSize, buffer_prop->mincount); + } + else if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) + { + property.ePropId = SWVDEC_PROP_ID_OPBUFFREQ; + DEBUG_PRINT_HIGH("swvdec output Buffer Size = %lu and Count = %d",property.uProperty.sOpBuffReq.nSize, buffer_prop->actualcount); + } + else + { + eRet = OMX_ErrorBadParameter; + } + + if(eRet==OMX_ErrorNone) + { + sRet = SwVdec_SetProperty(m_pSwVdec, &property); + } + + if (sRet != SWVDEC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("Set buffer requirements from ARM codec failed"); + return OMX_ErrorInsufficientResources; + } + } + + if ((m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) && + (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT)) + { + // need to update extradata buffers also + drv_ctx.extradata_info.size = buffer_prop->actualcount * drv_ctx.extradata_info.buffer_size; + drv_ctx.extradata_info.count = buffer_prop->actualcount; + eRet = set_buffer_req(&drv_ctx.interm_op_buf); + } + + return eRet; +} + +/* ====================================================================== +FUNCTION +omx_vdec::empty_this_buffer_proxy + +DESCRIPTION +This routine is used to push the encoded video frames to +the video decoder. + +PARAMETERS +None. + +RETURN VALUE +OMX Error None if everything went successful. + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::empty_this_buffer_proxy_swvdec(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + (void)hComp; + int push_cnt = 0,i=0; + unsigned nPortIndex = 0; + OMX_ERRORTYPE ret = OMX_ErrorNone; + struct vdec_input_frameinfo frameinfo; + struct vdec_bufferpayload *temp_buffer; + struct vdec_seqheader seq_header; + bool port_setting_changed = true; + bool not_coded_vop = false; + + /*Should we generate a Aync error event*/ + if (buffer == NULL) + { + DEBUG_PRINT_ERROR("ERROR:empty_this_buffer_proxy is invalid"); + return OMX_ErrorBadParameter; + } + + nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)m_interm_mem_ptr); + + if (nPortIndex > drv_ctx.interm_op_buf.actualcount) + { + DEBUG_PRINT_ERROR("ERROR:empty_this_buffer_proxy_swvdec invalid nPortIndex[%u]", + nPortIndex); + return OMX_ErrorBadParameter; + } + + /* return zero length and not an EOS buffer */ + if ( (buffer->nFilledLen == 0) && + ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == 0)) + { + DEBUG_PRINT_HIGH("return zero legth buffer"); + pthread_mutex_lock(&m_lock); + m_interm_buf_state[nPortIndex] = WITH_SWVDEC; + pthread_mutex_unlock(&m_lock); + post_event ((unsigned long)buffer,(unsigned long)VDEC_S_SUCCESS, + (unsigned long)OMX_COMPONENT_GENERATE_EBD_SWVDEC); + return OMX_ErrorNone; + } + + if(m_interm_bEnabled != OMX_TRUE || m_interm_flush_swvdec_progress == true) + { + DEBUG_PRINT_ERROR("empty_this_buffer_proxy_swvdec called when swvdec flush is in progress"); + return OMX_ErrorNone; + } + + // send this buffer to swvdec + DEBUG_PRINT_LOW("empty_this_buffer_proxy_swvdec bufHdr %p pBuffer %p nFilledLen %lu m_pSwVdecIpBuffer %p, idx %d nFlags %x", + buffer, buffer->pBuffer, buffer->nFilledLen, m_pSwVdecIpBuffer, nPortIndex, (unsigned int)buffer->nFlags); + m_pSwVdecIpBuffer[nPortIndex].nFlags = buffer->nFlags; + m_pSwVdecIpBuffer[nPortIndex].nFilledLen = buffer->nFilledLen; + m_pSwVdecIpBuffer[nPortIndex].nIpTimestamp = buffer->nTimeStamp; + if (SwVdec_EmptyThisBuffer(m_pSwVdec, &m_pSwVdecIpBuffer[nPortIndex]) != SWVDEC_S_SUCCESS) { + ret = OMX_ErrorBadParameter; + } + pthread_mutex_lock(&m_lock); + m_interm_buf_state[nPortIndex] = WITH_SWVDEC; + pthread_mutex_unlock(&m_lock); + return ret; +} + +OMX_ERRORTYPE omx_vdec::empty_buffer_done_swvdec(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + (void)hComp; + int idx = buffer - m_interm_mem_ptr; + if (buffer == NULL || idx > (int)drv_ctx.interm_op_buf.actualcount) + { + DEBUG_PRINT_ERROR("empty_buffer_done_swvdec: ERROR bufhdr = %p", buffer); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("empty_buffer_done_swvdec: bufhdr = %p, bufhdr->pBuffer = %p idx %d", + buffer, buffer->pBuffer, idx); + + buffer->nFilledLen = 0; + pthread_mutex_lock(&m_lock); + if (m_interm_buf_state[idx] != WITH_SWVDEC) + { + DEBUG_PRINT_ERROR("empty_buffer_done_swvdec error: bufhdr = %p, idx %d, buffer not with swvdec ",buffer, idx); + pthread_mutex_unlock(&m_lock); + return OMX_ErrorBadParameter; + } + m_interm_buf_state[idx] = WITH_COMPONENT; + pthread_mutex_unlock(&m_lock); + + if(m_interm_bEnabled != OMX_TRUE || + output_flush_progress == true || + m_interm_flush_dsp_progress == true || + m_interm_flush_swvdec_progress == true) + { + DEBUG_PRINT_HIGH("empty_buffer_done_swvdec: Buffer (%p) flushed idx %d", buffer, idx); + buffer->nFilledLen = 0; + buffer->nTimeStamp = 0; + buffer->nFlags &= ~OMX_BUFFERFLAG_EXTRADATA; + buffer->nFlags &= ~QOMX_VIDEO_BUFFERFLAG_EOSEQ; + buffer->nFlags &= ~OMX_BUFFERFLAG_DATACORRUPT; + return OMX_ErrorNone; + } + + // call DSP FTB for the intermediate buffer. post event to the command queue do it asynchrounously + if (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY && in_reconfig != true) + { + post_event((unsigned long)&m_cmp, (unsigned long)buffer, (unsigned long)OMX_COMPONENT_GENERATE_FTB_DSP); + } + else if (m_swvdec_mode == SWVDEC_MODE_PARSE_DECODE) + { + post_event((unsigned long)&m_cmp, (unsigned long)buffer, (unsigned long)OMX_COMPONENT_GENERATE_EBD); + } + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::fill_all_buffers_proxy_dsp(OMX_HANDLETYPE hComp) +{ + int idx = 0; + OMX_ERRORTYPE nRet = OMX_ErrorNone; + if (m_fill_internal_bufers == OMX_FALSE) + { + return nRet; + } + + if (m_interm_mem_ptr == NULL) + { + DEBUG_PRINT_ERROR("fill_all_buffers_proxy_dsp called in bad state"); + return nRet; + } + m_fill_internal_bufers = OMX_FALSE; + + for (idx=0; idx < (int)drv_ctx.interm_op_buf.actualcount; idx++) + { + pthread_mutex_lock(&m_lock); + if (m_interm_buf_state[idx] == WITH_COMPONENT) + { + OMX_BUFFERHEADERTYPE* bufHdr = m_interm_mem_ptr + idx; + nRet = fill_this_buffer_proxy_dsp(hComp, bufHdr); + if (nRet != OMX_ErrorNone) + { + DEBUG_PRINT_ERROR("fill_this_buffer_proxy_dsp failed for buff %d bufHdr %p pBuffer %p", + idx, bufHdr, bufHdr->pBuffer); + break; + } + } + pthread_mutex_unlock(&m_lock); + } + return nRet; +} + + +/* ====================================================================== +FUNCTION +omx_vdec::fill_this_buffer_proxy_dsp + +DESCRIPTION +IL client uses this method to release the frame buffer +after displaying them. + +PARAMETERS +None. + +RETURN VALUE +true/false + +========================================================================== */ +OMX_ERRORTYPE omx_vdec::fill_this_buffer_proxy_dsp( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* bufferAdd) +{ + (void)hComp; + OMX_ERRORTYPE nRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *buffer = bufferAdd; + unsigned nPortIndex = 0; + struct vdec_fillbuffer_cmd fillbuffer; + struct vdec_bufferpayload *ptr_outputbuffer = NULL; + struct vdec_output_frameinfo *ptr_respbuffer = NULL; + int rc = 0; + + if(m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("FTB in Invalid State"); + return OMX_ErrorInvalidState; + } + + nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)m_interm_mem_ptr); + + if (bufferAdd == NULL || nPortIndex > drv_ctx.interm_op_buf.actualcount) { + DEBUG_PRINT_ERROR("FTBProxyDSP: bufhdr = %p, nPortIndex %u bufCount %u", + bufferAdd, nPortIndex, drv_ctx.interm_op_buf.actualcount); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("fill_this_buffer_proxy_dsp: bufhdr = %p,pBuffer = %p, idx %d, state %d", + bufferAdd, bufferAdd->pBuffer, nPortIndex, m_interm_buf_state[nPortIndex]); + + pthread_mutex_lock(&m_lock); + if (m_interm_buf_state[nPortIndex] == WITH_DSP) + { + DEBUG_PRINT_HIGH("fill_this_buffer_proxy_dsp: buffer is with dsp"); + pthread_mutex_unlock(&m_lock); + return OMX_ErrorNone; + } + pthread_mutex_unlock(&m_lock); + + ptr_respbuffer = (struct vdec_output_frameinfo*)buffer->pOutputPortPrivate; + if (ptr_respbuffer) + { + ptr_outputbuffer = (struct vdec_bufferpayload*)ptr_respbuffer->client_data; + } + + if (ptr_respbuffer == NULL || ptr_outputbuffer == NULL) + { + DEBUG_PRINT_ERROR("resp buffer or outputbuffer is NULL"); + buffer->nFilledLen = 0; + return OMX_ErrorBadParameter; + } + + if(m_interm_bEnabled != OMX_TRUE || m_interm_flush_dsp_progress == true) + { + DEBUG_PRINT_ERROR("fill_this_buffer_proxy_dsp called when dsp flush in progress"); + buffer->nFilledLen = 0; + return OMX_ErrorNone; + } + + memcpy (&fillbuffer.buffer,ptr_outputbuffer, + sizeof(struct vdec_bufferpayload)); + fillbuffer.client_data = bufferAdd; + + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + memset( (void *)&buf, 0, sizeof(buf)); + memset( (void *)plane, 0, (sizeof(struct v4l2_plane)*VIDEO_MAX_PLANES)); + int extra_idx = 0; + + buf.index = nPortIndex; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].bytesused = buffer->nFilledLen; + plane[0].length = drv_ctx.interm_op_buf.buffer_size; + plane[0].m.userptr = + (unsigned long)drv_ctx.ptr_interm_outputbuffer[nPortIndex].bufferaddr - + (unsigned long)drv_ctx.ptr_interm_outputbuffer[nPortIndex].offset; + + plane[0].reserved[0] = drv_ctx.ptr_interm_outputbuffer[nPortIndex].pmem_fd; + plane[0].reserved[1] = drv_ctx.ptr_interm_outputbuffer[nPortIndex].offset; + plane[0].data_offset = 0; + + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].bytesused = 0; + plane[extra_idx].length = drv_ctx.extradata_info.buffer_size; + plane[extra_idx].m.userptr = (long unsigned int) (drv_ctx.extradata_info.uaddr + nPortIndex * drv_ctx.extradata_info.buffer_size); + plane[extra_idx].reserved[0] = drv_ctx.extradata_info.ion.fd_ion_data.fd; + plane[extra_idx].reserved[1] = nPortIndex * drv_ctx.extradata_info.buffer_size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index higher than expected: %d", extra_idx); + return OMX_ErrorBadParameter; + } + + buf.m.planes = plane; + buf.length = drv_ctx.num_planes; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_QBUF, &buf); + if (rc) { + DEBUG_PRINT_ERROR("Failed to qbuf to driver"); + return OMX_ErrorBadParameter; + } + + pthread_mutex_lock(&m_lock); + m_interm_buf_state[nPortIndex] = WITH_DSP; + pthread_mutex_unlock(&m_lock); + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::fill_buffer_done_dsp(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer) +{ + (void)hComp; + int idx = buffer - m_interm_mem_ptr; + if (!buffer || idx >= (int)drv_ctx.interm_op_buf.actualcount) + { + DEBUG_PRINT_ERROR("[FBD] ERROR in ptr(%p), m_interm_mem_ptr(%p) idx %d", buffer, m_interm_mem_ptr, idx); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("fill_buffer_done_dsp: bufhdr = %p, bufhdr->pBuffer = %p, idx %d nFilledLen %lu nFlags %x", + buffer, buffer->pBuffer, idx, buffer->nFilledLen, (unsigned int)buffer->nFlags); + + pthread_mutex_lock(&m_lock); + if (m_interm_buf_state[idx] != WITH_DSP) + { + DEBUG_PRINT_ERROR("fill_buffer_done_dsp error: bufhdr = %p, idx %d, buffer not with dsp", buffer, idx); + pthread_mutex_unlock(&m_lock); + return OMX_ErrorBadParameter; + } + m_interm_buf_state[idx] = WITH_COMPONENT; + pthread_mutex_unlock(&m_lock); + + if (m_interm_bEnabled != OMX_TRUE || + output_flush_progress == true || + m_interm_flush_dsp_progress == true || + m_interm_flush_swvdec_progress == true) + { + DEBUG_PRINT_HIGH("fill_buffer_done_dsp: Buffer (%p) flushed idx %d", buffer, idx); + buffer->nFilledLen = 0; + buffer->nTimeStamp = 0; + buffer->nFlags &= ~OMX_BUFFERFLAG_EXTRADATA; + buffer->nFlags &= ~QOMX_VIDEO_BUFFERFLAG_EOSEQ; + buffer->nFlags &= ~OMX_BUFFERFLAG_DATACORRUPT; + return OMX_ErrorNone; + } + + if (buffer->nFlags & OMX_BUFFERFLAG_EOS) + { + DEBUG_PRINT_HIGH("interm EOS has been reached"); + + if (psource_frame) + { + m_cb.EmptyBufferDone(&m_cmp, m_app_data, psource_frame); + psource_frame = NULL; + } + if (pdest_frame) + { + pdest_frame->nFilledLen = 0; + m_input_free_q.insert_entry((unsigned long) pdest_frame,(unsigned long)NULL, + (unsigned long)NULL); + pdest_frame = NULL; + } + } + + if (m_debug.im_buffer_log) + { + log_im_buffer(buffer); + } + + post_event((unsigned long)&m_cmp, (unsigned long)buffer, (unsigned long)OMX_COMPONENT_GENERATE_ETB_SWVDEC); + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::allocate_interm_buffer(OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr= NULL; // buffer header + unsigned i= 0; // Temporary counter + struct vdec_setbuffer_cmd setbuffers; + int extra_idx = 0; + int heap_id = 0; + + int ion_device_fd =-1; + struct ion_allocation_data ion_alloc_data; + struct ion_fd_data fd_ion_data; + +#ifdef _HEVC_USE_ADSP_HEAP_ + heap_id = ION_ADSP_HEAP_ID; +#else + heap_id = ION_IOMMU_HEAP_ID; +#endif + + if(!m_interm_mem_ptr) + { + DEBUG_PRINT_HIGH("Allocate interm buffer Header: Cnt(%d) Sz(%d)", + drv_ctx.interm_op_buf.actualcount, drv_ctx.interm_op_buf.buffer_size); + + int nBufHdrSize = drv_ctx.interm_op_buf.actualcount * sizeof(OMX_BUFFERHEADERTYPE); + m_interm_mem_ptr = (OMX_BUFFERHEADERTYPE *)calloc(nBufHdrSize,1); + + drv_ctx.ptr_interm_outputbuffer = (struct vdec_bufferpayload *) + calloc (sizeof(struct vdec_bufferpayload), drv_ctx.interm_op_buf.actualcount); + drv_ctx.ptr_interm_respbuffer = (struct vdec_output_frameinfo *) + calloc (sizeof (struct vdec_output_frameinfo), drv_ctx.interm_op_buf.actualcount); + drv_ctx.interm_op_buf_ion_info = (struct vdec_ion *) + calloc (sizeof(struct vdec_ion), drv_ctx.interm_op_buf.actualcount); + m_pSwVdecIpBuffer = (SWVDEC_IPBUFFER *)calloc(sizeof(SWVDEC_IPBUFFER), drv_ctx.interm_op_buf.actualcount); + + if (m_interm_mem_ptr == NULL || + drv_ctx.ptr_interm_outputbuffer == NULL || + drv_ctx.ptr_interm_respbuffer == NULL || + drv_ctx.interm_op_buf_ion_info == NULL || + m_pSwVdecIpBuffer == NULL) + { + goto clean_up; + } + } + + bufHdr = m_interm_mem_ptr; + for (unsigned long i = 0; i < drv_ctx.interm_op_buf.actualcount; i++) + { + int pmem_fd = -1; + unsigned char *pmem_baseaddress = NULL; + int flags = secure_mode ? ION_SECURE : 0; + if (m_pSwVdec) + { + DEBUG_PRINT_HIGH("Allocate cached interm buffers"); + flags = ION_FLAG_CACHED; + } + + DEBUG_PRINT_HIGH("allocate interm output buffer size %d idx %lu", + drv_ctx.interm_op_buf.buffer_size, i); + ion_device_fd = alloc_map_ion_memory( + drv_ctx.interm_op_buf.buffer_size, + drv_ctx.interm_op_buf.alignment, + &ion_alloc_data, &fd_ion_data, flags, heap_id); + if (ion_device_fd < 0) { + eRet = OMX_ErrorInsufficientResources; + goto clean_up; + } + pmem_fd = fd_ion_data.fd; + + drv_ctx.ptr_interm_outputbuffer[i].pmem_fd = pmem_fd; + drv_ctx.interm_op_buf_ion_info[i].ion_device_fd = ion_device_fd; + drv_ctx.interm_op_buf_ion_info[i].ion_alloc_data = ion_alloc_data; + drv_ctx.interm_op_buf_ion_info[i].fd_ion_data = fd_ion_data; + + if (!secure_mode) { + pmem_baseaddress = (unsigned char *)mmap(NULL, + drv_ctx.interm_op_buf.buffer_size, + PROT_READ|PROT_WRITE,MAP_SHARED, pmem_fd, 0); + if (pmem_baseaddress == MAP_FAILED) + { + DEBUG_PRINT_ERROR("MMAP failed for Size %d", + drv_ctx.interm_op_buf.buffer_size); + eRet = OMX_ErrorInsufficientResources; + goto clean_up; + } + } + + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = bytes; + bufHdr->nFilledLen = 0; + bufHdr->pAppPrivate = this; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + bufHdr->pBuffer = pmem_baseaddress; + bufHdr->nOffset = 0; + + bufHdr->pOutputPortPrivate = &drv_ctx.ptr_interm_respbuffer[i]; + drv_ctx.ptr_interm_respbuffer[i].client_data = (void *)&drv_ctx.ptr_interm_outputbuffer[i]; + drv_ctx.ptr_interm_outputbuffer[i].offset = 0; + drv_ctx.ptr_interm_outputbuffer[i].bufferaddr = pmem_baseaddress; + drv_ctx.ptr_interm_outputbuffer[i].mmaped_size = drv_ctx.interm_op_buf.buffer_size; + drv_ctx.ptr_interm_outputbuffer[i].buffer_len = drv_ctx.interm_op_buf.buffer_size; + + DEBUG_PRINT_LOW("interm pmem_fd = %d offset = %d address = %p, bufHdr %p", + pmem_fd, drv_ctx.ptr_interm_outputbuffer[i].offset, + drv_ctx.ptr_interm_outputbuffer[i].bufferaddr, bufHdr); + + m_interm_buf_state[i] = WITH_COMPONENT; + m_pSwVdecIpBuffer[i].pBuffer = bufHdr->pBuffer; + m_pSwVdecIpBuffer[i].pClientBufferData = (void*)i; + + // Move the buffer and buffer header pointers + bufHdr++; + } + + eRet = allocate_extradata(); + if (eRet != OMX_ErrorNone) + { + goto clean_up; + } + + for(i=0; i<drv_ctx.interm_op_buf.actualcount; i++) + { + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + int rc; + + bufHdr = (m_interm_mem_ptr + i ); + if (secure_mode) { + drv_ctx.ptr_interm_outputbuffer[i].bufferaddr = bufHdr; + } + + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].length = drv_ctx.interm_op_buf.buffer_size; + plane[0].m.userptr = (unsigned long)drv_ctx.ptr_interm_outputbuffer[i].bufferaddr - + (unsigned long)drv_ctx.ptr_interm_outputbuffer[i].offset; + plane[0].reserved[0] = drv_ctx.interm_op_buf_ion_info[i].fd_ion_data.fd; + plane[0].reserved[1] = drv_ctx.ptr_interm_outputbuffer[i].offset; + plane[0].data_offset = 0; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].length = drv_ctx.extradata_info.buffer_size; + plane[extra_idx].m.userptr = (long unsigned int) (drv_ctx.extradata_info.uaddr + + i * drv_ctx.extradata_info.buffer_size); + plane[extra_idx].reserved[0] = drv_ctx.extradata_info.ion.fd_ion_data.fd; + plane[extra_idx].reserved[1] = i * drv_ctx.extradata_info.buffer_size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index higher than allowed: %d", extra_idx); + goto clean_up; + } + buf.m.planes = plane; + buf.length = drv_ctx.num_planes; + DEBUG_PRINT_LOW("Set interm Output Buffer Idx: %d Addr: %p", i, drv_ctx.ptr_interm_outputbuffer[i].bufferaddr); + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_PREPARE_BUF, &buf); + if (rc) { + DEBUG_PRINT_ERROR("VIDIOC_PREPARE_BUF failed"); + goto clean_up; + } + + if (i == (drv_ctx.interm_op_buf.actualcount -1 ) && !streaming[CAPTURE_PORT]) { + enum v4l2_buf_type buf_type; + buf_type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + rc=ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type); + if (rc) { + return OMX_ErrorInsufficientResources; + } else { + streaming[CAPTURE_PORT] = true; + DEBUG_PRINT_LOW("STREAMON Successful"); + } + } + + bufHdr->pAppPrivate = this; + } + + m_interm_bEnabled = OMX_TRUE; + m_interm_bPopulated = OMX_TRUE; + + return OMX_ErrorNone; + +clean_up: + + if (drv_ctx.interm_op_buf_ion_info) + { + for(i=0; i< drv_ctx.interm_op_buf.actualcount; i++) + { + if(drv_ctx.ptr_interm_outputbuffer) + { + close(drv_ctx.ptr_interm_outputbuffer[i].pmem_fd); + drv_ctx.ptr_interm_outputbuffer[i].pmem_fd = 0; + } + free_ion_memory(&drv_ctx.interm_op_buf_ion_info[i]); + } + } + + if(m_interm_mem_ptr) + { + free(m_interm_mem_ptr); + m_interm_mem_ptr = NULL; + } + if(drv_ctx.ptr_interm_outputbuffer) + { + free(drv_ctx.ptr_interm_outputbuffer); + drv_ctx.ptr_interm_outputbuffer = NULL; + } + if(drv_ctx.ptr_interm_respbuffer) + { + free(drv_ctx.ptr_interm_respbuffer); + drv_ctx.ptr_interm_respbuffer = NULL; + } + if (drv_ctx.interm_op_buf_ion_info) { + DEBUG_PRINT_LOW("Free o/p ion context"); + free(drv_ctx.interm_op_buf_ion_info); + drv_ctx.interm_op_buf_ion_info = NULL; + } + return OMX_ErrorInsufficientResources; +} + +//callback function used by SWVdec + +SWVDEC_STATUS omx_vdec::swvdec_input_buffer_done_cb +( + SWVDEC_HANDLE pSwDec, + SWVDEC_IPBUFFER *m_pSwVdecIpBuffer, + void *pClientHandle + ) +{ + (void)pSwDec; + SWVDEC_STATUS eRet = SWVDEC_S_SUCCESS; + omx_vdec *omx = reinterpret_cast<omx_vdec*>(pClientHandle); + + if (m_pSwVdecIpBuffer == NULL) + { + eRet = SWVDEC_S_EFAIL; + } + else + { + DEBUG_PRINT_LOW("%s invoked", __func__); + omx->swvdec_input_buffer_done(m_pSwVdecIpBuffer); + } + + return eRet; +} + +void omx_vdec::swvdec_input_buffer_done(SWVDEC_IPBUFFER *m_pSwVdecIpBuffer) +{ + unsigned long index = (unsigned long)m_pSwVdecIpBuffer->pClientBufferData; + + if (m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + post_event((unsigned long)(m_interm_mem_ptr + index), + (unsigned long)VDEC_S_SUCCESS, (unsigned long)OMX_COMPONENT_GENERATE_EBD_SWVDEC); + } + else + { + post_event((unsigned long)(m_inp_mem_ptr + index), + (unsigned long)VDEC_S_SUCCESS, (unsigned long)OMX_COMPONENT_GENERATE_EBD); + } +} + +SWVDEC_STATUS omx_vdec::swvdec_fill_buffer_done_cb +( + SWVDEC_HANDLE pSwDec, + SWVDEC_OPBUFFER *m_pSwVdecOpBuffer, + void *pClientHandle +) +{ + (void)pSwDec; + SWVDEC_STATUS eRet = SWVDEC_S_SUCCESS; + omx_vdec *omx = reinterpret_cast<omx_vdec*>(pClientHandle); + + if (m_pSwVdecOpBuffer == NULL) + { + eRet = SWVDEC_S_EFAIL; + } + else + { + omx->swvdec_fill_buffer_done(m_pSwVdecOpBuffer); + } + return eRet; +} + +void omx_vdec::swvdec_fill_buffer_done(SWVDEC_OPBUFFER *m_pSwVdecOpBuffer) +{ + unsigned long index = (unsigned long)m_pSwVdecOpBuffer->pClientBufferData; + OMX_BUFFERHEADERTYPE *bufHdr = m_out_mem_ptr + index; + bufHdr->nFilledLen = m_pSwVdecOpBuffer->nFilledLen; + bufHdr->nFlags = m_pSwVdecOpBuffer->nFlags; + bufHdr->nTimeStamp = m_pSwVdecOpBuffer->nOpTimestamp; + + if (m_pSwVdecOpBuffer->nFilledLen != 0) + { + if ((m_pSwVdecOpBuffer->nHeight != rectangle.nHeight) || + (m_pSwVdecOpBuffer->nWidth != rectangle.nWidth)) + { + drv_ctx.video_resolution.frame_height = m_pSwVdecOpBuffer->nHeight; + drv_ctx.video_resolution.frame_width = m_pSwVdecOpBuffer->nWidth; + + rectangle.nLeft = 0; + rectangle.nTop = 0; + rectangle.nWidth = m_pSwVdecOpBuffer->nWidth; + rectangle.nHeight = m_pSwVdecOpBuffer->nHeight; + + DEBUG_PRINT_HIGH("swvdec_fill_buffer_done rectangle.WxH: %lu %lu", + rectangle.nWidth, rectangle.nHeight); + + post_event (OMX_CORE_OUTPUT_PORT_INDEX, OMX_IndexConfigCommonOutputCrop, + OMX_COMPONENT_GENERATE_PORT_RECONFIG); + } + } + + if (dynamic_buf_mode && m_pSwVdecOpBuffer->nFilledLen) + { + bufHdr->nFilledLen = bufHdr->nAllocLen; + } + if (bufHdr->nFlags & OMX_BUFFERFLAG_EOS) + { + DEBUG_PRINT_HIGH("swvdec output EOS reached"); + } + DEBUG_PRINT_LOW("swvdec_fill_buffer_done bufHdr %p pBuffer %p SwvdecOpBuffer %p idx %lu nFilledLen %lu nAllocLen %lu nFlags %lx", + bufHdr, bufHdr->pBuffer, m_pSwVdecOpBuffer->pBuffer, index, m_pSwVdecOpBuffer->nFilledLen, bufHdr->nAllocLen, m_pSwVdecOpBuffer->nFlags); + post_event((unsigned long)bufHdr, (unsigned long)VDEC_S_SUCCESS, (unsigned long)OMX_COMPONENT_GENERATE_FBD); +} + +SWVDEC_STATUS omx_vdec::swvdec_handle_event_cb +( + SWVDEC_HANDLE pSwDec, + SWVDEC_EVENTHANDLER* pEventHandler, + void *pClientHandle +) +{ + (void)pSwDec; + omx_vdec *omx = reinterpret_cast<omx_vdec*>(pClientHandle); + omx->swvdec_handle_event(pEventHandler); + return SWVDEC_S_SUCCESS; +} + +void omx_vdec::swvdec_handle_event(SWVDEC_EVENTHANDLER *pEvent) +{ + switch(pEvent->eEvent) + { + case SWVDEC_FLUSH_DONE: + DEBUG_PRINT_ERROR("SWVDEC_FLUSH_DONE input_flush_progress %d output_flush_progress %d", + input_flush_progress, output_flush_progress); + if (input_flush_progress) + { + post_event ((unsigned long)NULL, (unsigned long)VDEC_S_SUCCESS, (unsigned long)OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH); + } + if (output_flush_progress) + { + post_event ((unsigned long)NULL, (unsigned long)VDEC_S_SUCCESS, (unsigned long)OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH); + } + break; + + case SWVDEC_RECONFIG_SUFFICIENT_RESOURCES: + { + DEBUG_PRINT_HIGH("swvdec port settings changed info"); + if (false == m_smoothstreaming_mode) + { + // get_buffer_req and populate port defn structure + SWVDEC_PROP prop; + prop.ePropId = SWVDEC_PROP_ID_DIMENSIONS; + SwVdec_GetProperty(m_pSwVdec, &prop); + + update_resolution(prop.uProperty.sDimensions.nWidth, + prop.uProperty.sDimensions.nHeight, + prop.uProperty.sDimensions.nWidth, + prop.uProperty.sDimensions.nHeight); + drv_ctx.video_resolution.stride = (prop.uProperty.sDimensions.nWidth + 127) & (~127); + drv_ctx.video_resolution.scan_lines = (prop.uProperty.sDimensions.nHeight + 31) & (~31); + + m_port_def.nPortIndex = 1; + update_portdef(&m_port_def); + post_event ((unsigned)NULL, VDEC_S_SUCCESS, OMX_COMPONENT_GENERATE_INFO_PORT_RECONFIG); + } + } + break; + + case SWVDEC_RECONFIG_INSUFFICIENT_RESOURCES: + { + SWVDEC_PROP prop; + DEBUG_PRINT_HIGH("swvdec port settings changed"); + in_reconfig = true; + // get_buffer_req and populate port defn structure + prop.ePropId = SWVDEC_PROP_ID_DIMENSIONS; + SwVdec_GetProperty(m_pSwVdec, &prop); + + update_resolution(prop.uProperty.sDimensions.nWidth, + prop.uProperty.sDimensions.nHeight, + prop.uProperty.sDimensions.nWidth, + prop.uProperty.sDimensions.nHeight); + drv_ctx.video_resolution.stride = + (prop.uProperty.sDimensions.nWidth + 127) & (~127); + drv_ctx.video_resolution.scan_lines = + (prop.uProperty.sDimensions.nHeight + 31) & (~31); + + m_port_def.nPortIndex = 1; + update_portdef(&m_port_def); + + //Set property for dimensions and attrb to SwVdec + SwVdec_SetProperty(m_pSwVdec,&prop); + prop.ePropId = SWVDEC_PROP_ID_FRAME_ATTR; + prop.uProperty.sFrameAttr.eColorFormat = SWVDEC_FORMAT_NV12; + SwVdec_SetProperty(m_pSwVdec,&prop); + + post_event (OMX_CORE_OUTPUT_PORT_INDEX, OMX_IndexParamPortDefinition, + OMX_COMPONENT_GENERATE_PORT_RECONFIG); + } + break; + + case SWVDEC_ERROR: + { + DEBUG_PRINT_ERROR("swvdec fatal error"); + post_event ((unsigned)NULL, VDEC_S_SUCCESS,\ + OMX_COMPONENT_GENERATE_HARDWARE_ERROR); + } + break; + + case SWVDEC_RELEASE_BUFFER_REFERENCE: + { + SWVDEC_OPBUFFER* pOpBuffer = (SWVDEC_OPBUFFER *)pEvent->pEventData; + if (pOpBuffer == NULL) + { + DEBUG_PRINT_ERROR("swvdec release buffer reference for null buffer"); + } + unsigned long idx = (unsigned long)pOpBuffer->pClientBufferData; + DEBUG_PRINT_HIGH("swvdec release buffer reference idx %lu", idx); + + if (idx < drv_ctx.op_buf.actualcount) + { + DEBUG_PRINT_LOW("swvdec REFERENCE RELEASE EVENT fd = %d offset = %u buf idx %lu pBuffer %p", + drv_ctx.ptr_outputbuffer[idx].pmem_fd, drv_ctx.ptr_outputbuffer[idx].offset, + idx, drv_ctx.ptr_outputbuffer[idx].bufferaddr); + buf_ref_remove(drv_ctx.ptr_outputbuffer[idx].pmem_fd, + drv_ctx.ptr_outputbuffer[idx].offset); + } + } + break; + default: + break; + } + + // put into the event command q + // m_cmd_q.insert_entry((unsigned int)NULL, + // SWVDEC_S_SUCCESS, + // OMX_COMPONENT_GENERATE_STOP_DONE_SWVDEC); + // post_message(this, OMX_COMPONENT_GENERATE_STOP_DONE_SWVDEC); +} + +bool omx_vdec::execute_input_flush_swvdec() +{ + int idx =0; + unsigned long p1 = 0; // Parameter - 1 + unsigned long p2 = 0; // Parameter - 2 + unsigned long ident = 0; + bool bRet = true; + + DEBUG_PRINT_LOW("execute_input_flush_swvdec qsize %d, actual %d", + m_etb_q_swvdec.m_size, drv_ctx.interm_op_buf.actualcount); + + pthread_mutex_lock(&m_lock); + while (m_etb_q_swvdec.m_size) + { + OMX_BUFFERHEADERTYPE* bufHdr = NULL; + m_etb_q_swvdec.pop_entry(&p1,&p2,&ident); + if (ident == OMX_COMPONENT_GENERATE_ETB_SWVDEC) + { + bufHdr = (OMX_BUFFERHEADERTYPE*)p2; + } + else if (ident == OMX_COMPONENT_GENERATE_EBD_SWVDEC) + { + bufHdr = (OMX_BUFFERHEADERTYPE*)p1; + } + idx = (bufHdr - m_interm_mem_ptr); + if (idx >= 0 && idx < (int)drv_ctx.interm_op_buf.actualcount) + { + DEBUG_PRINT_ERROR("execute_input_flush_swvdec flushed buffer idx %d", idx); + m_interm_buf_state[idx] = WITH_COMPONENT; + } + else + { + DEBUG_PRINT_ERROR("execute_input_flush_swvdec issue: invalid idx %d", idx); + } + } + m_interm_flush_swvdec_progress = false; + pthread_mutex_unlock(&m_lock); + + for (idx = 0; idx < (int)drv_ctx.interm_op_buf.actualcount; idx++) + { + DEBUG_PRINT_LOW("Flush swvdec interm bufq idx %d, state %d", idx, m_interm_buf_state[idx]); + // m_interm_buf_state[idx] = WITH_COMPONENT; + } + + return true; +} + + +bool omx_vdec::execute_output_flush_dsp() +{ + int idx =0; + unsigned long p1 = 0; // Parameter - 1 + unsigned long p2 = 0; // Parameter - 2 + unsigned long ident = 0; + bool bRet = true; + + DEBUG_PRINT_LOW("execute_output_flush_dsp qsize %d, actual %d", + m_ftb_q_dsp.m_size, drv_ctx.interm_op_buf.actualcount); + + pthread_mutex_lock(&m_lock); + while (m_ftb_q_dsp.m_size) + { + OMX_BUFFERHEADERTYPE* bufHdr = NULL; + m_ftb_q_dsp.pop_entry(&p1,&p2,&ident); + if (ident == OMX_COMPONENT_GENERATE_FTB_DSP) + { + bufHdr = (OMX_BUFFERHEADERTYPE*)p2; + } + else if (ident == OMX_COMPONENT_GENERATE_FBD_DSP) + { + bufHdr = (OMX_BUFFERHEADERTYPE*)p1; + } + idx = (bufHdr - m_interm_mem_ptr); + if (idx >= 0 && idx < (int)drv_ctx.interm_op_buf.actualcount) + { + DEBUG_PRINT_ERROR("execute_output_flush_dsp flushed buffer idx %d", idx); + m_interm_buf_state[idx] = WITH_COMPONENT; + } + else + { + DEBUG_PRINT_ERROR("execute_output_flush_dsp issue: invalid idx %d", idx); + } + } + m_interm_flush_dsp_progress = false; + m_fill_internal_bufers = OMX_TRUE; + pthread_mutex_unlock(&m_lock); + + for (idx = 0; idx < (int)drv_ctx.interm_op_buf.actualcount; idx++) + { + DEBUG_PRINT_LOW("Flush dsp interm bufq idx %d, state %d", idx, m_interm_buf_state[idx]); + // m_interm_buf_state[idx] = WITH_COMPONENT; + } + return true; +} + +OMX_ERRORTYPE omx_vdec::free_interm_buffers() +{ + free_extradata(); + + if (drv_ctx.ptr_interm_outputbuffer) + { + for(unsigned long i=0; i< drv_ctx.interm_op_buf.actualcount; i++) + { + if (drv_ctx.ptr_interm_outputbuffer[i].pmem_fd > 0) + { + DEBUG_PRINT_LOW("Free interm ouput Buffer index = %lu addr = %p", i, + drv_ctx.ptr_interm_outputbuffer[i].bufferaddr); + + munmap (drv_ctx.ptr_interm_outputbuffer[i].bufferaddr, + drv_ctx.ptr_interm_outputbuffer[i].mmaped_size); + close(drv_ctx.ptr_interm_outputbuffer[i].pmem_fd); + drv_ctx.ptr_interm_outputbuffer[i].pmem_fd = 0; + free_ion_memory(&drv_ctx.interm_op_buf_ion_info[i]); + } + } + } + + if (m_interm_mem_ptr) + { + free(m_interm_mem_ptr); + m_interm_mem_ptr = NULL; + } + + if (drv_ctx.ptr_interm_respbuffer) + { + free (drv_ctx.ptr_interm_respbuffer); + drv_ctx.ptr_interm_respbuffer = NULL; + } + + if (drv_ctx.ptr_interm_outputbuffer) + { + free (drv_ctx.ptr_interm_outputbuffer); + drv_ctx.ptr_interm_outputbuffer = NULL; + } + + if (drv_ctx.interm_op_buf_ion_info) { + free(drv_ctx.interm_op_buf_ion_info); + drv_ctx.interm_op_buf_ion_info = NULL; + } + + if (!in_reconfig || m_swvdec_mode == SWVDEC_MODE_DECODE_ONLY) + { + if (m_pSwVdecIpBuffer) + { + free(m_pSwVdecIpBuffer); + m_pSwVdecIpBuffer = NULL; + } + } + + if (m_pSwVdecOpBuffer) + { + free(m_pSwVdecOpBuffer); + m_pSwVdecOpBuffer = NULL; + } + + m_interm_bEnabled = OMX_FALSE; + m_interm_bPopulated = OMX_FALSE; + return OMX_ErrorNone; +} + diff --git a/msm8998/mm-video-v4l2/vidc/vdec/src/omx_vdec_v4l2.cpp b/msm8998/mm-video-v4l2/vidc/vdec/src/omx_vdec_v4l2.cpp new file mode 100644 index 0000000..ae02358 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/src/omx_vdec_v4l2.cpp @@ -0,0 +1,13028 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010 - 2016, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ + +/*============================================================================ + O p e n M A X w r a p p e r s + O p e n M A X C o r e + + This module contains the implementation of the OpenMAX core & component. + +*//*========================================================================*/ + +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#include <string.h> +#include <pthread.h> +#include <sys/prctl.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "omx_vdec.h" +#include <fcntl.h> +#include <limits.h> +#include <stdlib.h> +#include <media/hardware/HardwareAPI.h> +#include <media/msm_media_info.h> +#include <sys/eventfd.h> + +#ifndef _ANDROID_ +#include <sys/ioctl.h> +#include <sys/mman.h> +#endif //_ANDROID_ + +#ifdef _ANDROID_ +#include <cutils/properties.h> +#undef USE_EGL_IMAGE_GPU +#endif + +#include <qdMetaData.h> +#include <gralloc_priv.h> + +#ifdef ANDROID_JELLYBEAN_MR2 +#include "QComOMXMetadata.h" +#endif + +#ifdef USE_EGL_IMAGE_GPU +#include <EGL/egl.h> +#include <EGL/eglQCOM.h> +#define EGL_BUFFER_HANDLE 0x4F00 +#define EGL_BUFFER_OFFSET 0x4F01 +#endif + +#define BUFFER_LOG_LOC "/data/misc/media" + +#ifdef OUTPUT_EXTRADATA_LOG +FILE *outputExtradataFile; +char output_extradata_filename [] = "/data/misc/media/extradata"; +#endif + +#define DEFAULT_FPS 30 +#define MAX_SUPPORTED_FPS 240 +#define DEFAULT_WIDTH_ALIGNMENT 128 +#define DEFAULT_HEIGHT_ALIGNMENT 32 + +#define VC1_SP_MP_START_CODE 0xC5000000 +#define VC1_SP_MP_START_CODE_MASK 0xFF000000 +#define VC1_AP_SEQ_START_CODE 0x0F010000 +#define VC1_STRUCT_C_PROFILE_MASK 0xF0 +#define VC1_STRUCT_B_LEVEL_MASK 0xE0000000 +#define VC1_SIMPLE_PROFILE 0 +#define VC1_MAIN_PROFILE 1 +#define VC1_ADVANCE_PROFILE 3 +#define VC1_SIMPLE_PROFILE_LOW_LEVEL 0 +#define VC1_SIMPLE_PROFILE_MED_LEVEL 2 +#define VC1_STRUCT_C_LEN 4 +#define VC1_STRUCT_C_POS 8 +#define VC1_STRUCT_A_POS 12 +#define VC1_STRUCT_B_POS 24 +#define VC1_SEQ_LAYER_SIZE 36 +#define POLL_TIMEOUT 0x7fffffff + +#define MEM_DEVICE "/dev/ion" + +#ifdef _ANDROID_ +extern "C" { +#include<utils/Log.h> +} +#endif//_ANDROID_ + +#define SZ_4K 0x1000 +#define SZ_1M 0x100000 + +#define Log2(number, power) { OMX_U32 temp = number; power = 0; while( (0 == (temp & 0x1)) && power < 16) { temp >>=0x1; power++; } } +#define Q16ToFraction(q,num,den) { OMX_U32 power; Log2(q,power); num = q >> power; den = 0x1 << (16 - power); } +#define EXTRADATA_IDX(__num_planes) ((__num_planes) ? (__num_planes) - 1 : 0) +#define ALIGN(x, to_align) ((((unsigned) x) + (to_align - 1)) & ~(to_align - 1)) + +#define DEFAULT_EXTRADATA (OMX_INTERLACE_EXTRADATA | OMX_FRAMEPACK_EXTRADATA | OMX_OUTPUTCROP_EXTRADATA \ + | OMX_DISPLAY_INFO_EXTRADATA | OMX_HDR_COLOR_INFO_EXTRADATA) +#define DEFAULT_CONCEAL_COLOR "32784" //0x8010, black by default + +#ifndef ION_FLAG_CP_BITSTREAM +#define ION_FLAG_CP_BITSTREAM 0 +#endif + +#ifndef ION_FLAG_CP_PIXEL +#define ION_FLAG_CP_PIXEL 0 +#endif + +#ifdef MASTER_SIDE_CP +#define MEM_HEAP_ID ION_SECURE_HEAP_ID +#define SECURE_ALIGN SZ_4K +#define SECURE_FLAGS_INPUT_BUFFER (ION_SECURE | ION_FLAG_CP_BITSTREAM) +#define SECURE_FLAGS_OUTPUT_BUFFER (ION_SECURE | ION_FLAG_CP_PIXEL) +#else //SLAVE_SIDE_CP +#define MEM_HEAP_ID ION_CP_MM_HEAP_ID +#define SECURE_ALIGN SZ_1M +#define SECURE_FLAGS_INPUT_BUFFER ION_SECURE +#define SECURE_FLAGS_OUTPUT_BUFFER ION_SECURE +#endif + +static OMX_U32 maxSmoothStreamingWidth = 1920; +static OMX_U32 maxSmoothStreamingHeight = 1088; + +void* async_message_thread (void *input) +{ + OMX_BUFFERHEADERTYPE *buffer; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + struct pollfd pfds[2]; + struct v4l2_buffer v4l2_buf; + memset((void *)&v4l2_buf,0,sizeof(v4l2_buf)); + struct v4l2_event dqevent; + omx_vdec *omx = reinterpret_cast<omx_vdec*>(input); + pfds[0].events = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLRDBAND | POLLPRI; + pfds[1].events = POLLIN | POLLERR; + pfds[0].fd = omx->drv_ctx.video_driver_fd; + pfds[1].fd = omx->m_poll_efd; + int error_code = 0,rc=0,bytes_read = 0,bytes_written = 0; + DEBUG_PRINT_HIGH("omx_vdec: Async thread start"); + prctl(PR_SET_NAME, (unsigned long)"VideoDecCallBackThread", 0, 0, 0); + while (!omx->async_thread_force_stop) { + rc = poll(pfds, 2, POLL_TIMEOUT); + if (!rc) { + DEBUG_PRINT_ERROR("Poll timedout"); + break; + } else if (rc < 0 && errno != EINTR && errno != EAGAIN) { + DEBUG_PRINT_ERROR("Error while polling: %d, errno = %d", rc, errno); + break; + } + if ((pfds[1].revents & POLLIN) || (pfds[1].revents & POLLERR)) { + DEBUG_PRINT_HIGH("async_message_thread interrupted to be exited"); + break; + } + if ((pfds[0].revents & POLLIN) || (pfds[0].revents & POLLRDNORM)) { + struct vdec_msginfo vdec_msg; + memset(&vdec_msg, 0, sizeof(vdec_msg)); + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.length = omx->drv_ctx.num_planes; + v4l2_buf.m.planes = plane; + while (!ioctl(pfds[0].fd, VIDIOC_DQBUF, &v4l2_buf)) { + vdec_msg.msgcode=VDEC_MSG_RESP_OUTPUT_BUFFER_DONE; + vdec_msg.status_code=VDEC_S_SUCCESS; + vdec_msg.msgdata.output_frame.client_data=(void*)&v4l2_buf; + vdec_msg.msgdata.output_frame.len=plane[0].bytesused; + vdec_msg.msgdata.output_frame.bufferaddr=(void*)plane[0].m.userptr; + vdec_msg.msgdata.output_frame.time_stamp= ((uint64_t)v4l2_buf.timestamp.tv_sec * (uint64_t)1000000) + + (uint64_t)v4l2_buf.timestamp.tv_usec; + + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } + } + if ((pfds[0].revents & POLLOUT) || (pfds[0].revents & POLLWRNORM)) { + struct vdec_msginfo vdec_msg; + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.length = 1; + v4l2_buf.m.planes = plane; + while (!ioctl(pfds[0].fd, VIDIOC_DQBUF, &v4l2_buf)) { + vdec_msg.msgcode=VDEC_MSG_RESP_INPUT_BUFFER_DONE; + vdec_msg.status_code=VDEC_S_SUCCESS; + vdec_msg.msgdata.input_frame_clientdata=(void*)&v4l2_buf; + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } + } + if (pfds[0].revents & POLLPRI) { + rc = ioctl(pfds[0].fd, VIDIOC_DQEVENT, &dqevent); + if (dqevent.type == V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT ) { + struct vdec_msginfo vdec_msg; + unsigned int *ptr = (unsigned int *)(void *)dqevent.u.data; + + vdec_msg.msgcode=VDEC_MSG_EVT_CONFIG_CHANGED; + vdec_msg.status_code=VDEC_S_SUCCESS; + vdec_msg.msgdata.output_frame.picsize.frame_height = ptr[0]; + vdec_msg.msgdata.output_frame.picsize.frame_width = ptr[1]; + DEBUG_PRINT_HIGH("VIDC Port Reconfig received insufficient"); + if(ptr[2] & V4L2_EVENT_BITDEPTH_FLAG) { + omx->dpb_bit_depth = ptr[3]; + DEBUG_PRINT_HIGH("VIDC Port Reconfig Bitdepth change - %d", ptr[3]); + } + if(ptr[2] & V4L2_EVENT_PICSTRUCT_FLAG) { + omx->m_progressive = ptr[4]; + DEBUG_PRINT_HIGH("VIDC Port Reconfig PicStruct change - %d", ptr[4]); + } + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_FLUSH_DONE) { + struct vdec_msginfo vdec_msg; + vdec_msg.msgcode=VDEC_MSG_RESP_FLUSH_INPUT_DONE; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_HIGH("VIDC Input Flush Done Recieved"); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + vdec_msg.msgcode=VDEC_MSG_RESP_FLUSH_OUTPUT_DONE; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_HIGH("VIDC Output Flush Done Recieved"); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_HW_OVERLOAD) { + struct vdec_msginfo vdec_msg; + vdec_msg.msgcode=VDEC_MSG_EVT_HW_OVERLOAD; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_ERROR("HW Overload received"); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED) { + struct vdec_msginfo vdec_msg; + vdec_msg.msgcode=VDEC_MSG_EVT_HW_UNSUPPORTED; + vdec_msg.status_code=VDEC_S_SUCCESS; + DEBUG_PRINT_ERROR("HW Unsupported received"); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_SYS_ERROR) { + struct vdec_msginfo vdec_msg; + vdec_msg.msgcode = VDEC_MSG_EVT_HW_ERROR; + vdec_msg.status_code = VDEC_S_SUCCESS; + DEBUG_PRINT_HIGH("SYS Error Recieved"); + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exited"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE) { + unsigned int *ptr = (unsigned int *)(void *)dqevent.u.data; + + DEBUG_PRINT_LOW("REFERENCE RELEASE EVENT RECVD fd = %d offset = %d", ptr[0], ptr[1]); + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER) { + unsigned int *ptr = (unsigned int *)(void *)dqevent.u.data; + struct vdec_msginfo vdec_msg; + + DEBUG_PRINT_LOW("Release unqueued buffer event recvd fd = %d offset = %d", ptr[0], ptr[1]); + + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.length = omx->drv_ctx.num_planes; + v4l2_buf.m.planes = plane; + v4l2_buf.index = ptr[5]; + v4l2_buf.flags = 0; + + vdec_msg.msgcode = VDEC_MSG_RESP_OUTPUT_BUFFER_DONE; + vdec_msg.status_code = VDEC_S_SUCCESS; + vdec_msg.msgdata.output_frame.client_data = (void*)&v4l2_buf; + vdec_msg.msgdata.output_frame.len = 0; + vdec_msg.msgdata.output_frame.bufferaddr = (void*)(intptr_t)ptr[2]; + vdec_msg.msgdata.output_frame.time_stamp = ((uint64_t)ptr[3] * (uint64_t)1000000) + + (uint64_t)ptr[4]; + if (omx->async_message_process(input,&vdec_msg) < 0) { + DEBUG_PRINT_HIGH("async_message_thread Exitedn"); + break; + } + } else { + DEBUG_PRINT_HIGH("VIDC Some Event recieved"); + continue; + } + } + } + DEBUG_PRINT_HIGH("omx_vdec: Async thread stop"); + return NULL; +} + +void* message_thread_dec(void *input) +{ + omx_vdec* omx = reinterpret_cast<omx_vdec*>(input); + unsigned char id; + int n; + + fd_set readFds; + int res = 0; + struct timeval tv; + + DEBUG_PRINT_HIGH("omx_vdec: message thread start"); + prctl(PR_SET_NAME, (unsigned long)"VideoDecMsgThread", 0, 0, 0); + while (!omx->message_thread_stop) { + + tv.tv_sec = 2; + tv.tv_usec = 0; + + FD_ZERO(&readFds); + FD_SET(omx->m_pipe_in, &readFds); + + res = select(omx->m_pipe_in + 1, &readFds, NULL, NULL, &tv); + if (res < 0) { + DEBUG_PRINT_ERROR("select() ERROR: %s", strerror(errno)); + continue; + } else if (res == 0 /*timeout*/ || omx->message_thread_stop) { + continue; + } + + n = read(omx->m_pipe_in, &id, 1); + + if (0 == n) { + break; + } + + if (1 == n) { + omx->process_event_cb(omx, id); + } + + if ((n < 0) && (errno != EINTR)) { + DEBUG_PRINT_LOW("ERROR: read from pipe failed, ret %d errno %d", n, errno); + break; + } + } + DEBUG_PRINT_HIGH("omx_vdec: message thread stop"); + return 0; +} + +void post_message(omx_vdec *omx, unsigned char id) +{ + int ret_value; + DEBUG_PRINT_LOW("omx_vdec: post_message %d pipe out%d", id,omx->m_pipe_out); + ret_value = write(omx->m_pipe_out, &id, 1); + if (ret_value <= 0) { + DEBUG_PRINT_ERROR("post_message to pipe failed : %s", strerror(errno)); + } else { + DEBUG_PRINT_LOW("post_message to pipe done %d",ret_value); + } +} + +// omx_cmd_queue destructor +omx_vdec::omx_cmd_queue::~omx_cmd_queue() +{ + // Nothing to do +} + +// omx cmd queue constructor +omx_vdec::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0) +{ + memset(m_q,0,sizeof(omx_event)*OMX_CORE_CONTROL_CMDQ_SIZE); +} + +// omx cmd queue insert +bool omx_vdec::omx_cmd_queue::insert_entry(unsigned long p1, unsigned long p2, unsigned long id) +{ + bool ret = true; + if (m_size < OMX_CORE_CONTROL_CMDQ_SIZE) { + m_q[m_write].id = id; + m_q[m_write].param1 = p1; + m_q[m_write].param2 = p2; + m_write++; + m_size ++; + if (m_write >= OMX_CORE_CONTROL_CMDQ_SIZE) { + m_write = 0; + } + } else { + ret = false; + DEBUG_PRINT_ERROR("ERROR: %s()::Command Queue Full", __func__); + } + return ret; +} + +// omx cmd queue pop +bool omx_vdec::omx_cmd_queue::pop_entry(unsigned long *p1, unsigned long *p2, unsigned long *id) +{ + bool ret = true; + if (m_size > 0) { + *id = m_q[m_read].id; + *p1 = m_q[m_read].param1; + *p2 = m_q[m_read].param2; + // Move the read pointer ahead + ++m_read; + --m_size; + if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE) { + m_read = 0; + } + } else { + ret = false; + } + return ret; +} + +// Retrieve the first mesg type in the queue +unsigned omx_vdec::omx_cmd_queue::get_q_msg_type() +{ + return m_q[m_read].id; +} + +#ifdef _ANDROID_ +omx_vdec::ts_arr_list::ts_arr_list() +{ + //initialize timestamps array + memset(m_ts_arr_list, 0, ( sizeof(ts_entry) * MAX_NUM_INPUT_OUTPUT_BUFFERS) ); +} +omx_vdec::ts_arr_list::~ts_arr_list() +{ + //free m_ts_arr_list? +} + +bool omx_vdec::ts_arr_list::insert_ts(OMX_TICKS ts) +{ + bool ret = true; + bool duplicate_ts = false; + int idx = 0; + + //insert at the first available empty location + for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) { + if (!m_ts_arr_list[idx].valid) { + //found invalid or empty entry, save timestamp + m_ts_arr_list[idx].valid = true; + m_ts_arr_list[idx].timestamp = ts; + DEBUG_PRINT_LOW("Insert_ts(): Inserting TIMESTAMP (%lld) at idx (%d)", + ts, idx); + break; + } + } + + if (idx == MAX_NUM_INPUT_OUTPUT_BUFFERS) { + DEBUG_PRINT_LOW("Timestamp array list is FULL. Unsuccessful insert"); + ret = false; + } + return ret; +} + +bool omx_vdec::ts_arr_list::pop_min_ts(OMX_TICKS &ts) +{ + bool ret = true; + int min_idx = -1; + OMX_TICKS min_ts = 0; + int idx = 0; + + for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) { + + if (m_ts_arr_list[idx].valid) { + //found valid entry, save index + if (min_idx < 0) { + //first valid entry + min_ts = m_ts_arr_list[idx].timestamp; + min_idx = idx; + } else if (m_ts_arr_list[idx].timestamp < min_ts) { + min_ts = m_ts_arr_list[idx].timestamp; + min_idx = idx; + } + } + + } + + if (min_idx < 0) { + //no valid entries found + DEBUG_PRINT_LOW("Timestamp array list is empty. Unsuccessful pop"); + ts = 0; + ret = false; + } else { + ts = m_ts_arr_list[min_idx].timestamp; + m_ts_arr_list[min_idx].valid = false; + DEBUG_PRINT_LOW("Pop_min_ts:Timestamp (%lld), index(%d)", + ts, min_idx); + } + + return ret; + +} + + +bool omx_vdec::ts_arr_list::reset_ts_list() +{ + bool ret = true; + int idx = 0; + + DEBUG_PRINT_LOW("reset_ts_list(): Resetting timestamp array list"); + for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) { + m_ts_arr_list[idx].valid = false; + } + return ret; +} +#endif + +// factory function executed by the core to create instances +void *get_omx_component_factory_fn(void) +{ + return (new omx_vdec); +} + +#ifdef _ANDROID_ +#ifdef USE_ION +VideoHeap::VideoHeap(int devicefd, size_t size, void* base, + ion_user_handle_t handle, int ionMapfd) +{ + (void) devicefd; + (void) size; + (void) base; + (void) handle; + (void) ionMapfd; + // ionInit(devicefd, base, size, 0 , MEM_DEVICE,handle,ionMapfd); +} +#else +VideoHeap::VideoHeap(int fd, size_t size, void* base) +{ + // dup file descriptor, map once, use pmem + init(dup(fd), base, size, 0 , MEM_DEVICE); +} +#endif +#endif // _ANDROID_ + +bool is_platform_tp10capture_supported() +{ + char platform_name[PROPERTY_VALUE_MAX] = {0}; + property_get("ro.board.platform", platform_name, "0"); + if (!strncmp(platform_name, "msmcobalt", 9)) { + DEBUG_PRINT_HIGH("TP10 on capture port is supported"); + return true; + } + DEBUG_PRINT_HIGH("TP10 on capture port is not supported"); + return false; +} + +/* ====================================================================== + FUNCTION + omx_vdec::omx_vdec + + DESCRIPTION + Constructor + + PARAMETERS + None + + RETURN VALUE + None. + ========================================================================== */ +omx_vdec::omx_vdec(): m_error_propogated(false), + m_state(OMX_StateInvalid), + m_app_data(NULL), + m_inp_mem_ptr(NULL), + m_out_mem_ptr(NULL), + input_flush_progress (false), + output_flush_progress (false), + input_use_buffer (false), + output_use_buffer (false), + ouput_egl_buffers(false), + m_use_output_pmem(OMX_FALSE), + m_out_mem_region_smi(OMX_FALSE), + m_out_pvt_entry_pmem(OMX_FALSE), + pending_input_buffers(0), + pending_output_buffers(0), + m_out_bm_count(0), + m_inp_bm_count(0), + m_inp_bPopulated(OMX_FALSE), + m_out_bPopulated(OMX_FALSE), + m_flags(0), +#ifdef _ANDROID_ + m_heap_ptr(NULL), +#endif + m_inp_bEnabled(OMX_TRUE), + m_out_bEnabled(OMX_TRUE), + m_in_alloc_cnt(0), + m_platform_list(NULL), + m_platform_entry(NULL), + m_pmem_info(NULL), + h264_parser(NULL), + arbitrary_bytes (true), + psource_frame (NULL), + pdest_frame (NULL), + m_inp_heap_ptr (NULL), + m_phdr_pmem_ptr(NULL), + m_heap_inp_bm_count (0), + codec_type_parse ((codec_type)0), + first_frame_meta (true), + frame_count (0), + nal_count (0), + nal_length(0), + look_ahead_nal (false), + first_frame(0), + first_buffer(NULL), + first_frame_size (0), + m_device_file_ptr(NULL), + m_vc1_profile((vc1_profile_type)0), + h264_last_au_ts(LLONG_MAX), + h264_last_au_flags(0), + m_disp_hor_size(0), + m_disp_vert_size(0), + prev_ts(LLONG_MAX), + prev_ts_actual(LLONG_MAX), + rst_prev_ts(true), + frm_int(0), + m_fps_received(0), + m_fps_prev(0), + m_drc_enable(0), + in_reconfig(false), + m_display_id(NULL), + client_extradata(0), + m_reject_avc_1080p_mp (0), +#ifdef _ANDROID_ + m_enable_android_native_buffers(OMX_FALSE), + m_use_android_native_buffers(OMX_FALSE), +#endif + m_desc_buffer_ptr(NULL), + secure_mode(false), + allocate_native_handle(false), + m_other_extradata(NULL), + m_profile(0), + client_set_fps(false), + stereo_output_mode(HAL_NO_3D), + m_last_rendered_TS(-1), + m_queued_codec_config_count(0), + current_perf_level(V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL), + secure_scaling_to_non_secure_opb(false), + m_force_compressed_for_dpb(true), + m_is_display_session(false) +{ + m_pipe_in = -1; + m_pipe_out = -1; + m_poll_efd = -1; + drv_ctx.video_driver_fd = -1; + drv_ctx.extradata_info.ion.fd_ion_data.fd = -1; + /* Assumption is that , to begin with , we have all the frames with decoder */ + DEBUG_PRINT_HIGH("In %u bit OMX vdec Constructor", (unsigned int)sizeof(long) * 8); + memset(&m_debug,0,sizeof(m_debug)); +#ifdef _ANDROID_ + char property_value[PROPERTY_VALUE_MAX] = {0}; + property_get("vidc.debug.level", property_value, "1"); + debug_level = strtoul(property_value, NULL, 16); + property_value[0] = '\0'; + + DEBUG_PRINT_HIGH("In OMX vdec Constructor"); + + property_get("vidc.dec.debug.perf", property_value, "0"); + perf_flag = atoi(property_value); + if (perf_flag) { + DEBUG_PRINT_HIGH("vidc.dec.debug.perf is %d", perf_flag); + dec_time.start(); + } + proc_frms = latency = 0; + prev_n_filled_len = 0; + property_value[0] = '\0'; + property_get("vidc.dec.debug.ts", property_value, "0"); + m_debug_timestamp = atoi(property_value); + DEBUG_PRINT_HIGH("vidc.dec.debug.ts value is %d",m_debug_timestamp); + if (m_debug_timestamp) { + time_stamp_dts.set_timestamp_reorder_mode(true); + time_stamp_dts.enable_debug_print(true); + } + + property_value[0] = '\0'; + property_get("vidc.dec.debug.concealedmb", property_value, "0"); + m_debug_concealedmb = atoi(property_value); + DEBUG_PRINT_HIGH("vidc.dec.debug.concealedmb value is %d",m_debug_concealedmb); + + property_value[0] = '\0'; + property_get("vidc.dec.profile.check", property_value, "0"); + m_reject_avc_1080p_mp = atoi(property_value); + DEBUG_PRINT_HIGH("vidc.dec.profile.check value is %d",m_reject_avc_1080p_mp); + + property_value[0] = '\0'; + property_get("vidc.dec.log.in", property_value, "0"); + m_debug.in_buffer_log = atoi(property_value); + + property_value[0] = '\0'; + property_get("vidc.dec.log.out", property_value, "0"); + m_debug.out_buffer_log = atoi(property_value); + snprintf(m_debug.log_loc, PROPERTY_VALUE_MAX, "%s", BUFFER_LOG_LOC); + + property_value[0] = '\0'; + property_get("vidc.dec.meta.log.out", property_value, "0"); + m_debug.out_meta_buffer_log = atoi(property_value); + snprintf(m_debug.log_loc, PROPERTY_VALUE_MAX, "%s", BUFFER_LOG_LOC); + + property_value[0] = '\0'; + property_get("vidc.log.loc", property_value, ""); + if (*property_value) + strlcpy(m_debug.log_loc, property_value, PROPERTY_VALUE_MAX); + + property_value[0] = '\0'; + property_get("vidc.dec.120fps.enabled", property_value, "0"); + + //if this feature is not enabled then reset this value -ve + if(atoi(property_value)) { + DEBUG_PRINT_LOW("feature 120 FPS decode enabled"); + m_last_rendered_TS = 0; + } + + property_value[0] = '\0'; + property_get("vidc.dec.debug.dyn.disabled", property_value, "0"); + m_disable_dynamic_buf_mode = atoi(property_value); + DEBUG_PRINT_HIGH("vidc.dec.debug.dyn.disabled value is %d",m_disable_dynamic_buf_mode); + + property_value[0] = '\0'; + property_get("vidc.dec.drc.enable", property_value, "0"); + if (atoi(property_value)) { + m_drc_enable = true; + DEBUG_PRINT_HIGH("DRC enabled"); + } + +#ifdef _UBWC_ + property_value[0] = '\0'; + property_get("debug.gralloc.gfx_ubwc_disable", property_value, "0"); + m_disable_ubwc_mode = atoi(property_value); + DEBUG_PRINT_HIGH("UBWC mode is %s", m_disable_ubwc_mode ? "disabled" : "enabled"); +#else + m_disable_ubwc_mode = true; +#endif +#endif + memset(&m_cmp,0,sizeof(m_cmp)); + memset(&m_cb,0,sizeof(m_cb)); + memset (&drv_ctx,0,sizeof(drv_ctx)); + memset (&h264_scratch,0,sizeof (OMX_BUFFERHEADERTYPE)); + memset (m_hwdevice_name,0,sizeof(m_hwdevice_name)); + memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) ); + memset(&m_custom_buffersize, 0, sizeof(m_custom_buffersize)); + memset(&m_client_color_space, 0, sizeof(DescribeColorAspectsParams)); + memset(&m_internal_color_space, 0, sizeof(DescribeColorAspectsParams)); + memset(&m_client_hdr_info, 0, sizeof(DescribeHDRStaticInfoParams)); + memset(&m_internal_hdr_info, 0, sizeof(DescribeHDRStaticInfoParams)); + m_demux_entries = 0; + msg_thread_id = 0; + async_thread_id = 0; + msg_thread_created = false; + async_thread_created = false; + async_thread_force_stop = false; + message_thread_stop = false; +#ifdef _ANDROID_ICS_ + memset(&native_buffer, 0 ,(sizeof(struct nativebuffer) * MAX_NUM_INPUT_OUTPUT_BUFFERS)); +#endif + memset(&drv_ctx.extradata_info, 0, sizeof(drv_ctx.extradata_info)); + + /* invalidate m_frame_pack_arrangement */ + memset(&m_frame_pack_arrangement, 0, sizeof(OMX_QCOM_FRAME_PACK_ARRANGEMENT)); + m_frame_pack_arrangement.cancel_flag = 1; + + drv_ctx.timestamp_adjust = false; + m_vendor_config.pData = NULL; + pthread_mutex_init(&m_lock, NULL); + pthread_mutex_init(&c_lock, NULL); + pthread_mutex_init(&buf_lock, NULL); + sem_init(&m_cmd_lock,0,0); + sem_init(&m_safe_flush, 0, 0); + streaming[CAPTURE_PORT] = + streaming[OUTPUT_PORT] = false; +#ifdef _ANDROID_ + char extradata_value[PROPERTY_VALUE_MAX] = {0}; + property_get("vidc.dec.debug.extradata", extradata_value, "0"); + m_debug_extradata = atoi(extradata_value); + DEBUG_PRINT_HIGH("vidc.dec.debug.extradata value is %d",m_debug_extradata); +#endif + m_fill_output_msg = OMX_COMPONENT_GENERATE_FTB; + client_buffers.set_vdec_client(this); + dynamic_buf_mode = false; + out_dynamic_list = NULL; + is_down_scalar_enabled = false; + m_downscalar_width = 0; + m_downscalar_height = 0; + m_force_down_scalar = 0; + m_reconfig_height = 0; + m_reconfig_width = 0; + m_smoothstreaming_mode = false; + m_smoothstreaming_width = 0; + m_smoothstreaming_height = 0; + is_q6_platform = false; + m_perf_control.send_hint_to_mpctl(true); + m_input_pass_buffer_fd = false; + memset(&m_extradata_info, 0, sizeof(m_extradata_info)); + m_client_color_space.nPortIndex = (OMX_U32)OMX_CORE_INPUT_PORT_INDEX; + m_client_color_space.sAspects.mRange = ColorAspects::RangeUnspecified; + m_client_color_space.sAspects.mPrimaries = ColorAspects::PrimariesUnspecified; + m_client_color_space.sAspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified; + m_client_color_space.sAspects.mTransfer = ColorAspects::TransferUnspecified; + + m_internal_color_space.nPortIndex = (OMX_U32)OMX_CORE_OUTPUT_PORT_INDEX; + m_internal_color_space.sAspects.mRange = ColorAspects::RangeUnspecified; + m_internal_color_space.sAspects.mPrimaries = ColorAspects::PrimariesUnspecified; + m_internal_color_space.sAspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified; + m_internal_color_space.sAspects.mTransfer = ColorAspects::TransferUnspecified; + m_internal_color_space.nSize = sizeof(DescribeColorAspectsParams); + + m_client_hdr_info.nPortIndex = (OMX_U32)OMX_CORE_INPUT_PORT_INDEX; + m_internal_hdr_info.nPortIndex = (OMX_U32)OMX_CORE_OUTPUT_PORT_INDEX; + m_change_client_hdr_info = false; + pthread_mutex_init(&m_hdr_info_client_lock, NULL); + m_dither_config = is_platform_tp10capture_supported() ? DITHER_DISABLE : DITHER_ALL_COLORSPACE; + m_color_space = EXCEPT_BT2020; +} + +static const int event_type[] = { + V4L2_EVENT_MSM_VIDC_FLUSH_DONE, + V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT, + V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT, + V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_BITDEPTH_CHANGED_INSUFFICIENT, + V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE, + V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER, + V4L2_EVENT_MSM_VIDC_SYS_ERROR, + V4L2_EVENT_MSM_VIDC_HW_OVERLOAD, + V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED +}; + +static OMX_ERRORTYPE subscribe_to_events(int fd) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_event_subscription sub; + int array_sz = sizeof(event_type)/sizeof(int); + int i,rc; + if (fd < 0) { + DEBUG_PRINT_ERROR("Invalid input: %d", fd); + return OMX_ErrorBadParameter; + } + + for (i = 0; i < array_sz; ++i) { + memset(&sub, 0, sizeof(sub)); + sub.type = event_type[i]; + rc = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub); + if (rc) { + DEBUG_PRINT_ERROR("Failed to subscribe event: 0x%x", sub.type); + break; + } + } + if (i < array_sz) { + for (--i; i >=0 ; i--) { + memset(&sub, 0, sizeof(sub)); + sub.type = event_type[i]; + rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub); + if (rc) + DEBUG_PRINT_ERROR("Failed to unsubscribe event: 0x%x", sub.type); + } + eRet = OMX_ErrorNotImplemented; + } + return eRet; +} + + +static OMX_ERRORTYPE unsubscribe_to_events(int fd) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_event_subscription sub; + int array_sz = sizeof(event_type)/sizeof(int); + int i,rc; + if (fd < 0) { + DEBUG_PRINT_ERROR("Invalid input: %d", fd); + return OMX_ErrorBadParameter; + } + + for (i = 0; i < array_sz; ++i) { + memset(&sub, 0, sizeof(sub)); + sub.type = event_type[i]; + rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub); + if (rc) { + DEBUG_PRINT_ERROR("Failed to unsubscribe event: 0x%x", sub.type); + break; + } + } + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::~omx_vdec + + DESCRIPTION + Destructor + + PARAMETERS + None + + RETURN VALUE + None. + ========================================================================== */ +omx_vdec::~omx_vdec() +{ + m_pmem_info = NULL; + DEBUG_PRINT_HIGH("In OMX vdec Destructor"); + if (msg_thread_created) { + DEBUG_PRINT_HIGH("Signalling close to OMX Msg Thread"); + message_thread_stop = true; + post_message(this, OMX_COMPONENT_CLOSE_MSG); + DEBUG_PRINT_HIGH("Waiting on OMX Msg Thread exit"); + pthread_join(msg_thread_id,NULL); + } + close(m_pipe_in); + close(m_pipe_out); + m_pipe_in = -1; + m_pipe_out = -1; + DEBUG_PRINT_HIGH("Waiting on OMX Async Thread exit"); + if(eventfd_write(m_poll_efd, 1)) { + DEBUG_PRINT_ERROR("eventfd_write failed for fd: %d, errno = %d, force stop async_thread", m_poll_efd, errno); + async_thread_force_stop = true; + } + + if (async_thread_created) + pthread_join(async_thread_id,NULL); + unsubscribe_to_events(drv_ctx.video_driver_fd); + close(m_poll_efd); + close(drv_ctx.video_driver_fd); + pthread_mutex_destroy(&m_lock); + pthread_mutex_destroy(&c_lock); + pthread_mutex_destroy(&buf_lock); + sem_destroy(&m_cmd_lock); + pthread_mutex_destroy(&m_hdr_info_client_lock); + if (perf_flag) { + DEBUG_PRINT_HIGH("--> TOTAL PROCESSING TIME"); + dec_time.end(); + } + DEBUG_PRINT_INFO("Exit OMX vdec Destructor: fd=%d",drv_ctx.video_driver_fd); + m_perf_control.send_hint_to_mpctl(false); +} + +int release_buffers(omx_vdec* obj, enum vdec_buffer buffer_type) +{ + struct v4l2_requestbuffers bufreq; + int rc = 0; + if (buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = 0; + bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + rc = ioctl(obj->drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); + } else if(buffer_type == VDEC_BUFFER_TYPE_INPUT) { + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = 0; + bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + rc = ioctl(obj->drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); + } + return rc; +} + +OMX_ERRORTYPE omx_vdec::set_dpb(bool is_split_mode, int dpb_color_format) +{ + int rc = 0; + struct v4l2_ext_control ctrl[2]; + struct v4l2_ext_controls controls; + + DEBUG_PRINT_HIGH("DPB mode: %s DPB color format: %s OPB color format: %s", + is_split_mode ? "split" : "combined", + dpb_color_format == V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC ? "nv12_ubwc": + dpb_color_format == V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC ? "nv12_10bit_ubwc": + dpb_color_format == V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE ? "same as opb": + "unknown", + capture_capability == V4L2_PIX_FMT_NV12 ? "nv12": + capture_capability == V4L2_PIX_FMT_NV12_UBWC ? "nv12_ubwc": + capture_capability == V4L2_PIX_FMT_NV12_TP10_UBWC ? "nv12_10bit_ubwc": + "unknown"); + + ctrl[0].id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE; + if (is_split_mode) { + ctrl[0].value = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY; + } else { + ctrl[0].value = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY; + } + + ctrl[1].id = V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT; + ctrl[1].value = dpb_color_format; + + controls.count = 2; + controls.ctrl_class = V4L2_CTRL_CLASS_MPEG; + controls.controls = ctrl; + + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_EXT_CTRLS, &controls); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set ext ctrls for opb_dpb: %d\n", rc); + return OMX_ErrorUnsupportedSetting; + } + return OMX_ErrorNone; +} + + +OMX_ERRORTYPE omx_vdec::decide_dpb_buffer_mode(bool split_opb_dpb_with_same_color_fmt) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_format fmt; + int rc = 0; + bool cpu_access = (capture_capability != V4L2_PIX_FMT_NV12_UBWC) && + capture_capability != V4L2_PIX_FMT_NV12_TP10_UBWC; + bool tp10_enable = !cpu_access && + dpb_bit_depth == MSM_VIDC_BIT_DEPTH_10; + bool dither_enable = true; + + switch (m_dither_config) { + case DITHER_DISABLE: + dither_enable = false; + break; + case DITHER_COLORSPACE_EXCEPTBT2020: + dither_enable = (m_color_space == EXCEPT_BT2020); + break; + case DITHER_ALL_COLORSPACE: + dither_enable = true; + break; + default: + DEBUG_PRINT_ERROR("Unsupported dither configuration:%d", m_dither_config); + } + + if (tp10_enable && !dither_enable) { + drv_ctx.output_format = VDEC_YUV_FORMAT_NV12_TP10_UBWC; + capture_capability = V4L2_PIX_FMT_NV12_TP10_UBWC; + + memset(&fmt, 0x0, sizeof(struct v4l2_format)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_G_FMT, &fmt); + if (rc) { + DEBUG_PRINT_ERROR("%s: Failed get format on capture mplane", __func__); + return OMX_ErrorUnsupportedSetting; + } + fmt.fmt.pix_mp.pixelformat = capture_capability; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (rc) { + DEBUG_PRINT_ERROR("%s: Failed set format on capture mplane", __func__); + return OMX_ErrorUnsupportedSetting; + } + + } + + + if (!BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_IDLE_PENDING) && + !BITMASK_PRESENT(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) { + DEBUG_PRINT_LOW("Invalid state to decide on dpb-opb split"); + return eRet; + } + + + if (cpu_access) { + if (dpb_bit_depth == MSM_VIDC_BIT_DEPTH_8) { + /* Disabled split mode for VP9. In split mode the DPB buffers are part of the internal + * scratch buffers and the driver does not does the reference buffer management for + * scratch buffers. In case of VP9 with spatial scalability, when a sequence changed + * event is received with the new resolution, and when a flush is sent by the driver, it + * releases all the references of internal scratch buffers. However as per the VP9 + * spatial scalability, even after the flush, the buffers which have not yet received + * release reference event should not be unmapped and freed. Currently in driver, + * reference buffer management of the internal scratch buffer is not implemented + * and hence the DPB buffers get unmapped. For other codecs it does not matter + * as with the new SPS/PPS, the DPB is flushed. + */ + bool is_not_vp9 = eCompressionFormat != OMX_VIDEO_CodingVP9; + bool eligible_for_split_dpb_ubwc = + m_progressive == MSM_VIDC_PIC_STRUCT_PROGRESSIVE && //@ Due to Venus limitation for Interlaced, Split mode enabled only for Progressive. + is_not_vp9 && //@ Split mode disabled for VP9. + !drv_ctx.idr_only_decoding && //@ Split mode disabled for Thumbnail usecase. + !m_disable_split_mode; //@ Set prop to disable split mode + + //Since opb is linear, dpb should also be linear. + if (split_opb_dpb_with_same_color_fmt) { + eligible_for_split_dpb_ubwc = false; + } + + if (eligible_for_split_dpb_ubwc) { + //split DPB-OPB + //DPB -> UBWC , OPB -> Linear + eRet = set_dpb(true, V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC); + } else if (split_opb_dpb_with_same_color_fmt) { + //DPB -> Linear, OPB -> Linear + eRet = set_dpb(true, V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE); + } else { + //DPB-OPB combined linear + eRet = set_dpb(false, V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE); + } + } else if (dpb_bit_depth == MSM_VIDC_BIT_DEPTH_10) { + //split DPB-OPB + //DPB -> UBWC, OPB -> Linear + eRet = set_dpb(true, V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC); + } + } else { //no cpu access + if (dpb_bit_depth == MSM_VIDC_BIT_DEPTH_8) { + if (split_opb_dpb_with_same_color_fmt) { + //split DPB-OPB + //DPB -> UBWC, OPB -> UBWC + eRet = set_dpb(true, V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC); + } else { + //DPB-OPB combined UBWC + eRet = set_dpb(false, V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE); + } + } else if (dpb_bit_depth == MSM_VIDC_BIT_DEPTH_10) { + if (dither_enable) { + //split DPB-OPB + //DPB -> TP10UBWC, OPB -> UBWC + eRet = set_dpb(true, V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC); + } else { + //combined DPB-OPB + //DPB -> TP10UBWC, OPB -> TP10UBWC + eRet = set_dpb(false, V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC); + } + } + } + if (eRet) { + DEBUG_PRINT_HIGH("Failed to set DPB buffer mode: %d", eRet); + } + + + + return eRet; +} + +int omx_vdec::enable_downscalar() +{ + int rc = 0; + struct v4l2_control control; + struct v4l2_format fmt; + + if (is_down_scalar_enabled) { + DEBUG_PRINT_LOW("%s: already enabled", __func__); + return 0; + } + + DEBUG_PRINT_LOW("omx_vdec::enable_downscalar"); + rc = decide_dpb_buffer_mode(true); + if (rc) { + DEBUG_PRINT_ERROR("%s: decide_dpb_buffer_mode Failed ", __func__); + return rc; + } + is_down_scalar_enabled = true; + + memset(&control, 0x0, sizeof(struct v4l2_control)); + control.id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO; + control.value = 1; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("%s: Failed to set VIDEO_KEEP_ASPECT_RATIO", __func__); + return rc; + } + + return 0; +} + +int omx_vdec::disable_downscalar() +{ + int rc = 0; + struct v4l2_control control; + + if (!is_down_scalar_enabled) { + DEBUG_PRINT_LOW("omx_vdec::disable_downscalar: already disabled"); + return 0; + } + + rc = decide_dpb_buffer_mode(false); + if (rc < 0) { + DEBUG_PRINT_ERROR("%s:decide_dpb_buffer_mode failed\n", __func__); + return rc; + } + is_down_scalar_enabled = false; + + return rc; +} + +int omx_vdec::decide_downscalar() +{ + int rc = 0; + struct v4l2_format fmt; + enum color_fmts color_format; + OMX_U32 width, height; + + if (capture_capability == V4L2_PIX_FMT_NV12_TP10_UBWC) { + rc = disable_downscalar(); + if (rc) { + DEBUG_PRINT_ERROR("Disable downscalar failed!"); + return rc; + } + return 0; + } + + if (!m_downscalar_width || !m_downscalar_height) { + DEBUG_PRINT_LOW("%s: downscalar not supported", __func__); + return 0; + } + + if (m_force_down_scalar) { + DEBUG_PRINT_LOW("%s: m_force_down_scalar %d ", __func__, m_force_down_scalar); + return 0; + } + + memset(&fmt, 0x0, sizeof(struct v4l2_format)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = capture_capability; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_G_FMT, &fmt); + if (rc < 0) { + DEBUG_PRINT_ERROR("%s: Failed to get format on capture mplane", __func__); + return rc; + } + + height = fmt.fmt.pix_mp.height; + width = fmt.fmt.pix_mp.width; + + DEBUG_PRINT_HIGH("%s: driver wxh = %dx%d, downscalar wxh = %dx%d m_is_display_session = %d", __func__, + fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height, m_downscalar_width, m_downscalar_height, m_is_display_session); + + if ((fmt.fmt.pix_mp.width * fmt.fmt.pix_mp.height >= m_downscalar_width * m_downscalar_height) && + m_is_display_session) { + rc = enable_downscalar(); + if (rc < 0) { + DEBUG_PRINT_ERROR("%s: enable_downscalar failed\n", __func__); + return rc; + } + + width = m_downscalar_width > fmt.fmt.pix_mp.width ? + fmt.fmt.pix_mp.width : m_downscalar_width; + height = m_downscalar_height > fmt.fmt.pix_mp.height ? + fmt.fmt.pix_mp.height : m_downscalar_height; + switch (capture_capability) { + case V4L2_PIX_FMT_NV12: + color_format = COLOR_FMT_NV12; + break; + case V4L2_PIX_FMT_NV12_UBWC: + color_format = COLOR_FMT_NV12_UBWC; + break; + case V4L2_PIX_FMT_NV12_TP10_UBWC: + color_format = COLOR_FMT_NV12_BPP10_UBWC; + break; + default: + DEBUG_PRINT_ERROR("Color format not recognized\n"); + rc = OMX_ErrorUndefined; + return rc; + } + } else { + + rc = disable_downscalar(); + if (rc < 0) { + DEBUG_PRINT_ERROR("%s: disable_downscalar failed\n", __func__); + return rc; + } + } + + memset(&fmt, 0x0, sizeof(struct v4l2_format)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.height = height; + fmt.fmt.pix_mp.width = width; + fmt.fmt.pix_mp.pixelformat = capture_capability; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (rc) { + DEBUG_PRINT_ERROR("%s: Failed set format on capture mplane", __func__); + return rc; + } + + rc = get_buffer_req(&drv_ctx.op_buf); + if (rc) { + DEBUG_PRINT_ERROR("%s: Failed to get output buffer requirements", __func__); + return rc; + } + + return rc; +} + +/* ====================================================================== + FUNCTION + omx_vdec::OMXCntrlProcessMsgCb + + DESCRIPTION + IL Client callbacks are generated through this routine. The decoder + provides the thread context for this routine. + + PARAMETERS + ctxt -- Context information related to the self. + id -- Event identifier. This could be any of the following: + 1. Command completion event + 2. Buffer done callback event + 3. Frame done callback event + + RETURN VALUE + None. + + ========================================================================== */ +void omx_vdec::process_event_cb(void *ctxt, unsigned char id) +{ + unsigned long p1; // Parameter - 1 + unsigned long p2; // Parameter - 2 + unsigned long ident; + unsigned qsize=0; // qsize + omx_vdec *pThis = (omx_vdec *) ctxt; + + if (!pThis) { + DEBUG_PRINT_ERROR("ERROR: %s()::Context is incorrect, bailing out", + __func__); + return; + } + + // Protect the shared queue data structure + do { + /*Read the message id's from the queue*/ + pthread_mutex_lock(&pThis->m_lock); + qsize = pThis->m_cmd_q.m_size; + if (qsize) { + pThis->m_cmd_q.pop_entry(&p1, &p2, &ident); + } + + if (qsize == 0 && pThis->m_state != OMX_StatePause) { + qsize = pThis->m_ftb_q.m_size; + if (qsize) { + pThis->m_ftb_q.pop_entry(&p1, &p2, &ident); + } + } + + if (qsize == 0 && pThis->m_state != OMX_StatePause) { + qsize = pThis->m_etb_q.m_size; + if (qsize) { + pThis->m_etb_q.pop_entry(&p1, &p2, &ident); + } + } + pthread_mutex_unlock(&pThis->m_lock); + + /*process message if we have one*/ + if (qsize > 0) { + id = ident; + switch (id) { + case OMX_COMPONENT_GENERATE_EVENT: + if (pThis->m_cb.EventHandler) { + switch (p1) { + case OMX_CommandStateSet: + pThis->m_state = (OMX_STATETYPE) p2; + DEBUG_PRINT_HIGH("OMX_CommandStateSet complete, m_state = %d", + pThis->m_state); + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete, p1, p2, NULL); + break; + + case OMX_EventError: + if (p2 == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("OMX_EventError: p2 is OMX_StateInvalid"); + pThis->m_state = (OMX_STATETYPE) p2; + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventError, OMX_ErrorInvalidState, p2, NULL); + } else if (p2 == (unsigned long)OMX_ErrorHardware) { + pThis->omx_report_error(); + } else { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventError, p2, (OMX_U32)NULL, NULL ); + } + break; + + case OMX_CommandPortDisable: + DEBUG_PRINT_HIGH("OMX_CommandPortDisable complete for port [%lu]", p2); + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING)) { + BITMASK_SET(&pThis->m_flags, OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED); + break; + } + if (p2 == OMX_CORE_OUTPUT_PORT_INDEX) { + OMX_ERRORTYPE eRet = OMX_ErrorNone; + pThis->stream_off(OMX_CORE_OUTPUT_PORT_INDEX); + if (release_buffers(pThis, VDEC_BUFFER_TYPE_OUTPUT)) + DEBUG_PRINT_HIGH("Failed to release output buffers"); + OMX_ERRORTYPE eRet1 = pThis->get_buffer_req(&pThis->drv_ctx.op_buf); + pThis->in_reconfig = false; + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("set_buffer_req failed eRet = %d",eRet); + pThis->omx_report_error(); + break; + } + } + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete, p1, p2, NULL ); + break; + case OMX_CommandPortEnable: + DEBUG_PRINT_HIGH("OMX_CommandPortEnable complete for port [%lu]", p2); + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,\ + OMX_EventCmdComplete, p1, p2, NULL ); + break; + + default: + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete, p1, p2, NULL ); + break; + + } + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + break; + case OMX_COMPONENT_GENERATE_ETB_ARBITRARY: + if (pThis->empty_this_buffer_proxy_arbitrary((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)(intptr_t)p2) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("empty_this_buffer_proxy_arbitrary failure"); + pThis->omx_report_error (); + } + break; + case OMX_COMPONENT_GENERATE_ETB: { + OMX_ERRORTYPE iret; + iret = pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1, (OMX_BUFFERHEADERTYPE *)p2); + if (iret == OMX_ErrorInsufficientResources) { + DEBUG_PRINT_ERROR("empty_this_buffer_proxy failure due to HW overload"); + pThis->omx_report_hw_overload (); + } else if (iret != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("empty_this_buffer_proxy failure"); + pThis->omx_report_error (); + } + } + break; + + case OMX_COMPONENT_GENERATE_FTB: + if ( pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)(intptr_t)p1,\ + (OMX_BUFFERHEADERTYPE *)(intptr_t)p2) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("fill_this_buffer_proxy failure"); + pThis->omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_COMMAND: + pThis->send_command_proxy(&pThis->m_cmp,(OMX_COMMANDTYPE)p1,\ + (OMX_U32)p2,(OMX_PTR)NULL); + break; + + case OMX_COMPONENT_GENERATE_EBD: + + if (p2 != VDEC_S_SUCCESS && p2 != VDEC_S_INPUT_BITSTREAM_ERR) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_EBD failure"); + pThis->omx_report_error (); + } else { + if (p2 == VDEC_S_INPUT_BITSTREAM_ERR && p1) { + pThis->time_stamp_dts.remove_time_stamp( + ((OMX_BUFFERHEADERTYPE *)(intptr_t)p1)->nTimeStamp, + (pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) + ?true:false); + } + + if ( pThis->empty_buffer_done(&pThis->m_cmp, + (OMX_BUFFERHEADERTYPE *)(intptr_t)p1) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("empty_buffer_done failure"); + pThis->omx_report_error (); + } + } + break; + case OMX_COMPONENT_GENERATE_INFO_FIELD_DROPPED: { + int64_t *timestamp = (int64_t *)(intptr_t)p1; + if (p1) { + pThis->time_stamp_dts.remove_time_stamp(*timestamp, + (pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) + ?true:false); + free(timestamp); + } + } + break; + case OMX_COMPONENT_GENERATE_FBD: + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_FBD failure"); + pThis->omx_report_error (); + } else if ( pThis->fill_buffer_done(&pThis->m_cmp, + (OMX_BUFFERHEADERTYPE *)(intptr_t)p1) != OMX_ErrorNone ) { + DEBUG_PRINT_ERROR("fill_buffer_done failure"); + pThis->omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH: + DEBUG_PRINT_HIGH("Driver flush i/p Port complete"); + if (!pThis->input_flush_progress) { + DEBUG_PRINT_HIGH("WARNING: Unexpected flush from driver"); + } else { + pThis->execute_input_flush(); + if (pThis->m_cb.EventHandler) { + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH failure"); + pThis->omx_report_error (); + } else { + /*Check if we need generate event for Flush done*/ + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_INPUT_FLUSH_PENDING)) { + BITMASK_CLEAR (&pThis->m_flags,OMX_COMPONENT_INPUT_FLUSH_PENDING); + DEBUG_PRINT_LOW("Input Flush completed - Notify Client"); + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandFlush, + OMX_CORE_INPUT_PORT_INDEX,NULL ); + } + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_IDLE_PENDING)) { + if (pThis->stream_off(OMX_CORE_INPUT_PORT_INDEX)) { + DEBUG_PRINT_ERROR("Failed to call streamoff on OUTPUT Port"); + pThis->omx_report_error (); + } else { + pThis->streaming[OUTPUT_PORT] = false; + } + if (!pThis->output_flush_progress) { + DEBUG_PRINT_LOW("Input flush done hence issue stop"); + pThis->post_event ((unsigned int)NULL, VDEC_S_SUCCESS,\ + OMX_COMPONENT_GENERATE_STOP_DONE); + } + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + } + break; + + case OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH: + DEBUG_PRINT_HIGH("Driver flush o/p Port complete"); + if (!pThis->output_flush_progress) { + DEBUG_PRINT_HIGH("WARNING: Unexpected flush from driver"); + } else { + pThis->execute_output_flush(); + if (pThis->m_cb.EventHandler) { + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH failed"); + pThis->omx_report_error (); + } else { + /*Check if we need generate event for Flush done*/ + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_PENDING)) { + DEBUG_PRINT_LOW("Notify Output Flush done"); + BITMASK_CLEAR (&pThis->m_flags,OMX_COMPONENT_OUTPUT_FLUSH_PENDING); + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandFlush, + OMX_CORE_OUTPUT_PORT_INDEX,NULL ); + } + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING)) { + DEBUG_PRINT_LOW("Internal flush complete"); + BITMASK_CLEAR (&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING); + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED)) { + pThis->post_event(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + BITMASK_CLEAR (&pThis->m_flags, + OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED); + BITMASK_CLEAR (&pThis->m_flags, + OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + + } + } + + if (BITMASK_PRESENT(&pThis->m_flags ,OMX_COMPONENT_IDLE_PENDING)) { + if (pThis->stream_off(OMX_CORE_OUTPUT_PORT_INDEX)) { + DEBUG_PRINT_ERROR("Failed to call streamoff on CAPTURE Port"); + pThis->omx_report_error (); + break; + } + pThis->streaming[CAPTURE_PORT] = false; + if (!pThis->input_flush_progress) { + DEBUG_PRINT_LOW("Output flush done hence issue stop"); + pThis->post_event ((unsigned int)NULL, VDEC_S_SUCCESS,\ + OMX_COMPONENT_GENERATE_STOP_DONE); + } + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + } + break; + + case OMX_COMPONENT_GENERATE_START_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_START_DONE"); + + if (pThis->m_cb.EventHandler) { + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_START_DONE Failure"); + pThis->omx_report_error (); + } else { + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_START_DONE Success"); + if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_EXECUTE_PENDING)) { + DEBUG_PRINT_LOW("Move to executing"); + // Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_EXECUTE_PENDING); + pThis->m_state = OMX_StateExecuting; + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StateExecuting, NULL); + } else if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_PAUSE_PENDING)) { + if (/*ioctl (pThis->drv_ctx.video_driver_fd, + VDEC_IOCTL_CMD_PAUSE,NULL ) < */0) { + DEBUG_PRINT_ERROR("VDEC_IOCTL_CMD_PAUSE failed"); + pThis->omx_report_error (); + } + } + } + } else { + DEBUG_PRINT_LOW("Event Handler callback is NULL"); + } + break; + + case OMX_COMPONENT_GENERATE_PAUSE_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_PAUSE_DONE"); + if (pThis->m_cb.EventHandler) { + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_PAUSE_DONE ret failed"); + pThis->omx_report_error (); + } else { + pThis->complete_pending_buffer_done_cbs(); + if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_PAUSE_PENDING)) { + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_PAUSE_DONE nofity"); + //Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_PAUSE_PENDING); + pThis->m_state = OMX_StatePause; + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StatePause, NULL); + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + + break; + + case OMX_COMPONENT_GENERATE_RESUME_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_RESUME_DONE"); + if (pThis->m_cb.EventHandler) { + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_RESUME_DONE failed"); + pThis->omx_report_error (); + } else { + if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_EXECUTE_PENDING)) { + DEBUG_PRINT_LOW("Moving the decoder to execute state"); + // Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_EXECUTE_PENDING); + pThis->m_state = OMX_StateExecuting; + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StateExecuting,NULL); + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + + break; + + case OMX_COMPONENT_GENERATE_STOP_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_STOP_DONE"); + if (pThis->m_cb.EventHandler) { + if (p2 != VDEC_S_SUCCESS) { + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_STOP_DONE ret failed"); + pThis->omx_report_error (); + } else { + pThis->complete_pending_buffer_done_cbs(); + if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_IDLE_PENDING)) { + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_STOP_DONE Success"); + // Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_IDLE_PENDING); + pThis->m_state = OMX_StateIdle; + DEBUG_PRINT_LOW("Move to Idle State"); + pThis->m_cb.EventHandler(&pThis->m_cmp,pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StateIdle,NULL); + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + + break; + + case OMX_COMPONENT_GENERATE_PORT_RECONFIG: + if (p2 == OMX_IndexParamPortDefinition) { + DEBUG_PRINT_HIGH("Rxd PORT_RECONFIG: OMX_IndexParamPortDefinition"); + pThis->in_reconfig = true; + } else if (p2 == OMX_IndexConfigCommonOutputCrop) { + DEBUG_PRINT_HIGH("Rxd PORT_RECONFIG: OMX_IndexConfigCommonOutputCrop"); + + /* Check if resolution is changed in smooth streaming mode */ + if (pThis->m_smoothstreaming_mode && + (pThis->framesize.nWidth != + pThis->drv_ctx.video_resolution.frame_width) || + (pThis->framesize.nHeight != + pThis->drv_ctx.video_resolution.frame_height)) { + + DEBUG_PRINT_HIGH("Resolution changed from: wxh = %dx%d to: wxh = %dx%d", + pThis->framesize.nWidth, + pThis->framesize.nHeight, + pThis->drv_ctx.video_resolution.frame_width, + pThis->drv_ctx.video_resolution.frame_height); + + /* Update new resolution */ + pThis->framesize.nWidth = + pThis->drv_ctx.video_resolution.frame_width; + pThis->framesize.nHeight = + pThis->drv_ctx.video_resolution.frame_height; + + /* Update C2D with new resolution */ + if (!pThis->client_buffers.update_buffer_req()) { + DEBUG_PRINT_ERROR("Setting C2D buffer requirements failed"); + } + } + + /* Update new crop information */ + pThis->rectangle.nLeft = pThis->drv_ctx.frame_size.left; + pThis->rectangle.nTop = pThis->drv_ctx.frame_size.top; + pThis->rectangle.nWidth = pThis->drv_ctx.frame_size.right; + pThis->rectangle.nHeight = pThis->drv_ctx.frame_size.bottom; + + /* Validate the new crop information */ + if (pThis->rectangle.nLeft + pThis->rectangle.nWidth > + pThis->drv_ctx.video_resolution.frame_width) { + + DEBUG_PRINT_HIGH("Crop L[%u] + R[%u] > W[%u]", + pThis->rectangle.nLeft, pThis->rectangle.nWidth, + pThis->drv_ctx.video_resolution.frame_width); + pThis->rectangle.nLeft = 0; + + if (pThis->rectangle.nWidth > + pThis->drv_ctx.video_resolution.frame_width) { + + DEBUG_PRINT_HIGH("Crop R[%u] > W[%u]", + pThis->rectangle.nWidth, + pThis->drv_ctx.video_resolution.frame_width); + pThis->rectangle.nWidth = + pThis->drv_ctx.video_resolution.frame_width; + } + } + if (pThis->rectangle.nTop + pThis->rectangle.nHeight > + pThis->drv_ctx.video_resolution.frame_height) { + + DEBUG_PRINT_HIGH("Crop T[%u] + B[%u] > H[%u]", + pThis->rectangle.nTop, pThis->rectangle.nHeight, + pThis->drv_ctx.video_resolution.frame_height); + pThis->rectangle.nTop = 0; + + if (pThis->rectangle.nHeight > + pThis->drv_ctx.video_resolution.frame_height) { + + DEBUG_PRINT_HIGH("Crop B[%u] > H[%u]", + pThis->rectangle.nHeight, + pThis->drv_ctx.video_resolution.frame_height); + pThis->rectangle.nHeight = + pThis->drv_ctx.video_resolution.frame_height; + } + } + DEBUG_PRINT_HIGH("Updated Crop Info: L: %u, T: %u, R: %u, B: %u", + pThis->rectangle.nLeft, pThis->rectangle.nTop, + pThis->rectangle.nWidth, pThis->rectangle.nHeight); + } else if (p2 == OMX_QTIIndexConfigDescribeColorAspects) { + DEBUG_PRINT_HIGH("Rxd PORT_RECONFIG: OMX_QTIIndexConfigDescribeColorAspects"); + } else if (p2 == OMX_QTIIndexConfigDescribeHDRColorInfo) { + DEBUG_PRINT_HIGH("Rxd PORT_RECONFIG: OMX_QTIIndexConfigDescribeHDRcolorinfo"); + } else { + DEBUG_PRINT_ERROR("Rxd Invalid PORT_RECONFIG event (%lu)", p2); + break; + } + if (pThis->m_debug.outfile) { + fclose(pThis->m_debug.outfile); + pThis->m_debug.outfile = NULL; + } + if (pThis->m_debug.out_ymeta_file) { + fclose(pThis->m_debug.out_ymeta_file); + pThis->m_debug.out_ymeta_file = NULL; + } + if (pThis->m_debug.out_uvmeta_file) { + fclose(pThis->m_debug.out_uvmeta_file); + pThis->m_debug.out_uvmeta_file = NULL; + } + + if (pThis->secure_mode && pThis->m_cb.EventHandler && pThis->in_reconfig) { + pThis->prefetchNewBuffers(); + } + + if (pThis->m_cb.EventHandler) { + uint32_t frame_data[4]; + frame_data[0] = (p2 == OMX_IndexParamPortDefinition) ? + pThis->m_reconfig_height : pThis->rectangle.nHeight; + frame_data[1] = (p2 == OMX_IndexParamPortDefinition) ? + pThis->m_reconfig_width : pThis->rectangle.nWidth; + + frame_data[2] = (p2 == OMX_IndexParamPortDefinition) ? + frame_data[0] : pThis->drv_ctx.video_resolution.frame_height; + + frame_data[3] = (p2 == OMX_IndexParamPortDefinition) ? + frame_data[1] : pThis->drv_ctx.video_resolution.frame_width; + + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventPortSettingsChanged, p1, p2, (void*) frame_data ); + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + break; + + case OMX_COMPONENT_GENERATE_EOS_DONE: + DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_EOS_DONE"); + if (pThis->m_cb.EventHandler) { + pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, OMX_EventBufferFlag, + OMX_CORE_OUTPUT_PORT_INDEX, OMX_BUFFERFLAG_EOS, NULL ); + } else { + DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); + } + pThis->prev_ts = LLONG_MAX; + pThis->rst_prev_ts = true; + break; + + case OMX_COMPONENT_GENERATE_HARDWARE_ERROR: + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_HARDWARE_ERROR"); + pThis->omx_report_error(); + break; + + case OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING: + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING"); + pThis->omx_report_unsupported_setting(); + break; + + case OMX_COMPONENT_GENERATE_HARDWARE_OVERLOAD: + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_HARDWARE_OVERLOAD"); + pThis->omx_report_hw_overload(); + break; + + default: + break; + } + } + pthread_mutex_lock(&pThis->m_lock); + qsize = pThis->m_cmd_q.m_size; + if (pThis->m_state != OMX_StatePause) + qsize += (pThis->m_ftb_q.m_size + pThis->m_etb_q.m_size); + pthread_mutex_unlock(&pThis->m_lock); + } while (qsize>0); + +} + +int omx_vdec::update_resolution(int width, int height, int stride, int scan_lines) +{ + int format_changed = 0; + if ((height != (int)drv_ctx.video_resolution.frame_height) || + (width != (int)drv_ctx.video_resolution.frame_width)) { + DEBUG_PRINT_HIGH("NOTE_CIF: W/H %d (%d), %d (%d)", + width, drv_ctx.video_resolution.frame_width, + height,drv_ctx.video_resolution.frame_height); + format_changed = 1; + } + drv_ctx.video_resolution.frame_height = height; + drv_ctx.video_resolution.frame_width = width; + drv_ctx.video_resolution.scan_lines = scan_lines; + drv_ctx.video_resolution.stride = stride; + + if (!is_down_scalar_enabled) { + rectangle.nLeft = m_extradata_info.output_crop_rect.nLeft; + rectangle.nTop = m_extradata_info.output_crop_rect.nTop; + rectangle.nWidth = m_extradata_info.output_crop_rect.nWidth; + rectangle.nHeight = m_extradata_info.output_crop_rect.nHeight; + } + return format_changed; +} + +OMX_ERRORTYPE omx_vdec::is_video_session_supported() +{ + if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc", + OMX_MAX_STRINGNAME_SIZE) && + (m_profile == HIGH_PROFILE || m_profile == MAIN_PROFILE)) { + m_decoder_capability.max_width = 1280; + m_decoder_capability.max_height = 720; + DEBUG_PRINT_HIGH("Set max_width=1280 & max_height=720 for H264 HP/MP"); + } + + if ((drv_ctx.video_resolution.frame_width * + drv_ctx.video_resolution.frame_height > + m_decoder_capability.max_width * + m_decoder_capability.max_height) || + (drv_ctx.video_resolution.frame_width* + drv_ctx.video_resolution.frame_height < + m_decoder_capability.min_width * + m_decoder_capability.min_height)) { + DEBUG_PRINT_ERROR( + "Unsupported WxH = (%u)x(%u) supported range is min(%u)x(%u) - max(%u)x(%u)", + drv_ctx.video_resolution.frame_width, + drv_ctx.video_resolution.frame_height, + m_decoder_capability.min_width, + m_decoder_capability.min_height, + m_decoder_capability.max_width, + m_decoder_capability.max_height); + return OMX_ErrorUnsupportedSetting; + } + DEBUG_PRINT_HIGH("video session supported"); + return OMX_ErrorNone; +} + +int omx_vdec::log_input_buffers(const char *buffer_addr, int buffer_len) +{ + if (m_debug.in_buffer_log && !m_debug.infile) { + if(!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.mpeg4", OMX_MAX_STRINGNAME_SIZE)) { + snprintf(m_debug.infile_name, OMX_MAX_STRINGNAME_SIZE, "%s/input_dec_%d_%d_%p.m4v", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + } else if(!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.mpeg2", OMX_MAX_STRINGNAME_SIZE)) { + snprintf(m_debug.infile_name, OMX_MAX_STRINGNAME_SIZE, "%s/input_dec_%d_%d_%p.mpg", m_debug.log_loc, + drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + } else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263", OMX_MAX_STRINGNAME_SIZE)) { + snprintf(m_debug.infile_name, OMX_MAX_STRINGNAME_SIZE, "%s/input_dec_%d_%d_%p.263", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + } else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc", OMX_MAX_STRINGNAME_SIZE) || + !strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mvc", OMX_MAX_STRINGNAME_SIZE)) { + snprintf(m_debug.infile_name, OMX_MAX_STRINGNAME_SIZE, "%s/input_dec_%d_%d_%p.264", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + } else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc", OMX_MAX_STRINGNAME_SIZE)) { + snprintf(m_debug.infile_name, OMX_MAX_STRINGNAME_SIZE, "%s/input_dec_%d_%d_%p.265", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + } else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vc1", OMX_MAX_STRINGNAME_SIZE)) { + snprintf(m_debug.infile_name, OMX_MAX_STRINGNAME_SIZE, "%s/input_dec_%d_%d_%p.vc1", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + } else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.wmv", OMX_MAX_STRINGNAME_SIZE)) { + snprintf(m_debug.infile_name, OMX_MAX_STRINGNAME_SIZE, "%s/input_dec_%d_%d_%p.vc1", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + } else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8", OMX_MAX_STRINGNAME_SIZE)) { + snprintf(m_debug.infile_name, OMX_MAX_STRINGNAME_SIZE, "%s/input_dec_%d_%d_%p.ivf", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + } else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp9", OMX_MAX_STRINGNAME_SIZE)) { + snprintf(m_debug.infile_name, OMX_MAX_STRINGNAME_SIZE, "%s/input_dec_%d_%d_%p.ivf", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + } else { + snprintf(m_debug.infile_name, OMX_MAX_STRINGNAME_SIZE, "%s/input_dec_%d_%d_%p.divx", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + } + m_debug.infile = fopen (m_debug.infile_name, "ab"); + if (!m_debug.infile) { + DEBUG_PRINT_HIGH("Failed to open input file: %s for logging", m_debug.infile_name); + m_debug.infile_name[0] = '\0'; + return -1; + } + if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8", OMX_MAX_STRINGNAME_SIZE) || + !strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp9", OMX_MAX_STRINGNAME_SIZE)) { + struct ivf_file_header { + OMX_U8 signature[4]; //='DKIF'; + OMX_U8 version ; //= 0; + OMX_U8 headersize ; //= 32; + OMX_U32 FourCC; + OMX_U8 width; + OMX_U8 height; + OMX_U32 rate; + OMX_U32 scale; + OMX_U32 length; + OMX_U8 unused[4]; + } file_header; + + memset((void *)&file_header,0,sizeof(file_header)); + file_header.signature[0] = 'D'; + file_header.signature[1] = 'K'; + file_header.signature[2] = 'I'; + file_header.signature[3] = 'F'; + file_header.version = 0; + file_header.headersize = 32; + switch (drv_ctx.decoder_format) { + case VDEC_CODECTYPE_VP8: + file_header.FourCC = 0x30385056; + break; + case VDEC_CODECTYPE_VP9: + file_header.FourCC = 0x30395056; + break; + default: + DEBUG_PRINT_ERROR("unsupported format for VP8/VP9"); + break; + } + fwrite((const char *)&file_header, + sizeof(file_header),1,m_debug.infile); + } + } + if (m_debug.infile && buffer_addr && buffer_len) { + if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8", OMX_MAX_STRINGNAME_SIZE) || + !strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp9", OMX_MAX_STRINGNAME_SIZE)) { + struct vpx_ivf_frame_header { + OMX_U32 framesize; + OMX_U32 timestamp_lo; + OMX_U32 timestamp_hi; + } vpx_frame_header; + vpx_frame_header.framesize = buffer_len; + /* Currently FW doesn't use timestamp values */ + vpx_frame_header.timestamp_lo = 0; + vpx_frame_header.timestamp_hi = 0; + fwrite((const char *)&vpx_frame_header, + sizeof(vpx_frame_header),1,m_debug.infile); + } + fwrite(buffer_addr, buffer_len, 1, m_debug.infile); + } + return 0; +} + +int omx_vdec::log_output_buffers(OMX_BUFFERHEADERTYPE *buffer) { + int buf_index = 0; + char *temp = NULL; + + if (m_debug.out_buffer_log && !m_debug.outfile && buffer->nFilledLen) { + snprintf(m_debug.outfile_name, OMX_MAX_STRINGNAME_SIZE, "%s/output_%d_%d_%p.yuv", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + m_debug.outfile = fopen (m_debug.outfile_name, "ab"); + if (!m_debug.outfile) { + DEBUG_PRINT_HIGH("Failed to open output file: %s for logging", m_debug.log_loc); + m_debug.outfile_name[0] = '\0'; + return -1; + } + } + + if (m_debug.out_meta_buffer_log && !m_debug.out_ymeta_file && !m_debug.out_uvmeta_file + && buffer->nFilledLen) { + snprintf(m_debug.out_ymetafile_name, OMX_MAX_STRINGNAME_SIZE, "%s/output_%d_%d_%p.ymeta", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + snprintf(m_debug.out_uvmetafile_name, OMX_MAX_STRINGNAME_SIZE, "%s/output_%d_%d_%p.uvmeta", + m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); + m_debug.out_ymeta_file = fopen (m_debug.out_ymetafile_name, "ab"); + m_debug.out_uvmeta_file = fopen (m_debug.out_uvmetafile_name, "ab"); + if (!m_debug.out_ymeta_file || !m_debug.out_uvmeta_file) { + DEBUG_PRINT_HIGH("Failed to open output y/uv meta file: %s for logging", m_debug.log_loc); + m_debug.out_ymetafile_name[0] = '\0'; + m_debug.out_uvmetafile_name[0] = '\0'; + return -1; + } + } + + if ((!m_debug.outfile && !m_debug.out_ymeta_file) || !buffer || !buffer->nFilledLen) + return 0; + + buf_index = buffer - m_out_mem_ptr; + temp = (char *)drv_ctx.ptr_outputbuffer[buf_index].bufferaddr; + + if (drv_ctx.output_format == VDEC_YUV_FORMAT_NV12_UBWC || + drv_ctx.output_format == VDEC_YUV_FORMAT_NV12_TP10_UBWC) { + DEBUG_PRINT_HIGH("Logging UBWC yuv width/height(%u/%u)", + drv_ctx.video_resolution.frame_width, + drv_ctx.video_resolution.frame_height); + + if (m_debug.outfile) + fwrite(temp, buffer->nFilledLen, 1, m_debug.outfile); + + if (m_debug.out_ymeta_file && m_debug.out_uvmeta_file) { + unsigned int width = 0, height = 0; + unsigned int y_plane, y_meta_plane; + int y_stride = 0, y_sclines = 0; + int y_meta_stride = 0, y_meta_scanlines = 0, uv_meta_stride = 0, uv_meta_scanlines = 0; + int color_fmt = (drv_ctx.output_format== VDEC_YUV_FORMAT_NV12_UBWC)? COLOR_FMT_NV12_UBWC: COLOR_FMT_NV12_BPP10_UBWC; + int i; + int bytes_written = 0; + + width = drv_ctx.video_resolution.frame_width; + height = drv_ctx.video_resolution.frame_height; + y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width); + y_meta_scanlines = VENUS_Y_META_SCANLINES(color_fmt, height); + y_stride = VENUS_Y_STRIDE(color_fmt, width); + y_sclines = VENUS_Y_SCANLINES(color_fmt, height); + uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width); + uv_meta_scanlines = VENUS_UV_META_SCANLINES(color_fmt, height); + + y_meta_plane = MSM_MEDIA_ALIGN(y_meta_stride * y_meta_scanlines, 4096); + y_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); + + temp = (char *)drv_ctx.ptr_outputbuffer[buf_index].bufferaddr; + for (i = 0; i < y_meta_scanlines; i++) { + bytes_written = fwrite(temp, y_meta_stride, 1, m_debug.out_ymeta_file); + temp += y_meta_stride; + } + + temp = (char *)drv_ctx.ptr_outputbuffer[buf_index].bufferaddr + y_meta_plane + y_plane; + for(i = 0; i < uv_meta_scanlines; i++) { + bytes_written += fwrite(temp, uv_meta_stride, 1, m_debug.out_uvmeta_file); + temp += uv_meta_stride; + } + } + } else if (drv_ctx.output_format == VDEC_YUV_FORMAT_NV12) { + int stride = drv_ctx.video_resolution.stride; + int scanlines = drv_ctx.video_resolution.scan_lines; + if (m_smoothstreaming_mode) { + stride = drv_ctx.video_resolution.frame_width; + scanlines = drv_ctx.video_resolution.frame_height; + stride = (stride + DEFAULT_WIDTH_ALIGNMENT - 1) & (~(DEFAULT_WIDTH_ALIGNMENT - 1)); + scanlines = (scanlines + DEFAULT_HEIGHT_ALIGNMENT - 1) & (~(DEFAULT_HEIGHT_ALIGNMENT - 1)); + } + unsigned i; + DEBUG_PRINT_HIGH("Logging width/height(%u/%u) stride/scanlines(%u/%u)", + drv_ctx.video_resolution.frame_width, + drv_ctx.video_resolution.frame_height, stride, scanlines); + int bytes_written = 0; + for (i = 0; i < drv_ctx.video_resolution.frame_height; i++) { + bytes_written = fwrite(temp, drv_ctx.video_resolution.frame_width, 1, m_debug.outfile); + temp += stride; + } + temp = (char *)drv_ctx.ptr_outputbuffer[buf_index].bufferaddr + stride * scanlines; + int stride_c = stride; + for(i = 0; i < drv_ctx.video_resolution.frame_height/2; i++) { + bytes_written += fwrite(temp, drv_ctx.video_resolution.frame_width, 1, m_debug.outfile); + temp += stride_c; + } + } + return 0; +} + +/* ====================================================================== + FUNCTION + omx_vdec::ComponentInit + + DESCRIPTION + Initialize the component. + + PARAMETERS + ctxt -- Context information related to the self. + id -- Event identifier. This could be any of the following: + 1. Command completion event + 2. Buffer done callback event + 3. Frame done callback event + + RETURN VALUE + None. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::component_init(OMX_STRING role) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_fmtdesc fdesc; + struct v4l2_format fmt; + struct v4l2_requestbuffers bufreq; + struct v4l2_control control; + struct v4l2_frmsizeenum frmsize; + unsigned int alignment = 0,buffer_size = 0; + int fds[2]; + int r,ret=0; + bool codec_ambiguous = false; + OMX_STRING device_name = (OMX_STRING)"/dev/video32"; + char property_value[PROPERTY_VALUE_MAX] = {0}; + FILE *soc_file = NULL; + char buffer[10]; + +#ifdef _ANDROID_ + char platform_name[PROPERTY_VALUE_MAX]; + property_get("ro.board.platform", platform_name, "0"); + if (!strncmp(platform_name, "msm8610", 7)) { + device_name = (OMX_STRING)"/dev/video/q6_dec"; + is_q6_platform = true; + maxSmoothStreamingWidth = 1280; + maxSmoothStreamingHeight = 720; + } +#endif + + is_thulium_v1 = false; + soc_file = fopen("/sys/devices/soc0/soc_id", "r"); + if (soc_file) { + fread(buffer, 1, 4, soc_file); + fclose(soc_file); + if (atoi(buffer) == 246) { + soc_file = fopen("/sys/devices/soc0/revision", "r"); + if (soc_file) { + fread(buffer, 1, 4, soc_file); + fclose(soc_file); + if (atoi(buffer) == 1) { + is_thulium_v1 = true; + DEBUG_PRINT_HIGH("is_thulium_v1 = TRUE"); + } + } + } + } + +#ifdef _ANDROID_ + /* + * turn off frame parsing for Android by default. + * Clients may configure OMX_QCOM_FramePacking_Arbitrary to enable this mode + */ + arbitrary_bytes = false; + property_get("vidc.dec.debug.arbitrarybytes.mode", property_value, "0"); + if (atoi(property_value)) { + DEBUG_PRINT_HIGH("arbitrary_bytes mode enabled via property command"); + arbitrary_bytes = true; + } +#endif + + if (!strncmp(role, "OMX.qcom.video.decoder.avc.secure", + OMX_MAX_STRINGNAME_SIZE)) { + secure_mode = true; + arbitrary_bytes = false; + role = (OMX_STRING)"OMX.qcom.video.decoder.avc"; + } else if (!strncmp(role, "OMX.qcom.video.decoder.mpeg2.secure", + OMX_MAX_STRINGNAME_SIZE)) { + secure_mode = true; + arbitrary_bytes = false; + role = (OMX_STRING)"OMX.qcom.video.decoder.mpeg2"; + } else if (!strncmp(role, "OMX.qcom.video.decoder.hevc.secure", + OMX_MAX_STRINGNAME_SIZE)) { + secure_mode = true; + arbitrary_bytes = false; + role = (OMX_STRING)"OMX.qcom.video.decoder.hevc"; + } else if (!strncmp(role, "OMX.qcom.video.decoder.vc1.secure", + OMX_MAX_STRINGNAME_SIZE)) { + secure_mode = true; + arbitrary_bytes = false; + role = (OMX_STRING)"OMX.qcom.video.decoder.vc1"; + } else if (!strncmp(role, "OMX.qcom.video.decoder.wmv.secure", + OMX_MAX_STRINGNAME_SIZE)) { + secure_mode = true; + arbitrary_bytes = false; + role = (OMX_STRING)"OMX.qcom.video.decoder.wmv"; + } else if (!strncmp(role, "OMX.qcom.video.decoder.mpeg4.secure", + OMX_MAX_STRINGNAME_SIZE)) { + secure_mode = true; + arbitrary_bytes = false; + role = (OMX_STRING)"OMX.qcom.video.decoder.mpeg4"; + } else if (!strncmp(role, "OMX.qcom.video.decoder.vp9.secure", + OMX_MAX_STRINGNAME_SIZE)) { + secure_mode = true; + arbitrary_bytes = false; + role = (OMX_STRING)"OMX.qcom.video.decoder.vp9"; + } + else if (!strncmp(role, "OMX.qcom.video.decoder.vp8.secure", + OMX_MAX_STRINGNAME_SIZE)) { + secure_mode = true; + arbitrary_bytes = false; + role = (OMX_STRING)"OMX.qcom.video.decoder.vp8"; + } + + drv_ctx.video_driver_fd = open(device_name, O_RDWR); + + DEBUG_PRINT_INFO("component_init: %s : fd=%d", role, drv_ctx.video_driver_fd); + + if (drv_ctx.video_driver_fd < 0) { + DEBUG_PRINT_ERROR("Omx_vdec::Comp Init Returning failure, errno %d", errno); + return OMX_ErrorInsufficientResources; + } + drv_ctx.frame_rate.fps_numerator = DEFAULT_FPS; + drv_ctx.frame_rate.fps_denominator = 1; + operating_frame_rate = DEFAULT_FPS; + high_fps = false; + m_poll_efd = eventfd(0, 0); + if (m_poll_efd < 0) { + DEBUG_PRINT_ERROR("Failed to create event fd(%s)", strerror(errno)); + return OMX_ErrorInsufficientResources; + } + ret = subscribe_to_events(drv_ctx.video_driver_fd); + if (!ret) { + async_thread_created = true; + ret = pthread_create(&async_thread_id,0,async_message_thread,this); + } + if (ret) { + DEBUG_PRINT_ERROR("Failed to create async_message_thread"); + async_thread_created = false; + return OMX_ErrorInsufficientResources; + } + +#ifdef OUTPUT_EXTRADATA_LOG + outputExtradataFile = fopen (output_extradata_filename, "ab"); +#endif + + // Copy the role information which provides the decoder kind + strlcpy(drv_ctx.kind,role,128); + + if (!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.mpeg4",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.mpeg4",\ + OMX_MAX_STRINGNAME_SIZE); + drv_ctx.timestamp_adjust = true; + drv_ctx.decoder_format = VDEC_CODECTYPE_MPEG4; + eCompressionFormat = OMX_VIDEO_CodingMPEG4; + output_capability=V4L2_PIX_FMT_MPEG4; + /*Initialize Start Code for MPEG4*/ + codec_type_parse = CODEC_TYPE_MPEG4; + m_frame_parser.init_start_codes(codec_type_parse); + } else if (!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.mpeg2",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.mpeg2",\ + OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_MPEG2; + output_capability = V4L2_PIX_FMT_MPEG2; + eCompressionFormat = OMX_VIDEO_CodingMPEG2; + /*Initialize Start Code for MPEG2*/ + codec_type_parse = CODEC_TYPE_MPEG2; + m_frame_parser.init_start_codes(codec_type_parse); + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.h263",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("H263 Decoder selected"); + drv_ctx.decoder_format = VDEC_CODECTYPE_H263; + eCompressionFormat = OMX_VIDEO_CodingH263; + output_capability = V4L2_PIX_FMT_H263; + codec_type_parse = CODEC_TYPE_H263; + m_frame_parser.init_start_codes(codec_type_parse); + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx311",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW ("DIVX 311 Decoder selected"); + drv_ctx.decoder_format = VDEC_CODECTYPE_DIVX_3; + output_capability = V4L2_PIX_FMT_DIVX_311; + eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; + codec_type_parse = CODEC_TYPE_DIVX; + m_frame_parser.init_start_codes(codec_type_parse); + + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx4",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_ERROR ("DIVX 4 Decoder selected"); + drv_ctx.decoder_format = VDEC_CODECTYPE_DIVX_4; + output_capability = V4L2_PIX_FMT_DIVX; + eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; + codec_type_parse = CODEC_TYPE_DIVX; + codec_ambiguous = true; + m_frame_parser.init_start_codes(codec_type_parse); + + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_ERROR ("DIVX 5/6 Decoder selected"); + drv_ctx.decoder_format = VDEC_CODECTYPE_DIVX_6; + output_capability = V4L2_PIX_FMT_DIVX; + eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; + codec_type_parse = CODEC_TYPE_DIVX; + codec_ambiguous = true; + m_frame_parser.init_start_codes(codec_type_parse); + + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.avc",OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_H264; + output_capability=V4L2_PIX_FMT_H264; + eCompressionFormat = OMX_VIDEO_CodingAVC; + codec_type_parse = CODEC_TYPE_H264; + m_frame_parser.init_start_codes(codec_type_parse); + m_frame_parser.init_nal_length(nal_length); + if (is_thulium_v1) { + arbitrary_bytes = true; + DEBUG_PRINT_HIGH("Enable arbitrary_bytes for h264"); + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mvc",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.mvc", OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_MVC; + output_capability = V4L2_PIX_FMT_H264_MVC; + eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingMVC; + codec_type_parse = CODEC_TYPE_H264; + m_frame_parser.init_start_codes(codec_type_parse); + m_frame_parser.init_nal_length(nal_length); + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.hevc",OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_HEVC; + output_capability = V4L2_PIX_FMT_HEVC; + eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc; + codec_type_parse = CODEC_TYPE_HEVC; + m_frame_parser.init_start_codes(codec_type_parse); + m_frame_parser.init_nal_length(nal_length); + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vc1",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_VC1; + eCompressionFormat = OMX_VIDEO_CodingWMV; + codec_type_parse = CODEC_TYPE_VC1; + output_capability = V4L2_PIX_FMT_VC1_ANNEX_G; + m_frame_parser.init_start_codes(codec_type_parse); + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.wmv",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_VC1_RCV; + eCompressionFormat = OMX_VIDEO_CodingWMV; + codec_type_parse = CODEC_TYPE_VC1; + output_capability = V4L2_PIX_FMT_VC1_ANNEX_L; + m_frame_parser.init_start_codes(codec_type_parse); + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8", \ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.vp8",OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_VP8; + output_capability = V4L2_PIX_FMT_VP8; + eCompressionFormat = OMX_VIDEO_CodingVP8; + codec_type_parse = CODEC_TYPE_VP8; + arbitrary_bytes = false; + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp9", \ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_decoder.vp9",OMX_MAX_STRINGNAME_SIZE); + drv_ctx.decoder_format = VDEC_CODECTYPE_VP9; + output_capability = V4L2_PIX_FMT_VP9; + eCompressionFormat = OMX_VIDEO_CodingVP9; + codec_type_parse = CODEC_TYPE_VP9; + arbitrary_bytes = false; + } else { + DEBUG_PRINT_ERROR("ERROR:Unknown Component"); + eRet = OMX_ErrorInvalidComponentName; + } + + if (eRet == OMX_ErrorNone) { + OMX_COLOR_FORMATTYPE dest_color_format; + if (m_disable_ubwc_mode) { + drv_ctx.output_format = VDEC_YUV_FORMAT_NV12; + } else { + drv_ctx.output_format = VDEC_YUV_FORMAT_NV12_UBWC; + } + if (eCompressionFormat == (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingMVC) + dest_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView; + else + dest_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + if (!client_buffers.set_color_format(dest_color_format)) { + DEBUG_PRINT_ERROR("Setting color format failed"); + eRet = OMX_ErrorInsufficientResources; + } + + dpb_bit_depth = MSM_VIDC_BIT_DEPTH_8; + m_progressive = MSM_VIDC_PIC_STRUCT_PROGRESSIVE; + + if (m_disable_ubwc_mode) { + capture_capability = V4L2_PIX_FMT_NV12; + } else { + capture_capability = V4L2_PIX_FMT_NV12_UBWC; + } + + struct v4l2_capability cap; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_QUERYCAP, &cap); + if (ret) { + DEBUG_PRINT_ERROR("Failed to query capabilities"); + /*TODO: How to handle this case */ + } else { + DEBUG_PRINT_LOW("Capabilities: driver_name = %s, card = %s, bus_info = %s," + " version = %d, capabilities = %x", cap.driver, cap.card, + cap.bus_info, cap.version, cap.capabilities); + } + ret=0; + fdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fdesc.index=0; + while (ioctl(drv_ctx.video_driver_fd, VIDIOC_ENUM_FMT, &fdesc) == 0) { + DEBUG_PRINT_HIGH("fmt: description: %s, fmt: %x, flags = %x", fdesc.description, + fdesc.pixelformat, fdesc.flags); + fdesc.index++; + } + fdesc.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fdesc.index=0; + while (ioctl(drv_ctx.video_driver_fd, VIDIOC_ENUM_FMT, &fdesc) == 0) { + + DEBUG_PRINT_HIGH("fmt: description: %s, fmt: %x, flags = %x", fdesc.description, + fdesc.pixelformat, fdesc.flags); + fdesc.index++; + } + m_extradata_info.output_crop_rect.nLeft = 0; + m_extradata_info.output_crop_rect.nTop = 0; + m_extradata_info.output_crop_rect.nWidth = 320; + m_extradata_info.output_crop_rect.nHeight = 240; + update_resolution(320, 240, 320, 240); + + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = output_capability; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to set format on output port"); + return OMX_ErrorInsufficientResources; + } + DEBUG_PRINT_HIGH("Set Format was successful"); + if (codec_ambiguous) { + if (output_capability == V4L2_PIX_FMT_DIVX) { + struct v4l2_control divx_ctrl; + + if (drv_ctx.decoder_format == VDEC_CODECTYPE_DIVX_4) { + divx_ctrl.value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4; + } else if (drv_ctx.decoder_format == VDEC_CODECTYPE_DIVX_5) { + divx_ctrl.value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5; + } else { + divx_ctrl.value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6; + } + + divx_ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &divx_ctrl); + if (ret) { + DEBUG_PRINT_ERROR("Failed to set divx version"); + } + } else { + DEBUG_PRINT_ERROR("Codec should not be ambiguous"); + } + } + + property_get("persist.vidc.dec.conceal_color", property_value, DEFAULT_CONCEAL_COLOR); + m_conceal_color= atoi(property_value); + DEBUG_PRINT_HIGH("trying to set 0x%u as conceal color\n", (unsigned int)m_conceal_color); + control.id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR; + control.value = m_conceal_color; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if (ret) { + DEBUG_PRINT_ERROR("Failed to set conceal color %d\n", ret); + } + + //Get the hardware capabilities + memset((void *)&frmsize,0,sizeof(frmsize)); + frmsize.index = 0; + frmsize.pixel_format = output_capability; + ret = ioctl(drv_ctx.video_driver_fd, + VIDIOC_ENUM_FRAMESIZES, &frmsize); + if (ret || frmsize.type != V4L2_FRMSIZE_TYPE_STEPWISE) { + DEBUG_PRINT_ERROR("Failed to get framesizes"); + return OMX_ErrorHardware; + } + + if (frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) { + m_decoder_capability.min_width = frmsize.stepwise.min_width; + m_decoder_capability.max_width = frmsize.stepwise.max_width; + m_decoder_capability.min_height = frmsize.stepwise.min_height; + m_decoder_capability.max_height = frmsize.stepwise.max_height; + } + + memset(&fmt, 0x0, sizeof(struct v4l2_format)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = capture_capability; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to set format on capture port"); + } + memset(&framesize, 0, sizeof(OMX_FRAMESIZETYPE)); + framesize.nWidth = drv_ctx.video_resolution.frame_width; + framesize.nHeight = drv_ctx.video_resolution.frame_height; + + memset(&rectangle, 0, sizeof(OMX_CONFIG_RECTTYPE)); + rectangle.nWidth = drv_ctx.video_resolution.frame_width; + rectangle.nHeight = drv_ctx.video_resolution.frame_height; + + DEBUG_PRINT_HIGH("Set Format was successful"); + if (secure_mode) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE; + control.value = 1; + DEBUG_PRINT_LOW("Omx_vdec:: calling to open secure device %d", ret); + ret=ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL,&control); + if (ret) { + DEBUG_PRINT_ERROR("Omx_vdec:: Unable to open secure device %d", ret); + return OMX_ErrorInsufficientResources; + } + } + if (output_capability == V4L2_PIX_FMT_H264_MVC) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT; + control.value = V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if (ret) { + DEBUG_PRINT_ERROR("Failed to set MVC buffer layout"); + return OMX_ErrorInsufficientResources; + } + } + + if (is_thulium_v1) { + eRet = enable_smoothstreaming(); + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("Failed to enable smooth streaming on driver"); + return eRet; + } + } + + /*Get the Buffer requirements for input and output ports*/ + drv_ctx.ip_buf.buffer_type = VDEC_BUFFER_TYPE_INPUT; + drv_ctx.op_buf.buffer_type = VDEC_BUFFER_TYPE_OUTPUT; + + if (secure_mode) { + drv_ctx.op_buf.alignment = SECURE_ALIGN; + drv_ctx.ip_buf.alignment = SECURE_ALIGN; + } else { + drv_ctx.op_buf.alignment = SZ_4K; + drv_ctx.ip_buf.alignment = SZ_4K; + } + + drv_ctx.interlace = VDEC_InterlaceFrameProgressive; + drv_ctx.extradata = 0; + drv_ctx.picture_order = VDEC_ORDER_DISPLAY; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER; + control.value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + drv_ctx.idr_only_decoding = 0; + +#ifdef _ANDROID_ + property_get("vidc.dec.downscalar_width",property_value,"0"); + if (atoi(property_value)) { + m_downscalar_width = atoi(property_value); + } + property_get("vidc.dec.downscalar_height",property_value,"0"); + if (atoi(property_value)) { + m_downscalar_height = atoi(property_value); + } + + if (m_downscalar_width < m_decoder_capability.min_width || + m_downscalar_height < m_decoder_capability.min_height) { + m_downscalar_width = 0; + m_downscalar_height = 0; + } + + DEBUG_PRINT_LOW("Downscaler configured WxH %dx%d\n", + m_downscalar_width, m_downscalar_height); + + property_get("vidc.disable.split.mode",property_value,"0"); + m_disable_split_mode = atoi(property_value); + DEBUG_PRINT_HIGH("split mode is %s", m_disable_split_mode ? "disabled" : "enabled"); +#endif + m_state = OMX_StateLoaded; +#ifdef DEFAULT_EXTRADATA + enable_extradata(DEFAULT_EXTRADATA, true, true); +#endif + eRet = get_buffer_req(&drv_ctx.ip_buf); + DEBUG_PRINT_HIGH("Input Buffer Size =%u",(unsigned int)drv_ctx.ip_buf.buffer_size); + get_buffer_req(&drv_ctx.op_buf); + if (drv_ctx.decoder_format == VDEC_CODECTYPE_H264 || + drv_ctx.decoder_format == VDEC_CODECTYPE_HEVC || + drv_ctx.decoder_format == VDEC_CODECTYPE_MVC) { + h264_scratch.nAllocLen = drv_ctx.ip_buf.buffer_size; + h264_scratch.pBuffer = (OMX_U8 *)malloc (drv_ctx.ip_buf.buffer_size); + h264_scratch.nFilledLen = 0; + h264_scratch.nOffset = 0; + + if (h264_scratch.pBuffer == NULL) { + DEBUG_PRINT_ERROR("h264_scratch.pBuffer Allocation failed "); + return OMX_ErrorInsufficientResources; + } + } + if (drv_ctx.decoder_format == VDEC_CODECTYPE_H264 || + drv_ctx.decoder_format == VDEC_CODECTYPE_MVC) { + if (m_frame_parser.mutils == NULL) { + m_frame_parser.mutils = new H264_Utils(); + if (m_frame_parser.mutils == NULL) { + DEBUG_PRINT_ERROR("parser utils Allocation failed "); + eRet = OMX_ErrorInsufficientResources; + } else { + m_frame_parser.mutils->initialize_frame_checking_environment(); + m_frame_parser.mutils->allocate_rbsp_buffer (drv_ctx.ip_buf.buffer_size); + } + } + + h264_parser = new h264_stream_parser(); + if (!h264_parser) { + DEBUG_PRINT_ERROR("ERROR: H264 parser allocation failed!"); + eRet = OMX_ErrorInsufficientResources; + } + } + + if (pipe(fds)) { + DEBUG_PRINT_ERROR("pipe creation failed"); + eRet = OMX_ErrorInsufficientResources; + } else { + m_pipe_in = fds[0]; + m_pipe_out = fds[1]; + msg_thread_created = true; + r = pthread_create(&msg_thread_id,0,message_thread_dec,this); + + if (r < 0) { + DEBUG_PRINT_ERROR("component_init(): message_thread_dec creation failed"); + msg_thread_created = false; + eRet = OMX_ErrorInsufficientResources; + } + } + } + + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("Component Init Failed"); + } else { + DEBUG_PRINT_INFO("omx_vdec::component_init() success : fd=%d", + drv_ctx.video_driver_fd); + } + //memset(&h264_mv_buff,0,sizeof(struct h264_mv_buffer)); + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::GetComponentVersion + + DESCRIPTION + Returns the component version. + + PARAMETERS + TBD. + + RETURN VALUE + OMX_ErrorNone. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_component_version +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STRING componentName, + OMX_OUT OMX_VERSIONTYPE* componentVersion, + OMX_OUT OMX_VERSIONTYPE* specVersion, + OMX_OUT OMX_UUIDTYPE* componentUUID + ) +{ + (void) hComp; + (void) componentName; + (void) componentVersion; + (void) componentUUID; + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Get Comp Version in Invalid State"); + return OMX_ErrorInvalidState; + } + /* TBD -- Return the proper version */ + if (specVersion) { + specVersion->nVersion = OMX_SPEC_VERSION; + } + return OMX_ErrorNone; +} +/* ====================================================================== + FUNCTION + omx_vdec::SendCommand + + DESCRIPTION + Returns zero if all the buffers released.. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::send_command(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData + ) +{ + (void) hComp; + (void) cmdData; + DEBUG_PRINT_LOW("send_command: Recieved a Command from Client"); + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: Send Command in Invalid State"); + return OMX_ErrorInvalidState; + } + if (cmd == OMX_CommandFlush && param1 != OMX_CORE_INPUT_PORT_INDEX + && param1 != OMX_CORE_OUTPUT_PORT_INDEX && param1 != OMX_ALL) { + DEBUG_PRINT_ERROR("send_command(): ERROR OMX_CommandFlush " + "to invalid port: %u", (unsigned int)param1); + return OMX_ErrorBadPortIndex; + } + + post_event((unsigned)cmd,(unsigned)param1,OMX_COMPONENT_GENERATE_COMMAND); + sem_wait(&m_cmd_lock); + DEBUG_PRINT_LOW("send_command: Command Processed"); + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::SendCommand + + DESCRIPTION + Returns zero if all the buffers released.. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData + ) +{ + (void) hComp; + (void) cmdData; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_STATETYPE eState = (OMX_STATETYPE) param1; + int bFlag = 1,sem_posted = 0,ret=0; + + DEBUG_PRINT_LOW("send_command_proxy(): cmd = %d", cmd); + DEBUG_PRINT_HIGH("send_command_proxy(): Current State %d, Expected State %d", + m_state, eState); + + if (cmd == OMX_CommandStateSet) { + DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandStateSet issued"); + DEBUG_PRINT_HIGH("Current State %d, Expected State %d", m_state, eState); + /***************************/ + /* Current State is Loaded */ + /***************************/ + if (m_state == OMX_StateLoaded) { + if (eState == OMX_StateIdle) { + //if all buffers are allocated or all ports disabled + if (allocate_done() || + (m_inp_bEnabled == OMX_FALSE && m_out_bEnabled == OMX_FALSE)) { + DEBUG_PRINT_LOW("send_command_proxy(): Loaded-->Idle"); + } else { + DEBUG_PRINT_LOW("send_command_proxy(): Loaded-->Idle-Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING); + // Skip the event notification + bFlag = 0; + } + } + /* Requesting transition from Loaded to Loaded */ + else if (eState == OMX_StateLoaded) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Loaded"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Loaded to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + /* Since error is None , we will post an event + at the end of this function definition */ + DEBUG_PRINT_LOW("send_command_proxy(): Loaded-->WaitForResources"); + } + /* Requesting transition from Loaded to Executing */ + else if (eState == OMX_StateExecuting) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Executing"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Loaded to Pause */ + else if (eState == OMX_StatePause) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Pause"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Loaded to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } else { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Invalid(%d Not Handled)",\ + eState); + eRet = OMX_ErrorBadParameter; + } + } + + /***************************/ + /* Current State is IDLE */ + /***************************/ + else if (m_state == OMX_StateIdle) { + if (eState == OMX_StateLoaded) { + if (release_done()) { + /* + Since error is None , we will post an event at the end + of this function definition + */ + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Loaded"); + } else { + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Loaded-Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING); + // Skip the event notification + bFlag = 0; + } + } + /* Requesting transition from Idle to Executing */ + else if (eState == OMX_StateExecuting) { + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing"); + //BITMASK_SET(&m_flags, OMX_COMPONENT_EXECUTE_PENDING); + bFlag = 1; + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing"); + m_state=OMX_StateExecuting; + DEBUG_PRINT_HIGH("Stream On CAPTURE Was successful"); + } + /* Requesting transition from Idle to Idle */ + else if (eState == OMX_StateIdle) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->Idle"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Idle to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->WaitForResources"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Idle to Pause */ + else if (eState == OMX_StatePause) { + /*To pause the Video core we need to start the driver*/ + if (/*ioctl (drv_ctx.video_driver_fd,VDEC_IOCTL_CMD_START, + NULL) < */0) { + DEBUG_PRINT_ERROR("VDEC_IOCTL_CMD_START FAILED"); + omx_report_error (); + eRet = OMX_ErrorHardware; + } else { + BITMASK_SET(&m_flags,OMX_COMPONENT_PAUSE_PENDING); + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Pause"); + bFlag = 0; + } + } + /* Requesting transition from Idle to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } else { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle --> %d Not Handled",eState); + eRet = OMX_ErrorBadParameter; + } + } + + /******************************/ + /* Current State is Executing */ + /******************************/ + else if (m_state == OMX_StateExecuting) { + DEBUG_PRINT_LOW("Command Recieved in OMX_StateExecuting"); + /* Requesting transition from Executing to Idle */ + if (eState == OMX_StateIdle) { + /* Since error is None , we will post an event + at the end of this function definition + */ + DEBUG_PRINT_LOW("send_command_proxy(): Executing --> Idle"); + BITMASK_SET(&m_flags,OMX_COMPONENT_IDLE_PENDING); + if (!sem_posted) { + sem_posted = 1; + sem_post (&m_cmd_lock); + execute_omx_flush(OMX_ALL); + } + bFlag = 0; + } + /* Requesting transition from Executing to Paused */ + else if (eState == OMX_StatePause) { + DEBUG_PRINT_LOW("PAUSE Command Issued"); + m_state = OMX_StatePause; + bFlag = 1; + } + /* Requesting transition from Executing to Loaded */ + else if (eState == OMX_StateLoaded) { + DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> Loaded"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Executing to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> WaitForResources"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Executing to Executing */ + else if (eState == OMX_StateExecuting) { + DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> Executing"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Executing to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } else { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Executing --> %d Not Handled",eState); + eRet = OMX_ErrorBadParameter; + } + } + /***************************/ + /* Current State is Pause */ + /***************************/ + else if (m_state == OMX_StatePause) { + /* Requesting transition from Pause to Executing */ + if (eState == OMX_StateExecuting) { + DEBUG_PRINT_LOW("Pause --> Executing"); + m_state = OMX_StateExecuting; + bFlag = 1; + } + /* Requesting transition from Pause to Idle */ + else if (eState == OMX_StateIdle) { + /* Since error is None , we will post an event + at the end of this function definition */ + DEBUG_PRINT_LOW("Pause --> Idle"); + BITMASK_SET(&m_flags,OMX_COMPONENT_IDLE_PENDING); + if (!sem_posted) { + sem_posted = 1; + sem_post (&m_cmd_lock); + execute_omx_flush(OMX_ALL); + } + bFlag = 0; + } + /* Requesting transition from Pause to loaded */ + else if (eState == OMX_StateLoaded) { + DEBUG_PRINT_ERROR("Pause --> loaded"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Pause to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + DEBUG_PRINT_ERROR("Pause --> WaitForResources"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Pause to Pause */ + else if (eState == OMX_StatePause) { + DEBUG_PRINT_ERROR("Pause --> Pause"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Pause to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Pause --> Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } else { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Paused --> %d Not Handled",eState); + eRet = OMX_ErrorBadParameter; + } + } + /***************************/ + /* Current State is WaitForResources */ + /***************************/ + else if (m_state == OMX_StateWaitForResources) { + /* Requesting transition from WaitForResources to Loaded */ + if (eState == OMX_StateLoaded) { + /* Since error is None , we will post an event + at the end of this function definition */ + DEBUG_PRINT_LOW("send_command_proxy(): WaitForResources-->Loaded"); + } + /* Requesting transition from WaitForResources to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->WaitForResources"); + post_event(OMX_EventError,OMX_ErrorSameState, + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from WaitForResources to Executing */ + else if (eState == OMX_StateExecuting) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->Executing"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from WaitForResources to Pause */ + else if (eState == OMX_StatePause) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->Pause"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from WaitForResources to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } + /* Requesting transition from WaitForResources to Loaded - + is NOT tested by Khronos TS */ + + } else { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): %d --> %d(Not Handled)",m_state,eState); + eRet = OMX_ErrorBadParameter; + } + } + /********************************/ + /* Current State is Invalid */ + /*******************************/ + else if (m_state == OMX_StateInvalid) { + /* State Transition from Inavlid to any state */ + if (eState == (OMX_StateLoaded || OMX_StateWaitForResources + || OMX_StateIdle || OMX_StateExecuting + || OMX_StatePause || OMX_StateInvalid)) { + DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Invalid -->Loaded"); + post_event(OMX_EventError,OMX_ErrorInvalidState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } + } else if (cmd == OMX_CommandFlush) { + DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandFlush issued" + "with param1: %u", (unsigned int)param1); +#ifdef _MSM8974_ + send_codec_config(); +#endif + if (cmd == OMX_CommandFlush && (param1 == OMX_CORE_INPUT_PORT_INDEX || + param1 == OMX_ALL)) { + if (android_atomic_add(0, &m_queued_codec_config_count) > 0) { + struct timespec ts; + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 2; + DEBUG_PRINT_LOW("waiting for %d EBDs of CODEC CONFIG buffers ", + m_queued_codec_config_count); + BITMASK_SET(&m_flags, OMX_COMPONENT_FLUSH_DEFERRED); + if (sem_timedwait(&m_safe_flush, &ts)) { + DEBUG_PRINT_ERROR("Failed to wait for EBDs of CODEC CONFIG buffers"); + } + BITMASK_CLEAR (&m_flags,OMX_COMPONENT_FLUSH_DEFERRED); + } + } + + if (OMX_CORE_INPUT_PORT_INDEX == param1 || OMX_ALL == param1) { + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_FLUSH_PENDING); + } + if (OMX_CORE_OUTPUT_PORT_INDEX == param1 || OMX_ALL == param1) { + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_FLUSH_PENDING); + } + if (!sem_posted) { + sem_posted = 1; + DEBUG_PRINT_LOW("Set the Semaphore"); + sem_post (&m_cmd_lock); + execute_omx_flush(param1); + } + bFlag = 0; + } else if ( cmd == OMX_CommandPortEnable) { + DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandPortEnable issued" + "with param1: %u", (unsigned int)param1); + if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) { + m_inp_bEnabled = OMX_TRUE; + + if ( (m_state == OMX_StateLoaded && + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || allocate_input_done()) { + post_event(OMX_CommandPortEnable,OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else { + DEBUG_PRINT_LOW("send_command_proxy(): Disabled-->Enabled Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING); + // Skip the event notification + bFlag = 0; + } + } + if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) { + DEBUG_PRINT_LOW("Enable output Port command recieved"); + m_out_bEnabled = OMX_TRUE; + + if ( (m_state == OMX_StateLoaded && + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (allocate_output_done())) { + post_event(OMX_CommandPortEnable,OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + + } else { + DEBUG_PRINT_LOW("send_command_proxy(): Disabled-->Enabled Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + // Skip the event notification + bFlag = 0; + /* enable/disable downscaling if required */ + ret = decide_downscalar(); + if (ret) { + DEBUG_PRINT_LOW("decide_downscalar failed\n"); + } + } + } + } else if (cmd == OMX_CommandPortDisable) { + DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandPortDisable issued" + "with param1: %u", (unsigned int)param1); + if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) { + codec_config_flag = false; + m_inp_bEnabled = OMX_FALSE; + if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_input_done()) { + post_event(OMX_CommandPortDisable,OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else { + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING); + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) { + if (!sem_posted) { + sem_posted = 1; + sem_post (&m_cmd_lock); + } + execute_omx_flush(OMX_CORE_INPUT_PORT_INDEX); + } + + // Skip the event notification + bFlag = 0; + } + } + if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) { + m_out_bEnabled = OMX_FALSE; + DEBUG_PRINT_LOW("Disable output Port command recieved"); + if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_output_done()) { + post_event(OMX_CommandPortDisable,OMX_CORE_OUTPUT_PORT_INDEX,\ + OMX_COMPONENT_GENERATE_EVENT); + } else { + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) { + if (!sem_posted) { + sem_posted = 1; + sem_post (&m_cmd_lock); + } + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING); + execute_omx_flush(OMX_CORE_OUTPUT_PORT_INDEX); + } + // Skip the event notification + bFlag = 0; + + } + } + } else { + DEBUG_PRINT_ERROR("Error: Invalid Command other than StateSet (%d)",cmd); + eRet = OMX_ErrorNotImplemented; + } + if (eRet == OMX_ErrorNone && bFlag) { + post_event(cmd,eState,OMX_COMPONENT_GENERATE_EVENT); + } + if (!sem_posted) { + sem_post(&m_cmd_lock); + } + + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::ExecuteOmxFlush + + DESCRIPTION + Executes the OMX flush. + + PARAMETERS + flushtype - input flush(1)/output flush(0)/ both. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_vdec::execute_omx_flush(OMX_U32 flushType) +{ + bool bRet = false; + struct v4l2_plane plane; + struct v4l2_buffer v4l2_buf; + struct v4l2_decoder_cmd dec; + DEBUG_PRINT_LOW("in %s, flushing %u", __func__, (unsigned int)flushType); + memset((void *)&v4l2_buf,0,sizeof(v4l2_buf)); + dec.cmd = V4L2_DEC_QCOM_CMD_FLUSH; + + DEBUG_PRINT_HIGH("in %s: reconfig? %d", __func__, in_reconfig); + + if (in_reconfig && flushType == OMX_CORE_OUTPUT_PORT_INDEX) { + output_flush_progress = true; + dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE; + } else { + /* XXX: The driver/hardware does not support flushing of individual ports + * in all states. So we pretty much need to flush both ports internally, + * but client should only get the FLUSH_(INPUT|OUTPUT)_DONE for the one it + * requested. Since OMX_COMPONENT_(OUTPUT|INPUT)_FLUSH_PENDING isn't set, + * we automatically omit sending the FLUSH done for the "opposite" port. */ + input_flush_progress = true; + output_flush_progress = true; + dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT | V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE; + request_perf_level(VIDC_TURBO); + } + + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_DECODER_CMD, &dec)) { + DEBUG_PRINT_ERROR("Flush Port (%u) Failed ", (unsigned int)flushType); + bRet = false; + } + + return bRet; +} +/*========================================================================= +FUNCTION : execute_output_flush + +DESCRIPTION +Executes the OMX flush at OUTPUT PORT. + +PARAMETERS +None. + +RETURN VALUE +true/false +==========================================================================*/ +bool omx_vdec::execute_output_flush() +{ + unsigned long p1 = 0; // Parameter - 1 + unsigned long p2 = 0; // Parameter - 2 + unsigned long ident = 0; + bool bRet = true; + + /*Generate FBD for all Buffers in the FTBq*/ + pthread_mutex_lock(&m_lock); + DEBUG_PRINT_LOW("Initiate Output Flush"); + + //reset last render TS + if(m_last_rendered_TS > 0) { + m_last_rendered_TS = 0; + } + + while (m_ftb_q.m_size) { + DEBUG_PRINT_LOW("Buffer queue size %lu pending buf cnt %d", + m_ftb_q.m_size,pending_output_buffers); + m_ftb_q.pop_entry(&p1,&p2,&ident); + DEBUG_PRINT_LOW("ID(%lx) P1(%lx) P2(%lx)", ident, p1, p2); + if (ident == m_fill_output_msg ) { + m_cb.FillBufferDone(&m_cmp, m_app_data, (OMX_BUFFERHEADERTYPE *)(intptr_t)p2); + } else if (ident == OMX_COMPONENT_GENERATE_FBD) { + fill_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)(intptr_t)p1); + } + } + pthread_mutex_unlock(&m_lock); + output_flush_progress = false; + + if (arbitrary_bytes) { + prev_ts = LLONG_MAX; + rst_prev_ts = true; + } + DEBUG_PRINT_HIGH("OMX flush o/p Port complete PenBuf(%d)", pending_output_buffers); + return bRet; +} +/*========================================================================= +FUNCTION : execute_input_flush + +DESCRIPTION +Executes the OMX flush at INPUT PORT. + +PARAMETERS +None. + +RETURN VALUE +true/false +==========================================================================*/ +bool omx_vdec::execute_input_flush() +{ + unsigned i =0; + unsigned long p1 = 0; // Parameter - 1 + unsigned long p2 = 0; // Parameter - 2 + unsigned long ident = 0; + bool bRet = true; + + /*Generate EBD for all Buffers in the ETBq*/ + DEBUG_PRINT_LOW("Initiate Input Flush"); + + pthread_mutex_lock(&m_lock); + DEBUG_PRINT_LOW("Check if the Queue is empty"); + while (m_etb_q.m_size) { + m_etb_q.pop_entry(&p1,&p2,&ident); + + if (ident == OMX_COMPONENT_GENERATE_ETB_ARBITRARY) { + DEBUG_PRINT_LOW("Flush Input Heap Buffer %p",(OMX_BUFFERHEADERTYPE *)p2); + m_cb.EmptyBufferDone(&m_cmp ,m_app_data, (OMX_BUFFERHEADERTYPE *)p2); + } else if (ident == OMX_COMPONENT_GENERATE_ETB) { + pending_input_buffers++; + VIDC_TRACE_INT_LOW("ETB-pending", pending_input_buffers); + DEBUG_PRINT_LOW("Flush Input OMX_COMPONENT_GENERATE_ETB %p, pending_input_buffers %d", + (OMX_BUFFERHEADERTYPE *)p2, pending_input_buffers); + empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p2); + } else if (ident == OMX_COMPONENT_GENERATE_EBD) { + DEBUG_PRINT_LOW("Flush Input OMX_COMPONENT_GENERATE_EBD %p", + (OMX_BUFFERHEADERTYPE *)p1); + empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1); + } + } + time_stamp_dts.flush_timestamp(); + /*Check if Heap Buffers are to be flushed*/ + if (arbitrary_bytes && !(codec_config_flag)) { + DEBUG_PRINT_LOW("Reset all the variables before flusing"); + h264_scratch.nFilledLen = 0; + nal_count = 0; + look_ahead_nal = false; + frame_count = 0; + h264_last_au_ts = LLONG_MAX; + h264_last_au_flags = 0; + memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) ); + m_demux_entries = 0; + DEBUG_PRINT_LOW("Initialize parser"); + if (m_frame_parser.mutils) { + m_frame_parser.mutils->initialize_frame_checking_environment(); + } + + while (m_input_pending_q.m_size) { + m_input_pending_q.pop_entry(&p1,&p2,&ident); + m_cb.EmptyBufferDone(&m_cmp ,m_app_data, (OMX_BUFFERHEADERTYPE *)p1); + } + + if (psource_frame) { + m_cb.EmptyBufferDone(&m_cmp ,m_app_data,psource_frame); + psource_frame = NULL; + } + + if (pdest_frame) { + pdest_frame->nFilledLen = 0; + m_input_free_q.insert_entry((unsigned long) pdest_frame, (unsigned int)NULL, + (unsigned int)NULL); + pdest_frame = NULL; + } + m_frame_parser.flush(); + } else if (codec_config_flag) { + DEBUG_PRINT_HIGH("frame_parser flushing skipped due to codec config buffer " + "is not sent to the driver yet"); + } + pthread_mutex_unlock(&m_lock); + input_flush_progress = false; + if (!arbitrary_bytes) { + prev_ts = LLONG_MAX; + rst_prev_ts = true; + } +#ifdef _ANDROID_ + if (m_debug_timestamp) { + m_timestamp_list.reset_ts_list(); + } +#endif + DEBUG_PRINT_HIGH("OMX flush i/p Port complete PenBuf(%d)", pending_input_buffers); + return bRet; +} + + +/* ====================================================================== + FUNCTION + omx_vdec::SendCommandEvent + + DESCRIPTION + Send the event to decoder pipe. This is needed to generate the callbacks + in decoder thread context. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_vdec::post_event(unsigned long p1, + unsigned long p2, + unsigned long id) +{ + bool bRet = false; + + /* Just drop messages typically generated by hardware (w/o client request), + * if we've reported an error to client. */ + if (m_error_propogated) { + switch (id) { + case OMX_COMPONENT_GENERATE_PORT_RECONFIG: + case OMX_COMPONENT_GENERATE_HARDWARE_ERROR: + DEBUG_PRINT_ERROR("Dropping message %lx " + "since client expected to be in error state", id); + return false; + default: + /* whatever */ + break; + } + } + + pthread_mutex_lock(&m_lock); + + if (id == m_fill_output_msg || + id == OMX_COMPONENT_GENERATE_FBD || + id == OMX_COMPONENT_GENERATE_PORT_RECONFIG || + id == OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH) { + m_ftb_q.insert_entry(p1,p2,id); + } else if (id == OMX_COMPONENT_GENERATE_ETB || + id == OMX_COMPONENT_GENERATE_EBD || + id == OMX_COMPONENT_GENERATE_ETB_ARBITRARY || + id == OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH) { + m_etb_q.insert_entry(p1,p2,id); + } else { + m_cmd_q.insert_entry(p1,p2,id); + } + + bRet = true; + DEBUG_PRINT_LOW("Value of this pointer in post_event %p",this); + post_message(this, id); + + pthread_mutex_unlock(&m_lock); + + return bRet; +} + +OMX_ERRORTYPE omx_vdec::get_supported_profile_level(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (!profileLevelType) + return OMX_ErrorBadParameter; + + if (profileLevelType->nPortIndex == 0) { + if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc",OMX_MAX_STRINGNAME_SIZE)) { + profileLevelType->eLevel = OMX_VIDEO_AVCLevel52; + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileBaseline; + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileMain; + } else if (profileLevelType->nProfileIndex == 2) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileHigh; + } else if (profileLevelType->nProfileIndex == 3) { + profileLevelType->eProfile = QOMX_VIDEO_AVCProfileConstrainedBaseline; + } else if (profileLevelType->nProfileIndex == 4) { + profileLevelType->eProfile = QOMX_VIDEO_AVCProfileConstrainedHigh; + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u", + (unsigned int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mvc", OMX_MAX_STRINGNAME_SIZE)) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = QOMX_VIDEO_MVCProfileStereoHigh; + profileLevelType->eLevel = QOMX_VIDEO_MVCLevel51; + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u", + (unsigned int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc", OMX_MAX_STRINGNAME_SIZE)) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_HEVCProfileMain; + profileLevelType->eLevel = OMX_VIDEO_HEVCMainTierLevel51; + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_HEVCProfileMain10; + profileLevelType->eLevel = OMX_VIDEO_HEVCMainTierLevel51; + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u", + (unsigned int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if ((!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263",OMX_MAX_STRINGNAME_SIZE))) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_H263ProfileBaseline; + profileLevelType->eLevel = OMX_VIDEO_H263Level70; + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u", + (unsigned int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE)) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_MPEG4ProfileSimple; + profileLevelType->eLevel = OMX_VIDEO_MPEG4Level5; + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple; + profileLevelType->eLevel = OMX_VIDEO_MPEG4Level5; + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u", + (unsigned int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8",OMX_MAX_STRINGNAME_SIZE) || + !strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp9",OMX_MAX_STRINGNAME_SIZE)) { + eRet = OMX_ErrorNoMore; + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg2",OMX_MAX_STRINGNAME_SIZE)) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_MPEG2ProfileSimple; + profileLevelType->eLevel = OMX_VIDEO_MPEG2LevelHL; + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_MPEG2ProfileMain; + profileLevelType->eLevel = OMX_VIDEO_MPEG2LevelHL; + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u", + (unsigned int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported ret NoMore for codec: %s", drv_ctx.kind); + eRet = OMX_ErrorNoMore; + } + } else { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported should be queries on Input port only %u", + (unsigned int)profileLevelType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::GetParameter + + DESCRIPTION + OMX Get Parameter method implementation + + PARAMETERS + <TBD>. + + RETURN VALUE + Error None if successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_INOUT OMX_PTR paramData) +{ + (void) hComp; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + DEBUG_PRINT_LOW("get_parameter:"); + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Get Param in Invalid State"); + return OMX_ErrorInvalidState; + } + if (paramData == NULL) { + DEBUG_PRINT_LOW("Get Param in Invalid paramData"); + return OMX_ErrorBadParameter; + } + switch ((unsigned long)paramIndex) { + case OMX_IndexParamPortDefinition: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_PORTDEFINITIONTYPE); + OMX_PARAM_PORTDEFINITIONTYPE *portDefn = + (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamPortDefinition"); + decide_dpb_buffer_mode(is_down_scalar_enabled); + eRet = update_portdef(portDefn); + if (eRet == OMX_ErrorNone) + m_port_def = *portDefn; + break; + } + case OMX_IndexParamVideoInit: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PORT_PARAM_TYPE); + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoInit"); + + portParamType->nVersion.nVersion = OMX_SPEC_VERSION; + portParamType->nSize = sizeof(OMX_PORT_PARAM_TYPE); + portParamType->nPorts = 2; + portParamType->nStartPortNumber = 0; + break; + } + case OMX_IndexParamVideoPortFormat: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_PORTFORMATTYPE); + OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoPortFormat"); + + portFmt->nVersion.nVersion = OMX_SPEC_VERSION; + portFmt->nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE); + + if (0 == portFmt->nPortIndex) { + if (0 == portFmt->nIndex) { + portFmt->eColorFormat = OMX_COLOR_FormatUnused; + portFmt->eCompressionFormat = eCompressionFormat; + } else { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoPortFormat:"\ + " NoMore compression formats"); + eRet = OMX_ErrorNoMore; + } + } else if (1 == portFmt->nPortIndex) { + portFmt->eCompressionFormat = OMX_VIDEO_CodingUnused; + + // Distinguish non-surface mode from normal playback use-case based on + // usage hinted via "OMX.google.android.index.useAndroidNativeBuffer2" + // For non-android, use the default list + // Also use default format-list if FLEXIBLE YUV is supported, + // as the client negotiates the standard color-format if it needs to + bool useNonSurfaceMode = false; +#if defined(_ANDROID_) && !defined(FLEXYUV_SUPPORTED) + useNonSurfaceMode = (m_enable_android_native_buffers == OMX_FALSE); +#endif + if (is_thulium_v1) { + portFmt->eColorFormat = getPreferredColorFormatDefaultMode(portFmt->nIndex); + } else { + portFmt->eColorFormat = useNonSurfaceMode ? + getPreferredColorFormatNonSurfaceMode(portFmt->nIndex) : + getPreferredColorFormatDefaultMode(portFmt->nIndex); + } + + if (portFmt->eColorFormat == OMX_COLOR_FormatMax ) { + eRet = OMX_ErrorNoMore; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoPortFormat:"\ + " NoMore Color formats"); + } + DEBUG_PRINT_HIGH("returning color-format: 0x%x", portFmt->eColorFormat); + } else { + DEBUG_PRINT_ERROR("get_parameter: Bad port index %d", + (int)portFmt->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + /*Component should support this port definition*/ + case OMX_IndexParamAudioInit: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PORT_PARAM_TYPE); + OMX_PORT_PARAM_TYPE *audioPortParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamAudioInit"); + audioPortParamType->nVersion.nVersion = OMX_SPEC_VERSION; + audioPortParamType->nSize = sizeof(OMX_PORT_PARAM_TYPE); + audioPortParamType->nPorts = 0; + audioPortParamType->nStartPortNumber = 0; + break; + } + /*Component should support this port definition*/ + case OMX_IndexParamImageInit: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PORT_PARAM_TYPE); + OMX_PORT_PARAM_TYPE *imagePortParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamImageInit"); + imagePortParamType->nVersion.nVersion = OMX_SPEC_VERSION; + imagePortParamType->nSize = sizeof(OMX_PORT_PARAM_TYPE); + imagePortParamType->nPorts = 0; + imagePortParamType->nStartPortNumber = 0; + break; + + } + /*Component should support this port definition*/ + case OMX_IndexParamOtherInit: { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamOtherInit %08x", + paramIndex); + eRet =OMX_ErrorUnsupportedIndex; + break; + } + case OMX_IndexParamStandardComponentRole: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_COMPONENTROLETYPE); + OMX_PARAM_COMPONENTROLETYPE *comp_role; + comp_role = (OMX_PARAM_COMPONENTROLETYPE *) paramData; + comp_role->nVersion.nVersion = OMX_SPEC_VERSION; + comp_role->nSize = sizeof(*comp_role); + + DEBUG_PRINT_LOW("Getparameter: OMX_IndexParamStandardComponentRole %d", + paramIndex); + strlcpy((char*)comp_role->cRole,(const char*)m_cRole, + OMX_MAX_STRINGNAME_SIZE); + break; + } + /* Added for parameter test */ + case OMX_IndexParamPriorityMgmt: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PRIORITYMGMTTYPE); + OMX_PRIORITYMGMTTYPE *priorityMgmType = + (OMX_PRIORITYMGMTTYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamPriorityMgmt"); + priorityMgmType->nVersion.nVersion = OMX_SPEC_VERSION; + priorityMgmType->nSize = sizeof(OMX_PRIORITYMGMTTYPE); + + break; + } + /* Added for parameter test */ + case OMX_IndexParamCompBufferSupplier: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_BUFFERSUPPLIERTYPE); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType = + (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamCompBufferSupplier"); + + bufferSupplierType->nSize = sizeof(OMX_PARAM_BUFFERSUPPLIERTYPE); + bufferSupplierType->nVersion.nVersion = OMX_SPEC_VERSION; + if (0 == bufferSupplierType->nPortIndex) + bufferSupplierType->nPortIndex = OMX_BufferSupplyUnspecified; + else if (1 == bufferSupplierType->nPortIndex) + bufferSupplierType->nPortIndex = OMX_BufferSupplyUnspecified; + else + eRet = OMX_ErrorBadPortIndex; + + + break; + } + case OMX_IndexParamVideoAvc: { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoAvc %08x", + paramIndex); + break; + } + case (OMX_INDEXTYPE)QOMX_IndexParamVideoMvc: { + DEBUG_PRINT_LOW("get_parameter: QOMX_IndexParamVideoMvc %08x", + paramIndex); + break; + } + case OMX_IndexParamVideoH263: { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoH263 %08x", + paramIndex); + break; + } + case OMX_IndexParamVideoMpeg4: { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoMpeg4 %08x", + paramIndex); + break; + } + case OMX_IndexParamVideoMpeg2: { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoMpeg2 %08x", + paramIndex); + break; + } + case OMX_IndexParamVideoProfileLevelQuerySupported: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_PROFILELEVELTYPE); + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported %08x", paramIndex); + OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType = + (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)paramData; + eRet = get_supported_profile_level(profileLevelType); + break; + } +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) + case OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage: { + VALIDATE_OMX_PARAM_DATA(paramData, GetAndroidNativeBufferUsageParams); + DEBUG_PRINT_LOW("get_parameter: OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage"); + GetAndroidNativeBufferUsageParams* nativeBuffersUsage = (GetAndroidNativeBufferUsageParams *) paramData; + if (nativeBuffersUsage->nPortIndex == OMX_CORE_OUTPUT_PORT_INDEX) { + + if (secure_mode && !secure_scaling_to_non_secure_opb) { + nativeBuffersUsage->nUsage = (GRALLOC_USAGE_PRIVATE_MM_HEAP | GRALLOC_USAGE_PROTECTED | + GRALLOC_USAGE_PRIVATE_UNCACHED); + } else { + nativeBuffersUsage->nUsage = GRALLOC_USAGE_PRIVATE_UNCACHED; + } + } else { + DEBUG_PRINT_HIGH("get_parameter: OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage failed!"); + eRet = OMX_ErrorBadParameter; + } + } + break; +#endif + +#ifdef FLEXYUV_SUPPORTED + case OMX_QcomIndexFlexibleYUVDescription: { + DEBUG_PRINT_LOW("get_parameter: describeColorFormat"); + VALIDATE_OMX_PARAM_DATA(paramData, DescribeColorFormatParams); + eRet = describeColorFormat(paramData); + break; + } +#endif + case OMX_IndexParamVideoProfileLevelCurrent: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_PROFILELEVELTYPE); + OMX_VIDEO_PARAM_PROFILELEVELTYPE* pParam = (OMX_VIDEO_PARAM_PROFILELEVELTYPE*)paramData; + struct v4l2_control profile_control, level_control; + + switch (drv_ctx.decoder_format) { + case VDEC_CODECTYPE_H264: + profile_control.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE; + level_control.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL; + break; + default: + DEBUG_PRINT_ERROR("get_param of OMX_IndexParamVideoProfileLevelCurrent only available for H264"); + eRet = OMX_ErrorNotImplemented; + break; + } + + if (!eRet && !ioctl(drv_ctx.video_driver_fd, VIDIOC_G_CTRL, &profile_control)) { + switch ((enum v4l2_mpeg_video_h264_profile)profile_control.value) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + pParam->eProfile = OMX_VIDEO_AVCProfileBaseline; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + pParam->eProfile = OMX_VIDEO_AVCProfileMain; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: + pParam->eProfile = OMX_VIDEO_AVCProfileExtended; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + pParam->eProfile = OMX_VIDEO_AVCProfileHigh; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: + pParam->eProfile = OMX_VIDEO_AVCProfileHigh10; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: + pParam->eProfile = OMX_VIDEO_AVCProfileHigh422; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA: + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA: + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA: + case V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA: + case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE: + case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH: + case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA: + case V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH: + case V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH: + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH: + eRet = OMX_ErrorUnsupportedIndex; + break; + } + } else { + eRet = OMX_ErrorUnsupportedIndex; + } + + + if (!eRet && !ioctl(drv_ctx.video_driver_fd, VIDIOC_G_CTRL, &level_control)) { + switch ((enum v4l2_mpeg_video_h264_level)level_control.value) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + pParam->eLevel = OMX_VIDEO_AVCLevel1; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + pParam->eLevel = OMX_VIDEO_AVCLevel1b; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + pParam->eLevel = OMX_VIDEO_AVCLevel11; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + pParam->eLevel = OMX_VIDEO_AVCLevel12; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + pParam->eLevel = OMX_VIDEO_AVCLevel13; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + pParam->eLevel = OMX_VIDEO_AVCLevel2; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + pParam->eLevel = OMX_VIDEO_AVCLevel21; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + pParam->eLevel = OMX_VIDEO_AVCLevel22; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + pParam->eLevel = OMX_VIDEO_AVCLevel3; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + pParam->eLevel = OMX_VIDEO_AVCLevel31; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + pParam->eLevel = OMX_VIDEO_AVCLevel32; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + pParam->eLevel = OMX_VIDEO_AVCLevel4; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + pParam->eLevel = OMX_VIDEO_AVCLevel41; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + pParam->eLevel = OMX_VIDEO_AVCLevel42; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + pParam->eLevel = OMX_VIDEO_AVCLevel5; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + pParam->eLevel = OMX_VIDEO_AVCLevel51; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_2: + pParam->eLevel = OMX_VIDEO_AVCLevel52; + break; + } + } else { + eRet = OMX_ErrorUnsupportedIndex; + } + + break; + + } + case OMX_QTIIndexParamVideoClientExtradata: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_VIDEO_CLIENT_EXTRADATATYPE); + DEBUG_PRINT_LOW("get_parameter: OMX_QTIIndexParamVideoClientExtradata"); + QOMX_VIDEO_CLIENT_EXTRADATATYPE *pParam = + (QOMX_VIDEO_CLIENT_EXTRADATATYPE *)paramData; + pParam->nExtradataSize = VENUS_EXTRADATA_SIZE(4096, 2160); + pParam->nExtradataAllocSize = pParam->nExtradataSize * MAX_NUM_INPUT_OUTPUT_BUFFERS; + eRet = OMX_ErrorNone; + break; + } + default: { + DEBUG_PRINT_ERROR("get_parameter: unknown param %08x", paramIndex); + eRet =OMX_ErrorUnsupportedIndex; + } + + } + + DEBUG_PRINT_LOW("get_parameter returning WxH(%d x %d) SxSH(%d x %d)", + drv_ctx.video_resolution.frame_width, + drv_ctx.video_resolution.frame_height, + drv_ctx.video_resolution.stride, + drv_ctx.video_resolution.scan_lines); + + return eRet; +} + +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) +OMX_ERRORTYPE omx_vdec::use_android_native_buffer(OMX_IN OMX_HANDLETYPE hComp, OMX_PTR data) +{ + DEBUG_PRINT_LOW("Inside use_android_native_buffer"); + OMX_ERRORTYPE eRet = OMX_ErrorNone; + UseAndroidNativeBufferParams *params = (UseAndroidNativeBufferParams *)data; + + if ((params == NULL) || + (params->nativeBuffer == NULL) || + (params->nativeBuffer->handle == NULL) || + !m_enable_android_native_buffers) + return OMX_ErrorBadParameter; + m_use_android_native_buffers = OMX_TRUE; + sp<android_native_buffer_t> nBuf = params->nativeBuffer; + private_handle_t *handle = (private_handle_t *)nBuf->handle; + if (OMX_CORE_OUTPUT_PORT_INDEX == params->nPortIndex) { //android native buffers can be used only on Output port + OMX_U8 *buffer = NULL; + if (!secure_mode) { + buffer = (OMX_U8*)mmap(0, handle->size, + PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0); + if (buffer == MAP_FAILED) { + DEBUG_PRINT_ERROR("Failed to mmap pmem with fd = %d, size = %d", handle->fd, handle->size); + return OMX_ErrorInsufficientResources; + } + } + eRet = use_buffer(hComp,params->bufferHeader,params->nPortIndex,data,handle->size,buffer); + } else { + eRet = OMX_ErrorBadParameter; + } + return eRet; +} +#endif + +OMX_ERRORTYPE omx_vdec::enable_smoothstreaming() { + struct v4l2_control control; + struct v4l2_format fmt; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER; + control.value = 1; + int rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL,&control); + if (rc < 0) { + DEBUG_PRINT_ERROR("Failed to enable Smooth Streaming on driver."); + return OMX_ErrorHardware; + } + m_smoothstreaming_mode = true; + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::Setparameter + + DESCRIPTION + OMX Set Parameter method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::set_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_IN OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + int ret=0; + struct v4l2_format fmt; +#ifdef _ANDROID_ + char property_value[PROPERTY_VALUE_MAX] = {0}; +#endif + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Set Param in Invalid State"); + return OMX_ErrorInvalidState; + } + if (paramData == NULL) { + DEBUG_PRINT_ERROR("Get Param in Invalid paramData"); + return OMX_ErrorBadParameter; + } + if ((m_state != OMX_StateLoaded) && + BITMASK_ABSENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING) && + (m_out_bEnabled == OMX_TRUE) && + BITMASK_ABSENT(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING) && + (m_inp_bEnabled == OMX_TRUE)) { + DEBUG_PRINT_ERROR("Set Param in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + switch ((unsigned long)paramIndex) { + case OMX_IndexParamPortDefinition: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_PORTDEFINITIONTYPE); + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + //TODO: Check if any allocate buffer/use buffer/useNativeBuffer has + //been called. + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition H= %d, W = %d", + (int)portDefn->format.video.nFrameHeight, + (int)portDefn->format.video.nFrameWidth); + + if (portDefn->nBufferCountActual > MAX_NUM_INPUT_OUTPUT_BUFFERS) { + DEBUG_PRINT_ERROR("ERROR: Buffers requested exceeds max limit %d", + portDefn->nBufferCountActual); + eRet = OMX_ErrorBadParameter; + break; + } + if (OMX_DirOutput == portDefn->eDir) { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition OP port"); + bool port_format_changed = false; + m_display_id = portDefn->format.video.pNativeWindow; + unsigned int buffer_size; + /* update output port resolution with client supplied dimensions + in case scaling is enabled, else it follows input resolution set + */ + decide_dpb_buffer_mode(is_down_scalar_enabled); + if (is_down_scalar_enabled) { + DEBUG_PRINT_LOW("SetParam OP: WxH(%u x %u)", + (unsigned int)portDefn->format.video.nFrameWidth, + (unsigned int)portDefn->format.video.nFrameHeight); + if (portDefn->format.video.nFrameHeight != 0x0 && + portDefn->format.video.nFrameWidth != 0x0) { + memset(&fmt, 0x0, sizeof(struct v4l2_format)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = capture_capability; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_G_FMT, &fmt); + if (ret) { + DEBUG_PRINT_ERROR("Get Resolution failed"); + eRet = OMX_ErrorHardware; + break; + } + if ((portDefn->format.video.nFrameHeight != (unsigned int)fmt.fmt.pix_mp.height) || + (portDefn->format.video.nFrameWidth != (unsigned int)fmt.fmt.pix_mp.width)) { + port_format_changed = true; + } + + /* set crop info */ + rectangle.nLeft = 0; + rectangle.nTop = 0; + rectangle.nWidth = portDefn->format.video.nFrameWidth; + rectangle.nHeight = portDefn->format.video.nFrameHeight; + + m_extradata_info.output_crop_rect.nLeft = 0; + m_extradata_info.output_crop_rect.nTop = 0; + m_extradata_info.output_crop_rect.nWidth = rectangle.nWidth; + m_extradata_info.output_crop_rect.nHeight = rectangle.nHeight; + + eRet = is_video_session_supported(); + if (eRet) + break; + memset(&fmt, 0x0, sizeof(struct v4l2_format)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.height = (unsigned int)portDefn->format.video.nFrameHeight; + fmt.fmt.pix_mp.width = (unsigned int)portDefn->format.video.nFrameWidth; + fmt.fmt.pix_mp.pixelformat = capture_capability; + DEBUG_PRINT_LOW("fmt.fmt.pix_mp.height = %d , fmt.fmt.pix_mp.width = %d", + fmt.fmt.pix_mp.height, fmt.fmt.pix_mp.width); + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + DEBUG_PRINT_ERROR("Set Resolution failed"); + eRet = OMX_ErrorUnsupportedSetting; + } else + eRet = get_buffer_req(&drv_ctx.op_buf); + } + + if (eRet) { + break; + } + + if (secure_mode) { + struct v4l2_control control; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_G_CTRL, &control) < 0) { + DEBUG_PRINT_ERROR("Failed getting secure scaling threshold : %d, id was : %x", errno, control.id); + eRet = OMX_ErrorHardware; + } else { + /* This is a workaround for a bug in fw which uses stride + * and slice instead of width and height to check against + * the threshold. + */ + OMX_U32 stride, slice; + if (drv_ctx.output_format == VDEC_YUV_FORMAT_NV12) { + stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, portDefn->format.video.nFrameWidth); + slice = VENUS_Y_SCANLINES(COLOR_FMT_NV12, portDefn->format.video.nFrameHeight); + } else if (drv_ctx.output_format == VDEC_YUV_FORMAT_NV12_UBWC) { + stride = VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, portDefn->format.video.nFrameWidth); + slice = VENUS_Y_SCANLINES(COLOR_FMT_NV12_UBWC, portDefn->format.video.nFrameHeight); + } else if (drv_ctx.output_format == VDEC_YUV_FORMAT_NV12_TP10_UBWC) { + stride = VENUS_Y_STRIDE(COLOR_FMT_NV12_BPP10_UBWC, portDefn->format.video.nFrameWidth); + slice = VENUS_Y_SCANLINES(COLOR_FMT_NV12_BPP10_UBWC, portDefn->format.video.nFrameHeight); + } else { + stride = portDefn->format.video.nFrameWidth; + slice = portDefn->format.video.nFrameHeight; + } + + DEBUG_PRINT_LOW("Stride is %d, slice is %d, sxs is %d\n", stride, slice, stride * slice); + DEBUG_PRINT_LOW("Threshold value is %d\n", control.value); + + if (stride * slice <= (OMX_U32)control.value) { + secure_scaling_to_non_secure_opb = true; + DEBUG_PRINT_HIGH("Enabling secure scalar out of CPZ"); + control.id = V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2; + control.value = 1; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control) < 0) { + DEBUG_PRINT_ERROR("Enabling non-secure output2 failed"); + eRet = OMX_ErrorUnsupportedSetting; + } + } + } + } + } + + if (eRet) { + break; + } + + if (portDefn->nBufferCountActual > MAX_NUM_INPUT_OUTPUT_BUFFERS) { + DEBUG_PRINT_ERROR("Requested o/p buf count (%u) exceeds limit (%u)", + portDefn->nBufferCountActual, MAX_NUM_INPUT_OUTPUT_BUFFERS); + eRet = OMX_ErrorBadParameter; + } else if (!client_buffers.get_buffer_req(buffer_size)) { + DEBUG_PRINT_ERROR("Error in getting buffer requirements"); + eRet = OMX_ErrorBadParameter; + } else if (!port_format_changed) { + + // Buffer count can change only when port is unallocated + if (m_out_mem_ptr && + (portDefn->nBufferCountActual != drv_ctx.op_buf.actualcount || + portDefn->nBufferSize != drv_ctx.op_buf.buffer_size)) { + + DEBUG_PRINT_ERROR("Cannot change o/p buffer count since all buffers are not freed yet !"); + eRet = OMX_ErrorInvalidState; + break; + } + + // route updating of buffer requirements via c2d proxy. + // Based on whether c2d is enabled, requirements will be handed + // to the vidc driver appropriately + eRet = client_buffers.set_buffer_req(portDefn->nBufferSize, + portDefn->nBufferCountActual); + if (eRet == OMX_ErrorNone) { + m_port_def = *portDefn; + } else { + DEBUG_PRINT_ERROR("ERROR: OP Requirements(#%d: %u) Requested(#%u: %u)", + drv_ctx.op_buf.mincount, (unsigned int)buffer_size, + (unsigned int)portDefn->nBufferCountActual, (unsigned int)portDefn->nBufferSize); + eRet = OMX_ErrorBadParameter; + } + } + } else if (OMX_DirInput == portDefn->eDir) { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition IP port"); + bool port_format_changed = false; + if ((portDefn->format.video.xFramerate >> 16) > 0 && + (portDefn->format.video.xFramerate >> 16) <= MAX_SUPPORTED_FPS) { + // Frame rate only should be set if this is a "known value" or to + // activate ts prediction logic (arbitrary mode only) sending input + // timestamps with max value (LLONG_MAX). + m_fps_received = portDefn->format.video.xFramerate; + DEBUG_PRINT_HIGH("set_parameter: frame rate set by omx client : %u", + (unsigned int)portDefn->format.video.xFramerate >> 16); + Q16ToFraction(portDefn->format.video.xFramerate, drv_ctx.frame_rate.fps_numerator, + drv_ctx.frame_rate.fps_denominator); + if (!drv_ctx.frame_rate.fps_numerator) { + DEBUG_PRINT_ERROR("Numerator is zero setting to 30"); + drv_ctx.frame_rate.fps_numerator = 30; + } + if (drv_ctx.frame_rate.fps_denominator) + drv_ctx.frame_rate.fps_numerator = (int) + drv_ctx.frame_rate.fps_numerator / drv_ctx.frame_rate.fps_denominator; + drv_ctx.frame_rate.fps_denominator = 1; + frm_int = drv_ctx.frame_rate.fps_denominator * 1e6 / + drv_ctx.frame_rate.fps_numerator; + DEBUG_PRINT_LOW("set_parameter: frm_int(%u) fps(%.2f)", + (unsigned int)frm_int, drv_ctx.frame_rate.fps_numerator / + (float)drv_ctx.frame_rate.fps_denominator); + + struct v4l2_outputparm oparm; + /*XXX: we're providing timing info as seconds per frame rather than frames + * per second.*/ + oparm.timeperframe.numerator = drv_ctx.frame_rate.fps_denominator; + oparm.timeperframe.denominator = drv_ctx.frame_rate.fps_numerator; + + struct v4l2_streamparm sparm; + sparm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + sparm.parm.output = oparm; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_PARM, &sparm)) { + DEBUG_PRINT_ERROR("Unable to convey fps info to driver, performance might be affected"); + eRet = OMX_ErrorHardware; + break; + } + m_perf_control.request_cores(frm_int); + } + + if (drv_ctx.video_resolution.frame_height != + portDefn->format.video.nFrameHeight || + drv_ctx.video_resolution.frame_width != + portDefn->format.video.nFrameWidth) { + DEBUG_PRINT_LOW("SetParam IP: WxH(%u x %u)", + (unsigned int)portDefn->format.video.nFrameWidth, + (unsigned int)portDefn->format.video.nFrameHeight); + port_format_changed = true; + OMX_U32 frameWidth = portDefn->format.video.nFrameWidth; + OMX_U32 frameHeight = portDefn->format.video.nFrameHeight; + if (frameHeight != 0x0 && frameWidth != 0x0) { + if (m_smoothstreaming_mode && + ((frameWidth * frameHeight) < + (m_smoothstreaming_width * m_smoothstreaming_height))) { + frameWidth = m_smoothstreaming_width; + frameHeight = m_smoothstreaming_height; + DEBUG_PRINT_LOW("NOTE: Setting resolution %u x %u " + "for adaptive-playback/smooth-streaming", + (unsigned int)frameWidth, (unsigned int)frameHeight); + } + + m_extradata_info.output_crop_rect.nLeft = 0; + m_extradata_info.output_crop_rect.nTop = 0; + m_extradata_info.output_crop_rect.nWidth = frameWidth; + m_extradata_info.output_crop_rect.nHeight = frameHeight; + + update_resolution(frameWidth, frameHeight, + frameWidth, frameHeight); + eRet = is_video_session_supported(); + if (eRet) + break; + if (is_down_scalar_enabled) { + memset(&fmt, 0x0, sizeof(struct v4l2_format)); + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = output_capability; + DEBUG_PRINT_LOW("DS Enabled : height = %d , width = %d", + fmt.fmt.pix_mp.height,fmt.fmt.pix_mp.width); + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + } else { + memset(&fmt, 0x0, sizeof(struct v4l2_format)); + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = output_capability; + DEBUG_PRINT_LOW("DS Disabled : height = %d , width = %d", + fmt.fmt.pix_mp.height,fmt.fmt.pix_mp.width); + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = capture_capability; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + } + if (ret) { + DEBUG_PRINT_ERROR("Set Resolution failed"); + eRet = OMX_ErrorUnsupportedSetting; + } else { + if (!is_down_scalar_enabled) + eRet = get_buffer_req(&drv_ctx.op_buf); + } + } + } + if (m_custom_buffersize.input_buffersize + && (portDefn->nBufferSize > m_custom_buffersize.input_buffersize)) { + DEBUG_PRINT_ERROR("ERROR: Custom buffer size set by client: %d, trying to set: %d", + m_custom_buffersize.input_buffersize, portDefn->nBufferSize); + eRet = OMX_ErrorBadParameter; + break; + } + if (portDefn->nBufferCountActual > MAX_NUM_INPUT_OUTPUT_BUFFERS) { + DEBUG_PRINT_ERROR("Requested i/p buf count (%u) exceeds limit (%u)", + portDefn->nBufferCountActual, MAX_NUM_INPUT_OUTPUT_BUFFERS); + eRet = OMX_ErrorBadParameter; + break; + } + // Buffer count can change only when port is unallocated + if (m_inp_mem_ptr && + (portDefn->nBufferCountActual != drv_ctx.ip_buf.actualcount || + portDefn->nBufferSize != drv_ctx.ip_buf.buffer_size)) { + DEBUG_PRINT_ERROR("Cannot change i/p buffer count since all buffers are not freed yet !"); + eRet = OMX_ErrorInvalidState; + break; + } + + if (portDefn->nBufferCountActual >= drv_ctx.ip_buf.mincount + || portDefn->nBufferSize != drv_ctx.ip_buf.buffer_size) { + port_format_changed = true; + vdec_allocatorproperty *buffer_prop = &drv_ctx.ip_buf; + drv_ctx.ip_buf.actualcount = portDefn->nBufferCountActual; + drv_ctx.ip_buf.buffer_size = (portDefn->nBufferSize + buffer_prop->alignment - 1) & + (~(buffer_prop->alignment - 1)); + eRet = set_buffer_req(buffer_prop); + } + if (false == port_format_changed) { + DEBUG_PRINT_ERROR("ERROR: IP Requirements(#%d: %u) Requested(#%u: %u)", + drv_ctx.ip_buf.mincount, (unsigned int)drv_ctx.ip_buf.buffer_size, + (unsigned int)portDefn->nBufferCountActual, (unsigned int)portDefn->nBufferSize); + eRet = OMX_ErrorBadParameter; + } + } else if (portDefn->eDir == OMX_DirMax) { + DEBUG_PRINT_ERROR(" Set_parameter: Bad Port idx %d", + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + } + break; + case OMX_IndexParamVideoPortFormat: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_PORTFORMATTYPE); + OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; + int ret=0; + struct v4l2_format fmt; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoPortFormat 0x%x, port: %u", + portFmt->eColorFormat, (unsigned int)portFmt->nPortIndex); + + memset(&fmt, 0x0, sizeof(struct v4l2_format)); + if (1 == portFmt->nPortIndex) { + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_G_FMT, &fmt); + if (ret < 0) { + DEBUG_PRINT_ERROR("%s: Failed to get format on capture mplane", __func__); + return OMX_ErrorBadParameter; + } + enum vdec_output_fromat op_format; + if (portFmt->eColorFormat == (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m || + portFmt->eColorFormat == (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView || + portFmt->eColorFormat == OMX_COLOR_FormatYUV420Planar || + portFmt->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { + op_format = (enum vdec_output_fromat)VDEC_YUV_FORMAT_NV12; + } else if (portFmt->eColorFormat == (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed) { + op_format = (enum vdec_output_fromat)VDEC_YUV_FORMAT_NV12_UBWC; + } else + eRet = OMX_ErrorBadParameter; + + if (portFmt->eColorFormat == (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed) { + fmt.fmt.pix_mp.pixelformat = capture_capability = V4L2_PIX_FMT_NV12_UBWC; + } else { + fmt.fmt.pix_mp.pixelformat = capture_capability = V4L2_PIX_FMT_NV12; + } + + if (eRet == OMX_ErrorNone) { + drv_ctx.output_format = op_format; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + DEBUG_PRINT_ERROR("Set output format failed"); + eRet = OMX_ErrorUnsupportedSetting; + /*TODO: How to handle this case */ + } else { + eRet = get_buffer_req(&drv_ctx.op_buf); + } + } + if (eRet == OMX_ErrorNone) { + if (!client_buffers.set_color_format(portFmt->eColorFormat)) { + DEBUG_PRINT_ERROR("Set color format failed"); + eRet = OMX_ErrorBadParameter; + } + } + } + } + break; + + case OMX_QcomIndexPortDefn: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_PARAM_PORTDEFINITIONTYPE); + OMX_QCOM_PARAM_PORTDEFINITIONTYPE *portFmt = + (OMX_QCOM_PARAM_PORTDEFINITIONTYPE *) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexQcomParamPortDefinitionType %u", + (unsigned int)portFmt->nFramePackingFormat); + + /* Input port */ + if (portFmt->nPortIndex == 0) { + // arbitrary_bytes mode cannot be changed arbitrarily since this controls how: + // - headers are allocated and + // - headers-indices are derived + // Avoid changing arbitrary_bytes when the port is already allocated + if (m_inp_mem_ptr) { + DEBUG_PRINT_ERROR("Cannot change arbitrary-bytes-mode since input port is not free!"); + return OMX_ErrorUnsupportedSetting; + } + if (portFmt->nFramePackingFormat == OMX_QCOM_FramePacking_Arbitrary) { + if (secure_mode || m_input_pass_buffer_fd) { + arbitrary_bytes = false; + DEBUG_PRINT_ERROR("setparameter: cannot set to arbitary bytes mode"); + eRet = OMX_ErrorUnsupportedSetting; + } else { + arbitrary_bytes = true; + } + } else if (portFmt->nFramePackingFormat == + OMX_QCOM_FramePacking_OnlyOneCompleteFrame) { + arbitrary_bytes = false; +#ifdef _ANDROID_ + property_get("vidc.dec.debug.arbitrarybytes.mode", property_value, "0"); + if (atoi(property_value)) { + DEBUG_PRINT_HIGH("arbitrary_bytes enabled via property command"); + arbitrary_bytes = true; + } +#endif + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown FramePacking format %u", + (unsigned int)portFmt->nFramePackingFormat); + eRet = OMX_ErrorUnsupportedSetting; + } + } else if (portFmt->nPortIndex == OMX_CORE_OUTPUT_PORT_INDEX) { + DEBUG_PRINT_HIGH("set_parameter: OMX_IndexQcomParamPortDefinitionType OP Port"); + if ( (portFmt->nMemRegion > OMX_QCOM_MemRegionInvalid && + portFmt->nMemRegion < OMX_QCOM_MemRegionMax) && + portFmt->nCacheAttr == OMX_QCOM_CacheAttrNone) { + m_out_mem_region_smi = OMX_TRUE; + if ((m_out_mem_region_smi && m_out_pvt_entry_pmem)) { + DEBUG_PRINT_HIGH("set_parameter: OMX_IndexQcomParamPortDefinitionType OP Port: out pmem set"); + m_use_output_pmem = OMX_TRUE; + } + } + } + } + if (is_thulium_v1 && !strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc", + OMX_MAX_STRINGNAME_SIZE)) { + arbitrary_bytes = true; + DEBUG_PRINT_HIGH("Force arbitrary_bytes to true for h264"); + } + break; + + case OMX_IndexParamStandardComponentRole: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_COMPONENTROLETYPE); + OMX_PARAM_COMPONENTROLETYPE *comp_role; + comp_role = (OMX_PARAM_COMPONENTROLETYPE *) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamStandardComponentRole %s", + comp_role->cRole); + + if ((m_state == OMX_StateLoaded)&& + !BITMASK_PRESENT(&m_flags, OMX_COMPONENT_IDLE_PENDING)) { + DEBUG_PRINT_LOW("Set Parameter called in valid state"); + } else { + DEBUG_PRINT_ERROR("Set Parameter called in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + + if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc", OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((char*)comp_role->cRole, "video_decoder.avc", OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole, "video_decoder.avc", OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mvc", OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((char*)comp_role->cRole, "video_decoder.mvc", OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole, "video_decoder.mvc", OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet = OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg4", OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole, "video_decoder.mpeg4", OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole, "video_decoder.mpeg4", OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet = OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263", OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole, "video_decoder.h263", OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole, "video_decoder.h263", OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg2", OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole, "video_decoder.mpeg2", OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole, "video_decoder.mpeg2", OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet = OMX_ErrorUnsupportedSetting; + } + } else if ((!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx", OMX_MAX_STRINGNAME_SIZE)) || + (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx311", OMX_MAX_STRINGNAME_SIZE)) || + (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx4", OMX_MAX_STRINGNAME_SIZE)) + ) { + if (!strncmp((const char*)comp_role->cRole, "video_decoder.divx", OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole, "video_decoder.divx", OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } else if ( (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vc1", OMX_MAX_STRINGNAME_SIZE)) || + (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.wmv", OMX_MAX_STRINGNAME_SIZE)) + ) { + if (!strncmp((const char*)comp_role->cRole, "video_decoder.vc1", OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole, "video_decoder.vc1", OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8", OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole, "video_decoder.vp8", OMX_MAX_STRINGNAME_SIZE) || + !strncmp((const char*)comp_role->cRole, "video_decoder.vpx", OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole, "video_decoder.vp8", OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet = OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp9", OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole, "video_decoder.vp9", OMX_MAX_STRINGNAME_SIZE) || + !strncmp((const char*)comp_role->cRole, "video_decoder.vpx", OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole, "video_decoder.vp9", OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet = OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc", OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole, "video_decoder.hevc", OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole, "video_decoder.hevc", OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown Index %s", comp_role->cRole); + eRet = OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_ERROR("Setparameter: unknown param %s", drv_ctx.kind); + eRet = OMX_ErrorInvalidComponentName; + } + break; + } + + case OMX_IndexParamPriorityMgmt: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PRIORITYMGMTTYPE); + if (m_state != OMX_StateLoaded) { + DEBUG_PRINT_ERROR("Set Parameter called in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + OMX_PRIORITYMGMTTYPE *priorityMgmtype = (OMX_PRIORITYMGMTTYPE*) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPriorityMgmt %u", + (unsigned int)priorityMgmtype->nGroupID); + + DEBUG_PRINT_LOW("set_parameter: priorityMgmtype %u", + (unsigned int)priorityMgmtype->nGroupPriority); + + m_priority_mgm.nGroupID = priorityMgmtype->nGroupID; + m_priority_mgm.nGroupPriority = priorityMgmtype->nGroupPriority; + + break; + } + + case OMX_IndexParamCompBufferSupplier: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_BUFFERSUPPLIERTYPE); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamCompBufferSupplier %d", + bufferSupplierType->eBufferSupplier); + if (bufferSupplierType->nPortIndex == 0 || bufferSupplierType->nPortIndex ==1) + m_buffer_supplier.eBufferSupplier = bufferSupplierType->eBufferSupplier; + + else + + eRet = OMX_ErrorBadPortIndex; + + break; + + } + case OMX_IndexParamVideoAvc: { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoAvc %d", + paramIndex); + break; + } + case (OMX_INDEXTYPE)QOMX_IndexParamVideoMvc: { + DEBUG_PRINT_LOW("set_parameter: QOMX_IndexParamVideoMvc %d", + paramIndex); + break; + } + case OMX_IndexParamVideoH263: { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoH263 %d", + paramIndex); + break; + } + case OMX_IndexParamVideoMpeg4: { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoMpeg4 %d", + paramIndex); + break; + } + case OMX_IndexParamVideoMpeg2: { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoMpeg2 %d", + paramIndex); + break; + } + case OMX_QTIIndexParamLowLatencyMode: { + struct v4l2_control control; + int rc = 0; + QOMX_EXTNINDEX_VIDEO_VENC_LOW_LATENCY_MODE* pParam = + (QOMX_EXTNINDEX_VIDEO_VENC_LOW_LATENCY_MODE*)paramData; + if (pParam->bLowLatencyMode) { + DEBUG_PRINT_HIGH("Enabling DECODE order"); + time_stamp_dts.set_timestamp_reorder_mode(false); + control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER; + control.value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Set picture order failed"); + eRet = OMX_ErrorUnsupportedSetting; + } + } + break; + } + case OMX_QcomIndexParamVideoDecoderPictureOrder: { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_VIDEO_DECODER_PICTURE_ORDER); + QOMX_VIDEO_DECODER_PICTURE_ORDER *pictureOrder = + (QOMX_VIDEO_DECODER_PICTURE_ORDER *)paramData; + struct v4l2_control control; + int pic_order,rc=0; + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexParamVideoDecoderPictureOrder %d", + pictureOrder->eOutputPictureOrder); + if (pictureOrder->eOutputPictureOrder == QOMX_VIDEO_DISPLAY_ORDER) { + pic_order = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY; + } else if (pictureOrder->eOutputPictureOrder == QOMX_VIDEO_DECODE_ORDER) { + pic_order = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE; + time_stamp_dts.set_timestamp_reorder_mode(false); + } else + eRet = OMX_ErrorBadParameter; + if (eRet == OMX_ErrorNone) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER; + control.value = pic_order; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Set picture order failed"); + eRet = OMX_ErrorUnsupportedSetting; + } + } + break; + } + case OMX_QcomIndexParamConcealMBMapExtraData: + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_ENABLETYPE); + eRet = enable_extradata(VDEC_EXTRADATA_MB_ERROR_MAP, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + break; + case OMX_QcomIndexParamFrameInfoExtraData: + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_ENABLETYPE); + eRet = enable_extradata(OMX_FRAMEINFO_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + break; + case OMX_ExtraDataFrameDimension: + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_ENABLETYPE); + eRet = enable_extradata(OMX_FRAMEDIMENSION_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + break; + case OMX_QcomIndexParamInterlaceExtraData: + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_ENABLETYPE); + eRet = enable_extradata(OMX_INTERLACE_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + break; + case OMX_QcomIndexParamH264TimeInfo: + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_ENABLETYPE); + eRet = enable_extradata(OMX_TIMEINFO_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + break; + case OMX_QcomIndexParamVideoFramePackingExtradata: + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_ENABLETYPE); + eRet = enable_extradata(OMX_FRAMEPACK_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + break; + case OMX_QcomIndexParamVideoQPExtraData: + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_ENABLETYPE); + eRet = enable_extradata(OMX_QP_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + break; + case OMX_QcomIndexParamVideoInputBitsInfoExtraData: + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_ENABLETYPE); + eRet = enable_extradata(OMX_BITSINFO_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + break; + case OMX_QcomIndexEnableExtnUserData: + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_ENABLETYPE); + eRet = enable_extradata(OMX_EXTNUSER_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + break; + case OMX_QTIIndexParamVQZipSEIExtraData: + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_ENABLETYPE); + eRet = enable_extradata(OMX_VQZIPSEI_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + break; + case OMX_QcomIndexParamVideoDivx: { + QOMX_VIDEO_PARAM_DIVXTYPE* divXType = (QOMX_VIDEO_PARAM_DIVXTYPE *) paramData; + } + break; + case OMX_QcomIndexPlatformPvt: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_PLATFORMPRIVATE_EXTN); + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexPlatformPvt OP Port"); + OMX_QCOM_PLATFORMPRIVATE_EXTN* entryType = (OMX_QCOM_PLATFORMPRIVATE_EXTN *) paramData; + if (entryType->type != OMX_QCOM_PLATFORM_PRIVATE_PMEM) { + DEBUG_PRINT_HIGH("set_parameter: Platform Private entry type (%d) not supported.", entryType->type); + eRet = OMX_ErrorUnsupportedSetting; + } else { + m_out_pvt_entry_pmem = OMX_TRUE; + if ((m_out_mem_region_smi && m_out_pvt_entry_pmem)) { + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexPlatformPvt OP Port: out pmem set"); + m_use_output_pmem = OMX_TRUE; + } + } + + } + break; + case OMX_QcomIndexParamVideoSyncFrameDecodingMode: { + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexParamVideoSyncFrameDecodingMode"); + DEBUG_PRINT_HIGH("set idr only decoding for thumbnail mode"); + struct v4l2_control control; + int rc; + drv_ctx.idr_only_decoding = 1; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER; + control.value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Set picture order failed"); + eRet = OMX_ErrorUnsupportedSetting; + } else { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE; + control.value = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE; + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Sync frame setting failed"); + eRet = OMX_ErrorUnsupportedSetting; + } + /*Setting sync frame decoding on driver might change buffer + * requirements so update them here*/ + if (get_buffer_req(&drv_ctx.ip_buf)) { + DEBUG_PRINT_ERROR("Sync frame setting failed: falied to get buffer i/p requirements"); + eRet = OMX_ErrorUnsupportedSetting; + } + if (get_buffer_req(&drv_ctx.op_buf)) { + DEBUG_PRINT_ERROR("Sync frame setting failed: falied to get buffer o/p requirements"); + eRet = OMX_ErrorUnsupportedSetting; + } + } + } + break; + + case OMX_QcomIndexParamIndexExtraDataType: { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_INDEXEXTRADATATYPE); + QOMX_INDEXEXTRADATATYPE *extradataIndexType = (QOMX_INDEXEXTRADATATYPE *) paramData; + if ((extradataIndexType->nIndex == OMX_IndexParamPortDefinition) && + (extradataIndexType->bEnabled == OMX_TRUE) && + (extradataIndexType->nPortIndex == 1)) { + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexParamIndexExtraDataType SmoothStreaming"); + eRet = enable_extradata(OMX_PORTDEF_EXTRADATA, false, extradataIndexType->bEnabled); + + } + } + break; + case OMX_QcomIndexParamEnableSmoothStreaming: { +#ifndef SMOOTH_STREAMING_DISABLED + eRet = enable_smoothstreaming(); +#else + eRet = OMX_ErrorUnsupportedSetting; +#endif + } + break; +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) + /* Need to allow following two set_parameters even in Idle + * state. This is ANDROID architecture which is not in sync + * with openmax standard. */ + case OMX_GoogleAndroidIndexEnableAndroidNativeBuffers: { + VALIDATE_OMX_PARAM_DATA(paramData, EnableAndroidNativeBuffersParams); + EnableAndroidNativeBuffersParams* enableNativeBuffers = (EnableAndroidNativeBuffersParams *) paramData; + if (enableNativeBuffers->nPortIndex != OMX_CORE_OUTPUT_PORT_INDEX) { + DEBUG_PRINT_ERROR("Enable/Disable android-native-buffers allowed only on output port!"); + eRet = OMX_ErrorUnsupportedSetting; + break; + } else if (m_out_mem_ptr) { + DEBUG_PRINT_ERROR("Enable/Disable android-native-buffers is not allowed since Output port is not free !"); + eRet = OMX_ErrorInvalidState; + break; + } + if (enableNativeBuffers) { + m_enable_android_native_buffers = enableNativeBuffers->enable; + } +#if !defined(FLEXYUV_SUPPORTED) + if (m_enable_android_native_buffers) { + // Use the most-preferred-native-color-format as surface-mode is hinted here + if(!client_buffers.set_color_format(getPreferredColorFormatDefaultMode(0))) { + DEBUG_PRINT_ERROR("Failed to set native color format!"); + eRet = OMX_ErrorUnsupportedSetting; + } + } +#endif + } + break; + case OMX_GoogleAndroidIndexUseAndroidNativeBuffer: { + VALIDATE_OMX_PARAM_DATA(paramData, UseAndroidNativeBufferParams); + eRet = use_android_native_buffer(hComp, paramData); + } + break; +#if ALLOCATE_OUTPUT_NATIVEHANDLE + case OMX_GoogleAndroidIndexAllocateNativeHandle: { + + AllocateNativeHandleParams* allocateNativeHandleParams = (AllocateNativeHandleParams *) paramData; + VALIDATE_OMX_PARAM_DATA(paramData, AllocateNativeHandleParams); + + if (allocateNativeHandleParams->nPortIndex != OMX_CORE_INPUT_PORT_INDEX) { + DEBUG_PRINT_ERROR("Enable/Disable allocate-native-handle allowed only on input port!"); + eRet = OMX_ErrorUnsupportedSetting; + break; + } else if (m_inp_mem_ptr) { + DEBUG_PRINT_ERROR("Enable/Disable allocate-native-handle is not allowed since Input port is not free !"); + eRet = OMX_ErrorInvalidState; + break; + } + + if (allocateNativeHandleParams != NULL) { + allocate_native_handle = allocateNativeHandleParams->enable; + } + } + break; +#endif //ALLOCATE_OUTPUT_NATIVEHANDLE +#endif + case OMX_QcomIndexParamEnableTimeStampReorder: { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_INDEXTIMESTAMPREORDER); + QOMX_INDEXTIMESTAMPREORDER *reorder = (QOMX_INDEXTIMESTAMPREORDER *)paramData; + if (drv_ctx.picture_order == (vdec_output_order)QOMX_VIDEO_DISPLAY_ORDER) { + if (reorder->bEnable == OMX_TRUE) { + frm_int =0; + time_stamp_dts.set_timestamp_reorder_mode(true); + } else + time_stamp_dts.set_timestamp_reorder_mode(false); + } else { + time_stamp_dts.set_timestamp_reorder_mode(false); + if (reorder->bEnable == OMX_TRUE) { + eRet = OMX_ErrorUnsupportedSetting; + } + } + } + break; + case OMX_IndexParamVideoProfileLevelCurrent: { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_PROFILELEVELTYPE); + OMX_VIDEO_PARAM_PROFILELEVELTYPE* pParam = + (OMX_VIDEO_PARAM_PROFILELEVELTYPE*)paramData; + if (pParam) { + m_profile_lvl.eProfile = pParam->eProfile; + m_profile_lvl.eLevel = pParam->eLevel; + } + break; + + } + case OMX_QcomIndexParamVideoMetaBufferMode: + { + VALIDATE_OMX_PARAM_DATA(paramData, StoreMetaDataInBuffersParams); + StoreMetaDataInBuffersParams *metabuffer = + (StoreMetaDataInBuffersParams *)paramData; + if (!metabuffer) { + DEBUG_PRINT_ERROR("Invalid param: %p", metabuffer); + eRet = OMX_ErrorBadParameter; + break; + } + if (m_disable_dynamic_buf_mode) { + DEBUG_PRINT_HIGH("Dynamic buffer mode is disabled"); + eRet = OMX_ErrorUnsupportedSetting; + break; + } + if (metabuffer->nPortIndex == OMX_CORE_OUTPUT_PORT_INDEX) { + + if (m_out_mem_ptr) { + DEBUG_PRINT_ERROR("Enable/Disable dynamic-buffer-mode is not allowed since Output port is not free !"); + eRet = OMX_ErrorInvalidState; + break; + } + //set property dynamic buffer mode to driver. + struct v4l2_control control; + struct v4l2_format fmt; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT; + if (metabuffer->bStoreMetaData == true) { + control.value = V4L2_MPEG_VIDC_VIDEO_DYNAMIC; + } else { + control.value = V4L2_MPEG_VIDC_VIDEO_STATIC; + } + int rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL,&control); + if (!rc) { + DEBUG_PRINT_HIGH("%s buffer mode", + (metabuffer->bStoreMetaData == true)? "Enabled dynamic" : "Disabled dynamic"); + dynamic_buf_mode = metabuffer->bStoreMetaData; + } else { + DEBUG_PRINT_ERROR("Failed to %s buffer mode", + (metabuffer->bStoreMetaData == true)? "enable dynamic" : "disable dynamic"); + eRet = OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_ERROR( + "OMX_QcomIndexParamVideoMetaBufferMode not supported for port: %u", + (unsigned int)metabuffer->nPortIndex); + eRet = OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QcomIndexParamVideoDownScalar: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_INDEXDOWNSCALAR); + QOMX_INDEXDOWNSCALAR* pParam = (QOMX_INDEXDOWNSCALAR*)paramData; + struct v4l2_control control; + int rc; + DEBUG_PRINT_LOW("set_parameter: OMX_QcomIndexParamVideoDownScalar %d\n", pParam->bEnable); + + if (pParam && pParam->bEnable) { + rc = enable_downscalar(); + if (rc < 0) { + DEBUG_PRINT_ERROR("%s: enable_downscalar failed\n", __func__); + return OMX_ErrorUnsupportedSetting; + } + m_force_down_scalar = pParam->bEnable; + } else { + rc = disable_downscalar(); + if (rc < 0) { + DEBUG_PRINT_ERROR("%s: disable_downscalar failed\n", __func__); + return OMX_ErrorUnsupportedSetting; + } + m_force_down_scalar = pParam->bEnable; + } + break; + } +#ifdef ADAPTIVE_PLAYBACK_SUPPORTED + case OMX_QcomIndexParamVideoAdaptivePlaybackMode: + { + VALIDATE_OMX_PARAM_DATA(paramData, PrepareForAdaptivePlaybackParams); + DEBUG_PRINT_LOW("set_parameter: OMX_GoogleAndroidIndexPrepareForAdaptivePlayback"); + PrepareForAdaptivePlaybackParams* pParams = + (PrepareForAdaptivePlaybackParams *) paramData; + if (pParams->nPortIndex == OMX_CORE_OUTPUT_PORT_INDEX) { + if (!pParams->bEnable) { + return OMX_ErrorNone; + } + if (pParams->nMaxFrameWidth > maxSmoothStreamingWidth + || pParams->nMaxFrameHeight > maxSmoothStreamingHeight) { + DEBUG_PRINT_ERROR( + "Adaptive playback request exceeds max supported resolution : [%u x %u] vs [%u x %u]", + (unsigned int)pParams->nMaxFrameWidth, (unsigned int)pParams->nMaxFrameHeight, + (unsigned int)maxSmoothStreamingWidth, (unsigned int)maxSmoothStreamingHeight); + eRet = OMX_ErrorBadParameter; + } else { + eRet = enable_adaptive_playback(pParams->nMaxFrameWidth, pParams->nMaxFrameHeight); + } + } else { + DEBUG_PRINT_ERROR( + "Prepare for adaptive playback supported only on output port"); + eRet = OMX_ErrorBadParameter; + } + break; + } + + case OMX_QTIIndexParamVideoPreferAdaptivePlayback: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_ENABLETYPE); + DEBUG_PRINT_LOW("set_parameter: OMX_QTIIndexParamVideoPreferAdaptivePlayback"); + m_disable_dynamic_buf_mode = ((QOMX_ENABLETYPE *)paramData)->bEnable; + if (m_disable_dynamic_buf_mode) { + DEBUG_PRINT_HIGH("Prefer Adaptive Playback is set"); + } + break; + } +#endif + case OMX_QcomIndexParamVideoCustomBufferSize: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_VIDEO_CUSTOM_BUFFERSIZE); + DEBUG_PRINT_LOW("set_parameter: OMX_QcomIndexParamVideoCustomBufferSize"); + QOMX_VIDEO_CUSTOM_BUFFERSIZE* pParam = (QOMX_VIDEO_CUSTOM_BUFFERSIZE*)paramData; + if (pParam->nPortIndex == OMX_CORE_INPUT_PORT_INDEX) { + struct v4l2_control control; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT; + control.value = pParam->nBufferSize; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set input buffer size"); + eRet = OMX_ErrorUnsupportedSetting; + } else { + eRet = get_buffer_req(&drv_ctx.ip_buf); + if (eRet == OMX_ErrorNone) { + m_custom_buffersize.input_buffersize = drv_ctx.ip_buf.buffer_size; + DEBUG_PRINT_HIGH("Successfully set custom input buffer size = %d", + m_custom_buffersize.input_buffersize); + } else { + DEBUG_PRINT_ERROR("Failed to get buffer requirement"); + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: Custom buffer size in not supported on output port"); + eRet = OMX_ErrorBadParameter; + } + break; + } + case OMX_QTIIndexParamVQZIPSEIType: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QTI_VIDEO_PARAM_VQZIP_SEI_TYPE); + DEBUG_PRINT_LOW("set_parameter: OMX_QTIIndexParamVQZIPSEIType"); + OMX_QTI_VIDEO_PARAM_VQZIP_SEI_TYPE *pParam = + (OMX_QTI_VIDEO_PARAM_VQZIP_SEI_TYPE *)paramData; + DEBUG_PRINT_LOW("Enable VQZIP SEI: %d", pParam->bEnable); + eRet = enable_extradata(OMX_VQZIPSEI_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("ERROR: Failed to set SEI Extradata"); + eRet = OMX_ErrorBadParameter; + client_extradata = client_extradata & ~OMX_VQZIPSEI_EXTRADATA; + } else { + eRet = enable_extradata(OMX_QP_EXTRADATA, false, + ((QOMX_ENABLETYPE *)paramData)->bEnable); + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("ERROR: Failed to set QP Extradata"); + eRet = OMX_ErrorBadParameter; + client_extradata = client_extradata & ~OMX_VQZIPSEI_EXTRADATA; + client_extradata = client_extradata & ~OMX_QP_EXTRADATA; + } + } + break; + } + + case OMX_QTIIndexParamPassInputBufferFd: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_ENABLETYPE); + if (arbitrary_bytes) { + DEBUG_PRINT_ERROR("OMX_QTIIndexParamPassInputBufferFd not supported in arbitrary buffer mode"); + eRet = OMX_ErrorUnsupportedSetting; + break; + } + + m_input_pass_buffer_fd = ((QOMX_ENABLETYPE *)paramData)->bEnable; + if (m_input_pass_buffer_fd) + DEBUG_PRINT_LOW("Enable passing input buffer FD"); + break; + } + case OMX_QTIIndexParamForceCompressedForDPB: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QTI_VIDEO_PARAM_FORCE_COMPRESSED_FOR_DPB_TYPE); + DEBUG_PRINT_LOW("set_parameter: OMX_QTIIndexParamForceCompressedForDPB"); + OMX_QTI_VIDEO_PARAM_FORCE_COMPRESSED_FOR_DPB_TYPE *pParam = + (OMX_QTI_VIDEO_PARAM_FORCE_COMPRESSED_FOR_DPB_TYPE *)paramData; + if (m_disable_ubwc_mode) { + DEBUG_PRINT_ERROR("OMX_QTIIndexParamForceCompressedForDPB not supported when ubwc disabled"); + eRet = OMX_ErrorUnsupportedSetting; + break; + } + if (!paramData) { + DEBUG_PRINT_ERROR("set_parameter: OMX_QTIIndexParamForceCompressedForDPB paramData NULL"); + eRet = OMX_ErrorBadParameter; + break; + } + + m_force_compressed_for_dpb = pParam->bEnable; + break; + } + case OMX_QTIIndexParamForceUnCompressedForOPB: + { + DEBUG_PRINT_LOW("set_parameter: OMX_QTIIndexParamForceUnCompressedForOPB"); + OMX_QTI_VIDEO_PARAM_FORCE_UNCOMPRESSED_FOR_OPB_TYPE *pParam = + (OMX_QTI_VIDEO_PARAM_FORCE_UNCOMPRESSED_FOR_OPB_TYPE *)paramData; + if (!paramData) { + DEBUG_PRINT_ERROR("set_parameter: OMX_QTIIndexParamForceUnCompressedForOPB paramData is NULL"); + eRet = OMX_ErrorBadParameter; + break; + } + m_disable_ubwc_mode = pParam->bEnable; + DEBUG_PRINT_LOW("set_parameter: UBWC %s for OPB", pParam->bEnable ? "disabled" : "enabled"); + break; + } + case OMX_QTIIndexParamVideoClientExtradata: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_VIDEO_CLIENT_EXTRADATATYPE); + DEBUG_PRINT_LOW("set_parameter: OMX_QTIIndexParamVideoClientExtradata"); + QOMX_VIDEO_CLIENT_EXTRADATATYPE *pParam = + (QOMX_VIDEO_CLIENT_EXTRADATATYPE *)paramData; + OMX_U32 extradata_size = VENUS_EXTRADATA_SIZE(4096, 2160); + if (pParam->nExtradataSize < extradata_size || + pParam->nExtradataAllocSize < (extradata_size * MAX_NUM_INPUT_OUTPUT_BUFFERS) || + pParam->nExtradataAllocSize < (pParam->nExtradataSize * MAX_NUM_INPUT_OUTPUT_BUFFERS)) { + DEBUG_PRINT_ERROR("set_parameter: Incorrect buffer size for client extradata"); + eRet = OMX_ErrorBadParameter; + break; + } + if (!m_client_extradata_info.set_extradata_info(dup(pParam->nFd), + pParam->nExtradataAllocSize, pParam->nExtradataSize)) { + DEBUG_PRINT_ERROR("set_parameter: Setting client extradata failed."); + eRet = OMX_ErrorBadParameter; + break; + } + break; + } + + default: { + DEBUG_PRINT_ERROR("Setparameter: unknown param %d", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + } + } + if (eRet != OMX_ErrorNone) + DEBUG_PRINT_ERROR("set_parameter: Error: 0x%x, setting param 0x%x", eRet, paramIndex); + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::GetConfig + + DESCRIPTION + OMX Get Config Method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_INOUT OMX_PTR configData) +{ + (void) hComp; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Get Config in Invalid State"); + return OMX_ErrorInvalidState; + } + + switch ((unsigned long)configIndex) { + case OMX_QcomIndexConfigInterlaced: { + VALIDATE_OMX_PARAM_DATA(configData, OMX_QCOM_CONFIG_INTERLACETYPE); + OMX_QCOM_CONFIG_INTERLACETYPE *configFmt = + (OMX_QCOM_CONFIG_INTERLACETYPE *) configData; + if (configFmt->nPortIndex == 1) { + if (configFmt->nIndex == 0) { + configFmt->eInterlaceType = OMX_QCOM_InterlaceFrameProgressive; + } else if (configFmt->nIndex == 1) { + configFmt->eInterlaceType = + OMX_QCOM_InterlaceInterleaveFrameTopFieldFirst; + } else if (configFmt->nIndex == 2) { + configFmt->eInterlaceType = + OMX_QCOM_InterlaceInterleaveFrameBottomFieldFirst; + } else { + DEBUG_PRINT_ERROR("get_config: OMX_QcomIndexConfigInterlaced:" + " NoMore Interlaced formats"); + eRet = OMX_ErrorNoMore; + } + + } else { + DEBUG_PRINT_ERROR("get_config: Bad port index %d queried on only o/p port", + (int)configFmt->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_QcomIndexQueryNumberOfVideoDecInstance: { + VALIDATE_OMX_PARAM_DATA(configData, QOMX_VIDEO_QUERY_DECODER_INSTANCES); + QOMX_VIDEO_QUERY_DECODER_INSTANCES *decoderinstances = + (QOMX_VIDEO_QUERY_DECODER_INSTANCES*)configData; + decoderinstances->nNumOfInstances = 16; + /*TODO: How to handle this case */ + break; + } + case OMX_QcomIndexConfigVideoFramePackingArrangement: { + if (drv_ctx.decoder_format == VDEC_CODECTYPE_H264) { + VALIDATE_OMX_PARAM_DATA(configData, OMX_QCOM_FRAME_PACK_ARRANGEMENT); + OMX_QCOM_FRAME_PACK_ARRANGEMENT *configFmt = + (OMX_QCOM_FRAME_PACK_ARRANGEMENT *) configData; + memcpy(configFmt, &m_frame_pack_arrangement, + sizeof(OMX_QCOM_FRAME_PACK_ARRANGEMENT)); + } else { + DEBUG_PRINT_ERROR("get_config: Framepack data not supported for non H264 codecs"); + } + break; + } + case OMX_IndexConfigCommonOutputCrop: { + VALIDATE_OMX_PARAM_DATA(configData, OMX_CONFIG_RECTTYPE); + OMX_CONFIG_RECTTYPE *rect = (OMX_CONFIG_RECTTYPE *) configData; + memcpy(rect, &rectangle, sizeof(OMX_CONFIG_RECTTYPE)); + DEBUG_PRINT_HIGH("get_config: crop info: L: %u, T: %u, R: %u, B: %u", + rectangle.nLeft, rectangle.nTop, + rectangle.nWidth, rectangle.nHeight); + break; + } + case OMX_QcomIndexConfigPerfLevel: { + VALIDATE_OMX_PARAM_DATA(configData, OMX_QCOM_VIDEO_CONFIG_PERF_LEVEL); + struct v4l2_control control; + OMX_QCOM_VIDEO_CONFIG_PERF_LEVEL *perf = + (OMX_QCOM_VIDEO_CONFIG_PERF_LEVEL *)configData; + + control.id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_G_CTRL, &control) < 0) { + DEBUG_PRINT_ERROR("Failed getting performance level: %d", errno); + eRet = OMX_ErrorHardware; + } + + if (eRet == OMX_ErrorNone) { + switch (control.value) { + case V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO: + perf->ePerfLevel = OMX_QCOM_PerfLevelTurbo; + break; + default: + DEBUG_PRINT_HIGH("Unknown perf level %d, reporting Nominal instead", control.value); + /* Fall through */ + case V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL: + perf->ePerfLevel = OMX_QCOM_PerfLevelNominal; + break; + } + } + + break; + } + case OMX_QcomIndexConfigH264EntropyCodingCabac: { + VALIDATE_OMX_PARAM_DATA(configData, QOMX_VIDEO_H264ENTROPYCODINGTYPE); + QOMX_VIDEO_H264ENTROPYCODINGTYPE *coding = (QOMX_VIDEO_H264ENTROPYCODINGTYPE *)configData; + struct v4l2_control control; + + if (drv_ctx.decoder_format != VDEC_CODECTYPE_H264) { + DEBUG_PRINT_ERROR("get_config of OMX_QcomIndexConfigH264EntropyCodingCabac only available for H264"); + eRet = OMX_ErrorNotImplemented; + break; + } + + control.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE; + if (!ioctl(drv_ctx.video_driver_fd, VIDIOC_G_CTRL, &control)) { + coding->bCabac = (OMX_BOOL) + (control.value == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC); + /* We can't query driver at the moment for the cabac mode, so + * just use 0xff...f as a place holder for future improvement */ + coding->nCabacInitIdc = ~0; + } else { + eRet = OMX_ErrorUnsupportedIndex; + } + + break; + } + case OMX_QTIIndexConfigDescribeColorAspects: + { + VALIDATE_OMX_PARAM_DATA(configData, DescribeColorAspectsParams); + DescribeColorAspectsParams *params = (DescribeColorAspectsParams *)configData; + + print_debug_color_aspects(&(m_client_color_space.sAspects), "GetConfig Client"); + print_debug_color_aspects(&(m_internal_color_space.sAspects), "GetConfig Internal"); + + if (params->bRequestingDataSpace) { + DEBUG_PRINT_ERROR("Does not handle dataspace request"); + return OMX_ErrorUnsupportedSetting; + } + if (m_internal_color_space.bDataSpaceChanged == OMX_TRUE) { + DEBUG_PRINT_LOW("Updating Client's color aspects with internal"); + memcpy(&(m_client_color_space.sAspects), + &(m_internal_color_space.sAspects), sizeof(ColorAspects)); + m_internal_color_space.bDataSpaceChanged = OMX_FALSE; + } + memcpy(&(params->sAspects), &(m_client_color_space.sAspects), sizeof(ColorAspects)); + + break; + } + case OMX_QTIIndexConfigDescribeHDRColorInfo: + { + VALIDATE_OMX_PARAM_DATA(configData, DescribeHDRStaticInfoParams); + DescribeHDRStaticInfoParams *params = (DescribeHDRStaticInfoParams *)configData; + auto_lock lock(m_hdr_info_client_lock); + + print_debug_hdr_color_info(&(m_client_hdr_info.sInfo), "GetConfig Client HDR"); + print_debug_hdr_color_info(&(m_internal_hdr_info.sInfo), "GetConfig Internal HDR"); + + if (m_change_client_hdr_info) { + DEBUG_PRINT_LOW("Updating Client's HDR Info with internal"); + memcpy(&m_client_hdr_info.sInfo, + &m_internal_hdr_info.sInfo, sizeof(HDRStaticInfo)); + m_change_client_hdr_info = false; + } + + memcpy(&(params->sInfo), &(m_client_hdr_info.sInfo), sizeof(HDRStaticInfo)); + + break; + } + default: + { + DEBUG_PRINT_ERROR("get_config: unknown param %d",configIndex); + eRet = OMX_ErrorBadParameter; + } + + } + + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::SetConfig + + DESCRIPTION + OMX Set Config method implementation + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if successful. + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::set_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_IN OMX_PTR configData) +{ + (void) hComp; + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Get Config in Invalid State"); + return OMX_ErrorInvalidState; + } + + OMX_ERRORTYPE ret = OMX_ErrorNone; + OMX_VIDEO_CONFIG_NALSIZE *pNal; + + DEBUG_PRINT_LOW("Set Config Called"); + + if (configIndex == OMX_IndexConfigVideoNalSize) { + struct v4l2_control temp; + temp.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT; + + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_NALSIZE); + pNal = reinterpret_cast < OMX_VIDEO_CONFIG_NALSIZE * >(configData); + switch (pNal->nNaluBytes) { + case 0: + temp.value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES; + break; + case 2: + temp.value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH; + break; + case 4: + temp.value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH; + break; + default: + return OMX_ErrorUnsupportedSetting; + } + + if (!arbitrary_bytes) { + /* In arbitrary bytes mode, the assembler strips out nal size and replaces + * with start code, so only need to notify driver in frame by frame mode */ + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &temp)) { + DEBUG_PRINT_ERROR("Failed to set V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT"); + return OMX_ErrorHardware; + } + } + + nal_length = pNal->nNaluBytes; + m_frame_parser.init_nal_length(nal_length); + + DEBUG_PRINT_LOW("OMX_IndexConfigVideoNalSize called with Size %d", nal_length); + return ret; + } else if ((int)configIndex == (int)OMX_IndexVendorVideoFrameRate) { + OMX_VENDOR_VIDEOFRAMERATE *config = (OMX_VENDOR_VIDEOFRAMERATE *) configData; + DEBUG_PRINT_HIGH("Index OMX_IndexVendorVideoFrameRate %u", (unsigned int)config->nFps); + + if (config->nPortIndex == OMX_CORE_INPUT_PORT_INDEX) { + if (config->bEnabled) { + if ((config->nFps >> 16) > 0 && + (config->nFps >> 16) <= MAX_SUPPORTED_FPS) { + m_fps_received = config->nFps; + DEBUG_PRINT_HIGH("set_config: frame rate set by omx client : %u", + (unsigned int)config->nFps >> 16); + Q16ToFraction(config->nFps, drv_ctx.frame_rate.fps_numerator, + drv_ctx.frame_rate.fps_denominator); + + if (!drv_ctx.frame_rate.fps_numerator) { + DEBUG_PRINT_ERROR("Numerator is zero setting to 30"); + drv_ctx.frame_rate.fps_numerator = 30; + } + + if (drv_ctx.frame_rate.fps_denominator) { + drv_ctx.frame_rate.fps_numerator = (int) + drv_ctx.frame_rate.fps_numerator / drv_ctx.frame_rate.fps_denominator; + } + + drv_ctx.frame_rate.fps_denominator = 1; + frm_int = drv_ctx.frame_rate.fps_denominator * 1e6 / + drv_ctx.frame_rate.fps_numerator; + + struct v4l2_outputparm oparm; + /*XXX: we're providing timing info as seconds per frame rather than frames + * per second.*/ + oparm.timeperframe.numerator = drv_ctx.frame_rate.fps_denominator; + oparm.timeperframe.denominator = drv_ctx.frame_rate.fps_numerator; + + struct v4l2_streamparm sparm; + sparm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + sparm.parm.output = oparm; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_PARM, &sparm)) { + DEBUG_PRINT_ERROR("Unable to convey fps info to driver, \ + performance might be affected"); + ret = OMX_ErrorHardware; + } + client_set_fps = true; + } else { + DEBUG_PRINT_ERROR("Frame rate not supported."); + ret = OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_HIGH("set_config: Disabled client's frame rate"); + client_set_fps = false; + } + } else { + DEBUG_PRINT_ERROR(" Set_config: Bad Port idx %d", + (int)config->nPortIndex); + ret = OMX_ErrorBadPortIndex; + } + + return ret; + } else if ((int)configIndex == (int)OMX_QcomIndexConfigPerfLevel) { + OMX_QCOM_VIDEO_CONFIG_PERF_LEVEL *perf = + (OMX_QCOM_VIDEO_CONFIG_PERF_LEVEL *)configData; + struct v4l2_control control; + + DEBUG_PRINT_LOW("Set perf level: %d", perf->ePerfLevel); + + control.id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL; + + switch (perf->ePerfLevel) { + case OMX_QCOM_PerfLevelNominal: + control.value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL; + break; + case OMX_QCOM_PerfLevelTurbo: + control.value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO; + break; + default: + ret = OMX_ErrorUnsupportedSetting; + break; + } + + if (ret == OMX_ErrorNone) { + ret = (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control) < 0) ? + OMX_ErrorUnsupportedSetting : OMX_ErrorNone; + } + + return ret; + } else if ((int)configIndex == (int)OMX_QcomIndexConfigPictureTypeDecode) { + OMX_QCOM_VIDEO_CONFIG_PICTURE_TYPE_DECODE *config = + (OMX_QCOM_VIDEO_CONFIG_PICTURE_TYPE_DECODE *)configData; + struct v4l2_control control; + DEBUG_PRINT_LOW("Set picture type decode: %d", config->eDecodeType); + control.id = V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE; + + switch (config->eDecodeType) { + case OMX_QCOM_PictypeDecode_I: + control.value = V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_ON; + break; + case OMX_QCOM_PictypeDecode_IPB: + default: + control.value = V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_OFF; + break; + } + + ret = (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control) < 0) ? + OMX_ErrorUnsupportedSetting : OMX_ErrorNone; + if (ret) + DEBUG_PRINT_ERROR("Failed to set picture type decode"); + + return ret; + } else if ((int)configIndex == (int)OMX_IndexConfigPriority) { + OMX_PARAM_U32TYPE *priority = (OMX_PARAM_U32TYPE *)configData; + DEBUG_PRINT_LOW("Set_config: priority %d",priority->nU32); + + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY; + if (priority->nU32 == 0) + control.value = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_ENABLE; + else + control.value = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE; + + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set Priority"); + ret = OMX_ErrorUnsupportedSetting; + } + return ret; + } else if ((int)configIndex == (int)OMX_IndexConfigOperatingRate) { + OMX_PARAM_U32TYPE *rate = (OMX_PARAM_U32TYPE *)configData; + DEBUG_PRINT_LOW("Set_config: operating-rate %u fps", rate->nU32 >> 16); + + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE; + control.value = rate->nU32; + + operating_frame_rate = rate->nU32 >> 16; + + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + ret = errno == -EBUSY ? OMX_ErrorInsufficientResources : + OMX_ErrorUnsupportedSetting; + DEBUG_PRINT_ERROR("Failed to set operating rate %u fps (%s)", + rate->nU32 >> 16, errno == -EBUSY ? "HW Overload" : strerror(errno)); + } + return ret; + + } else if ((int)configIndex == (int)OMX_QTIIndexConfigDescribeColorAspects) { + VALIDATE_OMX_PARAM_DATA(configData, DescribeColorAspectsParams); + DescribeColorAspectsParams *params = (DescribeColorAspectsParams *)configData; + if (!DEFAULT_EXTRADATA & OMX_DISPLAY_INFO_EXTRADATA) { + enable_extradata(OMX_DISPLAY_INFO_EXTRADATA, true, true); + } + + print_debug_color_aspects(&(params->sAspects), "Set Config"); + memcpy(&m_client_color_space, params, sizeof(DescribeColorAspectsParams)); + return ret; + } else if ((int)configIndex == (int)OMX_QTIIndexConfigDescribeHDRColorInfo) { + VALIDATE_OMX_PARAM_DATA(configData, DescribeHDRStaticInfoParams); + DescribeHDRStaticInfoParams *params = (DescribeHDRStaticInfoParams *)configData; + if (!DEFAULT_EXTRADATA & OMX_HDR_COLOR_INFO_EXTRADATA) { + ret = enable_extradata(OMX_HDR_COLOR_INFO_EXTRADATA, true, true); + if (ret != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("Failed to enable OMX_HDR_COLOR_INFO_EXTRADATA"); + return ret; + } + } + + print_debug_hdr_color_info(&(params->sInfo), "Set Config HDR"); + memcpy(&m_client_hdr_info, params, sizeof(DescribeHDRStaticInfoParams)); + return ret; + } + + return OMX_ErrorNotImplemented; +} + +#define extn_equals(param, extn) (!strcmp(param, extn)) + +/* ====================================================================== + FUNCTION + omx_vdec::GetExtensionIndex + + DESCRIPTION + OMX GetExtensionIndex method implementaion. <TBD> + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_extension_index(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_STRING paramName, + OMX_OUT OMX_INDEXTYPE* indexType) +{ + (void) hComp; + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Get Extension Index in Invalid State"); + return OMX_ErrorInvalidState; + } else if (extn_equals(paramName, "OMX.QCOM.index.param.video.SyncFrameDecodingMode")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoSyncFrameDecodingMode; + } else if (extn_equals(paramName, "OMX.QCOM.index.param.IndexExtraData")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamIndexExtraDataType; + } else if (extn_equals(paramName, OMX_QCOM_INDEX_PARAM_VIDEO_FRAMEPACKING_EXTRADATA)) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoFramePackingExtradata; + } else if (extn_equals(paramName, OMX_QCOM_INDEX_CONFIG_VIDEO_FRAMEPACKING_INFO)) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexConfigVideoFramePackingArrangement; + } else if (extn_equals(paramName, OMX_QCOM_INDEX_PARAM_VIDEO_QP_EXTRADATA)) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoQPExtraData; + } else if (extn_equals(paramName, OMX_QCOM_INDEX_PARAM_VIDEO_INPUTBITSINFO_EXTRADATA)) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoInputBitsInfoExtraData; + } else if (extn_equals(paramName, OMX_QCOM_INDEX_PARAM_VIDEO_EXTNUSER_EXTRADATA)) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexEnableExtnUserData; + } +#if defined (_ANDROID_HONEYCOMB_) || defined (_ANDROID_ICS_) + else if (extn_equals(paramName, "OMX.google.android.index.enableAndroidNativeBuffers")) { + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexEnableAndroidNativeBuffers; + } else if (extn_equals(paramName, "OMX.google.android.index.useAndroidNativeBuffer2")) { + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexUseAndroidNativeBuffer2; + } else if (extn_equals(paramName, "OMX.google.android.index.useAndroidNativeBuffer")) { + DEBUG_PRINT_ERROR("Extension: %s is supported", paramName); + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexUseAndroidNativeBuffer; + } else if (extn_equals(paramName, "OMX.google.android.index.getAndroidNativeBufferUsage")) { + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage; + } +#if ALLOCATE_OUTPUT_NATIVEHANDLE + else if (extn_equals(paramName, "OMX.google.android.index.allocateNativeHandle")) { + *indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexAllocateNativeHandle; + } +#endif //ALLOCATE_OUTPUT_NATIVEHANDLE +#endif + else if (extn_equals(paramName, "OMX.google.android.index.storeMetaDataInBuffers")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoMetaBufferMode; + } +#ifdef ADAPTIVE_PLAYBACK_SUPPORTED + else if (extn_equals(paramName, "OMX.google.android.index.prepareForAdaptivePlayback")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoAdaptivePlaybackMode; + } else if (extn_equals(paramName, OMX_QTI_INDEX_PARAM_VIDEO_PREFER_ADAPTIVE_PLAYBACK)) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexParamVideoPreferAdaptivePlayback; + } +#endif +#ifdef FLEXYUV_SUPPORTED + else if (extn_equals(paramName,"OMX.google.android.index.describeColorFormat")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexFlexibleYUVDescription; + } +#endif + else if (extn_equals(paramName, "OMX.QCOM.index.param.video.PassInputBufferFd")) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexParamPassInputBufferFd; + } else if (extn_equals(paramName, "OMX.QTI.index.param.video.ForceCompressedForDPB")) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexParamForceCompressedForDPB; + } else if (extn_equals(paramName, "OMX.QTI.index.param.video.ForceUnCompressedForOPB")) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexParamForceUnCompressedForOPB; + } else if (extn_equals(paramName, "OMX.QTI.index.param.video.LowLatency")) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexParamLowLatencyMode; + } else if (extn_equals(paramName, OMX_QTI_INDEX_PARAM_VIDEO_CLIENT_EXTRADATA)) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexParamVideoClientExtradata; + } else if (extn_equals(paramName, "OMX.google.android.index.describeColorAspects")) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexConfigDescribeColorAspects; + } else if (extn_equals(paramName, "OMX.google.android.index.describeHDRStaticInfo")) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexConfigDescribeHDRColorInfo; + } else { + DEBUG_PRINT_ERROR("Extension: %s not implemented", paramName); + return OMX_ErrorNotImplemented; + } + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::GetState + + DESCRIPTION + Returns the state information back to the caller.<TBD> + + PARAMETERS + <TBD>. + + RETURN VALUE + Error None if everything is successful. + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::get_state(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STATETYPE* state) +{ + (void) hComp; + *state = m_state; + DEBUG_PRINT_LOW("get_state: Returning the state %d",*state); + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::ComponentTunnelRequest + + DESCRIPTION + OMX Component Tunnel Request method implementation. <TBD> + + PARAMETERS + None. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::component_tunnel_request(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_HANDLETYPE peerComponent, + OMX_IN OMX_U32 peerPort, + OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup) +{ + (void) hComp; + (void) port; + (void) peerComponent; + (void) peerPort; + (void) tunnelSetup; + DEBUG_PRINT_ERROR("Error: component_tunnel_request Not Implemented"); + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== + FUNCTION + omx_vdec::UseOutputBuffer + + DESCRIPTION + Helper function for Use buffer in the input pin + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::allocate_extradata() +{ +#ifdef USE_ION + if (drv_ctx.extradata_info.buffer_size) { + if (drv_ctx.extradata_info.ion.ion_alloc_data.handle) { + munmap((void *)drv_ctx.extradata_info.uaddr, drv_ctx.extradata_info.size); + close(drv_ctx.extradata_info.ion.fd_ion_data.fd); + free_ion_memory(&drv_ctx.extradata_info.ion); + } + drv_ctx.extradata_info.size = (drv_ctx.extradata_info.size + 4095) & (~4095); + drv_ctx.extradata_info.ion.ion_device_fd = alloc_map_ion_memory( + drv_ctx.extradata_info.size, 4096, + &drv_ctx.extradata_info.ion.ion_alloc_data, + &drv_ctx.extradata_info.ion.fd_ion_data, 0); + if (drv_ctx.extradata_info.ion.ion_device_fd < 0) { + DEBUG_PRINT_ERROR("Failed to alloc extradata memory"); + return OMX_ErrorInsufficientResources; + } + drv_ctx.extradata_info.uaddr = (char *)mmap(NULL, + drv_ctx.extradata_info.size, + PROT_READ|PROT_WRITE, MAP_SHARED, + drv_ctx.extradata_info.ion.fd_ion_data.fd , 0); + if (drv_ctx.extradata_info.uaddr == MAP_FAILED) { + DEBUG_PRINT_ERROR("Failed to map extradata memory"); + close(drv_ctx.extradata_info.ion.fd_ion_data.fd); + free_ion_memory(&drv_ctx.extradata_info.ion); + return OMX_ErrorInsufficientResources; + } + } +#endif + if (!m_other_extradata) { + m_other_extradata = (OMX_OTHER_EXTRADATATYPE *)malloc(drv_ctx.extradata_info.buffer_size); + if (!m_other_extradata) { + DEBUG_PRINT_ERROR("Failed to alloc memory\n"); + return OMX_ErrorInsufficientResources; + } + } + return OMX_ErrorNone; +} + +void omx_vdec::free_extradata() +{ +#ifdef USE_ION + if (drv_ctx.extradata_info.uaddr) { + munmap((void *)drv_ctx.extradata_info.uaddr, drv_ctx.extradata_info.size); + close(drv_ctx.extradata_info.ion.fd_ion_data.fd); + free_ion_memory(&drv_ctx.extradata_info.ion); + } +#endif + if (m_other_extradata) { + free(m_other_extradata); + m_other_extradata = NULL; + } +} + +OMX_ERRORTYPE omx_vdec::use_output_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr= NULL; // buffer header + unsigned i= 0; // Temporary counter + struct vdec_setbuffer_cmd setbuffers; + OMX_PTR privateAppData = NULL; + private_handle_t *handle = NULL; + OMX_U8 *buff = buffer; + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + int extra_idx = 0; + (void) hComp; + (void) port; + + if (!m_out_mem_ptr) { + DEBUG_PRINT_HIGH("Use_op_buf:Allocating output headers"); + eRet = allocate_output_headers(); + if (eRet == OMX_ErrorNone) + eRet = allocate_extradata(); + } + + if (eRet == OMX_ErrorNone) { + for (i=0; i< drv_ctx.op_buf.actualcount; i++) { + if (BITMASK_ABSENT(&m_out_bm_count,i)) { + break; + } + } + } + + if (i >= drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("Already using %d o/p buffers", drv_ctx.op_buf.actualcount); + eRet = OMX_ErrorInsufficientResources; + } + + if (eRet != OMX_ErrorNone) + return eRet; + + if (dynamic_buf_mode) { + *bufferHdr = (m_out_mem_ptr + i ); + (*bufferHdr)->pBuffer = NULL; + if (i == (drv_ctx.op_buf.actualcount - 1) && !streaming[CAPTURE_PORT]) { + enum v4l2_buf_type buf_type; + int rr = 0; + buf_type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (rr = ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON, &buf_type)) { + DEBUG_PRINT_ERROR("STREAMON FAILED : %d", rr); + return OMX_ErrorInsufficientResources; + } else { + streaming[CAPTURE_PORT] = true; + DEBUG_PRINT_LOW("STREAMON Successful"); + } + + DEBUG_PRINT_HIGH("Enabling Turbo mode"); + request_perf_level(VIDC_TURBO); + } + BITMASK_SET(&m_out_bm_count,i); + (*bufferHdr)->pAppPrivate = appData; + (*bufferHdr)->pBuffer = buffer; + (*bufferHdr)->nAllocLen = sizeof(struct VideoDecoderOutputMetaData); + return eRet; + } + + if (eRet == OMX_ErrorNone) { +#if defined(_ANDROID_HONEYCOMB_) || defined(_ANDROID_ICS_) + if (m_enable_android_native_buffers) { + if (m_use_android_native_buffers) { + UseAndroidNativeBufferParams *params = (UseAndroidNativeBufferParams *)appData; + sp<android_native_buffer_t> nBuf = params->nativeBuffer; + handle = (private_handle_t *)nBuf->handle; + privateAppData = params->pAppPrivate; + } else { + handle = (private_handle_t *)buff; + privateAppData = appData; + } + if (!handle) { + DEBUG_PRINT_ERROR("handle is invalid"); + return OMX_ErrorBadParameter; + } + + if ((OMX_U32)handle->size < drv_ctx.op_buf.buffer_size) { + if (secure_mode && secure_scaling_to_non_secure_opb) { + DEBUG_PRINT_HIGH("Buffer size expected %u, got %u, but it's ok since we will never map it", + (unsigned int)drv_ctx.op_buf.buffer_size, (unsigned int)handle->size); + } else { + DEBUG_PRINT_ERROR("Insufficient sized buffer given for playback," + " expected %u, got %u", + (unsigned int)drv_ctx.op_buf.buffer_size, (unsigned int)handle->size); + return OMX_ErrorBadParameter; + } + } + + drv_ctx.op_buf.buffer_size = handle->size; + + if (!m_use_android_native_buffers) { + if (!secure_mode) { + buff = (OMX_U8*)mmap(0, handle->size, + PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0); + if (buff == MAP_FAILED) { + DEBUG_PRINT_ERROR("Failed to mmap pmem with fd = %d, size = %d", handle->fd, handle->size); + return OMX_ErrorInsufficientResources; + } + } + } +#if defined(_ANDROID_ICS_) + native_buffer[i].nativehandle = handle; + native_buffer[i].privatehandle = handle; +#endif + if (!handle) { + DEBUG_PRINT_ERROR("Native Buffer handle is NULL"); + return OMX_ErrorBadParameter; + } + drv_ctx.ptr_outputbuffer[i].pmem_fd = handle->fd; + drv_ctx.ptr_outputbuffer[i].offset = 0; + drv_ctx.ptr_outputbuffer[i].bufferaddr = buff; + drv_ctx.ptr_outputbuffer[i].buffer_len = drv_ctx.op_buf.buffer_size; + drv_ctx.ptr_outputbuffer[i].mmaped_size = handle->size; + } else +#endif + + if (!ouput_egl_buffers && !m_use_output_pmem) { +#ifdef USE_ION + drv_ctx.op_buf_ion_info[i].ion_device_fd = alloc_map_ion_memory( + drv_ctx.op_buf.buffer_size,drv_ctx.op_buf.alignment, + &drv_ctx.op_buf_ion_info[i].ion_alloc_data, + &drv_ctx.op_buf_ion_info[i].fd_ion_data, + secure_mode ? SECURE_FLAGS_OUTPUT_BUFFER : 0); + if (drv_ctx.op_buf_ion_info[i].ion_device_fd < 0) { + DEBUG_PRINT_ERROR("ION device fd is bad %d", drv_ctx.op_buf_ion_info[i].ion_device_fd); + return OMX_ErrorInsufficientResources; + } + drv_ctx.ptr_outputbuffer[i].pmem_fd = \ + drv_ctx.op_buf_ion_info[i].fd_ion_data.fd; +#else + drv_ctx.ptr_outputbuffer[i].pmem_fd = \ + open (MEM_DEVICE,O_RDWR); + + if (drv_ctx.ptr_outputbuffer[i].pmem_fd < 0) { + DEBUG_PRINT_ERROR("ION/pmem buffer fd is bad %d", drv_ctx.ptr_outputbuffer[i].pmem_fd); + return OMX_ErrorInsufficientResources; + } + + /* FIXME: why is this code even here? We already open MEM_DEVICE a few lines above */ + if (drv_ctx.ptr_outputbuffer[i].pmem_fd == 0) { + drv_ctx.ptr_outputbuffer[i].pmem_fd = \ + open (MEM_DEVICE,O_RDWR); + if (drv_ctx.ptr_outputbuffer[i].pmem_fd < 0) { + DEBUG_PRINT_ERROR("ION/pmem buffer fd is bad %d", drv_ctx.ptr_outputbuffer[i].pmem_fd); + return OMX_ErrorInsufficientResources; + } + } + + if (!align_pmem_buffers(drv_ctx.ptr_outputbuffer[i].pmem_fd, + drv_ctx.op_buf.buffer_size, + drv_ctx.op_buf.alignment)) { + DEBUG_PRINT_ERROR("align_pmem_buffers() failed"); + close(drv_ctx.ptr_outputbuffer[i].pmem_fd); + return OMX_ErrorInsufficientResources; + } +#endif + if (!secure_mode) { + drv_ctx.ptr_outputbuffer[i].bufferaddr = + (unsigned char *)mmap(NULL, drv_ctx.op_buf.buffer_size, + PROT_READ|PROT_WRITE, MAP_SHARED, + drv_ctx.ptr_outputbuffer[i].pmem_fd,0); + if (drv_ctx.ptr_outputbuffer[i].bufferaddr == MAP_FAILED) { + close(drv_ctx.ptr_outputbuffer[i].pmem_fd); +#ifdef USE_ION + free_ion_memory(&drv_ctx.op_buf_ion_info[i]); +#endif + DEBUG_PRINT_ERROR("Unable to mmap output buffer"); + return OMX_ErrorInsufficientResources; + } + } + drv_ctx.ptr_outputbuffer[i].offset = 0; + privateAppData = appData; + } else { + + DEBUG_PRINT_LOW("Use_op_buf: out_pmem=%d",m_use_output_pmem); + if (!appData || !bytes ) { + if (!secure_mode && !buffer) { + DEBUG_PRINT_ERROR("Bad parameters for use buffer in EGL image case"); + return OMX_ErrorBadParameter; + } + } + + OMX_QCOM_PLATFORM_PRIVATE_LIST *pmem_list; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pmem_info; + pmem_list = (OMX_QCOM_PLATFORM_PRIVATE_LIST*) appData; + if (!pmem_list || !pmem_list->entryList || !pmem_list->entryList->entry || + !pmem_list->nEntries || + pmem_list->entryList->type != OMX_QCOM_PLATFORM_PRIVATE_PMEM) { + DEBUG_PRINT_ERROR("Pmem info not valid in use buffer"); + return OMX_ErrorBadParameter; + } + pmem_info = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) + pmem_list->entryList->entry; + DEBUG_PRINT_LOW("vdec: use buf: pmem_fd=0x%lx", + pmem_info->pmem_fd); + drv_ctx.ptr_outputbuffer[i].pmem_fd = pmem_info->pmem_fd; + drv_ctx.ptr_outputbuffer[i].offset = pmem_info->offset; + drv_ctx.ptr_outputbuffer[i].bufferaddr = buff; + drv_ctx.ptr_outputbuffer[i].mmaped_size = + drv_ctx.ptr_outputbuffer[i].buffer_len = drv_ctx.op_buf.buffer_size; + privateAppData = appData; + } + m_pmem_info[i].offset = drv_ctx.ptr_outputbuffer[i].offset; + m_pmem_info[i].pmem_fd = drv_ctx.ptr_outputbuffer[i].pmem_fd; + m_pmem_info[i].size = drv_ctx.ptr_outputbuffer[i].buffer_len; + m_pmem_info[i].mapped_size = drv_ctx.ptr_outputbuffer[i].mmaped_size; + m_pmem_info[i].buffer = drv_ctx.ptr_outputbuffer[i].bufferaddr; + + *bufferHdr = (m_out_mem_ptr + i ); + if (secure_mode) + drv_ctx.ptr_outputbuffer[i].bufferaddr = *bufferHdr; + //setbuffers.buffer_type = VDEC_BUFFER_TYPE_OUTPUT; + memcpy (&setbuffers.buffer,&drv_ctx.ptr_outputbuffer[i], + sizeof (vdec_bufferpayload)); + + DEBUG_PRINT_HIGH("Set the Output Buffer Idx: %d Addr: %p, pmem_fd=0x%x", i, + drv_ctx.ptr_outputbuffer[i].bufferaddr, + drv_ctx.ptr_outputbuffer[i].pmem_fd ); + + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].length = drv_ctx.op_buf.buffer_size; + plane[0].m.userptr = (unsigned long)drv_ctx.ptr_outputbuffer[i].bufferaddr - + (unsigned long)drv_ctx.ptr_outputbuffer[i].offset; + plane[0].reserved[0] = drv_ctx.ptr_outputbuffer[i].pmem_fd; + plane[0].reserved[1] = drv_ctx.ptr_outputbuffer[i].offset; + plane[0].data_offset = 0; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].length = drv_ctx.extradata_info.buffer_size; + plane[extra_idx].m.userptr = (long unsigned int) (drv_ctx.extradata_info.uaddr + i * drv_ctx.extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = drv_ctx.extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = i * drv_ctx.extradata_info.buffer_size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index is more than allowed: %d", extra_idx); + return OMX_ErrorBadParameter; + } + buf.m.planes = plane; + buf.length = drv_ctx.num_planes; + + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_PREPARE_BUF, &buf)) { + DEBUG_PRINT_ERROR("Failed to prepare bufs"); + /*TODO: How to handle this case */ + return OMX_ErrorInsufficientResources; + } + + if (i == (drv_ctx.op_buf.actualcount -1) && !streaming[CAPTURE_PORT]) { + enum v4l2_buf_type buf_type; + buf_type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type)) { + return OMX_ErrorInsufficientResources; + } else { + streaming[CAPTURE_PORT] = true; + DEBUG_PRINT_LOW("STREAMON Successful"); + } + + DEBUG_PRINT_HIGH("Enabling Turbo mode"); + request_perf_level(VIDC_TURBO); + } + + (*bufferHdr)->nAllocLen = drv_ctx.op_buf.buffer_size; + if (m_enable_android_native_buffers) { + DEBUG_PRINT_LOW("setting pBuffer to private_handle_t %p", handle); + (*bufferHdr)->pBuffer = (OMX_U8 *)handle; + } else { + (*bufferHdr)->pBuffer = buff; + } + (*bufferHdr)->pAppPrivate = privateAppData; + BITMASK_SET(&m_out_bm_count,i); + } + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::use_input_heap_buffers + + DESCRIPTION + OMX Use Buffer Heap allocation method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None , if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::use_input_heap_buffers( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + DEBUG_PRINT_LOW("Inside %s, %p", __FUNCTION__, buffer); + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if (secure_mode) { + DEBUG_PRINT_ERROR("use_input_heap_buffers is not allowed in secure mode"); + return OMX_ErrorUndefined; + } + + if (!m_inp_heap_ptr) + m_inp_heap_ptr = (OMX_BUFFERHEADERTYPE*) + calloc( (sizeof(OMX_BUFFERHEADERTYPE)), + drv_ctx.ip_buf.actualcount); + if (!m_phdr_pmem_ptr) + m_phdr_pmem_ptr = (OMX_BUFFERHEADERTYPE**) + calloc( (sizeof(OMX_BUFFERHEADERTYPE*)), + drv_ctx.ip_buf.actualcount); + if (!m_inp_heap_ptr || !m_phdr_pmem_ptr) { + DEBUG_PRINT_ERROR("Insufficent memory"); + eRet = OMX_ErrorInsufficientResources; + } else if (m_in_alloc_cnt < drv_ctx.ip_buf.actualcount) { + input_use_buffer = true; + memset(&m_inp_heap_ptr[m_in_alloc_cnt], 0, sizeof(OMX_BUFFERHEADERTYPE)); + m_inp_heap_ptr[m_in_alloc_cnt].pBuffer = buffer; + m_inp_heap_ptr[m_in_alloc_cnt].nAllocLen = bytes; + m_inp_heap_ptr[m_in_alloc_cnt].pAppPrivate = appData; + m_inp_heap_ptr[m_in_alloc_cnt].nInputPortIndex = (OMX_U32) OMX_DirInput; + m_inp_heap_ptr[m_in_alloc_cnt].nOutputPortIndex = (OMX_U32) OMX_DirMax; + *bufferHdr = &m_inp_heap_ptr[m_in_alloc_cnt]; + eRet = allocate_input_buffer(hComp, &m_phdr_pmem_ptr[m_in_alloc_cnt], port, appData, bytes); + DEBUG_PRINT_HIGH("Heap buffer(%p) Pmem buffer(%p)", *bufferHdr, m_phdr_pmem_ptr[m_in_alloc_cnt]); + if (!m_input_free_q.insert_entry((unsigned long)m_phdr_pmem_ptr[m_in_alloc_cnt], + (unsigned)NULL, (unsigned)NULL)) { + DEBUG_PRINT_ERROR("ERROR:Free_q is full"); + return OMX_ErrorInsufficientResources; + } + m_in_alloc_cnt++; + } else { + DEBUG_PRINT_ERROR("All i/p buffers have been set!"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::UseBuffer + + DESCRIPTION + OMX Use Buffer method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None , if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::use_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE error = OMX_ErrorNone; + struct vdec_setbuffer_cmd setbuffers; + + if (bufferHdr == NULL || bytes == 0 || (!secure_mode && buffer == NULL)) { + DEBUG_PRINT_ERROR("bad param 0x%p %u 0x%p",bufferHdr, (unsigned int)bytes, buffer); + return OMX_ErrorBadParameter; + } + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Use Buffer in Invalid State"); + return OMX_ErrorInvalidState; + } + if (port == OMX_CORE_INPUT_PORT_INDEX) { + // If this is not the first allocation (i.e m_inp_mem_ptr is allocated), + // ensure that use-buffer was called for previous allocation. + // Mix-and-match of useBuffer and allocateBuffer is not allowed + if (m_inp_mem_ptr && !input_use_buffer) { + DEBUG_PRINT_ERROR("'Use' Input buffer called after 'Allocate' Input buffer !"); + return OMX_ErrorUndefined; + } + error = use_input_heap_buffers(hComp, bufferHdr, port, appData, bytes, buffer); + } else if (port == OMX_CORE_OUTPUT_PORT_INDEX) + error = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer); //not tested + else { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d",(int)port); + error = OMX_ErrorBadPortIndex; + } + DEBUG_PRINT_LOW("Use Buffer: port %u, buffer %p, eRet %d", (unsigned int)port, *bufferHdr, error); + if (error == OMX_ErrorNone) { + if (allocate_done() && BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) { + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_IDLE_PENDING); + post_event(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + } + if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated && + BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } else if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated && + BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + return error; +} + +OMX_ERRORTYPE omx_vdec::free_input_buffer(unsigned int bufferindex, + OMX_BUFFERHEADERTYPE *pmem_bufferHdr) +{ + if (m_inp_heap_ptr && !input_use_buffer && arbitrary_bytes) { + if (m_inp_heap_ptr[bufferindex].pBuffer) + free(m_inp_heap_ptr[bufferindex].pBuffer); + m_inp_heap_ptr[bufferindex].pBuffer = NULL; + } + if (pmem_bufferHdr) + free_input_buffer(pmem_bufferHdr); + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::free_input_buffer(OMX_BUFFERHEADERTYPE *bufferHdr) +{ + unsigned int index = 0; + if (bufferHdr == NULL || m_inp_mem_ptr == NULL) { + return OMX_ErrorBadParameter; + } + + index = bufferHdr - m_inp_mem_ptr; + DEBUG_PRINT_LOW("Free Input Buffer index = %d",index); + + auto_lock l(buf_lock); + bufferHdr->pInputPortPrivate = NULL; + + if (index < drv_ctx.ip_buf.actualcount && drv_ctx.ptr_inputbuffer) { + DEBUG_PRINT_LOW("Free Input Buffer index = %d",index); + if (drv_ctx.ptr_inputbuffer[index].pmem_fd >= 0) { + struct vdec_setbuffer_cmd setbuffers; + setbuffers.buffer_type = VDEC_BUFFER_TYPE_INPUT; + memcpy (&setbuffers.buffer,&drv_ctx.ptr_inputbuffer[index], + sizeof (vdec_bufferpayload)); + if (!secure_mode) { + DEBUG_PRINT_LOW("unmap the input buffer fd=%d", + drv_ctx.ptr_inputbuffer[index].pmem_fd); + DEBUG_PRINT_LOW("unmap the input buffer size=%u address = %p", + (unsigned int)drv_ctx.ptr_inputbuffer[index].mmaped_size, + drv_ctx.ptr_inputbuffer[index].bufferaddr); + munmap (drv_ctx.ptr_inputbuffer[index].bufferaddr, + drv_ctx.ptr_inputbuffer[index].mmaped_size); + } + + if (allocate_native_handle){ + native_handle_t *nh = (native_handle_t *)bufferHdr->pBuffer; + native_handle_close(nh); + native_handle_delete(nh); + } else { + // Close fd for non-secure and secure non-native-handle case + close(drv_ctx.ptr_inputbuffer[index].pmem_fd); + } + drv_ctx.ptr_inputbuffer[index].pmem_fd = -1; + + if (m_desc_buffer_ptr && m_desc_buffer_ptr[index].buf_addr) { + free(m_desc_buffer_ptr[index].buf_addr); + m_desc_buffer_ptr[index].buf_addr = NULL; + m_desc_buffer_ptr[index].desc_data_size = 0; + } +#ifdef USE_ION + free_ion_memory(&drv_ctx.ip_buf_ion_info[index]); +#endif + } + } + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::free_output_buffer(OMX_BUFFERHEADERTYPE *bufferHdr) +{ + unsigned int index = 0; + + if (bufferHdr == NULL || m_out_mem_ptr == NULL) { + return OMX_ErrorBadParameter; + } + + index = bufferHdr - m_out_mem_ptr; + DEBUG_PRINT_LOW("Free ouput Buffer index = %d",index); + + if (index < drv_ctx.op_buf.actualcount + && drv_ctx.ptr_outputbuffer) { + DEBUG_PRINT_LOW("Free ouput Buffer index = %d addr = %p", index, + drv_ctx.ptr_outputbuffer[index].bufferaddr); + + struct vdec_setbuffer_cmd setbuffers; + setbuffers.buffer_type = VDEC_BUFFER_TYPE_OUTPUT; + memcpy (&setbuffers.buffer,&drv_ctx.ptr_outputbuffer[index], + sizeof (vdec_bufferpayload)); + + if (!dynamic_buf_mode) { + if (streaming[CAPTURE_PORT] && + !(in_reconfig || BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_FLUSH_PENDING))) { + if (stream_off(OMX_CORE_OUTPUT_PORT_INDEX)) { + DEBUG_PRINT_ERROR("STREAMOFF Failed"); + } else { + DEBUG_PRINT_LOW("STREAMOFF Successful"); + } + } +#ifdef _ANDROID_ + if (m_enable_android_native_buffers) { + if (!secure_mode) { + if (drv_ctx.ptr_outputbuffer[index].pmem_fd > 0) { + munmap(drv_ctx.ptr_outputbuffer[index].bufferaddr, + drv_ctx.ptr_outputbuffer[index].mmaped_size); + } + } + drv_ctx.ptr_outputbuffer[index].pmem_fd = -1; + } else { +#endif + if (drv_ctx.ptr_outputbuffer[0].pmem_fd > 0 && !ouput_egl_buffers && !m_use_output_pmem) { + if (!secure_mode) { + DEBUG_PRINT_LOW("unmap the output buffer fd = %d", + drv_ctx.ptr_outputbuffer[0].pmem_fd); + DEBUG_PRINT_LOW("unmap the ouput buffer size=%u address = %p", + (unsigned int)drv_ctx.ptr_outputbuffer[0].mmaped_size * drv_ctx.op_buf.actualcount, + drv_ctx.ptr_outputbuffer[0].bufferaddr); + munmap (drv_ctx.ptr_outputbuffer[0].bufferaddr, + drv_ctx.ptr_outputbuffer[0].mmaped_size * drv_ctx.op_buf.actualcount); + } + close (drv_ctx.ptr_outputbuffer[0].pmem_fd); + drv_ctx.ptr_outputbuffer[0].pmem_fd = -1; +#ifdef USE_ION + free_ion_memory(&drv_ctx.op_buf_ion_info[0]); +#endif + } +#ifdef _ANDROID_ + } +#endif + } //!dynamic_buf_mode + if (release_output_done()) { + free_extradata(); + } + } + + return OMX_ErrorNone; + +} + +OMX_ERRORTYPE omx_vdec::allocate_input_heap_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes) +{ + OMX_BUFFERHEADERTYPE *input = NULL; + unsigned char *buf_addr = NULL; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned i = 0; + + /* Sanity Check*/ + if (bufferHdr == NULL) { + return OMX_ErrorBadParameter; + } + + if (m_inp_heap_ptr == NULL) { + m_inp_heap_ptr = (OMX_BUFFERHEADERTYPE*) \ + calloc( (sizeof(OMX_BUFFERHEADERTYPE)), + drv_ctx.ip_buf.actualcount); + m_phdr_pmem_ptr = (OMX_BUFFERHEADERTYPE**) \ + calloc( (sizeof(OMX_BUFFERHEADERTYPE*)), + drv_ctx.ip_buf.actualcount); + + if (m_inp_heap_ptr == NULL || m_phdr_pmem_ptr == NULL) { + DEBUG_PRINT_ERROR("m_inp_heap_ptr or m_phdr_pmem_ptr Allocation failed "); + return OMX_ErrorInsufficientResources; + } + } + + /*Find a Free index*/ + for (i=0; i< drv_ctx.ip_buf.actualcount; i++) { + if (BITMASK_ABSENT(&m_heap_inp_bm_count,i)) { + DEBUG_PRINT_LOW("Free Input Buffer Index %d",i); + break; + } + } + + if (i < drv_ctx.ip_buf.actualcount) { + buf_addr = (unsigned char *)malloc (drv_ctx.ip_buf.buffer_size); + + if (buf_addr == NULL) { + return OMX_ErrorInsufficientResources; + } + + *bufferHdr = (m_inp_heap_ptr + i); + input = *bufferHdr; + BITMASK_SET(&m_heap_inp_bm_count,i); + + input->pBuffer = (OMX_U8 *)buf_addr; + input->nSize = sizeof(OMX_BUFFERHEADERTYPE); + input->nVersion.nVersion = OMX_SPEC_VERSION; + input->nAllocLen = drv_ctx.ip_buf.buffer_size; + input->pAppPrivate = appData; + input->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + DEBUG_PRINT_LOW("Address of Heap Buffer %p",*bufferHdr ); + eRet = allocate_input_buffer(hComp,&m_phdr_pmem_ptr [i],port,appData,bytes); + DEBUG_PRINT_LOW("Address of Pmem Buffer %p",m_phdr_pmem_ptr[i]); + /*Add the Buffers to freeq*/ + if (!m_input_free_q.insert_entry((unsigned long)m_phdr_pmem_ptr[i], + (unsigned)NULL, (unsigned)NULL)) { + DEBUG_PRINT_ERROR("ERROR:Free_q is full"); + return OMX_ErrorInsufficientResources; + } + } else { + return OMX_ErrorBadParameter; + } + + return eRet; + +} + + +/* ====================================================================== + FUNCTION + omx_vdec::AllocateInputBuffer + + DESCRIPTION + Helper function for allocate buffer in the input pin + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::allocate_input_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct vdec_setbuffer_cmd setbuffers; + OMX_BUFFERHEADERTYPE *input = NULL; + unsigned i = 0; + unsigned char *buf_addr = NULL; + int pmem_fd = -1; + + (void) hComp; + (void) port; + + + if (bytes != drv_ctx.ip_buf.buffer_size) { + DEBUG_PRINT_LOW("Requested Size is wrong %u epected is %u", + (unsigned int)bytes, (unsigned int)drv_ctx.ip_buf.buffer_size); + return OMX_ErrorBadParameter; + } + + if (!m_inp_mem_ptr) { + DEBUG_PRINT_HIGH("Allocate i/p buffer Header: Cnt(%d) Sz(%u)", + drv_ctx.ip_buf.actualcount, + (unsigned int)drv_ctx.ip_buf.buffer_size); + + m_inp_mem_ptr = (OMX_BUFFERHEADERTYPE*) \ + calloc( (sizeof(OMX_BUFFERHEADERTYPE)), drv_ctx.ip_buf.actualcount); + + if (m_inp_mem_ptr == NULL) { + return OMX_ErrorInsufficientResources; + } + + drv_ctx.ptr_inputbuffer = (struct vdec_bufferpayload *) \ + calloc ((sizeof (struct vdec_bufferpayload)),drv_ctx.ip_buf.actualcount); + + if (drv_ctx.ptr_inputbuffer == NULL) { + return OMX_ErrorInsufficientResources; + } +#ifdef USE_ION + drv_ctx.ip_buf_ion_info = (struct vdec_ion *) \ + calloc ((sizeof (struct vdec_ion)),drv_ctx.ip_buf.actualcount); + + if (drv_ctx.ip_buf_ion_info == NULL) { + return OMX_ErrorInsufficientResources; + } +#endif + + for (i=0; i < drv_ctx.ip_buf.actualcount; i++) { + drv_ctx.ptr_inputbuffer [i].pmem_fd = -1; +#ifdef USE_ION + drv_ctx.ip_buf_ion_info[i].ion_device_fd = -1; +#endif + } + } + + for (i=0; i< drv_ctx.ip_buf.actualcount; i++) { + if (BITMASK_ABSENT(&m_inp_bm_count,i)) { + DEBUG_PRINT_LOW("Free Input Buffer Index %d",i); + break; + } + } + + if (i < drv_ctx.ip_buf.actualcount) { + struct v4l2_buffer buf; + struct v4l2_plane plane; + int rc; + DEBUG_PRINT_LOW("Allocate input Buffer"); +#ifdef USE_ION + drv_ctx.ip_buf_ion_info[i].ion_device_fd = alloc_map_ion_memory( + drv_ctx.ip_buf.buffer_size,drv_ctx.op_buf.alignment, + &drv_ctx.ip_buf_ion_info[i].ion_alloc_data, + &drv_ctx.ip_buf_ion_info[i].fd_ion_data, secure_mode ? + SECURE_FLAGS_INPUT_BUFFER : ION_FLAG_CACHED); + if (drv_ctx.ip_buf_ion_info[i].ion_device_fd < 0) { + return OMX_ErrorInsufficientResources; + } + pmem_fd = drv_ctx.ip_buf_ion_info[i].fd_ion_data.fd; +#else + pmem_fd = open (MEM_DEVICE,O_RDWR); + + if (pmem_fd < 0) { + DEBUG_PRINT_ERROR("open failed for pmem/adsp for input buffer"); + return OMX_ErrorInsufficientResources; + } + + if (pmem_fd == 0) { + pmem_fd = open (MEM_DEVICE,O_RDWR); + + if (pmem_fd < 0) { + DEBUG_PRINT_ERROR("open failed for pmem/adsp for input buffer"); + return OMX_ErrorInsufficientResources; + } + } + + if (!align_pmem_buffers(pmem_fd, drv_ctx.ip_buf.buffer_size, + drv_ctx.ip_buf.alignment)) { + DEBUG_PRINT_ERROR("align_pmem_buffers() failed"); + close(pmem_fd); + return OMX_ErrorInsufficientResources; + } +#endif + if (!secure_mode) { + buf_addr = (unsigned char *)mmap(NULL, + drv_ctx.ip_buf.buffer_size, + PROT_READ|PROT_WRITE, MAP_SHARED, pmem_fd, 0); + + if (buf_addr == MAP_FAILED) { + close(pmem_fd); +#ifdef USE_ION + free_ion_memory(&drv_ctx.ip_buf_ion_info[i]); +#endif + DEBUG_PRINT_ERROR("Map Failed to allocate input buffer"); + return OMX_ErrorInsufficientResources; + } + } + *bufferHdr = (m_inp_mem_ptr + i); + if (secure_mode) + drv_ctx.ptr_inputbuffer [i].bufferaddr = *bufferHdr; + else + drv_ctx.ptr_inputbuffer [i].bufferaddr = buf_addr; + drv_ctx.ptr_inputbuffer [i].pmem_fd = pmem_fd; + drv_ctx.ptr_inputbuffer [i].buffer_len = drv_ctx.ip_buf.buffer_size; + drv_ctx.ptr_inputbuffer [i].mmaped_size = drv_ctx.ip_buf.buffer_size; + drv_ctx.ptr_inputbuffer [i].offset = 0; + + + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane.bytesused = 0; + plane.length = drv_ctx.ptr_inputbuffer [i].mmaped_size; + plane.m.userptr = (unsigned long)drv_ctx.ptr_inputbuffer[i].bufferaddr; + plane.reserved[0] =drv_ctx.ptr_inputbuffer [i].pmem_fd; + plane.reserved[1] = 0; + plane.data_offset = drv_ctx.ptr_inputbuffer[i].offset; + buf.m.planes = &plane; + buf.length = 1; + + DEBUG_PRINT_LOW("Set the input Buffer Idx: %d Addr: %p", i, + drv_ctx.ptr_inputbuffer[i].bufferaddr); + + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_PREPARE_BUF, &buf); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to prepare bufs"); + /*TODO: How to handle this case */ + return OMX_ErrorInsufficientResources; + } + + input = *bufferHdr; + BITMASK_SET(&m_inp_bm_count,i); + DEBUG_PRINT_LOW("Buffer address %p of pmem",*bufferHdr); + if (allocate_native_handle) { + native_handle_t *nh = native_handle_create(1 /*numFds*/, 0 /*numInts*/); + if (!nh) { + DEBUG_PRINT_ERROR("Native handle create failed"); + return OMX_ErrorInsufficientResources; + } + nh->data[0] = drv_ctx.ptr_inputbuffer[i].pmem_fd; + input->pBuffer = (OMX_U8 *)nh; + } else if (secure_mode || m_input_pass_buffer_fd) { + /*Legacy method, pass ion fd stashed directly in pBuffer*/ + input->pBuffer = (OMX_U8 *)(intptr_t)drv_ctx.ptr_inputbuffer[i].pmem_fd; + } else { + input->pBuffer = (OMX_U8 *)buf_addr; + } + input->nSize = sizeof(OMX_BUFFERHEADERTYPE); + input->nVersion.nVersion = OMX_SPEC_VERSION; + input->nAllocLen = drv_ctx.ip_buf.buffer_size; + input->pAppPrivate = appData; + input->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX; + input->pInputPortPrivate = (void *)&drv_ctx.ptr_inputbuffer [i]; + + if (drv_ctx.disable_dmx) { + eRet = allocate_desc_buffer(i); + } + } else { + DEBUG_PRINT_ERROR("ERROR:Input Buffer Index not found"); + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + + +/* ====================================================================== + FUNCTION + omx_vdec::AllocateOutputBuffer + + DESCRIPTION + Helper fn for AllocateBuffer in the output pin + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything went well. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::allocate_output_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + (void)hComp; + (void)port; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr= NULL; // buffer header + unsigned i= 0; // Temporary counter + struct vdec_setbuffer_cmd setbuffers; + int extra_idx = 0; +#ifdef USE_ION + int ion_device_fd =-1; + struct ion_allocation_data ion_alloc_data; + struct ion_fd_data fd_ion_data; +#endif + if (!m_out_mem_ptr) { + DEBUG_PRINT_HIGH("Allocate o/p buffer Header: Cnt(%d) Sz(%u)", + drv_ctx.op_buf.actualcount, + (unsigned int)drv_ctx.op_buf.buffer_size); + int nBufHdrSize = 0; + int nPlatformEntrySize = 0; + int nPlatformListSize = 0; + int nPMEMInfoSize = 0; + int pmem_fd = -1; + unsigned char *pmem_baseaddress = NULL; + + OMX_QCOM_PLATFORM_PRIVATE_LIST *pPlatformList; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY *pPlatformEntry; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo; + + DEBUG_PRINT_LOW("Allocating First Output Buffer(%d)", + drv_ctx.op_buf.actualcount); + nBufHdrSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_BUFFERHEADERTYPE); + + nPMEMInfoSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO); + nPlatformListSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_LIST); + nPlatformEntrySize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_ENTRY); + + DEBUG_PRINT_LOW("TotalBufHdr %d BufHdrSize %u PMEM %d PL %d",nBufHdrSize, + (unsigned int)sizeof(OMX_BUFFERHEADERTYPE), + nPMEMInfoSize, + nPlatformListSize); + DEBUG_PRINT_LOW("PE %d OutputBuffer Count %d",nPlatformEntrySize, + drv_ctx.op_buf.actualcount); +#ifdef USE_ION + // Allocate output buffers as cached to improve performance of software-reading + // of the YUVs. Output buffers are cache-invalidated in driver. + // If color-conversion is involved, Only the C2D output buffers are cached, no + // need to cache the decoder's output buffers + int cache_flag = client_buffers.is_color_conversion_enabled() ? 0 : ION_FLAG_CACHED; + ion_device_fd = alloc_map_ion_memory( + drv_ctx.op_buf.buffer_size * drv_ctx.op_buf.actualcount, + secure_scaling_to_non_secure_opb ? SZ_4K : drv_ctx.op_buf.alignment, + &ion_alloc_data, &fd_ion_data, + (secure_mode && !secure_scaling_to_non_secure_opb) ? + SECURE_FLAGS_OUTPUT_BUFFER : cache_flag); + if (ion_device_fd < 0) { + return OMX_ErrorInsufficientResources; + } + pmem_fd = fd_ion_data.fd; +#else + pmem_fd = open (MEM_DEVICE,O_RDWR); + + if (pmem_fd < 0) { + DEBUG_PRINT_ERROR("ERROR:pmem fd for output buffer %d", + drv_ctx.op_buf.buffer_size); + return OMX_ErrorInsufficientResources; + } + + if (!align_pmem_buffers(pmem_fd, drv_ctx.op_buf.buffer_size * + drv_ctx.op_buf.actualcount, + drv_ctx.op_buf.alignment)) { + DEBUG_PRINT_ERROR("align_pmem_buffers() failed"); + close(pmem_fd); + return OMX_ErrorInsufficientResources; + } +#endif + if (!secure_mode) { + pmem_baseaddress = (unsigned char *)mmap(NULL, + (drv_ctx.op_buf.buffer_size * + drv_ctx.op_buf.actualcount), + PROT_READ|PROT_WRITE,MAP_SHARED,pmem_fd,0); + if (pmem_baseaddress == MAP_FAILED) { + DEBUG_PRINT_ERROR("MMAP failed for Size %u", + (unsigned int)drv_ctx.op_buf.buffer_size); + close(pmem_fd); +#ifdef USE_ION + free_ion_memory(&drv_ctx.op_buf_ion_info[i]); +#endif + return OMX_ErrorInsufficientResources; + } + } + m_out_mem_ptr = (OMX_BUFFERHEADERTYPE *)calloc(nBufHdrSize,1); + // Alloc mem for platform specific info + char *pPtr=NULL; + pPtr = (char*) calloc(nPlatformListSize + nPlatformEntrySize + + nPMEMInfoSize,1); + drv_ctx.ptr_outputbuffer = (struct vdec_bufferpayload *)\ + calloc (sizeof(struct vdec_bufferpayload), + drv_ctx.op_buf.actualcount); + drv_ctx.ptr_respbuffer = (struct vdec_output_frameinfo *)\ + calloc (sizeof (struct vdec_output_frameinfo), + drv_ctx.op_buf.actualcount); + if (!drv_ctx.ptr_outputbuffer || !drv_ctx.ptr_respbuffer) { + DEBUG_PRINT_ERROR("Failed to alloc drv_ctx.ptr_outputbuffer or drv_ctx.ptr_respbuffer "); + return OMX_ErrorInsufficientResources; + } + +#ifdef USE_ION + drv_ctx.op_buf_ion_info = (struct vdec_ion *)\ + calloc (sizeof(struct vdec_ion), + drv_ctx.op_buf.actualcount); + if (!drv_ctx.op_buf_ion_info) { + DEBUG_PRINT_ERROR("Failed to alloc drv_ctx.op_buf_ion_info"); + return OMX_ErrorInsufficientResources; + } +#endif + + if (m_out_mem_ptr && pPtr && drv_ctx.ptr_outputbuffer + && drv_ctx.ptr_respbuffer) { + drv_ctx.ptr_outputbuffer[0].mmaped_size = + (drv_ctx.op_buf.buffer_size * + drv_ctx.op_buf.actualcount); + bufHdr = m_out_mem_ptr; + m_platform_list = (OMX_QCOM_PLATFORM_PRIVATE_LIST *)(pPtr); + m_platform_entry= (OMX_QCOM_PLATFORM_PRIVATE_ENTRY *) + (((char *) m_platform_list) + nPlatformListSize); + m_pmem_info = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) + (((char *) m_platform_entry) + nPlatformEntrySize); + pPlatformList = m_platform_list; + pPlatformEntry = m_platform_entry; + pPMEMInfo = m_pmem_info; + + DEBUG_PRINT_LOW("Memory Allocation Succeeded for OUT port%p",m_out_mem_ptr); + + // Settting the entire storage nicely + DEBUG_PRINT_LOW("bHdr %p OutMem %p PE %p",bufHdr, m_out_mem_ptr,pPlatformEntry); + DEBUG_PRINT_LOW(" Pmem Info = %p",pPMEMInfo); + for (i=0; i < drv_ctx.op_buf.actualcount ; i++) { + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + // Set the values when we determine the right HxW param + bufHdr->nAllocLen = bytes; + bufHdr->nFilledLen = 0; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + // Platform specific PMEM Information + // Initialize the Platform Entry + //DEBUG_PRINT_LOW("Initializing the Platform Entry for %d",i); + pPlatformEntry->type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; + pPlatformEntry->entry = pPMEMInfo; + // Initialize the Platform List + pPlatformList->nEntries = 1; + pPlatformList->entryList = pPlatformEntry; + // Keep pBuffer NULL till vdec is opened + bufHdr->pBuffer = NULL; + bufHdr->nOffset = 0; + + pPMEMInfo->offset = drv_ctx.op_buf.buffer_size*i; + pPMEMInfo->pmem_fd = -1; + bufHdr->pPlatformPrivate = pPlatformList; + + drv_ctx.ptr_outputbuffer[i].pmem_fd = pmem_fd; + m_pmem_info[i].pmem_fd = pmem_fd; +#ifdef USE_ION + drv_ctx.op_buf_ion_info[i].ion_device_fd = ion_device_fd; + drv_ctx.op_buf_ion_info[i].ion_alloc_data = ion_alloc_data; + drv_ctx.op_buf_ion_info[i].fd_ion_data = fd_ion_data; +#endif + + /*Create a mapping between buffers*/ + bufHdr->pOutputPortPrivate = &drv_ctx.ptr_respbuffer[i]; + drv_ctx.ptr_respbuffer[i].client_data = (void *)\ + &drv_ctx.ptr_outputbuffer[i]; + drv_ctx.ptr_outputbuffer[i].offset = drv_ctx.op_buf.buffer_size*i; + drv_ctx.ptr_outputbuffer[i].bufferaddr = + pmem_baseaddress + (drv_ctx.op_buf.buffer_size*i); + m_pmem_info[i].size = drv_ctx.ptr_outputbuffer[i].buffer_len; + m_pmem_info[i].mapped_size = drv_ctx.ptr_outputbuffer[i].mmaped_size; + m_pmem_info[i].buffer = drv_ctx.ptr_outputbuffer[i].bufferaddr; + + DEBUG_PRINT_LOW("pmem_fd = %d offset = %u address = %p", + pmem_fd, (unsigned int)drv_ctx.ptr_outputbuffer[i].offset, + drv_ctx.ptr_outputbuffer[i].bufferaddr); + // Move the buffer and buffer header pointers + bufHdr++; + pPMEMInfo++; + pPlatformEntry++; + pPlatformList++; + } + } else { + DEBUG_PRINT_ERROR("Output buf mem alloc failed[0x%p][0x%p]",\ + m_out_mem_ptr, pPtr); + if (m_out_mem_ptr) { + free(m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + if (pPtr) { + free(pPtr); + pPtr = NULL; + } + if (drv_ctx.ptr_outputbuffer) { + free(drv_ctx.ptr_outputbuffer); + drv_ctx.ptr_outputbuffer = NULL; + } + if (drv_ctx.ptr_respbuffer) { + free(drv_ctx.ptr_respbuffer); + drv_ctx.ptr_respbuffer = NULL; + } +#ifdef USE_ION + if (drv_ctx.op_buf_ion_info) { + DEBUG_PRINT_LOW("Free o/p ion context"); + free(drv_ctx.op_buf_ion_info); + drv_ctx.op_buf_ion_info = NULL; + } +#endif + eRet = OMX_ErrorInsufficientResources; + } + if (eRet == OMX_ErrorNone) + eRet = allocate_extradata(); + } + + for (i=0; i< drv_ctx.op_buf.actualcount; i++) { + if (BITMASK_ABSENT(&m_out_bm_count,i)) { + DEBUG_PRINT_LOW("Found a Free Output Buffer %d",i); + break; + } + } + + if (eRet == OMX_ErrorNone) { + if (i < drv_ctx.op_buf.actualcount) { + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + int rc; + m_pmem_info[i].offset = drv_ctx.ptr_outputbuffer[i].offset; + + drv_ctx.ptr_outputbuffer[i].buffer_len = + drv_ctx.op_buf.buffer_size; + + *bufferHdr = (m_out_mem_ptr + i ); + if (secure_mode) { +#ifdef USE_ION + drv_ctx.ptr_outputbuffer[i].bufferaddr = + (OMX_U8 *)(intptr_t)drv_ctx.op_buf_ion_info[i].fd_ion_data.fd; +#else + drv_ctx.ptr_outputbuffer[i].bufferaddr = *bufferHdr; +#endif + } + drv_ctx.ptr_outputbuffer[i].mmaped_size = drv_ctx.op_buf.buffer_size; + + buf.index = i; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].length = drv_ctx.op_buf.buffer_size; + plane[0].m.userptr = (unsigned long)drv_ctx.ptr_outputbuffer[i].bufferaddr - + (unsigned long)drv_ctx.ptr_outputbuffer[i].offset; +#ifdef USE_ION + plane[0].reserved[0] = drv_ctx.op_buf_ion_info[i].fd_ion_data.fd; +#endif + plane[0].reserved[1] = drv_ctx.ptr_outputbuffer[i].offset; + plane[0].data_offset = 0; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].length = drv_ctx.extradata_info.buffer_size; + plane[extra_idx].m.userptr = (long unsigned int) (drv_ctx.extradata_info.uaddr + i * drv_ctx.extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = drv_ctx.extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = i * drv_ctx.extradata_info.buffer_size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index higher than allowed: %d", extra_idx); + return OMX_ErrorBadParameter; + } + buf.m.planes = plane; + buf.length = drv_ctx.num_planes; + DEBUG_PRINT_LOW("Set the Output Buffer Idx: %d Addr: %p", i, drv_ctx.ptr_outputbuffer[i].bufferaddr); + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_PREPARE_BUF, &buf); + if (rc) { + /*TODO: How to handle this case */ + return OMX_ErrorInsufficientResources; + } + + if (i == (drv_ctx.op_buf.actualcount -1 ) && !streaming[CAPTURE_PORT]) { + enum v4l2_buf_type buf_type; + buf_type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + rc=ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type); + if (rc) { + return OMX_ErrorInsufficientResources; + } else { + streaming[CAPTURE_PORT] = true; + DEBUG_PRINT_LOW("STREAMON Successful"); + } + + DEBUG_PRINT_HIGH("Enabling Turbo mode"); + request_perf_level(VIDC_TURBO); + } + + (*bufferHdr)->pBuffer = (OMX_U8*)drv_ctx.ptr_outputbuffer[i].bufferaddr; + (*bufferHdr)->pAppPrivate = appData; + BITMASK_SET(&m_out_bm_count,i); + } else { + DEBUG_PRINT_ERROR("All the Output Buffers have been Allocated ; Returning Insufficient"); + eRet = OMX_ErrorInsufficientResources; + } + } + + return eRet; +} + + +// AllocateBuffer -- API Call +/* ====================================================================== + FUNCTION + omx_vdec::AllocateBuffer + + DESCRIPTION + Returns zero if all the buffers released.. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::allocate_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + unsigned i = 0; + OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type + + DEBUG_PRINT_LOW("Allocate buffer on port %d", (int)port); + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Allocate Buf in Invalid State"); + return OMX_ErrorInvalidState; + } + + if (port == OMX_CORE_INPUT_PORT_INDEX) { + // If this is not the first allocation (i.e m_inp_mem_ptr is allocated), + // ensure that use-buffer was never called. + // Mix-and-match of useBuffer and allocateBuffer is not allowed + if (m_inp_mem_ptr && input_use_buffer) { + DEBUG_PRINT_ERROR("'Allocate' Input buffer called after 'Use' Input buffer !"); + return OMX_ErrorUndefined; + } + if (arbitrary_bytes) { + eRet = allocate_input_heap_buffer (hComp,bufferHdr,port,appData,bytes); + } else { + eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes); + } + } else if (port == OMX_CORE_OUTPUT_PORT_INDEX) { + eRet = client_buffers.allocate_buffers_color_convert(hComp,bufferHdr,port, + appData,bytes); + } else { + DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d",(int)port); + eRet = OMX_ErrorBadPortIndex; + } + DEBUG_PRINT_LOW("Checking for Output Allocate buffer Done"); + if (eRet == OMX_ErrorNone) { + if (allocate_done()) { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) { + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_IDLE_PENDING); + post_event(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated) { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated) { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } + } + DEBUG_PRINT_LOW("Allocate Buffer exit with ret Code %d",eRet); + return eRet; +} + +// Free Buffer - API call +/* ====================================================================== + FUNCTION + omx_vdec::FreeBuffer + + DESCRIPTION + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::free_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned int nPortIndex; + (void) hComp; + DEBUG_PRINT_LOW("In for decoder free_buffer"); + + if (m_state == OMX_StateIdle && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) { + DEBUG_PRINT_LOW(" free buffer while Component in Loading pending"); + } else if ((m_inp_bEnabled == OMX_FALSE && port == OMX_CORE_INPUT_PORT_INDEX)|| + (m_out_bEnabled == OMX_FALSE && port == OMX_CORE_OUTPUT_PORT_INDEX)) { + DEBUG_PRINT_LOW("Free Buffer while port %u disabled", (unsigned int)port); + } else if ((port == OMX_CORE_INPUT_PORT_INDEX && + BITMASK_PRESENT(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING)) || + (port == OMX_CORE_OUTPUT_PORT_INDEX && + BITMASK_PRESENT(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING))) { + DEBUG_PRINT_LOW("Free Buffer while port %u enable pending", (unsigned int)port); + } else if (m_state == OMX_StateExecuting || m_state == OMX_StatePause) { + DEBUG_PRINT_ERROR("Invalid state to free buffer,ports need to be disabled"); + post_event(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + + return OMX_ErrorIncorrectStateOperation; + } else if (m_state != OMX_StateInvalid) { + DEBUG_PRINT_ERROR("Invalid state to free buffer,port lost Buffers"); + post_event(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + } + + if (port == OMX_CORE_INPUT_PORT_INDEX) { + /*Check if arbitrary bytes*/ + if (!arbitrary_bytes && !input_use_buffer) + nPortIndex = buffer - m_inp_mem_ptr; + else + nPortIndex = buffer - m_inp_heap_ptr; + + DEBUG_PRINT_LOW("free_buffer on i/p port - Port idx %d", nPortIndex); + if (nPortIndex < drv_ctx.ip_buf.actualcount && + BITMASK_PRESENT(&m_inp_bm_count, nPortIndex)) { + // Clear the bit associated with it. + BITMASK_CLEAR(&m_inp_bm_count,nPortIndex); + BITMASK_CLEAR(&m_heap_inp_bm_count,nPortIndex); + if (input_use_buffer == true) { + + DEBUG_PRINT_LOW("Free pmem Buffer index %d",nPortIndex); + if (m_phdr_pmem_ptr) + free_input_buffer(m_phdr_pmem_ptr[nPortIndex]); + } else { + if (arbitrary_bytes) { + if (m_phdr_pmem_ptr) + free_input_buffer(nPortIndex,m_phdr_pmem_ptr[nPortIndex]); + else + free_input_buffer(nPortIndex,NULL); + } else + free_input_buffer(buffer); + } + m_inp_bPopulated = OMX_FALSE; + if(release_input_done()) + release_buffers(this, VDEC_BUFFER_TYPE_INPUT); + /*Free the Buffer Header*/ + if (release_input_done()) { + DEBUG_PRINT_HIGH("ALL input buffers are freed/released"); + free_input_buffer_header(); + } + } else { + DEBUG_PRINT_ERROR("Error: free_buffer ,Port Index Invalid"); + eRet = OMX_ErrorBadPortIndex; + } + + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING) + && release_input_done()) { + DEBUG_PRINT_LOW("MOVING TO DISABLED STATE"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING); + post_event(OMX_CommandPortDisable, + OMX_CORE_INPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } else if (port == OMX_CORE_OUTPUT_PORT_INDEX) { + // check if the buffer is valid + nPortIndex = buffer - client_buffers.get_il_buf_hdr(); + if (nPortIndex < drv_ctx.op_buf.actualcount && + BITMASK_PRESENT(&m_out_bm_count, nPortIndex)) { + DEBUG_PRINT_LOW("free_buffer on o/p port - Port idx %d", nPortIndex); + // Clear the bit associated with it. + BITMASK_CLEAR(&m_out_bm_count,nPortIndex); + m_out_bPopulated = OMX_FALSE; + client_buffers.free_output_buffer (buffer); + + if(release_output_done()) { + release_buffers(this, VDEC_BUFFER_TYPE_OUTPUT); + } + if (release_output_done()) { + free_output_buffer_header(); + } + } else { + DEBUG_PRINT_ERROR("Error: free_buffer , Port Index Invalid"); + eRet = OMX_ErrorBadPortIndex; + } + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING) + && release_output_done()) { + DEBUG_PRINT_LOW("FreeBuffer : If any Disable event pending,post it"); + + DEBUG_PRINT_LOW("MOVING TO DISABLED STATE"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING); +#ifdef _ANDROID_ICS_ + if (m_enable_android_native_buffers) { + DEBUG_PRINT_LOW("FreeBuffer - outport disabled: reset native buffers"); + memset(&native_buffer, 0 ,(sizeof(struct nativebuffer) * MAX_NUM_INPUT_OUTPUT_BUFFERS)); + } +#endif + + post_event(OMX_CommandPortDisable, + OMX_CORE_OUTPUT_PORT_INDEX, + OMX_COMPONENT_GENERATE_EVENT); + } + } else { + eRet = OMX_ErrorBadPortIndex; + } + if ((eRet == OMX_ErrorNone) && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) { + if (release_done()) { + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING); + post_event(OMX_CommandStateSet, OMX_StateLoaded, + OMX_COMPONENT_GENERATE_EVENT); + } + } + return eRet; +} + + +/* ====================================================================== + FUNCTION + omx_vdec::EmptyThisBuffer + + DESCRIPTION + This routine is used to push the encoded video frames to + the video decoder. + + PARAMETERS + None. + + RETURN VALUE + OMX Error None if everything went successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::empty_this_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE ret1 = OMX_ErrorNone; + unsigned int nBufferIndex = drv_ctx.ip_buf.actualcount; + + if (m_state != OMX_StateExecuting && + m_state != OMX_StatePause && + m_state != OMX_StateIdle) { + DEBUG_PRINT_ERROR("Empty this buffer in Invalid State"); + return OMX_ErrorInvalidState; + } + + if (buffer == NULL) { + DEBUG_PRINT_ERROR("ERROR:ETB Buffer is NULL"); + return OMX_ErrorBadParameter; + } + + if (!m_inp_bEnabled) { + DEBUG_PRINT_ERROR("ERROR:ETB incorrect state operation, input port is disabled."); + return OMX_ErrorIncorrectStateOperation; + } + + if (buffer->nInputPortIndex != OMX_CORE_INPUT_PORT_INDEX) { + DEBUG_PRINT_ERROR("ERROR:ETB invalid port in header %u", (unsigned int)buffer->nInputPortIndex); + return OMX_ErrorBadPortIndex; + } + + if (perf_flag) { + if (!latency) { + dec_time.stop(); + latency = dec_time.processing_time_us(); + dec_time.start(); + } + } + + if (arbitrary_bytes) { + nBufferIndex = buffer - m_inp_heap_ptr; + } else { + if (input_use_buffer == true) { + nBufferIndex = buffer - m_inp_heap_ptr; + if (nBufferIndex >= drv_ctx.ip_buf.actualcount ) { + DEBUG_PRINT_ERROR("ERROR: ETB nBufferIndex is invalid in use-buffer mode"); + return OMX_ErrorBadParameter; + } + m_inp_mem_ptr[nBufferIndex].nFilledLen = m_inp_heap_ptr[nBufferIndex].nFilledLen; + m_inp_mem_ptr[nBufferIndex].nTimeStamp = m_inp_heap_ptr[nBufferIndex].nTimeStamp; + m_inp_mem_ptr[nBufferIndex].nFlags = m_inp_heap_ptr[nBufferIndex].nFlags; + buffer = &m_inp_mem_ptr[nBufferIndex]; + DEBUG_PRINT_LOW("Non-Arbitrary mode - buffer address is: malloc %p, pmem%p in Index %d, buffer %p of size %u", + &m_inp_heap_ptr[nBufferIndex], &m_inp_mem_ptr[nBufferIndex],nBufferIndex, buffer, (unsigned int)buffer->nFilledLen); + } else { + nBufferIndex = buffer - m_inp_mem_ptr; + } + } + + if (nBufferIndex >= drv_ctx.ip_buf.actualcount ) { + DEBUG_PRINT_ERROR("ERROR:ETB nBufferIndex is invalid"); + return OMX_ErrorBadParameter; + } + + if (buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { + codec_config_flag = true; + DEBUG_PRINT_LOW("%s: codec_config buffer", __FUNCTION__); + } + + /* The client should not set this when codec is in arbitrary bytes mode */ + if (m_input_pass_buffer_fd) { + buffer->pBuffer = (OMX_U8*)drv_ctx.ptr_inputbuffer[nBufferIndex].bufferaddr; + } + + DEBUG_PRINT_LOW("[ETB] BHdr(%p) pBuf(%p) nTS(%lld) nFL(%u)", + buffer, buffer->pBuffer, buffer->nTimeStamp, (unsigned int)buffer->nFilledLen); + if (arbitrary_bytes) { + post_event ((unsigned long)hComp,(unsigned long)buffer, + OMX_COMPONENT_GENERATE_ETB_ARBITRARY); + } else { + post_event ((unsigned long)hComp,(unsigned long)buffer,OMX_COMPONENT_GENERATE_ETB); + } + time_stamp_dts.insert_timestamp(buffer); + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::empty_this_buffer_proxy + + DESCRIPTION + This routine is used to push the encoded video frames to + the video decoder. + + PARAMETERS + None. + + RETURN VALUE + OMX Error None if everything went successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::empty_this_buffer_proxy(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + VIDC_TRACE_NAME_HIGH("ETB"); + (void) hComp; + int push_cnt = 0,i=0; + unsigned nPortIndex = 0; + OMX_ERRORTYPE ret = OMX_ErrorNone; + struct vdec_input_frameinfo frameinfo; + struct vdec_bufferpayload *temp_buffer; + struct vdec_seqheader seq_header; + bool port_setting_changed = true; + + /*Should we generate a Aync error event*/ + if (buffer == NULL || buffer->pInputPortPrivate == NULL) { + DEBUG_PRINT_ERROR("ERROR:empty_this_buffer_proxy is invalid"); + return OMX_ErrorBadParameter; + } + + nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)m_inp_mem_ptr); + + if (nPortIndex >= drv_ctx.ip_buf.actualcount) { + DEBUG_PRINT_ERROR("ERROR:empty_this_buffer_proxy invalid nPortIndex[%u]", + nPortIndex); + return OMX_ErrorBadParameter; + } + + pending_input_buffers++; + VIDC_TRACE_INT_LOW("ETB-pending", pending_input_buffers); + + /* return zero length and not an EOS buffer */ + if (!arbitrary_bytes && (buffer->nFilledLen == 0) && + ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == 0)) { + DEBUG_PRINT_HIGH("return zero legth buffer"); + post_event ((unsigned long)buffer,VDEC_S_SUCCESS, + OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorNone; + } + + if (input_flush_progress == true) { + DEBUG_PRINT_LOW("Flush in progress return buffer "); + post_event ((unsigned long)buffer,VDEC_S_SUCCESS, + OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorNone; + } + + auto_lock l(buf_lock); + temp_buffer = (struct vdec_bufferpayload *)buffer->pInputPortPrivate; + + if (!temp_buffer || (temp_buffer - drv_ctx.ptr_inputbuffer) > (int)drv_ctx.ip_buf.actualcount) { + return OMX_ErrorBadParameter; + } + /* If its first frame, H264 codec and reject is true, then parse the nal + and get the profile. Based on this, reject the clip playback */ + if (first_frame == 0 && codec_type_parse == CODEC_TYPE_H264 && + m_reject_avc_1080p_mp) { + first_frame = 1; + DEBUG_PRINT_ERROR("Parse nal to get the profile"); + h264_parser->parse_nal((OMX_U8*)buffer->pBuffer, buffer->nFilledLen, + NALU_TYPE_SPS); + m_profile = h264_parser->get_profile(); + ret = is_video_session_supported(); + if (ret) { + post_event ((unsigned long)buffer,VDEC_S_SUCCESS,OMX_COMPONENT_GENERATE_EBD); + post_event(OMX_EventError, OMX_ErrorInvalidState,OMX_COMPONENT_GENERATE_EVENT); + /* Move the state to Invalid to avoid queueing of pending ETB to the driver */ + m_state = OMX_StateInvalid; + return OMX_ErrorNone; + } + } + + VIDC_TRACE_INT_LOW("ETB-TS", buffer->nTimeStamp / 1000); + VIDC_TRACE_INT_LOW("ETB-size", buffer->nFilledLen); + DEBUG_PRINT_LOW("ETBProxy: bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer); + /*for use buffer we need to memcpy the data*/ + temp_buffer->buffer_len = buffer->nFilledLen; + + if (input_use_buffer && temp_buffer->bufferaddr && !secure_mode) { + if (buffer->nFilledLen <= temp_buffer->buffer_len) { + if (arbitrary_bytes) { + memcpy (temp_buffer->bufferaddr, (buffer->pBuffer + buffer->nOffset),buffer->nFilledLen); + } else { + memcpy (temp_buffer->bufferaddr, (m_inp_heap_ptr[nPortIndex].pBuffer + m_inp_heap_ptr[nPortIndex].nOffset), + buffer->nFilledLen); + } + } else { + return OMX_ErrorBadParameter; + } + + } + + frameinfo.bufferaddr = temp_buffer->bufferaddr; + frameinfo.client_data = (void *) buffer; + frameinfo.datalen = temp_buffer->buffer_len; + frameinfo.flags = 0; + frameinfo.offset = buffer->nOffset; + frameinfo.pmem_fd = temp_buffer->pmem_fd; + frameinfo.pmem_offset = temp_buffer->offset; + frameinfo.timestamp = buffer->nTimeStamp; + if (drv_ctx.disable_dmx && m_desc_buffer_ptr && m_desc_buffer_ptr[nPortIndex].buf_addr) { + DEBUG_PRINT_LOW("ETB: dmx enabled"); + if (m_demux_entries == 0) { + extract_demux_addr_offsets(buffer); + } + + DEBUG_PRINT_LOW("ETB: handle_demux_data - entries=%u",(unsigned int)m_demux_entries); + handle_demux_data(buffer); + frameinfo.desc_addr = (OMX_U8 *)m_desc_buffer_ptr[nPortIndex].buf_addr; + frameinfo.desc_size = m_desc_buffer_ptr[nPortIndex].desc_data_size; + } else { + frameinfo.desc_addr = NULL; + frameinfo.desc_size = 0; + } + if (!arbitrary_bytes) { + frameinfo.flags |= buffer->nFlags; + } + +#ifdef _ANDROID_ + if (m_debug_timestamp) { + if (arbitrary_bytes) { + DEBUG_PRINT_LOW("Inserting TIMESTAMP (%lld) into queue", buffer->nTimeStamp); + m_timestamp_list.insert_ts(buffer->nTimeStamp); + } else if (!arbitrary_bytes && !(buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { + DEBUG_PRINT_LOW("Inserting TIMESTAMP (%lld) into queue", buffer->nTimeStamp); + m_timestamp_list.insert_ts(buffer->nTimeStamp); + } + } +#endif + + log_input_buffers((const char *)temp_buffer->bufferaddr, temp_buffer->buffer_len); + +if (buffer->nFlags & QOMX_VIDEO_BUFFERFLAG_EOSEQ) { + frameinfo.flags |= QOMX_VIDEO_BUFFERFLAG_EOSEQ; + buffer->nFlags &= ~QOMX_VIDEO_BUFFERFLAG_EOSEQ; + } + + if (temp_buffer->buffer_len == 0 || (buffer->nFlags & OMX_BUFFERFLAG_EOS)) { + DEBUG_PRINT_HIGH("Rxd i/p EOS, Notify Driver that EOS has been reached"); + frameinfo.flags |= VDEC_BUFFERFLAG_EOS; + h264_scratch.nFilledLen = 0; + nal_count = 0; + look_ahead_nal = false; + frame_count = 0; + if (m_frame_parser.mutils) + m_frame_parser.mutils->initialize_frame_checking_environment(); + m_frame_parser.flush(); + h264_last_au_ts = LLONG_MAX; + h264_last_au_flags = 0; + memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) ); + m_demux_entries = 0; + } + struct v4l2_buffer buf; + struct v4l2_plane plane; + memset( (void *)&buf, 0, sizeof(buf)); + memset( (void *)&plane, 0, sizeof(plane)); + int rc; + unsigned long print_count; + if (temp_buffer->buffer_len == 0 || (buffer->nFlags & OMX_BUFFERFLAG_EOS)) { + buf.flags = V4L2_QCOM_BUF_FLAG_EOS; + DEBUG_PRINT_HIGH("INPUT EOS reached") ; + } + OMX_ERRORTYPE eRet = OMX_ErrorNone; + buf.index = nPortIndex; + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane.bytesused = temp_buffer->buffer_len; + plane.length = drv_ctx.ip_buf.buffer_size; + plane.m.userptr = (unsigned long)temp_buffer->bufferaddr - + (unsigned long)temp_buffer->offset; + plane.reserved[0] = temp_buffer->pmem_fd; + plane.reserved[1] = temp_buffer->offset; + plane.data_offset = 0; + buf.m.planes = &plane; + buf.length = 1; + if (frameinfo.timestamp >= LLONG_MAX) { + buf.flags |= V4L2_QCOM_BUF_TIMESTAMP_INVALID; + } + //assumption is that timestamp is in milliseconds + buf.timestamp.tv_sec = frameinfo.timestamp / 1000000; + buf.timestamp.tv_usec = (frameinfo.timestamp % 1000000); + buf.flags |= (buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) ? V4L2_QCOM_BUF_FLAG_CODECCONFIG: 0; + buf.flags |= (buffer->nFlags & OMX_BUFFERFLAG_DECODEONLY) ? V4L2_QCOM_BUF_FLAG_DECODEONLY: 0; + + if (buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { + DEBUG_PRINT_LOW("Increment codec_config buffer counter"); + android_atomic_inc(&m_queued_codec_config_count); + } + + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_QBUF, &buf); + if (rc) { + DEBUG_PRINT_ERROR("Failed to qbuf Input buffer to driver, send ETB back to client"); + m_cb.EmptyBufferDone(hComp, m_app_data, buffer); + return OMX_ErrorHardware; + } + + if (codec_config_flag && !(buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { + codec_config_flag = false; + } + if (!streaming[OUTPUT_PORT]) { + enum v4l2_buf_type buf_type; + int ret,r; + + buf_type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing"); + ret=ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type); + if (!ret) { + DEBUG_PRINT_HIGH("Streamon on OUTPUT Plane was successful"); + streaming[OUTPUT_PORT] = true; + } else if (errno == EBUSY) { + DEBUG_PRINT_ERROR("Failed to call stream on OUTPUT due to HW_OVERLOAD"); + post_event ((unsigned long)buffer, VDEC_S_SUCCESS, + OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorInsufficientResources; + } else { + DEBUG_PRINT_ERROR("Failed to call streamon on OUTPUT"); + DEBUG_PRINT_LOW("If Stream on failed no buffer should be queued"); + post_event ((unsigned long)buffer, VDEC_S_SUCCESS, + OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorBadParameter; + } + } + DEBUG_PRINT_LOW("[ETBP] pBuf(%p) nTS(%lld) Sz(%u)", + frameinfo.bufferaddr, (long long)frameinfo.timestamp, + (unsigned int)frameinfo.datalen); + + return ret; +} + +/* ====================================================================== + FUNCTION + omx_vdec::FillThisBuffer + + DESCRIPTION + IL client uses this method to release the frame buffer + after displaying them. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::fill_this_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + if (m_state != OMX_StateExecuting && + m_state != OMX_StatePause && + m_state != OMX_StateIdle) { + DEBUG_PRINT_ERROR("FTB in Invalid State"); + return OMX_ErrorInvalidState; + } + + if (!m_out_bEnabled) { + DEBUG_PRINT_ERROR("ERROR:FTB incorrect state operation, output port is disabled."); + return OMX_ErrorIncorrectStateOperation; + } + + unsigned nPortIndex = 0; + if (dynamic_buf_mode) { + private_handle_t *handle = NULL; + struct VideoDecoderOutputMetaData *meta; + unsigned int nPortIndex = 0; + + if (!buffer || !buffer->pBuffer) { + DEBUG_PRINT_ERROR("%s: invalid params: %p", __FUNCTION__, buffer); + return OMX_ErrorBadParameter; + } + + //get the buffer type and fd info + meta = (struct VideoDecoderOutputMetaData *)buffer->pBuffer; + handle = (private_handle_t *)meta->pHandle; + DEBUG_PRINT_LOW("FTB: metabuf: %p buftype: %d bufhndl: %p ", meta, meta->eType, meta->pHandle); + + if (!handle) { + DEBUG_PRINT_ERROR("FTB: Error: IL client passed an invalid buf handle - %p", handle); + return OMX_ErrorBadParameter; + } + //Fill outputbuffer with buffer details, this will be sent to f/w during VIDIOC_QBUF + nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)client_buffers.get_il_buf_hdr()); + if (nPortIndex < drv_ctx.op_buf.actualcount && + nPortIndex < MAX_NUM_INPUT_OUTPUT_BUFFERS) { + drv_ctx.ptr_outputbuffer[nPortIndex].pmem_fd = handle->fd; + drv_ctx.ptr_outputbuffer[nPortIndex].bufferaddr = (OMX_U8*) buffer; + + //Store private handle from GraphicBuffer + native_buffer[nPortIndex].privatehandle = handle; + native_buffer[nPortIndex].nativehandle = handle; + } else { + DEBUG_PRINT_ERROR("[FTB]Invalid native_buffer index: %d", nPortIndex); + return OMX_ErrorBadParameter; + } + + //buffer->nAllocLen will be sizeof(struct VideoDecoderOutputMetaData). Overwrite + //this with a more sane size so that we don't compensate in rest of code + //We'll restore this size later on, so that it's transparent to client + buffer->nFilledLen = 0; + buffer->nAllocLen = handle->size; + + if (handle->flags & private_handle_t::PRIV_FLAGS_DISP_CONSUMER) { + m_is_display_session = true; + } else { + m_is_display_session = false; + } + DEBUG_PRINT_LOW("%s: m_is_display_session = %d", __func__, m_is_display_session); + + drv_ctx.op_buf.buffer_size = handle->size; + } + + nPortIndex = buffer - client_buffers.get_il_buf_hdr(); + if (buffer == NULL || + (nPortIndex >= drv_ctx.op_buf.actualcount)) { + DEBUG_PRINT_ERROR("FTB: ERROR: invalid buffer index, nPortIndex %u bufCount %u", + nPortIndex, drv_ctx.op_buf.actualcount); + return OMX_ErrorBadParameter; + } + + if (buffer->nOutputPortIndex != OMX_CORE_OUTPUT_PORT_INDEX) { + DEBUG_PRINT_ERROR("ERROR:FTB invalid port in header %u", (unsigned int)buffer->nOutputPortIndex); + return OMX_ErrorBadPortIndex; + } + + DEBUG_PRINT_LOW("[FTB] bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer); + post_event((unsigned long) hComp, (unsigned long)buffer, m_fill_output_msg); + return OMX_ErrorNone; +} +/* ====================================================================== + FUNCTION + omx_vdec::fill_this_buffer_proxy + + DESCRIPTION + IL client uses this method to release the frame buffer + after displaying them. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::fill_this_buffer_proxy( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* bufferAdd) +{ + VIDC_TRACE_NAME_HIGH("FTB"); + OMX_ERRORTYPE nRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *buffer = bufferAdd; + unsigned nPortIndex = 0; + struct vdec_fillbuffer_cmd fillbuffer; + struct vdec_bufferpayload *ptr_outputbuffer = NULL; + struct vdec_output_frameinfo *ptr_respbuffer = NULL; + + nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)client_buffers.get_il_buf_hdr()); + + if (bufferAdd == NULL || nPortIndex >= drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("FTBProxy: ERROR: invalid buffer index, nPortIndex %u bufCount %u", + nPortIndex, drv_ctx.op_buf.actualcount); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("FTBProxy: bufhdr = %p, bufhdr->pBuffer = %p", + bufferAdd, bufferAdd->pBuffer); + /*Return back the output buffer to client*/ + if (m_out_bEnabled != OMX_TRUE || output_flush_progress == true || in_reconfig) { + DEBUG_PRINT_LOW("Output Buffers return flush/disable condition"); + buffer->nFilledLen = 0; + m_cb.FillBufferDone (hComp,m_app_data,buffer); + return OMX_ErrorNone; + } + + if (dynamic_buf_mode) { + drv_ctx.ptr_outputbuffer[nPortIndex].offset = 0; + drv_ctx.ptr_outputbuffer[nPortIndex].buffer_len = buffer->nAllocLen; + buf_ref_add(nPortIndex); + drv_ctx.ptr_outputbuffer[nPortIndex].mmaped_size = buffer->nAllocLen; + } + + pending_output_buffers++; + VIDC_TRACE_INT_LOW("FTB-pending", pending_output_buffers); + buffer = client_buffers.get_dr_buf_hdr(bufferAdd); + if (!buffer) { + DEBUG_PRINT_ERROR("err: client_buffer ptr invalid"); + return OMX_ErrorBadParameter; + } + ptr_respbuffer = (struct vdec_output_frameinfo*)buffer->pOutputPortPrivate; + if (ptr_respbuffer) { + ptr_outputbuffer = (struct vdec_bufferpayload*)ptr_respbuffer->client_data; + } + + if (ptr_respbuffer == NULL || ptr_outputbuffer == NULL) { + DEBUG_PRINT_ERROR("resp buffer or outputbuffer is NULL"); + buffer->nFilledLen = 0; + m_cb.FillBufferDone (hComp,m_app_data,buffer); + pending_output_buffers--; + VIDC_TRACE_INT_LOW("FTB-pending", pending_output_buffers); + return OMX_ErrorBadParameter; + } + + int rc = 0; + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + memset( (void *)&buf, 0, sizeof(buf)); + memset( (void *)plane, 0, (sizeof(struct v4l2_plane)*VIDEO_MAX_PLANES)); + unsigned int extra_idx = 0; + + buf.index = nPortIndex; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].bytesused = buffer->nFilledLen; + plane[0].length = buffer->nAllocLen; + plane[0].m.userptr = + (unsigned long)drv_ctx.ptr_outputbuffer[nPortIndex].bufferaddr - + (unsigned long)drv_ctx.ptr_outputbuffer[nPortIndex].offset; + plane[0].reserved[0] = drv_ctx.ptr_outputbuffer[nPortIndex].pmem_fd; + plane[0].reserved[1] = drv_ctx.ptr_outputbuffer[nPortIndex].offset; + plane[0].data_offset = 0; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].bytesused = 0; + plane[extra_idx].length = drv_ctx.extradata_info.buffer_size; + plane[extra_idx].m.userptr = (long unsigned int) (drv_ctx.extradata_info.uaddr + nPortIndex * drv_ctx.extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = drv_ctx.extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = nPortIndex * drv_ctx.extradata_info.buffer_size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index higher than expected: %u", extra_idx); + return OMX_ErrorBadParameter; + } + buf.m.planes = plane; + buf.length = drv_ctx.num_planes; + DEBUG_PRINT_LOW("SENDING FTB TO F/W - fd[0] = %d fd[1] = %d offset[1] = %d in_flush = %d", + plane[0].reserved[0],plane[extra_idx].reserved[0], plane[extra_idx].reserved[1], output_flush_progress); + + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_QBUF, &buf); + if (rc) { + /*TODO: How to handle this case */ + buffer->nFilledLen = 0; + DEBUG_PRINT_ERROR("Failed to qbuf to driver, send FTB back to client"); + m_cb.FillBufferDone(hComp, m_app_data, buffer); + } +return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::SetCallbacks + + DESCRIPTION + Set the callbacks. + + PARAMETERS + None. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::set_callbacks(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_CALLBACKTYPE* callbacks, + OMX_IN OMX_PTR appData) +{ + (void) hComp; + m_cb = *callbacks; + DEBUG_PRINT_LOW("Callbacks Set %p %p %p",m_cb.EmptyBufferDone,\ + m_cb.EventHandler,m_cb.FillBufferDone); + m_app_data = appData; + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== + FUNCTION + omx_vdec::ComponentDeInit + + DESCRIPTION + Destroys the component and release memory allocated to the heap. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::component_deinit(OMX_IN OMX_HANDLETYPE hComp) +{ + (void) hComp; + + unsigned i = 0; + if (OMX_StateLoaded != m_state) { + DEBUG_PRINT_ERROR("WARNING:Rxd DeInit,OMX not in LOADED state %d",\ + m_state); + DEBUG_PRINT_ERROR("Playback Ended - FAILED"); + } else { + DEBUG_PRINT_HIGH("Playback Ended - PASSED"); + } + + /*Check if the output buffers have to be cleaned up*/ + if (m_out_mem_ptr) { + DEBUG_PRINT_LOW("Freeing the Output Memory"); + for (i = 0; i < drv_ctx.op_buf.actualcount; i++ ) { + if (BITMASK_PRESENT(&m_out_bm_count, i)) { + BITMASK_CLEAR(&m_out_bm_count, i); + client_buffers.free_output_buffer (&m_out_mem_ptr[i]); + } + + if (release_output_done()) { + break; + } + } +#ifdef _ANDROID_ICS_ + memset(&native_buffer, 0, (sizeof(nativebuffer) * MAX_NUM_INPUT_OUTPUT_BUFFERS)); +#endif + } + + /*Check if the input buffers have to be cleaned up*/ + if (m_inp_mem_ptr || m_inp_heap_ptr) { + DEBUG_PRINT_LOW("Freeing the Input Memory"); + for (i = 0; i<drv_ctx.ip_buf.actualcount; i++ ) { + + if (BITMASK_PRESENT(&m_inp_bm_count, i)) { + BITMASK_CLEAR(&m_inp_bm_count, i); + if (m_inp_mem_ptr) + free_input_buffer (i,&m_inp_mem_ptr[i]); + else + free_input_buffer (i,NULL); + } + + if (release_input_done()) { + break; + } + } + } + free_input_buffer_header(); + free_output_buffer_header(); + if (h264_scratch.pBuffer) { + free(h264_scratch.pBuffer); + h264_scratch.pBuffer = NULL; + } + + if (h264_parser) { + delete h264_parser; + h264_parser = NULL; + } + + if (m_frame_parser.mutils) { + DEBUG_PRINT_LOW("Free utils parser"); + delete (m_frame_parser.mutils); + m_frame_parser.mutils = NULL; + } + + if (m_platform_list) { + free(m_platform_list); + m_platform_list = NULL; + } + if (m_vendor_config.pData) { + free(m_vendor_config.pData); + m_vendor_config.pData = NULL; + } + + // Reset counters in mesg queues + m_ftb_q.m_size=0; + m_cmd_q.m_size=0; + m_etb_q.m_size=0; + m_ftb_q.m_read = m_ftb_q.m_write =0; + m_cmd_q.m_read = m_cmd_q.m_write =0; + m_etb_q.m_read = m_etb_q.m_write =0; +#ifdef _ANDROID_ + if (m_debug_timestamp) { + m_timestamp_list.reset_ts_list(); + } +#endif + + DEBUG_PRINT_LOW("Calling VDEC_IOCTL_STOP_NEXT_MSG"); + //(void)ioctl(drv_ctx.video_driver_fd, VDEC_IOCTL_STOP_NEXT_MSG, + // NULL); + DEBUG_PRINT_HIGH("Close the driver instance"); + + if (m_debug.infile) { + fclose(m_debug.infile); + m_debug.infile = NULL; + } + if (m_debug.outfile) { + fclose(m_debug.outfile); + m_debug.outfile = NULL; + } + if (m_debug.out_ymeta_file) { + fclose(m_debug.out_ymeta_file); + m_debug.out_ymeta_file = NULL; + } + if (m_debug.out_uvmeta_file) { + fclose(m_debug.out_uvmeta_file); + m_debug.out_uvmeta_file = NULL; + } +#ifdef OUTPUT_EXTRADATA_LOG + if (outputExtradataFile) + fclose (outputExtradataFile); +#endif + DEBUG_PRINT_INFO("omx_vdec::component_deinit() complete"); + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::UseEGLImage + + DESCRIPTION + OMX Use EGL Image method implementation <TBD>. + + PARAMETERS + <TBD>. + + RETURN VALUE + Not Implemented error. + + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::use_EGL_image(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN void* eglImage) +{ + (void) appData; + OMX_QCOM_PLATFORM_PRIVATE_LIST pmem_list; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY pmem_entry; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO pmem_info; + +#ifdef USE_EGL_IMAGE_GPU + PFNEGLQUERYIMAGEQUALCOMMPROC egl_queryfunc; + EGLint fd = -1, offset = 0,pmemPtr = 0; +#else + int fd = -1, offset = 0; +#endif + DEBUG_PRINT_HIGH("use EGL image support for decoder"); + if (!bufferHdr || !eglImage|| port != OMX_CORE_OUTPUT_PORT_INDEX) { + DEBUG_PRINT_ERROR("Invalid EGL image"); + } +#ifdef USE_EGL_IMAGE_GPU + if (m_display_id == NULL) { + DEBUG_PRINT_ERROR("Display ID is not set by IL client"); + return OMX_ErrorInsufficientResources; + } + egl_queryfunc = (PFNEGLQUERYIMAGEQUALCOMMPROC) + eglGetProcAddress("eglQueryImageKHR"); + egl_queryfunc(m_display_id, eglImage, EGL_BUFFER_HANDLE, &fd); + egl_queryfunc(m_display_id, eglImage, EGL_BUFFER_OFFSET, &offset); + egl_queryfunc(m_display_id, eglImage, EGL_BITMAP_POINTER_KHR, &pmemPtr); +#else //with OMX test app + struct temp_egl { + int pmem_fd; + int offset; + }; + struct temp_egl *temp_egl_id = NULL; + void * pmemPtr = (void *) eglImage; + temp_egl_id = (struct temp_egl *)eglImage; + if (temp_egl_id != NULL) { + fd = temp_egl_id->pmem_fd; + offset = temp_egl_id->offset; + } +#endif + if (fd < 0) { + DEBUG_PRINT_ERROR("Improper pmem fd by EGL client %d",fd); + return OMX_ErrorInsufficientResources; + } + pmem_info.pmem_fd = (OMX_U32) fd; + pmem_info.offset = (OMX_U32) offset; + pmem_entry.entry = (void *) &pmem_info; + pmem_entry.type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; + pmem_list.entryList = &pmem_entry; + pmem_list.nEntries = 1; + ouput_egl_buffers = true; + if (OMX_ErrorNone != use_buffer(hComp,bufferHdr, port, + (void *)&pmem_list, drv_ctx.op_buf.buffer_size, + (OMX_U8 *)pmemPtr)) { + DEBUG_PRINT_ERROR("use buffer call failed for egl image"); + return OMX_ErrorInsufficientResources; + } + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_vdec::ComponentRoleEnum + + DESCRIPTION + OMX Component Role Enum method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything is successful. + ========================================================================== */ +OMX_ERRORTYPE omx_vdec::component_role_enum(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_U8* role, + OMX_IN OMX_U32 index) +{ + (void) hComp; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + eRet = OMX_ErrorNoMore; + } + } + if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg2",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.mpeg2",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.h263",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } + + else if ((!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx",OMX_MAX_STRINGNAME_SIZE)) || + (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx311",OMX_MAX_STRINGNAME_SIZE))) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.avc",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mvc", OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.mvc", OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc", OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.hevc", OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s", role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if ( (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vc1",OMX_MAX_STRINGNAME_SIZE)) || + (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.wmv",OMX_MAX_STRINGNAME_SIZE)) + ) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.vp8",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp9",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.vp9",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_LOW("No more roles"); + eRet = OMX_ErrorNoMore; + } + } else { + DEBUG_PRINT_ERROR("ERROR:Querying Role on Unknown Component"); + eRet = OMX_ErrorInvalidComponentName; + } + return eRet; +} + + + + +/* ====================================================================== + FUNCTION + omx_vdec::AllocateDone + + DESCRIPTION + Checks if entire buffer pool is allocated by IL Client or not. + Need this to move to IDLE state. + + PARAMETERS + None. + + RETURN VALUE + true/false. + + ========================================================================== */ +bool omx_vdec::allocate_done(void) +{ + bool bRet = false; + bool bRet_In = false; + bool bRet_Out = false; + + bRet_In = allocate_input_done(); + bRet_Out = allocate_output_done(); + + if (bRet_In && bRet_Out) { + bRet = true; + } + + return bRet; +} +/* ====================================================================== + FUNCTION + omx_vdec::AllocateInputDone + + DESCRIPTION + Checks if I/P buffer pool is allocated by IL Client or not. + + PARAMETERS + None. + + RETURN VALUE + true/false. + + ========================================================================== */ +bool omx_vdec::allocate_input_done(void) +{ + bool bRet = false; + unsigned i=0; + + if (m_inp_mem_ptr == NULL) { + return bRet; + } + if (m_inp_mem_ptr ) { + for (; i<drv_ctx.ip_buf.actualcount; i++) { + if (BITMASK_ABSENT(&m_inp_bm_count,i)) { + break; + } + } + } + if (i == drv_ctx.ip_buf.actualcount) { + bRet = true; + DEBUG_PRINT_HIGH("Allocate done for all i/p buffers"); + } + if (i==drv_ctx.ip_buf.actualcount && m_inp_bEnabled) { + m_inp_bPopulated = OMX_TRUE; + } + return bRet; +} +/* ====================================================================== + FUNCTION + omx_vdec::AllocateOutputDone + + DESCRIPTION + Checks if entire O/P buffer pool is allocated by IL Client or not. + + PARAMETERS + None. + + RETURN VALUE + true/false. + + ========================================================================== */ +bool omx_vdec::allocate_output_done(void) +{ + bool bRet = false; + unsigned j=0; + + if (m_out_mem_ptr == NULL) { + return bRet; + } + + if (m_out_mem_ptr) { + for (; j < drv_ctx.op_buf.actualcount; j++) { + if (BITMASK_ABSENT(&m_out_bm_count,j)) { + break; + } + } + } + + if (j == drv_ctx.op_buf.actualcount) { + bRet = true; + DEBUG_PRINT_HIGH("Allocate done for all o/p buffers"); + if (m_out_bEnabled) + m_out_bPopulated = OMX_TRUE; + } + + return bRet; +} + +/* ====================================================================== + FUNCTION + omx_vdec::ReleaseDone + + DESCRIPTION + Checks if IL client has released all the buffers. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_vdec::release_done(void) +{ + bool bRet = false; + + if (release_input_done()) { + if (release_output_done()) { + bRet = true; + } + } + return bRet; +} + + +/* ====================================================================== + FUNCTION + omx_vdec::ReleaseOutputDone + + DESCRIPTION + Checks if IL client has released all the buffers. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_vdec::release_output_done(void) +{ + bool bRet = false; + unsigned i=0,j=0; + + DEBUG_PRINT_LOW("Value of m_out_mem_ptr %p", m_out_mem_ptr); + if (m_out_mem_ptr) { + for (; j < drv_ctx.op_buf.actualcount ; j++) { + if (BITMASK_PRESENT(&m_out_bm_count,j)) { + break; + } + } + if (j == drv_ctx.op_buf.actualcount) { + m_out_bm_count = 0; + bRet = true; + } + } else { + m_out_bm_count = 0; + bRet = true; + } + return bRet; +} +/* ====================================================================== + FUNCTION + omx_vdec::ReleaseInputDone + + DESCRIPTION + Checks if IL client has released all the buffers. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_vdec::release_input_done(void) +{ + bool bRet = false; + unsigned i=0,j=0; + + DEBUG_PRINT_LOW("Value of m_inp_mem_ptr %p",m_inp_mem_ptr); + if (m_inp_mem_ptr) { + for (; j<drv_ctx.ip_buf.actualcount; j++) { + if ( BITMASK_PRESENT(&m_inp_bm_count,j)) { + break; + } + } + if (j==drv_ctx.ip_buf.actualcount) { + bRet = true; + } + } else { + bRet = true; + } + return bRet; +} + +OMX_ERRORTYPE omx_vdec::fill_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer) +{ + VIDC_TRACE_NAME_HIGH("FBD"); + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo = NULL; + if (!buffer || (buffer - m_out_mem_ptr) >= (int)drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("[FBD] ERROR in ptr(%p)", buffer); + return OMX_ErrorBadParameter; + } else if (output_flush_progress) { + DEBUG_PRINT_LOW("FBD: Buffer (%p) flushed", buffer); + buffer->nFilledLen = 0; + buffer->nTimeStamp = 0; + buffer->nFlags &= ~OMX_BUFFERFLAG_EXTRADATA; + buffer->nFlags &= ~QOMX_VIDEO_BUFFERFLAG_EOSEQ; + buffer->nFlags &= ~OMX_BUFFERFLAG_DATACORRUPT; + } + + if (m_debug_extradata) { + if (buffer->nFlags & QOMX_VIDEO_BUFFERFLAG_EOSEQ) { + DEBUG_PRINT_HIGH("***************************************************"); + DEBUG_PRINT_HIGH("FillBufferDone: End Of Sequence Received"); + DEBUG_PRINT_HIGH("***************************************************"); + } + + if (buffer->nFlags & OMX_BUFFERFLAG_DATACORRUPT) { + DEBUG_PRINT_HIGH("***************************************************"); + DEBUG_PRINT_HIGH("FillBufferDone: OMX_BUFFERFLAG_DATACORRUPT Received"); + DEBUG_PRINT_HIGH("***************************************************"); + } + } + + + DEBUG_PRINT_LOW("fill_buffer_done: bufhdr = %p, bufhdr->pBuffer = %p, flags: 0x%x, timestamp: %lld", + buffer, buffer->pBuffer, buffer->nFlags, buffer->nTimeStamp); + pending_output_buffers --; + VIDC_TRACE_INT_LOW("FTB-pending", pending_output_buffers); + + if (buffer->nFlags & OMX_BUFFERFLAG_EOS) { + DEBUG_PRINT_HIGH("Output EOS has been reached"); + if (!output_flush_progress) + post_event((unsigned)NULL, (unsigned)NULL, + OMX_COMPONENT_GENERATE_EOS_DONE); + + if (psource_frame) { + m_cb.EmptyBufferDone(&m_cmp, m_app_data, psource_frame); + psource_frame = NULL; + } + if (pdest_frame) { + pdest_frame->nFilledLen = 0; + m_input_free_q.insert_entry((unsigned long) pdest_frame,(unsigned)NULL, + (unsigned)NULL); + pdest_frame = NULL; + } + } + +#ifdef OUTPUT_EXTRADATA_LOG + if (outputExtradataFile) { + int buf_index = buffer - m_out_mem_ptr; + OMX_U8 *pBuffer = (OMX_U8 *)(drv_ctx.ptr_outputbuffer[buf_index].bufferaddr); + + OMX_OTHER_EXTRADATATYPE *p_extra = NULL; + p_extra = (OMX_OTHER_EXTRADATATYPE *) + ((unsigned long)(pBuffer + buffer->nOffset + buffer->nFilledLen + 3)&(~3)); + + while (p_extra && (OMX_U8*)p_extra < (pBuffer + buffer->nAllocLen) ) { + DEBUG_PRINT_LOW("WRITING extradata, size=%d,type=%x", + p_extra->nSize, p_extra->eType); + fwrite (p_extra,1,p_extra->nSize,outputExtradataFile); + + if (p_extra->eType == OMX_ExtraDataNone) { + break; + } + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + p_extra->nSize); + } + } +#endif + + /* For use buffer we need to copy the data */ + if (!output_flush_progress) { + /* This is the error check for non-recoverable errros */ + bool is_duplicate_ts_valid = true; + bool is_interlaced = (drv_ctx.interlace != VDEC_InterlaceFrameProgressive); + + if (output_capability == V4L2_PIX_FMT_MPEG4 || + output_capability == V4L2_PIX_FMT_MPEG2 || + output_capability == V4L2_PIX_FMT_DIVX || + output_capability == V4L2_PIX_FMT_DIVX_311) + is_duplicate_ts_valid = false; + + if ((output_capability == V4L2_PIX_FMT_H264 || + output_capability == V4L2_PIX_FMT_H264_MVC) && + is_interlaced) { + if (buffer->nFlags & QOMX_VIDEO_BUFFERFLAG_MBAFF) { + is_interlaced = false; + } + } + + if (buffer->nFilledLen > 0) { + time_stamp_dts.get_next_timestamp(buffer, + is_interlaced && is_duplicate_ts_valid); + if (m_debug_timestamp) { + { + OMX_TICKS expected_ts = 0; + m_timestamp_list.pop_min_ts(expected_ts); + if (is_interlaced && is_duplicate_ts_valid) { + m_timestamp_list.pop_min_ts(expected_ts); + } + DEBUG_PRINT_LOW("Current timestamp (%lld),Popped TIMESTAMP (%lld) from list", + buffer->nTimeStamp, expected_ts); + + if (buffer->nTimeStamp != expected_ts) { + DEBUG_PRINT_ERROR("ERROR in omx_vdec::async_message_process timestamp Check"); + } + } + } + } + } + VIDC_TRACE_INT_LOW("FBD-TS", buffer->nTimeStamp / 1000); + + if (m_cb.FillBufferDone) { + if (buffer->nFilledLen > 0) { + if (arbitrary_bytes) + adjust_timestamp(buffer->nTimeStamp); + else + set_frame_rate(buffer->nTimeStamp); + + proc_frms++; + if (perf_flag) { + if (1 == proc_frms) { + dec_time.stop(); + latency = dec_time.processing_time_us() - latency; + DEBUG_PRINT_HIGH(">>> FBD Metrics: Latency(%.2f)mS", latency / 1e3); + dec_time.start(); + fps_metrics.start(); + } + if (buffer->nFlags & OMX_BUFFERFLAG_EOS) { + OMX_U64 proc_time = 0; + fps_metrics.stop(); + proc_time = fps_metrics.processing_time_us(); + DEBUG_PRINT_HIGH(">>> FBD Metrics: proc_frms(%u) proc_time(%.2f)S fps(%.2f)", + (unsigned int)proc_frms, (float)proc_time / 1e6, + (float)(1e6 * proc_frms) / proc_time); + } + } + } + if (buffer->nFlags & OMX_BUFFERFLAG_EOS) { + prev_ts = LLONG_MAX; + rst_prev_ts = true; + proc_frms = 0; + } + + pPMEMInfo = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) + ((OMX_QCOM_PLATFORM_PRIVATE_LIST *) + buffer->pPlatformPrivate)->entryList->entry; + DEBUG_PRINT_LOW("Before FBD callback Accessed Pmeminfo %lu",pPMEMInfo->pmem_fd); + OMX_BUFFERHEADERTYPE *il_buffer; + il_buffer = client_buffers.get_il_buf_hdr(buffer); + OMX_U32 current_framerate = (int)(drv_ctx.frame_rate.fps_numerator / drv_ctx.frame_rate.fps_denominator); + + if (il_buffer && m_last_rendered_TS >= 0) { + OMX_TICKS ts_delta = (OMX_TICKS)llabs(il_buffer->nTimeStamp - m_last_rendered_TS); + + // Current frame can be send for rendering if + // (a) current FPS is <= 60 + // (b) is the next frame after the frame with TS 0 + // (c) is the first frame after seek + // (d) the delta TS b\w two consecutive frames is > 16 ms + // (e) its TS is equal to previous frame TS + // (f) if marked EOS + + if(current_framerate <= 60 || m_last_rendered_TS == 0 || + il_buffer->nTimeStamp == 0 || ts_delta >= 16000 || + ts_delta == 0 || (il_buffer->nFlags & OMX_BUFFERFLAG_EOS)) { + m_last_rendered_TS = il_buffer->nTimeStamp; + } else { + //mark for droping + buffer->nFilledLen = 0; + } + + DEBUG_PRINT_LOW(" -- %s Frame -- info:: fps(%d) lastRenderTime(%lld) bufferTs(%lld) ts_delta(%lld)", + buffer->nFilledLen? "Rendering":"Dropping",current_framerate,m_last_rendered_TS, + il_buffer->nTimeStamp,ts_delta); + + //above code makes sure that delta b\w two consecutive frames is not + //greater than 16ms, slow-mo feature, so cap fps to max 60 + if (current_framerate > 60 ) { + current_framerate = 60; + } + } + + // add current framerate to gralloc meta data + if (buffer->nFilledLen > 0 && m_drc_enable && m_enable_android_native_buffers && m_out_mem_ptr) { + //If valid fps was received, directly send it to display for the 1st fbd. + //Otherwise, calculate fps using fbd timestamps, + // when received 2 fbds, send a coarse fps, + // when received 30 fbds, update fps again as it should be + // more accurate than the one when only 2 fbds received. + //For other frames, set value 0 to inform that refresh rate has no update + float refresh_rate = m_fps_prev; + if (m_fps_received) { + if (1 == proc_frms) { + refresh_rate = m_fps_received / (float)(1<<16); + } + } else { + if (2 == proc_frms || 30 == proc_frms) { + refresh_rate = drv_ctx.frame_rate.fps_numerator / (float) drv_ctx.frame_rate.fps_denominator; + } + } + if (refresh_rate > 60) { + refresh_rate = 60; + } + DEBUG_PRINT_LOW("frc set refresh_rate %f, frame %d", refresh_rate, proc_frms); + OMX_U32 buf_index = buffer - m_out_mem_ptr; + setMetaData((private_handle_t *)native_buffer[buf_index].privatehandle, + UPDATE_REFRESH_RATE, (void*)&refresh_rate); + m_fps_prev = refresh_rate; + } + + if (buffer->nFilledLen && m_enable_android_native_buffers && m_out_mem_ptr) { + OMX_U32 buf_index = buffer - m_out_mem_ptr; + DEBUG_PRINT_LOW("stereo_output_mode = %d",stereo_output_mode); + setMetaData((private_handle_t *)native_buffer[buf_index].privatehandle, + S3D_FORMAT, (void*)&stereo_output_mode); + } + + if (il_buffer) { + log_output_buffers(il_buffer); + if (dynamic_buf_mode) { + unsigned int nPortIndex = 0; + nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)client_buffers.get_il_buf_hdr()); + + // Since we're passing around handles, adjust nFilledLen and nAllocLen + // to size of the handle. Do it _after_ log_output_buffers which + // requires the respective sizes to be accurate. + + buffer->nAllocLen = sizeof(struct VideoDecoderOutputMetaData); + buffer->nFilledLen = buffer->nFilledLen ? + sizeof(struct VideoDecoderOutputMetaData) : 0; + + //Clear graphic buffer handles in dynamic mode + if (nPortIndex < drv_ctx.op_buf.actualcount && + nPortIndex < MAX_NUM_INPUT_OUTPUT_BUFFERS) { + native_buffer[nPortIndex].privatehandle = NULL; + native_buffer[nPortIndex].nativehandle = NULL; + } else { + DEBUG_PRINT_ERROR("[FBD]Invalid native_buffer index: %d", nPortIndex); + return OMX_ErrorBadParameter; + } + } + m_cb.FillBufferDone (hComp,m_app_data,il_buffer); + } else { + DEBUG_PRINT_ERROR("Invalid buffer address from get_il_buf_hdr"); + return OMX_ErrorBadParameter; + } + DEBUG_PRINT_LOW("After Fill Buffer Done callback %lu",pPMEMInfo->pmem_fd); + } else { + return OMX_ErrorBadParameter; + } + +#ifdef ADAPTIVE_PLAYBACK_SUPPORTED + if (m_smoothstreaming_mode && m_out_mem_ptr) { + OMX_U32 buf_index = buffer - m_out_mem_ptr; + BufferDim_t dim; + private_handle_t *private_handle = NULL; + dim.sliceWidth = framesize.nWidth; + dim.sliceHeight = framesize.nHeight; + if (buf_index < drv_ctx.op_buf.actualcount && + buf_index < MAX_NUM_INPUT_OUTPUT_BUFFERS && + native_buffer[buf_index].privatehandle) + private_handle = native_buffer[buf_index].privatehandle; + if (private_handle) { + DEBUG_PRINT_LOW("set metadata: update buf-geometry with stride %d slice %d", + dim.sliceWidth, dim.sliceHeight); + setMetaData(private_handle, UPDATE_BUFFER_GEOMETRY, (void*)&dim); + } + } +#endif + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::empty_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + VIDC_TRACE_NAME_HIGH("EBD"); + int nBufferIndex = buffer - m_inp_mem_ptr; + + if (buffer == NULL || (nBufferIndex >= (int)drv_ctx.ip_buf.actualcount)) { + DEBUG_PRINT_ERROR("empty_buffer_done: ERROR bufhdr = %p", buffer); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("empty_buffer_done: bufhdr = %p, bufhdr->pBuffer = %p, bufhdr->nFlags = 0x%x", + buffer, buffer->pBuffer, buffer->nFlags); + pending_input_buffers--; + VIDC_TRACE_INT_LOW("ETB-pending", pending_input_buffers); + + if (arbitrary_bytes) { + if (pdest_frame == NULL && input_flush_progress == false) { + DEBUG_PRINT_LOW("Push input from buffer done address of Buffer %p",buffer); + pdest_frame = buffer; + buffer->nFilledLen = 0; + buffer->nTimeStamp = LLONG_MAX; + push_input_buffer (hComp); + } else { + DEBUG_PRINT_LOW("Push buffer into freeq address of Buffer %p",buffer); + buffer->nFilledLen = 0; + if (!m_input_free_q.insert_entry((unsigned long)buffer, + (unsigned)NULL, (unsigned)NULL)) { + DEBUG_PRINT_ERROR("ERROR:i/p free Queue is FULL Error"); + } + } + } else if (m_cb.EmptyBufferDone) { + buffer->nFilledLen = 0; + if (input_use_buffer == true) { + buffer = &m_inp_heap_ptr[buffer-m_inp_mem_ptr]; + } + + /* Restore the FD that we over-wrote in ETB */ + if (m_input_pass_buffer_fd) { + buffer->pBuffer = (OMX_U8*)(uintptr_t)drv_ctx.ptr_inputbuffer[nBufferIndex].pmem_fd; + } + + m_cb.EmptyBufferDone(hComp ,m_app_data, buffer); + } + return OMX_ErrorNone; +} + +int omx_vdec::async_message_process (void *context, void* message) +{ + omx_vdec* omx = NULL; + struct vdec_msginfo *vdec_msg = NULL; + OMX_BUFFERHEADERTYPE* omxhdr = NULL; + struct v4l2_buffer *v4l2_buf_ptr = NULL; + struct v4l2_plane *plane = NULL; + struct vdec_output_frameinfo *output_respbuf = NULL; + int rc=1; + if (context == NULL || message == NULL) { + DEBUG_PRINT_ERROR("FATAL ERROR in omx_vdec::async_message_process NULL Check"); + return -1; + } + vdec_msg = (struct vdec_msginfo *)message; + + omx = reinterpret_cast<omx_vdec*>(context); + + switch (vdec_msg->msgcode) { + + case VDEC_MSG_EVT_HW_ERROR: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_HARDWARE_ERROR); + break; + + case VDEC_MSG_EVT_HW_OVERLOAD: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_HARDWARE_OVERLOAD); + break; + + case VDEC_MSG_EVT_HW_UNSUPPORTED: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING); + break; + + case VDEC_MSG_RESP_START_DONE: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_START_DONE); + break; + + case VDEC_MSG_RESP_STOP_DONE: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_STOP_DONE); + break; + + case VDEC_MSG_RESP_RESUME_DONE: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_RESUME_DONE); + break; + + case VDEC_MSG_RESP_PAUSE_DONE: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_PAUSE_DONE); + break; + + case VDEC_MSG_RESP_FLUSH_INPUT_DONE: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH); + break; + case VDEC_MSG_RESP_FLUSH_OUTPUT_DONE: + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH); + break; + case VDEC_MSG_RESP_INPUT_FLUSHED: + case VDEC_MSG_RESP_INPUT_BUFFER_DONE: + + /* omxhdr = (OMX_BUFFERHEADERTYPE* ) + vdec_msg->msgdata.input_frame_clientdata; */ + + v4l2_buf_ptr = (v4l2_buffer*)vdec_msg->msgdata.input_frame_clientdata; + if (omx->m_inp_mem_ptr == NULL || v4l2_buf_ptr == NULL || + v4l2_buf_ptr->index >= omx->drv_ctx.ip_buf.actualcount) { + omxhdr = NULL; + vdec_msg->status_code = VDEC_S_EFATAL; + break; + + } + omxhdr = omx->m_inp_mem_ptr + v4l2_buf_ptr->index; + + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_INPUT_UNSUPPORTED) { + DEBUG_PRINT_HIGH("Unsupported input"); + omx->post_event ((unsigned)NULL, vdec_msg->status_code,\ + OMX_COMPONENT_GENERATE_HARDWARE_ERROR); + } + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_DATA_CORRUPT) { + omxhdr->nFlags |= OMX_BUFFERFLAG_DATACORRUPT; + vdec_msg->status_code = VDEC_S_INPUT_BITSTREAM_ERR; + } + if (omxhdr->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { + + DEBUG_PRINT_LOW("Decrement codec_config buffer counter"); + android_atomic_dec(&omx->m_queued_codec_config_count); + if ((android_atomic_add(0, &omx->m_queued_codec_config_count) == 0) && + BITMASK_PRESENT(&omx->m_flags, OMX_COMPONENT_FLUSH_DEFERRED)) { + DEBUG_PRINT_LOW("sem post for CODEC CONFIG buffer"); + sem_post(&omx->m_safe_flush); + } + } + if (v4l2_buf_ptr->flags & V4L2_BUF_FLAG_KEYFRAME || + v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_IDRFRAME) { + omxhdr->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; + } + omx->post_event ((unsigned long)omxhdr,vdec_msg->status_code, + OMX_COMPONENT_GENERATE_EBD); + break; + case VDEC_MSG_EVT_INFO_FIELD_DROPPED: + int64_t *timestamp; + timestamp = (int64_t *) malloc(sizeof(int64_t)); + if (timestamp) { + *timestamp = vdec_msg->msgdata.output_frame.time_stamp; + omx->post_event ((unsigned long)timestamp, vdec_msg->status_code, + OMX_COMPONENT_GENERATE_INFO_FIELD_DROPPED); + DEBUG_PRINT_HIGH("Field dropped time stamp is %lld", + (long long)vdec_msg->msgdata.output_frame.time_stamp); + } + break; + case VDEC_MSG_RESP_OUTPUT_FLUSHED: + case VDEC_MSG_RESP_OUTPUT_BUFFER_DONE: + + v4l2_buf_ptr = (v4l2_buffer*)vdec_msg->msgdata.output_frame.client_data; + if (v4l2_buf_ptr == NULL || omx->m_out_mem_ptr == NULL || + v4l2_buf_ptr->index >= omx->drv_ctx.op_buf.actualcount) { + omxhdr = NULL; + vdec_msg->status_code = VDEC_S_EFATAL; + break; + } + plane = v4l2_buf_ptr->m.planes; + omxhdr = omx->m_out_mem_ptr + v4l2_buf_ptr->index; + + if (omxhdr && omxhdr->pOutputPortPrivate && + ((omxhdr - omx->m_out_mem_ptr) < (int)omx->drv_ctx.op_buf.actualcount) && + (((struct vdec_output_frameinfo *)omxhdr->pOutputPortPrivate + - omx->drv_ctx.ptr_respbuffer) < (int)omx->drv_ctx.op_buf.actualcount)) { + + if (vdec_msg->msgdata.output_frame.len <= omxhdr->nAllocLen) { + omxhdr->nFilledLen = vdec_msg->msgdata.output_frame.len; + omxhdr->nOffset = vdec_msg->msgdata.output_frame.offset; + omxhdr->nTimeStamp = vdec_msg->msgdata.output_frame.time_stamp; + omxhdr->nFlags = 0; + + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_EOS) { + omxhdr->nFlags |= OMX_BUFFERFLAG_EOS; + //rc = -1; + } + if (omxhdr->nFilledLen) { + omxhdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; + } + if (v4l2_buf_ptr->flags & V4L2_BUF_FLAG_KEYFRAME || v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_IDRFRAME) { + omxhdr->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; + } else { + omxhdr->nFlags &= ~OMX_BUFFERFLAG_SYNCFRAME; + } + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_EOSEQ) { + omxhdr->nFlags |= QOMX_VIDEO_BUFFERFLAG_EOSEQ; + } + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_DECODEONLY) { + omxhdr->nFlags |= OMX_BUFFERFLAG_DECODEONLY; + } + if (v4l2_buf_ptr->flags & V4L2_MSM_BUF_FLAG_MBAFF) { + omxhdr->nFlags |= QOMX_VIDEO_BUFFERFLAG_MBAFF; + } + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_READONLY) { + omxhdr->nFlags |= OMX_BUFFERFLAG_READONLY; + DEBUG_PRINT_LOW("F_B_D: READONLY BUFFER - REFERENCE WITH F/W fd = %d", + omx->drv_ctx.ptr_outputbuffer[v4l2_buf_ptr->index].pmem_fd); + } + + if (omxhdr && (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_DROP_FRAME) && + !omx->output_flush_progress && + !(v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_DECODEONLY) && + !(v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_EOS)) { + unsigned int index = v4l2_buf_ptr->index; + unsigned int extra_idx = EXTRADATA_IDX(omx->drv_ctx.num_planes); + omx->time_stamp_dts.remove_time_stamp( + omxhdr->nTimeStamp, + (omx->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) + ?true:false); + plane[0].bytesused = 0; + plane[0].m.userptr = + (unsigned long)omx->drv_ctx.ptr_outputbuffer[index].bufferaddr - + (unsigned long)omx->drv_ctx.ptr_outputbuffer[index].offset; + plane[0].reserved[0] = omx->drv_ctx.ptr_outputbuffer[index].pmem_fd; + plane[0].reserved[1] = omx->drv_ctx.ptr_outputbuffer[index].offset; + plane[0].data_offset = 0; + v4l2_buf_ptr->flags = 0x0; + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].bytesused = 0; + plane[extra_idx].length = omx->drv_ctx.extradata_info.buffer_size; + plane[extra_idx].m.userptr = (long unsigned int) (omx->drv_ctx.extradata_info.uaddr + index * omx->drv_ctx.extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = omx->drv_ctx.extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = v4l2_buf_ptr->index * omx->drv_ctx.extradata_info.buffer_size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index higher than expected: %u", extra_idx); + return -1; + } + + DEBUG_PRINT_LOW("SENDING FTB TO F/W from async_message_process - fd[0] = %d fd[1] = %d offset[1] = %d in_flush = %d", + plane[0].reserved[0],plane[extra_idx].reserved[0], plane[extra_idx].reserved[1], omx->output_flush_progress); + if(ioctl(omx->drv_ctx.video_driver_fd, VIDIOC_QBUF, v4l2_buf_ptr)) { + DEBUG_PRINT_ERROR("Failed to queue buffer back to driver: %d, %d, %d", v4l2_buf_ptr->length, v4l2_buf_ptr->m.planes[0].reserved[0], v4l2_buf_ptr->m.planes[1].reserved[0]); + return -1; + } + break; + } + if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_DATA_CORRUPT) { + omxhdr->nFlags |= OMX_BUFFERFLAG_DATACORRUPT; + } + + output_respbuf = (struct vdec_output_frameinfo *)\ + omxhdr->pOutputPortPrivate; + if (!output_respbuf) { + DEBUG_PRINT_ERROR("async_message_process: invalid output buf received"); + return -1; + } + output_respbuf->len = vdec_msg->msgdata.output_frame.len; + output_respbuf->offset = vdec_msg->msgdata.output_frame.offset; + + if (v4l2_buf_ptr->flags & V4L2_BUF_FLAG_KEYFRAME) { + output_respbuf->pic_type = PICTURE_TYPE_I; + } + if (v4l2_buf_ptr->flags & V4L2_BUF_FLAG_PFRAME) { + output_respbuf->pic_type = PICTURE_TYPE_P; + } + if (v4l2_buf_ptr->flags & V4L2_BUF_FLAG_BFRAME) { + output_respbuf->pic_type = PICTURE_TYPE_B; + } + + if (vdec_msg->msgdata.output_frame.len) { + if (!omx->output_flush_progress && (omxhdr->nFilledLen > 0)) { + // set the default colorspace advised by client, since the bitstream may be + // devoid of colorspace-info. + if (omx->m_enable_android_native_buffers) { + ColorSpace_t color_space = ITU_R_601; + + // Disabled ? + // WA for VP8. Vp8 encoder does not embed color-info (yet!). + // Encoding RGBA results in 601-LR for all resolutions. + // This conflicts with the client't defaults which are based on resolution. + // Eg: 720p will be encoded as 601-LR. Client will say 709. + // Re-enable this code once vp8 encoder generates color-info and hence the + // decoder will be able to override with the correct source color. +#if 0 + switch (omx->m_client_color_space.sAspects.mPrimaries) { + case ColorAspects::PrimariesBT601_6_625: + case ColorAspects::PrimariesBT601_6_525: + { + color_space = omx->m_client_color_space.sAspects.mRange == ColorAspects::RangeFull ? + ITU_R_601_FR : ITU_R_601; + break; + } + case ColorAspects::PrimariesBT709_5: + { + color_space = ITU_R_709; + break; + } + default: + { + break; + } + } +#endif + DEBUG_PRINT_LOW("setMetaData for Color Space (client) = 0x%x (601=%u FR=%u 709=%u)", + color_space, ITU_R_601, ITU_R_601_FR, ITU_R_709); + omx->set_colorspace_in_handle(color_space, omxhdr - omx->m_out_mem_ptr); + } + } + + DEBUG_PRINT_LOW("Processing extradata"); + omx->handle_extradata(omxhdr); + + if (omx->m_extradata_info.output_crop_updated) { + DEBUG_PRINT_LOW("Read FBD crop from output extra data"); + vdec_msg->msgdata.output_frame.framesize.left = omx->m_extradata_info.output_crop_rect.nLeft; + vdec_msg->msgdata.output_frame.framesize.top = omx->m_extradata_info.output_crop_rect.nTop; + vdec_msg->msgdata.output_frame.framesize.right = omx->m_extradata_info.output_crop_rect.nWidth; + vdec_msg->msgdata.output_frame.framesize.bottom = omx->m_extradata_info.output_crop_rect.nHeight; + vdec_msg->msgdata.output_frame.picsize.frame_width = omx->m_extradata_info.output_width; + vdec_msg->msgdata.output_frame.picsize.frame_height = omx->m_extradata_info.output_height; + } else { + DEBUG_PRINT_LOW("Read FBD crop from v4l2 reserved fields"); + vdec_msg->msgdata.output_frame.framesize.left = plane[0].reserved[2]; + vdec_msg->msgdata.output_frame.framesize.top = plane[0].reserved[3]; + vdec_msg->msgdata.output_frame.framesize.right = plane[0].reserved[2] + plane[0].reserved[4]; + vdec_msg->msgdata.output_frame.framesize.bottom = plane[0].reserved[3] + plane[0].reserved[5]; + vdec_msg->msgdata.output_frame.picsize.frame_width = plane[0].reserved[6]; + vdec_msg->msgdata.output_frame.picsize.frame_height = plane[0].reserved[7]; + + /* Copy these values back to OMX internal variables to make both handlign same*/ + + omx->m_extradata_info.output_crop_rect.nLeft = vdec_msg->msgdata.output_frame.framesize.left; + omx->m_extradata_info.output_crop_rect.nTop = vdec_msg->msgdata.output_frame.framesize.top; + omx->m_extradata_info.output_crop_rect.nWidth = vdec_msg->msgdata.output_frame.framesize.right; + omx->m_extradata_info.output_crop_rect.nHeight = vdec_msg->msgdata.output_frame.framesize.bottom; + omx->m_extradata_info.output_width = vdec_msg->msgdata.output_frame.picsize.frame_width; + omx->m_extradata_info.output_height = vdec_msg->msgdata.output_frame.picsize.frame_height; + } + } + + vdec_msg->msgdata.output_frame.bufferaddr = + omx->drv_ctx.ptr_outputbuffer[v4l2_buf_ptr->index].bufferaddr; + + if (vdec_msg->msgdata.output_frame.len) + memcpy(&omx->drv_ctx.frame_size, + &vdec_msg->msgdata.output_frame.framesize, + sizeof(struct vdec_framesize)); + + DEBUG_PRINT_LOW("[RespBufDone] Fd(%d) Buf(%p) Ts(%lld) PicType(%u) Flags (0x%x)" + " FillLen(%u) Crop: L(%u) T(%u) R(%u) B(%u)", + omx->drv_ctx.ptr_outputbuffer[v4l2_buf_ptr->index].pmem_fd, + omxhdr, (long long)vdec_msg->msgdata.output_frame.time_stamp, + vdec_msg->msgdata.output_frame.pic_type, v4l2_buf_ptr->flags, + (unsigned int)vdec_msg->msgdata.output_frame.len, + vdec_msg->msgdata.output_frame.framesize.left, + vdec_msg->msgdata.output_frame.framesize.top, + vdec_msg->msgdata.output_frame.framesize.right, + vdec_msg->msgdata.output_frame.framesize.bottom); + + /* Post event if resolution OR crop changed */ + /* filled length will be changed if resolution changed */ + /* Crop parameters can be changed even without resolution change */ + if (omxhdr->nFilledLen + && ((omx->prev_n_filled_len != omxhdr->nFilledLen) + || (omx->drv_ctx.frame_size.left != vdec_msg->msgdata.output_frame.framesize.left) + || (omx->drv_ctx.frame_size.top != vdec_msg->msgdata.output_frame.framesize.top) + || (omx->drv_ctx.frame_size.right != vdec_msg->msgdata.output_frame.framesize.right) + || (omx->drv_ctx.frame_size.bottom != vdec_msg->msgdata.output_frame.framesize.bottom) + || (omx->drv_ctx.video_resolution.frame_width != vdec_msg->msgdata.output_frame.picsize.frame_width) + || (omx->drv_ctx.video_resolution.frame_height != vdec_msg->msgdata.output_frame.picsize.frame_height) )) { + + DEBUG_PRINT_HIGH("Parameters Changed From: Len: %u, WxH: %dx%d, L: %u, T: %u, R: %u, B: %u --> Len: %u, WxH: %dx%d, L: %u, T: %u, R: %u, B: %u", + omx->prev_n_filled_len, + omx->drv_ctx.video_resolution.frame_width, + omx->drv_ctx.video_resolution.frame_height, + omx->drv_ctx.frame_size.left, omx->drv_ctx.frame_size.top, + omx->drv_ctx.frame_size.right, omx->drv_ctx.frame_size.bottom, + omxhdr->nFilledLen, vdec_msg->msgdata.output_frame.picsize.frame_width, + vdec_msg->msgdata.output_frame.picsize.frame_height, + vdec_msg->msgdata.output_frame.framesize.left, + vdec_msg->msgdata.output_frame.framesize.top, + vdec_msg->msgdata.output_frame.framesize.right, + vdec_msg->msgdata.output_frame.framesize.bottom); + + omx->drv_ctx.video_resolution.frame_width = + vdec_msg->msgdata.output_frame.picsize.frame_width; + omx->drv_ctx.video_resolution.frame_height = + vdec_msg->msgdata.output_frame.picsize.frame_height; + if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12) { + omx->drv_ctx.video_resolution.stride = + VENUS_Y_STRIDE(COLOR_FMT_NV12, omx->drv_ctx.video_resolution.frame_width); + omx->drv_ctx.video_resolution.scan_lines = + VENUS_Y_SCANLINES(COLOR_FMT_NV12, omx->drv_ctx.video_resolution.frame_height); + } else if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12_UBWC) { + omx->drv_ctx.video_resolution.stride = + VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, omx->drv_ctx.video_resolution.frame_width); + omx->drv_ctx.video_resolution.scan_lines = + VENUS_Y_SCANLINES(COLOR_FMT_NV12_UBWC, omx->drv_ctx.video_resolution.frame_height); + } else if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12_TP10_UBWC) { + omx->drv_ctx.video_resolution.stride = + VENUS_Y_STRIDE(COLOR_FMT_NV12_BPP10_UBWC, omx->drv_ctx.video_resolution.frame_width); + omx->drv_ctx.video_resolution.scan_lines = + VENUS_Y_SCANLINES(COLOR_FMT_NV12_BPP10_UBWC, omx->drv_ctx.video_resolution.frame_height); + } + + omx->post_event(OMX_CORE_OUTPUT_PORT_INDEX, + OMX_IndexConfigCommonOutputCrop, + OMX_COMPONENT_GENERATE_PORT_RECONFIG); + } + + if (omxhdr->nFilledLen) + omx->prev_n_filled_len = omxhdr->nFilledLen; + + if (omxhdr && omxhdr->nFilledLen && !omx->high_fps) { + omx->request_perf_level(VIDC_NOMINAL); + } + if (omx->output_use_buffer && omxhdr->pBuffer && + vdec_msg->msgdata.output_frame.bufferaddr) + memcpy ( omxhdr->pBuffer, (void *) + ((unsigned long)vdec_msg->msgdata.output_frame.bufferaddr + + (unsigned long)vdec_msg->msgdata.output_frame.offset), + vdec_msg->msgdata.output_frame.len); + } else { + DEBUG_PRINT_ERROR("Invalid filled length = %u, buffer size = %u, prev_length = %u", + (unsigned int)vdec_msg->msgdata.output_frame.len, + omxhdr->nAllocLen, omx->prev_n_filled_len); + omxhdr->nFilledLen = 0; + } + + omx->post_event ((unsigned long)omxhdr, vdec_msg->status_code, + OMX_COMPONENT_GENERATE_FBD); + + } else if (vdec_msg->msgdata.output_frame.flags & OMX_BUFFERFLAG_EOS) { + omx->post_event ((unsigned long)NULL, vdec_msg->status_code, + OMX_COMPONENT_GENERATE_EOS_DONE); + } else { + omx->post_event ((unsigned int)NULL, vdec_msg->status_code, + OMX_COMPONENT_GENERATE_HARDWARE_ERROR); + } + break; + case VDEC_MSG_EVT_CONFIG_CHANGED: + DEBUG_PRINT_HIGH("Port settings changed"); + omx->m_reconfig_width = vdec_msg->msgdata.output_frame.picsize.frame_width; + omx->m_reconfig_height = vdec_msg->msgdata.output_frame.picsize.frame_height; + omx->post_event (OMX_CORE_OUTPUT_PORT_INDEX, OMX_IndexParamPortDefinition, + OMX_COMPONENT_GENERATE_PORT_RECONFIG); + if (!omx->high_fps) { + omx->request_perf_level(VIDC_NOMINAL); + } + break; + default: + break; + } + return rc; +} + +OMX_ERRORTYPE omx_vdec::empty_this_buffer_proxy_arbitrary ( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ) +{ + unsigned address,p2,id; + DEBUG_PRINT_LOW("Empty this arbitrary"); + + if (buffer == NULL) { + return OMX_ErrorBadParameter; + } + DEBUG_PRINT_LOW("ETBProxyArb: bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer); + DEBUG_PRINT_LOW("ETBProxyArb: nFilledLen %u, flags %u, timestamp %lld", + (unsigned int)buffer->nFilledLen, (unsigned int)buffer->nFlags, buffer->nTimeStamp); + + /* return zero length and not an EOS buffer */ + /* return buffer if input flush in progress */ + if ((input_flush_progress == true) || ((buffer->nFilledLen == 0) && + ((buffer->nFlags & OMX_BUFFERFLAG_EOS) == 0))) { + DEBUG_PRINT_HIGH("return zero legth buffer or flush in progress"); + m_cb.EmptyBufferDone (hComp,m_app_data,buffer); + return OMX_ErrorNone; + } + + if (psource_frame == NULL) { + DEBUG_PRINT_LOW("Set Buffer as source Buffer %p time stamp %lld",buffer,buffer->nTimeStamp); + psource_frame = buffer; + DEBUG_PRINT_LOW("Try to Push One Input Buffer "); + push_input_buffer (hComp); + } else { + DEBUG_PRINT_LOW("Push the source buffer into pendingq %p",buffer); + if (!m_input_pending_q.insert_entry((unsigned long)buffer, (unsigned)NULL, + (unsigned)NULL)) { + return OMX_ErrorBadParameter; + } + } + + if (codec_config_flag && !(buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { + codec_config_flag = false; + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::push_input_buffer (OMX_HANDLETYPE hComp) +{ + unsigned long address,p2,id; + OMX_ERRORTYPE ret = OMX_ErrorNone; + + if (pdest_frame == NULL || psource_frame == NULL) { + /*Check if we have a destination buffer*/ + if (pdest_frame == NULL) { + DEBUG_PRINT_LOW("Get a Destination buffer from the queue"); + if (m_input_free_q.m_size) { + m_input_free_q.pop_entry(&address,&p2,&id); + pdest_frame = (OMX_BUFFERHEADERTYPE *)address; + pdest_frame->nFilledLen = 0; + pdest_frame->nTimeStamp = LLONG_MAX; + DEBUG_PRINT_LOW("Address of Pmem Buffer %p",pdest_frame); + } + } + + /*Check if we have a destination buffer*/ + if (psource_frame == NULL) { + DEBUG_PRINT_LOW("Get a source buffer from the queue"); + if (m_input_pending_q.m_size) { + m_input_pending_q.pop_entry(&address,&p2,&id); + psource_frame = (OMX_BUFFERHEADERTYPE *)address; + DEBUG_PRINT_LOW("Next source Buffer %p time stamp %lld",psource_frame, + psource_frame->nTimeStamp); + DEBUG_PRINT_LOW("Next source Buffer flag %u length %u", + (unsigned int)psource_frame->nFlags, (unsigned int)psource_frame->nFilledLen); + + } + } + + } + + while ((pdest_frame != NULL) && (psource_frame != NULL)) { + switch (codec_type_parse) { + case CODEC_TYPE_MPEG4: + case CODEC_TYPE_H263: + case CODEC_TYPE_MPEG2: + ret = push_input_sc_codec(hComp); + break; + case CODEC_TYPE_H264: + ret = push_input_h264(hComp); + break; + case CODEC_TYPE_HEVC: + ret = push_input_hevc(hComp); + break; + case CODEC_TYPE_VC1: + ret = push_input_vc1(hComp); + break; + default: + break; + } + if (ret != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("Pushing input Buffer Failed"); + omx_report_error (); + break; + } + } + + return ret; +} + +OMX_ERRORTYPE omx_vdec::push_input_sc_codec(OMX_HANDLETYPE hComp) +{ + OMX_U32 partial_frame = 1; + OMX_BOOL generate_ebd = OMX_TRUE; + unsigned long address = 0, p2 = 0, id = 0; + + DEBUG_PRINT_LOW("Start Parsing the bit stream address %p TimeStamp %lld", + psource_frame,psource_frame->nTimeStamp); + if (m_frame_parser.parse_sc_frame(psource_frame, + pdest_frame,&partial_frame) == -1) { + DEBUG_PRINT_ERROR("Error In Parsing Return Error"); + return OMX_ErrorBadParameter; + } + + if (partial_frame == 0) { + DEBUG_PRINT_LOW("Frame size %u source %p frame count %d", + (unsigned int)pdest_frame->nFilledLen,psource_frame,frame_count); + + + DEBUG_PRINT_LOW("TimeStamp updated %lld", pdest_frame->nTimeStamp); + /*First Parsed buffer will have only header Hence skip*/ + if (frame_count == 0) { + DEBUG_PRINT_LOW("H263/MPEG4 Codec First Frame "); + + if (codec_type_parse == CODEC_TYPE_MPEG4 || + codec_type_parse == CODEC_TYPE_DIVX) { + mp4StreamType psBits; + psBits.data = pdest_frame->pBuffer + pdest_frame->nOffset; + psBits.numBytes = pdest_frame->nFilledLen; + mp4_headerparser.parseHeader(&psBits); + } + + frame_count++; + } else { + pdest_frame->nFlags &= ~OMX_BUFFERFLAG_EOS; + if (pdest_frame->nFilledLen) { + /*Push the frame to the Decoder*/ + if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + frame_count++; + pdest_frame = NULL; + + if (m_input_free_q.m_size) { + m_input_free_q.pop_entry(&address,&p2,&id); + pdest_frame = (OMX_BUFFERHEADERTYPE *) address; + pdest_frame->nFilledLen = 0; + } + } else if (!(psource_frame->nFlags & OMX_BUFFERFLAG_EOS)) { + DEBUG_PRINT_ERROR("Zero len buffer return back to POOL"); + m_input_free_q.insert_entry((unsigned long) pdest_frame, (unsigned)NULL, + (unsigned)NULL); + pdest_frame = NULL; + } + } + } else { + DEBUG_PRINT_LOW("Not a Complete Frame %u", (unsigned int)pdest_frame->nFilledLen); + /*Check if Destination Buffer is full*/ + if (pdest_frame->nAllocLen == + pdest_frame->nFilledLen + pdest_frame->nOffset) { + DEBUG_PRINT_ERROR("ERROR:Frame Not found though Destination Filled"); + return OMX_ErrorStreamCorrupt; + } + } + + if (psource_frame->nFilledLen == 0) { + if (psource_frame->nFlags & OMX_BUFFERFLAG_EOS) { + if (pdest_frame) { + pdest_frame->nFlags |= psource_frame->nFlags; + pdest_frame->nTimeStamp = psource_frame->nTimeStamp; + DEBUG_PRINT_LOW("Frame Found start Decoding Size =%u TimeStamp = %lld", + (unsigned int)pdest_frame->nFilledLen,pdest_frame->nTimeStamp); + DEBUG_PRINT_LOW("Found a frame size = %u number = %d", + (unsigned int)pdest_frame->nFilledLen,frame_count++); + /*Push the frame to the Decoder*/ + if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + frame_count++; + pdest_frame = NULL; + } else { + DEBUG_PRINT_LOW("Last frame in else dest addr") ; + generate_ebd = OMX_FALSE; + } + } + if (generate_ebd) { + DEBUG_PRINT_LOW("Buffer Consumed return back to client %p",psource_frame); + m_cb.EmptyBufferDone (hComp,m_app_data,psource_frame); + psource_frame = NULL; + + if (m_input_pending_q.m_size) { + DEBUG_PRINT_LOW("Pull Next source Buffer %p",psource_frame); + m_input_pending_q.pop_entry(&address,&p2,&id); + psource_frame = (OMX_BUFFERHEADERTYPE *) address; + DEBUG_PRINT_LOW("Next source Buffer %p time stamp %lld",psource_frame, + psource_frame->nTimeStamp); + DEBUG_PRINT_LOW("Next source Buffer flag %u length %u", + (unsigned int)psource_frame->nFlags, (unsigned int)psource_frame->nFilledLen); + } + } + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::push_input_h264 (OMX_HANDLETYPE hComp) +{ + OMX_U32 partial_frame = 1; + unsigned long address = 0, p2 = 0, id = 0; + OMX_BOOL isNewFrame = OMX_FALSE; + OMX_BOOL generate_ebd = OMX_TRUE; + + if (h264_scratch.pBuffer == NULL) { + DEBUG_PRINT_ERROR("ERROR:H.264 Scratch Buffer not allocated"); + return OMX_ErrorBadParameter; + } + DEBUG_PRINT_LOW("Pending h264_scratch.nFilledLen %u " + "look_ahead_nal %d", (unsigned int)h264_scratch.nFilledLen, look_ahead_nal); + DEBUG_PRINT_LOW("Pending pdest_frame->nFilledLen %u",(unsigned int)pdest_frame->nFilledLen); + if (h264_scratch.nFilledLen && look_ahead_nal) { + look_ahead_nal = false; + if ((pdest_frame->nAllocLen - pdest_frame->nFilledLen) >= + h264_scratch.nFilledLen) { + memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen), + h264_scratch.pBuffer,h264_scratch.nFilledLen); + pdest_frame->nFilledLen += h264_scratch.nFilledLen; + DEBUG_PRINT_LOW("Copy the previous NAL (h264 scratch) into Dest frame"); + h264_scratch.nFilledLen = 0; + } else { + DEBUG_PRINT_ERROR("Error:1: Destination buffer overflow for H264"); + return OMX_ErrorBadParameter; + } + } + + /* If an empty input is queued with EOS, do not coalesce with the destination-frame yet, as this may result + in EOS flag getting associated with the destination + */ + if (!psource_frame->nFilledLen && (psource_frame->nFlags & OMX_BUFFERFLAG_EOS) && + pdest_frame->nFilledLen) { + DEBUG_PRINT_HIGH("delay ETB for 'empty buffer with EOS'"); + generate_ebd = OMX_FALSE; + } + + if (nal_length == 0) { + DEBUG_PRINT_LOW("Zero NAL, hence parse using start code"); + if (m_frame_parser.parse_sc_frame(psource_frame, + &h264_scratch,&partial_frame) == -1) { + DEBUG_PRINT_ERROR("Error In Parsing Return Error"); + return OMX_ErrorBadParameter; + } + } else { + DEBUG_PRINT_LOW("Non-zero NAL length clip, hence parse with NAL size %d ",nal_length); + if (m_frame_parser.parse_h264_nallength(psource_frame, + &h264_scratch,&partial_frame) == -1) { + DEBUG_PRINT_ERROR("Error In Parsing NAL size, Return Error"); + return OMX_ErrorBadParameter; + } + } + + if (partial_frame == 0) { + if (nal_count == 0 && h264_scratch.nFilledLen == 0) { + DEBUG_PRINT_LOW("First NAL with Zero Length, hence Skip"); + nal_count++; + h264_scratch.nTimeStamp = psource_frame->nTimeStamp; + h264_scratch.nFlags = psource_frame->nFlags; + } else { + DEBUG_PRINT_LOW("Parsed New NAL Length = %u",(unsigned int)h264_scratch.nFilledLen); + if (h264_scratch.nFilledLen) { + h264_parser->parse_nal((OMX_U8*)h264_scratch.pBuffer, h264_scratch.nFilledLen, + NALU_TYPE_SPS); +#ifndef PROCESS_EXTRADATA_IN_OUTPUT_PORT + if (client_extradata & OMX_TIMEINFO_EXTRADATA) + h264_parser->parse_nal((OMX_U8*)h264_scratch.pBuffer, + h264_scratch.nFilledLen, NALU_TYPE_SEI); + else if (client_extradata & OMX_FRAMEINFO_EXTRADATA) + // If timeinfo is present frame info from SEI is already processed + h264_parser->parse_nal((OMX_U8*)h264_scratch.pBuffer, + h264_scratch.nFilledLen, NALU_TYPE_SEI); +#endif + m_frame_parser.mutils->isNewFrame(&h264_scratch, 0, isNewFrame); + nal_count++; + if (VALID_TS(h264_last_au_ts) && !VALID_TS(pdest_frame->nTimeStamp)) { + pdest_frame->nTimeStamp = h264_last_au_ts; + pdest_frame->nFlags = h264_last_au_flags; +#ifdef PANSCAN_HDLR + if (client_extradata & OMX_FRAMEINFO_EXTRADATA) + h264_parser->update_panscan_data(h264_last_au_ts); +#endif + } + if (m_frame_parser.mutils->nalu_type == NALU_TYPE_NON_IDR || + m_frame_parser.mutils->nalu_type == NALU_TYPE_IDR) { + h264_last_au_ts = h264_scratch.nTimeStamp; + h264_last_au_flags = h264_scratch.nFlags; +#ifndef PROCESS_EXTRADATA_IN_OUTPUT_PORT + if (client_extradata & OMX_TIMEINFO_EXTRADATA) { + OMX_S64 ts_in_sei = h264_parser->process_ts_with_sei_vui(h264_last_au_ts); + if (!VALID_TS(h264_last_au_ts)) + h264_last_au_ts = ts_in_sei; + } +#endif + } else + h264_last_au_ts = LLONG_MAX; + } + + if (!isNewFrame) { + if ( (pdest_frame->nAllocLen - pdest_frame->nFilledLen) >= + h264_scratch.nFilledLen) { + DEBUG_PRINT_LOW("Not a NewFrame Copy into Dest len %u", + (unsigned int)h264_scratch.nFilledLen); + memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen), + h264_scratch.pBuffer,h264_scratch.nFilledLen); + pdest_frame->nFilledLen += h264_scratch.nFilledLen; + if (m_frame_parser.mutils->nalu_type == NALU_TYPE_EOSEQ) + pdest_frame->nFlags |= QOMX_VIDEO_BUFFERFLAG_EOSEQ; + h264_scratch.nFilledLen = 0; + } else { + DEBUG_PRINT_LOW("Error:2: Destination buffer overflow for H264"); + return OMX_ErrorBadParameter; + } + } else if(h264_scratch.nFilledLen) { + look_ahead_nal = true; + DEBUG_PRINT_LOW("Frame Found start Decoding Size =%u TimeStamp = %llu", + (unsigned int)pdest_frame->nFilledLen,pdest_frame->nTimeStamp); + DEBUG_PRINT_LOW("Found a frame size = %u number = %d", + (unsigned int)pdest_frame->nFilledLen,frame_count++); + + if (pdest_frame->nFilledLen == 0) { + DEBUG_PRINT_LOW("Copy the Current Frame since and push it"); + look_ahead_nal = false; + if ( (pdest_frame->nAllocLen - pdest_frame->nFilledLen) >= + h264_scratch.nFilledLen) { + memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen), + h264_scratch.pBuffer,h264_scratch.nFilledLen); + pdest_frame->nFilledLen += h264_scratch.nFilledLen; + h264_scratch.nFilledLen = 0; + } else { + DEBUG_PRINT_ERROR("Error:3: Destination buffer overflow for H264"); + return OMX_ErrorBadParameter; + } + } else { + if (psource_frame->nFilledLen || h264_scratch.nFilledLen) { + DEBUG_PRINT_LOW("Reset the EOS Flag"); + pdest_frame->nFlags &= ~OMX_BUFFERFLAG_EOS; + } + /*Push the frame to the Decoder*/ + if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + //frame_count++; + pdest_frame = NULL; + if (m_input_free_q.m_size) { + m_input_free_q.pop_entry(&address,&p2,&id); + pdest_frame = (OMX_BUFFERHEADERTYPE *) address; + DEBUG_PRINT_LOW("Pop the next pdest_buffer %p",pdest_frame); + pdest_frame->nFilledLen = 0; + pdest_frame->nFlags = 0; + pdest_frame->nTimeStamp = LLONG_MAX; + } + } + } + } + } else { + DEBUG_PRINT_LOW("Not a Complete Frame, pdest_frame->nFilledLen %u", (unsigned int)pdest_frame->nFilledLen); + /*Check if Destination Buffer is full*/ + if (h264_scratch.nAllocLen == + h264_scratch.nFilledLen + h264_scratch.nOffset) { + DEBUG_PRINT_ERROR("ERROR: Frame Not found though Destination Filled"); + return OMX_ErrorStreamCorrupt; + } + } + + if (!psource_frame->nFilledLen) { + DEBUG_PRINT_LOW("Buffer Consumed return source %p back to client",psource_frame); + + if (psource_frame->nFlags & OMX_BUFFERFLAG_EOS) { + if (pdest_frame) { + DEBUG_PRINT_LOW("EOS Reached Pass Last Buffer"); + if ( (pdest_frame->nAllocLen - pdest_frame->nFilledLen) >= + h264_scratch.nFilledLen) { + if(pdest_frame->nFilledLen == 0) { + /* No residual frame from before, send whatever + * we have left */ + memcpy((pdest_frame->pBuffer + pdest_frame->nFilledLen), + h264_scratch.pBuffer, h264_scratch.nFilledLen); + pdest_frame->nFilledLen += h264_scratch.nFilledLen; + h264_scratch.nFilledLen = 0; + pdest_frame->nTimeStamp = h264_scratch.nTimeStamp; + } else { + m_frame_parser.mutils->isNewFrame(&h264_scratch, 0, isNewFrame); + if(!isNewFrame) { + /* Have a residual frame, but we know that the + * AU in this frame is belonging to whatever + * frame we had left over. So append it */ + memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen), + h264_scratch.pBuffer,h264_scratch.nFilledLen); + pdest_frame->nFilledLen += h264_scratch.nFilledLen; + h264_scratch.nFilledLen = 0; + if (h264_last_au_ts != LLONG_MAX) + pdest_frame->nTimeStamp = h264_last_au_ts; + } else { + /* Completely new frame, let's just push what + * we have now. The resulting EBD would trigger + * another push */ + generate_ebd = OMX_FALSE; + pdest_frame->nTimeStamp = h264_last_au_ts; + h264_last_au_ts = h264_scratch.nTimeStamp; + } + } + } else { + DEBUG_PRINT_ERROR("ERROR:4: Destination buffer overflow for H264"); + return OMX_ErrorBadParameter; + } + + /* Iff we coalesced two buffers, inherit the flags of both bufs */ + if(generate_ebd == OMX_TRUE) { + pdest_frame->nFlags = h264_scratch.nFlags | psource_frame->nFlags; + } + + DEBUG_PRINT_LOW("pdest_frame->nFilledLen =%u TimeStamp = %llu", + (unsigned int)pdest_frame->nFilledLen,pdest_frame->nTimeStamp); + DEBUG_PRINT_LOW("Push AU frame number %d to driver", frame_count++); +#ifndef PROCESS_EXTRADATA_IN_OUTPUT_PORT + if (client_extradata & OMX_TIMEINFO_EXTRADATA) { + OMX_S64 ts_in_sei = h264_parser->process_ts_with_sei_vui(pdest_frame->nTimeStamp); + if (!VALID_TS(pdest_frame->nTimeStamp)) + pdest_frame->nTimeStamp = ts_in_sei; + } +#endif + /*Push the frame to the Decoder*/ + if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + frame_count++; + pdest_frame = NULL; + } else { + DEBUG_PRINT_LOW("Last frame in else dest addr %p size %u", + pdest_frame, (unsigned int)h264_scratch.nFilledLen); + generate_ebd = OMX_FALSE; + } + } + } + if (generate_ebd && !psource_frame->nFilledLen) { + m_cb.EmptyBufferDone (hComp,m_app_data,psource_frame); + psource_frame = NULL; + if (m_input_pending_q.m_size) { + DEBUG_PRINT_LOW("Pull Next source Buffer %p",psource_frame); + m_input_pending_q.pop_entry(&address,&p2,&id); + psource_frame = (OMX_BUFFERHEADERTYPE *) address; + DEBUG_PRINT_LOW("Next source Buffer flag %u src length %u", + (unsigned int)psource_frame->nFlags, (unsigned int)psource_frame->nFilledLen); + } + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE copy_buffer(OMX_BUFFERHEADERTYPE* pDst, OMX_BUFFERHEADERTYPE* pSrc) +{ + OMX_ERRORTYPE rc = OMX_ErrorNone; + if ((pDst->nAllocLen - pDst->nFilledLen) >= pSrc->nFilledLen) { + memcpy((pDst->pBuffer + pDst->nFilledLen), pSrc->pBuffer, pSrc->nFilledLen); + if (pDst->nTimeStamp == LLONG_MAX) { + pDst->nTimeStamp = pSrc->nTimeStamp; + DEBUG_PRINT_LOW("Assign Dst nTimeStamp = %lld", pDst->nTimeStamp); + } + pDst->nFilledLen += pSrc->nFilledLen; + pSrc->nFilledLen = 0; + } else { + DEBUG_PRINT_ERROR("Error: Destination buffer overflow"); + rc = OMX_ErrorBadParameter; + } + return rc; +} + +OMX_ERRORTYPE omx_vdec::push_input_hevc(OMX_HANDLETYPE hComp) +{ + OMX_U32 partial_frame = 1; + unsigned long address,p2,id; + OMX_BOOL isNewFrame = OMX_FALSE; + OMX_BOOL generate_ebd = OMX_TRUE; + OMX_ERRORTYPE rc = OMX_ErrorNone; + if (h264_scratch.pBuffer == NULL) { + DEBUG_PRINT_ERROR("ERROR:Hevc Scratch Buffer not allocated"); + return OMX_ErrorBadParameter; + } + + DEBUG_PRINT_LOW("h264_scratch.nFilledLen %u has look_ahead_nal %d \ + pdest_frame nFilledLen %u nTimeStamp %lld", + (unsigned int)h264_scratch.nFilledLen, look_ahead_nal, (unsigned int)pdest_frame->nFilledLen, pdest_frame->nTimeStamp); + + if (h264_scratch.nFilledLen && look_ahead_nal) { + look_ahead_nal = false; + rc = copy_buffer(pdest_frame, &h264_scratch); + if (rc != OMX_ErrorNone) { + return rc; + } + } + + if (nal_length == 0) { + if (m_frame_parser.parse_sc_frame(psource_frame, + &h264_scratch,&partial_frame) == -1) { + DEBUG_PRINT_ERROR("Error In Parsing Return Error"); + return OMX_ErrorBadParameter; + } + } else { + DEBUG_PRINT_LOW("Non-zero NAL length clip, hence parse with NAL size %d",nal_length); + if (m_frame_parser.parse_h264_nallength(psource_frame, + &h264_scratch,&partial_frame) == -1) { + DEBUG_PRINT_ERROR("Error In Parsing NAL size, Return Error"); + return OMX_ErrorBadParameter; + } + } + + if (partial_frame == 0) { + if (nal_count == 0 && h264_scratch.nFilledLen == 0) { + DEBUG_PRINT_LOW("First NAL with Zero Length, hence Skip"); + nal_count++; + h264_scratch.nTimeStamp = psource_frame->nTimeStamp; + h264_scratch.nFlags = psource_frame->nFlags; + } else { + DEBUG_PRINT_LOW("Parsed New NAL Length = %u", (unsigned int)h264_scratch.nFilledLen); + if (h264_scratch.nFilledLen) { + m_hevc_utils.isNewFrame(&h264_scratch, 0, isNewFrame); + nal_count++; + } + + if (!isNewFrame) { + DEBUG_PRINT_LOW("Not a new frame, copy h264_scratch nFilledLen %u \ + nTimestamp %lld, pdest_frame nFilledLen %u nTimestamp %lld", + (unsigned int)h264_scratch.nFilledLen, h264_scratch.nTimeStamp, + (unsigned int)pdest_frame->nFilledLen, pdest_frame->nTimeStamp); + rc = copy_buffer(pdest_frame, &h264_scratch); + if (rc != OMX_ErrorNone) { + return rc; + } + } else { + look_ahead_nal = true; + if (pdest_frame->nFilledLen == 0) { + look_ahead_nal = false; + DEBUG_PRINT_LOW("dest nation buffer empty, copy scratch buffer"); + rc = copy_buffer(pdest_frame, &h264_scratch); + if (rc != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + } else { + if (psource_frame->nFilledLen || h264_scratch.nFilledLen) { + pdest_frame->nFlags &= ~OMX_BUFFERFLAG_EOS; + } + DEBUG_PRINT_LOW("FrameDetected # %d pdest_frame nFilledLen %u \ + nTimeStamp %lld, look_ahead_nal in h264_scratch \ + nFilledLen %u nTimeStamp %lld", + frame_count++, (unsigned int)pdest_frame->nFilledLen, + pdest_frame->nTimeStamp, (unsigned int)h264_scratch.nFilledLen, + h264_scratch.nTimeStamp); + if (empty_this_buffer_proxy(hComp, pdest_frame) != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + pdest_frame = NULL; + if (m_input_free_q.m_size) { + m_input_free_q.pop_entry(&address, &p2, &id); + pdest_frame = (OMX_BUFFERHEADERTYPE *) address; + DEBUG_PRINT_LOW("pop the next pdest_buffer %p", pdest_frame); + pdest_frame->nFilledLen = 0; + pdest_frame->nFlags = 0; + pdest_frame->nTimeStamp = LLONG_MAX; + } + } + } + } + } else { + DEBUG_PRINT_LOW("psource_frame is partial nFilledLen %u nTimeStamp %lld, \ + pdest_frame nFilledLen %u nTimeStamp %lld, h264_scratch \ + nFilledLen %u nTimeStamp %lld", + (unsigned int)psource_frame->nFilledLen, psource_frame->nTimeStamp, + (unsigned int)pdest_frame->nFilledLen, pdest_frame->nTimeStamp, + (unsigned int)h264_scratch.nFilledLen, h264_scratch.nTimeStamp); + + if (h264_scratch.nAllocLen == + h264_scratch.nFilledLen + h264_scratch.nOffset) { + DEBUG_PRINT_ERROR("ERROR: Frame Not found though Destination Filled"); + return OMX_ErrorStreamCorrupt; + } + } + + if (!psource_frame->nFilledLen) { + DEBUG_PRINT_LOW("Buffer Consumed return source %p back to client", psource_frame); + if (psource_frame->nFlags & OMX_BUFFERFLAG_EOS) { + if (pdest_frame) { + DEBUG_PRINT_LOW("EOS Reached Pass Last Buffer"); + rc = copy_buffer(pdest_frame, &h264_scratch); + if ( rc != OMX_ErrorNone ) { + return rc; + } + pdest_frame->nTimeStamp = h264_scratch.nTimeStamp; + pdest_frame->nFlags = h264_scratch.nFlags | psource_frame->nFlags; + DEBUG_PRINT_LOW("Push EOS frame number:%d nFilledLen =%u TimeStamp = %lld", + frame_count, (unsigned int)pdest_frame->nFilledLen, pdest_frame->nTimeStamp); + if (empty_this_buffer_proxy(hComp, pdest_frame) != OMX_ErrorNone) { + return OMX_ErrorBadParameter; + } + frame_count++; + pdest_frame = NULL; + } else { + DEBUG_PRINT_LOW("Last frame in else dest addr %p size %u", + pdest_frame, (unsigned int)h264_scratch.nFilledLen); + generate_ebd = OMX_FALSE; + } + } + } + + if (generate_ebd && !psource_frame->nFilledLen) { + m_cb.EmptyBufferDone (hComp, m_app_data, psource_frame); + psource_frame = NULL; + if (m_input_pending_q.m_size) { + m_input_pending_q.pop_entry(&address, &p2, &id); + psource_frame = (OMX_BUFFERHEADERTYPE *)address; + DEBUG_PRINT_LOW("Next source Buffer flag %u nFilledLen %u, nTimeStamp %lld", + (unsigned int)psource_frame->nFlags, (unsigned int)psource_frame->nFilledLen, psource_frame->nTimeStamp); + } + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::push_input_vc1(OMX_HANDLETYPE hComp) +{ + OMX_U8 *buf, *pdest; + OMX_U32 partial_frame = 1; + OMX_U32 buf_len, dest_len; + + if (first_frame == 0) { + first_frame = 1; + DEBUG_PRINT_LOW("First i/p buffer for VC1 arbitrary bytes"); + if (!m_vendor_config.pData) { + DEBUG_PRINT_LOW("Check profile type in 1st source buffer"); + buf = psource_frame->pBuffer; + buf_len = psource_frame->nFilledLen; + + if ((*((OMX_U32 *) buf) & VC1_SP_MP_START_CODE_MASK) == + VC1_SP_MP_START_CODE) { + m_vc1_profile = VC1_SP_MP_RCV; + } else if (*((OMX_U32 *) buf) & VC1_AP_SEQ_START_CODE) { + m_vc1_profile = VC1_AP; + } else { + DEBUG_PRINT_ERROR("Invalid sequence layer in first buffer"); + return OMX_ErrorStreamCorrupt; + } + } else { + pdest = pdest_frame->pBuffer + pdest_frame->nFilledLen + + pdest_frame->nOffset; + dest_len = pdest_frame->nAllocLen - (pdest_frame->nFilledLen + + pdest_frame->nOffset); + + if (dest_len < m_vendor_config.nDataSize) { + DEBUG_PRINT_ERROR("Destination buffer full"); + return OMX_ErrorBadParameter; + } else { + memcpy(pdest, m_vendor_config.pData, m_vendor_config.nDataSize); + pdest_frame->nFilledLen += m_vendor_config.nDataSize; + } + } + } + + switch (m_vc1_profile) { + case VC1_AP: + DEBUG_PRINT_LOW("VC1 AP, hence parse using frame start code"); + if (push_input_sc_codec(hComp) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("Error In Parsing VC1 AP start code"); + return OMX_ErrorBadParameter; + } + break; + + case VC1_SP_MP_RCV: + default: + DEBUG_PRINT_ERROR("Unsupported VC1 profile in ArbitraryBytes Mode"); + return OMX_ErrorBadParameter; + } + return OMX_ErrorNone; +} + +#ifndef USE_ION +bool omx_vdec::align_pmem_buffers(int pmem_fd, OMX_U32 buffer_size, + OMX_U32 alignment) +{ + struct pmem_allocation allocation; + allocation.size = buffer_size; + allocation.align = clip2(alignment); + if (allocation.align < 4096) { + allocation.align = 4096; + } + if (ioctl(pmem_fd, PMEM_ALLOCATE_ALIGNED, &allocation) < 0) { + DEBUG_PRINT_ERROR("Aligment(%u) failed with pmem driver Sz(%lu)", + allocation.align, allocation.size); + return false; + } + return true; +} +#endif +#ifdef USE_ION +int omx_vdec::alloc_map_ion_memory(OMX_U32 buffer_size, + OMX_U32 alignment, struct ion_allocation_data *alloc_data, + struct ion_fd_data *fd_data, int flag) +{ + int fd = -EINVAL; + int rc = -EINVAL; + int ion_dev_flag; + struct vdec_ion ion_buf_info; + if (!alloc_data || buffer_size <= 0 || !fd_data) { + DEBUG_PRINT_ERROR("Invalid arguments to alloc_map_ion_memory"); + return -EINVAL; + } + ion_dev_flag = O_RDONLY; + fd = open (MEM_DEVICE, ion_dev_flag); + if (fd < 0) { + DEBUG_PRINT_ERROR("opening ion device failed with fd = %d", fd); + return fd; + } + + alloc_data->flags = flag; + alloc_data->len = buffer_size; + alloc_data->align = clip2(alignment); + if (alloc_data->align < 4096) { + alloc_data->align = 4096; + } + + alloc_data->heap_id_mask = ION_HEAP(ION_IOMMU_HEAP_ID); + if (secure_mode && (alloc_data->flags & ION_SECURE)) { + alloc_data->heap_id_mask = ION_HEAP(MEM_HEAP_ID); + } + + /* Use secure display cma heap for obvious reasons. */ + if (alloc_data->flags & ION_FLAG_CP_BITSTREAM) { + alloc_data->heap_id_mask |= ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID); + } + + rc = ioctl(fd,ION_IOC_ALLOC,alloc_data); + if (rc || !alloc_data->handle) { + DEBUG_PRINT_ERROR("ION ALLOC memory failed"); + alloc_data->handle = 0; + close(fd); + fd = -ENOMEM; + return fd; + } + fd_data->handle = alloc_data->handle; + rc = ioctl(fd,ION_IOC_MAP,fd_data); + if (rc) { + DEBUG_PRINT_ERROR("ION MAP failed "); + ion_buf_info.ion_alloc_data = *alloc_data; + ion_buf_info.ion_device_fd = fd; + ion_buf_info.fd_ion_data = *fd_data; + free_ion_memory(&ion_buf_info); + fd_data->fd =-1; + fd = -ENOMEM; + } + + return fd; +} + +void omx_vdec::free_ion_memory(struct vdec_ion *buf_ion_info) +{ + + if (!buf_ion_info) { + DEBUG_PRINT_ERROR("ION: free called with invalid fd/allocdata"); + return; + } + if (ioctl(buf_ion_info->ion_device_fd,ION_IOC_FREE, + &buf_ion_info->ion_alloc_data.handle)) { + DEBUG_PRINT_ERROR("ION: free failed" ); + } + close(buf_ion_info->ion_device_fd); + buf_ion_info->ion_device_fd = -1; + buf_ion_info->ion_alloc_data.handle = 0; + buf_ion_info->fd_ion_data.fd = -1; +} +#endif +void omx_vdec::free_output_buffer_header() +{ + DEBUG_PRINT_HIGH("ALL output buffers are freed/released"); + output_use_buffer = false; + ouput_egl_buffers = false; + + if (m_out_mem_ptr) { + free (m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + + if (m_platform_list) { + free(m_platform_list); + m_platform_list = NULL; + } + + if (drv_ctx.ptr_respbuffer) { + free (drv_ctx.ptr_respbuffer); + drv_ctx.ptr_respbuffer = NULL; + } + if (drv_ctx.ptr_outputbuffer) { + free (drv_ctx.ptr_outputbuffer); + drv_ctx.ptr_outputbuffer = NULL; + } +#ifdef USE_ION + if (drv_ctx.op_buf_ion_info) { + DEBUG_PRINT_LOW("Free o/p ion context"); + free(drv_ctx.op_buf_ion_info); + drv_ctx.op_buf_ion_info = NULL; + } +#endif + buf_ref_remove(); +} + +void omx_vdec::free_input_buffer_header() +{ + input_use_buffer = false; + if (arbitrary_bytes) { + if (m_inp_heap_ptr) { + DEBUG_PRINT_LOW("Free input Heap Pointer"); + free (m_inp_heap_ptr); + m_inp_heap_ptr = NULL; + } + + if (m_phdr_pmem_ptr) { + DEBUG_PRINT_LOW("Free input pmem header Pointer"); + free (m_phdr_pmem_ptr); + m_phdr_pmem_ptr = NULL; + } + } + if (m_inp_mem_ptr) { + DEBUG_PRINT_LOW("Free input pmem Pointer area"); + free (m_inp_mem_ptr); + m_inp_mem_ptr = NULL; + } + /* We just freed all the buffer headers, every thing in m_input_free_q, + * m_input_pending_q, pdest_frame, and psource_frame is now invalid */ + while (m_input_free_q.m_size) { + unsigned long address, p2, id; + m_input_free_q.pop_entry(&address, &p2, &id); + } + while (m_input_pending_q.m_size) { + unsigned long address, p2, id; + m_input_pending_q.pop_entry(&address, &p2, &id); + } + pdest_frame = NULL; + psource_frame = NULL; + if (drv_ctx.ptr_inputbuffer) { + DEBUG_PRINT_LOW("Free Driver Context pointer"); + free (drv_ctx.ptr_inputbuffer); + drv_ctx.ptr_inputbuffer = NULL; + } +#ifdef USE_ION + if (drv_ctx.ip_buf_ion_info) { + DEBUG_PRINT_LOW("Free ion context"); + free(drv_ctx.ip_buf_ion_info); + drv_ctx.ip_buf_ion_info = NULL; + } +#endif +} + +int omx_vdec::stream_off(OMX_U32 port) +{ + enum v4l2_buf_type btype; + int rc = 0; + enum v4l2_ports v4l2_port = OUTPUT_PORT; + + if (port == OMX_CORE_INPUT_PORT_INDEX) { + btype = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + v4l2_port = OUTPUT_PORT; + } else if (port == OMX_CORE_OUTPUT_PORT_INDEX) { + btype = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_port = CAPTURE_PORT; + } else if (port == OMX_ALL) { + int rc_input = stream_off(OMX_CORE_INPUT_PORT_INDEX); + int rc_output = stream_off(OMX_CORE_OUTPUT_PORT_INDEX); + + if (!rc_input) + return rc_input; + else + return rc_output; + } + + if (!streaming[v4l2_port]) { + // already streamed off, warn and move on + DEBUG_PRINT_HIGH("Warning: Attempting to stream off on %d port," + " which is already streamed off", v4l2_port); + return 0; + } + + DEBUG_PRINT_HIGH("Streaming off %d port", v4l2_port); + + rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMOFF, &btype); + if (rc) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Failed to call streamoff on %d Port", v4l2_port); + } else { + streaming[v4l2_port] = false; + } + + return rc; +} + +OMX_ERRORTYPE omx_vdec::get_buffer_req(vdec_allocatorproperty *buffer_prop) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_requestbuffers bufreq; + unsigned int buf_size = 0, extra_data_size = 0, default_extra_data_size = 0; + unsigned int final_extra_data_size = 0; + struct v4l2_format fmt; + int ret = 0; + DEBUG_PRINT_LOW("GetBufReq IN: ActCnt(%d) Size(%u)", + buffer_prop->actualcount, (unsigned int)buffer_prop->buffer_size); + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = 1; + if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_INPUT) { + bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.type =V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.pixelformat = output_capability; + } else if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { + bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.type =V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = capture_capability; + } else { + eRet = OMX_ErrorBadParameter; + } + if (eRet==OMX_ErrorNone) { + ret = ioctl(drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); + } + if (ret) { + DEBUG_PRINT_ERROR("Requesting buffer requirements failed"); + /*TODO: How to handle this case */ + eRet = OMX_ErrorInsufficientResources; + return eRet; + } else { + bool is_res_1080p_or_below = (drv_ctx.video_resolution.frame_width <= 1920 && + drv_ctx.video_resolution.frame_height <= 1088) || + (drv_ctx.video_resolution.frame_height <= 1088 && + drv_ctx.video_resolution.frame_width <= 1920); + + int fps = drv_ctx.frame_rate.fps_numerator / (float)drv_ctx.frame_rate.fps_denominator; + bool fps_above_180 = (fps >= 180 || operating_frame_rate >= 180) ? true : false; + bool increase_output = (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) && (bufreq.count >= 16); + + if (increase_output && fps_above_180 && + output_capability == V4L2_PIX_FMT_H264 && + is_res_1080p_or_below) { + high_fps = true; + DEBUG_PRINT_LOW("High fps - fps = %d operating_rate = %d", fps, operating_frame_rate); + DEBUG_PRINT_LOW("getbufreq[output]: Increase buffer count (%d) to (%d) to support high fps", + bufreq.count, bufreq.count + 10); + bufreq.count += 10; + ret = ioctl(drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); + if (ret) { + DEBUG_PRINT_ERROR("(Failed to set updated buffer count to driver"); + eRet = OMX_ErrorInsufficientResources; + return eRet; + } + DEBUG_PRINT_LOW("new buf count = %d set to driver", bufreq.count); + request_perf_level(VIDC_TURBO); + } + + buffer_prop->actualcount = bufreq.count; + buffer_prop->mincount = bufreq.count; + DEBUG_PRINT_HIGH("Count = %d",bufreq.count); + } + DEBUG_PRINT_LOW("GetBufReq IN: ActCnt(%d) Size(%u)", + buffer_prop->actualcount, (unsigned int)buffer_prop->buffer_size); + + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_G_FMT, &fmt); + + if (fmt.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + drv_ctx.num_planes = fmt.fmt.pix_mp.num_planes; + DEBUG_PRINT_HIGH("Buffer Size = %d",fmt.fmt.pix_mp.plane_fmt[0].sizeimage); + + if (ret) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Requesting buffer requirements failed"); + eRet = OMX_ErrorInsufficientResources; + } else { + int extra_idx = 0; + + eRet = is_video_session_supported(); + if (eRet) + return eRet; + + buffer_prop->buffer_size = fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + buf_size = buffer_prop->buffer_size; + extra_idx = EXTRADATA_IDX(drv_ctx.num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + extra_data_size = fmt.fmt.pix_mp.plane_fmt[extra_idx].sizeimage; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index is more than allowed: %d", extra_idx); + return OMX_ErrorBadParameter; + } + + default_extra_data_size = VENUS_EXTRADATA_SIZE( + drv_ctx.video_resolution.frame_height, + drv_ctx.video_resolution.frame_width); + final_extra_data_size = extra_data_size > default_extra_data_size ? + extra_data_size : default_extra_data_size; + + final_extra_data_size = (final_extra_data_size + buffer_prop->alignment - 1) & + (~(buffer_prop->alignment - 1)); + + drv_ctx.extradata_info.size = buffer_prop->actualcount * final_extra_data_size; + drv_ctx.extradata_info.count = buffer_prop->actualcount; + drv_ctx.extradata_info.buffer_size = final_extra_data_size; + buf_size = (buf_size + buffer_prop->alignment - 1)&(~(buffer_prop->alignment - 1)); + DEBUG_PRINT_LOW("GetBufReq UPDATE: ActCnt(%d) Size(%u) BufSize(%d)", + buffer_prop->actualcount, (unsigned int)buffer_prop->buffer_size, buf_size); + if (extra_data_size) + DEBUG_PRINT_LOW("GetBufReq UPDATE: extradata: TotalSize(%d) BufferSize(%lu)", + drv_ctx.extradata_info.size, drv_ctx.extradata_info.buffer_size); + + if (in_reconfig) // BufReq will be set to driver when port is disabled + buffer_prop->buffer_size = buf_size; + else if (buf_size != buffer_prop->buffer_size) { + buffer_prop->buffer_size = buf_size; + eRet = set_buffer_req(buffer_prop); + } + } + DEBUG_PRINT_LOW("GetBufReq OUT: ActCnt(%d) Size(%u)", + buffer_prop->actualcount, (unsigned int)buffer_prop->buffer_size); + return eRet; +} + +OMX_ERRORTYPE omx_vdec::set_buffer_req(vdec_allocatorproperty *buffer_prop) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned buf_size = 0; + struct v4l2_format fmt, c_fmt; + struct v4l2_requestbuffers bufreq; + int ret = 0; + DEBUG_PRINT_LOW("SetBufReq IN: ActCnt(%d) Size(%u)", + buffer_prop->actualcount, (unsigned int)buffer_prop->buffer_size); + buf_size = (buffer_prop->buffer_size + buffer_prop->alignment - 1)&(~(buffer_prop->alignment - 1)); + if (buf_size != buffer_prop->buffer_size) { + DEBUG_PRINT_ERROR("Buffer size alignment error: Requested(%u) Required(%d)", + (unsigned int)buffer_prop->buffer_size, buf_size); + eRet = OMX_ErrorBadParameter; + } else { + memset(&fmt, 0x0, sizeof(struct v4l2_format)); + memset(&c_fmt, 0x0, sizeof(struct v4l2_format)); + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.plane_fmt[0].sizeimage = buf_size; + + if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_INPUT) { + fmt.type =V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.pixelformat = output_capability; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + } else if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { + c_fmt.type =V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + c_fmt.fmt.pix_mp.pixelformat = capture_capability; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_G_FMT, &c_fmt); + c_fmt.fmt.pix_mp.plane_fmt[0].sizeimage = buf_size; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &c_fmt); + } else { + eRet = OMX_ErrorBadParameter; + } + + if (ret) { + /*TODO: How to handle this case */ + DEBUG_PRINT_ERROR("Setting buffer requirements (format) failed %d", ret); + eRet = OMX_ErrorInsufficientResources; + } + + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = buffer_prop->actualcount; + if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_INPUT) { + bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + } else if (buffer_prop->buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { + bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + } else { + eRet = OMX_ErrorBadParameter; + } + + if (eRet==OMX_ErrorNone) { + ret = ioctl(drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); + } + + if (ret) { + DEBUG_PRINT_ERROR("Setting buffer requirements (reqbufs) failed %d", ret); + /*TODO: How to handle this case */ + eRet = OMX_ErrorInsufficientResources; + } else if (bufreq.count < buffer_prop->actualcount) { + DEBUG_PRINT_ERROR("Driver refused to change the number of buffers" + " on v4l2 port %d to %d (prefers %d)", bufreq.type, + buffer_prop->actualcount, bufreq.count); + eRet = OMX_ErrorInsufficientResources; + } else { + if (!client_buffers.update_buffer_req()) { + DEBUG_PRINT_ERROR("Setting c2D buffer requirements failed"); + eRet = OMX_ErrorInsufficientResources; + } + } + } + return eRet; +} + +OMX_ERRORTYPE omx_vdec::update_picture_resolution() +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + return eRet; +} + +OMX_ERRORTYPE omx_vdec::update_portdef(OMX_PARAM_PORTDEFINITIONTYPE *portDefn) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_format fmt; + if (!portDefn) { + return OMX_ErrorBadParameter; + } + DEBUG_PRINT_LOW("omx_vdec::update_portdef"); + portDefn->nVersion.nVersion = OMX_SPEC_VERSION; + portDefn->nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); + portDefn->eDomain = OMX_PortDomainVideo; + memset(&fmt, 0x0, sizeof(struct v4l2_format)); + if (0 == portDefn->nPortIndex) { + portDefn->eDir = OMX_DirInput; + portDefn->nBufferCountActual = drv_ctx.ip_buf.actualcount; + portDefn->nBufferCountMin = drv_ctx.ip_buf.mincount; + portDefn->nBufferSize = drv_ctx.ip_buf.buffer_size; + portDefn->format.video.eColorFormat = OMX_COLOR_FormatUnused; + portDefn->format.video.eCompressionFormat = eCompressionFormat; + //for input port, always report the fps value set by client, + //to distinguish whether client got valid fps from parser. + portDefn->format.video.xFramerate = m_fps_received; + portDefn->bEnabled = m_inp_bEnabled; + portDefn->bPopulated = m_inp_bPopulated; + + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.pixelformat = output_capability; + ioctl(drv_ctx.video_driver_fd, VIDIOC_G_FMT, &fmt); + } else if (1 == portDefn->nPortIndex) { + unsigned int buf_size = 0; + int ret = 0; + if (!is_down_scalar_enabled) { + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_G_FMT, &fmt); + fmt.fmt.pix_mp.pixelformat = capture_capability; + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + } + + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = capture_capability; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_G_FMT, &fmt); + if (ret) { + DEBUG_PRINT_ERROR("Get Resolution failed"); + return OMX_ErrorHardware; + } + drv_ctx.op_buf.buffer_size = fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + if (!client_buffers.update_buffer_req()) { + DEBUG_PRINT_ERROR("client_buffers.update_buffer_req Failed"); + return OMX_ErrorHardware; + } + + if (!client_buffers.get_buffer_req(buf_size)) { + DEBUG_PRINT_ERROR("update buffer requirements"); + return OMX_ErrorHardware; + } + portDefn->nBufferSize = buf_size; + portDefn->eDir = OMX_DirOutput; + portDefn->nBufferCountActual = drv_ctx.op_buf.actualcount; + portDefn->nBufferCountMin = drv_ctx.op_buf.mincount; + portDefn->format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; + if (drv_ctx.frame_rate.fps_denominator > 0) + portDefn->format.video.xFramerate = (drv_ctx.frame_rate.fps_numerator / + drv_ctx.frame_rate.fps_denominator) << 16; //Q16 format + else { + DEBUG_PRINT_ERROR("Error: Divide by zero"); + return OMX_ErrorBadParameter; + } + portDefn->bEnabled = m_out_bEnabled; + portDefn->bPopulated = m_out_bPopulated; + if (!client_buffers.get_color_format(portDefn->format.video.eColorFormat)) { + DEBUG_PRINT_ERROR("Error in getting color format"); + return OMX_ErrorHardware; + } + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = capture_capability; + } else { + portDefn->eDir = OMX_DirMax; + DEBUG_PRINT_LOW(" get_parameter: Bad Port idx %d", + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + update_resolution(fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height, + fmt.fmt.pix_mp.plane_fmt[0].bytesperline, fmt.fmt.pix_mp.plane_fmt[0].reserved[0]); + + portDefn->format.video.nFrameHeight = drv_ctx.video_resolution.frame_height; + portDefn->format.video.nFrameWidth = drv_ctx.video_resolution.frame_width; + portDefn->format.video.nStride = drv_ctx.video_resolution.stride; + portDefn->format.video.nSliceHeight = drv_ctx.video_resolution.scan_lines; + + if ((portDefn->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar) || + (portDefn->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar)) { + portDefn->format.video.nStride = ALIGN(drv_ctx.video_resolution.frame_width, 16); + portDefn->format.video.nSliceHeight = drv_ctx.video_resolution.frame_height; + } + DEBUG_PRINT_HIGH("update_portdef(%u): Width = %u Height = %u Stride = %d " + "SliceHeight = %u eColorFormat = %d nBufSize %u nBufCnt %u", + (unsigned int)portDefn->nPortIndex, + (unsigned int)portDefn->format.video.nFrameWidth, + (unsigned int)portDefn->format.video.nFrameHeight, + (int)portDefn->format.video.nStride, + (unsigned int)portDefn->format.video.nSliceHeight, + (unsigned int)portDefn->format.video.eColorFormat, + (unsigned int)portDefn->nBufferSize, + (unsigned int)portDefn->nBufferCountActual); + + return eRet; +} + +OMX_ERRORTYPE omx_vdec::allocate_output_headers() +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr = NULL; + unsigned i= 0; + + if (!m_out_mem_ptr) { + DEBUG_PRINT_HIGH("Use o/p buffer case - Header List allocation"); + int nBufHdrSize = 0; + int nPlatformEntrySize = 0; + int nPlatformListSize = 0; + int nPMEMInfoSize = 0; + OMX_QCOM_PLATFORM_PRIVATE_LIST *pPlatformList; + OMX_QCOM_PLATFORM_PRIVATE_ENTRY *pPlatformEntry; + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo; + + DEBUG_PRINT_LOW("Setting First Output Buffer(%d)", + drv_ctx.op_buf.actualcount); + nBufHdrSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_BUFFERHEADERTYPE); + + nPMEMInfoSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO); + nPlatformListSize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_LIST); + nPlatformEntrySize = drv_ctx.op_buf.actualcount * + sizeof(OMX_QCOM_PLATFORM_PRIVATE_ENTRY); + + DEBUG_PRINT_LOW("TotalBufHdr %d BufHdrSize %u PMEM %d PL %d",nBufHdrSize, + (unsigned int)sizeof(OMX_BUFFERHEADERTYPE), + nPMEMInfoSize, + nPlatformListSize); + DEBUG_PRINT_LOW("PE %d bmSize % " PRId64 , nPlatformEntrySize, + m_out_bm_count); + m_out_mem_ptr = (OMX_BUFFERHEADERTYPE *)calloc(nBufHdrSize,1); + // Alloc mem for platform specific info + char *pPtr=NULL; + pPtr = (char*) calloc(nPlatformListSize + nPlatformEntrySize + + nPMEMInfoSize,1); + drv_ctx.ptr_outputbuffer = (struct vdec_bufferpayload *) \ + calloc (sizeof(struct vdec_bufferpayload), + drv_ctx.op_buf.actualcount); + drv_ctx.ptr_respbuffer = (struct vdec_output_frameinfo *)\ + calloc (sizeof (struct vdec_output_frameinfo), + drv_ctx.op_buf.actualcount); + if (!drv_ctx.ptr_outputbuffer || !drv_ctx.ptr_respbuffer) { + DEBUG_PRINT_ERROR("Failed to alloc drv_ctx.ptr_outputbuffer or drv_ctx.ptr_respbuffer"); + return OMX_ErrorInsufficientResources; + } + +#ifdef USE_ION + drv_ctx.op_buf_ion_info = (struct vdec_ion * ) \ + calloc (sizeof(struct vdec_ion),drv_ctx.op_buf.actualcount); + if (!drv_ctx.op_buf_ion_info) { + DEBUG_PRINT_ERROR("Failed to alloc drv_ctx.op_buf_ion_info"); + return OMX_ErrorInsufficientResources; + } +#endif + if (dynamic_buf_mode) { + out_dynamic_list = (struct dynamic_buf_list *) \ + calloc (sizeof(struct dynamic_buf_list), drv_ctx.op_buf.actualcount); + if (out_dynamic_list) { + for (unsigned int i = 0; i < drv_ctx.op_buf.actualcount; i++) + out_dynamic_list[i].dup_fd = -1; + } + } + + if (m_out_mem_ptr && pPtr && drv_ctx.ptr_outputbuffer + && drv_ctx.ptr_respbuffer) { + bufHdr = m_out_mem_ptr; + m_platform_list = (OMX_QCOM_PLATFORM_PRIVATE_LIST *)(pPtr); + m_platform_entry= (OMX_QCOM_PLATFORM_PRIVATE_ENTRY *) + (((char *) m_platform_list) + nPlatformListSize); + m_pmem_info = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) + (((char *) m_platform_entry) + nPlatformEntrySize); + pPlatformList = m_platform_list; + pPlatformEntry = m_platform_entry; + pPMEMInfo = m_pmem_info; + + DEBUG_PRINT_LOW("Memory Allocation Succeeded for OUT port%p",m_out_mem_ptr); + + // Settting the entire storage nicely + DEBUG_PRINT_LOW("bHdr %p OutMem %p PE %p",bufHdr, + m_out_mem_ptr,pPlatformEntry); + DEBUG_PRINT_LOW(" Pmem Info = %p",pPMEMInfo); + for (i=0; i < drv_ctx.op_buf.actualcount ; i++) { + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + // Set the values when we determine the right HxW param + bufHdr->nAllocLen = 0; + bufHdr->nFilledLen = 0; + bufHdr->pAppPrivate = NULL; + bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + pPlatformEntry->type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; + pPlatformEntry->entry = pPMEMInfo; + // Initialize the Platform List + pPlatformList->nEntries = 1; + pPlatformList->entryList = pPlatformEntry; + // Keep pBuffer NULL till vdec is opened + bufHdr->pBuffer = NULL; + pPMEMInfo->offset = 0; + pPMEMInfo->pmem_fd = -1; + bufHdr->pPlatformPrivate = pPlatformList; + drv_ctx.ptr_outputbuffer[i].pmem_fd = -1; +#ifdef USE_ION + drv_ctx.op_buf_ion_info[i].ion_device_fd =-1; +#endif + /*Create a mapping between buffers*/ + bufHdr->pOutputPortPrivate = &drv_ctx.ptr_respbuffer[i]; + drv_ctx.ptr_respbuffer[i].client_data = (void *) \ + &drv_ctx.ptr_outputbuffer[i]; + // Move the buffer and buffer header pointers + bufHdr++; + pPMEMInfo++; + pPlatformEntry++; + pPlatformList++; + } + } else { + DEBUG_PRINT_ERROR("Output buf mem alloc failed[0x%p][0x%p]",\ + m_out_mem_ptr, pPtr); + if (m_out_mem_ptr) { + free(m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + if (pPtr) { + free(pPtr); + pPtr = NULL; + } + if (drv_ctx.ptr_outputbuffer) { + free(drv_ctx.ptr_outputbuffer); + drv_ctx.ptr_outputbuffer = NULL; + } + if (drv_ctx.ptr_respbuffer) { + free(drv_ctx.ptr_respbuffer); + drv_ctx.ptr_respbuffer = NULL; + } +#ifdef USE_ION + if (drv_ctx.op_buf_ion_info) { + DEBUG_PRINT_LOW("Free o/p ion context"); + free(drv_ctx.op_buf_ion_info); + drv_ctx.op_buf_ion_info = NULL; + } +#endif + eRet = OMX_ErrorInsufficientResources; + } + } else { + eRet = OMX_ErrorInsufficientResources; + } + return eRet; +} + +void omx_vdec::complete_pending_buffer_done_cbs() +{ + unsigned long p1, p2, ident; + omx_cmd_queue tmp_q, pending_bd_q; + pthread_mutex_lock(&m_lock); + // pop all pending GENERATE FDB from ftb queue + while (m_ftb_q.m_size) { + m_ftb_q.pop_entry(&p1,&p2,&ident); + if (ident == OMX_COMPONENT_GENERATE_FBD) { + pending_bd_q.insert_entry(p1,p2,ident); + } else { + tmp_q.insert_entry(p1,p2,ident); + } + } + //return all non GENERATE FDB to ftb queue + while (tmp_q.m_size) { + tmp_q.pop_entry(&p1,&p2,&ident); + m_ftb_q.insert_entry(p1,p2,ident); + } + // pop all pending GENERATE EDB from etb queue + while (m_etb_q.m_size) { + m_etb_q.pop_entry(&p1,&p2,&ident); + if (ident == OMX_COMPONENT_GENERATE_EBD) { + pending_bd_q.insert_entry(p1,p2,ident); + } else { + tmp_q.insert_entry(p1,p2,ident); + } + } + //return all non GENERATE FDB to etb queue + while (tmp_q.m_size) { + tmp_q.pop_entry(&p1,&p2,&ident); + m_etb_q.insert_entry(p1,p2,ident); + } + pthread_mutex_unlock(&m_lock); + // process all pending buffer dones + while (pending_bd_q.m_size) { + pending_bd_q.pop_entry(&p1,&p2,&ident); + switch (ident) { + case OMX_COMPONENT_GENERATE_EBD: + if (empty_buffer_done(&m_cmp, (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("ERROR: empty_buffer_done() failed!"); + omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_FBD: + if (fill_buffer_done(&m_cmp, (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone ) { + DEBUG_PRINT_ERROR("ERROR: fill_buffer_done() failed!"); + omx_report_error (); + } + break; + } + } +} + +void omx_vdec::set_frame_rate(OMX_S64 act_timestamp) +{ + OMX_U32 new_frame_interval = 0; + if (VALID_TS(act_timestamp) && VALID_TS(prev_ts) && act_timestamp != prev_ts + && llabs(act_timestamp - prev_ts) > 2000) { + new_frame_interval = client_set_fps ? frm_int : (act_timestamp - prev_ts) > 0 ? + llabs(act_timestamp - prev_ts) : llabs(act_timestamp - prev_ts_actual); + if (new_frame_interval != frm_int || frm_int == 0) { + frm_int = new_frame_interval; + if (frm_int) { + drv_ctx.frame_rate.fps_numerator = 1e6; + drv_ctx.frame_rate.fps_denominator = frm_int; + DEBUG_PRINT_LOW("set_frame_rate: frm_int(%u) fps(%f)", + (unsigned int)frm_int, drv_ctx.frame_rate.fps_numerator / + (float)drv_ctx.frame_rate.fps_denominator); + m_perf_control.request_cores(frm_int); + /* We need to report the difference between this FBD and the previous FBD + * back to the driver for clock scaling purposes. */ + struct v4l2_outputparm oparm; + /*XXX: we're providing timing info as seconds per frame rather than frames + * per second.*/ + oparm.timeperframe.numerator = drv_ctx.frame_rate.fps_denominator; + oparm.timeperframe.denominator = drv_ctx.frame_rate.fps_numerator; + + struct v4l2_streamparm sparm; + sparm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + sparm.parm.output = oparm; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_PARM, &sparm)) { + DEBUG_PRINT_ERROR("Unable to convey fps info to driver, \ + performance might be affected"); + } + + } + } + } + prev_ts = act_timestamp; +} + +void omx_vdec::adjust_timestamp(OMX_S64 &act_timestamp) +{ + if (rst_prev_ts && VALID_TS(act_timestamp)) { + prev_ts = act_timestamp; + prev_ts_actual = act_timestamp; + rst_prev_ts = false; + } else if (VALID_TS(prev_ts)) { + bool codec_cond = (drv_ctx.timestamp_adjust)? + (!VALID_TS(act_timestamp) || act_timestamp < prev_ts_actual || llabs(act_timestamp - prev_ts_actual) <= 2000) : + (!VALID_TS(act_timestamp) || act_timestamp <= prev_ts_actual); + prev_ts_actual = act_timestamp; //unadjusted previous timestamp + if (frm_int > 0 && codec_cond) { + DEBUG_PRINT_LOW("adjust_timestamp: original ts[%lld]", act_timestamp); + act_timestamp = prev_ts + frm_int; + DEBUG_PRINT_LOW("adjust_timestamp: predicted ts[%lld]", act_timestamp); + prev_ts = act_timestamp; + } else { + if (drv_ctx.picture_order == VDEC_ORDER_DISPLAY && act_timestamp < prev_ts) { + // ensure that timestamps can never step backwards when in display order + act_timestamp = prev_ts; + } + set_frame_rate(act_timestamp); + } + } else if (frm_int > 0) // In this case the frame rate was set along + { // with the port definition, start ts with 0 + act_timestamp = prev_ts = 0; // and correct if a valid ts is received. + rst_prev_ts = true; + } +} + +OMX_BUFFERHEADERTYPE* omx_vdec::get_omx_output_buffer_header(int index) +{ + return m_out_mem_ptr + index; +} + +void omx_vdec::convert_color_space_info(OMX_U32 primaries, OMX_U32 range, + OMX_U32 transfer, OMX_U32 matrix, ColorSpace_t *color_space, ColorAspects *aspects) +{ + switch (primaries) { + case MSM_VIDC_BT709_5: + *color_space = ITU_R_709; + aspects->mPrimaries = ColorAspects::PrimariesBT709_5; + break; + case MSM_VIDC_BT470_6_M: + aspects->mPrimaries = ColorAspects::PrimariesBT470_6M; + break; + case MSM_VIDC_BT601_6_625: + aspects->mPrimaries = ColorAspects::PrimariesBT601_6_625; + break; + case MSM_VIDC_BT601_6_525: + *color_space = range ? ITU_R_601_FR : ITU_R_601; + aspects->mPrimaries = ColorAspects::PrimariesBT601_6_525; + break; + case MSM_VIDC_GENERIC_FILM: + aspects->mPrimaries = ColorAspects::PrimariesGenericFilm; + break; + case MSM_VIDC_BT2020: + aspects->mPrimaries = ColorAspects::PrimariesBT2020; + break; + case MSM_VIDC_UNSPECIFIED: + //Client does not expect ColorAspects::PrimariesUnspecified, but rather the supplied default + default: + //aspects->mPrimaries = ColorAspects::PrimariesOther; + aspects->mPrimaries = m_client_color_space.sAspects.mPrimaries; + break; + } + + aspects->mRange = range ? ColorAspects::RangeFull : ColorAspects::RangeLimited; + + switch (transfer) { + case MSM_VIDC_TRANSFER_BT709_5: + case MSM_VIDC_TRANSFER_601_6_525: // case MSM_VIDC_TRANSFER_601_6_625: + aspects->mTransfer = ColorAspects::TransferSMPTE170M; + break; + case MSM_VIDC_TRANSFER_BT_470_6_M: + aspects->mTransfer = ColorAspects::TransferGamma22; + break; + case MSM_VIDC_TRANSFER_BT_470_6_BG: + aspects->mTransfer = ColorAspects::TransferGamma28; + break; + case MSM_VIDC_TRANSFER_SMPTE_240M: + aspects->mTransfer = ColorAspects::TransferSMPTE240M; + break; + case MSM_VIDC_TRANSFER_LINEAR: + aspects->mTransfer = ColorAspects::TransferLinear; + break; + case MSM_VIDC_TRANSFER_IEC_61966: + aspects->mTransfer = ColorAspects::TransferXvYCC; + break; + case MSM_VIDC_TRANSFER_BT_1361: + aspects->mTransfer = ColorAspects::TransferBT1361; + break; + case MSM_VIDC_TRANSFER_SRGB: + aspects->mTransfer = ColorAspects::TransferSRGB; + break; + default: + //aspects->mTransfer = ColorAspects::TransferOther; + aspects->mTransfer = m_client_color_space.sAspects.mTransfer; + break; + } + + switch (matrix) { + case MSM_VIDC_MATRIX_BT_709_5: + aspects->mMatrixCoeffs = ColorAspects::MatrixBT709_5; + break; + case MSM_VIDC_MATRIX_FCC_47: + aspects->mMatrixCoeffs = ColorAspects::MatrixBT470_6M; + break; + case MSM_VIDC_MATRIX_601_6_625: + case MSM_VIDC_MATRIX_601_6_525: + aspects->mMatrixCoeffs = ColorAspects::MatrixBT601_6; + break; + case MSM_VIDC_MATRIX_SMPTE_240M: + aspects->mMatrixCoeffs = ColorAspects::MatrixSMPTE240M; + break; + case MSM_VIDC_MATRIX_BT_2020: + aspects->mMatrixCoeffs = ColorAspects::MatrixBT2020; + break; + case MSM_VIDC_MATRIX_BT_2020_CONST: + aspects->mMatrixCoeffs = ColorAspects::MatrixBT2020Constant; + break; + default: + //aspects->mMatrixCoeffs = ColorAspects::MatrixOther; + aspects->mMatrixCoeffs = m_client_color_space.sAspects.mMatrixCoeffs; + break; + } +} + +void omx_vdec::print_debug_color_aspects(ColorAspects *aspects, const char *prefix) { + DEBUG_PRINT_HIGH("%s : Color aspects : Primaries = %d Range = %d Transfer = %d MatrixCoeffs = %d", + prefix, aspects->mPrimaries, aspects->mRange, aspects->mTransfer, aspects->mMatrixCoeffs); +} + +bool omx_vdec::handle_color_space_info(void *data, unsigned int buf_index) +{ + ColorSpace_t color_space = ITU_R_601; + ColorAspects tempAspects; + memset(&tempAspects, 0x0, sizeof(ColorAspects)); + ColorAspects *aspects = &tempAspects; + + switch(output_capability) { + case V4L2_PIX_FMT_MPEG2: + { + struct msm_vidc_mpeg2_seqdisp_payload *seqdisp_payload; + seqdisp_payload = (struct msm_vidc_mpeg2_seqdisp_payload *)data; + + /* Refer MPEG2 Spec @ Rec. ISO/IEC 13818-2, ITU-T Draft Rec. H.262 to + * understand this code */ + + if (seqdisp_payload && seqdisp_payload->color_descp) { + + convert_color_space_info(seqdisp_payload->color_primaries, 1, + seqdisp_payload->transfer_char, seqdisp_payload->matrix_coeffs, + &color_space,aspects); + m_disp_hor_size = seqdisp_payload->disp_width; + m_disp_vert_size = seqdisp_payload->disp_height; + } + } + break; + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_HEVC: + { + struct msm_vidc_vui_display_info_payload *display_info_payload; + display_info_payload = (struct msm_vidc_vui_display_info_payload*)data; + + /* Refer H264 Spec @ Rec. ITU-T H.264 (02/2014) to understand this code */ + + if (display_info_payload->video_signal_present_flag && + display_info_payload->color_description_present_flag) { + convert_color_space_info(display_info_payload->color_primaries, + display_info_payload->video_full_range_flag, + display_info_payload->transfer_characteristics, + display_info_payload->matrix_coefficients, + &color_space,aspects); + } + } + break; + case V4L2_PIX_FMT_VC1_ANNEX_G: + case V4L2_PIX_FMT_VC1_ANNEX_L: + { + struct msm_vidc_vc1_seqdisp_payload *vc1_seq_disp_payload; + vc1_seq_disp_payload = (struct msm_vidc_vc1_seqdisp_payload*)data; + + /* Refer VC-1 Spec @ SMPTE Draft Standard for Television Date: 2005-08-23 + * SMPTE 421M to understand this code */ + + if (m_enable_android_native_buffers && + vc1_seq_disp_payload->color_primaries) { + + convert_color_space_info(vc1_seq_disp_payload->color_primaries, + 1, + vc1_seq_disp_payload->transfer_char, + vc1_seq_disp_payload->matrix_coeffs, + &color_space,aspects); + } + } + break; + case V4L2_PIX_FMT_VP8: + { + struct msm_vidc_vpx_colorspace_payload *vpx_color_space_payload; + vpx_color_space_payload = (struct msm_vidc_vpx_colorspace_payload*)data; + + /* Refer VP8 Data Format in latest VP8 spec and Decoding Guide November 2011 + * to understand this code */ + + if (vpx_color_space_payload->color_space == 0) { + color_space = ITU_R_601; + } else { + DEBUG_PRINT_ERROR("Unsupported Color space for VP8"); + break; + } + } + break; + case V4L2_PIX_FMT_VP9: + { + struct msm_vidc_vpx_colorspace_payload *vpx_color_space_payload; + vpx_color_space_payload = (struct msm_vidc_vpx_colorspace_payload*)data; + + /* Refer VP9 Spec @ VP9 Bitstream & Decoding Process Specification - v0.6 31st March 2016 + * to understand this code */ + + switch(vpx_color_space_payload->color_space) { + case MSM_VIDC_CS_BT_601: + aspects->mMatrixCoeffs = ColorAspects::MatrixBT601_6; + aspects->mTransfer = ColorAspects::TransferSMPTE170M; + aspects->mPrimaries = ColorAspects::PrimariesBT601_6_625; + aspects->mRange = m_client_color_space.sAspects.mRange; + break; + case MSM_VIDC_CS_BT_709: + color_space = ITU_R_709; + aspects->mMatrixCoeffs = ColorAspects::MatrixBT709_5; + aspects->mTransfer = ColorAspects::TransferSMPTE170M; + aspects->mPrimaries = ColorAspects::PrimariesBT709_5; + aspects->mRange = m_client_color_space.sAspects.mRange; + break; + case MSM_VIDC_CS_SMPTE_170: + aspects->mMatrixCoeffs = ColorAspects::MatrixBT709_5; + aspects->mTransfer = ColorAspects::TransferSMPTE170M; + aspects->mPrimaries = m_client_color_space.sAspects.mPrimaries; + aspects->mRange = m_client_color_space.sAspects.mRange; + break; + case MSM_VIDC_CS_SMPTE_240: + aspects->mMatrixCoeffs = m_client_color_space.sAspects.mMatrixCoeffs; + aspects->mTransfer = ColorAspects::TransferSMPTE240M; + aspects->mPrimaries = m_client_color_space.sAspects.mPrimaries; + aspects->mRange = m_client_color_space.sAspects.mRange; + break; + case MSM_VIDC_CS_BT_2020: + aspects->mMatrixCoeffs = ColorAspects::MatrixBT2020; + aspects->mTransfer = ColorAspects:: TransferSMPTE170M; + aspects->mPrimaries = ColorAspects::PrimariesBT2020; + aspects->mRange = m_client_color_space.sAspects.mRange; + break; + case MSM_VIDC_CS_RESERVED: + aspects->mMatrixCoeffs = ColorAspects::MatrixOther; + aspects->mTransfer = ColorAspects::TransferOther; + aspects->mPrimaries = ColorAspects::PrimariesOther; + aspects->mRange = m_client_color_space.sAspects.mRange; + break; + case MSM_VIDC_CS_RGB: + aspects->mMatrixCoeffs = ColorAspects::MatrixBT709_5; + aspects->mTransfer = ColorAspects::TransferSMPTE170M; + aspects->mPrimaries = ColorAspects::PrimariesOther; + aspects->mRange = m_client_color_space.sAspects.mRange; + break; + default: + break; + } + } + break; + default: + break; + } + if (m_enable_android_native_buffers) { + DEBUG_PRINT_HIGH("setMetaData for Color Space = 0x%x (601=%u FR=%u 709=%u)", color_space, ITU_R_601, ITU_R_601_FR, ITU_R_709); + set_colorspace_in_handle(color_space, buf_index); + } + print_debug_color_aspects(aspects, "Bitstream"); + + if (m_internal_color_space.sAspects.mPrimaries != aspects->mPrimaries || + m_internal_color_space.sAspects.mTransfer != aspects->mTransfer || + m_internal_color_space.sAspects.mMatrixCoeffs != aspects->mMatrixCoeffs || + m_internal_color_space.sAspects.mRange != aspects->mRange) { + memcpy(&(m_internal_color_space.sAspects), aspects, sizeof(ColorAspects)); + m_internal_color_space.bDataSpaceChanged = OMX_TRUE; + + DEBUG_PRINT_HIGH("Initiating PORT Reconfig due to Color Aspects Change"); + print_debug_color_aspects(&(m_internal_color_space.sAspects), "Internal"); + print_debug_color_aspects(&(m_client_color_space.sAspects), "Client"); + + post_event(OMX_CORE_OUTPUT_PORT_INDEX, + OMX_QTIIndexConfigDescribeColorAspects, + OMX_COMPONENT_GENERATE_PORT_RECONFIG); + return true; + } + return false; +} + +void omx_vdec::set_colorspace_in_handle(ColorSpace_t color_space, unsigned int buf_index) { + private_handle_t *private_handle = NULL; + if (buf_index < drv_ctx.op_buf.actualcount && + buf_index < MAX_NUM_INPUT_OUTPUT_BUFFERS && + native_buffer[buf_index].privatehandle) { + private_handle = native_buffer[buf_index].privatehandle; + } + if (private_handle) { + setMetaData(private_handle, UPDATE_COLOR_SPACE, (void*)&color_space); + } +} + +void omx_vdec::print_debug_hdr_color_info(HDRStaticInfo *hdr_info, const char *prefix) +{ + if (!hdr_info->mID) { + DEBUG_PRINT_LOW("%s : HDRstaticinfo MDC: mR.x = %d mR.y = %d", prefix, + hdr_info->sType1.mR.x, hdr_info->sType1.mR.y); + DEBUG_PRINT_LOW("%s : HDRstaticinfo MDC: mG.x = %d mG.y = %d", prefix, + hdr_info->sType1.mG.x, hdr_info->sType1.mG.y); + DEBUG_PRINT_LOW("%s : HDRstaticinfo MDC: mB.x = %d mB.y = %d", prefix, + hdr_info->sType1.mB.x, hdr_info->sType1.mB.y); + DEBUG_PRINT_LOW("%s : HDRstaticinfo MDC: mW.x = %d mW.y = %d", prefix, + hdr_info->sType1.mW.x, hdr_info->sType1.mW.y); + DEBUG_PRINT_LOW("%s : HDRstaticinfo MDC: maxDispLum = %d minDispLum = %d", prefix, + hdr_info->sType1.mMaxDisplayLuminance, hdr_info->sType1.mMinDisplayLuminance); + DEBUG_PRINT_LOW("%s : HDRstaticinfo CLL: CLL = %d FLL = %d", prefix, + hdr_info->sType1.mMaxContentLightLevel, hdr_info->sType1.mMaxFrameAverageLightLevel); + } + +} + + + +bool omx_vdec::handle_content_light_level_info(void* data) +{ + struct msm_vidc_content_light_level_sei_payload *light_level_payload = + (msm_vidc_content_light_level_sei_payload*)(data); + + if ((m_internal_hdr_info.sInfo.sType1.mMaxContentLightLevel != light_level_payload->nMaxContentLight) || + (m_internal_hdr_info.sInfo.sType1.mMaxFrameAverageLightLevel != light_level_payload->nMaxPicAverageLight)) { + m_internal_hdr_info.sInfo.sType1.mMaxContentLightLevel = light_level_payload->nMaxContentLight; + m_internal_hdr_info.sInfo.sType1.mMaxFrameAverageLightLevel = light_level_payload->nMaxPicAverageLight; + return true; + } + return false; +} + +bool omx_vdec::handle_mastering_display_color_info(void* data) +{ + struct msm_vidc_mastering_display_colour_sei_payload *mastering_display_payload = + (msm_vidc_mastering_display_colour_sei_payload*)(data); + HDRStaticInfo* hdr_info = &m_internal_hdr_info.sInfo; + bool internal_disp_changed_flag = false; + + internal_disp_changed_flag = (hdr_info->sType1.mR.x != mastering_display_payload->nDisplayPrimariesX[0]) || + (hdr_info->sType1.mR.y != mastering_display_payload->nDisplayPrimariesY[0]); + internal_disp_changed_flag |= (hdr_info->sType1.mG.x != mastering_display_payload->nDisplayPrimariesX[1]) || + (hdr_info->sType1.mG.y != mastering_display_payload->nDisplayPrimariesY[1]); + internal_disp_changed_flag |= (hdr_info->sType1.mB.x != mastering_display_payload->nDisplayPrimariesX[2]) || + (hdr_info->sType1.mB.y != mastering_display_payload->nDisplayPrimariesY[2]); + + internal_disp_changed_flag |= (hdr_info->sType1.mW.x != mastering_display_payload->nWhitePointX) || + (hdr_info->sType1.mW.y != mastering_display_payload->nWhitePointY); + + internal_disp_changed_flag != (hdr_info->sType1.mMaxDisplayLuminance != mastering_display_payload->nMaxDisplayMasteringLuminance) || + (hdr_info->sType1.mMinDisplayLuminance != mastering_display_payload->nMinDisplayMasteringLuminance); + + if (internal_disp_changed_flag) { + hdr_info->sType1.mR.x = mastering_display_payload->nDisplayPrimariesX[0]; + hdr_info->sType1.mR.y = mastering_display_payload->nDisplayPrimariesY[0]; + hdr_info->sType1.mG.x = mastering_display_payload->nDisplayPrimariesX[1]; + hdr_info->sType1.mG.y = mastering_display_payload->nDisplayPrimariesY[1]; + hdr_info->sType1.mB.x = mastering_display_payload->nDisplayPrimariesX[2]; + hdr_info->sType1.mB.y = mastering_display_payload->nDisplayPrimariesY[2]; + hdr_info->sType1.mW.x = mastering_display_payload->nWhitePointX; + hdr_info->sType1.mW.y = mastering_display_payload->nWhitePointY; + + hdr_info->sType1.mMaxDisplayLuminance = mastering_display_payload->nMaxDisplayMasteringLuminance; + hdr_info->sType1.mMinDisplayLuminance = mastering_display_payload->nMinDisplayMasteringLuminance; + } + + return internal_disp_changed_flag; +} + +void omx_vdec::handle_extradata(OMX_BUFFERHEADERTYPE *p_buf_hdr) +{ + OMX_OTHER_EXTRADATATYPE *p_extra = NULL, *p_sei = NULL, *p_vui = NULL, *p_client_extra = NULL; + OMX_U8 *pBuffer = NULL; + OMX_U32 num_conceal_MB = 0; + OMX_TICKS time_stamp = 0; + OMX_U32 frame_rate = 0; + unsigned long consumed_len = 0; + OMX_U32 num_MB_in_frame; + OMX_U32 recovery_sei_flags = 1; + int enable = OMX_InterlaceFrameProgressive; + bool internal_hdr_info_changed_flag = false; + bool color_event = false; + if (output_flush_progress) + return; + + int buf_index = p_buf_hdr - m_out_mem_ptr; + if (buf_index >= drv_ctx.extradata_info.count) { + DEBUG_PRINT_ERROR("handle_extradata: invalid index(%d) max(%d)", + buf_index, drv_ctx.extradata_info.count); + return; + } + struct msm_vidc_panscan_window_payload *panscan_payload = NULL; + + if (drv_ctx.ptr_outputbuffer[buf_index].bufferaddr == NULL) { + DEBUG_PRINT_ERROR("handle_extradata: Error: Mapped output buffer address is NULL"); + return; + } + + if (!drv_ctx.extradata_info.uaddr) { + DEBUG_PRINT_HIGH("NULL drv_ctx.extradata_info.uaddr"); + return; + } + if (!secure_mode && (drv_ctx.extradata_info.buffer_size > (p_buf_hdr->nAllocLen - p_buf_hdr->nFilledLen)) ) { + DEBUG_PRINT_ERROR("Error: Insufficient size allocated for extra-data"); + p_extra = NULL; + return; + } + if (!secure_mode) { + pBuffer = (OMX_U8*)mmap(0, drv_ctx.ptr_outputbuffer[buf_index].buffer_len, + PROT_READ|PROT_WRITE, MAP_SHARED, drv_ctx.ptr_outputbuffer[buf_index].pmem_fd, 0); + if (pBuffer == MAP_FAILED) { + DEBUG_PRINT_ERROR("handle_extradata output buffer mmap failed - errno: %d", errno); + return; + } + p_extra = (OMX_OTHER_EXTRADATATYPE *) + ((unsigned long)(pBuffer + p_buf_hdr->nOffset + p_buf_hdr->nFilledLen + 3)&(~3)); + } else + p_extra = m_other_extradata; + + AutoUnmap autounmap(pBuffer, drv_ctx.ptr_outputbuffer[buf_index].buffer_len); + if (m_client_extradata_info.getBase() && + m_client_extradata_info.getSize() >= drv_ctx.extradata_info.buffer_size) { + p_client_extra = (OMX_OTHER_EXTRADATATYPE *) (m_client_extradata_info.getBase() + + buf_index * m_client_extradata_info.getSize()); + } + + char *p_extradata = drv_ctx.extradata_info.uaddr + buf_index * drv_ctx.extradata_info.buffer_size; + + if (!secure_mode && ((OMX_U8*)p_extra > (pBuffer + p_buf_hdr->nAllocLen))) { + p_extra = NULL; + DEBUG_PRINT_ERROR("Error: out of bound memory access by p_extra"); + return; + } + m_extradata_info.output_crop_updated = OMX_FALSE; + OMX_OTHER_EXTRADATATYPE *data = (struct OMX_OTHER_EXTRADATATYPE *)p_extradata; + if (data && p_extra) { + while ((consumed_len < drv_ctx.extradata_info.buffer_size) + && (data->eType != (OMX_EXTRADATATYPE)MSM_VIDC_EXTRADATA_NONE)) { + if ((consumed_len + data->nSize) > (unsigned)drv_ctx.extradata_info.buffer_size) { + DEBUG_PRINT_LOW("Invalid extra data size"); + break; + } + + if (!secure_mode && ((OMX_U8*)p_extra > (pBuffer + p_buf_hdr->nAllocLen))) { + p_extra = NULL; + DEBUG_PRINT_ERROR("Error: out of bound memory access by p_extra"); + return; + } + + DEBUG_PRINT_LOW("handle_extradata: eType = 0x%x", data->eType); + switch ((unsigned long)data->eType) { + case MSM_VIDC_EXTRADATA_INTERLACE_VIDEO: + struct msm_vidc_interlace_payload *payload; + OMX_U32 interlace_color_format; + payload = (struct msm_vidc_interlace_payload *)(void *)data->data; + if (payload) { + enable = OMX_InterlaceFrameProgressive; + switch (payload->format) { + case MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE: + drv_ctx.interlace = VDEC_InterlaceFrameProgressive; + break; + case MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST: + drv_ctx.interlace = VDEC_InterlaceInterleaveFrameTopFieldFirst; + enable = OMX_InterlaceInterleaveFrameTopFieldFirst; + break; + case MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST: + drv_ctx.interlace = VDEC_InterlaceInterleaveFrameBottomFieldFirst; + enable = OMX_InterlaceInterleaveFrameBottomFieldFirst; + break; + default: + DEBUG_PRINT_LOW("default case - set to progressive"); + drv_ctx.interlace = VDEC_InterlaceFrameProgressive; + } + switch (payload->color_format) { + case MSM_VIDC_HAL_INTERLACE_COLOR_FORMAT_NV12: + interlace_color_format = (int)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + break; + case MSM_VIDC_HAL_INTERLACE_COLOR_FORMAT_NV12_UBWC: + interlace_color_format = (int)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed; + break; + default: + interlace_color_format = (int)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + DEBUG_PRINT_ERROR("Error - Unknown color format hint for interlaced frame"); + } + } + + if (m_enable_android_native_buffers) { + DEBUG_PRINT_LOW("setMetaData INTERLACED format:%d color_format: %x enable:%d mbaff:%d", + payload->format, interlace_color_format ,enable, + (p_buf_hdr->nFlags & QOMX_VIDEO_BUFFERFLAG_MBAFF)?true:false); + + setMetaData((private_handle_t *)native_buffer[buf_index].privatehandle, + PP_PARAM_INTERLACED, (void*)&enable); + + if (interlace_color_format == QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m) { + setMetaData((private_handle_t *)native_buffer[buf_index].privatehandle, + LINEAR_FORMAT, (void*)&interlace_color_format); + } else if (interlace_color_format == QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed) { + setMetaData((private_handle_t *)native_buffer[buf_index].privatehandle, + LINEAR_FORMAT, NULL); + } + } + if (client_extradata & OMX_INTERLACE_EXTRADATA) { + append_interlace_extradata(p_extra, payload->format); + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + ALIGN(p_extra->nSize, 4)); + if (p_client_extra) { + append_interlace_extradata(p_client_extra, payload->format); + p_client_extra = (OMX_OTHER_EXTRADATATYPE *) + (((OMX_U8 *)p_client_extra) + ALIGN(p_client_extra->nSize, 4)); + } + } + break; + case MSM_VIDC_EXTRADATA_FRAME_RATE: + struct msm_vidc_framerate_payload *frame_rate_payload; + frame_rate_payload = (struct msm_vidc_framerate_payload *)(void *)data->data; + frame_rate = frame_rate_payload->frame_rate; + break; + case MSM_VIDC_EXTRADATA_TIMESTAMP: + struct msm_vidc_ts_payload *time_stamp_payload; + time_stamp_payload = (struct msm_vidc_ts_payload *)(void *)data->data; + time_stamp = time_stamp_payload->timestamp_lo; + time_stamp |= ((unsigned long long)time_stamp_payload->timestamp_hi << 32); + p_buf_hdr->nTimeStamp = time_stamp; + break; + case MSM_VIDC_EXTRADATA_NUM_CONCEALED_MB: + struct msm_vidc_concealmb_payload *conceal_mb_payload; + conceal_mb_payload = (struct msm_vidc_concealmb_payload *)(void *)data->data; + num_MB_in_frame = ((drv_ctx.video_resolution.frame_width + 15) * + (drv_ctx.video_resolution.frame_height + 15)) >> 8; + num_conceal_MB = ((num_MB_in_frame > 0)?(conceal_mb_payload->num_mbs * 100 / num_MB_in_frame) : 0); + break; + case MSM_VIDC_EXTRADATA_INDEX: + int *etype; + etype = (int *)(void *)data->data; + if (etype && *etype == MSM_VIDC_EXTRADATA_ASPECT_RATIO) { + struct msm_vidc_aspect_ratio_payload *aspect_ratio_payload; + aspect_ratio_payload = (struct msm_vidc_aspect_ratio_payload *)(++etype); + if (aspect_ratio_payload) { + ((struct vdec_output_frameinfo *) + p_buf_hdr->pOutputPortPrivate)->aspect_ratio_info.par_width = aspect_ratio_payload->aspect_width; + ((struct vdec_output_frameinfo *) + p_buf_hdr->pOutputPortPrivate)->aspect_ratio_info.par_height = aspect_ratio_payload->aspect_height; + } + } else if (etype && *etype == MSM_VIDC_EXTRADATA_OUTPUT_CROP) { + struct msm_vidc_output_crop_payload *output_crop_payload; + output_crop_payload = (struct msm_vidc_output_crop_payload *)(++etype); + if (output_crop_payload) { + m_extradata_info.output_crop_rect.nLeft = output_crop_payload->left; + m_extradata_info.output_crop_rect.nTop = output_crop_payload->top; + m_extradata_info.output_crop_rect.nWidth = output_crop_payload->left + output_crop_payload->display_width; + m_extradata_info.output_crop_rect.nHeight = output_crop_payload->top + output_crop_payload->display_height; + m_extradata_info.output_width = output_crop_payload->width; + m_extradata_info.output_height = output_crop_payload->height; + m_extradata_info.output_crop_updated = OMX_TRUE; + } + } + break; + case MSM_VIDC_EXTRADATA_RECOVERY_POINT_SEI: + struct msm_vidc_recoverysei_payload *recovery_sei_payload; + recovery_sei_payload = (struct msm_vidc_recoverysei_payload *)(void *)data->data; + recovery_sei_flags = recovery_sei_payload->flags; + if (recovery_sei_flags != MSM_VIDC_FRAME_RECONSTRUCTION_CORRECT) { + p_buf_hdr->nFlags |= OMX_BUFFERFLAG_DATACORRUPT; + DEBUG_PRINT_HIGH("***************************************************"); + DEBUG_PRINT_HIGH("FillBufferDone: OMX_BUFFERFLAG_DATACORRUPT Received"); + DEBUG_PRINT_HIGH("***************************************************"); + } + break; + case MSM_VIDC_EXTRADATA_PANSCAN_WINDOW: + panscan_payload = (struct msm_vidc_panscan_window_payload *)(void *)data->data; + if (panscan_payload->num_panscan_windows > MAX_PAN_SCAN_WINDOWS) { + DEBUG_PRINT_ERROR("Panscan windows are more than supported\n"); + DEBUG_PRINT_ERROR("Max supported = %d FW returned = %d\n", + MAX_PAN_SCAN_WINDOWS, panscan_payload->num_panscan_windows); + return; + } + break; + case MSM_VIDC_EXTRADATA_MPEG2_SEQDISP: + case MSM_VIDC_EXTRADATA_VUI_DISPLAY_INFO: + case MSM_VIDC_EXTRADATA_VC1_SEQDISP: + case MSM_VIDC_EXTRADATA_VPX_COLORSPACE_INFO: + color_event = handle_color_space_info((void *)data->data, buf_index); + break; + case MSM_VIDC_EXTRADATA_S3D_FRAME_PACKING: + struct msm_vidc_s3d_frame_packing_payload *s3d_frame_packing_payload; + s3d_frame_packing_payload = (struct msm_vidc_s3d_frame_packing_payload *)(void *)data->data; + switch (s3d_frame_packing_payload->fpa_type) { + case MSM_VIDC_FRAMEPACK_SIDE_BY_SIDE: + if (s3d_frame_packing_payload->content_interprtation_type == 1) + stereo_output_mode = HAL_3D_SIDE_BY_SIDE_L_R; + else if (s3d_frame_packing_payload->content_interprtation_type == 2) + stereo_output_mode = HAL_3D_SIDE_BY_SIDE_R_L; + else { + DEBUG_PRINT_ERROR("Unsupported side-by-side framepacking type"); + stereo_output_mode = HAL_NO_3D; + } + break; + case MSM_VIDC_FRAMEPACK_TOP_BOTTOM: + stereo_output_mode = HAL_3D_TOP_BOTTOM; + break; + default: + DEBUG_PRINT_ERROR("Unsupported framepacking type"); + stereo_output_mode = HAL_NO_3D; + } + DEBUG_PRINT_LOW("setMetaData FRAMEPACKING : fpa_type = %u, content_interprtation_type = %u, stereo_output_mode= %d", + s3d_frame_packing_payload->fpa_type, s3d_frame_packing_payload->content_interprtation_type, stereo_output_mode); + if (client_extradata & OMX_FRAMEPACK_EXTRADATA) { + append_framepack_extradata(p_extra, s3d_frame_packing_payload); + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + ALIGN(p_extra->nSize, 4)); + if (p_client_extra) { + append_framepack_extradata(p_client_extra, s3d_frame_packing_payload); + p_client_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_client_extra) + ALIGN(p_client_extra->nSize, 4)); + } + } + break; + case MSM_VIDC_EXTRADATA_FRAME_QP: + struct msm_vidc_frame_qp_payload *qp_payload; + qp_payload = (struct msm_vidc_frame_qp_payload*)(void *)data->data; + if (client_extradata & OMX_QP_EXTRADATA) { + append_qp_extradata(p_extra, qp_payload); + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + ALIGN(p_extra->nSize, 4)); + if (p_client_extra) { + append_qp_extradata(p_client_extra, qp_payload); + p_client_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_client_extra) + ALIGN(p_client_extra->nSize, 4)); + } + } + break; + case MSM_VIDC_EXTRADATA_FRAME_BITS_INFO: + struct msm_vidc_frame_bits_info_payload *bits_info_payload; + bits_info_payload = (struct msm_vidc_frame_bits_info_payload*)(void *)data->data; + if (client_extradata & OMX_BITSINFO_EXTRADATA) { + append_bitsinfo_extradata(p_extra, bits_info_payload); + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + ALIGN(p_extra->nSize, 4)); + if (p_client_extra) { + append_bitsinfo_extradata(p_client_extra, bits_info_payload); + p_client_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_client_extra) + ALIGN(p_client_extra->nSize, 4)); + } + } + break; + case MSM_VIDC_EXTRADATA_STREAM_USERDATA: + if (client_extradata & OMX_EXTNUSER_EXTRADATA) { + append_user_extradata(p_extra, data); + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + ALIGN(p_extra->nSize, 4)); + if (p_client_extra) { + append_user_extradata(p_client_extra, data); + p_client_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_client_extra) + ALIGN(p_client_extra->nSize, 4)); + } + } + break; + case MSM_VIDC_EXTRADATA_VQZIP_SEI: + struct msm_vidc_vqzip_sei_payload *vqzip_payload; + vqzip_payload = (struct msm_vidc_vqzip_sei_payload*)(void *)data->data; + if (client_extradata & OMX_VQZIPSEI_EXTRADATA) { + p_buf_hdr->nFlags |= OMX_BUFFERFLAG_EXTRADATA; + append_vqzip_extradata(p_extra, vqzip_payload); + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + ALIGN(p_extra->nSize, 4)); + if (p_client_extra) { + append_vqzip_extradata(p_client_extra, vqzip_payload); + p_client_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_client_extra) + ALIGN(p_client_extra->nSize, 4)); + } + } + break; + case MSM_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI: + internal_hdr_info_changed_flag |= handle_content_light_level_info((void*)data->data); + break; + case MSM_VIDC_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI: + internal_hdr_info_changed_flag |= handle_mastering_display_color_info((void*)data->data); + break; + default: + DEBUG_PRINT_LOW("Unrecognized extradata"); + goto unrecognized_extradata; + } + consumed_len += data->nSize; + data = (OMX_OTHER_EXTRADATATYPE *)((char *)data + data->nSize); + } + if (client_extradata & OMX_FRAMEINFO_EXTRADATA) { + p_buf_hdr->nFlags |= OMX_BUFFERFLAG_EXTRADATA; + append_frame_info_extradata(p_extra, + num_conceal_MB, ((struct vdec_output_frameinfo *)p_buf_hdr->pOutputPortPrivate)->pic_type, frame_rate, + time_stamp, panscan_payload,&((struct vdec_output_frameinfo *) + p_buf_hdr->pOutputPortPrivate)->aspect_ratio_info); + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + ALIGN(p_extra->nSize, 4)); + if (p_client_extra) { + append_frame_info_extradata(p_client_extra, + num_conceal_MB, ((struct vdec_output_frameinfo *)p_buf_hdr->pOutputPortPrivate)->pic_type, frame_rate, + time_stamp, panscan_payload,&((struct vdec_output_frameinfo *) + p_buf_hdr->pOutputPortPrivate)->aspect_ratio_info); + p_client_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_client_extra) + ALIGN(p_client_extra->nSize, 4)); + } + } + if (client_extradata & OMX_FRAMEDIMENSION_EXTRADATA) { + append_frame_dimension_extradata(p_extra); + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + ALIGN(p_extra->nSize, 4)); + if (p_client_extra) { + append_frame_dimension_extradata(p_client_extra); + p_client_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_client_extra) + ALIGN(p_client_extra->nSize, 4)); + } + } + + if(internal_hdr_info_changed_flag) { + print_debug_hdr_color_info(&(m_internal_hdr_info.sInfo), "Internal"); + print_debug_hdr_color_info(&(m_client_hdr_info.sInfo), "Client"); + auto_lock lock(m_hdr_info_client_lock); + m_change_client_hdr_info = true; + if(!color_event) { + DEBUG_PRINT_HIGH("Initiating PORT Reconfig due to HDR Info Change"); + post_event(OMX_CORE_OUTPUT_PORT_INDEX, + OMX_QTIIndexConfigDescribeHDRColorInfo, + OMX_COMPONENT_GENERATE_PORT_RECONFIG); + } + } + + } +unrecognized_extradata: + if (client_extradata && p_extra) { + p_buf_hdr->nFlags |= OMX_BUFFERFLAG_EXTRADATA; + append_terminator_extradata(p_extra); + if (p_client_extra) { + append_terminator_extradata(p_client_extra); + } + } + if (secure_mode && p_extradata && m_other_extradata) { + struct vdec_output_frameinfo *ptr_extradatabuff = NULL; + memcpy(p_extradata, m_other_extradata, drv_ctx.extradata_info.buffer_size); + ptr_extradatabuff = (struct vdec_output_frameinfo *)p_buf_hdr->pOutputPortPrivate; + ptr_extradatabuff->metadata_info.metabufaddr = (void *)p_extradata; + ptr_extradatabuff->metadata_info.size = drv_ctx.extradata_info.buffer_size; + ptr_extradatabuff->metadata_info.fd = drv_ctx.extradata_info.ion.fd_ion_data.fd; + ptr_extradatabuff->metadata_info.offset = buf_index * drv_ctx.extradata_info.buffer_size; + ptr_extradatabuff->metadata_info.buffer_size = drv_ctx.extradata_info.size; + } + return; +} + +OMX_ERRORTYPE omx_vdec::enable_extradata(OMX_U64 requested_extradata, + bool is_internal, bool enable) +{ + OMX_ERRORTYPE ret = OMX_ErrorNone; + struct v4l2_control control; + if (m_state != OMX_StateLoaded) { + DEBUG_PRINT_ERROR("ERROR: enable extradata allowed in Loaded state only"); + return OMX_ErrorIncorrectStateOperation; + } + DEBUG_PRINT_HIGH("NOTE: enable_extradata: actual[%u] requested[%u] enable[%d], is_internal: %d", + (unsigned int)client_extradata, (unsigned int)requested_extradata, enable, is_internal); + + if (!is_internal) { + if (enable) + client_extradata |= requested_extradata; + else + client_extradata = client_extradata & ~requested_extradata; + } + + if (enable) { + if (requested_extradata & OMX_INTERLACE_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set interlaced extradata." + " Quality of interlaced clips might be impacted."); + } + } + if (requested_extradata & OMX_FRAMEINFO_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set framerate extradata"); + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set concealed MB extradata"); + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set recovery point SEI extradata"); + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set panscan extradata"); + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set panscan extradata"); + } + if (output_capability == V4L2_PIX_FMT_MPEG2) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set panscan extradata"); + } + } + } + if (requested_extradata & OMX_TIMEINFO_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set timeinfo extradata"); + } + } + if (!secure_mode && (requested_extradata & OMX_FRAMEPACK_EXTRADATA)) { + if (output_capability == V4L2_PIX_FMT_H264) { + DEBUG_PRINT_HIGH("enable OMX_FRAMEPACK_EXTRADATA"); + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set S3D_FRAME_PACKING extradata"); + } + } else { + DEBUG_PRINT_HIGH("OMX_FRAMEPACK_EXTRADATA supported for H264 only"); + } + } + if (requested_extradata & OMX_QP_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set QP extradata"); + } + } + if (requested_extradata & OMX_BITSINFO_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set frame bits info extradata"); + } + } + if (!secure_mode && (requested_extradata & OMX_EXTNUSER_EXTRADATA)) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set stream userdata extradata"); + } + } + if (requested_extradata & OMX_VQZIPSEI_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_VQZIP_SEI; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set VQZip SEI extradata"); + } + client_extradata |= OMX_VQZIPSEI_EXTRADATA; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set QP extradata"); + } + client_extradata |= OMX_QP_EXTRADATA; + } + if (requested_extradata & OMX_OUTPUTCROP_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_OUTPUT_CROP; + DEBUG_PRINT_LOW("Enable output crop extra data"); + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set output crop extradata"); + } + } + if (requested_extradata & OMX_DISPLAY_INFO_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + switch(output_capability) { + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_HEVC: + control.value = V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY; + break; + case CODEC_TYPE_MPEG2: + control.value = V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP; + break; + case V4L2_PIX_FMT_VP8: + case V4L2_PIX_FMT_VP9: + control.value = V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE; + break; + case V4L2_PIX_FMT_VC1_ANNEX_G: + case V4L2_PIX_FMT_VC1_ANNEX_L: + control.value = V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP; + break; + default: + DEBUG_PRINT_HIGH("Don't support Disp info for this codec : %s", drv_ctx.kind); + return ret; + } + + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set Display info extradata"); + } + } + if (requested_extradata & OMX_HDR_COLOR_INFO_EXTRADATA) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + if (output_capability == V4L2_PIX_FMT_H264 || + output_capability == V4L2_PIX_FMT_HEVC) { + control.value = V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set Display Colour SEI extradata"); + } + control.value = V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_HIGH("Failed to set Content Light Level SEI extradata"); + } + } + } + } + ret = get_buffer_req(&drv_ctx.op_buf); + return ret; +} + +OMX_U32 omx_vdec::count_MB_in_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + OMX_U32 num_MB = 0, byte_count = 0, num_MB_in_frame = 0; + OMX_U8 *data_ptr = extra->data, data = 0; + while (byte_count < extra->nDataSize) { + data = *data_ptr; + while (data) { + num_MB += (data&0x01); + data >>= 1; + } + data_ptr++; + byte_count++; + } + num_MB_in_frame = ((drv_ctx.video_resolution.frame_width + 15) * + (drv_ctx.video_resolution.frame_height + 15)) >> 8; + return ((num_MB_in_frame > 0)?(num_MB * 100 / num_MB_in_frame) : 0); +} + +void omx_vdec::print_debug_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + if (!m_debug_extradata || !extra) + return; + + + DEBUG_PRINT_HIGH( + "============== Extra Data ==============\n" + " Size: %u\n" + " Version: %u\n" + " PortIndex: %u\n" + " Type: %x\n" + " DataSize: %u", + (unsigned int)extra->nSize, (unsigned int)extra->nVersion.nVersion, + (unsigned int)extra->nPortIndex, extra->eType, (unsigned int)extra->nDataSize); + + if (extra->eType == (OMX_EXTRADATATYPE)OMX_ExtraDataInterlaceFormat) { + OMX_STREAMINTERLACEFORMAT *intfmt = (OMX_STREAMINTERLACEFORMAT *)(void *)extra->data; + DEBUG_PRINT_HIGH( + "------ Interlace Format ------\n" + " Size: %u\n" + " Version: %u\n" + " PortIndex: %u\n" + " Is Interlace Format: %d\n" + " Interlace Formats: %u\n" + "=========== End of Interlace ===========", + (unsigned int)intfmt->nSize, (unsigned int)intfmt->nVersion.nVersion, (unsigned int)intfmt->nPortIndex, + intfmt->bInterlaceFormat, (unsigned int)intfmt->nInterlaceFormats); + } else if (extra->eType == (OMX_EXTRADATATYPE)OMX_ExtraDataFrameInfo) { + OMX_QCOM_EXTRADATA_FRAMEINFO *fminfo = (OMX_QCOM_EXTRADATA_FRAMEINFO *)(void *)extra->data; + + DEBUG_PRINT_HIGH( + "-------- Frame Format --------\n" + " Picture Type: %d\n" + " Interlace Type: %d\n" + " Pan Scan Total Frame Num: %u\n" + " Concealed Macro Blocks: %u\n" + " frame rate: %u\n" + " Time Stamp: %llu\n" + " Aspect Ratio X: %u\n" + " Aspect Ratio Y: %u", + fminfo->ePicType, + fminfo->interlaceType, + (unsigned int)fminfo->panScan.numWindows, + (unsigned int)fminfo->nConcealedMacroblocks, + (unsigned int)fminfo->nFrameRate, + fminfo->nTimeStamp, + (unsigned int)fminfo->aspectRatio.aspectRatioX, + (unsigned int)fminfo->aspectRatio.aspectRatioY); + + for (OMX_U32 i = 0; i < fminfo->panScan.numWindows; i++) { + DEBUG_PRINT_HIGH( + "------------------------------" + " Pan Scan Frame Num: %u\n" + " Rectangle x: %d\n" + " Rectangle y: %d\n" + " Rectangle dx: %d\n" + " Rectangle dy: %d", + (unsigned int)i, (unsigned int)fminfo->panScan.window[i].x, (unsigned int)fminfo->panScan.window[i].y, + (unsigned int)fminfo->panScan.window[i].dx, (unsigned int)fminfo->panScan.window[i].dy); + } + + DEBUG_PRINT_HIGH("========= End of Frame Format =========="); + } else if (extra->eType == (OMX_EXTRADATATYPE)OMX_ExtraDataFramePackingArrangement) { + OMX_QCOM_FRAME_PACK_ARRANGEMENT *framepack = (OMX_QCOM_FRAME_PACK_ARRANGEMENT *)(void *)extra->data; + DEBUG_PRINT_HIGH( + "------------------ Framepack Format ----------\n" + " id: %u \n" + " cancel_flag: %u \n" + " type: %u \n" + " quincunx_sampling_flagFormat: %u \n" + " content_interpretation_type: %u \n" + " spatial_flipping_flag: %u \n" + " frame0_flipped_flag: %u \n" + " field_views_flag: %u \n" + " current_frame_is_frame0_flag: %u \n" + " frame0_self_contained_flag: %u \n" + " frame1_self_contained_flag: %u \n" + " frame0_grid_position_x: %u \n" + " frame0_grid_position_y: %u \n" + " frame1_grid_position_x: %u \n" + " frame1_grid_position_y: %u \n" + " reserved_byte: %u \n" + " repetition_period: %u \n" + " extension_flag: %u \n" + "================== End of Framepack ===========", + (unsigned int)framepack->id, + (unsigned int)framepack->cancel_flag, + (unsigned int)framepack->type, + (unsigned int)framepack->quincunx_sampling_flag, + (unsigned int)framepack->content_interpretation_type, + (unsigned int)framepack->spatial_flipping_flag, + (unsigned int)framepack->frame0_flipped_flag, + (unsigned int)framepack->field_views_flag, + (unsigned int)framepack->current_frame_is_frame0_flag, + (unsigned int)framepack->frame0_self_contained_flag, + (unsigned int)framepack->frame1_self_contained_flag, + (unsigned int)framepack->frame0_grid_position_x, + (unsigned int)framepack->frame0_grid_position_y, + (unsigned int)framepack->frame1_grid_position_x, + (unsigned int)framepack->frame1_grid_position_y, + (unsigned int)framepack->reserved_byte, + (unsigned int)framepack->repetition_period, + (unsigned int)framepack->extension_flag); + } else if (extra->eType == (OMX_EXTRADATATYPE)OMX_ExtraDataQP) { + OMX_QCOM_EXTRADATA_QP * qp = (OMX_QCOM_EXTRADATA_QP *)(void *)extra->data; + DEBUG_PRINT_HIGH( + "---- QP (Frame quantization parameter) ----\n" + " Frame QP: %u \n" + "================ End of QP ================\n", + (unsigned int)qp->nQP); + } else if (extra->eType == (OMX_EXTRADATATYPE)OMX_ExtraDataInputBitsInfo) { + OMX_QCOM_EXTRADATA_BITS_INFO * bits = (OMX_QCOM_EXTRADATA_BITS_INFO *)(void *)extra->data; + DEBUG_PRINT_HIGH( + "--------- Input bits information --------\n" + " Header bits: %u \n" + " Frame bits: %u \n" + "===== End of Input bits information =====\n", + (unsigned int)bits->header_bits, (unsigned int)bits->frame_bits); + } else if (extra->eType == (OMX_EXTRADATATYPE)OMX_ExtraDataMP2UserData) { + OMX_QCOM_EXTRADATA_USERDATA *userdata = (OMX_QCOM_EXTRADATA_USERDATA *)(void *)extra->data; + OMX_U8 *data_ptr = (OMX_U8 *)userdata->data; + OMX_U32 userdata_size = extra->nDataSize - sizeof(userdata->type); + OMX_U32 i = 0; + DEBUG_PRINT_HIGH( + "-------------- Userdata -------------\n" + " Stream userdata type: %u\n" + " userdata size: %u\n" + " STREAM_USERDATA:", + (unsigned int)userdata->type, (unsigned int)userdata_size); + for (i = 0; i < userdata_size; i+=4) { + DEBUG_PRINT_HIGH(" %x %x %x %x", + data_ptr[i], data_ptr[i+1], + data_ptr[i+2], data_ptr[i+3]); + } + DEBUG_PRINT_HIGH( + "=========== End of Userdata ==========="); + } else if (extra->eType == (OMX_EXTRADATATYPE)OMX_ExtraDataVQZipSEI) { + OMX_QCOM_EXTRADATA_VQZIPSEI *vq = (OMX_QCOM_EXTRADATA_VQZIPSEI *)(void *)extra->data; + DEBUG_PRINT_HIGH( + "-------------- VQZip -------------\n" + " Size: %u\n", + (unsigned int)vq->nSize); + DEBUG_PRINT_HIGH( "=========== End of VQZip ==========="); + } else if (extra->eType == OMX_ExtraDataNone) { + DEBUG_PRINT_HIGH("========== End of Terminator ==========="); + } else { + DEBUG_PRINT_HIGH("======= End of Driver Extradata ========"); + } +} + +void omx_vdec::append_interlace_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 interlaced_format_type) +{ + OMX_STREAMINTERLACEFORMAT *interlace_format; + + if (!(client_extradata & OMX_INTERLACE_EXTRADATA)) { + return; + } + if (!extra) { + DEBUG_PRINT_ERROR("Error: append_interlace_extradata - invalid input"); + return; + } + extra->nSize = OMX_INTERLACE_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataInterlaceFormat; + extra->nDataSize = sizeof(OMX_STREAMINTERLACEFORMAT); + interlace_format = (OMX_STREAMINTERLACEFORMAT *)(void *)extra->data; + interlace_format->nSize = sizeof(OMX_STREAMINTERLACEFORMAT); + interlace_format->nVersion.nVersion = OMX_SPEC_VERSION; + interlace_format->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + + if (interlaced_format_type == MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE) { + interlace_format->bInterlaceFormat = OMX_FALSE; + interlace_format->nInterlaceFormats = OMX_InterlaceFrameProgressive; + drv_ctx.interlace = VDEC_InterlaceFrameProgressive; + } else if (interlaced_format_type == MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST) { + interlace_format->bInterlaceFormat = OMX_TRUE; + interlace_format->nInterlaceFormats = OMX_InterlaceInterleaveFrameTopFieldFirst; + drv_ctx.interlace = VDEC_InterlaceInterleaveFrameTopFieldFirst; + } else if (interlaced_format_type == MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST) { + interlace_format->bInterlaceFormat = OMX_TRUE; + interlace_format->nInterlaceFormats = OMX_InterlaceInterleaveFrameBottomFieldFirst; + drv_ctx.interlace = VDEC_InterlaceInterleaveFrameBottomFieldFirst; + } else { + //default case - set to progressive + interlace_format->bInterlaceFormat = OMX_FALSE; + interlace_format->nInterlaceFormats = OMX_InterlaceFrameProgressive; + drv_ctx.interlace = VDEC_InterlaceFrameProgressive; + } + print_debug_extradata(extra); +} + +void omx_vdec::append_frame_dimension_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + OMX_QCOM_EXTRADATA_FRAMEDIMENSION *frame_dimension; + if (!(client_extradata & OMX_FRAMEDIMENSION_EXTRADATA)) { + return; + } + extra->nSize = OMX_FRAMEDIMENSION_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataFrameDimension; + extra->nDataSize = sizeof(OMX_QCOM_EXTRADATA_FRAMEDIMENSION); + frame_dimension = (OMX_QCOM_EXTRADATA_FRAMEDIMENSION *)(void *)extra->data; + frame_dimension->nDecWidth = rectangle.nLeft; + frame_dimension->nDecHeight = rectangle.nTop; + frame_dimension->nActualWidth = rectangle.nWidth; + frame_dimension->nActualHeight = rectangle.nHeight; +} + +void omx_vdec::fill_aspect_ratio_info( + struct vdec_aspectratioinfo *aspect_ratio_info, + OMX_QCOM_EXTRADATA_FRAMEINFO *frame_info) +{ + m_extradata = frame_info; + m_extradata->aspectRatio.aspectRatioX = aspect_ratio_info->par_width; + m_extradata->aspectRatio.aspectRatioY = aspect_ratio_info->par_height; + DEBUG_PRINT_LOW("aspectRatioX %u aspectRatioY %u", (unsigned int)m_extradata->aspectRatio.aspectRatioX, + (unsigned int)m_extradata->aspectRatio.aspectRatioY); +} + +void omx_vdec::append_frame_info_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_U32 num_conceal_mb, OMX_U32 picture_type, OMX_U32 frame_rate, + OMX_TICKS time_stamp, struct msm_vidc_panscan_window_payload *panscan_payload, + struct vdec_aspectratioinfo *aspect_ratio_info) +{ + OMX_QCOM_EXTRADATA_FRAMEINFO *frame_info = NULL; + struct msm_vidc_panscan_window *panscan_window; + if (!(client_extradata & OMX_FRAMEINFO_EXTRADATA)) { + return; + } + extra->nSize = OMX_FRAMEINFO_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataFrameInfo; + extra->nDataSize = sizeof(OMX_QCOM_EXTRADATA_FRAMEINFO); + frame_info = (OMX_QCOM_EXTRADATA_FRAMEINFO *)(void *)extra->data; + switch (picture_type) { + case PICTURE_TYPE_I: + frame_info->ePicType = OMX_VIDEO_PictureTypeI; + break; + case PICTURE_TYPE_P: + frame_info->ePicType = OMX_VIDEO_PictureTypeP; + break; + case PICTURE_TYPE_B: + frame_info->ePicType = OMX_VIDEO_PictureTypeB; + break; + default: + frame_info->ePicType = (OMX_VIDEO_PICTURETYPE)0; + } + if (drv_ctx.interlace == VDEC_InterlaceInterleaveFrameTopFieldFirst) + frame_info->interlaceType = OMX_QCOM_InterlaceInterleaveFrameTopFieldFirst; + else if (drv_ctx.interlace == VDEC_InterlaceInterleaveFrameBottomFieldFirst) + frame_info->interlaceType = OMX_QCOM_InterlaceInterleaveFrameBottomFieldFirst; + else + frame_info->interlaceType = OMX_QCOM_InterlaceFrameProgressive; + memset(&frame_info->aspectRatio, 0, sizeof(frame_info->aspectRatio)); + frame_info->nConcealedMacroblocks = num_conceal_mb; + frame_info->nFrameRate = frame_rate; + frame_info->nTimeStamp = time_stamp; + frame_info->panScan.numWindows = 0; + if (output_capability == V4L2_PIX_FMT_MPEG2) { + if (m_disp_hor_size && m_disp_vert_size) { + frame_info->displayAspectRatio.displayHorizontalSize = m_disp_hor_size; + frame_info->displayAspectRatio.displayVerticalSize = m_disp_vert_size; + } else { + frame_info->displayAspectRatio.displayHorizontalSize = 0; + frame_info->displayAspectRatio.displayVerticalSize = 0; + } + } + + if (panscan_payload) { + frame_info->panScan.numWindows = panscan_payload->num_panscan_windows; + panscan_window = &panscan_payload->wnd[0]; + for (OMX_U32 i = 0; i < frame_info->panScan.numWindows; i++) { + frame_info->panScan.window[i].x = panscan_window->panscan_window_width; + frame_info->panScan.window[i].y = panscan_window->panscan_window_height; + frame_info->panScan.window[i].dx = panscan_window->panscan_width_offset; + frame_info->panScan.window[i].dy = panscan_window->panscan_height_offset; + panscan_window++; + } + } + fill_aspect_ratio_info(aspect_ratio_info, frame_info); + print_debug_extradata(extra); +} + +void omx_vdec::append_portdef_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + OMX_PARAM_PORTDEFINITIONTYPE *portDefn = NULL; + extra->nSize = OMX_PORTDEF_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataPortDef; + extra->nDataSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *)(void *)extra->data; + *portDefn = m_port_def; + DEBUG_PRINT_LOW("append_portdef_extradata height = %u width = %u " + "stride = %u sliceheight = %u",(unsigned int)portDefn->format.video.nFrameHeight, + (unsigned int)portDefn->format.video.nFrameWidth, + (unsigned int)portDefn->format.video.nStride, + (unsigned int)portDefn->format.video.nSliceHeight); +} + +void omx_vdec::append_framepack_extradata(OMX_OTHER_EXTRADATATYPE *extra, + struct msm_vidc_s3d_frame_packing_payload *s3d_frame_packing_payload) +{ + OMX_QCOM_FRAME_PACK_ARRANGEMENT *framepack; + if (FRAME_PACK_SIZE*sizeof(OMX_U32) != sizeof(struct msm_vidc_s3d_frame_packing_payload)) { + DEBUG_PRINT_ERROR("frame packing size mismatch"); + return; + } + extra->nSize = OMX_FRAMEPACK_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataFramePackingArrangement; + extra->nDataSize = sizeof(OMX_QCOM_FRAME_PACK_ARRANGEMENT); + framepack = (OMX_QCOM_FRAME_PACK_ARRANGEMENT *)(void *)extra->data; + framepack->nSize = sizeof(OMX_QCOM_FRAME_PACK_ARRANGEMENT); + framepack->nVersion.nVersion = OMX_SPEC_VERSION; + framepack->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + memcpy(&framepack->id, s3d_frame_packing_payload, + sizeof(struct msm_vidc_s3d_frame_packing_payload)); + memcpy(&m_frame_pack_arrangement, framepack, + sizeof(OMX_QCOM_FRAME_PACK_ARRANGEMENT)); + print_debug_extradata(extra); +} + +void omx_vdec::append_qp_extradata(OMX_OTHER_EXTRADATATYPE *extra, + struct msm_vidc_frame_qp_payload *qp_payload) +{ + OMX_QCOM_EXTRADATA_QP * qp = NULL; + if (!qp_payload) { + DEBUG_PRINT_ERROR("QP payload is NULL"); + return; + } + extra->nSize = OMX_QP_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataQP; + extra->nDataSize = sizeof(OMX_QCOM_EXTRADATA_QP); + qp = (OMX_QCOM_EXTRADATA_QP *)(void *)extra->data; + qp->nQP = qp_payload->frame_qp; + print_debug_extradata(extra); +} + +void omx_vdec::append_bitsinfo_extradata(OMX_OTHER_EXTRADATATYPE *extra, + struct msm_vidc_frame_bits_info_payload *bits_payload) +{ + OMX_QCOM_EXTRADATA_BITS_INFO * bits = NULL; + if (!bits_payload) { + DEBUG_PRINT_ERROR("bits info payload is NULL"); + return; + } + extra->nSize = OMX_BITSINFO_EXTRADATA_SIZE; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataInputBitsInfo; + extra->nDataSize = sizeof(OMX_QCOM_EXTRADATA_BITS_INFO); + bits = (OMX_QCOM_EXTRADATA_BITS_INFO*)(void *)extra->data; + bits->frame_bits = bits_payload->frame_bits; + bits->header_bits = bits_payload->header_bits; + print_debug_extradata(extra); +} + +void omx_vdec::append_user_extradata(OMX_OTHER_EXTRADATATYPE *extra, + OMX_OTHER_EXTRADATATYPE *p_user) +{ + int userdata_size = 0; + struct msm_vidc_stream_userdata_payload *userdata_payload = NULL; + userdata_payload = + (struct msm_vidc_stream_userdata_payload *)(void *)p_user->data; + userdata_size = p_user->nDataSize; + extra->nSize = OMX_USERDATA_EXTRADATA_SIZE + userdata_size; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataMP2UserData; + extra->nDataSize = userdata_size; + if (extra->nDataSize && (p_user->nDataSize >= extra->nDataSize)) + memcpy(extra->data, p_user->data, extra->nDataSize); + print_debug_extradata(extra); +} + +void omx_vdec::append_terminator_extradata(OMX_OTHER_EXTRADATATYPE *extra) +{ + if (!client_extradata) { + return; + } + extra->nSize = sizeof(OMX_OTHER_EXTRADATATYPE); + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->eType = OMX_ExtraDataNone; + extra->nDataSize = 0; + extra->data[0] = 0; + + print_debug_extradata(extra); +} + +void omx_vdec::append_vqzip_extradata(OMX_OTHER_EXTRADATATYPE *extra, + struct msm_vidc_vqzip_sei_payload *vqzip_payload) +{ + OMX_QCOM_EXTRADATA_VQZIPSEI *vq = NULL; + + extra->nSize = OMX_VQZIPSEI_EXTRADATA_SIZE + vqzip_payload->size; + extra->nVersion.nVersion = OMX_SPEC_VERSION; + extra->nPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataVQZipSEI; + extra->nDataSize = sizeof(OMX_QCOM_EXTRADATA_VQZIPSEI) + vqzip_payload->size; + + vq = (OMX_QCOM_EXTRADATA_VQZIPSEI *)(void *)extra->data; + vq->nSize = vqzip_payload->size; + memcpy(vq->data, vqzip_payload->data, vqzip_payload->size); + + print_debug_extradata(extra); +} + +OMX_ERRORTYPE omx_vdec::allocate_desc_buffer(OMX_U32 index) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (index >= drv_ctx.ip_buf.actualcount) { + DEBUG_PRINT_ERROR("ERROR:Desc Buffer Index not found"); + return OMX_ErrorInsufficientResources; + } + if (m_desc_buffer_ptr == NULL) { + m_desc_buffer_ptr = (desc_buffer_hdr*) \ + calloc( (sizeof(desc_buffer_hdr)), + drv_ctx.ip_buf.actualcount); + if (m_desc_buffer_ptr == NULL) { + DEBUG_PRINT_ERROR("m_desc_buffer_ptr Allocation failed "); + return OMX_ErrorInsufficientResources; + } + } + + m_desc_buffer_ptr[index].buf_addr = (unsigned char *)malloc (DESC_BUFFER_SIZE * sizeof(OMX_U8)); + if (m_desc_buffer_ptr[index].buf_addr == NULL) { + DEBUG_PRINT_ERROR("desc buffer Allocation failed "); + return OMX_ErrorInsufficientResources; + } + + return eRet; +} + +void omx_vdec::insert_demux_addr_offset(OMX_U32 address_offset) +{ + DEBUG_PRINT_LOW("Inserting address offset (%u) at idx (%u)", (unsigned int)address_offset,(unsigned int)m_demux_entries); + if (m_demux_entries < 8192) { + m_demux_offsets[m_demux_entries++] = address_offset; + } + return; +} + +void omx_vdec::extract_demux_addr_offsets(OMX_BUFFERHEADERTYPE *buf_hdr) +{ + OMX_U32 bytes_to_parse = buf_hdr->nFilledLen; + OMX_U8 *buf = buf_hdr->pBuffer + buf_hdr->nOffset; + OMX_U32 index = 0; + + m_demux_entries = 0; + + while (index < bytes_to_parse) { + if ( ((buf[index] == 0x00) && (buf[index+1] == 0x00) && + (buf[index+2] == 0x00) && (buf[index+3] == 0x01)) || + ((buf[index] == 0x00) && (buf[index+1] == 0x00) && + (buf[index+2] == 0x01)) ) { + //Found start code, insert address offset + insert_demux_addr_offset(index); + if (buf[index+2] == 0x01) // 3 byte start code + index += 3; + else //4 byte start code + index += 4; + } else + index++; + } + DEBUG_PRINT_LOW("Extracted (%u) demux entry offsets", (unsigned int)m_demux_entries); + return; +} + +OMX_ERRORTYPE omx_vdec::handle_demux_data(OMX_BUFFERHEADERTYPE *p_buf_hdr) +{ + //fix this, handle 3 byte start code, vc1 terminator entry + OMX_U8 *p_demux_data = NULL; + OMX_U32 desc_data = 0; + OMX_U32 start_addr = 0; + OMX_U32 nal_size = 0; + OMX_U32 suffix_byte = 0; + OMX_U32 demux_index = 0; + OMX_U32 buffer_index = 0; + + if (m_desc_buffer_ptr == NULL) { + DEBUG_PRINT_ERROR("m_desc_buffer_ptr is NULL. Cannot append demux entries."); + return OMX_ErrorBadParameter; + } + + buffer_index = p_buf_hdr - ((OMX_BUFFERHEADERTYPE *)m_inp_mem_ptr); + if (buffer_index > drv_ctx.ip_buf.actualcount) { + DEBUG_PRINT_ERROR("handle_demux_data:Buffer index is incorrect (%u)", (unsigned int)buffer_index); + return OMX_ErrorBadParameter; + } + + p_demux_data = (OMX_U8 *) m_desc_buffer_ptr[buffer_index].buf_addr; + + if ( ((OMX_U8*)p_demux_data == NULL) || + ((m_demux_entries * 16) + 1) > DESC_BUFFER_SIZE) { + DEBUG_PRINT_ERROR("Insufficient buffer. Cannot append demux entries."); + return OMX_ErrorBadParameter; + } else { + for (; demux_index < m_demux_entries; demux_index++) { + desc_data = 0; + start_addr = m_demux_offsets[demux_index]; + if (p_buf_hdr->pBuffer[m_demux_offsets[demux_index] + 2] == 0x01) { + suffix_byte = p_buf_hdr->pBuffer[m_demux_offsets[demux_index] + 3]; + } else { + suffix_byte = p_buf_hdr->pBuffer[m_demux_offsets[demux_index] + 4]; + } + if (demux_index < (m_demux_entries - 1)) { + nal_size = m_demux_offsets[demux_index + 1] - m_demux_offsets[demux_index] - 2; + } else { + nal_size = p_buf_hdr->nFilledLen - m_demux_offsets[demux_index] - 2; + } + DEBUG_PRINT_LOW("Start_addr(0x%x), suffix_byte(0x%x),nal_size(%u),demux_index(%u)", + (unsigned int)start_addr, + (unsigned int)suffix_byte, + (unsigned int)nal_size, + (unsigned int)demux_index); + desc_data = (start_addr >> 3) << 1; + desc_data |= (start_addr & 7) << 21; + desc_data |= suffix_byte << 24; + + memcpy(p_demux_data, &desc_data, sizeof(OMX_U32)); + memcpy(p_demux_data + 4, &nal_size, sizeof(OMX_U32)); + memset(p_demux_data + 8, 0, sizeof(OMX_U32)); + memset(p_demux_data + 12, 0, sizeof(OMX_U32)); + + p_demux_data += 16; + } + if (codec_type_parse == CODEC_TYPE_VC1) { + DEBUG_PRINT_LOW("VC1 terminator entry"); + desc_data = 0; + desc_data = 0x82 << 24; + memcpy(p_demux_data, &desc_data, sizeof(OMX_U32)); + memset(p_demux_data + 4, 0, sizeof(OMX_U32)); + memset(p_demux_data + 8, 0, sizeof(OMX_U32)); + memset(p_demux_data + 12, 0, sizeof(OMX_U32)); + p_demux_data += 16; + m_demux_entries++; + } + //Add zero word to indicate end of descriptors + memset(p_demux_data, 0, sizeof(OMX_U32)); + + m_desc_buffer_ptr[buffer_index].desc_data_size = (m_demux_entries * 16) + sizeof(OMX_U32); + DEBUG_PRINT_LOW("desc table data size=%u", (unsigned int)m_desc_buffer_ptr[buffer_index].desc_data_size); + } + memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) ); + m_demux_entries = 0; + DEBUG_PRINT_LOW("Demux table complete!"); + return OMX_ErrorNone; +} + +void omx_vdec::request_perf_level(enum vidc_perf_level perf_level) +{ + struct v4l2_control control; + char property_value[PROPERTY_VALUE_MAX] = {0}; + + property_get("vidc.debug.turbo", property_value, "0"); + memset(&control, 0, sizeof(v4l2_control)); + control.id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL; + switch (perf_level) { + case VIDC_NOMINAL: + if (atoi(property_value)) + control.value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO; + else + control.value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL; + break; + case VIDC_TURBO: + control.value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO; + break; + default: + DEBUG_PRINT_ERROR("Requested PERF level not supported"); + break; + } + if ((current_perf_level == (OMX_U32)control.value) && !in_reconfig) + return; + + DEBUG_PRINT_HIGH("changing performance level to %d", control.value); + if (!ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { + current_perf_level = control.value; + } else { + DEBUG_PRINT_ERROR("Failed to set PERF level"); + } +} + +omx_vdec::allocate_color_convert_buf::allocate_color_convert_buf() +{ + enabled = false; + omx = NULL; + init_members(); + ColorFormat = OMX_COLOR_FormatMax; + dest_format = YCbCr420P; + m_c2d_width = 0; + m_c2d_height = 0; +} + +void omx_vdec::allocate_color_convert_buf::set_vdec_client(void *client) +{ + omx = reinterpret_cast<omx_vdec*>(client); +} + +void omx_vdec::allocate_color_convert_buf::init_members() +{ + allocated_count = 0; + buffer_size_req = 0; + buffer_alignment_req = 0; + m_c2d_width = m_c2d_height = 0; + memset(m_platform_list_client,0,sizeof(m_platform_list_client)); + memset(m_platform_entry_client,0,sizeof(m_platform_entry_client)); + memset(m_pmem_info_client,0,sizeof(m_pmem_info_client)); + memset(m_out_mem_ptr_client,0,sizeof(m_out_mem_ptr_client)); +#ifdef USE_ION + memset(op_buf_ion_info,0,sizeof(m_platform_entry_client)); +#endif + for (int i = 0; i < MAX_COUNT; i++) + pmem_fd[i] = -1; +} + +omx_vdec::allocate_color_convert_buf::~allocate_color_convert_buf() +{ + c2d.destroy(); +} + +bool omx_vdec::allocate_color_convert_buf::update_buffer_req() +{ + bool status = true; + unsigned int src_size = 0, destination_size = 0; + unsigned int height, width; + struct v4l2_format fmt; + OMX_COLOR_FORMATTYPE drv_color_format; + + if (!omx) { + DEBUG_PRINT_ERROR("Invalid client in color convert"); + return false; + } + if (!enabled) { + DEBUG_PRINT_HIGH("No color conversion required"); + return status; + } + pthread_mutex_lock(&omx->c_lock); + + memset(&fmt, 0x0, sizeof(struct v4l2_format)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.pixelformat = omx->capture_capability; + ioctl(omx->drv_ctx.video_driver_fd, VIDIOC_G_FMT, &fmt); + width = fmt.fmt.pix_mp.width; + height = fmt.fmt.pix_mp.height; + + bool resolution_upgrade = (height > m_c2d_height || + width > m_c2d_width); + if (resolution_upgrade) { + // resolution upgraded ? ensure we are yet to allocate; + // failing which, c2d buffers will never be reallocated and bad things will happen + if (allocated_count > 0) { + DEBUG_PRINT_ERROR("Cannot change C2D buffer requirements with %d active allocations", + allocated_count); + status = false; + goto fail_update_buf_req; + } + } + + if (omx->drv_ctx.output_format != VDEC_YUV_FORMAT_NV12 && + ColorFormat != OMX_COLOR_FormatYUV420Planar) { + DEBUG_PRINT_ERROR("update_buffer_req: Unsupported color conversion"); + status = false; + goto fail_update_buf_req; + } + c2d.close(); + status = c2d.open(height, + width, + NV12_128m,dest_format); + if (status) { + status = c2d.get_buffer_size(C2D_INPUT,src_size); + if (status) + status = c2d.get_buffer_size(C2D_OUTPUT,destination_size); + } + if (status) { + if (!src_size || src_size > omx->drv_ctx.op_buf.buffer_size || + !destination_size) { + DEBUG_PRINT_ERROR("ERROR: Size mismatch in C2D src_size %d" + "driver size %u destination size %d", + src_size, (unsigned int)omx->drv_ctx.op_buf.buffer_size, + destination_size); + status = false; + c2d.close(); + buffer_size_req = 0; + // TODO: make this fatal. Driver is not supposed to quote size + // smaller than what C2D needs !! + } else { + buffer_size_req = destination_size; + m_c2d_height = height; + m_c2d_width = width; + } + } +fail_update_buf_req: + pthread_mutex_unlock(&omx->c_lock); + return status; +} + +bool omx_vdec::allocate_color_convert_buf::set_color_format( + OMX_COLOR_FORMATTYPE dest_color_format) +{ + bool status = true, drv_colorformat_c2d_enable = false; + bool dest_color_format_c2d_enable = false; + OMX_COLOR_FORMATTYPE drv_color_format = OMX_COLOR_FormatUnused; + if (!omx) { + DEBUG_PRINT_ERROR("Invalid client in color convert"); + return false; + } + pthread_mutex_lock(&omx->c_lock); + if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12) + if (omx->drv_ctx.decoder_format == VDEC_CODECTYPE_MVC) + drv_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView; + else + drv_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + else if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12_UBWC) { + drv_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed; + } else if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12_TP10_UBWC) { + drv_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m10bitCompressed; + } else { + DEBUG_PRINT_ERROR("Incorrect color format"); + status = false; + } + drv_colorformat_c2d_enable = (drv_color_format != dest_color_format) && + (drv_color_format != (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView) && + (drv_color_format != (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed) && + (drv_color_format != (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m10bitCompressed); + + dest_color_format_c2d_enable = (dest_color_format != (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed) && + (dest_color_format != (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m10bitCompressed); + + if (status && drv_colorformat_c2d_enable && dest_color_format_c2d_enable) { + DEBUG_PRINT_LOW("Enabling C2D"); + if ((dest_color_format != OMX_COLOR_FormatYUV420Planar) && + (dest_color_format != OMX_COLOR_FormatYUV420SemiPlanar)) { + DEBUG_PRINT_ERROR("Unsupported color format for c2d"); + status = false; + } else { + ColorFormat = dest_color_format; + dest_format = (dest_color_format == OMX_COLOR_FormatYUV420Planar) ? + YCbCr420P : YCbCr420SP; + if (enabled) + c2d.destroy(); + enabled = false; + if (!c2d.init()) { + DEBUG_PRINT_ERROR("open failed for c2d"); + status = false; + } else + enabled = true; + } + } else { + if (enabled) + c2d.destroy(); + enabled = false; + } + pthread_mutex_unlock(&omx->c_lock); + return status; +} + +OMX_BUFFERHEADERTYPE* omx_vdec::allocate_color_convert_buf::get_il_buf_hdr() +{ + if (!omx) { + DEBUG_PRINT_ERROR("Invalid param get_buf_hdr"); + return NULL; + } + if (!enabled) + return omx->m_out_mem_ptr; + return m_out_mem_ptr_client; +} + + OMX_BUFFERHEADERTYPE* omx_vdec::allocate_color_convert_buf::get_il_buf_hdr +(OMX_BUFFERHEADERTYPE *bufadd) +{ + if (!omx) { + DEBUG_PRINT_ERROR("Invalid param get_buf_hdr"); + return NULL; + } + if (!enabled) + return bufadd; + + unsigned index = 0; + index = bufadd - omx->m_out_mem_ptr; + if (index < omx->drv_ctx.op_buf.actualcount) { + m_out_mem_ptr_client[index].nFlags = (bufadd->nFlags & OMX_BUFFERFLAG_EOS); + m_out_mem_ptr_client[index].nTimeStamp = bufadd->nTimeStamp; + bool status; + if (!omx->in_reconfig && !omx->output_flush_progress && bufadd->nFilledLen) { + pthread_mutex_lock(&omx->c_lock); + cache_clean_buffer(index); + status = c2d.convert(omx->drv_ctx.ptr_outputbuffer[index].pmem_fd, + omx->m_out_mem_ptr->pBuffer, bufadd->pBuffer, pmem_fd[index], + pmem_baseaddress[index], pmem_baseaddress[index]); + if (!status) { + DEBUG_PRINT_ERROR("Failed color conversion %d", status); + m_out_mem_ptr_client[index].nFilledLen = 0; + pthread_mutex_unlock(&omx->c_lock); + return &m_out_mem_ptr_client[index]; + } else { + unsigned int filledLen = 0; + c2d.get_output_filled_length(filledLen); + m_out_mem_ptr_client[index].nFilledLen = filledLen; + cache_clean_invalidate_buffer(index); + } + pthread_mutex_unlock(&omx->c_lock); + } else + m_out_mem_ptr_client[index].nFilledLen = 0; + return &m_out_mem_ptr_client[index]; + } + DEBUG_PRINT_ERROR("Index messed up in the get_il_buf_hdr"); + return NULL; +} + + OMX_BUFFERHEADERTYPE* omx_vdec::allocate_color_convert_buf::get_dr_buf_hdr +(OMX_BUFFERHEADERTYPE *bufadd) +{ + if (!omx) { + DEBUG_PRINT_ERROR("Invalid param get_buf_hdr"); + return NULL; + } + if (!enabled) + return bufadd; + unsigned index = 0; + index = bufadd - m_out_mem_ptr_client; + if (index < omx->drv_ctx.op_buf.actualcount) { + return &omx->m_out_mem_ptr[index]; + } + DEBUG_PRINT_ERROR("Index messed up in the get_dr_buf_hdr"); + return NULL; +} + bool omx_vdec::allocate_color_convert_buf::get_buffer_req +(unsigned int &buffer_size) +{ + bool status = true; + pthread_mutex_lock(&omx->c_lock); + if (!enabled) + buffer_size = omx->drv_ctx.op_buf.buffer_size; + else { + if (!c2d.get_buffer_size(C2D_OUTPUT,buffer_size)) { + DEBUG_PRINT_ERROR("Get buffer size failed"); + status = false; + goto fail_get_buffer_size; + } + } +fail_get_buffer_size: + pthread_mutex_unlock(&omx->c_lock); + return status; +} + +OMX_ERRORTYPE omx_vdec::allocate_color_convert_buf::set_buffer_req( + OMX_U32 buffer_size, OMX_U32 actual_count) { + OMX_U32 expectedSize = enabled ? buffer_size_req : omx->drv_ctx.op_buf.buffer_size; + + if (buffer_size < expectedSize) { + DEBUG_PRINT_ERROR("OP Requirements: Client size(%u) insufficient v/s requested(%u)", + buffer_size, expectedSize); + return OMX_ErrorBadParameter; + } + if (actual_count < omx->drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("OP Requirements: Client count(%u) insufficient v/s requested(%u)", + actual_count, omx->drv_ctx.op_buf.actualcount); + return OMX_ErrorBadParameter; + } + + bool reqs_updated = false; + if (enabled) { + // disallow changing buffer size/count while we have active allocated buffers + if (allocated_count > 0) { + DEBUG_PRINT_ERROR("Cannot change C2D buffer size from %u to %u with %d active allocations", + buffer_size_req, buffer_size, allocated_count); + return OMX_ErrorInvalidState; + } + + buffer_size_req = buffer_size; + } else { + if (buffer_size > omx->drv_ctx.op_buf.buffer_size) { + omx->drv_ctx.op_buf.buffer_size = buffer_size; + reqs_updated = true; + } + } + + if (actual_count > omx->drv_ctx.op_buf.actualcount) { + omx->drv_ctx.op_buf.actualcount = actual_count; + reqs_updated = true; + } + + if (reqs_updated) { + omx->drv_ctx.extradata_info.count = omx->drv_ctx.op_buf.actualcount; + omx->drv_ctx.extradata_info.size = omx->drv_ctx.extradata_info.count * + omx->drv_ctx.extradata_info.buffer_size; + return omx->set_buffer_req(&(omx->drv_ctx.op_buf)); + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_vdec::allocate_color_convert_buf::free_output_buffer( + OMX_BUFFERHEADERTYPE *bufhdr) +{ + unsigned int index = 0; + + if (!enabled) + return omx->free_output_buffer(bufhdr); + if (enabled && omx->is_component_secure()) + return OMX_ErrorNone; + if (!allocated_count || !bufhdr) { + DEBUG_PRINT_ERROR("Color convert no buffer to be freed %p",bufhdr); + return OMX_ErrorBadParameter; + } + index = bufhdr - m_out_mem_ptr_client; + if (index >= omx->drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("Incorrect index color convert free_output_buffer"); + return OMX_ErrorBadParameter; + } + if (pmem_fd[index] >= 0) { + munmap(pmem_baseaddress[index], buffer_size_req); + close(pmem_fd[index]); + } + pmem_fd[index] = -1; +#ifdef USE_ION + omx->free_ion_memory(&op_buf_ion_info[index]); +#endif + m_heap_ptr[index].video_heap_ptr = NULL; + if (allocated_count > 0) + allocated_count--; + else + allocated_count = 0; + if (!allocated_count) { + pthread_mutex_lock(&omx->c_lock); + c2d.close(); + init_members(); + pthread_mutex_unlock(&omx->c_lock); + } + return omx->free_output_buffer(&omx->m_out_mem_ptr[index]); +} + +OMX_ERRORTYPE omx_vdec::allocate_color_convert_buf::allocate_buffers_color_convert(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr,OMX_U32 port,OMX_PTR appData,OMX_U32 bytes) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (!enabled) { + eRet = omx->allocate_output_buffer(hComp,bufferHdr,port,appData,bytes); + return eRet; + } + if (enabled && omx->is_component_secure()) { + DEBUG_PRINT_ERROR("Notin color convert mode secure_mode %d", + omx->is_component_secure()); + return OMX_ErrorUnsupportedSetting; + } + if (!bufferHdr || bytes > buffer_size_req) { + DEBUG_PRINT_ERROR("Invalid params allocate_buffers_color_convert %p", bufferHdr); + DEBUG_PRINT_ERROR("color_convert buffer_size_req %u bytes %u", + (unsigned int)buffer_size_req, (unsigned int)bytes); + return OMX_ErrorBadParameter; + } + if (allocated_count >= omx->drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("Actual count err in allocate_buffers_color_convert"); + return OMX_ErrorInsufficientResources; + } + OMX_BUFFERHEADERTYPE *temp_bufferHdr = NULL; + eRet = omx->allocate_output_buffer(hComp,&temp_bufferHdr, + port,appData,omx->drv_ctx.op_buf.buffer_size); + if (eRet != OMX_ErrorNone || !temp_bufferHdr) { + DEBUG_PRINT_ERROR("Buffer allocation failed color_convert"); + return eRet; + } + if ((temp_bufferHdr - omx->m_out_mem_ptr) >= + (int)omx->drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("Invalid header index %ld", + (long int)(temp_bufferHdr - omx->m_out_mem_ptr)); + return OMX_ErrorUndefined; + } + unsigned int i = allocated_count; +#ifdef USE_ION + // Allocate color-conversion buffers as cached to improve software-reading + // performance of YUV (thumbnails). NOTE: These buffers will need an explicit + // cache invalidation. + op_buf_ion_info[i].ion_device_fd = omx->alloc_map_ion_memory( + buffer_size_req,buffer_alignment_req, + &op_buf_ion_info[i].ion_alloc_data,&op_buf_ion_info[i].fd_ion_data, + ION_FLAG_CACHED); + pmem_fd[i] = op_buf_ion_info[i].fd_ion_data.fd; + if (op_buf_ion_info[i].ion_device_fd < 0) { + DEBUG_PRINT_ERROR("alloc_map_ion failed in color_convert"); + return OMX_ErrorInsufficientResources; + } + pmem_baseaddress[i] = (unsigned char *)mmap(NULL,buffer_size_req, + PROT_READ|PROT_WRITE,MAP_SHARED,pmem_fd[i],0); + + if (pmem_baseaddress[i] == MAP_FAILED) { + DEBUG_PRINT_ERROR("MMAP failed for Size %d",buffer_size_req); + close(pmem_fd[i]); + omx->free_ion_memory(&op_buf_ion_info[i]); + return OMX_ErrorInsufficientResources; + } + m_heap_ptr[i].video_heap_ptr = new VideoHeap ( + op_buf_ion_info[i].ion_device_fd,buffer_size_req, + pmem_baseaddress[i],op_buf_ion_info[i].ion_alloc_data.handle,pmem_fd[i]); +#endif + m_pmem_info_client[i].pmem_fd = (unsigned long)m_heap_ptr[i].video_heap_ptr.get(); + m_pmem_info_client[i].offset = 0; + m_platform_entry_client[i].entry = (void *)&m_pmem_info_client[i]; + m_platform_entry_client[i].type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; + m_platform_list_client[i].nEntries = 1; + m_platform_list_client[i].entryList = &m_platform_entry_client[i]; + m_out_mem_ptr_client[i].pOutputPortPrivate = NULL; + m_out_mem_ptr_client[i].nAllocLen = buffer_size_req; + m_out_mem_ptr_client[i].nFilledLen = 0; + m_out_mem_ptr_client[i].nFlags = 0; + m_out_mem_ptr_client[i].nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX; + m_out_mem_ptr_client[i].nSize = sizeof(OMX_BUFFERHEADERTYPE); + m_out_mem_ptr_client[i].nVersion.nVersion = OMX_SPEC_VERSION; + m_out_mem_ptr_client[i].pPlatformPrivate = &m_platform_list_client[i]; + m_out_mem_ptr_client[i].pBuffer = pmem_baseaddress[i]; + m_out_mem_ptr_client[i].pAppPrivate = appData; + *bufferHdr = &m_out_mem_ptr_client[i]; + DEBUG_PRINT_HIGH("IL client buffer header %p", *bufferHdr); + allocated_count++; + return eRet; +} + +bool omx_vdec::is_component_secure() +{ + return secure_mode; +} + +bool omx_vdec::allocate_color_convert_buf::get_color_format(OMX_COLOR_FORMATTYPE &dest_color_format) +{ + bool status = true; + if (!enabled) { + if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12) { + if (omx->drv_ctx.decoder_format == VDEC_CODECTYPE_MVC) + dest_color_format = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView; + else + dest_color_format = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + } else if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12_UBWC){ + dest_color_format = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed; + } else if (omx->drv_ctx.output_format == VDEC_YUV_FORMAT_NV12_TP10_UBWC){ + dest_color_format = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m10bitCompressed; + } else + status = false; + } else { + if (ColorFormat == OMX_COLOR_FormatYUV420Planar || + ColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { + dest_color_format = ColorFormat; + } else + status = false; + } + return status; +} + +OMX_ERRORTYPE omx_vdec::allocate_color_convert_buf::cache_ops( + unsigned int index, unsigned int cmd) +{ + if (!enabled) { + return OMX_ErrorNone; + } + + if (!omx || index >= omx->drv_ctx.op_buf.actualcount) { + DEBUG_PRINT_ERROR("%s: Invalid param", __func__); + return OMX_ErrorBadParameter; + } + + struct ion_flush_data flush_data; + struct ion_custom_data custom_data; + + memset(&flush_data, 0x0, sizeof(flush_data)); + memset(&custom_data, 0x0, sizeof(custom_data)); + + flush_data.vaddr = pmem_baseaddress[index]; + flush_data.fd = op_buf_ion_info[index].fd_ion_data.fd; + flush_data.handle = op_buf_ion_info[index].fd_ion_data.handle; + flush_data.length = buffer_size_req; + custom_data.cmd = cmd; + custom_data.arg = (unsigned long)&flush_data; + + DEBUG_PRINT_LOW("Cache %s: fd=%d handle=%d va=%p size=%d", + (cmd == ION_IOC_CLEAN_CACHES) ? "Clean" : "Invalidate", + flush_data.fd, flush_data.handle, flush_data.vaddr, + flush_data.length); + int ret = ioctl(op_buf_ion_info[index].ion_device_fd, ION_IOC_CUSTOM, &custom_data); + if (ret < 0) { + DEBUG_PRINT_ERROR("Cache %s failed: %s\n", + (cmd == ION_IOC_CLEAN_CACHES) ? "Clean" : "Invalidate", + strerror(errno)); + return OMX_ErrorUndefined; + } + return OMX_ErrorNone; +} + +void omx_vdec::buf_ref_add(int nPortIndex) +{ + unsigned long i = 0; + bool buf_present = false; + long fd = drv_ctx.ptr_outputbuffer[nPortIndex].pmem_fd; + OMX_U32 offset = drv_ctx.ptr_outputbuffer[nPortIndex].offset; + + if (!dynamic_buf_mode || !out_dynamic_list) { + return; + } + + pthread_mutex_lock(&m_lock); + for (i = 0; i < drv_ctx.op_buf.actualcount; i++) { + //check the buffer fd, offset, uv addr with list contents + //If present increment reference. + if ((out_dynamic_list[i].fd == fd) && + (out_dynamic_list[i].offset == offset)) { + DEBUG_PRINT_LOW("buf_ref_add: [ALREADY PRESENT] fd = %u ref_count = %u", + (unsigned int)out_dynamic_list[i].fd, (unsigned int)out_dynamic_list[i].ref_count); + if (!secure_mode) { + drv_ctx.ptr_outputbuffer[nPortIndex].bufferaddr = out_dynamic_list[i].buffaddr; + } + buf_present = true; + break; + } + } + if (!buf_present) { + for (i = 0; i < drv_ctx.op_buf.actualcount; i++) { + //search for a entry to insert details of the new buffer + if (out_dynamic_list[i].dup_fd < 0) { + out_dynamic_list[i].fd = fd; + out_dynamic_list[i].offset = offset; + out_dynamic_list[i].dup_fd = dup(fd); + out_dynamic_list[i].ref_count++; + DEBUG_PRINT_LOW("buf_ref_add: [ADDED] fd = %u ref_count = %u", + (unsigned int)out_dynamic_list[i].fd, (unsigned int)out_dynamic_list[i].ref_count); + + if (!secure_mode) { + drv_ctx.ptr_outputbuffer[nPortIndex].bufferaddr = + (OMX_U8*)mmap(0, drv_ctx.ptr_outputbuffer[nPortIndex].buffer_len, + PROT_READ|PROT_WRITE, MAP_SHARED, + drv_ctx.ptr_outputbuffer[nPortIndex].pmem_fd, 0); + //mmap returns (void *)-1 on failure and sets error code in errno. + if (drv_ctx.ptr_outputbuffer[nPortIndex].bufferaddr == MAP_FAILED) { + DEBUG_PRINT_ERROR("buf_ref_add: mmap failed - errno: %d", errno); + drv_ctx.ptr_outputbuffer[nPortIndex].bufferaddr = NULL; + break; + } + out_dynamic_list[i].buffaddr = drv_ctx.ptr_outputbuffer[nPortIndex].bufferaddr; + out_dynamic_list[i].mapped_size = drv_ctx.ptr_outputbuffer[nPortIndex].buffer_len; + DEBUG_PRINT_LOW("mmap: %p %ld", out_dynamic_list[i].buffaddr, out_dynamic_list[i].mapped_size); + } + break; + } + } + } + pthread_mutex_unlock(&m_lock); +} + +void omx_vdec::buf_ref_remove() +{ + unsigned long i = 0; + + if (!dynamic_buf_mode || !out_dynamic_list) { + return; + } + + pthread_mutex_lock(&m_lock); + for (i = 0; i < drv_ctx.op_buf.actualcount; i++) { + if (!secure_mode && out_dynamic_list[i].buffaddr && out_dynamic_list[i].mapped_size) { + DEBUG_PRINT_LOW("munmap: %p %ld", out_dynamic_list[i].buffaddr, out_dynamic_list[i].mapped_size); + munmap(out_dynamic_list[i].buffaddr, + out_dynamic_list[i].mapped_size); + } + + DEBUG_PRINT_LOW("buf_ref_remove: [REMOVED] fd = %u ref_count = %u", + (unsigned int)out_dynamic_list[i].fd, (unsigned int)out_dynamic_list[i].ref_count); + close(out_dynamic_list[i].dup_fd); + out_dynamic_list[i].dup_fd = -1; + } + pthread_mutex_unlock(&m_lock); + + if (out_dynamic_list) { + free(out_dynamic_list); + out_dynamic_list = NULL; + } +} + +#ifdef _MSM8974_ +void omx_vdec::send_codec_config() { + if (codec_config_flag) { + unsigned long p1 = 0; // Parameter - 1 + unsigned long p2 = 0; // Parameter - 2 + unsigned long ident = 0; + pthread_mutex_lock(&m_lock); + DEBUG_PRINT_LOW("\n Check Queue for codec_config buffer \n"); + while (m_etb_q.m_size) { + m_etb_q.pop_entry(&p1,&p2,&ident); + if (ident == OMX_COMPONENT_GENERATE_ETB_ARBITRARY) { + if (((OMX_BUFFERHEADERTYPE *)p2)->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { + if (empty_this_buffer_proxy_arbitrary((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("\n empty_this_buffer_proxy_arbitrary failure"); + omx_report_error(); + } + } else { + DEBUG_PRINT_LOW("\n Flush Input Heap Buffer %p",(OMX_BUFFERHEADERTYPE *)p2); + m_cb.EmptyBufferDone(&m_cmp ,m_app_data, (OMX_BUFFERHEADERTYPE *)p2); + } + } else if (ident == OMX_COMPONENT_GENERATE_ETB) { + if (((OMX_BUFFERHEADERTYPE *)p2)->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { + if (empty_this_buffer_proxy((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("\n empty_this_buffer_proxy failure"); + omx_report_error (); + } + } else { + pending_input_buffers++; + VIDC_TRACE_INT_LOW("ETB-pending", pending_input_buffers); + DEBUG_PRINT_LOW("\n Flush Input OMX_COMPONENT_GENERATE_ETB %p, pending_input_buffers %d", + (OMX_BUFFERHEADERTYPE *)p2, pending_input_buffers); + empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p2); + } + } else if (ident == OMX_COMPONENT_GENERATE_EBD) { + DEBUG_PRINT_LOW("\n Flush Input OMX_COMPONENT_GENERATE_EBD %p", + (OMX_BUFFERHEADERTYPE *)p1); + empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1); + } + } + pthread_mutex_unlock(&m_lock); + } +} +#endif + +omx_vdec::perf_control::perf_control() +{ + m_perf_lib = NULL; + m_perf_handle = 0; + m_perf_lock_acquire = NULL; + m_perf_lock_release = NULL; +} + +omx_vdec::perf_control::~perf_control() +{ + if (m_perf_handle != 0 && m_perf_lock_release) { + DEBUG_PRINT_LOW("NOTE2: release perf lock"); + m_perf_lock_release(m_perf_handle); + } + if (m_perf_lib) { + dlclose(m_perf_lib); + } +} + +struct omx_vdec::perf_control::mpctl_stats omx_vdec::perf_control::mpctl_obj = {0, 0, 0}; + +omx_vdec::perf_lock omx_vdec::perf_control::m_perf_lock; + +void omx_vdec::perf_control::send_hint_to_mpctl(bool state) +{ + if (load_lib() == false) { + return; + } + m_perf_lock.lock(); + /* 0x4401 maps to video decode playback hint + * in perflock, enum number is 44 and state + * being sent on perflock acquire is 01 (true) + */ + int arg = 0x4401; + + if (state == true) { + mpctl_obj.vid_inst_count++; + } else if (state == false) { + mpctl_obj.vid_inst_count--; + } + + if (m_perf_lock_acquire && mpctl_obj.vid_inst_count == 1 && mpctl_obj.vid_acquired == false) { + mpctl_obj.vid_disp_handle = m_perf_lock_acquire(0, 0, &arg, sizeof(arg) / sizeof(int)); + mpctl_obj.vid_acquired = true; + DEBUG_PRINT_INFO("Video slvp perflock acquired"); + } else if (m_perf_lock_release && (mpctl_obj.vid_inst_count == 0 || mpctl_obj.vid_inst_count > 1) && mpctl_obj.vid_acquired == true) { + m_perf_lock_release(mpctl_obj.vid_disp_handle); + mpctl_obj.vid_acquired = false; + DEBUG_PRINT_INFO("Video slvp perflock released"); + } + m_perf_lock.unlock(); +} + +void omx_vdec::perf_control::request_cores(int frame_duration_us) +{ + if (frame_duration_us > MIN_FRAME_DURATION_FOR_PERF_REQUEST_US) { + return; + } + bool retVal = load_lib(); + if (retVal && m_perf_lock_acquire && m_perf_handle == 0) { + int arg = 0x700 /*base value*/ + 2 /*cores*/; + m_perf_handle = m_perf_lock_acquire(m_perf_handle, 0, &arg, sizeof(arg)/sizeof(int)); + if (m_perf_handle) { + DEBUG_PRINT_HIGH("perf lock acquired"); + } + } +} + +bool omx_vdec::perf_control::load_lib() +{ + char perf_lib_path[PROPERTY_VALUE_MAX] = {0}; + if (m_perf_lib) + return true; + + if((property_get("ro.vendor.extension_library", perf_lib_path, NULL) <= 0)) { + DEBUG_PRINT_ERROR("vendor library not set in ro.vendor.extension_library"); + goto handle_err; + } + + if ((m_perf_lib = dlopen(perf_lib_path, RTLD_NOW)) == NULL) { + DEBUG_PRINT_ERROR("Failed to open %s : %s",perf_lib_path, dlerror()); + goto handle_err; + } else { + m_perf_lock_acquire = (perf_lock_acquire_t)dlsym(m_perf_lib, "perf_lock_acq"); + if (m_perf_lock_acquire == NULL) { + DEBUG_PRINT_ERROR("Failed to load symbol: perf_lock_acq"); + goto handle_err; + } + m_perf_lock_release = (perf_lock_release_t)dlsym(m_perf_lib, "perf_lock_rel"); + if (m_perf_lock_release == NULL) { + DEBUG_PRINT_ERROR("Failed to load symbol: perf_lock_rel"); + goto handle_err; + } + } + return true; + +handle_err: + if (m_perf_lib) { + dlclose(m_perf_lib); + } + m_perf_lib = NULL; + return false; +} + +OMX_ERRORTYPE omx_vdec::enable_adaptive_playback(unsigned long nMaxFrameWidth, + unsigned long nMaxFrameHeight) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + int ret = 0; + unsigned long min_res_buf_count = 0; + + eRet = enable_smoothstreaming(); + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("Failed to enable Adaptive Playback on driver"); + return eRet; + } + + DEBUG_PRINT_HIGH("Enabling Adaptive playback for %lu x %lu", + nMaxFrameWidth, + nMaxFrameHeight); + m_smoothstreaming_mode = true; + m_smoothstreaming_width = nMaxFrameWidth; + m_smoothstreaming_height = nMaxFrameHeight; + + //Get upper limit buffer count for min supported resolution + struct v4l2_format fmt; + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = m_decoder_capability.min_height; + fmt.fmt.pix_mp.width = m_decoder_capability.min_width; + fmt.fmt.pix_mp.pixelformat = output_capability; + + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + DEBUG_PRINT_ERROR("Set Resolution failed for HxW = %ux%u", + m_decoder_capability.min_height, + m_decoder_capability.min_width); + return OMX_ErrorUnsupportedSetting; + } + + eRet = get_buffer_req(&drv_ctx.op_buf); + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("failed to get_buffer_req"); + return eRet; + } + + min_res_buf_count = drv_ctx.op_buf.mincount; + DEBUG_PRINT_LOW("enable adaptive - upper limit buffer count = %lu for HxW %ux%u", + min_res_buf_count, m_decoder_capability.min_height, m_decoder_capability.min_width); + + m_extradata_info.output_crop_rect.nLeft = 0; + m_extradata_info.output_crop_rect.nTop = 0; + m_extradata_info.output_crop_rect.nWidth = m_smoothstreaming_width; + m_extradata_info.output_crop_rect.nHeight = m_smoothstreaming_height; + + update_resolution(m_smoothstreaming_width, m_smoothstreaming_height, + m_smoothstreaming_width, m_smoothstreaming_height); + eRet = is_video_session_supported(); + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("video session is not supported"); + return eRet; + } + + //Get upper limit buffer size for max smooth streaming resolution set + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; + fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; + fmt.fmt.pix_mp.pixelformat = output_capability; + ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); + if (ret) { + DEBUG_PRINT_ERROR("Set Resolution failed for adaptive playback"); + return OMX_ErrorUnsupportedSetting; + } + + eRet = get_buffer_req(&drv_ctx.op_buf); + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("failed to get_buffer_req!!"); + return eRet; + } + DEBUG_PRINT_LOW("enable adaptive - upper limit buffer size = %u", + (unsigned int)drv_ctx.op_buf.buffer_size); + + drv_ctx.op_buf.mincount = min_res_buf_count; + drv_ctx.op_buf.actualcount = min_res_buf_count; + drv_ctx.op_buf.buffer_size = drv_ctx.op_buf.buffer_size; + eRet = set_buffer_req(&drv_ctx.op_buf); + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("failed to set_buffer_req"); + return eRet; + } + + eRet = get_buffer_req(&drv_ctx.op_buf); + if (eRet != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("failed to get_buffer_req!!!"); + return eRet; + } + DEBUG_PRINT_HIGH("adaptive playback enabled, buf count = %u bufsize = %u", + drv_ctx.op_buf.mincount, (unsigned int)drv_ctx.op_buf.buffer_size); + return eRet; +} + +//static +OMX_ERRORTYPE omx_vdec::describeColorFormat(OMX_PTR pParam) { + +#ifndef FLEXYUV_SUPPORTED + return OMX_ErrorUndefined; +#else + + if (pParam == NULL) { + DEBUG_PRINT_ERROR("describeColorFormat: invalid params"); + return OMX_ErrorBadParameter; + } + + DescribeColorFormatParams *params = (DescribeColorFormatParams*)pParam; + + MediaImage *img = &(params->sMediaImage); + switch(params->eColorFormat) { + case QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m: + { + img->mType = MediaImage::MEDIA_IMAGE_TYPE_YUV; + img->mNumPlanes = 3; + // mWidth and mHeight represent the W x H of the largest plane + // In our case, this happens to be the Stride x Scanlines of Y plane + img->mWidth = params->nFrameWidth; + img->mHeight = params->nFrameHeight; + size_t planeWidth = VENUS_Y_STRIDE(COLOR_FMT_NV12, params->nFrameWidth); + size_t planeHeight = VENUS_Y_SCANLINES(COLOR_FMT_NV12, params->nFrameHeight); + img->mBitDepth = 8; + //Plane 0 (Y) + img->mPlane[MediaImage::Y].mOffset = 0; + img->mPlane[MediaImage::Y].mColInc = 1; + img->mPlane[MediaImage::Y].mRowInc = planeWidth; //same as stride + img->mPlane[MediaImage::Y].mHorizSubsampling = 1; + img->mPlane[MediaImage::Y].mVertSubsampling = 1; + //Plane 1 (U) + img->mPlane[MediaImage::U].mOffset = planeWidth * planeHeight; + img->mPlane[MediaImage::U].mColInc = 2; //interleaved UV + img->mPlane[MediaImage::U].mRowInc = + VENUS_UV_STRIDE(COLOR_FMT_NV12, params->nFrameWidth); + img->mPlane[MediaImage::U].mHorizSubsampling = 2; + img->mPlane[MediaImage::U].mVertSubsampling = 2; + //Plane 2 (V) + img->mPlane[MediaImage::V].mOffset = planeWidth * planeHeight + 1; + img->mPlane[MediaImage::V].mColInc = 2; //interleaved UV + img->mPlane[MediaImage::V].mRowInc = + VENUS_UV_STRIDE(COLOR_FMT_NV12, params->nFrameWidth); + img->mPlane[MediaImage::V].mHorizSubsampling = 2; + img->mPlane[MediaImage::V].mVertSubsampling = 2; + break; + } + + case OMX_COLOR_FormatYUV420Planar: + case OMX_COLOR_FormatYUV420SemiPlanar: + // We need not describe the standard OMX linear formats as these are + // understood by client. Fail this deliberately to let client fill-in + return OMX_ErrorUnsupportedSetting; + + default: + // Rest all formats which are non-linear cannot be described + DEBUG_PRINT_LOW("color-format %x is not flexible", params->eColorFormat); + img->mType = MediaImage::MEDIA_IMAGE_TYPE_UNKNOWN; + return OMX_ErrorNone; + }; + + DEBUG_PRINT_LOW("NOTE: Describe color format : %x", params->eColorFormat); + DEBUG_PRINT_LOW(" FrameWidth x FrameHeight : %d x %d", params->nFrameWidth, params->nFrameHeight); + DEBUG_PRINT_LOW(" YWidth x YHeight : %d x %d", img->mWidth, img->mHeight); + for (size_t i = 0; i < img->mNumPlanes; ++i) { + DEBUG_PRINT_LOW(" Plane[%zu] : offset=%d / xStep=%d / yStep = %d", + i, img->mPlane[i].mOffset, img->mPlane[i].mColInc, img->mPlane[i].mRowInc); + } + return OMX_ErrorNone; +#endif //FLEXYUV_SUPPORTED +} + +void omx_vdec::prefetchNewBuffers() { + + struct v4l2_decoder_cmd dec; + uint32_t prefetch_count; + uint32_t prefetch_size; + uint32_t want_size; + uint32_t have_size; + int color_fmt, rc; + uint32_t new_calculated_size; + uint32_t new_buffer_size; + uint32_t new_buffer_count; + uint32_t old_buffer_size; + uint32_t old_buffer_count; + + memset((void *)&dec, 0 , sizeof(dec)); + DEBUG_PRINT_LOW("Old size : %zu, count : %d, width : %u, height : %u\n", + drv_ctx.op_buf.buffer_size, drv_ctx.op_buf.actualcount, + drv_ctx.video_resolution.frame_width, + drv_ctx.video_resolution.frame_height); + dec.cmd = V4L2_DEC_QCOM_CMD_RECONFIG_HINT; + if (ioctl(drv_ctx.video_driver_fd, VIDIOC_DECODER_CMD, &dec)) { + DEBUG_PRINT_ERROR("Buffer info cmd failed : %d\n", errno); + } else { + DEBUG_PRINT_LOW("From driver, new size is %d, count is %d\n", + dec.raw.data[0], dec.raw.data[1]); + } + + switch ((int)drv_ctx.output_format) { + case VDEC_YUV_FORMAT_NV12: + color_fmt = COLOR_FMT_NV12; + break; + case VDEC_YUV_FORMAT_NV12_UBWC: + color_fmt = COLOR_FMT_NV12_UBWC; + break; + case VDEC_YUV_FORMAT_NV12_TP10_UBWC: + color_fmt = COLOR_FMT_NV12_BPP10_UBWC; + break; + default: + color_fmt = -1; + DEBUG_PRINT_HIGH("Color format : %x not supported for secure memory prefetching\n", drv_ctx.output_format); + return; + } + + new_calculated_size = VENUS_BUFFER_SIZE(color_fmt, m_reconfig_width, m_reconfig_height); + DEBUG_PRINT_LOW("New calculated size for width : %d, height : %d, is %d\n", + m_reconfig_width, m_reconfig_height, new_calculated_size); + new_buffer_size = (dec.raw.data[0] > new_calculated_size) ? dec.raw.data[0] : new_calculated_size; + new_buffer_count = dec.raw.data[1]; + old_buffer_size = drv_ctx.op_buf.buffer_size; + old_buffer_count = drv_ctx.op_buf.actualcount; + + new_buffer_count = old_buffer_count > new_buffer_count ? old_buffer_count : new_buffer_count; + + prefetch_count = new_buffer_count; + prefetch_size = new_buffer_size - old_buffer_size; + want_size = new_buffer_size * new_buffer_count; + have_size = old_buffer_size * old_buffer_count; + + if (want_size > have_size) { + DEBUG_PRINT_LOW("Want: %d, have : %d\n", want_size, have_size); + DEBUG_PRINT_LOW("prefetch_count: %d, prefetch_size : %d\n", prefetch_count, prefetch_size); + + int ion_fd = open(MEM_DEVICE, O_RDONLY); + if (ion_fd < 0) { + DEBUG_PRINT_ERROR("Ion fd open failed : %d\n", ion_fd); + return; + } + + struct ion_custom_data *custom_data = (struct ion_custom_data*) malloc(sizeof(*custom_data)); + struct ion_prefetch_data *prefetch_data = (struct ion_prefetch_data*) malloc(sizeof(*prefetch_data)); + struct ion_prefetch_regions *regions = (struct ion_prefetch_regions*) malloc(sizeof(*regions)); + size_t *sizes = (size_t*) malloc(sizeof(size_t) * prefetch_count); + + if (custom_data == NULL || prefetch_data == NULL || regions == NULL || sizes == NULL) { + DEBUG_PRINT_ERROR("prefetch data allocation failed"); + goto prefetch_exit; + } + + for (uint32_t i = 0; i < prefetch_count; i++) { + sizes[i] = prefetch_size; + } + + regions[0].nr_sizes = prefetch_count; + regions[0].sizes = sizes; + regions[0].vmid = ION_FLAG_CP_PIXEL; + + prefetch_data->nr_regions = 1; + prefetch_data->regions = regions; + prefetch_data->heap_id = ION_HEAP(ION_SECURE_HEAP_ID); + + custom_data->cmd = ION_IOC_PREFETCH; + custom_data->arg = (unsigned long )prefetch_data; + + rc = ioctl(ion_fd, ION_IOC_CUSTOM, custom_data); + if (rc) { + DEBUG_PRINT_ERROR("Custom prefetch ioctl failed rc : %d, errno : %d\n", rc, errno); + } + +prefetch_exit: + close(ion_fd); + free(sizes); + free(regions); + free(prefetch_data); + free(custom_data); + } +} diff --git a/msm8998/mm-video-v4l2/vidc/vdec/src/ts_parser.cpp b/msm8998/mm-video-v4l2/vidc/vdec/src/ts_parser.cpp new file mode 100644 index 0000000..809a1f7 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/vdec/src/ts_parser.cpp @@ -0,0 +1,325 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#include "ts_parser.h" +#include "vidc_debug.h" + +#define DEBUG DEBUG_PRINT_ERROR + +void omx_time_stamp_reorder::set_timestamp_reorder_mode(bool mode) +{ + auto_lock l(&m_lock); + reorder_ts = mode; +} + +void omx_time_stamp_reorder::enable_debug_print(bool flag) +{ + auto_lock l(&m_lock); + print_debug = flag; +} + +omx_time_stamp_reorder::~omx_time_stamp_reorder() +{ + delete_list(); + pthread_mutex_destroy(&m_lock); +} + +omx_time_stamp_reorder::omx_time_stamp_reorder() +{ + reorder_ts = false; + phead = pcurrent = NULL; + error = false; + print_debug = false; + pthread_mutex_init(&m_lock, NULL); +} + +void omx_time_stamp_reorder::delete_list() +{ + time_stamp_list *ptemp; + + if (!phead) return; + + while (phead->next != phead) { + ptemp = phead; + phead = phead->next; + phead->prev = ptemp->prev; + ptemp->prev->next = phead; + delete ptemp; + } + + delete phead; + phead = NULL; +} + +bool omx_time_stamp_reorder::get_current_list() +{ + if (!phead) { + if (!add_new_list()) { + handle_error(); + return false; + } + } + + pcurrent = phead->prev; + return true; +} + +bool omx_time_stamp_reorder::update_head() +{ + time_stamp_list *ptemp; + + if (!phead) return false; + + if (phead->next != phead) { + ptemp = phead; + phead = ptemp->next; + phead->prev = ptemp->prev; + ptemp->prev->next = phead; + delete ptemp; + } + + return true; +} + +bool omx_time_stamp_reorder::add_new_list() +{ + bool status = true; + time_stamp_list *ptemp = NULL; + + if (!phead) { + ptemp = phead = new time_stamp_list; + + if (!phead) { + handle_error(); + status = false; + return status; + } + + phead->prev = phead->next = phead; + } else { + ptemp = new time_stamp_list; + + if (!ptemp) { + handle_error(); + status = false; + return status; + } + + ptemp->prev = phead->prev; + ptemp->next = phead; + phead->prev->next = ptemp; + phead->prev = ptemp; + } + + ptemp->entries_filled = 0; + + for (int i=0; i < TIME_SZ; i++) { + ptemp->input_timestamps[i].in_use = false; + ptemp->input_timestamps[i].timestamps = -1; + } + + return status; +} + +bool omx_time_stamp_reorder::insert_timestamp(OMX_BUFFERHEADERTYPE *header) +{ + auto_lock l(&m_lock); + OMX_TICKS *table_entry = NULL; + + if (!reorder_ts || error || !header) { + if (error || !header) + DEBUG("Invalid condition in insert_timestamp %p", header); + + return false; + } + + if (!get_current_list()) { + handle_error(); + return false; + } + + if (pcurrent->entries_filled > (TIME_SZ - 1)) { + DEBUG("Table full return error"); + handle_error(); + return false; + } + + if (header->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { + return true; + } + + if ((header->nFlags & OMX_BUFFERFLAG_EOS) && !header->nFilledLen) { + DEBUG("EOS with zero length recieved"); + + if (!add_new_list()) { + handle_error(); + return false; + } + + return true; + } + + for (int i = 0; i < TIME_SZ && !table_entry; i++) { + if (!pcurrent->input_timestamps[i].in_use) { + table_entry = &pcurrent->input_timestamps[i].timestamps; + pcurrent->input_timestamps[i].in_use = true; + pcurrent->entries_filled++; + } + } + + if (!table_entry) { + DEBUG("All entries in use"); + handle_error(); + return false; + } + + *table_entry = header->nTimeStamp; + + if (print_debug) + DEBUG("Time stamp inserted %lld", header->nTimeStamp); + + if (header->nFlags & OMX_BUFFERFLAG_EOS) { + if (!add_new_list()) { + handle_error(); + return false; + } + } + + return true; +} + +bool omx_time_stamp_reorder::remove_time_stamp(OMX_TICKS ts, bool is_interlaced = false) +{ + auto_lock l(&m_lock); + unsigned int num_ent_remove = (is_interlaced)?2:1; + + if (!reorder_ts || error) { + DEBUG("not in avi mode"); + return false; + } + + if (!phead || !phead->entries_filled) return false; + + for (int i=0; i < TIME_SZ && num_ent_remove; i++) { + if (phead->input_timestamps[i].in_use && phead->input_timestamps[i].timestamps == ts) { + phead->input_timestamps[i].in_use = false; + phead->entries_filled--; + num_ent_remove--; + + if (print_debug) + DEBUG("Removed TS %lld", ts); + } + } + + if (!phead->entries_filled) { + if (!update_head()) { + handle_error(); + return false; + } + } + + return true; +} + +void omx_time_stamp_reorder::flush_timestamp() +{ + auto_lock l(&m_lock); + delete_list(); +} + +bool omx_time_stamp_reorder::get_next_timestamp(OMX_BUFFERHEADERTYPE *header, bool is_interlaced) +{ + auto_lock l(&m_lock); + timestamp *element = NULL,*duplicate = NULL; + bool status = false; + + if (!reorder_ts || error || !header) { + if (error || !header) + DEBUG("Invalid condition in insert_timestamp %p", header); + + return false; + } + + if (!phead || !phead->entries_filled) return false; + + for (int i=0; i < TIME_SZ; i++) { + if (phead->input_timestamps[i].in_use) { + status = true; + + if (!element) + element = &phead->input_timestamps[i]; + else { + if (element->timestamps > phead->input_timestamps[i].timestamps) { + element = &phead->input_timestamps[i]; + duplicate = NULL; + } else if (element->timestamps == phead->input_timestamps[i].timestamps) + duplicate = &phead->input_timestamps[i]; + } + } + } + + if (element) { + phead->entries_filled--; + header->nTimeStamp = element->timestamps; + + if (print_debug) + DEBUG("Getnext Time stamp %lld", header->nTimeStamp); + + element->in_use = false; + } + + if (is_interlaced && duplicate) { + phead->entries_filled--; + duplicate->in_use = false; + } else if (is_interlaced && !duplicate) { + element = NULL; + + for (int i=0; i < TIME_SZ; i++) { + if (phead->input_timestamps[i].in_use) { + if (!element) + element = &phead->input_timestamps[i]; + else if (element->timestamps > phead->input_timestamps[i].timestamps) + element = &phead->input_timestamps[i]; + } + } + + if (element) { + phead->entries_filled--; + header->nTimeStamp = element->timestamps; + element->in_use = false; + } + } + + if (!phead->entries_filled) { + if (!update_head()) { + handle_error(); + return false; + } + } + + return status; +} diff --git a/msm8998/mm-video-v4l2/vidc/venc/Android.mk b/msm8998/mm-video-v4l2/vidc/venc/Android.mk new file mode 100644 index 0000000..bf74532 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/Android.mk @@ -0,0 +1,158 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# --------------------------------------------------------------------------------- +# Common definitons +# --------------------------------------------------------------------------------- + +libmm-venc-def := -g -O3 -Dlrintf=_ffix_r +libmm-venc-def += -D__align=__alignx +libmm-venc-def += -D__alignx\(x\)=__attribute__\(\(__aligned__\(x\)\)\) +libmm-venc-def += -DT_ARM +libmm-venc-def += -Dinline=__inline +libmm-venc-def += -D_ANDROID_ +libmm-venc-def += -UENABLE_DEBUG_LOW +libmm-venc-def += -UENABLE_DEBUG_HIGH +libmm-venc-def += -DENABLE_DEBUG_ERROR +libmm-venc-def += -UINPUT_BUFFER_LOG +libmm-venc-def += -UOUTPUT_BUFFER_LOG +libmm-venc-def += -USINGLE_ENCODER_INSTANCE +libmm-venc-def += -Werror +libmm-venc-def += -D_ANDROID_ICS_ +libmm-venc-def += -D_MSM8974_ + +TARGETS_THAT_USE_FLAG_MSM8226 := msm8226 msm8916 msm8909 +TARGETS_THAT_NEED_SW_VENC_MPEG4 := msm8909 msm8937 +TARGETS_THAT_NEED_SW_VENC_HEVC := msm8992 +TARGETS_THAT_SUPPORT_UBWC := msm8996 msmcobalt +TARGETS_THAT_SUPPORT_VQZIP := msm8996 msmcobalt +TARGETS_THAT_SUPPORT_PQ := msm8996 msmcobalt + +ifeq ($(TARGET_BOARD_PLATFORM),msm8610) +libmm-venc-def += -DMAX_RES_720P +libmm-venc-def += -D_MSM8610_ +else +ifeq ($(TARGET_BOARD_PLATFORM),msm8226) +libmm-venc-def += -DMAX_RES_1080P +else +libmm-venc-def += -DMAX_RES_1080P +libmm-venc-def += -DMAX_RES_1080P_EBI +endif +endif + +ifeq ($(call is-board-platform-in-list, $(TARGETS_THAT_SUPPORT_UBWC)),true) +libmm-venc-def += -D_UBWC_ +endif + +ifeq ($(call is-board-platform-in-list, $(TARGETS_THAT_SUPPORT_VQZIP)),true) +libmm-venc-def += -D_VQZIP_ +endif + +ifeq ($(call is-board-platform-in-list, $(TARGETS_THAT_SUPPORT_PQ)),true) +libmm-venc-def += -D_PQ_ +endif + +ifeq ($(call is-board-platform-in-list, $(TARGETS_THAT_USE_FLAG_MSM8226)),true) +libmm-venc-def += -D_MSM8226_ +endif + +ifeq ($(TARGET_USES_ION),true) +libmm-venc-def += -DUSE_ION +endif + +ifeq ($(TARGET_USES_MEDIA_EXTENSIONS),true) +libmm-venc-def += -DUSE_NATIVE_HANDLE_SOURCE +endif + +ifeq ($(call is-board-platform-in-list, $(MASTER_SIDE_CP_TARGET_LIST)),true) +libmm-venc-def += -DMASTER_SIDE_CP +endif + +ifeq ($(TARGET_USES_MEDIA_EXTENSIONS),true) +libmm-venc-def += -DSUPPORT_CONFIG_INTRA_REFRESH +endif + +libmm-venc-def += -DUSE_CAMERA_METABUFFER_UTILS + +# Common Includes +libmm-venc-inc := $(LOCAL_PATH)/inc +libmm-venc-inc += $(QCOM_MEDIA_ROOT)/mm-video-v4l2/vidc/common/inc +libmm-venc-inc += $(QCOM_MEDIA_ROOT)/mm-core/inc +libmm-venc-inc += $(QCOM_MEDIA_ROOT)/libstagefrighthw +libmm-venc-inc += $(TARGET_OUT_HEADERS)/qcom/display +libmm-venc-inc += $(TARGET_OUT_HEADERS)/adreno +libmm-venc-inc += frameworks/native/include/media/hardware +libmm-venc-inc += frameworks/native/include/media/openmax +libmm-venc-inc += $(QCOM_MEDIA_ROOT)/libc2dcolorconvert +libmm-venc-inc += $(TARGET_OUT_HEADERS)/libvqzip +libmm-venc-inc += $(TARGET_OUT_HEADERS)/libgpustats +libmm-venc-inc += frameworks/av/include/media/stagefright +ifeq ($(TARGET_COMPILE_WITH_MSM_KERNEL),true) +libmm-venc-inc += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include + +# Common Dependencies +libmm-venc-add-dep := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +endif + +# --------------------------------------------------------------------------------- +# Make the Shared library (libOmxVenc) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +LOCAL_MODULE := libOmxVenc +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libmm-venc-def) +LOCAL_C_INCLUDES := $(libmm-venc-inc) +LOCAL_ADDITIONAL_DEPENDENCIES := $(libmm-venc-add-dep) + +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := liblog libutils libbinder libcutils \ + libdl libgui +ifeq ($(BOARD_USES_ADRENO), true) +LOCAL_SHARED_LIBRARIES += libc2dcolorconvert +endif # ($(BOARD_USES_ADRENO), true) +LOCAL_SHARED_LIBRARIES += libqdMetaData +LOCAL_STATIC_LIBRARIES := libOmxVidcCommon + +LOCAL_SRC_FILES := src/omx_video_base.cpp +LOCAL_SRC_FILES += src/omx_video_encoder.cpp +LOCAL_SRC_FILES += src/video_encoder_device_v4l2.cpp + +include $(BUILD_SHARED_LIBRARY) + +ifeq ($(call is-board-platform-in-list, $(TARGETS_THAT_NEED_SW_VENC_MPEG4)),true) +# --------------------------------------------------------------------------------- +# Make the Shared library (libOmxSwVencMpeg4) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +libmm-venc-inc += $(TARGET_OUT_HEADERS)/mm-video/swvenc + +LOCAL_MODULE := libOmxSwVencMpeg4 + +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libmm-venc-def) +LOCAL_C_INCLUDES := $(libmm-venc-inc) +LOCAL_ADDITIONAL_DEPENDENCIES := $(libmm-venc-add-dep) + +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := liblog libutils libbinder libcutils \ + libdl libgui +LOCAL_SHARED_LIBRARIES += libMpeg4SwEncoder +ifeq ($(BOARD_USES_ADRENO), true) +LOCAL_SHARED_LIBRARIES += libc2dcolorconvert +endif # ($(BOARD_USES_ADRENO), true) +LOCAL_STATIC_LIBRARIES := libOmxVidcCommon + +LOCAL_SRC_FILES := src/omx_video_base.cpp +LOCAL_SRC_FILES += src/omx_swvenc_mpeg4.cpp + +include $(BUILD_SHARED_LIBRARY) +endif + + +# --------------------------------------------------------------------------------- +# END +# --------------------------------------------------------------------------------- diff --git a/msm8998/mm-video-v4l2/vidc/venc/Makefile.am b/msm8998/mm-video-v4l2/vidc/venc/Makefile.am new file mode 100644 index 0000000..22aed6f --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/Makefile.am @@ -0,0 +1,85 @@ +#AM_CFLAGS = -Wall +#AM_CFLAGS = -Wundef +#AM_CFLAGS += -Wstrict-prototypes +#AM_CFLAGS += -Wno-trigraphs +#AM_CFLAGS += -Wno-multichar + +AM_CPPFLAGS = -D__alignx\(x\)=__attribute__\(\(__aligned__\(x\)\)\) +AM_CPPFLAGS += -D__align=__alignx +AM_CPPFLAGS += -Dinline=__inline +AM_CPPFLAGS += -DIMAGE_APPS_PROC +AM_CPPFLAGS += -DCDECL +AM_CPPFLAGS += -DT_ARM +AM_CPPFLAGS += -DNO_ARM_CLZ +AM_CPPFLAGS += -D_ANDROID_ +AM_CPPFLAGS += -UENABLE_DEBUG_LOW +AM_CPPFLAGS += -DENABLE_DEBUG_HIGH +AM_CPPFLAGS += -DENABLE_DEBUG_ERROR +AM_CPPFLAGS += -UINPUT_BUFFER_LOG +AM_CPPFLAGS += -UOUTPUT_BUFFER_LOG +AM_CPPFLAGS += -Werror +AM_CPPFLAGS += -D_ANDROID_ICS_ +AM_CPPFLAGS += -D_MSM8974_ +AM_CPPFLAGS += -DUSE_ION +#AM_CPPFLAGS += "-include stdint.h" +AM_CPPFLAGS += "-Dstrlcpy=g_strlcpy" +AM_CPPFLAGS += "-Dstrlcat=g_strlcat" +AM_CPPFLAGS += "-std=c++11" +AM_CPPFLAGS += -Wno-undef +AM_CPPFLAGS += -Wno-multichar +AM_CPPFLAGS += -g -O3 + +if USE_GLIB +AM_CPPFLAGS += -D_USE_GLIB_ +endif + +if TARGET_MSM8610 +AM_CPPFLAGS += -DMAX_RES_720P +AM_CPPFLAGS += -D_MSM8610_ +else +if TARGET_MSM8226 +AM_CPPFLAGS += -DMAX_RES_1080P +else +AM_CPPFLAGS += -DMAX_RES_1080P +AM_CPPFLAGS += -DMAX_RES_1080P_EBI +endif +endif + +if TARGETS_THAT_SUPPORT_PQ +AM_CPPFLAGS += -D_PQ_ +endif + +if TARGETS_THAT_USE_FLAG_MSM8226 +AM_CPPFLAGS += -D_MSM8226_ +endif + +if TARGET_USES_MEDIA_EXTENSIONS +AM_CPPFLAGS += -DUSE_NATIVE_HANDLE_SOURCE +AM_CPPFLAGS += -DSUPPORT_CONFIG_INTRA_REFRESH +endif + +if MASTER_SIDE_CP_TARGET_LIST +AM_CPPFLAGS += -DMASTER_SIDE_CP +endif + +AM_CPPFLAGS += -I$(top_srcdir)/mm-video-v4l2/vidc/common/inc/ +AM_CPPFLAGS += -I$(top_srcdir)/mm-video-v4l2/vidc/venc/inc/ +AM_CPPFLAGS += -I$(top_srcdir)/libc2dcolorconvert/ +AM_CPPFLAGS += -I$(top_srcdir)/mm-core/inc/ +AM_CPPFLAGS += -I$(top_srcdir)/mm-core/src/common/ +AM_CPPFLAGS += -I$(top_srcdir)/libstagefrighthw/ + +sources = src/omx_video_base.cpp +sources += src/omx_video_encoder.cpp +sources += src/video_encoder_device_v4l2.cpp +sources += $(top_srcdir)/mm-video-v4l2/vidc/common/src/extra_data_handler.cpp +sources += $(top_srcdir)/mm-video-v4l2/vidc/common/src/vidc_color_converter.cpp + +lib_LTLIBRARIES = libOmxVenc.la +libOmxVenc_la_SOURCES = $(sources) +libOmxVenc_la_CFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS) -fPIC +#libOmxVenc_la_LDLIBS = ../libc2d2colorconvert/libc2dcolorconvert.la +#libOmxVenc_la_LIBADD = ../../../mm-core/libOmxCore.la +libOmxVenc_la_LDFLAGS = -lstdc++ -lpthread -llog -lutils -lbinder -lcutils -lglib-2.0 -lbase -ldl -lpthread -shared +# -lqdMetaData -lc2d2 -lgui -lOmxCore -lgpustats -ldl -lpthread +libOmxVenc_la_LDFLAGS += -version-info 0
\ No newline at end of file diff --git a/msm8998/mm-video-v4l2/vidc/venc/inc/camera_test.h b/msm8998/mm-video-v4l2/vidc/venc/inc/camera_test.h new file mode 100644 index 0000000..84c5e5f --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/inc/camera_test.h @@ -0,0 +1,58 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2011, 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#ifndef _CAMERA_TEST_H +#define _CAMERA_TEST_H + +#define EXTERN_C_START extern "C" { +#define EXTERN_C_END } + +#ifdef __cplusplus +EXTERN_C_START +#endif + +typedef void (*CameraPreviewCallback)(int nFD, + int nOffset, + void* pPhys, + void* pVirt, + long long nTimeStamp); + + +int CameraTest_Initialize(int nFrameRate, + int nFrameWidth, + int nFrameHeight, + CameraPreviewCallback pfnPreviewCallback); +int CameraTest_Run(); +int CameraTest_ReleaseFrame(void* pPhys, void* pVirt); +int CameraTest_Exit(); + + +#ifdef __cplusplus +EXTERN_C_END +#endif + +#endif diff --git a/msm8998/mm-video-v4l2/vidc/venc/inc/fb_test.h b/msm8998/mm-video-v4l2/vidc/venc/inc/fb_test.h new file mode 100644 index 0000000..173150c --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/inc/fb_test.h @@ -0,0 +1,48 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2011, 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#ifndef _FB_TEST_H +#define _FB_TEST_H + +#ifdef __cplusplus +extern "C" { +#endif + + + int FBTest_Initialize(int nFrameWidth, + int nFrameHeight); + int FBTest_DisplayImage(int nPmemFd, int nOffset); + int FBTest_Exit(); + + int FBTest_RunTest(); + +#ifdef __cplusplus +} +#endif + + +#endif // _FB_TEST_H diff --git a/msm8998/mm-video-v4l2/vidc/venc/inc/omx_swvenc_hevc.h b/msm8998/mm-video-v4l2/vidc/venc/inc/omx_swvenc_hevc.h new file mode 100644 index 0000000..4ec9906 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/inc/omx_swvenc_hevc.h @@ -0,0 +1,113 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2014, 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. +--------------------------------------------------------------------------*/ +#ifndef __OMX_SWVENC__H +#define __OMX_SWVENC__H + +#include <unistd.h> +#include "omx_video_base.h" +#include "SwVencTypes.h" +#include "SwVencAPI.h" + +extern "C" { + OMX_API void * get_omx_component_factory_fn(void); +} + +class omx_swvenc: public omx_video +{ +public: + omx_swvenc(); //constructor + ~omx_swvenc(); //des + + OMX_ERRORTYPE component_init(OMX_STRING role); + + OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp); + bool is_secure_session(); + + static SWVENC_STATUS swvenc_input_buffer_done_cb(SWVENC_HANDLE pSwEnc, SWVENC_IPBUFFER *pIpBuffer, void *pClientHandle); + static SWVENC_STATUS swvenc_fill_buffer_done_cb(SWVENC_HANDLE pSwEnc, SWVENC_OPBUFFER *pOpBuffer, void *pClientHandle); + static SWVENC_STATUS swvenc_handle_event_cb (SWVENC_HANDLE pSwEnc, SWVENC_EVENTHANDLER* pEventHandler, void *pClientHandle); + void swvenc_input_buffer_done(SWVENC_IPBUFFER *pIpBuffer); + void swvenc_fill_buffer_done(SWVENC_OPBUFFER *pOpBuffer); + void swvenc_handle_event(SWVENC_EVENTHANDLER *pEvent); + bool update_profile_level(); + + //OMX strucutres + OMX_U32 m_nVenc_format; + +private: + virtual OMX_U32 dev_stop(void); + virtual OMX_U32 dev_pause(void); + virtual OMX_U32 dev_start(void); + virtual OMX_U32 dev_flush(unsigned); + virtual OMX_U32 dev_resume(void); + virtual OMX_U32 dev_start_done(void); + virtual OMX_U32 dev_set_message_thread_id(pthread_t); + virtual bool dev_use_buf(void *,unsigned,unsigned); + virtual bool dev_free_buf(void *,unsigned); + virtual bool dev_empty_buf(void *, void *,unsigned,unsigned); + virtual bool dev_fill_buf(void *buffer, void *,unsigned,unsigned); + virtual bool dev_get_buf_req(OMX_U32 *,OMX_U32 *,OMX_U32 *,OMX_U32); + bool dev_set_buf_req(OMX_U32 *,OMX_U32 *,OMX_U32 *,OMX_U32); + virtual bool dev_get_seq_hdr(void *, unsigned, unsigned *); + virtual bool dev_loaded_start(void); + virtual bool dev_loaded_stop(void); + virtual bool dev_loaded_start_done(void); + virtual bool dev_loaded_stop_done(void); +#ifdef _MSM8974_ + virtual int dev_handle_extradata(void*, int); + virtual int dev_set_format(int); +#endif + virtual bool dev_is_video_session_supported(OMX_U32 width, OMX_U32 height); + virtual bool dev_get_capability_ltrcount(OMX_U32 *, OMX_U32 *, OMX_U32 *); + virtual bool dev_get_performance_level(OMX_U32 *); + virtual bool dev_get_vui_timing_info(OMX_U32 *); + virtual bool dev_get_peak_bitrate(OMX_U32 *); + virtual bool dev_get_temporal_layer_caps(OMX_U32 * /*nMaxLayers*/, + OMX_U32 * /*nMaxBLayers*/) { + return false; + } + virtual bool dev_color_align(OMX_BUFFERHEADERTYPE *buffer, OMX_U32 width, + OMX_U32 height); + virtual bool dev_get_output_log_flag(); + virtual int dev_output_log_buffers(const char *buffer_addr, int buffer_len); + virtual int dev_extradata_log_buffers(char *buffer_addr); + + SWVENC_HANDLE m_pSwVenc; + SWVENC_CALLBACK m_callBackInfo; + SWVENC_IPBUFFER m_pSwVencIpBuffer[32]; + SWVENC_OPBUFFER m_pSwVencOpBuffer[32]; +}; + +#endif //__OMX_SWVENC__H diff --git a/msm8998/mm-video-v4l2/vidc/venc/inc/omx_swvenc_mpeg4.h b/msm8998/mm-video-v4l2/vidc/venc/inc/omx_swvenc_mpeg4.h new file mode 100644 index 0000000..5971fbc --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/inc/omx_swvenc_mpeg4.h @@ -0,0 +1,168 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2014-2016, 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. +--------------------------------------------------------------------------*/ +#ifndef __OMX_VENC__H +#define __OMX_VENC__H + +#include <unistd.h> +#include "omx_video_base.h" +#ifdef _MSM8974_ +#include "video_encoder_device_v4l2.h" +#else +#include "video_encoder_device.h" +#endif + +#include "swvenc_api.h" +#include "swvenc_types.h" + +extern "C" { + OMX_API void * get_omx_component_factory_fn(void); +} + +struct swvenc_video_capability { + unsigned int min_width; + unsigned int max_width; + unsigned int min_height; + unsigned int max_height; +}; + + +class omx_venc: public omx_video +{ + public: + omx_venc(); + ~omx_venc(); + OMX_ERRORTYPE component_init(OMX_STRING role); + OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp); + bool is_secure_session(); + //OMX strucutres + OMX_U32 m_nVenc_format; + + SWVENC_HANDLE m_hSwVenc; + SWVENC_CODEC m_codec; + swvenc_video_capability m_capability; + bool m_max_allowed_bitrate_check; + bool m_stopped; + bool set_format; + + int dev_handle_output_extradata(void *, int); + int dev_handle_input_extradata(void *, int, int); + bool dev_buffer_ready_to_queue(OMX_BUFFERHEADERTYPE *buffer); + void dev_set_extradata_cookie(void *); + int dev_set_format(int); + + static SWVENC_STATUS swvenc_empty_buffer_done_cb + ( + SWVENC_HANDLE swvenc, + SWVENC_IPBUFFER *p_ipbuffer, + void *p_client + ); + SWVENC_STATUS swvenc_empty_buffer_done + ( + SWVENC_IPBUFFER *p_ipbuffer + ); + static SWVENC_STATUS swvenc_fill_buffer_done_cb + ( + SWVENC_HANDLE swvenc, + SWVENC_OPBUFFER *p_opbuffer, + void *p_client + ); + static SWVENC_STATUS swvenc_handle_event_cb + ( + SWVENC_HANDLE swvenc, + SWVENC_EVENT event, + void *p_client + ); + + private: + venc_debug_cap m_debug; + bool m_bSeqHdrRequested; + + OMX_U32 dev_stop(void); + OMX_U32 dev_pause(void); + OMX_U32 dev_start(void); + OMX_U32 dev_flush(unsigned); + OMX_U32 dev_resume(void); + OMX_U32 dev_start_done(void); + OMX_U32 dev_set_message_thread_id(pthread_t); + bool dev_use_buf( void *,unsigned,unsigned); + bool dev_free_buf( void *,unsigned); + bool dev_empty_buf(void *, void *,unsigned,unsigned); + bool dev_fill_buf(void *, void *,unsigned,unsigned); + bool dev_get_buf_req(OMX_U32 *,OMX_U32 *,OMX_U32 *,OMX_U32); + bool dev_set_buf_req(OMX_U32 const *,OMX_U32 const *,OMX_U32 const *,OMX_U32); + bool dev_get_seq_hdr(void *, unsigned, unsigned *); + bool dev_loaded_start(void); + bool dev_loaded_stop(void); + bool dev_loaded_start_done(void); + bool dev_loaded_stop_done(void); + bool dev_get_capability_ltrcount(OMX_U32 *, OMX_U32 *, OMX_U32 *); + bool dev_get_performance_level(OMX_U32 *); + bool dev_get_vui_timing_info(OMX_U32 *); + bool dev_get_vqzip_sei_info(OMX_U32 *); + bool dev_get_peak_bitrate(OMX_U32 *); + bool dev_get_batch_size(OMX_U32 *); + bool dev_get_temporal_layer_caps(OMX_U32 * /*nMaxLayers*/, + OMX_U32 * /*nMaxBLayers*/) { + return false; + } + bool dev_is_video_session_supported(OMX_U32 width, OMX_U32 height); + bool dev_color_align(OMX_BUFFERHEADERTYPE *buffer, OMX_U32 width, + OMX_U32 height); + bool dev_get_output_log_flag(); + int dev_output_log_buffers(const char *buffer_addr, int buffer_len); + int dev_extradata_log_buffers(char *buffer); + bool swvenc_color_align(OMX_BUFFERHEADERTYPE *buffer, OMX_U32 width, + OMX_U32 height); + + SWVENC_STATUS swvenc_set_rc_mode(OMX_VIDEO_CONTROLRATETYPE eControlRate); + SWVENC_STATUS swvenc_set_profile_level(OMX_U32 eProfile,OMX_U32 eLevel); + SWVENC_STATUS swvenc_set_intra_refresh(OMX_VIDEO_PARAM_INTRAREFRESHTYPE *IntraRefresh); + SWVENC_STATUS swvenc_set_frame_rate(OMX_U32 nFrameRate); + SWVENC_STATUS swvenc_set_bit_rate(OMX_U32 nTargetBitrate); + SWVENC_STATUS swvenc_set_intra_period(OMX_U32 nPFrame,OMX_U32 nBFrame); + SWVENC_STATUS swvenc_set_color_format(OMX_COLOR_FORMATTYPE); + SWVENC_STATUS swvenc_get_buffer_req + ( + OMX_U32 *min_buff_count, + OMX_U32 *actual_buff_count, + OMX_U32 *buff_size, + OMX_U32 *buff_alignment, + OMX_U32 port + ); + int swvenc_input_log_buffers(const char *buffer, int bufferlen); + +}; + +#endif //__OMX_VENC__H diff --git a/msm8998/mm-video-v4l2/vidc/venc/inc/omx_video_base.h b/msm8998/mm-video-v4l2/vidc/venc/inc/omx_video_base.h new file mode 100644 index 0000000..b2e21af --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/inc/omx_video_base.h @@ -0,0 +1,712 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2016, 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. +--------------------------------------------------------------------------*/ + +#ifndef __OMX_VIDEO_BASE_H__ +#define __OMX_VIDEO_BASE_H__ +/*============================================================================ + O p e n M A X Component + Video Encoder + +*//** @file comx_video_base.h + This module contains the class definition for openMAX decoder component. + +*//*========================================================================*/ + +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +#define LOG_TAG "OMX-VENC" +#include <stdlib.h> +#include <stdio.h> +#include <sys/mman.h> +#ifdef _ANDROID_ +#include <binder/MemoryHeapBase.h> +#ifdef _ANDROID_ICS_ +#include "QComOMXMetadata.h" +#endif +#endif // _ANDROID_ +#include <pthread.h> +#include <semaphore.h> +#include <linux/msm_vidc_enc.h> +#include <media/hardware/HardwareAPI.h> +#include "OMX_Core.h" +#include "OMX_QCOMExtns.h" +#include "OMX_Skype_VideoExtensions.h" +#include "OMX_VideoExt.h" +#include "OMX_IndexExt.h" +#include "qc_omx_component.h" +#include "omx_video_common.h" +#include "extra_data_handler.h" +#include <linux/videodev2.h> +#include <dlfcn.h> +#include "C2DColorConverter.h" +#include "vidc_debug.h" + +#ifdef _ANDROID_ +using namespace android; +// local pmem heap object +class VideoHeap : public MemoryHeapBase +{ + public: + VideoHeap(int fd, size_t size, void* base); + virtual ~VideoHeap() {} +}; + +#include <utils/Log.h> + +#endif // _ANDROID_ + +#ifdef USE_ION +static const char* MEM_DEVICE = "/dev/ion"; +#if defined(MAX_RES_720P) && !defined(_MSM8974_) +#define MEM_HEAP_ID ION_CAMERA_HEAP_ID +#else +#ifdef _MSM8974_ +#define MEM_HEAP_ID ION_IOMMU_HEAP_ID +#else +#define MEM_HEAP_ID ION_CP_MM_HEAP_ID +#endif +#endif +#elif MAX_RES_720P +static const char* MEM_DEVICE = "/dev/pmem_adsp"; +#elif MAX_RES_1080P_EBI +static const char* MEM_DEVICE = "/dev/pmem_adsp"; +#elif MAX_RES_1080P +static const char* MEM_DEVICE = "/dev/pmem_smipool"; +#else +#error MEM_DEVICE cannot be determined. +#endif + +////////////////////////////////////////////////////////////////////////////// +// Module specific globals +////////////////////////////////////////////////////////////////////////////// +#define OMX_SPEC_VERSION 0x00000101 +#define OMX_INIT_STRUCT(_s_, _name_) \ + memset((_s_), 0x0, sizeof(_name_)); \ +(_s_)->nSize = sizeof(_name_); \ +(_s_)->nVersion.nVersion = OMX_SPEC_VERSION + +////////////////////////////////////////////////////////////////////////////// +// Macros +////////////////////////////////////////////////////////////////////////////// +#define PrintFrameHdr(bufHdr) DEBUG_PRINT("bufHdr %x buf %x size %d TS %d\n",\ + (unsigned) bufHdr,\ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->pBuffer,\ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nFilledLen,\ + (unsigned)((OMX_BUFFERHEADERTYPE *)bufHdr)->nTimeStamp) + +// BitMask Management logic +#define BITS_PER_INDEX 64 +#define BITMASK_SIZE(mIndex) (((mIndex) + BITS_PER_INDEX - 1)/BITS_PER_INDEX) +#define BITMASK_OFFSET(mIndex) ((mIndex)/BITS_PER_INDEX) +#define BITMASK_FLAG(mIndex) ((uint64_t)1 << ((mIndex) % BITS_PER_INDEX)) +#define BITMASK_CLEAR(mArray,mIndex) (mArray)[BITMASK_OFFSET(mIndex)] \ + &= ~(BITMASK_FLAG(mIndex)) +#define BITMASK_SET(mArray,mIndex) (mArray)[BITMASK_OFFSET(mIndex)] \ + |= BITMASK_FLAG(mIndex) +#define BITMASK_PRESENT(mArray,mIndex) ((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) +#define BITMASK_ABSENT(mArray,mIndex) (((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) == 0x0) +#define BITMASK_PRESENT(mArray,mIndex) ((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) +#define BITMASK_ABSENT(mArray,mIndex) (((mArray)[BITMASK_OFFSET(mIndex)] \ + & BITMASK_FLAG(mIndex)) == 0x0) + +#define MAX_NUM_INPUT_BUFFERS 64 +#define MAX_NUM_OUTPUT_BUFFERS 64 + +#ifdef USE_NATIVE_HANDLE_SOURCE +#define LEGACY_CAM_SOURCE kMetadataBufferTypeNativeHandleSource +#define LEGACY_CAM_METADATA_TYPE encoder_nativehandle_buffer_type +#else +#define LEGACY_CAM_SOURCE kMetadataBufferTypeCameraSource +#define LEGACY_CAM_METADATA_TYPE encoder_media_buffer_type +#endif + +void* message_thread_enc(void *); + +enum omx_venc_extradata_types { + VENC_EXTRADATA_SLICEINFO = 0x100, + VENC_EXTRADATA_MBINFO = 0x400, + VENC_EXTRADATA_FRAMEDIMENSION = 0x1000000, + VENC_EXTRADATA_YUV_STATS = 0x800, + VENC_EXTRADATA_VQZIP = 0x02000000, + VENC_EXTRADATA_ROI = 0x04000000, +}; + +struct output_metabuffer { + OMX_U32 type; + native_handle_t *nh; +}; + +// OMX video class +class omx_video: public qc_omx_component +{ + protected: +#ifdef _ANDROID_ICS_ + bool meta_mode_enable; + bool c2d_opened; + LEGACY_CAM_METADATA_TYPE meta_buffers[MAX_NUM_INPUT_BUFFERS]; + OMX_BUFFERHEADERTYPE *opaque_buffer_hdr[MAX_NUM_INPUT_BUFFERS]; + bool get_syntaxhdr_enable; + OMX_BUFFERHEADERTYPE *psource_frame; + OMX_BUFFERHEADERTYPE *pdest_frame; + bool secure_session; + bool hier_b_enabled; + //intermediate conversion buffer queued to encoder in case of invalid EOS input + OMX_BUFFERHEADERTYPE *mEmptyEosBuffer; + + class omx_c2d_conv + { + public: + omx_c2d_conv(); + ~omx_c2d_conv(); + bool init(); + bool open(unsigned int height,unsigned int width, + ColorConvertFormat src, ColorConvertFormat dest, + unsigned int src_stride, unsigned int flags); + bool convert(int src_fd, void *src_base, void *src_viraddr, + int dest_fd, void *dest_base, void *dest_viraddr); + bool get_buffer_size(int port,unsigned int &buf_size); + int get_src_format(); + void close(); + private: + C2DColorConverterBase *c2dcc; + pthread_mutex_t c_lock; + void *mLibHandle; + ColorConvertFormat src_format; + createC2DColorConverter_t *mConvertOpen; + destroyC2DColorConverter_t *mConvertClose; + }; + omx_c2d_conv c2d_conv; +#endif + public: + + bool mUseProxyColorFormat; + //RGB or non-native input, and we have pre-allocated conversion buffers + bool mUsesColorConversion; + + omx_video(); // constructor + virtual ~omx_video(); // destructor + + // virtual int async_message_process (void *context, void* message); + void process_event_cb(void *ctxt,unsigned char id); + + OMX_ERRORTYPE allocate_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes + ); + + + virtual OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp)= 0; + + virtual OMX_ERRORTYPE component_init(OMX_STRING role)= 0; + + virtual OMX_U32 dev_stop(void) = 0; + virtual OMX_U32 dev_pause(void) = 0; + virtual OMX_U32 dev_start(void) = 0; + virtual OMX_U32 dev_flush(unsigned) = 0; + virtual OMX_U32 dev_resume(void) = 0; + virtual OMX_U32 dev_start_done(void) = 0; + virtual OMX_U32 dev_set_message_thread_id(pthread_t) = 0; + virtual bool dev_use_buf(void *,unsigned,unsigned) = 0; + virtual bool dev_free_buf(void *,unsigned) = 0; + virtual bool dev_empty_buf(void *, void *,unsigned,unsigned) = 0; + virtual bool dev_fill_buf(void *buffer, void *,unsigned,unsigned) = 0; + virtual bool dev_get_buf_req(OMX_U32 *,OMX_U32 *,OMX_U32 *,OMX_U32) = 0; + virtual bool dev_get_seq_hdr(void *, unsigned, unsigned *) = 0; + virtual bool dev_loaded_start(void) = 0; + virtual bool dev_loaded_stop(void) = 0; + virtual bool dev_loaded_start_done(void) = 0; + virtual bool dev_loaded_stop_done(void) = 0; + virtual bool is_secure_session(void) = 0; + virtual int dev_handle_output_extradata(void*, int) = 0; + virtual int dev_set_format(int) = 0; + virtual bool dev_is_video_session_supported(OMX_U32 width, OMX_U32 height) = 0; + virtual bool dev_get_capability_ltrcount(OMX_U32 *, OMX_U32 *, OMX_U32 *) = 0; + virtual bool dev_get_performance_level(OMX_U32 *) = 0; + virtual bool dev_get_vui_timing_info(OMX_U32 *) = 0; + virtual bool dev_get_vqzip_sei_info(OMX_U32 *) = 0; + virtual bool dev_get_peak_bitrate(OMX_U32 *) = 0; + virtual bool dev_get_batch_size(OMX_U32 *) = 0; + virtual bool dev_buffer_ready_to_queue(OMX_BUFFERHEADERTYPE *buffer) = 0; + virtual bool dev_get_temporal_layer_caps(OMX_U32 * /*nMaxLayers*/, + OMX_U32 * /*nMaxBLayers*/) = 0; +#ifdef _ANDROID_ICS_ + void omx_release_meta_buffer(OMX_BUFFERHEADERTYPE *buffer); +#endif + virtual bool dev_color_align(OMX_BUFFERHEADERTYPE *buffer, OMX_U32 width, + OMX_U32 height) = 0; + virtual bool dev_get_output_log_flag() = 0; + virtual int dev_output_log_buffers(const char *buffer_addr, int buffer_len) = 0; + virtual int dev_extradata_log_buffers(char *buffer_addr) = 0; + OMX_ERRORTYPE component_role_enum( + OMX_HANDLETYPE hComp, + OMX_U8 *role, + OMX_U32 index + ); + + OMX_ERRORTYPE component_tunnel_request( + OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_HANDLETYPE peerComponent, + OMX_U32 peerPort, + OMX_TUNNELSETUPTYPE *tunnelSetup + ); + + OMX_ERRORTYPE empty_this_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ); + + + + OMX_ERRORTYPE fill_this_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer + ); + + + OMX_ERRORTYPE free_buffer( + OMX_HANDLETYPE hComp, + OMX_U32 port, + OMX_BUFFERHEADERTYPE *buffer + ); + + OMX_ERRORTYPE get_component_version( + OMX_HANDLETYPE hComp, + OMX_STRING componentName, + OMX_VERSIONTYPE *componentVersion, + OMX_VERSIONTYPE *specVersion, + OMX_UUIDTYPE *componentUUID + ); + + OMX_ERRORTYPE get_config( + OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData + ); + + OMX_ERRORTYPE get_extension_index( + OMX_HANDLETYPE hComp, + OMX_STRING paramName, + OMX_INDEXTYPE *indexType + ); + + OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + + OMX_ERRORTYPE get_state(OMX_HANDLETYPE hComp, + OMX_STATETYPE *state); + + + + OMX_ERRORTYPE send_command(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + + + OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE hComp, + OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData); + + virtual OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData) = 0; + + virtual OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData) =0; + + OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); + + + OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + void * eglImage); + + + + int m_pipe_in; + int m_pipe_out; + + pthread_t msg_thread_id; + pthread_t async_thread_id; + bool async_thread_created; + bool msg_thread_created; + volatile bool msg_thread_stop; + + OMX_U8 m_nkind[128]; + + + //int *input_pmem_fd; + //int *output_pmem_fd; + struct pmem *m_pInput_pmem; + struct pmem *m_pOutput_pmem; +#ifdef USE_ION + struct venc_ion *m_pInput_ion; + struct venc_ion *m_pOutput_ion; +#endif + + + + public: + // Bit Positions + enum flags_bit_positions { + // Defer transition to IDLE + OMX_COMPONENT_IDLE_PENDING =0x1, + // Defer transition to LOADING + OMX_COMPONENT_LOADING_PENDING =0x2, + // First Buffer Pending + OMX_COMPONENT_FIRST_BUFFER_PENDING =0x3, + // Second Buffer Pending + OMX_COMPONENT_SECOND_BUFFER_PENDING =0x4, + // Defer transition to Enable + OMX_COMPONENT_INPUT_ENABLE_PENDING =0x5, + // Defer transition to Enable + OMX_COMPONENT_OUTPUT_ENABLE_PENDING =0x6, + // Defer transition to Disable + OMX_COMPONENT_INPUT_DISABLE_PENDING =0x7, + // Defer transition to Disable + OMX_COMPONENT_OUTPUT_DISABLE_PENDING =0x8, + //defer flush notification + OMX_COMPONENT_OUTPUT_FLUSH_PENDING =0x9, + OMX_COMPONENT_INPUT_FLUSH_PENDING =0xA, + OMX_COMPONENT_PAUSE_PENDING =0xB, + OMX_COMPONENT_EXECUTE_PENDING =0xC, + OMX_COMPONENT_LOADED_START_PENDING = 0xD, + OMX_COMPONENT_LOADED_STOP_PENDING = 0xF, + + }; + + // Deferred callback identifiers + enum { + //Event Callbacks from the venc component thread context + OMX_COMPONENT_GENERATE_EVENT = 0x1, + //Buffer Done callbacks from the venc component thread context + OMX_COMPONENT_GENERATE_BUFFER_DONE = 0x2, + //Frame Done callbacks from the venc component thread context + OMX_COMPONENT_GENERATE_FRAME_DONE = 0x3, + //Buffer Done callbacks from the venc component thread context + OMX_COMPONENT_GENERATE_FTB = 0x4, + //Frame Done callbacks from the venc component thread context + OMX_COMPONENT_GENERATE_ETB = 0x5, + //Command + OMX_COMPONENT_GENERATE_COMMAND = 0x6, + //Push-Pending Buffers + OMX_COMPONENT_PUSH_PENDING_BUFS = 0x7, + // Empty Buffer Done callbacks + OMX_COMPONENT_GENERATE_EBD = 0x8, + //Flush Event Callbacks from the venc component thread context + OMX_COMPONENT_GENERATE_EVENT_FLUSH = 0x9, + OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH = 0x0A, + OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH = 0x0B, + OMX_COMPONENT_GENERATE_FBD = 0xc, + OMX_COMPONENT_GENERATE_START_DONE = 0xD, + OMX_COMPONENT_GENERATE_PAUSE_DONE = 0xE, + OMX_COMPONENT_GENERATE_RESUME_DONE = 0xF, + OMX_COMPONENT_GENERATE_STOP_DONE = 0x10, + OMX_COMPONENT_GENERATE_HARDWARE_ERROR = 0x11, + OMX_COMPONENT_GENERATE_LTRUSE_FAILED = 0x12, + OMX_COMPONENT_GENERATE_ETB_OPQ = 0x13, + OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING = 0x14, + OMX_COMPONENT_GENERATE_HARDWARE_OVERLOAD = 0x15, + OMX_COMPONENT_CLOSE_MSG = 0x16 + }; + + struct omx_event { + unsigned long param1; + unsigned long param2; + unsigned long id; + }; + + struct omx_cmd_queue { + omx_event m_q[OMX_CORE_CONTROL_CMDQ_SIZE]; + unsigned long m_read; + unsigned long m_write; + unsigned long m_size; + + omx_cmd_queue(); + ~omx_cmd_queue(); + bool insert_entry(unsigned long p1, unsigned long p2, unsigned long id); + bool pop_entry(unsigned long *p1,unsigned long *p2, unsigned long *id); + // get msgtype of the first ele from the queue + unsigned get_q_msg_type(); + + }; + + bool allocate_done(void); + bool allocate_input_done(void); + bool allocate_output_done(void); + + OMX_ERRORTYPE free_input_buffer(OMX_BUFFERHEADERTYPE *bufferHdr); + OMX_ERRORTYPE free_output_buffer(OMX_BUFFERHEADERTYPE *bufferHdr); + + OMX_ERRORTYPE allocate_input_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes); +#ifdef _ANDROID_ICS_ + OMX_ERRORTYPE allocate_input_meta_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_PTR appData, + OMX_U32 bytes); +#endif + OMX_ERRORTYPE allocate_output_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port,OMX_PTR appData, + OMX_U32 bytes); + + OMX_ERRORTYPE use_input_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); + + OMX_ERRORTYPE use_output_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_U32 port, + OMX_PTR appData, + OMX_U32 bytes, + OMX_U8 *buffer); + + bool execute_omx_flush(OMX_U32); + bool execute_output_flush(void); + bool execute_input_flush(void); +#ifdef _MSM8974_ + bool execute_flush_all(void); +#endif + OMX_ERRORTYPE empty_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer); + + OMX_ERRORTYPE fill_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer); + OMX_ERRORTYPE empty_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + OMX_ERRORTYPE empty_this_buffer_opaque(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + OMX_ERRORTYPE push_input_buffer(OMX_HANDLETYPE hComp); + OMX_ERRORTYPE convert_queue_buffer(OMX_HANDLETYPE hComp, + struct pmem &Input_pmem_info,unsigned long &index); + OMX_ERRORTYPE queue_meta_buffer(OMX_HANDLETYPE hComp, + struct pmem &Input_pmem_info); + OMX_ERRORTYPE push_empty_eos_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + OMX_ERRORTYPE fill_this_buffer_proxy(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE *buffer); + bool release_done(); + + bool release_output_done(); + bool release_input_done(); + + OMX_ERRORTYPE send_command_proxy(OMX_HANDLETYPE hComp, + OMX_COMMANDTYPE cmd, + OMX_U32 param1, + OMX_PTR cmdData); + bool post_event( unsigned long p1, + unsigned long p2, + unsigned long id + ); + OMX_ERRORTYPE get_supported_profile_level(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType); + inline void omx_report_error () { + if (m_pCallbacks.EventHandler && !m_error_propogated && m_state != OMX_StateLoaded) { + m_error_propogated = true; + DEBUG_PRINT_ERROR("ERROR: send OMX_ErrorHardware to Client"); + m_pCallbacks.EventHandler(&m_cmp,m_app_data, + OMX_EventError,OMX_ErrorHardware,0,NULL); + } + } + + inline void omx_report_hw_overload () + { + if (m_pCallbacks.EventHandler && !m_error_propogated && m_state != OMX_StateLoaded) { + m_error_propogated = true; + DEBUG_PRINT_ERROR("ERROR: send OMX_ErrorInsufficientResources to Client"); + m_pCallbacks.EventHandler(&m_cmp, m_app_data, + OMX_EventError, OMX_ErrorInsufficientResources, 0, NULL); + } + } + + inline void omx_report_unsupported_setting () { + if (m_pCallbacks.EventHandler && !m_error_propogated && m_state != OMX_StateLoaded) { + m_error_propogated = true; + m_pCallbacks.EventHandler(&m_cmp,m_app_data, + OMX_EventError,OMX_ErrorUnsupportedSetting,0,NULL); + } + } + + void complete_pending_buffer_done_cbs(); + bool is_conv_needed(int, int); + void print_debug_color_aspects(ColorAspects *aspects, const char *prefix); + +#ifdef USE_ION + int alloc_map_ion_memory(int size, + struct ion_allocation_data *alloc_data, + struct ion_fd_data *fd_data,int flag); + void free_ion_memory(struct venc_ion *buf_ion_info); +#endif + + //************************************************************* + //*******************MEMBER VARIABLES ************************* + //************************************************************* + + pthread_mutex_t m_lock; + sem_t m_cmd_lock; + bool m_error_propogated; + + //sem to handle the minimum procesing of commands + + + // compression format + //OMX_VIDEO_CODINGTYPE eCompressionFormat; + // OMX State + OMX_STATETYPE m_state; + // Application data + OMX_PTR m_app_data; + OMX_BOOL m_use_input_pmem; + OMX_BOOL m_use_output_pmem; + // Application callbacks + OMX_CALLBACKTYPE m_pCallbacks; + OMX_PORT_PARAM_TYPE m_sPortParam; + OMX_VIDEO_PARAM_PROFILELEVELTYPE m_sParamProfileLevel; + OMX_VIDEO_PARAM_PORTFORMATTYPE m_sInPortFormat; + OMX_VIDEO_PARAM_PORTFORMATTYPE m_sOutPortFormat; + OMX_PARAM_PORTDEFINITIONTYPE m_sInPortDef; + OMX_PARAM_PORTDEFINITIONTYPE m_sOutPortDef; + OMX_VIDEO_PARAM_MPEG4TYPE m_sParamMPEG4; + OMX_VIDEO_PARAM_H263TYPE m_sParamH263; + OMX_VIDEO_PARAM_AVCTYPE m_sParamAVC; + OMX_VIDEO_PARAM_VP8TYPE m_sParamVP8; + OMX_VIDEO_PARAM_HEVCTYPE m_sParamHEVC; + OMX_PORT_PARAM_TYPE m_sPortParam_img; + OMX_PORT_PARAM_TYPE m_sPortParam_audio; + OMX_VIDEO_CONFIG_BITRATETYPE m_sConfigBitrate; + OMX_CONFIG_FRAMERATETYPE m_sConfigFramerate; + OMX_VIDEO_PARAM_BITRATETYPE m_sParamBitrate; + OMX_PRIORITYMGMTTYPE m_sPriorityMgmt; + OMX_PARAM_BUFFERSUPPLIERTYPE m_sInBufSupplier; + OMX_PARAM_BUFFERSUPPLIERTYPE m_sOutBufSupplier; + OMX_CONFIG_ROTATIONTYPE m_sConfigFrameRotation; + OMX_CONFIG_INTRAREFRESHVOPTYPE m_sConfigIntraRefreshVOP; + OMX_VIDEO_PARAM_QUANTIZATIONTYPE m_sSessionQuantization; + OMX_QCOM_VIDEO_PARAM_QPRANGETYPE m_sSessionQPRange; + OMX_QCOM_VIDEO_PARAM_IPB_QPRANGETYPE m_sSessionIPBQPRange; + OMX_VIDEO_PARAM_AVCSLICEFMO m_sAVCSliceFMO; + QOMX_VIDEO_INTRAPERIODTYPE m_sIntraperiod; + OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE m_sErrorCorrection; + OMX_VIDEO_PARAM_INTRAREFRESHTYPE m_sIntraRefresh; + QOMX_VIDEO_PARAM_LTRMODE_TYPE m_sParamLTRMode; + QOMX_VIDEO_PARAM_LTRCOUNT_TYPE m_sParamLTRCount; + QOMX_VIDEO_CONFIG_LTRPERIOD_TYPE m_sConfigLTRPeriod; + QOMX_VIDEO_CONFIG_LTRUSE_TYPE m_sConfigLTRUse; + OMX_VIDEO_CONFIG_AVCINTRAPERIOD m_sConfigAVCIDRPeriod; + OMX_VIDEO_CONFIG_DEINTERLACE m_sConfigDeinterlace; + OMX_VIDEO_VP8REFERENCEFRAMETYPE m_sConfigVp8ReferenceFrame; + QOMX_VIDEO_HIERARCHICALLAYERS m_sHierLayers; + OMX_QOMX_VIDEO_MBI_STATISTICS m_sMBIStatistics; + QOMX_EXTNINDEX_VIDEO_INITIALQP m_sParamInitqp; + QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS m_sHPlayers; + OMX_SKYPE_VIDEO_CONFIG_BASELAYERPID m_sBaseLayerID; + OMX_SKYPE_VIDEO_PARAM_DRIVERVER m_sDriverVer; + OMX_SKYPE_VIDEO_CONFIG_QP m_sConfigQP; + QOMX_EXTNINDEX_VIDEO_VENC_SAR m_sSar; + QOMX_VIDEO_H264ENTROPYCODINGTYPE m_sParamEntropy; + PrependSPSPPSToIDRFramesParams m_sPrependSPSPPS; + struct timestamp_info { + OMX_U64 m_TimeStamp; + bool is_buffer_pending; + OMX_BUFFERHEADERTYPE *pending_buffer; + pthread_mutex_t m_lock; + } timestamp; + OMX_U32 m_sExtraData; + OMX_U32 m_input_msg_id; + QOMX_EXTNINDEX_VIDEO_VENC_LOW_LATENCY_MODE m_slowLatencyMode; +#ifdef SUPPORT_CONFIG_INTRA_REFRESH + OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE m_sConfigIntraRefresh; +#endif + OMX_QTI_VIDEO_CONFIG_BLURINFO m_blurInfo; + DescribeColorAspectsParams m_sConfigColorAspects; + OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE m_sParamTemporalLayers; + OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE m_sConfigTemporalLayers; + + // fill this buffer queue + omx_cmd_queue m_ftb_q; + // Command Q for rest of the events + omx_cmd_queue m_cmd_q; + omx_cmd_queue m_etb_q; + // Input memory pointer + OMX_BUFFERHEADERTYPE *m_inp_mem_ptr; + // Output memory pointer + OMX_BUFFERHEADERTYPE *m_out_mem_ptr; + omx_cmd_queue m_opq_meta_q; + omx_cmd_queue m_opq_pmem_q; + OMX_BUFFERHEADERTYPE meta_buffer_hdr[MAX_NUM_INPUT_BUFFERS]; + + bool input_flush_progress; + bool output_flush_progress; + bool input_use_buffer; + bool output_use_buffer; + int pending_input_buffers; + int pending_output_buffers; + + uint64_t m_out_bm_count; + uint64_t m_inp_bm_count; + uint64_t m_flags; + uint64_t m_etb_count; + uint64_t m_fbd_count; +#ifdef _ANDROID_ + // Heap pointer to frame buffers + sp<MemoryHeapBase> m_heap_ptr; +#endif //_ANDROID_ + // to know whether Event Port Settings change has been triggered or not. + bool m_event_port_settings_sent; + OMX_U8 m_cRole[OMX_MAX_STRINGNAME_SIZE]; + extra_data_handler extra_data_handle; + bool hw_overload; + size_t m_graphicbuffer_size; + char m_platform[OMX_MAX_STRINGNAME_SIZE]; +}; + +#endif // __OMX_VIDEO_BASE_H__ diff --git a/msm8998/mm-video-v4l2/vidc/venc/inc/omx_video_common.h b/msm8998/mm-video-v4l2/vidc/venc/inc/omx_video_common.h new file mode 100644 index 0000000..699e1b9 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/inc/omx_video_common.h @@ -0,0 +1,112 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2016, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ + +#ifndef __OMX_VIDEO_COMMON_H__ +#define __OMX_VIDEO_COMMON_H__ +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +#include<stdlib.h> +#include <stdio.h> +#ifdef USE_ION +#include <linux/msm_ion.h> +#endif + +#ifdef _ANDROID_ +#include <cutils/properties.h> +#else +#define PROPERTY_VALUE_MAX 92 +#endif + +#define OMX_VIDEO_DEC_NUM_INPUT_BUFFERS 2 +#define OMX_VIDEO_DEC_NUM_OUTPUT_BUFFERS 2 + +#ifdef FEATURE_QTV_WVGA_ENABLE +#define OMX_VIDEO_DEC_INPUT_BUFFER_SIZE (256*1024) +#else +#define OMX_VIDEO_DEC_INPUT_BUFFER_SIZE (128*1024) +#endif + +#define OMX_CORE_CONTROL_CMDQ_SIZE 100 +#define OMX_CORE_QCIF_HEIGHT 144 +#define OMX_CORE_QCIF_WIDTH 176 +#define OMX_CORE_VGA_HEIGHT 480 +#define OMX_CORE_VGA_WIDTH 640 +#define OMX_CORE_WVGA_HEIGHT 480 +#define OMX_CORE_WVGA_WIDTH 800 +#define OMX_CORE_FWVGA_HEIGHT 480 +#define OMX_CORE_FWVGA_WIDTH 864 +#define OMX_CORE_720P_WIDTH 1280 +#define OMX_CORE_720P_HEIGHT 720 +#define OMX_CORE_1080P_WIDTH 1920 +#define OMX_CORE_1080P_HEIGHT 1080 +#define OMX_CORE_4KUHD_WIDTH 3840 +#define OMX_CORE_4KUHD_HEIGHT 2160 +#define OMX_CORE_4KDCI_WIDTH 4096 +#define OMX_CORE_4KDCI_HEIGHT 2160 + +enum PortIndexType { + PORT_INDEX_IN = 0, + PORT_INDEX_OUT = 1, + PORT_INDEX_BOTH = -1, + PORT_INDEX_NONE = -2 +}; + +struct pmem { + void *buffer; + int fd; + unsigned offset; + unsigned size; +}; + +struct venc_debug_cap { + bool in_buffer_log; + bool out_buffer_log; + bool extradata_log; + char infile_name[PROPERTY_VALUE_MAX]; + char outfile_name[PROPERTY_VALUE_MAX]; + char extradatafile_name[PROPERTY_VALUE_MAX]; + char log_loc[PROPERTY_VALUE_MAX]; + FILE *infile; + FILE *outfile; + FILE *extradatafile; +}; +#ifdef USE_ION +struct venc_ion { + int ion_device_fd; + struct ion_fd_data fd_ion_data; + struct ion_allocation_data ion_alloc_data; +}; + +#endif +#endif // __OMX_VIDEO_COMMON_H__ + + + + diff --git a/msm8998/mm-video-v4l2/vidc/venc/inc/omx_video_encoder.h b/msm8998/mm-video-v4l2/vidc/venc/inc/omx_video_encoder.h new file mode 100644 index 0000000..fc26690 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/inc/omx_video_encoder.h @@ -0,0 +1,119 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-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. +--------------------------------------------------------------------------*/ +#ifndef __OMX_VENC__H +#define __OMX_VENC__H + +#include <unistd.h> +#include "omx_video_base.h" +#include "video_encoder_device_v4l2.h" + +extern "C" { + OMX_API void * get_omx_component_factory_fn(void); +} + +class omx_venc: public omx_video +{ + public: + omx_venc(); //constructor + ~omx_venc(); //des + static int async_message_process (void *context, void* message); + OMX_ERRORTYPE component_init(OMX_STRING role); + OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE paramIndex, + OMX_PTR paramData); + OMX_ERRORTYPE set_config(OMX_HANDLETYPE hComp, + OMX_INDEXTYPE configIndex, + OMX_PTR configData); + OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE hComp); + bool is_secure_session(); + //OMX strucutres + OMX_U32 m_nVenc_format; + class venc_dev *handle; + int dev_handle_output_extradata(void *, int); + int dev_set_format(int); + private: + OMX_U32 dev_stop(void); + OMX_U32 dev_pause(void); + OMX_U32 dev_start(void); + OMX_U32 dev_flush(unsigned); + OMX_U32 dev_resume(void); + OMX_U32 dev_start_done(void); + OMX_U32 dev_set_message_thread_id(pthread_t); + bool dev_use_buf( void *,unsigned,unsigned); + bool dev_free_buf( void *,unsigned); + bool dev_empty_buf(void *, void *,unsigned,unsigned); + bool dev_fill_buf(void *, void *,unsigned,unsigned); + bool dev_buffer_ready_to_queue(OMX_BUFFERHEADERTYPE *buffer); + bool dev_get_buf_req(OMX_U32 *,OMX_U32 *,OMX_U32 *,OMX_U32); + bool dev_set_buf_req(OMX_U32 *,OMX_U32 *,OMX_U32 *,OMX_U32); + bool update_profile_level(); + bool dev_get_seq_hdr(void *, unsigned, unsigned *); + bool dev_loaded_start(void); + bool dev_loaded_stop(void); + bool dev_loaded_start_done(void); + bool dev_loaded_stop_done(void); + bool dev_get_capability_ltrcount(OMX_U32 *, OMX_U32 *, OMX_U32 *); + bool dev_get_performance_level(OMX_U32 *); + bool dev_get_vui_timing_info(OMX_U32 *); + bool dev_get_vqzip_sei_info(OMX_U32 *); + bool dev_get_peak_bitrate(OMX_U32 *); + bool dev_get_batch_size(OMX_U32 *); + bool dev_get_temporal_layer_caps(OMX_U32 * /*nMaxLayers*/, + OMX_U32 * /*nMaxBLayers*/); + bool dev_is_video_session_supported(OMX_U32 width, OMX_U32 height); + bool dev_color_align(OMX_BUFFERHEADERTYPE *buffer, OMX_U32 width, + OMX_U32 height); + bool dev_get_output_log_flag(); + int dev_output_log_buffers(const char *buffer_addr, int buffer_len); + int dev_extradata_log_buffers(char *buffer); + class perf_control { + typedef int (*perf_lock_acquire_t)(int, int, int*, int); + typedef int (*perf_lock_release_t)(int); + public: + perf_control(); + ~perf_control(); + void send_hint_to_mpctl(bool state); + private: + int m_perf_handle; + void *m_perf_lib; + bool load_lib(); + perf_lock_acquire_t m_perf_lock_acquire; + perf_lock_release_t m_perf_lock_release; + }; + perf_control m_perf_control; +}; + +#ifdef _UBWC_ + #define QOMX_DEFAULT_COLOR_FMT QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed + #define V4L2_DEFAULT_OUTPUT_COLOR_FMT V4L2_PIX_FMT_NV12_UBWC +#else + #define QOMX_DEFAULT_COLOR_FMT QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m + #define V4L2_DEFAULT_OUTPUT_COLOR_FMT V4L2_PIX_FMT_NV12 +#endif +#endif //__OMX_VENC__H diff --git a/msm8998/mm-video-v4l2/vidc/venc/inc/queue.h b/msm8998/mm-video-v4l2/vidc/venc/inc/queue.h new file mode 100644 index 0000000..0b653da --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/inc/queue.h @@ -0,0 +1,78 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2011, 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#ifndef QUEUE_H +#define QUEUE_H + +#include<pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <string.h> + +/* Message Queue structure */ +struct video_msgq { + /* Command to be executed */ + unsigned int cmd; + + unsigned int status; + + /* Client-specific data */ + void *clientdata; +}; + + +/* Thread & Message Queue information */ +struct video_queue_context { + /* Message Queue related members */ + pthread_mutex_t mutex; + sem_t sem_message; + int commandq_size; + int dataq_size; + struct video_msgq *ptr_dataq; + struct video_msgq *ptr_cmdq; + int write_dataq ; + int read_dataq; + int write_comq ; + int read_comq ; + +}; + +int check_if_queue_empty ( unsigned int queuetocheck,void* queuecontext ); + +struct video_msgq * queue_get_cmd ( void* queuecontext ); + + + +int queue_post_cmdq ( void *queuecontext, + struct video_msgq *post_msg + ); + +int queue_post_dataq ( void *queuecontext, + struct video_msgq *post_msg + ); + +#endif /* QUEUE_H */ diff --git a/msm8998/mm-video-v4l2/vidc/venc/inc/venc_util.h b/msm8998/mm-video-v4l2/vidc/venc/inc/venc_util.h new file mode 100644 index 0000000..79602dc --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/inc/venc_util.h @@ -0,0 +1,53 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2011, 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +/*============================================================================ + V E N C _ U T I L. H + + DESCRIPTION + + + REFERENCES + + + ============================================================================*/ + +#ifndef _VENC_UTIL_H +#define _VENC_UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + + long long GetTimeStamp(); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/msm8998/mm-video-v4l2/vidc/venc/inc/video_encoder_device.h b/msm8998/mm-video-v4l2/vidc/venc/inc/video_encoder_device.h new file mode 100644 index 0000000..fde041d --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/inc/video_encoder_device.h @@ -0,0 +1,177 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#ifndef __OMX_VENC_DEV__ +#define __OMX_VENC_DEV__ + +#include "OMX_Types.h" +#include "OMX_Core.h" +#include "OMX_QCOMExtns.h" +#include "qc_omx_component.h" +#include "omx_video_common.h" +#include <linux/msm_vidc_enc.h> +#include <pthread.h> +#include <linux/videodev2.h> +#include <poll.h> +#define TIMEOUT 5000 +#define MAX_RECON_BUFFERS 4 + +void* async_venc_message_thread (void *); + +class venc_dev +{ + public: + venc_dev(class omx_venc *venc_class); //constructor + ~venc_dev(); //des + + bool venc_open(OMX_U32); + void venc_close(); + unsigned venc_stop(void); + unsigned venc_pause(void); + unsigned venc_start(void); + unsigned venc_flush(unsigned); +#ifdef _ANDROID_ICS_ + bool venc_set_meta_mode(bool); +#endif + unsigned venc_resume(void); + unsigned venc_start_done(void); + unsigned venc_set_message_thread_id(pthread_t); + bool venc_use_buf(void*, unsigned,unsigned); + bool venc_free_buf(void*, unsigned); + bool venc_empty_buf(void *, void *,unsigned,unsigned); + bool venc_fill_buf(void *, void *,unsigned,unsigned); + + bool venc_get_buf_req(unsigned long *,unsigned long *, + unsigned long *,unsigned long); + bool venc_set_buf_req(unsigned long *,unsigned long *, + unsigned long *,unsigned long); + bool venc_set_param(void *,OMX_INDEXTYPE); + bool venc_set_config(void *configData, OMX_INDEXTYPE index); + bool venc_get_profile_level(OMX_U32 *eProfile,OMX_U32 *eLevel); + bool venc_max_allowed_bitrate_check(OMX_U32 nTargetBitrate); + bool venc_get_seq_hdr(void *, unsigned, unsigned *); + bool venc_loaded_start(void); + bool venc_loaded_stop(void); + bool venc_loaded_start_done(void); + bool venc_loaded_stop_done(void); + bool venc_get_output_log_flag(); + int venc_output_log_buffers(const char *buffer_addr, int buffer_len); + int venc_input_log_buffers(OMX_BUFFERHEADERTYPE *buffer, void* pmem_data_buf, int framelen); + int venc_extradata_log_buffers(char *buffer_addr); + bool venc_get_capability_ltrcount(OMX_U32 *, OMX_U32 *, OMX_U32 *); + OMX_U32 m_nDriver_fd; + bool m_profile_set; + bool m_level_set; + pthread_mutex_t loaded_start_stop_mlock; + pthread_cond_t loaded_start_stop_cond; + struct venc_debug_cap m_debug; + + struct recon_buffer { + unsigned char* virtual_address; + int pmem_fd; + int size; + int alignment; + int offset; +#ifdef USE_ION + int ion_device_fd; + struct ion_allocation_data alloc_data; + struct ion_fd_data ion_alloc_fd; +#endif + }; + + recon_buffer recon_buff[MAX_RECON_BUFFERS]; + int recon_buffers_count; + bool m_max_allowed_bitrate_check; + int m_eProfile; + int m_eLevel; + int etb_count; + private: + struct venc_basecfg m_sVenc_cfg; + struct venc_ratectrlcfg rate_ctrl; + struct venc_targetbitrate bitrate; + struct venc_intraperiod intra_period; + struct venc_profile codec_profile; + struct ven_profilelevel profile_level; + struct venc_switch set_param; + struct venc_voptimingcfg time_inc; + struct venc_allocatorproperty m_sInput_buff_property; + struct venc_allocatorproperty m_sOutput_buff_property; + struct venc_sessionqp session_qp; + struct venc_qprange qp_range; + struct venc_multiclicecfg multislice; + struct venc_entropycfg entropy; + struct venc_dbcfg dbkfilter; + struct venc_intrarefresh intra_refresh; + struct venc_headerextension hec; + struct venc_voptimingcfg voptimecfg; + struct venc_seqheader seqhdr; + struct venc_ltrmode ltrmode; + struct venc_ltrcount ltrcount; + struct venc_ltrperiod ltrperiod; + + bool venc_set_profile_level(OMX_U32 eProfile,OMX_U32 eLevel); + bool venc_set_intra_period(OMX_U32 nPFrames, OMX_U32 nBFrames); + bool venc_set_target_bitrate(OMX_U32 nTargetBitrate, OMX_U32 config); + bool venc_set_ratectrl_cfg(OMX_VIDEO_CONTROLRATETYPE eControlRate); + bool venc_set_qp_range(OMX_U32 min_qp, OMX_U32 max_qp); + bool venc_set_session_qp(OMX_U32 i_frame_qp, OMX_U32 p_frame_qp); + bool venc_set_extradata(OMX_U32 extra_data); + bool venc_set_encode_framerate(OMX_U32 encode_framerate, OMX_U32 config); + bool venc_set_intra_vop_refresh(OMX_BOOL intra_vop_refresh); + bool venc_set_color_format(OMX_COLOR_FORMATTYPE color_format); + bool venc_validate_profile_level(OMX_U32 *eProfile, OMX_U32 *eLevel); + bool venc_set_multislice_cfg(OMX_INDEXTYPE codec, OMX_U32 slicesize); + bool venc_set_entropy_config(OMX_BOOL enable, OMX_U32 i_cabac_level); + bool venc_set_inloop_filter(OMX_VIDEO_AVCLOOPFILTERTYPE loop_filter); + bool venc_set_intra_refresh (OMX_VIDEO_INTRAREFRESHTYPE intrarefresh, OMX_U32 nMBs); + bool venc_set_error_resilience(OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE* error_resilience); + bool venc_set_voptiming_cfg(OMX_U32 nTimeIncRes); + void venc_config_print(); + bool venc_set_slice_delivery_mode(OMX_BOOL enable); + bool venc_set_plusptype(OMX_BOOL enable); + bool venc_set_ltrmode(QOMX_VIDEO_LTRMODETYPE mode); + bool venc_set_ltrcount(OMX_U32 count); + bool venc_set_ltrperiod(OMX_U32 period); + bool venc_set_ltruse(OMX_U32 id, OMX_U32 frames); + bool venc_color_align(OMX_BUFFERHEADERTYPE *buffer, OMX_U32 width, OMX_U32 height); +#ifdef MAX_RES_1080P + OMX_U32 pmem_free(); + OMX_U32 pmem_allocate(OMX_U32 size, OMX_U32 alignment, OMX_U32 count); + OMX_U32 venc_allocate_recon_buffers(); + inline int clip2(int x) { + x = x -1; + x = x | x >> 1; + x = x | x >> 2; + x = x | x >> 4; + x = x | x >> 16; + x = x + 1; + return x; + } +#endif +}; + +#endif diff --git a/msm8998/mm-video-v4l2/vidc/venc/inc/video_encoder_device_v4l2.h b/msm8998/mm-video-v4l2/vidc/venc/inc/video_encoder_device_v4l2.h new file mode 100644 index 0000000..b13d613 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/inc/video_encoder_device_v4l2.h @@ -0,0 +1,657 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2012-2016, 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. +--------------------------------------------------------------------------*/ +#ifndef __OMX_VENC_DEV__ +#define __OMX_VENC_DEV__ + +#include "OMX_Types.h" +#include "OMX_Core.h" +#include "OMX_VideoExt.h" +#include "QComOMXMetadata.h" +#include "OMX_QCOMExtns.h" +#include "qc_omx_component.h" +#ifdef _VQZIP_ +#include "VQZip.h" +#endif + +#ifdef _PQ_ +#include "gpustats.h" +#endif +#include "omx_video_common.h" +#include "omx_video_base.h" +#include "omx_video_encoder.h" +#include <linux/videodev2.h> +#include <media/msm_vidc.h> +#include <poll.h> + +#define TIMEOUT 5*60*1000 +#define BIT(num) (1 << (num)) +#define MAX_HYB_HIERP_LAYERS 6 +#define MAX_AVC_HP_LAYERS (4) +#define MAX_V4L2_BUFS 64 //VB2_MAX_FRAME + +enum hier_type { + HIER_NONE = 0x0, + HIER_P = 0x1, + HIER_B = 0x2, + HIER_P_HYBRID = 0x3, +}; + +struct msm_venc_switch { + unsigned char status; +}; + +struct msm_venc_allocatorproperty { + unsigned long mincount; + unsigned long actualcount; + unsigned long datasize; + unsigned long suffixsize; + unsigned long alignment; + unsigned long bufpoolid; +}; + +struct msm_venc_basecfg { + unsigned long input_width; + unsigned long input_height; + unsigned long dvs_width; + unsigned long dvs_height; + unsigned long codectype; + unsigned long fps_num; + unsigned long fps_den; + unsigned long targetbitrate; + unsigned long inputformat; +}; + +struct msm_venc_profile { + unsigned long profile; +}; +struct msm_venc_profilelevel { + unsigned long level; +}; + +struct msm_venc_sessionqp { + unsigned long iframeqp; + unsigned long pframeqp; + unsigned long bframeqp; +}; + +struct msm_venc_initqp { + unsigned long iframeqp; + unsigned long pframeqp; + unsigned long bframeqp; + unsigned long enableinitqp; +}; + +struct msm_venc_qprange { + unsigned long maxqp; + unsigned long minqp; +}; + +struct msm_venc_ipb_qprange { + unsigned long max_i_qp; + unsigned long min_i_qp; + unsigned long max_p_qp; + unsigned long min_p_qp; + unsigned long max_b_qp; + unsigned long min_b_qp; +}; + +struct msm_venc_intraperiod { + unsigned long num_pframes; + unsigned long num_bframes; +}; +struct msm_venc_seqheader { + unsigned char *hdrbufptr; + unsigned long bufsize; + unsigned long hdrlen; +}; + +struct msm_venc_capability { + unsigned long codec_types; + unsigned long maxframe_width; + unsigned long maxframe_height; + unsigned long maxtarget_bitrate; + unsigned long maxframe_rate; + unsigned long input_formats; + unsigned char dvs; +}; + +struct msm_venc_entropycfg { + unsigned longentropysel; + unsigned long cabacmodel; +}; + +struct msm_venc_dbcfg { + unsigned long db_mode; + unsigned long slicealpha_offset; + unsigned long slicebeta_offset; +}; + +struct msm_venc_intrarefresh { + unsigned long irmode; + unsigned long mbcount; +}; + +struct msm_venc_multiclicecfg { + unsigned long mslice_mode; + unsigned long mslice_size; +}; + +struct msm_venc_bufferflush { + unsigned long flush_mode; +}; + +struct msm_venc_ratectrlcfg { + unsigned long rcmode; +}; + +struct msm_venc_voptimingcfg { + unsigned long voptime_resolution; +}; +struct msm_venc_framerate { + unsigned long fps_denominator; + unsigned long fps_numerator; +}; + +struct msm_venc_targetbitrate { + unsigned long target_bitrate; +}; + + +struct msm_venc_rotation { + unsigned long rotation; +}; + +struct msm_venc_timeout { + unsigned long millisec; +}; + +struct msm_venc_headerextension { + unsigned long header_extension; +}; + +struct msm_venc_video_capability { + unsigned int min_width; + unsigned int max_width; + unsigned int min_height; + unsigned int max_height; +}; + +struct msm_venc_idrperiod { + unsigned long idrperiod; +}; + +struct msm_venc_slice_delivery { + unsigned long enable; +}; + +struct msm_venc_hierlayers { + unsigned int numlayers; + enum hier_type hier_mode; +}; + +struct msm_venc_ltrinfo { + unsigned int enabled; + unsigned int count; +}; + +struct msm_venc_perf_level { + unsigned int perflevel; +}; + +struct msm_venc_vui_timing_info { + unsigned int enabled; +}; + +struct msm_venc_vqzip_sei_info { + unsigned int enabled; +}; + +struct msm_venc_peak_bitrate { + unsigned int peakbitrate; +}; + +struct msm_venc_vpx_error_resilience { + unsigned int enable; +}; + +struct msm_venc_priority { + OMX_U32 priority; +}; + +struct msm_venc_hybrid_hp { + unsigned int nSize; + unsigned int nKeyFrameInterval; + unsigned int nTemporalLayerBitrateRatio[OMX_VIDEO_MAX_HP_LAYERS]; + unsigned int nMinQuantizer; + unsigned int nMaxQuantizer; + unsigned int nHpLayers; +}; + +struct msm_venc_color_space { + OMX_U32 primaries; + OMX_U32 range; + OMX_U32 matrix_coeffs; + OMX_U32 transfer_chars; +}; + +struct msm_venc_temporal_layers { + enum hier_type hier_mode; + OMX_U32 nMaxLayers; + OMX_U32 nMaxBLayers; + OMX_U32 nPLayers; + OMX_U32 nBLayers; + OMX_BOOL bIsBitrateRatioValid; + // cumulative ratio: eg [25, 50, 75, 100] means [L0=25%, L1=25%, L2=25%, L3=25%] + OMX_U32 nTemporalLayerBitrateRatio[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS]; + // Layerwise ratio: eg [L0=25%, L1=25%, L2=25%, L3=25%] + OMX_U32 nTemporalLayerBitrateFraction[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS]; +}; + +enum v4l2_ports { + CAPTURE_PORT, + OUTPUT_PORT, + MAX_PORT +}; + +struct extradata_buffer_info { + unsigned long buffer_size; + char* uaddr; + int count; + int size; + OMX_BOOL allocated; + enum v4l2_ports port_index; +#ifdef USE_ION + struct venc_ion ion; + unsigned int m_ion_dev; +#endif + bool vqzip_sei_found; +}; + +struct statistics { + struct timeval prev_tv; + int prev_fbd; + int bytes_generated; +}; + +enum rc_modes { + RC_VBR_VFR = BIT(0), + RC_VBR_CFR = BIT(1), + RC_CBR_VFR = BIT(2), + RC_CBR_CFR = BIT(3), + RC_MBR_CFR = BIT(4), + RC_MBR_VFR = BIT(5), + RC_ALL = (RC_VBR_VFR | RC_VBR_CFR + | RC_CBR_VFR | RC_CBR_CFR | RC_MBR_CFR | RC_MBR_VFR) +}; + +class venc_dev +{ + public: + venc_dev(class omx_venc *venc_class); //constructor + ~venc_dev(); //des + + static void* async_venc_message_thread (void *); + bool venc_open(OMX_U32); + void venc_close(); + unsigned venc_stop(void); + unsigned venc_pause(void); + unsigned venc_start(void); + unsigned venc_flush(unsigned); +#ifdef _ANDROID_ICS_ + bool venc_set_meta_mode(bool); +#endif + unsigned venc_resume(void); + unsigned venc_start_done(void); + unsigned venc_stop_done(void); + unsigned venc_set_message_thread_id(pthread_t); + bool venc_use_buf(void*, unsigned,unsigned); + bool venc_free_buf(void*, unsigned); + bool venc_empty_buf(void *, void *,unsigned,unsigned); + bool venc_fill_buf(void *, void *,unsigned,unsigned); + + bool venc_get_buf_req(OMX_U32 *,OMX_U32 *, + OMX_U32 *,OMX_U32); + bool venc_set_buf_req(OMX_U32 *,OMX_U32 *, + OMX_U32 *,OMX_U32); + bool venc_set_param(void *,OMX_INDEXTYPE); + bool venc_set_config(void *configData, OMX_INDEXTYPE index); + bool venc_h264_transform_8x8(OMX_BOOL enable); + bool venc_get_profile_level(OMX_U32 *eProfile,OMX_U32 *eLevel); + bool venc_get_seq_hdr(void *, unsigned, unsigned *); + bool venc_loaded_start(void); + bool venc_loaded_stop(void); + bool venc_loaded_start_done(void); + bool venc_loaded_stop_done(void); + bool venc_is_video_session_supported(unsigned long width, unsigned long height); + bool venc_color_align(OMX_BUFFERHEADERTYPE *buffer, OMX_U32 width, + OMX_U32 height); + bool venc_get_performance_level(OMX_U32 *perflevel); + bool venc_get_vui_timing_info(OMX_U32 *enabled); + bool venc_get_vqzip_sei_info(OMX_U32 *enabled); + bool venc_get_peak_bitrate(OMX_U32 *peakbitrate); + bool venc_get_batch_size(OMX_U32 *size); + bool venc_get_temporal_layer_caps(OMX_U32 * /*nMaxLayers*/, + OMX_U32 * /*nMaxBLayers*/); + bool venc_get_output_log_flag(); + bool venc_check_valid_config(); + int venc_output_log_buffers(const char *buffer_addr, int buffer_len); + int venc_input_log_buffers(OMX_BUFFERHEADERTYPE *buffer, int fd, int plane_offset, + unsigned long inputformat); + int venc_extradata_log_buffers(char *buffer_addr); + bool venc_set_bitrate_type(OMX_U32 type); + +#ifdef _VQZIP_ + class venc_dev_vqzip + { + public: + venc_dev_vqzip(); + ~venc_dev_vqzip(); + bool init(); + void deinit(); + struct VQZipConfig pConfig; + int tempSEI[300]; + int fill_stats_data(void* pBuf, void *pStats); + typedef void (*vqzip_deinit_t)(void*); + typedef void* (*vqzip_init_t)(void); + typedef VQZipStatus (*vqzip_compute_stats_t)(void* const , const void * const , const VQZipConfig* ,VQZipStats*); + private: + pthread_mutex_t lock; + void *mLibHandle; + void *mVQZIPHandle; + vqzip_init_t mVQZIPInit; + vqzip_deinit_t mVQZIPDeInit; + vqzip_compute_stats_t mVQZIPComputeStats; + }; + venc_dev_vqzip vqzip; +#endif + +#ifdef _PQ_ + class venc_dev_pq + { + public: + venc_dev_pq(); + ~venc_dev_pq(); + bool is_pq_enabled; + bool is_pq_force_disable; + bool is_YUV_format_uncertain; + pthread_mutex_t lock; + struct extradata_buffer_info roi_extradata_info; + bool init(unsigned long); + void deinit(); + void get_caps(); + int configure(unsigned long width, unsigned long height); + bool is_pq_handle_valid(); + bool is_color_format_supported(unsigned long); + bool reinit(unsigned long); + struct gpu_stats_lib_input_config pConfig; + int fill_pq_stats(struct v4l2_buffer buf, unsigned int data_offset); + gpu_stats_lib_caps_t caps; + typedef gpu_stats_lib_op_status (*gpu_stats_lib_init_t)(void**, enum perf_hint gpu_hint, enum color_compression_format format); + typedef gpu_stats_lib_op_status (*gpu_stats_lib_deinit_t)(void*); + typedef gpu_stats_lib_op_status (*gpu_stats_lib_get_caps_t)(void* handle, gpu_stats_lib_caps_t *caps); + typedef gpu_stats_lib_op_status (*gpu_stats_lib_configure_t)(void* handle, gpu_stats_lib_input_config *input_t); + typedef gpu_stats_lib_op_status (*gpu_stats_lib_fill_data_t)(void *handle, gpu_stats_lib_buffer_params_t *yuv_input, + gpu_stats_lib_buffer_params_t *roi_input, + gpu_stats_lib_buffer_params_t *stats_output, void *addr, void *user_data); + private: + void *mLibHandle; + void *mPQHandle; + gpu_stats_lib_init_t mPQInit; + gpu_stats_lib_get_caps_t mPQGetCaps; + gpu_stats_lib_configure_t mPQConfigure; + gpu_stats_lib_deinit_t mPQDeInit; + gpu_stats_lib_fill_data_t mPQComputeStats; + unsigned long configured_format; + }; + venc_dev_pq m_pq; + bool venc_check_for_pq(void); + void venc_configure_pq(void); + void venc_try_enable_pq(void); +#endif + struct venc_debug_cap m_debug; + OMX_U32 m_nDriver_fd; + int m_poll_efd; + bool m_profile_set; + bool m_level_set; + int num_input_planes, num_output_planes; + int etb, ebd, ftb, fbd; + struct recon_buffer { + unsigned char* virtual_address; + int pmem_fd; + int size; + int alignment; + int offset; +#ifdef USE_ION + int ion_device_fd; + struct ion_allocation_data alloc_data; + struct ion_fd_data ion_alloc_fd; +#endif + }; + + int stopped; + int resume_in_stopped; + bool m_max_allowed_bitrate_check; + pthread_t m_tid; + bool async_thread_created; + bool async_thread_force_stop; + class omx_venc *venc_handle; + OMX_ERRORTYPE allocate_extradata(struct extradata_buffer_info *extradata_info, int flags); + void free_extradata_all(); + void free_extradata(struct extradata_buffer_info *extradata_info); + int append_mbi_extradata(void *, struct msm_vidc_extradata_header*); + bool handle_output_extradata(void *, int); + bool handle_input_extradata(struct v4l2_buffer); + int venc_set_format(int); + bool deinterlace_enabled; + bool hw_overload; + bool is_gralloc_source_ubwc; + bool is_camera_source_ubwc; + bool is_csc_enabled; + OMX_U32 fd_list[64]; + + private: + OMX_U32 m_codec; + struct msm_venc_basecfg m_sVenc_cfg; + struct msm_venc_ratectrlcfg rate_ctrl; + struct msm_venc_targetbitrate bitrate; + struct msm_venc_intraperiod intra_period; + struct msm_venc_profile codec_profile; + struct msm_venc_profilelevel profile_level; + struct msm_venc_switch set_param; + struct msm_venc_voptimingcfg time_inc; + struct msm_venc_allocatorproperty m_sInput_buff_property; + struct msm_venc_allocatorproperty m_sOutput_buff_property; + struct msm_venc_sessionqp session_qp; + struct msm_venc_initqp init_qp; + struct msm_venc_qprange session_qp_range; + struct msm_venc_qprange session_qp_values; + struct msm_venc_ipb_qprange session_ipb_qp_values; + struct msm_venc_multiclicecfg multislice; + struct msm_venc_entropycfg entropy; + struct msm_venc_dbcfg dbkfilter; + struct msm_venc_intrarefresh intra_refresh; + struct msm_venc_headerextension hec; + struct msm_venc_voptimingcfg voptimecfg; + struct msm_venc_video_capability capability; + struct msm_venc_idrperiod idrperiod; + struct msm_venc_slice_delivery slice_mode; + struct msm_venc_hierlayers hier_layers; + struct msm_venc_perf_level performance_level; + struct msm_venc_vui_timing_info vui_timing_info; + struct msm_venc_vqzip_sei_info vqzip_sei_info; + struct msm_venc_peak_bitrate peak_bitrate; + struct msm_venc_ltrinfo ltrinfo; + struct msm_venc_vpx_error_resilience vpx_err_resilience; + struct msm_venc_priority sess_priority; + OMX_U32 operating_rate; + int rc_off_level; + struct msm_venc_hybrid_hp hybrid_hp; + struct msm_venc_color_space color_space; + msm_venc_temporal_layers temporal_layers_config; + + bool venc_set_profile_level(OMX_U32 eProfile,OMX_U32 eLevel); + bool venc_set_intra_period(OMX_U32 nPFrames, OMX_U32 nBFrames); + bool venc_set_target_bitrate(OMX_U32 nTargetBitrate, OMX_U32 config); + bool venc_set_ratectrl_cfg(OMX_VIDEO_CONTROLRATETYPE eControlRate); + bool venc_set_session_qp(OMX_U32 i_frame_qp, OMX_U32 p_frame_qp,OMX_U32 b_frame_qp); + bool venc_set_session_qp_range(OMX_U32 min_qp, OMX_U32 max_qp); + bool venc_set_session_qp_range_packed(OMX_U32 min_qp, OMX_U32 max_qp); + bool venc_set_encode_framerate(OMX_U32 encode_framerate, OMX_U32 config); + bool venc_set_intra_vop_refresh(OMX_BOOL intra_vop_refresh); + bool venc_set_color_format(OMX_COLOR_FORMATTYPE color_format); + bool venc_validate_profile_level(OMX_U32 *eProfile, OMX_U32 *eLevel); + bool venc_set_multislice_cfg(OMX_INDEXTYPE codec, OMX_U32 slicesize); + bool venc_set_entropy_config(OMX_BOOL enable, OMX_U32 i_cabac_level); + bool venc_set_inloop_filter(OMX_VIDEO_AVCLOOPFILTERTYPE loop_filter); + bool venc_set_intra_refresh (OMX_VIDEO_INTRAREFRESHTYPE intrarefresh, OMX_U32 nMBs); + bool venc_set_error_resilience(OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE* error_resilience); + bool venc_set_voptiming_cfg(OMX_U32 nTimeIncRes); + void venc_config_print(); + bool venc_set_slice_delivery_mode(OMX_U32 enable); + bool venc_set_extradata(OMX_U32 extra_data, OMX_BOOL enable); + bool venc_set_idr_period(OMX_U32 nPFrames, OMX_U32 nIDRPeriod); + bool venc_reconfig_reqbufs(); + bool venc_set_vpe_rotation(OMX_S32 rotation_angle); + bool venc_set_deinterlace(OMX_U32 enable); + bool venc_set_ltrmode(OMX_U32 enable, OMX_U32 count); + bool venc_enable_initial_qp(QOMX_EXTNINDEX_VIDEO_INITIALQP* initqp); + bool venc_set_useltr(OMX_U32 frameIdx); + bool venc_set_markltr(OMX_U32 frameIdx); + bool venc_set_inband_video_header(OMX_BOOL enable); + bool venc_set_au_delimiter(OMX_BOOL enable); + bool venc_set_hier_layers(QOMX_VIDEO_HIERARCHICALCODINGTYPE type, OMX_U32 num_layers); + bool venc_set_perf_level(QOMX_VIDEO_PERF_LEVEL ePerfLevel); + bool venc_set_vui_timing_info(OMX_BOOL enable); + bool venc_set_peak_bitrate(OMX_U32 nPeakBitrate); + bool venc_set_searchrange(); + bool venc_set_vpx_error_resilience(OMX_BOOL enable); + bool venc_set_perf_mode(OMX_U32 mode); + bool venc_set_mbi_statistics_mode(OMX_U32 mode); + bool venc_set_vqzip_sei_type(OMX_BOOL enable); + bool venc_set_hybrid_hierp(QOMX_EXTNINDEX_VIDEO_HYBRID_HP_MODE* hhp); + bool venc_set_batch_size(OMX_U32 size); + bool venc_calibrate_gop(); + bool venc_set_vqzip_defaults(); + int venc_get_index_from_fd(OMX_U32 ion_fd, OMX_U32 buffer_fd); + bool venc_validate_hybridhp_params(OMX_U32 layers, OMX_U32 bFrames, OMX_U32 count, int mode); + bool venc_set_hierp_layers(OMX_U32 hierp_layers); + bool venc_set_baselayerid(OMX_U32 baseid); + bool venc_set_qp(OMX_U32 nQp); + bool venc_set_aspectratio(void *nSar); + bool venc_set_priority(OMX_U32 priority); + bool venc_set_session_priority(OMX_U32 priority); + bool venc_set_operatingrate(OMX_U32 rate); + bool venc_set_layer_bitrates(OMX_U32 *pLayerBitrates, OMX_U32 numLayers); + bool venc_set_lowlatency_mode(OMX_BOOL enable); + bool venc_set_low_latency(OMX_BOOL enable); + bool venc_set_roi_qp_info(OMX_QTI_VIDEO_CONFIG_ROIINFO *roiInfo); + bool venc_set_blur_resolution(OMX_QTI_VIDEO_CONFIG_BLURINFO *blurInfo); + bool venc_set_colorspace(OMX_U32 primaries, OMX_U32 range, OMX_U32 transfer_chars, OMX_U32 matrix_coeffs); + OMX_ERRORTYPE venc_set_temporal_layers(OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE *pTemporalParams); + OMX_ERRORTYPE venc_set_temporal_layers_internal(); + +#ifdef MAX_RES_1080P + OMX_U32 pmem_free(); + OMX_U32 pmem_allocate(OMX_U32 size, OMX_U32 alignment, OMX_U32 count); + OMX_U32 venc_allocate_recon_buffers(); + inline int clip2(int x) { + x = x -1; + x = x | x >> 1; + x = x | x >> 2; + x = x | x >> 4; + x = x | x >> 16; + x = x + 1; + return x; + } +#endif + int metadatamode; + bool streaming[MAX_PORT]; + bool extradata; + struct extradata_buffer_info input_extradata_info; + struct extradata_buffer_info output_extradata_info; + + pthread_mutex_t pause_resume_mlock; + pthread_cond_t pause_resume_cond; + bool paused; + int color_format; + bool is_searchrange_set; + bool enable_mv_narrow_searchrange; + int supported_rc_modes; + bool is_thulium_v1; + bool camera_mode_enabled; + OMX_BOOL low_latency_mode; + struct { + bool dirty; + OMX_QTI_VIDEO_CONFIG_ROIINFO info; + } roi; + + bool venc_empty_batch (OMX_BUFFERHEADERTYPE *buf, unsigned index); + static const int kMaxBuffersInBatch = 16; + unsigned int mBatchSize; + struct BatchInfo { + BatchInfo(); + /* register a buffer and obtain its unique id (v4l2-buf-id) + */ + int registerBuffer(int bufferId); + /* retrieve the buffer given its v4l2-buf-id + */ + int retrieveBufferAt(int v4l2Id); + bool isPending(int bufferId); + + private: + static const int kMaxBufs = 64; + static const int kBufIDFree = -1; + pthread_mutex_t mLock; + int mBufMap[64]; // Map with slots for each buffer + size_t mNumPending; + + }; + BatchInfo mBatchInfo; +}; + +enum instance_state { + MSM_VIDC_CORE_UNINIT_DONE = 0x0001, + MSM_VIDC_CORE_INIT, + MSM_VIDC_CORE_INIT_DONE, + MSM_VIDC_OPEN, + MSM_VIDC_OPEN_DONE, + MSM_VIDC_LOAD_RESOURCES, + MSM_VIDC_LOAD_RESOURCES_DONE, + MSM_VIDC_START, + MSM_VIDC_START_DONE, + MSM_VIDC_STOP, + MSM_VIDC_STOP_DONE, + MSM_VIDC_RELEASE_RESOURCES, + MSM_VIDC_RELEASE_RESOURCES_DONE, + MSM_VIDC_CLOSE, + MSM_VIDC_CLOSE_DONE, + MSM_VIDC_CORE_UNINIT, +}; +#endif + diff --git a/msm8998/mm-video-v4l2/vidc/venc/inc/video_encoder_test.h b/msm8998/mm-video-v4l2/vidc/venc/inc/video_encoder_test.h new file mode 100644 index 0000000..217611a --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/inc/video_encoder_test.h @@ -0,0 +1,75 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2011, 2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#include <stdio.h> +#include <stdlib.h> +#include "queue.h" +#include<fcntl.h> +#include<sys/ioctl.h> +#include <sys/mman.h> +#include <linux/msm_vidc_enc.h> +#include<pthread.h> +#include <semaphore.h> +#include <stdio.h> + +#define INPUT_BUFFER 0 +#define OUTPUT_BUFFER 1 + +struct video_encoder_context { + unsigned long input_width; + unsigned long input_height; + unsigned long codectype; + unsigned long fps_num; + unsigned long fps_den; + unsigned long targetbitrate; + unsigned long inputformat; + + struct venc_allocatorproperty input_buffer; + struct venc_allocatorproperty output_buffer; + struct venc_bufferpayload **ptr_inputbuffer; + struct venc_bufferpayload **ptr_outputbuffer; + struct video_queue_context queue_context; + int video_driver_fd; + + FILE * inputBufferFile; + FILE * outputBufferFile; + + pthread_t videothread_id; + pthread_t asyncthread_id; + sem_t sem_synchronize; +}; + +int init_encoder ( struct video_encoder_context *init_decode ); +int allocate_buffer ( unsigned int buffer_dir, + struct video_encoder_context *decode_context + ); +int free_buffer ( unsigned int buffer_dir, + struct video_encoder_context *decode_context + ); +int start_encoding (struct video_encoder_context *decode_context); +int stop_encoding (struct video_encoder_context *decode_context); +int deinit_encoder (struct video_encoder_context *init_decode); diff --git a/msm8998/mm-video-v4l2/vidc/venc/src/omx_swvenc_hevc.cpp b/msm8998/mm-video-v4l2/vidc/venc/src/omx_swvenc_hevc.cpp new file mode 100644 index 0000000..0bc2e32 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/src/omx_swvenc_hevc.cpp @@ -0,0 +1,1554 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#include "omx_swvenc_hevc.h" +#include <string.h> +#include <stdio.h> +#include <media/hardware/HardwareAPI.h> +#include <gralloc_priv.h> +#include <media/msm_media_info.h> + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ + +#define OMX_SPEC_VERSION 0x00000101 +#define OMX_INIT_STRUCT(_s_, _name_) \ + memset((_s_), 0x0, sizeof(_name_)); \ +(_s_)->nSize = sizeof(_name_); \ +(_s_)->nVersion.nVersion = OMX_SPEC_VERSION + +extern int m_pipe; + +// factory function executed by the core to create instances +void *get_omx_component_factory_fn(void) +{ + return(new omx_swvenc); +} + +//constructor + +omx_swvenc::omx_swvenc() +{ +#ifdef _ANDROID_ICS_ + meta_mode_enable = false; + memset(meta_buffer_hdr,0,sizeof(meta_buffer_hdr)); + memset(meta_buffers,0,sizeof(meta_buffers)); + memset(opaque_buffer_hdr,0,sizeof(opaque_buffer_hdr)); + mUseProxyColorFormat = false; + get_syntaxhdr_enable = false; +#endif + char property_value[PROPERTY_VALUE_MAX] = {0}; + property_get("vidc.debug.level", property_value, "0"); + debug_level = atoi(property_value); + property_value[0] = '\0'; + m_pSwVenc = NULL; +} + +omx_swvenc::~omx_swvenc() +{ + get_syntaxhdr_enable = false; + //nothing to do +} + +/* ====================================================================== + FUNCTION + omx_swvenc::ComponentInit + + DESCRIPTION + Initialize the component. + + PARAMETERS + ctxt -- Context information related to the self. + id -- Event identifier. This could be any of the following: + 1. Command completion event + 2. Buffer done callback event + 3. Frame done callback event + + RETURN VALUE + None. + + ========================================================================== */ +OMX_ERRORTYPE omx_swvenc::component_init(OMX_STRING role) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + int fds[2]; + int r; + + OMX_VIDEO_CODINGTYPE codec_type; + + DEBUG_PRINT_HIGH("omx_swvenc(): Inside component_init()"); + // Copy the role information which provides the decoder m_nkind + strlcpy((char *)m_nkind,role,OMX_MAX_STRINGNAME_SIZE); + secure_session = false; + + if (!strncmp((char *)m_nkind,"OMX.qti.video.encoder.hevc",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_encoder.hevc",\ + OMX_MAX_STRINGNAME_SIZE); + codec_type = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc; + } + else { + DEBUG_PRINT_ERROR("ERROR: Unknown Component"); + eRet = OMX_ErrorInvalidComponentName; + } + + + if (eRet != OMX_ErrorNone) { + return eRet; + } +#ifdef ENABLE_GET_SYNTAX_HDR + get_syntaxhdr_enable = true; + DEBUG_PRINT_HIGH("Get syntax header enabled"); +#endif + + OMX_INIT_STRUCT(&m_sParamHEVC, OMX_VIDEO_PARAM_HEVCTYPE); + m_sParamHEVC.eProfile = OMX_VIDEO_HEVCProfileMain; + m_sParamHEVC.eLevel = OMX_VIDEO_HEVCMainTierLevel3; + + // Init for SWCodec + DEBUG_PRINT_HIGH("\n:Initializing SwVenc"); + SWVENC_INITPARAMS swVencParameter; + memset(&swVencParameter, 0, sizeof(SWVENC_INITPARAMS)); + swVencParameter.sDimensions.nWidth = 176; + swVencParameter.sDimensions.nHeight = 144; + swVencParameter.uProfile.eHevcProfile = SWVENC_HEVC_MAIN_PROFILE; + //sSwVencParameter.nNumWorkerThreads = 3; + + m_callBackInfo.FillBufferDone = swvenc_fill_buffer_done_cb; + m_callBackInfo.EmptyBufferDone = swvenc_input_buffer_done_cb; + m_callBackInfo.HandleEvent = swvenc_handle_event_cb; + m_callBackInfo.pClientHandle = this; + SWVENC_STATUS sRet = SwVenc_Init(&swVencParameter, &m_callBackInfo, &m_pSwVenc); + if (sRet != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("ERROR: SwVenc_Init failed"); + return OMX_ErrorInsufficientResources; + } + + + //Intialise the OMX layer variables + memset(&m_pCallbacks,0,sizeof(OMX_CALLBACKTYPE)); + + OMX_INIT_STRUCT(&m_sPortParam, OMX_PORT_PARAM_TYPE); + m_sPortParam.nPorts = 0x2; + m_sPortParam.nStartPortNumber = (OMX_U32) PORT_INDEX_IN; + + OMX_INIT_STRUCT(&m_sPortParam_audio, OMX_PORT_PARAM_TYPE); + m_sPortParam_audio.nPorts = 0; + m_sPortParam_audio.nStartPortNumber = 0; + + OMX_INIT_STRUCT(&m_sPortParam_img, OMX_PORT_PARAM_TYPE); + m_sPortParam_img.nPorts = 0; + m_sPortParam_img.nStartPortNumber = 0; + + OMX_INIT_STRUCT(&m_sParamBitrate, OMX_VIDEO_PARAM_BITRATETYPE); + m_sParamBitrate.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamBitrate.eControlRate = OMX_Video_ControlRateVariableSkipFrames; + m_sParamBitrate.nTargetBitrate = 64000; + + OMX_INIT_STRUCT(&m_sConfigBitrate, OMX_VIDEO_CONFIG_BITRATETYPE); + m_sConfigBitrate.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigBitrate.nEncodeBitrate = 64000; + + OMX_INIT_STRUCT(&m_sConfigFramerate, OMX_CONFIG_FRAMERATETYPE); + m_sConfigFramerate.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigFramerate.xEncodeFramerate = 30 << 16; + + OMX_INIT_STRUCT(&m_sConfigIntraRefreshVOP, OMX_CONFIG_INTRAREFRESHVOPTYPE); + m_sConfigIntraRefreshVOP.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigIntraRefreshVOP.IntraRefreshVOP = OMX_FALSE; + + OMX_INIT_STRUCT(&m_sConfigFrameRotation, OMX_CONFIG_ROTATIONTYPE); + m_sConfigFrameRotation.nPortIndex = (OMX_U32) PORT_INDEX_IN; + m_sConfigFrameRotation.nRotation = 0; + + OMX_INIT_STRUCT(&m_sSessionQuantization, OMX_VIDEO_PARAM_QUANTIZATIONTYPE); + m_sSessionQuantization.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sSessionQuantization.nQpI = 9; + m_sSessionQuantization.nQpP = 6; + m_sSessionQuantization.nQpB = 2; + + OMX_INIT_STRUCT(&m_sSessionQPRange, OMX_QCOM_VIDEO_PARAM_QPRANGETYPE); + m_sSessionQPRange.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sSessionQPRange.minQP = 2; + if (codec_type == OMX_VIDEO_CodingAVC) + m_sSessionQPRange.maxQP = 51; + else + m_sSessionQPRange.maxQP = 31; + + OMX_INIT_STRUCT(&m_sAVCSliceFMO, OMX_VIDEO_PARAM_AVCSLICEFMO); + m_sAVCSliceFMO.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sAVCSliceFMO.eSliceMode = OMX_VIDEO_SLICEMODE_AVCDefault; + m_sAVCSliceFMO.nNumSliceGroups = 0; + m_sAVCSliceFMO.nSliceGroupMapType = 0; + OMX_INIT_STRUCT(&m_sParamProfileLevel, OMX_VIDEO_PARAM_PROFILELEVELTYPE); + m_sParamProfileLevel.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + + OMX_INIT_STRUCT(&m_sIntraperiod, QOMX_VIDEO_INTRAPERIODTYPE); + m_sIntraperiod.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sIntraperiod.nPFrames = (m_sConfigFramerate.xEncodeFramerate * 2) - 1; + + OMX_INIT_STRUCT(&m_sErrorCorrection, OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE); + m_sErrorCorrection.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sErrorCorrection.bEnableDataPartitioning = OMX_FALSE; + m_sErrorCorrection.bEnableHEC = OMX_FALSE; + m_sErrorCorrection.bEnableResync = OMX_FALSE; + m_sErrorCorrection.bEnableRVLC = OMX_FALSE; + m_sErrorCorrection.nResynchMarkerSpacing = 0; + + OMX_INIT_STRUCT(&m_sIntraRefresh, OMX_VIDEO_PARAM_INTRAREFRESHTYPE); + m_sIntraRefresh.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sIntraRefresh.eRefreshMode = OMX_VIDEO_IntraRefreshMax; + + // Initialize the video parameters for input port + OMX_INIT_STRUCT(&m_sInPortDef, OMX_PARAM_PORTDEFINITIONTYPE); + m_sInPortDef.nPortIndex= (OMX_U32) PORT_INDEX_IN; + m_sInPortDef.bEnabled = OMX_TRUE; + m_sInPortDef.bPopulated = OMX_FALSE; + m_sInPortDef.eDomain = OMX_PortDomainVideo; + m_sInPortDef.eDir = OMX_DirInput; + m_sInPortDef.format.video.cMIMEType = (char *)"YUV420"; + m_sInPortDef.format.video.nFrameWidth = OMX_CORE_QCIF_WIDTH; + m_sInPortDef.format.video.nFrameHeight = OMX_CORE_QCIF_HEIGHT; + m_sInPortDef.format.video.nStride = OMX_CORE_QCIF_WIDTH; + m_sInPortDef.format.video.nSliceHeight = OMX_CORE_QCIF_HEIGHT; + m_sInPortDef.format.video.nBitrate = 64000; + m_sInPortDef.format.video.xFramerate = 15 << 16; + m_sInPortDef.format.video.eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + m_sInPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; + + if (dev_get_buf_req(&m_sInPortDef.nBufferCountMin, + &m_sInPortDef.nBufferCountActual, + &m_sInPortDef.nBufferSize, + m_sInPortDef.nPortIndex) != true) { + eRet = OMX_ErrorUndefined; + } + + // Initialize the video parameters for output port + OMX_INIT_STRUCT(&m_sOutPortDef, OMX_PARAM_PORTDEFINITIONTYPE); + m_sOutPortDef.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sOutPortDef.bEnabled = OMX_TRUE; + m_sOutPortDef.bPopulated = OMX_FALSE; + m_sOutPortDef.eDomain = OMX_PortDomainVideo; + m_sOutPortDef.eDir = OMX_DirOutput; + m_sOutPortDef.format.video.nFrameWidth = OMX_CORE_QCIF_WIDTH; + m_sOutPortDef.format.video.nFrameHeight = OMX_CORE_QCIF_HEIGHT; + m_sOutPortDef.format.video.nBitrate = 64000; + m_sOutPortDef.format.video.xFramerate = 15 << 16; + m_sOutPortDef.format.video.eColorFormat = OMX_COLOR_FormatUnused; + if (codec_type == (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc) { + m_sOutPortDef.format.video.eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc; + } + if (dev_get_buf_req(&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + m_sOutPortDef.nPortIndex) != true) { + eRet = OMX_ErrorUndefined; + } + + // Initialize the video color format for input port + OMX_INIT_STRUCT(&m_sInPortFormat, OMX_VIDEO_PARAM_PORTFORMATTYPE); + m_sInPortFormat.nPortIndex = (OMX_U32) PORT_INDEX_IN; + m_sInPortFormat.nIndex = 0; + m_sInPortFormat.eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + m_sInPortFormat.eCompressionFormat = OMX_VIDEO_CodingUnused; + + + // Initialize the compression format for output port + OMX_INIT_STRUCT(&m_sOutPortFormat, OMX_VIDEO_PARAM_PORTFORMATTYPE); + m_sOutPortFormat.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sOutPortFormat.nIndex = 0; + m_sOutPortFormat.eColorFormat = OMX_COLOR_FormatUnused; + if (codec_type == (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc) { + m_sOutPortFormat.eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc; + }; + + + // mandatory Indices for kronos test suite + OMX_INIT_STRUCT(&m_sPriorityMgmt, OMX_PRIORITYMGMTTYPE); + + OMX_INIT_STRUCT(&m_sInBufSupplier, OMX_PARAM_BUFFERSUPPLIERTYPE); + m_sInBufSupplier.nPortIndex = (OMX_U32) PORT_INDEX_IN; + + OMX_INIT_STRUCT(&m_sOutBufSupplier, OMX_PARAM_BUFFERSUPPLIERTYPE); + m_sOutBufSupplier.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + + + OMX_INIT_STRUCT(&m_sParamLTRMode, QOMX_VIDEO_PARAM_LTRMODE_TYPE); + m_sParamLTRMode.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamLTRMode.eLTRMode = QOMX_VIDEO_LTRMode_Disable; + + OMX_INIT_STRUCT(&m_sParamLTRCount, QOMX_VIDEO_PARAM_LTRCOUNT_TYPE); + m_sParamLTRCount.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamLTRCount.nCount = 0; + + OMX_INIT_STRUCT(&m_sConfigDeinterlace, OMX_VIDEO_CONFIG_DEINTERLACE); + m_sConfigDeinterlace.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigDeinterlace.nEnable = OMX_FALSE; + + OMX_INIT_STRUCT(&m_sHierLayers, QOMX_VIDEO_HIERARCHICALLAYERS); + m_sHierLayers.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sHierLayers.nNumLayers = 0; + m_sHierLayers.eHierarchicalCodingType = QOMX_HIERARCHICALCODING_P; + + m_state = OMX_StateLoaded; + m_sExtraData = 0; + + if (eRet == OMX_ErrorNone) { + if (pipe(fds)) { + DEBUG_PRINT_ERROR("ERROR: pipe creation failed"); + eRet = OMX_ErrorInsufficientResources; + } else { + if (fds[0] == 0 || fds[1] == 0) { + if (pipe(fds)) { + DEBUG_PRINT_ERROR("ERROR: pipe creation failed"); + eRet = OMX_ErrorInsufficientResources; + } + } + if (eRet == OMX_ErrorNone) { + m_pipe_in = fds[0]; + m_pipe_out = fds[1]; + } + } + msg_thread_created = true; + r = pthread_create(&msg_thread_id,0, message_thread_enc, this); + if (r < 0) { + eRet = OMX_ErrorInsufficientResources; + msg_thread_created = false; + } + } + + DEBUG_PRINT_HIGH("Component_init return value = 0x%x", eRet); + return eRet; +} + + +/* ====================================================================== + FUNCTION + omx_swvenc::Setparameter + + DESCRIPTION + OMX Set Parameter method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_swvenc::set_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_IN OMX_PTR paramData) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: Set Param in Invalid State"); + return OMX_ErrorInvalidState; + } + if (paramData == NULL) { + DEBUG_PRINT_ERROR("ERROR: Get Param in Invalid paramData"); + return OMX_ErrorBadParameter; + } + + /*set_parameter can be called in loaded state + or disabled port */ + if (m_state == OMX_StateLoaded + || m_sInPortDef.bEnabled == OMX_FALSE + || m_sOutPortDef.bEnabled == OMX_FALSE) { + DEBUG_PRINT_LOW("Set Parameter called in valid state"); + } else { + DEBUG_PRINT_ERROR("ERROR: Set Parameter called in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + + switch ((int)paramIndex) { + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition H= %d, W = %d", + (int)portDefn->format.video.nFrameHeight, + (int)portDefn->format.video.nFrameWidth); + + SWVENC_PROP prop; + prop.ePropId = SWVENC_PROP_ID_DIMENSIONS; + prop.uProperty.sDimensions.nWidth = portDefn->format.video.nFrameWidth; + prop.uProperty.sDimensions.nHeight= portDefn->format.video.nFrameHeight; + SWVENC_STATUS status = SwVenc_SetProperty(m_pSwVenc,&prop); + if (status != SWVENC_S_SUCCESS) { + DEBUG_PRINT_ERROR("ERROR: (In_PORT) dimension not supported %d x %d", + portDefn->format.video.nFrameWidth, portDefn->format.video.nFrameHeight); + return OMX_ErrorUnsupportedSetting; + } + + if (PORT_INDEX_IN == portDefn->nPortIndex) { + if (!dev_is_video_session_supported(portDefn->format.video.nFrameWidth, + portDefn->format.video.nFrameHeight)) { + DEBUG_PRINT_ERROR("video session not supported"); + omx_report_unsupported_setting(); + return OMX_ErrorUnsupportedSetting; + } + DEBUG_PRINT_LOW("i/p actual cnt requested = %u", portDefn->nBufferCountActual); + DEBUG_PRINT_LOW("i/p min cnt requested = %u", portDefn->nBufferCountMin); + DEBUG_PRINT_LOW("i/p buffersize requested = %u", portDefn->nBufferSize); + if (portDefn->nBufferCountMin > portDefn->nBufferCountActual) { + DEBUG_PRINT_ERROR("ERROR: (In_PORT) Min buffers (%u) > actual count (%u)", + portDefn->nBufferCountMin, portDefn->nBufferCountActual); + return OMX_ErrorUnsupportedSetting; + } + + DEBUG_PRINT_LOW("i/p previous actual cnt = %u", m_sInPortDef.nBufferCountActual); + DEBUG_PRINT_LOW("i/p previous min cnt = %u", m_sInPortDef.nBufferCountMin); + memcpy(&m_sInPortDef, portDefn,sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); + DEBUG_PRINT_LOW("i/p COLOR FORMAT = %u", portDefn->format.video.eColorFormat); +#ifdef _ANDROID_ICS_ + if (portDefn->format.video.eColorFormat == + (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FormatAndroidOpaque) { + m_sInPortDef.format.video.eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + if (!mUseProxyColorFormat) { + if (!c2d_conv.init()) { + DEBUG_PRINT_ERROR("C2D init failed"); + return OMX_ErrorUnsupportedSetting; + } + DEBUG_PRINT_LOW("C2D init is successful"); + } + mUseProxyColorFormat = true; + m_input_msg_id = OMX_COMPONENT_GENERATE_ETB_OPQ; + } else + mUseProxyColorFormat = false; +#endif + /*Query Input Buffer Requirements*/ + dev_get_buf_req (&m_sInPortDef.nBufferCountMin, + &m_sInPortDef.nBufferCountActual, + &m_sInPortDef.nBufferSize, + m_sInPortDef.nPortIndex); + + /*Query ouput Buffer Requirements*/ + dev_get_buf_req (&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + m_sOutPortDef.nPortIndex); + m_sInPortDef.nBufferCountActual = portDefn->nBufferCountActual; + } else if (PORT_INDEX_OUT == portDefn->nPortIndex) { + DEBUG_PRINT_LOW("o/p actual cnt requested = %u", portDefn->nBufferCountActual); + DEBUG_PRINT_LOW("o/p min cnt requested = %u", portDefn->nBufferCountMin); + DEBUG_PRINT_LOW("o/p buffersize requested = %u", portDefn->nBufferSize); + if (portDefn->nBufferCountMin > portDefn->nBufferCountActual) { + DEBUG_PRINT_ERROR("ERROR: (Out_PORT) Min buffers (%u) > actual count (%u)", + portDefn->nBufferCountMin, portDefn->nBufferCountActual); + return OMX_ErrorUnsupportedSetting; + } + + /*Query ouput Buffer Requirements*/ + dev_get_buf_req(&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + m_sOutPortDef.nPortIndex); + + memcpy(&m_sOutPortDef,portDefn,sizeof(struct OMX_PARAM_PORTDEFINITIONTYPE)); + update_profile_level(); //framerate , bitrate + + DEBUG_PRINT_LOW("o/p previous actual cnt = %u", m_sOutPortDef.nBufferCountActual); + DEBUG_PRINT_LOW("o/p previous min cnt = %u", m_sOutPortDef.nBufferCountMin); + m_sOutPortDef.nBufferCountActual = portDefn->nBufferCountActual; + } else { + DEBUG_PRINT_ERROR("ERROR: Set_parameter: Bad Port idx %d", + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + m_sConfigFramerate.xEncodeFramerate = portDefn->format.video.xFramerate; + m_sConfigBitrate.nEncodeBitrate = portDefn->format.video.nBitrate; + m_sParamBitrate.nTargetBitrate = portDefn->format.video.nBitrate; + } + break; + + case OMX_IndexParamVideoPortFormat: + { + OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoPortFormat %d", + portFmt->eColorFormat); + //set the driver with the corresponding values + if (PORT_INDEX_IN == portFmt->nPortIndex) { + + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoPortFormat %d", + portFmt->eColorFormat); + + SWVENC_PROP prop; + prop.uProperty.nFrameRate = portFmt->xFramerate; + prop.ePropId = SWVENC_PROP_ID_FRAMERATE; + SwVenc_SetProperty(m_pSwVenc, &prop); + + update_profile_level(); //framerate + +#ifdef _ANDROID_ICS_ + if (portFmt->eColorFormat == + (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FormatAndroidOpaque) { + m_sInPortFormat.eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + if (!mUseProxyColorFormat) { + if (!c2d_conv.init()) { + DEBUG_PRINT_ERROR("C2D init failed"); + return OMX_ErrorUnsupportedSetting; + } + DEBUG_PRINT_LOW("C2D init is successful"); + } + mUseProxyColorFormat = true; + m_input_msg_id = OMX_COMPONENT_GENERATE_ETB_OPQ; + } else +#endif + { + m_sInPortFormat.eColorFormat = portFmt->eColorFormat; + m_input_msg_id = OMX_COMPONENT_GENERATE_ETB; + mUseProxyColorFormat = false; + } + m_sInPortFormat.xFramerate = portFmt->xFramerate; + } + //TODO if no use case for O/P port,delet m_sOutPortFormat + } + break; + case OMX_IndexParamVideoInit: + { //TODO, do we need this index set param + OMX_PORT_PARAM_TYPE* pParam = (OMX_PORT_PARAM_TYPE*)(paramData); + DEBUG_PRINT_LOW("Set OMX_IndexParamVideoInit called"); + break; + } + + case OMX_IndexParamVideoBitrate: + { + OMX_VIDEO_PARAM_BITRATETYPE* pParam = (OMX_VIDEO_PARAM_BITRATETYPE*)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoBitrate"); + + SWVENC_PROP prop; + prop.uProperty.nFrameRate = pParam->nTargetBitrate; + prop.ePropId = SWVENC_PROP_ID_BITRATE; + SwVenc_SetProperty(m_pSwVenc, &prop); + + prop.uProperty.nRcOn = pParam->eControlRate; + prop.ePropId = SWVENC_PROP_ID_RC_ON; + SwVenc_SetProperty(m_pSwVenc, &prop); + + m_sParamBitrate.nTargetBitrate = pParam->nTargetBitrate; + m_sParamBitrate.eControlRate = pParam->eControlRate; + update_profile_level(); //bitrate + m_sConfigBitrate.nEncodeBitrate = pParam->nTargetBitrate; + m_sInPortDef.format.video.nBitrate = pParam->nTargetBitrate; + m_sOutPortDef.format.video.nBitrate = pParam->nTargetBitrate; + DEBUG_PRINT_LOW("bitrate = %u", m_sOutPortDef.format.video.nBitrate); + break; + } + case OMX_IndexParamVideoMpeg4: + case OMX_IndexParamVideoH263: + case OMX_IndexParamVideoAvc: + case (OMX_INDEXTYPE)OMX_IndexParamVideoVp8: + return OMX_ErrorUnsupportedSetting; + case (OMX_INDEXTYPE)OMX_IndexParamVideoHevc: + { + OMX_VIDEO_PARAM_HEVCTYPE* pParam = (OMX_VIDEO_PARAM_HEVCTYPE*)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoHevc"); + if (pParam->eProfile != OMX_VIDEO_HEVCProfileMain || + (pParam->eLevel != OMX_VIDEO_HEVCMainTierLevel1 && + pParam->eLevel != OMX_VIDEO_HEVCMainTierLevel2 && + pParam->eLevel != OMX_VIDEO_HEVCMainTierLevel21 && + pParam->eLevel != OMX_VIDEO_HEVCMainTierLevel3)) + { + return OMX_ErrorBadParameter; + } + m_sParamHEVC.eProfile = OMX_VIDEO_HEVCProfileMain; + m_sParamHEVC.eLevel = pParam->eLevel; + break; + } + case OMX_IndexParamVideoProfileLevelCurrent: + { + OMX_VIDEO_PARAM_PROFILELEVELTYPE* pParam = (OMX_VIDEO_PARAM_PROFILELEVELTYPE*)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoProfileLevelCurrent"); + + m_sParamProfileLevel.eProfile = pParam->eProfile; + m_sParamProfileLevel.eLevel = pParam->eLevel; + + if (!strncmp((char *)m_nkind, "OMX.qti.video.encoder.hevc",\ + OMX_MAX_STRINGNAME_SIZE)) { + + // DEBUG_PRINT_LOW("HEVC profile = %d, level = %d"); + } + break; + } + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *comp_role; + comp_role = (OMX_PARAM_COMPONENTROLETYPE *) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamStandardComponentRole %s", + comp_role->cRole); + + if ((m_state == OMX_StateLoaded)&& + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) { + DEBUG_PRINT_LOW("Set Parameter called in valid state"); + } else { + DEBUG_PRINT_ERROR("Set Parameter called in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + + if (!strncmp((char*)m_nkind, "OMX.qti.video.encoder.hevc",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((char*)comp_role->cRole,"video_encoder.hevc",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_encoder.hevc",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } + else { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown param %s", m_nkind); + eRet = OMX_ErrorInvalidComponentName; + } + break; + } + + case OMX_IndexParamPriorityMgmt: + { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPriorityMgmt"); + if (m_state != OMX_StateLoaded) { + DEBUG_PRINT_ERROR("ERROR: Set Parameter called in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + OMX_PRIORITYMGMTTYPE *priorityMgmtype = (OMX_PRIORITYMGMTTYPE*) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPriorityMgmt %u", + priorityMgmtype->nGroupID); + + DEBUG_PRINT_LOW("set_parameter: priorityMgmtype %u", + priorityMgmtype->nGroupPriority); + + m_sPriorityMgmt.nGroupID = priorityMgmtype->nGroupID; + m_sPriorityMgmt.nGroupPriority = priorityMgmtype->nGroupPriority; + + break; + } + + case OMX_IndexParamCompBufferSupplier: + { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamCompBufferSupplier"); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamCompBufferSupplier %d", + bufferSupplierType->eBufferSupplier); + if (bufferSupplierType->nPortIndex == 0 || bufferSupplierType->nPortIndex ==1) + m_sInBufSupplier.eBufferSupplier = bufferSupplierType->eBufferSupplier; + + else + + eRet = OMX_ErrorBadPortIndex; + + break; + + } + case OMX_IndexParamVideoQuantization: + { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoQuantization"); + OMX_VIDEO_PARAM_QUANTIZATIONTYPE *session_qp = (OMX_VIDEO_PARAM_QUANTIZATIONTYPE*) paramData; + if (session_qp->nPortIndex == PORT_INDEX_OUT) { + SWVENC_PROP prop; + prop.uProperty.nQp = session_qp->nQpI; + prop.ePropId = SWVENC_PROP_ID_QP; + SwVenc_SetProperty(m_pSwVenc, &prop); + + m_sSessionQuantization.nQpI = session_qp->nQpI; + m_sSessionQuantization.nQpP = session_qp->nQpP; + } else { + DEBUG_PRINT_ERROR("ERROR: Unsupported port Index for Session QP setting"); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_QcomIndexParamVideoQPRange: + { + DEBUG_PRINT_LOW("set_parameter: OMX_QcomIndexParamVideoQPRange"); + OMX_QCOM_VIDEO_PARAM_QPRANGETYPE *qp_range = (OMX_QCOM_VIDEO_PARAM_QPRANGETYPE*) paramData; + if (qp_range->nPortIndex == PORT_INDEX_OUT) { + m_sSessionQPRange.minQP= qp_range->minQP; + m_sSessionQPRange.maxQP= qp_range->maxQP; + } else { + DEBUG_PRINT_ERROR("ERROR: Unsupported port Index for QP range setting"); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_QcomIndexPortDefn: + { + OMX_QCOM_PARAM_PORTDEFINITIONTYPE* pParam = + (OMX_QCOM_PARAM_PORTDEFINITIONTYPE*)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_QcomIndexPortDefn"); + if (pParam->nPortIndex == (OMX_U32)PORT_INDEX_IN) { + if (pParam->nMemRegion > OMX_QCOM_MemRegionInvalid && + pParam->nMemRegion < OMX_QCOM_MemRegionMax) { + m_use_input_pmem = OMX_TRUE; + } else { + m_use_input_pmem = OMX_FALSE; + } + } else if (pParam->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { + if (pParam->nMemRegion > OMX_QCOM_MemRegionInvalid && + pParam->nMemRegion < OMX_QCOM_MemRegionMax) { + m_use_output_pmem = OMX_TRUE; + } else { + m_use_output_pmem = OMX_FALSE; + } + } else { + DEBUG_PRINT_ERROR("ERROR: SetParameter called on unsupported Port Index for QcomPortDefn"); + return OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_IndexParamVideoErrorCorrection: + { + DEBUG_PRINT_LOW("OMX_IndexParamVideoErrorCorrection"); + OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE* pParam = + (OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE*)paramData; + memcpy(&m_sErrorCorrection,pParam, sizeof(m_sErrorCorrection)); + break; + } + case OMX_IndexParamVideoIntraRefresh: + { + DEBUG_PRINT_LOW("set_param:OMX_IndexParamVideoIntraRefresh"); + OMX_VIDEO_PARAM_INTRAREFRESHTYPE* pParam = + (OMX_VIDEO_PARAM_INTRAREFRESHTYPE*)paramData; + + memcpy(&m_sIntraRefresh, pParam, sizeof(m_sIntraRefresh)); + break; + } + + case OMX_QcomIndexParamVideoMetaBufferMode: + { + StoreMetaDataInBuffersParams *pParam = + (StoreMetaDataInBuffersParams*)paramData; + DEBUG_PRINT_HIGH("set_parameter:OMX_QcomIndexParamVideoMetaBufferMode: " + "port_index = %u, meta_mode = %d", pParam->nPortIndex, pParam->bStoreMetaData); + if (pParam->nPortIndex == PORT_INDEX_IN) + { + meta_mode_enable = pParam->bStoreMetaData; + } + else + { + if (pParam->bStoreMetaData) + { + DEBUG_PRINT_ERROR("set_parameter: metamode is " + "valid for input port only"); + eRet = OMX_ErrorUnsupportedIndex; + } + } + } + break; + default: + { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown param %d", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + } + return eRet; +} + +bool omx_swvenc::update_profile_level() +{ + if (!strncmp((char *)m_nkind, "OMX.qti.video.encoder.hevc",\ + OMX_MAX_STRINGNAME_SIZE)) + { + if (m_sParamHEVC.eProfile != OMX_VIDEO_HEVCProfileMain) + { + return false; + } + SWVENC_PROP prop; + prop.ePropId = SWVENC_PROP_ID_PROFILE; + prop.uProperty.nProfile = SWVENC_HEVC_MAIN_PROFILE; + if (SwVenc_SetProperty(m_pSwVenc, &prop) != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("ERROR: failed to set profile"); + } + + int level = 0; + if (m_sParamHEVC.eLevel == OMX_VIDEO_HEVCMainTierLevel1) + { + level = SWVENC_HEVC_LEVEL_1; + } + else if (m_sParamHEVC.eLevel == OMX_VIDEO_HEVCMainTierLevel2) + { + level = SWVENC_HEVC_LEVEL_2; + } + else if (m_sParamHEVC.eLevel == OMX_VIDEO_HEVCMainTierLevel21) + { + level = SWVENC_HEVC_LEVEL_2_1; + } + else if (m_sParamHEVC.eLevel == OMX_VIDEO_HEVCMainTierLevel3) + { + level = SWVENC_HEVC_LEVEL_3; + } + + if (level) + { + prop.ePropId = SWVENC_PROP_ID_LEVEL; + prop.uProperty.nLevel = (SWVENC_HEVC_LEVEL)level; + if (SwVenc_SetProperty(m_pSwVenc, &prop) != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("ERROR: failed to set level %d", level); + } + } + } + + return true; +} +/* ====================================================================== + FUNCTION + omx_video::SetConfig + + DESCRIPTION + OMX Set Config method implementation + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if successful. + ========================================================================== */ +OMX_ERRORTYPE omx_swvenc::set_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_IN OMX_PTR configData) +{ + if (configData == NULL) { + DEBUG_PRINT_ERROR("ERROR: param is null"); + return OMX_ErrorBadParameter; + } + + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: config called in Invalid state"); + return OMX_ErrorIncorrectStateOperation; + } + + // params will be validated prior to venc_init + switch ((int)configIndex) { + case OMX_IndexConfigVideoBitrate: + { + OMX_VIDEO_CONFIG_BITRATETYPE* pParam = + reinterpret_cast<OMX_VIDEO_CONFIG_BITRATETYPE*>(configData); + DEBUG_PRINT_HIGH("set_config(): OMX_IndexConfigVideoBitrate (%u)", pParam->nEncodeBitrate); + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + SWVENC_PROP prop; + prop.uProperty.nBitrate = pParam->nEncodeBitrate; + prop.ePropId = SWVENC_PROP_ID_BITRATE; + SwVenc_SetProperty(m_pSwVenc, &prop); + + + m_sConfigBitrate.nEncodeBitrate = pParam->nEncodeBitrate; + m_sParamBitrate.nTargetBitrate = pParam->nEncodeBitrate; + m_sOutPortDef.format.video.nBitrate = pParam->nEncodeBitrate; + } else { + DEBUG_PRINT_ERROR("ERROR: Unsupported port index: %u", pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexConfigVideoFramerate: + { + OMX_CONFIG_FRAMERATETYPE* pParam = + reinterpret_cast<OMX_CONFIG_FRAMERATETYPE*>(configData); + DEBUG_PRINT_HIGH("set_config(): OMX_IndexConfigVideoFramerate (0x%x)", pParam->xEncodeFramerate); + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + SWVENC_PROP prop; + prop.uProperty.nFrameRate = pParam->xEncodeFramerate; + prop.ePropId = SWVENC_PROP_ID_FRAMERATE; + SwVenc_SetProperty(m_pSwVenc, &prop); + + m_sConfigFramerate.xEncodeFramerate = pParam->xEncodeFramerate; + m_sOutPortDef.format.video.xFramerate = pParam->xEncodeFramerate; + m_sOutPortFormat.xFramerate = pParam->xEncodeFramerate; + } else { + DEBUG_PRINT_ERROR("ERROR: Unsupported port index: %u", pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + case QOMX_IndexConfigVideoIntraperiod: + { + QOMX_VIDEO_INTRAPERIODTYPE* pParam = + reinterpret_cast<QOMX_VIDEO_INTRAPERIODTYPE*>(configData); + + DEBUG_PRINT_HIGH("set_config(): QOMX_IndexConfigVideoIntraperiod"); + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (pParam->nBFrames > 0) { + DEBUG_PRINT_ERROR("B frames not supported"); + return OMX_ErrorUnsupportedSetting; + } + DEBUG_PRINT_HIGH("Old: P/B frames = %u/%u, New: P/B frames = %u/%u", + m_sIntraperiod.nPFrames, m_sIntraperiod.nBFrames, + pParam->nPFrames, pParam->nBFrames); + if (m_sIntraperiod.nBFrames != pParam->nBFrames) { + DEBUG_PRINT_HIGH("Dynamically changing B-frames not supported"); + return OMX_ErrorUnsupportedSetting; + } + + SWVENC_PROP prop; + prop.uProperty.sIntraPeriod.pFrames = pParam->nPFrames; + prop.uProperty.sIntraPeriod.bFrames = pParam->nBFrames; + prop.ePropId = SWVENC_PROP_ID_INTRA_PERIOD; + SwVenc_SetProperty(m_pSwVenc, &prop); + + m_sIntraperiod.nPFrames = pParam->nPFrames; + m_sIntraperiod.nBFrames = pParam->nBFrames; + m_sIntraperiod.nIDRPeriod = pParam->nIDRPeriod; + } else { + DEBUG_PRINT_ERROR("ERROR: (QOMX_IndexConfigVideoIntraperiod) Unsupported port index: %u", pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + + case OMX_IndexConfigVideoIntraVOPRefresh: + { + OMX_CONFIG_INTRAREFRESHVOPTYPE* pParam = + reinterpret_cast<OMX_CONFIG_INTRAREFRESHVOPTYPE*>(configData); + + DEBUG_PRINT_HIGH("set_config(): OMX_IndexConfigVideoIntraVOPRefresh"); + if (pParam->nPortIndex == PORT_INDEX_OUT) { + SWVENC_PROP prop; + prop.ePropId = SWVENC_PROP_ID_IDR_INSERTION; + SwVenc_SetProperty(m_pSwVenc, &prop); + DEBUG_PRINT_HIGH("Setting SWVENC OMX_IndexConfigVideoIntraVOPRefresh"); + m_sConfigIntraRefreshVOP.IntraRefreshVOP = pParam->IntraRefreshVOP; + } else { + DEBUG_PRINT_ERROR("ERROR: Unsupported port index: %u", pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + case OMX_QcomIndexConfigVideoFramePackingArrangement: + { + DEBUG_PRINT_HIGH("set_config(): OMX_QcomIndexConfigVideoFramePackingArrangement"); + if (m_sOutPortFormat.eCompressionFormat == OMX_VIDEO_CodingAVC) { + OMX_QCOM_FRAME_PACK_ARRANGEMENT *configFmt = + (OMX_QCOM_FRAME_PACK_ARRANGEMENT *) configData; + extra_data_handle.set_frame_pack_data(configFmt); + } else { + DEBUG_PRINT_ERROR("ERROR: FramePackingData not supported for non AVC compression"); + } + break; + } + default: + DEBUG_PRINT_ERROR("ERROR: unsupported index %d", (int) configIndex); + return OMX_ErrorUnsupportedSetting; + } + + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_swvenc::ComponentDeInit + + DESCRIPTION + Destroys the component and release memory allocated to the heap. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_swvenc::component_deinit(OMX_IN OMX_HANDLETYPE hComp) +{ + OMX_U32 i = 0; + DEBUG_PRINT_HIGH("omx_swvenc(): Inside component_deinit()"); + if (OMX_StateLoaded != m_state) { + DEBUG_PRINT_ERROR("WARNING:Rxd DeInit,OMX not in LOADED state %d",\ + m_state); + } + if (m_out_mem_ptr) { + DEBUG_PRINT_LOW("Freeing the Output Memory"); + for (i=0; i< m_sOutPortDef.nBufferCountActual; i++ ) { + free_output_buffer (&m_out_mem_ptr[i]); + } + free(m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + + /*Check if the input buffers have to be cleaned up*/ + if (m_inp_mem_ptr +#ifdef _ANDROID_ICS_ + && !meta_mode_enable +#endif + ) { + DEBUG_PRINT_LOW("Freeing the Input Memory"); + for (i=0; i<m_sInPortDef.nBufferCountActual; i++ ) { + free_input_buffer (&m_inp_mem_ptr[i]); + } + + + free(m_inp_mem_ptr); + m_inp_mem_ptr = NULL; + } + + // Reset counters in mesg queues + m_ftb_q.m_size=0; + m_cmd_q.m_size=0; + m_etb_q.m_size=0; + m_ftb_q.m_read = m_ftb_q.m_write =0; + m_cmd_q.m_read = m_cmd_q.m_write =0; + m_etb_q.m_read = m_etb_q.m_write =0; + +#ifdef _ANDROID_ + // Clear the strong reference + DEBUG_PRINT_HIGH("Calling m_heap_ptr.clear()"); + m_heap_ptr.clear(); +#endif // _ANDROID_ + + DEBUG_PRINT_HIGH("Calling SwVenc_Stop()"); + SWVENC_STATUS ret = SwVenc_Stop(m_pSwVenc); + if (ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("SwVenc_Stop Command failed in venc destructor"); + } + + DEBUG_PRINT_HIGH("Deleting m_pSwVenc HANDLE[%p]", m_pSwVenc); + SwVenc_DeInit(m_pSwVenc); + m_pSwVenc = NULL; + + DEBUG_PRINT_HIGH("omx_swvenc:Component Deinit"); + return OMX_ErrorNone; +} + + +OMX_U32 omx_swvenc::dev_stop( void) +{ + SwVenc_Stop(m_pSwVenc); + post_event (0,0,OMX_COMPONENT_GENERATE_STOP_DONE); + return SWVENC_S_SUCCESS; +} + + +OMX_U32 omx_swvenc::dev_pause(void) +{ + return SWVENC_S_SUCCESS; +} + +OMX_U32 omx_swvenc::dev_start(void) +{ + SwVenc_Start(m_pSwVenc); + post_event (0,0,OMX_COMPONENT_GENERATE_START_DONE); + return SWVENC_S_SUCCESS; +} + +OMX_U32 omx_swvenc::dev_flush(unsigned port) +{ + if (port == PORT_INDEX_IN) + { + return SWVENC_S_EUNSUPPORTED; + } + + DEBUG_PRINT_HIGH("SwVenc_Flush port %d", port); + return SwVenc_Flush(m_pSwVenc); +} + +OMX_U32 omx_swvenc::dev_resume(void) +{ + return SWVENC_S_SUCCESS; +} + +OMX_U32 omx_swvenc::dev_start_done(void) +{ + return SWVENC_S_SUCCESS; +} + +OMX_U32 omx_swvenc::dev_set_message_thread_id(pthread_t tid) +{ + return SWVENC_S_SUCCESS; +} + +bool omx_swvenc::dev_use_buf(void *buf_addr,unsigned port,unsigned index) +{ + struct pmem* buf = (struct pmem*)buf_addr; + if (port == PORT_INDEX_IN) + { + // m_pSwVencIpBuffer[index].nSize = buf->size; + m_pSwVencIpBuffer[index].pBuffer = (unsigned char*)buf->buffer; + m_pSwVencIpBuffer[index].pClientBufferData = (void*)index; + + DEBUG_PRINT_LOW("dev_use_buf input %p, index %d userData %p", + m_pSwVencIpBuffer[index].pBuffer, index, m_pSwVencIpBuffer[index].pClientBufferData); + } + else + { + m_pSwVencOpBuffer[index].nSize = buf->size; + m_pSwVencOpBuffer[index].pBuffer = (unsigned char*)buf->buffer; + m_pSwVencOpBuffer[index].pClientBufferData = (void*)index; + DEBUG_PRINT_LOW("dev_use_buf output %p, index %d userData %p", + m_pSwVencIpBuffer[index].pBuffer, index, m_pSwVencIpBuffer[index].pClientBufferData); + } + return true; +} + +bool omx_swvenc::dev_free_buf(void *buf_addr,unsigned port) +{ + struct pmem* buf = (struct pmem*)buf_addr; + int i = 0; + if (port == PORT_INDEX_IN) + { + for (; i<32;i++) + { + if (m_pSwVencIpBuffer[i].pBuffer == buf->buffer) + { + m_pSwVencIpBuffer[i].pBuffer = NULL; + // m_pSwVencIpBuffer[i].nSize = 0; + } + } + } + else + { + for (; i<32;i++) + { + if (m_pSwVencOpBuffer[i].pBuffer == buf->buffer) + { + m_pSwVencOpBuffer[i].pBuffer = NULL; + m_pSwVencOpBuffer[i].nSize = 0; + } + } + } + return true; +} + +void dump_buffer(unsigned char* buffer, int stride, int scanlines, int width, int height) +{ + static FILE* pFile = NULL; + static int count = 0; + if (count++ >= 100) return; + + if (pFile == NULL) + { + pFile = fopen("/data/input.yuv", "wb"); + } + if (buffer) + { + char *temp = (char *)buffer; + int i; + int bytes_written = 0; + int bytes = 0; + + for (i = 0; i < height; i++) { + bytes_written = fwrite(temp, width, 1, pFile); + temp += stride; + if (bytes_written >0) + bytes += bytes_written * width; + } + temp = (char *)buffer + stride * scanlines; + int stride_c = stride; + for(i = 0; i < height/2; i++) { + bytes_written = fwrite(temp, width, 1, pFile); + temp += stride_c; + if (bytes_written >0) + bytes += bytes_written * width; + } + + DEBUG_PRINT_ERROR("stride %d, scanlines %d, frame_height %d bytes_written %d", + stride, scanlines, height, bytes); + } +} + +static FILE* gYUV = NULL; + +bool omx_swvenc::dev_empty_buf(void *buffer, void *pmem_data_buf,unsigned index,unsigned fd) +{ + SWVENC_STATUS status; + SWVENC_IPBUFFER ipbuffer; + OMX_BUFFERHEADERTYPE *bufHdr = (OMX_BUFFERHEADERTYPE *)buffer; + + if (meta_mode_enable) + { + unsigned int size = 0, offset = 0; + encoder_media_buffer_type *meta_buf = NULL; + meta_buf = (encoder_media_buffer_type *)bufHdr->pBuffer; + if (meta_buf) + { + if (meta_buf->buffer_type == kMetadataBufferTypeCameraSource) + { + offset = meta_buf->meta_handle->data[1]; + size = meta_buf->meta_handle->data[2]; + } + else if (meta_buf->buffer_type == kMetadataBufferTypeGrallocSource) + { + private_handle_t *handle = (private_handle_t *)meta_buf->meta_handle; + size = handle->size; + } + } + + ipbuffer.pBuffer = (unsigned char *)mmap(NULL, size, PROT_READ|PROT_WRITE,MAP_SHARED, fd, offset); + ipbuffer.nFilledLen = size; + DEBUG_PRINT_LOW("mapped meta buf fd %d size %d %p", fd, size, ipbuffer.pBuffer); + } + else + { + ipbuffer.pBuffer = bufHdr->pBuffer; + ipbuffer.nFilledLen = bufHdr->nFilledLen; + } + + ipbuffer.nFlags = bufHdr->nFlags; + ipbuffer.nIpTimestamp = bufHdr->nTimeStamp; + ipbuffer.pClientBufferData = (unsigned char *)bufHdr; + + DEBUG_PRINT_LOW("SwVenc_EmptyThisBuffer index %d pBuffer %p", index, ipbuffer.pBuffer); + status = SwVenc_EmptyThisBuffer(m_pSwVenc, &ipbuffer); + + if (status != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("SwVenc_EmptyThisBuffer failed"); + post_event ((unsigned int)buffer,0,OMX_COMPONENT_GENERATE_EBD); + pending_output_buffers--; + } + + return status == SWVENC_S_SUCCESS; +} + +bool omx_swvenc::dev_fill_buf(void *buffer, void *pmem_data_buf,unsigned index,unsigned fd) +{ + SWVENC_STATUS status; + OMX_BUFFERHEADERTYPE* bufHdr = (OMX_BUFFERHEADERTYPE*)buffer; + + DEBUG_PRINT_LOW("SwVenc_FillThisBuffer index %d pBuffer %p pmem_data_buf %p", + index, bufHdr->pBuffer, pmem_data_buf); + status = SwVenc_FillThisBuffer(m_pSwVenc, &m_pSwVencOpBuffer[index]); + + if (status != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("SwVenc_FillThisBuffer failed"); + post_event ((unsigned int)buffer,0,OMX_COMPONENT_GENERATE_FBD); + pending_output_buffers--; + } + + return status == SWVENC_S_SUCCESS; +} + +bool omx_swvenc::dev_get_seq_hdr(void *buffer, unsigned size, unsigned *hdrlen) +{ + return false; +} + +bool omx_swvenc::dev_get_capability_ltrcount(OMX_U32 *min, OMX_U32 *max, OMX_U32 *step_size) +{ + return true; +} + +bool omx_swvenc::dev_loaded_start() +{ + return true; +} + +bool omx_swvenc::dev_loaded_stop() +{ + return true; +} + +bool omx_swvenc::dev_loaded_start_done() +{ + return true; +} + +bool omx_swvenc::dev_loaded_stop_done() +{ + return true; +} + + +bool omx_swvenc::dev_get_performance_level(OMX_U32 *perflevel) +{ + DEBUG_PRINT_ERROR("Get performance level is not supported"); + return false; +} + +bool omx_swvenc::dev_get_vui_timing_info(OMX_U32 *enabled) +{ + DEBUG_PRINT_ERROR("Get vui timing information is not supported"); + return false; +} + +bool omx_swvenc::dev_get_peak_bitrate(OMX_U32 *peakbitrate) +{ + DEBUG_PRINT_ERROR("Get peak bitrate is not supported"); + return false; +} + +bool omx_swvenc::dev_get_buf_req(OMX_U32 *min_buff_count, + OMX_U32 *actual_buff_count, + OMX_U32 *buff_size, + OMX_U32 port) +{ + SWVENC_STATUS sRet = SWVENC_S_SUCCESS; + SWVENC_PROP property; + property.ePropId = (port == 0) ? SWVENC_PROP_ID_IPBUFFREQ : SWVENC_PROP_ID_OPBUFFREQ; + + sRet = SwVenc_GetProperty(m_pSwVenc, &property); + if (sRet == SWVENC_S_SUCCESS) + { + if (port == 0) + { + *min_buff_count = property.uProperty.sIpBuffReq.nMinCount; + *buff_size = property.uProperty.sIpBuffReq.nSize; + *actual_buff_count = property.uProperty.sIpBuffReq.nMinCount; + DEBUG_PRINT_HIGH("SwVenc input buffer Size =%u Count = %u", *buff_size, *actual_buff_count); + } + else + { + *min_buff_count = property.uProperty.sOpBuffReq.nMinCount; + *buff_size = property.uProperty.sOpBuffReq.nSize; + *actual_buff_count = property.uProperty.sOpBuffReq.nMinCount; + DEBUG_PRINT_HIGH("SwVenc output buffer Size =%u Count = %u", property.uProperty.sOpBuffReq.nSize, property.uProperty.sOpBuffReq.nMinCount); + } + } + + return (sRet == SWVENC_S_SUCCESS); +} + +bool omx_swvenc::dev_set_buf_req(OMX_U32 *min_buff_count, + OMX_U32 *actual_buff_count, + OMX_U32 *buff_size, + OMX_U32 port) +{ + SWVENC_PROP property; + SWVENC_STATUS sRet = SWVENC_S_SUCCESS; + + if (port != PORT_INDEX_IN || port != PORT_INDEX_OUT) return false; + if (*min_buff_count > *actual_buff_count) return false; + + if(port == PORT_INDEX_IN) + { + property.ePropId = SWVENC_PROP_ID_IPBUFFREQ; + property.uProperty.sIpBuffReq.nSize = *buff_size;; + property.uProperty.sIpBuffReq.nMaxCount = *actual_buff_count; + property.uProperty.sIpBuffReq.nMinCount = *actual_buff_count; + DEBUG_PRINT_HIGH("Set SwVenc input Buffer Size =%d Count = %d",property.uProperty.sIpBuffReq.nSize, *actual_buff_count); + } + else if (port == PORT_INDEX_OUT) + { + property.ePropId = SWVENC_PROP_ID_OPBUFFREQ; + property.uProperty.sOpBuffReq.nSize = *buff_size; + property.uProperty.sOpBuffReq.nMaxCount = *actual_buff_count; + property.uProperty.sOpBuffReq.nMinCount = *actual_buff_count; + DEBUG_PRINT_HIGH("Set SwVenc output Buffer Size =%d and Count = %d",property.uProperty.sOpBuffReq.nSize, *actual_buff_count); + } + + sRet = SwVenc_SetProperty(m_pSwVenc, &property); + if (sRet != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("Set buffer requirements from ARM codec failed"); + } + + return sRet == SWVENC_S_SUCCESS; +} + +bool omx_swvenc::dev_is_video_session_supported(OMX_U32 width, OMX_U32 height) +{ + if (width > 1280 || height > 720) return false; + return true; +} + + +int omx_swvenc::dev_handle_extradata(void *buffer, int index) +{ + return SWVENC_S_EUNSUPPORTED; +} + +int omx_swvenc::dev_set_format(int color) +{ + return SWVENC_S_SUCCESS; +} + +bool omx_swvenc::dev_color_align(OMX_BUFFERHEADERTYPE *buffer, + OMX_U32 width, OMX_U32 height) +{ + if(secure_session) { + DEBUG_PRINT_ERROR("Cannot align colors in secure session."); + return OMX_FALSE; + } + return true; +} + +bool omx_swvenc::is_secure_session() +{ + return secure_session; +} + +bool omx_swvenc::dev_get_output_log_flag() +{ + return false; +} + +int omx_swvenc::dev_output_log_buffers(const char *buffer, int bufferlen) +{ + return 0; +} + +int omx_swvenc::dev_extradata_log_buffers(char *buffer) +{ + return 0; +} + +SWVENC_STATUS omx_swvenc::swvenc_input_buffer_done_cb +( + SWVENC_HANDLE pSwEnc, + SWVENC_IPBUFFER *pIpBuffer, + void *pClientHandle +) +{ + SWVENC_STATUS eRet = SWVENC_S_SUCCESS; + omx_swvenc *omx = reinterpret_cast<omx_swvenc*>(pClientHandle); + + if (pIpBuffer == NULL) + { + eRet = SWVENC_S_EFAIL; + } + else + { + omx->swvenc_input_buffer_done(pIpBuffer); + } + + return eRet; +} + +void omx_swvenc::swvenc_input_buffer_done(SWVENC_IPBUFFER *pIpBuffer) +{ + OMX_BUFFERHEADERTYPE *bufHdr = (OMX_BUFFERHEADERTYPE *)pIpBuffer->pClientBufferData; + + if (meta_mode_enable) + { + omx_release_meta_buffer(bufHdr); + + // fd is not dupped, nothing needs to be done here + munmap(pIpBuffer->pBuffer, pIpBuffer->nFilledLen); + } + + DEBUG_PRINT_LOW("swvenc_empty_buffer_done bufHdr %p pBuffer %p = %p nFilledLen %d nFlags %x", + bufHdr, bufHdr->pBuffer, pIpBuffer->pBuffer, pIpBuffer->nFilledLen, pIpBuffer->nFlags); + + post_event((unsigned int)(bufHdr), SWVENC_S_SUCCESS, OMX_COMPONENT_GENERATE_EBD); +} + +SWVENC_STATUS omx_swvenc::swvenc_fill_buffer_done_cb +( + SWVENC_HANDLE pSwEnc, + SWVENC_OPBUFFER *m_pSWVencOpBuffer, + void *pClientHandle +) +{ + SWVENC_STATUS eRet = SWVENC_S_SUCCESS; + omx_swvenc *omx = reinterpret_cast<omx_swvenc*>(pClientHandle); + + if (m_pSWVencOpBuffer == NULL) + { + eRet = SWVENC_S_EFAIL; + } + else + { + omx->swvenc_fill_buffer_done(m_pSWVencOpBuffer); + } + return eRet; +} + +void omx_swvenc::swvenc_fill_buffer_done(SWVENC_OPBUFFER *pOpBuffer) +{ + int index = (int)pOpBuffer->pClientBufferData; + OMX_BUFFERHEADERTYPE *bufHdr = m_out_mem_ptr + index; + + bufHdr->nOffset = 0; + bufHdr->nFilledLen = pOpBuffer->nFilledLen; + bufHdr->nFlags = pOpBuffer->nFlags; + bufHdr->nTimeStamp = pOpBuffer->nOpTimestamp; + + if (bufHdr->nFlags & OMX_BUFFERFLAG_EOS) + { + DEBUG_PRINT_ERROR("swvenc output EOS reached\n"); + } + + /*Use buffer case*/ + if (output_use_buffer && !m_use_output_pmem && + !output_flush_progress && pOpBuffer->nFilledLen) + { + DEBUG_PRINT_LOW("memcpy for o/p Heap UseBuffer size %d", pOpBuffer->nFilledLen); + memcpy(bufHdr->pBuffer, pOpBuffer->pBuffer, pOpBuffer->nFilledLen); + } + + DEBUG_PRINT_LOW("swvenc_fill_buffer_done bufHdr %p pBuffer %p = %p idx %d nFilledLen %d nFlags %x\n", + bufHdr, bufHdr->pBuffer, pOpBuffer->pBuffer, index, pOpBuffer->nFilledLen, pOpBuffer->nFlags); + post_event((unsigned int)bufHdr, SWVENC_S_SUCCESS, OMX_COMPONENT_GENERATE_FBD); +} + +SWVENC_STATUS omx_swvenc::swvenc_handle_event_cb +( + SWVENC_HANDLE pSwEnc, + SWVENC_EVENTHANDLER* pEventHandler, + void *pClientHandle +) +{ + omx_swvenc *omx = reinterpret_cast<omx_swvenc*>(pClientHandle); + omx->swvenc_handle_event(pEventHandler); + return SWVENC_S_SUCCESS; +} + +void omx_swvenc::swvenc_handle_event(SWVENC_EVENTHANDLER *pEvent) +{ + switch(pEvent->eEvent) + { + case SWVENC_FLUSH_DONE: + DEBUG_PRINT_HIGH("SWVENC_FLUSH_DONE input_flush_progress %d output_flush_progress %d\n", + input_flush_progress, output_flush_progress); + if (input_flush_progress) + { + post_event ((unsigned)NULL, SWVENC_S_SUCCESS, OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH); + } + if (output_flush_progress) + { + post_event ((unsigned)NULL, SWVENC_S_SUCCESS, OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH); + } + break; + case SWVENC_ERROR: + break; + + default: + break; + } + +} + + diff --git a/msm8998/mm-video-v4l2/vidc/venc/src/omx_swvenc_mpeg4.cpp b/msm8998/mm-video-v4l2/vidc/venc/src/omx_swvenc_mpeg4.cpp new file mode 100644 index 0000000..b6c6160 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/src/omx_swvenc_mpeg4.cpp @@ -0,0 +1,3048 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2014-2016, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#include "omx_swvenc_mpeg4.h" + +/* def: StoreMetaDataInBuffersParams */ +#include <media/hardware/HardwareAPI.h> + +/* def: VENUS_BUFFER_SIZE, VENUS_Y_STRIDE etc */ +#include <media/msm_media_info.h> + +/* def: private_handle_t*/ +#include <gralloc_priv.h> + + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#define OMX_SPEC_VERSION 0x00000101 +#define OMX_INIT_STRUCT(_s_, _name_) \ + memset((_s_), 0x0, sizeof(_name_)); \ + (_s_)->nSize = sizeof(_name_); \ + (_s_)->nVersion.nVersion = OMX_SPEC_VERSION + +#define ENTER_FUNC() DEBUG_PRINT_HIGH("ENTERING: %s",__FUNCTION__) +#define EXIT_FUNC() DEBUG_PRINT_HIGH("EXITING: %s",__FUNCTION__) +#define RETURN(x) EXIT_FUNC(); return x; +#define ALIGN(value,alignment) (((value) + (alignment-1)) & (~(alignment-1))) + +#define BUFFER_LOG_LOC "/data/misc/media" + +/* factory function executed by the core to create instances */ +void *get_omx_component_factory_fn(void) +{ + RETURN((new omx_venc)); +} + +omx_venc::omx_venc() +{ + ENTER_FUNC(); + + char property_value[PROPERTY_VALUE_MAX] = {0}; + + memset(&m_debug,0,sizeof(m_debug)); + + property_value[0] = '\0'; + property_get("vidc.debug.level", property_value, "1"); + debug_level = atoi(property_value); + + property_value[0] = '\0'; + property_get("vidc.enc.log.in", property_value, "0"); + m_debug.in_buffer_log = atoi(property_value); + + property_value[0] = '\0'; + property_get("vidc.enc.log.out", property_value, "0"); + m_debug.out_buffer_log = atoi(property_value); + + snprintf(m_debug.log_loc, PROPERTY_VALUE_MAX, "%s", BUFFER_LOG_LOC); + property_value[0] = '\0'; + property_get("vidc.log.loc", property_value, ""); + if (*property_value) + { + strlcpy(m_debug.log_loc, property_value, PROPERTY_VALUE_MAX); + } + + memset(meta_buffer_hdr,0,sizeof(meta_buffer_hdr)); + meta_mode_enable = false; + memset(meta_buffer_hdr,0,sizeof(meta_buffer_hdr)); + memset(meta_buffers,0,sizeof(meta_buffers)); + memset(opaque_buffer_hdr,0,sizeof(opaque_buffer_hdr)); + mUseProxyColorFormat = false; + get_syntaxhdr_enable = false; + m_bSeqHdrRequested = false; + set_format = false; + + EXIT_FUNC(); +} + +omx_venc::~omx_venc() +{ + ENTER_FUNC(); + get_syntaxhdr_enable = false; + EXIT_FUNC(); +} + +OMX_ERRORTYPE omx_venc::component_init(OMX_STRING role) +{ + ENTER_FUNC(); + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + SWVENC_STATUS Ret = SWVENC_S_SUCCESS; + SWVENC_CALLBACK callBackInfo; + OMX_VIDEO_CODINGTYPE codec_type; + SWVENC_PROPERTY Prop; + int fds[2]; + + strlcpy((char *)m_nkind,role,OMX_MAX_STRINGNAME_SIZE); + secure_session = false; + + if (!strncmp( (char *)m_nkind,"OMX.qcom.video.encoder.mpeg4sw", + OMX_MAX_STRINGNAME_SIZE)) + { + strlcpy((char *)m_cRole, "video_encoder.mpeg4",\ + OMX_MAX_STRINGNAME_SIZE); + codec_type = OMX_VIDEO_CodingMPEG4; + m_codec = SWVENC_CODEC_MPEG4; + } + else if (!strncmp( (char *)m_nkind,"OMX.qcom.video.encoder.h263sw", + OMX_MAX_STRINGNAME_SIZE)) + { + strlcpy((char *)m_cRole, "video_encoder.h263",\ + OMX_MAX_STRINGNAME_SIZE); + codec_type = OMX_VIDEO_CodingH263; + m_codec = SWVENC_CODEC_H263; + } + else + { + DEBUG_PRINT_ERROR("ERROR: Unknown Component"); + eRet = OMX_ErrorInvalidComponentName; + RETURN(eRet); + } + +#ifdef ENABLE_GET_SYNTAX_HDR + get_syntaxhdr_enable = true; + DEBUG_PRINT_HIGH("Get syntax header enabled"); +#endif + + callBackInfo.pfn_empty_buffer_done = swvenc_empty_buffer_done_cb; + callBackInfo.pfn_fill_buffer_done = swvenc_fill_buffer_done_cb; + callBackInfo.pfn_event_notification = swvenc_handle_event_cb; + callBackInfo.p_client = (void*)this; + + SWVENC_STATUS sRet = swvenc_init(&m_hSwVenc, m_codec, &callBackInfo); + if (sRet != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("swvenc_init returned %d, ret insufficient resources", + sRet); + RETURN(OMX_ErrorInsufficientResources); + } + + m_stopped = true; + + //Intialise the OMX layer variables + memset(&m_pCallbacks,0,sizeof(OMX_CALLBACKTYPE)); + + OMX_INIT_STRUCT(&m_sPortParam, OMX_PORT_PARAM_TYPE); + m_sPortParam.nPorts = 0x2; + m_sPortParam.nStartPortNumber = (OMX_U32) PORT_INDEX_IN; + + OMX_INIT_STRUCT(&m_sPortParam_audio, OMX_PORT_PARAM_TYPE); + m_sPortParam_audio.nPorts = 0; + m_sPortParam_audio.nStartPortNumber = 0; + + OMX_INIT_STRUCT(&m_sPortParam_img, OMX_PORT_PARAM_TYPE); + m_sPortParam_img.nPorts = 0; + m_sPortParam_img.nStartPortNumber = 0; + + OMX_INIT_STRUCT(&m_sParamBitrate, OMX_VIDEO_PARAM_BITRATETYPE); + m_sParamBitrate.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamBitrate.eControlRate = OMX_Video_ControlRateVariableSkipFrames; + m_sParamBitrate.nTargetBitrate = 64000; + + OMX_INIT_STRUCT(&m_sConfigBitrate, OMX_VIDEO_CONFIG_BITRATETYPE); + m_sConfigBitrate.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigBitrate.nEncodeBitrate = 64000; + + OMX_INIT_STRUCT(&m_sConfigFramerate, OMX_CONFIG_FRAMERATETYPE); + m_sConfigFramerate.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigFramerate.xEncodeFramerate = 30 << 16; + + OMX_INIT_STRUCT(&m_sConfigIntraRefreshVOP, OMX_CONFIG_INTRAREFRESHVOPTYPE); + m_sConfigIntraRefreshVOP.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigIntraRefreshVOP.IntraRefreshVOP = OMX_FALSE; + + OMX_INIT_STRUCT(&m_sConfigFrameRotation, OMX_CONFIG_ROTATIONTYPE); + m_sConfigFrameRotation.nPortIndex = (OMX_U32) PORT_INDEX_IN; + m_sConfigFrameRotation.nRotation = 0; + + OMX_INIT_STRUCT(&m_sSessionQuantization, OMX_VIDEO_PARAM_QUANTIZATIONTYPE); + m_sSessionQuantization.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sSessionQuantization.nQpI = 9; + m_sSessionQuantization.nQpP = 6; + m_sSessionQuantization.nQpB = 2; + + OMX_INIT_STRUCT(&m_sSessionQPRange, OMX_QCOM_VIDEO_PARAM_QPRANGETYPE); + m_sSessionQPRange.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sSessionQPRange.minQP = 2; + + OMX_INIT_STRUCT(&m_sParamProfileLevel, OMX_VIDEO_PARAM_PROFILELEVELTYPE); + m_sParamProfileLevel.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + + OMX_INIT_STRUCT(&m_sIntraperiod, QOMX_VIDEO_INTRAPERIODTYPE); + m_sIntraperiod.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sIntraperiod.nPFrames = (m_sConfigFramerate.xEncodeFramerate * 2) - 1; + + OMX_INIT_STRUCT(&m_sErrorCorrection, OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE); + m_sErrorCorrection.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sErrorCorrection.bEnableDataPartitioning = OMX_FALSE; + m_sErrorCorrection.bEnableHEC = OMX_FALSE; + m_sErrorCorrection.bEnableResync = OMX_FALSE; + m_sErrorCorrection.bEnableRVLC = OMX_FALSE; + m_sErrorCorrection.nResynchMarkerSpacing = 0; + + OMX_INIT_STRUCT(&m_sIntraRefresh, OMX_VIDEO_PARAM_INTRAREFRESHTYPE); + m_sIntraRefresh.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sIntraRefresh.eRefreshMode = OMX_VIDEO_IntraRefreshMax; + + if (codec_type == OMX_VIDEO_CodingMPEG4) + { + m_sParamProfileLevel.eProfile = (OMX_U32) OMX_VIDEO_MPEG4ProfileSimple; + m_sParamProfileLevel.eLevel = (OMX_U32) OMX_VIDEO_MPEG4Level0; + } else if (codec_type == OMX_VIDEO_CodingH263) + { + m_sParamProfileLevel.eProfile = (OMX_U32) OMX_VIDEO_H263ProfileBaseline; + m_sParamProfileLevel.eLevel = (OMX_U32) OMX_VIDEO_H263Level10; + } + + /* set the profile and level */ + Ret = swvenc_set_profile_level(m_sParamProfileLevel.eProfile, + m_sParamProfileLevel.eLevel); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_rc_mode failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUndefined); + } + + // Initialize the video parameters for input port + OMX_INIT_STRUCT(&m_sInPortDef, OMX_PARAM_PORTDEFINITIONTYPE); + m_sInPortDef.nPortIndex= (OMX_U32) PORT_INDEX_IN; + m_sInPortDef.bEnabled = OMX_TRUE; + m_sInPortDef.bPopulated = OMX_FALSE; + m_sInPortDef.eDomain = OMX_PortDomainVideo; + m_sInPortDef.eDir = OMX_DirInput; + m_sInPortDef.format.video.cMIMEType = (char *)"YUV420"; + m_sInPortDef.format.video.nFrameWidth = OMX_CORE_QCIF_WIDTH; + m_sInPortDef.format.video.nFrameHeight = OMX_CORE_QCIF_HEIGHT; + m_sInPortDef.format.video.nStride = OMX_CORE_QCIF_WIDTH; + m_sInPortDef.format.video.nSliceHeight = OMX_CORE_QCIF_HEIGHT; + m_sInPortDef.format.video.nBitrate = 64000; + m_sInPortDef.format.video.xFramerate = 15 << 16; + m_sInPortDef.format.video.eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + m_sInPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; + + /* set the frame size */ + Prop.id = SWVENC_PROPERTY_ID_FRAME_SIZE; + Prop.info.frame_size.height = m_sInPortDef.format.video.nFrameHeight; + Prop.info.frame_size.width = m_sInPortDef.format.video.nFrameWidth; + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + /* set the frame attributes */ + Prop.id = SWVENC_PROPERTY_ID_FRAME_ATTRIBUTES; + Prop.info.frame_attributes.stride_luma = m_sInPortDef.format.video.nStride; + Prop.info.frame_attributes.stride_chroma = m_sInPortDef.format.video.nStride; + Prop.info.frame_attributes.offset_luma = 0; + Prop.info.frame_attributes.offset_chroma = + (m_sInPortDef.format.video.nSliceHeight * m_sInPortDef.format.video.nStride); + Prop.info.frame_attributes.size = (Prop.info.frame_attributes.offset_chroma * 3) >> 1; + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUndefined); + } + + Ret = swvenc_get_buffer_req(&m_sInPortDef.nBufferCountMin, + &m_sInPortDef.nBufferCountActual, + &m_sInPortDef.nBufferSize, + &m_sInPortDef.nBufferAlignment, + PORT_INDEX_IN); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("ERROR: %s, swvenc_get_buffer_req failed (%d)", __FUNCTION__, + Ret); + RETURN(OMX_ErrorUndefined); + } + + // Initialize the video parameters for output port + OMX_INIT_STRUCT(&m_sOutPortDef, OMX_PARAM_PORTDEFINITIONTYPE); + m_sOutPortDef.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sOutPortDef.bEnabled = OMX_TRUE; + m_sOutPortDef.bPopulated = OMX_FALSE; + m_sOutPortDef.eDomain = OMX_PortDomainVideo; + m_sOutPortDef.eDir = OMX_DirOutput; + m_sOutPortDef.format.video.nFrameWidth = OMX_CORE_QCIF_WIDTH; + m_sOutPortDef.format.video.nFrameHeight = OMX_CORE_QCIF_HEIGHT; + m_sOutPortDef.format.video.nBitrate = 64000; + m_sOutPortDef.format.video.xFramerate = 15 << 16; + m_sOutPortDef.format.video.eColorFormat = OMX_COLOR_FormatUnused; + if (codec_type == OMX_VIDEO_CodingMPEG4) + { + m_sOutPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4; + } + else if (codec_type == OMX_VIDEO_CodingH263) + { + m_sOutPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingH263; + } + + Ret = swvenc_get_buffer_req(&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + &m_sOutPortDef.nBufferAlignment, + PORT_INDEX_OUT); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("ERROR: %s, swvenc_get_buffer_req failed (%d)", __FUNCTION__, + Ret); + RETURN(OMX_ErrorUndefined); + } + + // Initialize the video color format for input port + OMX_INIT_STRUCT(&m_sInPortFormat, OMX_VIDEO_PARAM_PORTFORMATTYPE); + m_sInPortFormat.nPortIndex = (OMX_U32) PORT_INDEX_IN; + m_sInPortFormat.nIndex = 0; + m_sInPortFormat.eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + m_sInPortFormat.eCompressionFormat = OMX_VIDEO_CodingUnused; + + // Initialize the compression format for output port + OMX_INIT_STRUCT(&m_sOutPortFormat, OMX_VIDEO_PARAM_PORTFORMATTYPE); + m_sOutPortFormat.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sOutPortFormat.nIndex = 0; + m_sOutPortFormat.eColorFormat = OMX_COLOR_FormatUnused; + if (codec_type == OMX_VIDEO_CodingMPEG4) + { + m_sOutPortFormat.eCompressionFormat = OMX_VIDEO_CodingMPEG4; + } else if (codec_type == OMX_VIDEO_CodingH263) + { + m_sOutPortFormat.eCompressionFormat = OMX_VIDEO_CodingH263; + } + + // mandatory Indices for kronos test suite + OMX_INIT_STRUCT(&m_sPriorityMgmt, OMX_PRIORITYMGMTTYPE); + + OMX_INIT_STRUCT(&m_sInBufSupplier, OMX_PARAM_BUFFERSUPPLIERTYPE); + m_sInBufSupplier.nPortIndex = (OMX_U32) PORT_INDEX_IN; + + OMX_INIT_STRUCT(&m_sOutBufSupplier, OMX_PARAM_BUFFERSUPPLIERTYPE); + m_sOutBufSupplier.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + + OMX_INIT_STRUCT(&m_sParamInitqp, QOMX_EXTNINDEX_VIDEO_INITIALQP); + m_sParamInitqp.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + + // mp4 specific init + OMX_INIT_STRUCT(&m_sParamMPEG4, OMX_VIDEO_PARAM_MPEG4TYPE); + m_sParamMPEG4.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamMPEG4.eProfile = OMX_VIDEO_MPEG4ProfileSimple; + m_sParamMPEG4.eLevel = OMX_VIDEO_MPEG4Level0; + m_sParamMPEG4.nSliceHeaderSpacing = 0; + m_sParamMPEG4.bSVH = OMX_FALSE; + m_sParamMPEG4.bGov = OMX_FALSE; + // 2 second intra period for default outport fps + m_sParamMPEG4.nPFrames = (m_sOutPortFormat.xFramerate * 2 - 1); + m_sParamMPEG4.bACPred = OMX_TRUE; + // delta = 2 @ 15 fps + m_sParamMPEG4.nTimeIncRes = 30; + // pframe and iframe + m_sParamMPEG4.nAllowedPictureTypes = 2; + // number of video packet headers per vop + m_sParamMPEG4.nHeaderExtension = 1; + m_sParamMPEG4.bReversibleVLC = OMX_FALSE; + + // h263 specific init + OMX_INIT_STRUCT(&m_sParamH263, OMX_VIDEO_PARAM_H263TYPE); + m_sParamH263.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + // 2 second intra period for default outport fps + m_sParamH263.nPFrames = (m_sOutPortFormat.xFramerate * 2 - 1); + m_sParamH263.nBFrames = 0; + m_sParamH263.eProfile = OMX_VIDEO_H263ProfileBaseline; + m_sParamH263.eLevel = OMX_VIDEO_H263Level10; + m_sParamH263.bPLUSPTYPEAllowed = OMX_FALSE; + m_sParamH263.nAllowedPictureTypes = 2; + m_sParamH263.bForceRoundingTypeToZero = OMX_TRUE; + m_sParamH263.nPictureHeaderRepetition = 0; + m_sParamH263.nGOBHeaderInterval = 1; + + m_state = OMX_StateLoaded; + m_sExtraData = 0; + + m_capability.max_height = OMX_CORE_FWVGA_HEIGHT; + m_capability.max_width = OMX_CORE_FWVGA_WIDTH; + m_capability.min_height = 32; + m_capability.min_width = 32; + + if (eRet == OMX_ErrorNone) + { + if (pipe(fds)) + { + DEBUG_PRINT_ERROR("ERROR: pipe creation failed"); + eRet = OMX_ErrorInsufficientResources; + } + else + { + if ((fds[0] == 0) || (fds[1] == 0)) + { + if (pipe(fds)) + { + DEBUG_PRINT_ERROR("ERROR: pipe creation failed"); + eRet = OMX_ErrorInsufficientResources; + } + } + if (eRet == OMX_ErrorNone) + { + m_pipe_in = fds[0]; + m_pipe_out = fds[1]; + } + } + + if (pthread_create(&msg_thread_id,0, message_thread_enc, this) < 0) + { + eRet = OMX_ErrorInsufficientResources; + msg_thread_created = false; + } + else + { + msg_thread_created = true; + } + } + + DEBUG_PRINT_HIGH("Component_init return value = 0x%x", eRet); + + EXIT_FUNC(); + + RETURN(eRet); +} + +OMX_ERRORTYPE omx_venc::set_parameter +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_IN OMX_PTR paramData +) +{ + ENTER_FUNC(); + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + SWVENC_STATUS Ret = SWVENC_S_SUCCESS; + SWVENC_PROPERTY Prop; + bool bResult; + unsigned int stride, scanlines; + + (void)hComp; + + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("ERROR: Set Param in Invalid State"); + RETURN(OMX_ErrorInvalidState); + } + if (paramData == NULL) + { + DEBUG_PRINT_ERROR("ERROR: Get Param in Invalid paramData"); + RETURN(OMX_ErrorBadParameter); + } + + /* set_parameter can be called in loaded state or disabled port */ + if ( (m_state == OMX_StateLoaded) || + (m_sInPortDef.bEnabled == OMX_FALSE) || + (m_sOutPortDef.bEnabled == OMX_FALSE) + ) + { + DEBUG_PRINT_LOW("Set Parameter called in valid state"); + } + else + { + DEBUG_PRINT_ERROR("ERROR: Set Parameter called in Invalid State"); + RETURN(OMX_ErrorIncorrectStateOperation); + } + + switch ((int)paramIndex) + { + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition H= %d, W = %d", + (int)portDefn->format.video.nFrameHeight, + (int)portDefn->format.video.nFrameWidth); + + if (PORT_INDEX_IN == portDefn->nPortIndex) + { + if (!dev_is_video_session_supported(portDefn->format.video.nFrameWidth, + portDefn->format.video.nFrameHeight)) + { + DEBUG_PRINT_ERROR("video session not supported"); + omx_report_unsupported_setting(); + RETURN(OMX_ErrorUnsupportedSetting); + } + DEBUG_PRINT_LOW("i/p actual cnt requested = %u", portDefn->nBufferCountActual); + DEBUG_PRINT_LOW("i/p min cnt requested = %u", portDefn->nBufferCountMin); + DEBUG_PRINT_LOW("i/p buffersize requested = %u", portDefn->nBufferSize); + if (portDefn->nBufferCountMin > portDefn->nBufferCountActual) + { + DEBUG_PRINT_ERROR("ERROR: (In_PORT) Min buffers (%u) > actual count (%u)", + portDefn->nBufferCountMin, portDefn->nBufferCountActual); + RETURN(OMX_ErrorUnsupportedSetting); + } + + /* set the frame size */ + Prop.id = SWVENC_PROPERTY_ID_FRAME_SIZE; + Prop.info.frame_size.height = portDefn->format.video.nFrameHeight; + Prop.info.frame_size.width = portDefn->format.video.nFrameWidth; + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + /* set the input frame-rate */ + if (portDefn->format.video.xFramerate != 0) + { + Ret = swvenc_set_frame_rate(portDefn->format.video.xFramerate >> 16); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_frame_rate failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + } + + /* set the frame attributes */ + stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, portDefn->format.video.nFrameWidth); + scanlines = VENUS_Y_SCANLINES(COLOR_FMT_NV12, portDefn->format.video.nSliceHeight); + Prop.id = SWVENC_PROPERTY_ID_FRAME_ATTRIBUTES; + Prop.info.frame_attributes.stride_luma = stride; + Prop.info.frame_attributes.stride_chroma = stride; + Prop.info.frame_attributes.offset_luma = 0; + Prop.info.frame_attributes.offset_chroma = scanlines * stride; + Prop.info.frame_attributes.size = + VENUS_BUFFER_SIZE(COLOR_FMT_NV12, + portDefn->format.video.nFrameWidth, + portDefn->format.video.nFrameHeight); + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + DEBUG_PRINT_LOW("i/p previous actual cnt = %u", m_sInPortDef.nBufferCountActual); + DEBUG_PRINT_LOW("i/p previous min cnt = %u", m_sInPortDef.nBufferCountMin); + DEBUG_PRINT_LOW("i/p previous buffersize = %u", m_sInPortDef.nBufferSize); + + memcpy(&m_sInPortDef, portDefn,sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); + + /* update the input buffer requirement */ + Ret = swvenc_get_buffer_req(&m_sInPortDef.nBufferCountMin, + &m_sInPortDef.nBufferCountActual, + &m_sInPortDef.nBufferSize, + &m_sInPortDef.nBufferAlignment, + portDefn->nPortIndex); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("ERROR: %s, swvenc_get_buffer_req failed (%d)", __FUNCTION__, + Ret); + RETURN(OMX_ErrorUndefined); + } + + if (portDefn->nBufferCountActual > m_sInPortDef.nBufferCountActual) + { + m_sInPortDef.nBufferCountActual = portDefn->nBufferCountActual; + } + if (portDefn->nBufferSize > m_sInPortDef.nBufferSize) + { + m_sInPortDef.nBufferSize = portDefn->nBufferSize; + } + + DEBUG_PRINT_LOW("i/p new actual cnt = %u", m_sInPortDef.nBufferCountActual); + DEBUG_PRINT_LOW("i/p new min cnt = %u", m_sInPortDef.nBufferCountMin); + DEBUG_PRINT_LOW("i/p new buffersize = %u", m_sInPortDef.nBufferSize); + } + else if (PORT_INDEX_OUT == portDefn->nPortIndex) + { + DEBUG_PRINT_LOW("o/p actual cnt requested = %u", portDefn->nBufferCountActual); + DEBUG_PRINT_LOW("o/p min cnt requested = %u", portDefn->nBufferCountMin); + DEBUG_PRINT_LOW("o/p buffersize requested = %u", portDefn->nBufferSize); + if (portDefn->nBufferCountMin > portDefn->nBufferCountActual) + { + DEBUG_PRINT_ERROR("ERROR: (Out_PORT) Min buffers (%u) > actual count (%u)", + portDefn->nBufferCountMin, portDefn->nBufferCountActual); + RETURN(OMX_ErrorUnsupportedSetting); + } + + /* set the output bit-rate */ + Ret = swvenc_set_bit_rate(portDefn->format.video.nBitrate); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_bit_rate failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + DEBUG_PRINT_LOW("o/p previous actual cnt = %u", m_sOutPortDef.nBufferCountActual); + DEBUG_PRINT_LOW("o/p previous min cnt = %u", m_sOutPortDef.nBufferCountMin); + DEBUG_PRINT_LOW("o/p previous buffersize = %u", m_sOutPortDef.nBufferSize); + + /* set the buffer requirement */ + bResult = dev_set_buf_req(&portDefn->nBufferCountMin, + &portDefn->nBufferCountActual, + &portDefn->nBufferSize, + portDefn->nPortIndex); + if (bResult != true) + { + DEBUG_PRINT_ERROR("%s, dev_set_buf_req failed", + __FUNCTION__); + RETURN(OMX_ErrorUnsupportedSetting); + } + memcpy(&m_sOutPortDef, portDefn,sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); + + /* update the output buffer requirement */ + Ret = swvenc_get_buffer_req(&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + &m_sOutPortDef.nBufferAlignment, + portDefn->nPortIndex); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("ERROR: %s, swvenc_get_buffer_req failed (%d)", __FUNCTION__, + Ret); + RETURN(OMX_ErrorUndefined); + } + + if (portDefn->nBufferCountActual > m_sOutPortDef.nBufferCountActual) + { + m_sOutPortDef.nBufferCountActual = portDefn->nBufferCountActual; + } + if (portDefn->nBufferSize > m_sOutPortDef.nBufferSize) + { + m_sOutPortDef.nBufferSize = portDefn->nBufferSize; + } + + DEBUG_PRINT_LOW("o/p new actual cnt = %u", m_sOutPortDef.nBufferCountActual); + DEBUG_PRINT_LOW("o/p new min cnt = %u", m_sOutPortDef.nBufferCountMin); + DEBUG_PRINT_LOW("o/p new buffersize = %u", m_sOutPortDef.nBufferSize); + } + else + { + DEBUG_PRINT_ERROR("ERROR: Set_parameter: Bad Port idx %d", + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + m_sConfigFramerate.xEncodeFramerate = portDefn->format.video.xFramerate; + m_sConfigBitrate.nEncodeBitrate = portDefn->format.video.nBitrate; + m_sParamBitrate.nTargetBitrate = portDefn->format.video.nBitrate; + break; + } + + case OMX_IndexParamVideoPortFormat: + { + OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoPortFormat %d", + portFmt->eColorFormat); + SWVENC_COLOR_FORMAT color_format; + + /* set the driver with the corresponding values */ + if (PORT_INDEX_IN == portFmt->nPortIndex) + { + if (portFmt->eColorFormat == + ((OMX_COLOR_FORMATTYPE) QOMX_COLOR_FormatAndroidOpaque)) + { + /* meta_mode = 2 (kMetadataBufferTypeGrallocSource) */ + m_sInPortFormat.eColorFormat = + (OMX_COLOR_FORMATTYPE) QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + color_format = SWVENC_COLOR_FORMAT_NV12; + if (!mUseProxyColorFormat) + { + if (!c2d_conv.init()) + { + DEBUG_PRINT_ERROR("C2D init failed"); + return OMX_ErrorUnsupportedSetting; + } + DEBUG_PRINT_ERROR("C2D init is successful"); + } + mUseProxyColorFormat = true; + m_input_msg_id = OMX_COMPONENT_GENERATE_ETB_OPQ; + } + else + { + m_sInPortFormat.eColorFormat = portFmt->eColorFormat; + if ((portFmt->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) || + (portFmt->eColorFormat == + ((OMX_COLOR_FORMATTYPE) QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m))) + { + color_format = SWVENC_COLOR_FORMAT_NV12; + } + else if (portFmt->eColorFormat == + ((OMX_COLOR_FORMATTYPE) QOMX_COLOR_FormatYVU420SemiPlanar)) + { + color_format = SWVENC_COLOR_FORMAT_NV21; + } + else + { + DEBUG_PRINT_ERROR("%s: OMX_IndexParamVideoPortFormat %d invalid", + __FUNCTION__, + portFmt->eColorFormat); + RETURN(OMX_ErrorBadParameter); + } + m_input_msg_id = OMX_COMPONENT_GENERATE_ETB; + mUseProxyColorFormat = false; + } + m_sInPortDef.format.video.eColorFormat = m_sInPortFormat.eColorFormat; + /* set the input color format */ + Prop.id = SWVENC_PROPERTY_ID_COLOR_FORMAT; + Prop.info.color_format = color_format; + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + /* set the input frame-rate */ + if (portFmt->xFramerate != 0) + { + Ret = swvenc_set_frame_rate(portFmt->xFramerate >> 16); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_frame_rate failed (%d)", + __FUNCTION__, Ret); + //RETURN(OMX_ErrorUnsupportedSetting); + } + m_sInPortFormat.xFramerate = portFmt->xFramerate; + } + } + break; + } + + case OMX_IndexParamVideoInit: + { + OMX_PORT_PARAM_TYPE* pParam = (OMX_PORT_PARAM_TYPE*)(paramData); + DEBUG_PRINT_LOW("Set OMX_IndexParamVideoInit called"); + break; + } + + case OMX_IndexParamVideoBitrate: + { + OMX_VIDEO_PARAM_BITRATETYPE* pParam = (OMX_VIDEO_PARAM_BITRATETYPE*)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoBitrate"); + + if (m_max_allowed_bitrate_check) + { + //TBD: to add bitrate check + } + + /* set the output bit-rate */ + Ret = swvenc_set_bit_rate(pParam->nTargetBitrate); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_bit_rate failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + /* set the RC-mode */ + Ret = swvenc_set_rc_mode(pParam->eControlRate); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_rc_mode failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + m_sParamBitrate.nTargetBitrate = pParam->nTargetBitrate; + m_sParamBitrate.eControlRate = pParam->eControlRate; + m_sConfigBitrate.nEncodeBitrate = pParam->nTargetBitrate; + m_sInPortDef.format.video.nBitrate = pParam->nTargetBitrate; + m_sOutPortDef.format.video.nBitrate = pParam->nTargetBitrate; + DEBUG_PRINT_LOW("bitrate = %u", m_sOutPortDef.format.video.nBitrate); + break; + } + + case OMX_IndexParamVideoMpeg4: + { + OMX_VIDEO_PARAM_MPEG4TYPE* pParam = (OMX_VIDEO_PARAM_MPEG4TYPE*)paramData; + + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoMpeg4"); + + if (pParam->nBFrames) + { + DEBUG_PRINT_ERROR("Warning: B frames not supported"); + } + + /* set the intra period */ + Ret = swvenc_set_intra_period(pParam->nPFrames,pParam->nBFrames); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_intra_period failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + memcpy(&m_sParamMPEG4,pParam, sizeof(struct OMX_VIDEO_PARAM_MPEG4TYPE)); + m_sIntraperiod.nPFrames = m_sParamMPEG4.nPFrames; + m_sIntraperiod.nBFrames = m_sParamMPEG4.nBFrames; + break; + } + + case OMX_IndexParamVideoH263: + { + OMX_VIDEO_PARAM_H263TYPE* pParam = (OMX_VIDEO_PARAM_H263TYPE*)paramData; + + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoH263"); + + /* set the intra period */ + Ret = swvenc_set_intra_period(pParam->nPFrames,pParam->nBFrames); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_intra_period failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + memcpy(&m_sParamH263,pParam, sizeof(struct OMX_VIDEO_PARAM_H263TYPE)); + m_sIntraperiod.nPFrames = m_sParamH263.nPFrames; + m_sIntraperiod.nBFrames = m_sParamH263.nBFrames; + break; + } + + case OMX_IndexParamVideoProfileLevelCurrent: + { + OMX_VIDEO_PARAM_PROFILELEVELTYPE* pParam = (OMX_VIDEO_PARAM_PROFILELEVELTYPE*)paramData; + + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoProfileLevelCurrent"); + + /* set the profile and level */ + Ret = swvenc_set_profile_level(pParam->eProfile,pParam->eLevel); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_rc_mode failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + + m_sParamProfileLevel.eProfile = pParam->eProfile; + m_sParamProfileLevel.eLevel = pParam->eLevel; + + if (SWVENC_CODEC_MPEG4 == m_codec) + { + m_sParamMPEG4.eProfile = (OMX_VIDEO_MPEG4PROFILETYPE)m_sParamProfileLevel.eProfile; + m_sParamMPEG4.eLevel = (OMX_VIDEO_MPEG4LEVELTYPE)m_sParamProfileLevel.eLevel; + DEBUG_PRINT_LOW("MPEG4 profile = %d, level = %d", m_sParamMPEG4.eProfile, + m_sParamMPEG4.eLevel); + } + else if (SWVENC_CODEC_H263 == m_codec) + { + m_sParamH263.eProfile = (OMX_VIDEO_H263PROFILETYPE)m_sParamProfileLevel.eProfile; + m_sParamH263.eLevel = (OMX_VIDEO_H263LEVELTYPE)m_sParamProfileLevel.eLevel; + DEBUG_PRINT_LOW("H263 profile = %d, level = %d", m_sParamH263.eProfile, + m_sParamH263.eLevel); + } + break; + } + + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *comp_role; + comp_role = (OMX_PARAM_COMPONENTROLETYPE *) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamStandardComponentRole %s", + comp_role->cRole); + + if ((m_state == OMX_StateLoaded)&& + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + { + DEBUG_PRINT_LOW("Set Parameter called in valid state"); + } + else + { + DEBUG_PRINT_ERROR("Set Parameter called in Invalid State"); + RETURN(OMX_ErrorIncorrectStateOperation); + } + + if (SWVENC_CODEC_MPEG4 == m_codec) + { + if (!strncmp((const char*)comp_role->cRole,"video_encoder.mpeg4",OMX_MAX_STRINGNAME_SIZE)) + { + strlcpy((char*)m_cRole,"video_encoder.mpeg4",OMX_MAX_STRINGNAME_SIZE); + } + else + { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown Index %s", comp_role->cRole); + eRet = OMX_ErrorUnsupportedSetting; + } + } + else if (SWVENC_CODEC_H263 == m_codec) + { + if (!strncmp((const char*)comp_role->cRole,"video_encoder.h263",OMX_MAX_STRINGNAME_SIZE)) + { + strlcpy((char*)m_cRole,"video_encoder.h263",OMX_MAX_STRINGNAME_SIZE); + } + else + { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } + else + { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown param %s", m_nkind); + eRet = OMX_ErrorInvalidComponentName; + } + break; + } + + case OMX_IndexParamPriorityMgmt: + { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPriorityMgmt"); + if (m_state != OMX_StateLoaded) { + DEBUG_PRINT_ERROR("ERROR: Set Parameter called in Invalid State"); + RETURN(OMX_ErrorIncorrectStateOperation); + } + OMX_PRIORITYMGMTTYPE *priorityMgmtype = (OMX_PRIORITYMGMTTYPE*) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPriorityMgmt %u", + priorityMgmtype->nGroupID); + + DEBUG_PRINT_LOW("set_parameter: priorityMgmtype %u", + priorityMgmtype->nGroupPriority); + + m_sPriorityMgmt.nGroupID = priorityMgmtype->nGroupID; + m_sPriorityMgmt.nGroupPriority = priorityMgmtype->nGroupPriority; + + break; + } + + case OMX_IndexParamCompBufferSupplier: + { + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamCompBufferSupplier"); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamCompBufferSupplier %d", + bufferSupplierType->eBufferSupplier); + if ( (bufferSupplierType->nPortIndex == 0) || + (bufferSupplierType->nPortIndex ==1) + ) + { + m_sInBufSupplier.eBufferSupplier = bufferSupplierType->eBufferSupplier; + } + else + { + eRet = OMX_ErrorBadPortIndex; + } + + break; + + } + + case OMX_IndexParamVideoQuantization: + { + // this is applicable only for RC-off case + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoQuantization"); + OMX_VIDEO_PARAM_QUANTIZATIONTYPE *session_qp = (OMX_VIDEO_PARAM_QUANTIZATIONTYPE*) paramData; + if (session_qp->nPortIndex == PORT_INDEX_OUT) + { + Prop.id = SWVENC_PROPERTY_ID_QP; + Prop.info.qp.qp_i = session_qp->nQpI; + Prop.info.qp.qp_p = session_qp->nQpP; + Prop.info.qp.qp_b = session_qp->nQpB; + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + m_sSessionQuantization.nQpI = session_qp->nQpI; + m_sSessionQuantization.nQpP = session_qp->nQpP; + m_sSessionQuantization.nQpB = session_qp->nQpB; + } + else + { + DEBUG_PRINT_ERROR("ERROR: Unsupported port Index for Session QP setting"); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_QcomIndexParamVideoQPRange: + { + DEBUG_PRINT_LOW("set_parameter: OMX_QcomIndexParamVideoQPRange"); + OMX_QCOM_VIDEO_PARAM_QPRANGETYPE *qp_range = (OMX_QCOM_VIDEO_PARAM_QPRANGETYPE*) paramData; + if (qp_range->nPortIndex == PORT_INDEX_OUT) + { + if ( (qp_range->minQP > 255) || + (qp_range->maxQP > 255) + ) + { + DEBUG_PRINT_ERROR("ERROR: Out of range QP"); + eRet = OMX_ErrorBadParameter; + } + + Prop.id = SWVENC_PROPERTY_ID_QP_RANGE; + Prop.info.qp_range.min_qp_packed = + (qp_range->minQP << 16) | (qp_range->minQP) | (qp_range->minQP << 8); + Prop.info.qp_range.max_qp_packed = + (qp_range->maxQP << 16) | (qp_range->maxQP) | (qp_range->maxQP << 8); + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + m_sSessionQPRange.minQP= qp_range->minQP; + m_sSessionQPRange.maxQP= qp_range->maxQP; + } + else + { + DEBUG_PRINT_ERROR("ERROR: Unsupported port Index for QP range setting"); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_QcomIndexPortDefn: + { + OMX_QCOM_PARAM_PORTDEFINITIONTYPE* pParam = + (OMX_QCOM_PARAM_PORTDEFINITIONTYPE*)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_QcomIndexPortDefn"); + if (pParam->nPortIndex == (OMX_U32)PORT_INDEX_IN) + { + if (pParam->nMemRegion > OMX_QCOM_MemRegionInvalid && + pParam->nMemRegion < OMX_QCOM_MemRegionMax) + { + m_use_input_pmem = OMX_TRUE; + } + else + { + m_use_input_pmem = OMX_FALSE; + } + } + else if (pParam->nPortIndex == (OMX_U32)PORT_INDEX_OUT) + { + if (pParam->nMemRegion > OMX_QCOM_MemRegionInvalid && + pParam->nMemRegion < OMX_QCOM_MemRegionMax) + { + m_use_output_pmem = OMX_TRUE; + } + else + { + m_use_output_pmem = OMX_FALSE; + } + } + else + { + DEBUG_PRINT_ERROR("ERROR: SetParameter called on unsupported Port Index for QcomPortDefn"); + RETURN(OMX_ErrorBadPortIndex); + } + break; + } + + case OMX_IndexParamVideoErrorCorrection: + { + DEBUG_PRINT_LOW("OMX_IndexParamVideoErrorCorrection"); + OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE* pParam = + (OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE*)paramData; + + /* HEC */ + if (m_codec == SWVENC_CODEC_MPEG4) + { + Prop.id = SWVENC_PROPERTY_ID_MPEG4_HEC; + Prop.info.mpeg4_hec = pParam->bEnableHEC; + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUndefined); + } + + /* Data partitioning */ + Prop.id = SWVENC_PROPERTY_ID_MPEG4_DP; + Prop.info.mpeg4_dp = pParam->bEnableDataPartitioning; + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUndefined); + } + } + + /* RVLC */ + if (pParam->bEnableRVLC) + { + DEBUG_PRINT_ERROR("%s, RVLC not support", __FUNCTION__); + } + + /* Re-sync Marker */ + Prop.id = SWVENC_PROPERTY_ID_SLICE_CONFIG; + if ( (m_codec != SWVENC_CODEC_H263) && (pParam->bEnableDataPartitioning) ) + { + DEBUG_PRINT_ERROR("DataPartioning are not Supported for this codec"); + break; + } + if ( (m_codec != SWVENC_CODEC_H263) && (pParam->nResynchMarkerSpacing) ) + { + Prop.info.slice_config.mode = SWVENC_SLICE_MODE_BYTE; + Prop.info.slice_config.size = pParam->nResynchMarkerSpacing; + } + else if ( (SWVENC_CODEC_H263 == m_codec) && (pParam->bEnableResync) ) + { + Prop.info.slice_config.mode = SWVENC_SLICE_MODE_GOB; + Prop.info.slice_config.size = 0; + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUndefined); + } + } + else + { + Prop.info.slice_config.mode = SWVENC_SLICE_MODE_OFF; + Prop.info.slice_config.size = 0; + } + + memcpy(&m_sErrorCorrection,pParam, sizeof(m_sErrorCorrection)); + break; + } + + case OMX_IndexParamVideoIntraRefresh: + { + DEBUG_PRINT_LOW("set_param:OMX_IndexParamVideoIntraRefresh"); + OMX_VIDEO_PARAM_INTRAREFRESHTYPE* pParam = + (OMX_VIDEO_PARAM_INTRAREFRESHTYPE*)paramData; + + Ret = swvenc_set_intra_refresh(pParam); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_intra_refresh failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + + memcpy(&m_sIntraRefresh, pParam, sizeof(m_sIntraRefresh)); + break; + } + + case OMX_QcomIndexParamVideoMetaBufferMode: + { + StoreMetaDataInBuffersParams *pParam = + (StoreMetaDataInBuffersParams*)paramData; + DEBUG_PRINT_HIGH("set_parameter:OMX_QcomIndexParamVideoMetaBufferMode: " + "port_index = %u, meta_mode = %d", pParam->nPortIndex, pParam->bStoreMetaData); + + if (pParam->nPortIndex == PORT_INDEX_IN) + { + if (pParam->bStoreMetaData != meta_mode_enable) + { + meta_mode_enable = pParam->bStoreMetaData; + if (!meta_mode_enable) + { + Ret = swvenc_get_buffer_req(&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + &m_sOutPortDef.nBufferAlignment, + m_sOutPortDef.nPortIndex); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("ERROR: %s, swvenc_get_buffer_req failed (%d)", __FUNCTION__, + Ret); + eRet = OMX_ErrorUndefined; + break; + } + } + } + } + else if (pParam->nPortIndex == PORT_INDEX_OUT && secure_session) + { + if (pParam->bStoreMetaData != meta_mode_enable) + { + meta_mode_enable = pParam->bStoreMetaData; + } + } + else + { + if (pParam->bStoreMetaData) + { + DEBUG_PRINT_ERROR("set_parameter: metamode is " + "valid for input port only"); + eRet = OMX_ErrorUnsupportedIndex; + } + } + } + break; + + case OMX_QcomIndexParamIndexExtraDataType: + { + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexParamIndexExtraDataType"); + QOMX_INDEXEXTRADATATYPE *pParam = (QOMX_INDEXEXTRADATATYPE *)paramData; + OMX_U32 mask = 0; + + if (pParam->nIndex == (OMX_INDEXTYPE)OMX_ExtraDataVideoEncoderSliceInfo) + { + if (pParam->nPortIndex == PORT_INDEX_OUT) + { + mask = VEN_EXTRADATA_SLICEINFO; + + DEBUG_PRINT_HIGH("SliceInfo extradata %s", + ((pParam->bEnabled == OMX_TRUE) ? "enabled" : "disabled")); + } + else + { + DEBUG_PRINT_ERROR("set_parameter: Slice information is " + "valid for output port only"); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + } + else if (pParam->nIndex == (OMX_INDEXTYPE)OMX_ExtraDataVideoEncoderMBInfo) + { + if (pParam->nPortIndex == PORT_INDEX_OUT) + { + mask = VEN_EXTRADATA_MBINFO; + + DEBUG_PRINT_HIGH("MBInfo extradata %s", + ((pParam->bEnabled == OMX_TRUE) ? "enabled" : "disabled")); + } + else + { + DEBUG_PRINT_ERROR("set_parameter: MB information is " + "valid for output port only"); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + } + else + { + DEBUG_PRINT_ERROR("set_parameter: unsupported extrdata index (%x)", + pParam->nIndex); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + + + if (pParam->bEnabled == OMX_TRUE) + { + m_sExtraData |= mask; + } + else + { + m_sExtraData &= ~mask; + } + + #if 0 + // TBD: add setprop to swvenc once the support is added + if (handle->venc_set_param((OMX_PTR)!!(m_sExtraData & mask), + (OMX_INDEXTYPE)pParam->nIndex) != true) + { + DEBUG_PRINT_ERROR("ERROR: Setting Extradata (%x) failed", pParam->nIndex); + RETURN(OMX_ErrorUnsupportedSetting); + } + else + #endif + { + m_sOutPortDef.nPortIndex = PORT_INDEX_OUT; + bResult = dev_get_buf_req(&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + m_sOutPortDef.nPortIndex); + if (false == bResult) + { + DEBUG_PRINT_ERROR("dev_get_buf_req failed"); + eRet = OMX_ErrorUndefined; + break; + } + + DEBUG_PRINT_HIGH("updated out_buf_req: buffer cnt=%u, " + "count min=%u, buffer size=%u", + m_sOutPortDef.nBufferCountActual, + m_sOutPortDef.nBufferCountMin, + m_sOutPortDef.nBufferSize); + } + break; + } + + case OMX_QcomIndexParamVideoMaxAllowedBitrateCheck: + { + QOMX_EXTNINDEX_PARAMTYPE* pParam = + (QOMX_EXTNINDEX_PARAMTYPE*)paramData; + if (pParam->nPortIndex == PORT_INDEX_OUT) + { + m_max_allowed_bitrate_check = + ((pParam->bEnable == OMX_TRUE) ? true : false); + DEBUG_PRINT_HIGH("set_parameter: max allowed bitrate check %s", + ((pParam->bEnable == OMX_TRUE) ? "enabled" : "disabled")); + } + else + { + DEBUG_PRINT_ERROR("ERROR: OMX_QcomIndexParamVideoMaxAllowedBitrateCheck " + " called on wrong port(%u)", pParam->nPortIndex); + RETURN(OMX_ErrorBadPortIndex); + } + break; + } + + case OMX_QcomIndexEnableSliceDeliveryMode: + { + QOMX_EXTNINDEX_PARAMTYPE* pParam = + (QOMX_EXTNINDEX_PARAMTYPE*)paramData; + if (pParam->nPortIndex == PORT_INDEX_OUT) + { + //TBD: add setprop to swvenc once the support is added + #if 0 + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexEnableSliceDeliveryMode)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting slice delivery mode failed"); + RETURN( OMX_ErrorUnsupportedSetting; + } + #endif + { + DEBUG_PRINT_ERROR("ERROR: Request for setting slice delivery mode failed"); + RETURN(OMX_ErrorUnsupportedSetting); + } + } + else + { + DEBUG_PRINT_ERROR("ERROR: OMX_QcomIndexEnableSliceDeliveryMode " + "called on wrong port(%u)", pParam->nPortIndex); + RETURN(OMX_ErrorBadPortIndex); + } + break; + } + + case OMX_QcomIndexEnableH263PlusPType: + { + QOMX_EXTNINDEX_PARAMTYPE* pParam = + (QOMX_EXTNINDEX_PARAMTYPE*)paramData; + DEBUG_PRINT_LOW("OMX_QcomIndexEnableH263PlusPType"); + if (pParam->nPortIndex == PORT_INDEX_OUT) + { + DEBUG_PRINT_ERROR("ERROR: Request for setting PlusPType failed"); + RETURN(OMX_ErrorUnsupportedSetting); + } + else + { + DEBUG_PRINT_ERROR("ERROR: OMX_QcomIndexEnableH263PlusPType " + "called on wrong port(%u)", pParam->nPortIndex); + RETURN(OMX_ErrorBadPortIndex); + } + break; + } + + case OMX_QcomIndexParamPeakBitrate: + { + DEBUG_PRINT_ERROR("ERROR: Setting peak bitrate"); + RETURN(OMX_ErrorUnsupportedSetting); + break; + } + + case QOMX_IndexParamVideoInitialQp: + { + // TBD: applicable to RC-on case only + DEBUG_PRINT_ERROR("ERROR: Setting Initial QP for RC-on case"); + RETURN(OMX_ErrorNone); + break; + } + + + case OMX_QcomIndexParamSetMVSearchrange: + { + DEBUG_PRINT_ERROR("ERROR: Setting Searchrange"); + RETURN(OMX_ErrorUnsupportedSetting); + break; + } + + default: + { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown param %d", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + } + + RETURN(eRet); +} + +OMX_ERRORTYPE omx_venc::set_config +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_IN OMX_PTR configData +) +{ + ENTER_FUNC(); + + SWVENC_STATUS SwStatus; + + (void)hComp; + + if (configData == NULL) + { + DEBUG_PRINT_ERROR("ERROR: param is null"); + RETURN(OMX_ErrorBadParameter); + } + + if (m_state == OMX_StateInvalid) + { + DEBUG_PRINT_ERROR("ERROR: config called in Invalid state"); + RETURN(OMX_ErrorIncorrectStateOperation); + } + + switch ((int)configIndex) + { + case OMX_IndexConfigVideoBitrate: + { + OMX_VIDEO_CONFIG_BITRATETYPE* pParam = + reinterpret_cast<OMX_VIDEO_CONFIG_BITRATETYPE*>(configData); + DEBUG_PRINT_HIGH("set_config(): OMX_IndexConfigVideoBitrate (%u)", pParam->nEncodeBitrate); + + if (pParam->nPortIndex == PORT_INDEX_OUT) + { + SwStatus = swvenc_set_bit_rate(pParam->nEncodeBitrate); + if (SwStatus != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_bit_rate failed (%d)", + __FUNCTION__, SwStatus); + RETURN(OMX_ErrorUnsupportedSetting); + } + + m_sConfigBitrate.nEncodeBitrate = pParam->nEncodeBitrate; + m_sParamBitrate.nTargetBitrate = pParam->nEncodeBitrate; + m_sOutPortDef.format.video.nBitrate = pParam->nEncodeBitrate; + } + else + { + DEBUG_PRINT_ERROR("ERROR: Unsupported port index: %u", pParam->nPortIndex); + RETURN(OMX_ErrorBadPortIndex); + } + break; + } + case OMX_IndexConfigVideoFramerate: + { + OMX_CONFIG_FRAMERATETYPE* pParam = + reinterpret_cast<OMX_CONFIG_FRAMERATETYPE*>(configData); + DEBUG_PRINT_HIGH("set_config(): OMX_IndexConfigVideoFramerate (0x%x)", pParam->xEncodeFramerate); + + if (pParam->nPortIndex == PORT_INDEX_OUT) + { + SwStatus = swvenc_set_frame_rate(pParam->xEncodeFramerate >> 16); + if (SwStatus != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_frame_rate failed (%d)", + __FUNCTION__, SwStatus); + RETURN(OMX_ErrorUnsupportedSetting); + } + + m_sConfigFramerate.xEncodeFramerate = pParam->xEncodeFramerate; + m_sOutPortDef.format.video.xFramerate = pParam->xEncodeFramerate; + m_sOutPortFormat.xFramerate = pParam->xEncodeFramerate; + } + else + { + DEBUG_PRINT_ERROR("ERROR: Unsupported port index: %u", pParam->nPortIndex); + RETURN(OMX_ErrorBadPortIndex); + } + break; + } + case QOMX_IndexConfigVideoIntraperiod: + { + QOMX_VIDEO_INTRAPERIODTYPE* pParam = + reinterpret_cast<QOMX_VIDEO_INTRAPERIODTYPE*>(configData); + DEBUG_PRINT_HIGH("set_config(): QOMX_IndexConfigVideoIntraperiod"); + + if (pParam->nPortIndex == PORT_INDEX_OUT) + { + if (pParam->nBFrames > 0) + { + DEBUG_PRINT_ERROR("B frames not supported"); + RETURN(OMX_ErrorUnsupportedSetting); + } + + DEBUG_PRINT_HIGH("Old: P/B frames = %u/%u, New: P/B frames = %u/%u", + m_sIntraperiod.nPFrames, m_sIntraperiod.nBFrames, + pParam->nPFrames, pParam->nBFrames); + if (m_sIntraperiod.nBFrames != pParam->nBFrames) + { + DEBUG_PRINT_HIGH("Dynamically changing B-frames not supported"); + RETURN(OMX_ErrorUnsupportedSetting); + } + + /* set the intra period */ + SwStatus = swvenc_set_intra_period(pParam->nPFrames,pParam->nBFrames); + if (SwStatus != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_set_intra_period failed (%d)", + __FUNCTION__, SwStatus); + RETURN(OMX_ErrorUnsupportedSetting); + } + + m_sIntraperiod.nPFrames = pParam->nPFrames; + m_sIntraperiod.nBFrames = pParam->nBFrames; + m_sIntraperiod.nIDRPeriod = pParam->nIDRPeriod; + + if (m_sOutPortFormat.eCompressionFormat == OMX_VIDEO_CodingMPEG4) + { + m_sParamMPEG4.nPFrames = pParam->nPFrames; + if (m_sParamMPEG4.eProfile != OMX_VIDEO_MPEG4ProfileSimple) + { + m_sParamMPEG4.nBFrames = pParam->nBFrames; + } + else + { + m_sParamMPEG4.nBFrames = 0; + } + } + else if (m_sOutPortFormat.eCompressionFormat == OMX_VIDEO_CodingH263) + { + m_sParamH263.nPFrames = pParam->nPFrames; + } + } + else + { + DEBUG_PRINT_ERROR("ERROR: (QOMX_IndexConfigVideoIntraperiod) Unsupported port index: %u", pParam->nPortIndex); + RETURN(OMX_ErrorBadPortIndex); + } + + break; + } + case OMX_IndexConfigVideoIntraVOPRefresh: + { + OMX_CONFIG_INTRAREFRESHVOPTYPE* pParam = + reinterpret_cast<OMX_CONFIG_INTRAREFRESHVOPTYPE*>(configData); + DEBUG_PRINT_HIGH("set_config(): OMX_IndexConfigVideoIntraVOPRefresh"); + + if (pParam->nPortIndex == PORT_INDEX_OUT) + { + + SWVENC_PROPERTY Prop; + + Prop.id = SWVENC_PROPERTY_ID_IFRAME_REQUEST; + + SwStatus = swvenc_setproperty(m_hSwVenc, &Prop); + if (SwStatus != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, SwStatus); + RETURN(OMX_ErrorUnsupportedSetting); + } + + m_sConfigIntraRefreshVOP.IntraRefreshVOP = pParam->IntraRefreshVOP; + } + else + { + DEBUG_PRINT_ERROR("ERROR: Unsupported port index: %u", pParam->nPortIndex); + RETURN(OMX_ErrorBadPortIndex); + } + break; + } + case OMX_IndexConfigCommonRotate: + { + DEBUG_PRINT_ERROR("ERROR: OMX_IndexConfigCommonRotate not supported"); + RETURN(OMX_ErrorUnsupportedSetting); + break; + } + default: + DEBUG_PRINT_ERROR("ERROR: unsupported index %d", (int) configIndex); + RETURN(OMX_ErrorUnsupportedSetting); + break; + } + + EXIT_FUNC(); + + RETURN(OMX_ErrorNone); +} + +OMX_ERRORTYPE omx_venc::component_deinit(OMX_IN OMX_HANDLETYPE hComp) +{ + ENTER_FUNC(); + + OMX_U32 i = 0; + DEBUG_PRINT_HIGH("omx_venc(): Inside component_deinit()"); + + (void)hComp; + + if (OMX_StateLoaded != m_state) + { + DEBUG_PRINT_ERROR("WARNING:Rxd DeInit,OMX not in LOADED state %d", + m_state); + } + if (m_out_mem_ptr) + { + DEBUG_PRINT_LOW("Freeing the Output Memory"); + for (i=0; i< m_sOutPortDef.nBufferCountActual; i++ ) + { + free_output_buffer (&m_out_mem_ptr[i]); + } + free(m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + + /* Check if the input buffers have to be cleaned up */ + if ( m_inp_mem_ptr && !meta_mode_enable ) + { + DEBUG_PRINT_LOW("Freeing the Input Memory"); + for (i=0; i<m_sInPortDef.nBufferCountActual; i++) + { + free_input_buffer (&m_inp_mem_ptr[i]); + } + + free(m_inp_mem_ptr); + m_inp_mem_ptr = NULL; + } + + /* Reset counters in msg queues */ + m_ftb_q.m_size=0; + m_cmd_q.m_size=0; + m_etb_q.m_size=0; + m_ftb_q.m_read = m_ftb_q.m_write =0; + m_cmd_q.m_read = m_cmd_q.m_write =0; + m_etb_q.m_read = m_etb_q.m_write =0; + + /* Clear the strong reference */ + DEBUG_PRINT_HIGH("Calling m_heap_ptr.clear()"); + m_heap_ptr.clear(); + + DEBUG_PRINT_HIGH("Calling swvenc_deinit()"); + swvenc_deinit(m_hSwVenc); + + DEBUG_PRINT_HIGH("OMX_Venc:Component Deinit"); + + RETURN(OMX_ErrorNone); +} + +OMX_U32 omx_venc::dev_stop(void) +{ + ENTER_FUNC(); + + SWVENC_STATUS Ret; + + if (false == m_stopped) + { + Ret = swvenc_stop(m_hSwVenc); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_stop failed (%d)", + __FUNCTION__, Ret); + RETURN(-1); + } + set_format = false; + m_stopped = true; + + /* post STOP_DONE event as start is synchronus */ + post_event (0, OMX_ErrorNone, OMX_COMPONENT_GENERATE_STOP_DONE); + } + + RETURN(0); +} + +OMX_U32 omx_venc::dev_pause(void) +{ + ENTER_FUNC(); + // nothing to be done for sw encoder + + RETURN(true); +} + +OMX_U32 omx_venc::dev_resume(void) +{ + ENTER_FUNC(); + // nothing to be done for sw encoder + + RETURN(true); +} + +OMX_U32 omx_venc::dev_start(void) +{ + ENTER_FUNC(); + SWVENC_STATUS Ret; + Ret = swvenc_start(m_hSwVenc); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_start failed (%d)", + __FUNCTION__, Ret); + RETURN(-1); + } + + m_stopped = false; + + RETURN(0); +} + +OMX_U32 omx_venc::dev_flush(unsigned port) +{ + ENTER_FUNC(); + SWVENC_STATUS Ret; + + (void)port; + Ret = swvenc_flush(m_hSwVenc); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_flush failed (%d)", + __FUNCTION__, Ret); + RETURN(-1); + } + + RETURN(0); +} + +OMX_U32 omx_venc::dev_start_done(void) +{ + ENTER_FUNC(); + + /* post START_DONE event as start is synchronus */ + post_event (0, OMX_ErrorNone, OMX_COMPONENT_GENERATE_START_DONE); + + RETURN(0); +} + +OMX_U32 omx_venc::dev_set_message_thread_id(pthread_t tid) +{ + ENTER_FUNC(); + + // nothing to be done for sw encoder + (void)tid; + + RETURN(true); +} + +bool omx_venc::dev_use_buf(void *buf_addr,unsigned port,unsigned index) +{ + ENTER_FUNC(); + + (void)buf_addr; + (void)port; + (void)index; + + RETURN(true); +} + +bool omx_venc::dev_free_buf(void *buf_addr,unsigned port) +{ + ENTER_FUNC(); + + (void)buf_addr; + (void)port; + + RETURN(true); +} + +bool omx_venc::dev_empty_buf +( + void *buffer, + void *pmem_data_buf, + unsigned index, + unsigned fd +) +{ + ENTER_FUNC(); + + SWVENC_STATUS Ret; + SWVENC_IPBUFFER ipbuffer; + OMX_BUFFERHEADERTYPE *bufhdr = (OMX_BUFFERHEADERTYPE *)buffer; + unsigned int size = 0, filled_length, offset = 0; + SWVENC_COLOR_FORMAT color_format; + SWVENC_PROPERTY prop; + + (void)pmem_data_buf; + (void)index; + + if (meta_mode_enable) + { + LEGACY_CAM_METADATA_TYPE *meta_buf = NULL; + meta_buf = (LEGACY_CAM_METADATA_TYPE *)bufhdr->pBuffer; + if(m_sInPortDef.format.video.eColorFormat == ((OMX_COLOR_FORMATTYPE) QOMX_COLOR_FormatAndroidOpaque)) + { + DEBUG_PRINT_LOW("dev_empty_buf: color_format is QOMX_COLOR_FormatAndroidOpaque"); + set_format = true; + } + if(!meta_buf) + { + if (!bufhdr->nFilledLen && (bufhdr->nFlags & OMX_BUFFERFLAG_EOS)) + { + ipbuffer.p_buffer= bufhdr->pBuffer; + ipbuffer.size = bufhdr->nAllocLen; + ipbuffer.filled_length = bufhdr->nFilledLen; + DEBUG_PRINT_LOW("dev_empty_buf: empty EOS buffer"); + } + else + { + return false; + } + } + else + { + if (meta_buf->buffer_type == LEGACY_CAM_SOURCE) + { + offset = meta_buf->meta_handle->data[1]; + size = meta_buf->meta_handle->data[2]; + if (set_format && (meta_buf->meta_handle->numFds + meta_buf->meta_handle->numInts > 5)) + { + m_sInPortFormat.eColorFormat = (OMX_COLOR_FORMATTYPE)meta_buf->meta_handle->data[5]; + } + ipbuffer.p_buffer = (unsigned char *)mmap(NULL, size, PROT_READ|PROT_WRITE,MAP_SHARED, fd, offset); + if (ipbuffer.p_buffer == MAP_FAILED) + { + DEBUG_PRINT_ERROR("mmap() failed for fd %d of size %d",fd,size); + RETURN(OMX_ErrorBadParameter); + } + ipbuffer.size = size; + ipbuffer.filled_length = size; + } + else if (meta_buf->buffer_type == kMetadataBufferTypeGrallocSource) + { + VideoGrallocMetadata *meta_buf = (VideoGrallocMetadata *)bufhdr->pBuffer; + private_handle_t *handle = (private_handle_t *)meta_buf->pHandle; + size = handle->size; + if(set_format) + { + DEBUG_PRINT_LOW("color format = 0x%x",handle->format); + if (((OMX_COLOR_FORMATTYPE)handle->format) != m_sInPortFormat.eColorFormat) + { + if(handle->format == HAL_PIXEL_FORMAT_NV12_ENCODEABLE) + { + m_sInPortFormat.eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + } + else + { + DEBUG_PRINT_ERROR("%s: OMX_IndexParamVideoPortFormat 0x%x invalid", + __FUNCTION__,handle->format); + RETURN(OMX_ErrorBadParameter); + } + } + } + ipbuffer.p_buffer = (unsigned char *)mmap(NULL, size, PROT_READ|PROT_WRITE,MAP_SHARED, fd, offset); + if (ipbuffer.p_buffer == MAP_FAILED) + { + DEBUG_PRINT_ERROR("mmap() failed for fd %d of size %d",fd,size); + RETURN(OMX_ErrorBadParameter); + } + ipbuffer.size = size; + ipbuffer.filled_length = size; + } + else + { + //handles the use case for surface encode + ipbuffer.p_buffer = bufhdr->pBuffer; + ipbuffer.size = bufhdr->nAllocLen; + ipbuffer.filled_length = bufhdr->nFilledLen; + } + if (set_format) + { + set_format = false; + m_sInPortDef.format.video.eColorFormat = m_sInPortFormat.eColorFormat; + Ret = swvenc_set_color_format(m_sInPortFormat.eColorFormat); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(OMX_ErrorUnsupportedSetting); + } + } + } + } + else + { + ipbuffer.p_buffer = bufhdr->pBuffer; + ipbuffer.size = bufhdr->nAllocLen; + ipbuffer.filled_length = bufhdr->nFilledLen; + } + ipbuffer.flags = 0; + if (bufhdr->nFlags & OMX_BUFFERFLAG_EOS) + { + ipbuffer.flags |= SWVENC_FLAG_EOS; + } + ipbuffer.timestamp = bufhdr->nTimeStamp; + ipbuffer.p_client_data = (unsigned char *)bufhdr; + + DEBUG_PRINT_LOW("ETB: p_buffer (%p) size (%d) filled_len (%d) flags (0x%X) timestamp (%lld) clientData (%p)", + ipbuffer.p_buffer, + ipbuffer.size, + ipbuffer.filled_length, + (unsigned int)ipbuffer.flags, + ipbuffer.timestamp, + ipbuffer.p_client_data); + + Ret = swvenc_emptythisbuffer(m_hSwVenc, &ipbuffer); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_emptythisbuffer failed (%d)", + __FUNCTION__, Ret); + RETURN(false); + } + + if (m_debug.in_buffer_log) + { + swvenc_input_log_buffers((const char*)ipbuffer.p_buffer, ipbuffer.filled_length); + } + + RETURN(true); +} + +bool omx_venc::dev_fill_buf +( + void *buffer, + void *pmem_data_buf, + unsigned index, + unsigned fd +) +{ + ENTER_FUNC(); + + SWVENC_STATUS Ret; + + SWVENC_OPBUFFER opbuffer; + OMX_BUFFERHEADERTYPE *bufhdr = (OMX_BUFFERHEADERTYPE *)buffer; + + (void)pmem_data_buf; + (void)index; + (void)fd; + + opbuffer.p_buffer = bufhdr->pBuffer; + opbuffer.size = bufhdr->nAllocLen; + opbuffer.filled_length = bufhdr->nFilledLen; + opbuffer.flags = bufhdr->nFlags; + opbuffer.p_client_data = (unsigned char *)bufhdr; + + DEBUG_PRINT_LOW("FTB: p_buffer (%p) size (%d) filled_len (%d) flags (0x%X) timestamp (%lld) clientData (%p)", + opbuffer.p_buffer, + opbuffer.size, + opbuffer.filled_length, + opbuffer.flags, + opbuffer.timestamp, + opbuffer.p_client_data); + + if ( false == m_bSeqHdrRequested) + { + if (dev_get_seq_hdr(opbuffer.p_buffer, opbuffer.size, &opbuffer.filled_length) == 0) + { + bufhdr->nFilledLen = opbuffer.filled_length; + bufhdr->nOffset = 0; + bufhdr->nTimeStamp = 0; + bufhdr->nFlags = OMX_BUFFERFLAG_CODECCONFIG; + + DEBUG_PRINT_LOW("sending FBD with codec config"); + m_bSeqHdrRequested = true; + post_event ((unsigned long)bufhdr,0,OMX_COMPONENT_GENERATE_FBD); + } + else + { + DEBUG_PRINT_ERROR("ERROR: couldn't get sequence header"); + post_event(OMX_EventError,OMX_ErrorUndefined,OMX_COMPONENT_GENERATE_EVENT); + } + } + else + { + Ret = swvenc_fillthisbuffer(m_hSwVenc, &opbuffer); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_fillthisbuffer failed (%d)", + __FUNCTION__, Ret); + RETURN(false); + } + } + + RETURN(true); +} + +bool omx_venc::dev_get_seq_hdr +( + void *buffer, + unsigned size, + unsigned *hdrlen +) +{ + ENTER_FUNC(); + + SWVENC_STATUS Ret; + SWVENC_OPBUFFER Buffer; + + Buffer.p_buffer = (unsigned char*) buffer; + Buffer.size = size; + + Ret = swvenc_getsequenceheader(m_hSwVenc, &Buffer); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_flush failed (%d)", + __FUNCTION__, Ret); + RETURN(-1); + } + + *hdrlen = Buffer.filled_length; + + RETURN(0); +} + +bool omx_venc::dev_get_capability_ltrcount +( + OMX_U32 *min, + OMX_U32 *max, + OMX_U32 *step_size +) +{ + ENTER_FUNC(); + + (void)min; + (void)max; + (void)step_size; + + DEBUG_PRINT_ERROR("Get Capability LTR Count is not supported"); + + RETURN(false); +} + +bool omx_venc::dev_get_performance_level(OMX_U32 *perflevel) +{ + ENTER_FUNC(); + + (void)perflevel; + DEBUG_PRINT_ERROR("Get performance level is not supported"); + + RETURN(false); +} + +bool omx_venc::dev_get_vui_timing_info(OMX_U32 *enabled) +{ + ENTER_FUNC(); + + (void)enabled; + DEBUG_PRINT_ERROR("Get vui timing information is not supported"); + + RETURN(false); +} + +bool omx_venc::dev_get_vqzip_sei_info(OMX_U32 *enabled) +{ + ENTER_FUNC(); + + (void)enabled; + DEBUG_PRINT_ERROR("Get vqzip sei info is not supported"); + + RETURN(false); +} + +bool omx_venc::dev_get_peak_bitrate(OMX_U32 *peakbitrate) +{ + //TBD: store the peak bitrate in class and return here; + ENTER_FUNC(); + + (void)peakbitrate; + DEBUG_PRINT_ERROR("Get peak bitrate is not supported"); + + RETURN(false); +} + +bool omx_venc::dev_get_batch_size(OMX_U32 *size) +{ + ENTER_FUNC(); + + (void)size; + + DEBUG_PRINT_ERROR("Get batch size is not supported"); + + RETURN(false); +} + +bool omx_venc::dev_loaded_start() +{ + ENTER_FUNC(); + RETURN(true); +} + +bool omx_venc::dev_loaded_stop() +{ + ENTER_FUNC(); + RETURN(true); +} + +bool omx_venc::dev_loaded_start_done() +{ + ENTER_FUNC(); + RETURN(true); +} + +bool omx_venc::dev_loaded_stop_done() +{ + ENTER_FUNC(); + RETURN(true); +} + +bool omx_venc::dev_get_buf_req(OMX_U32 *min_buff_count, + OMX_U32 *actual_buff_count, + OMX_U32 *buff_size, + OMX_U32 port) +{ + ENTER_FUNC(); + + bool bRet = true; + OMX_PARAM_PORTDEFINITIONTYPE *PortDef; + + if (PORT_INDEX_IN == port) + { + PortDef = &m_sInPortDef; + } + else if (PORT_INDEX_OUT == port) + { + PortDef = &m_sOutPortDef; + } + else + { + DEBUG_PRINT_ERROR("ERROR: %s, Unsupported parameter", __FUNCTION__); + bRet = false; + } + + if (true == bRet) + { + *min_buff_count = PortDef->nBufferCountMin; + *actual_buff_count = PortDef->nBufferCountActual; + *buff_size = PortDef->nBufferSize; + } + + RETURN(true); +} + +bool omx_venc::dev_set_buf_req +( + OMX_U32 const *min_buff_count, + OMX_U32 const *actual_buff_count, + OMX_U32 const *buff_size, + OMX_U32 port +) +{ + ENTER_FUNC(); + + SWVENC_STATUS Ret; + OMX_PARAM_PORTDEFINITIONTYPE *PortDef; + + (void)min_buff_count; + if (PORT_INDEX_IN == port) + { + PortDef = &m_sInPortDef; + } + else if (PORT_INDEX_OUT == port) + { + PortDef = &m_sOutPortDef; + } + else + { + DEBUG_PRINT_ERROR("ERROR: %s, Unsupported parameter", __FUNCTION__); + RETURN(false); + } + + if (*actual_buff_count < PortDef->nBufferCountMin) + { + DEBUG_PRINT_ERROR("ERROR: %s, (actual,min) buffer count (%d, %d)", + __FUNCTION__, *actual_buff_count, PortDef->nBufferCountMin); + RETURN(false); + } + if (false == meta_mode_enable) + { + if (*buff_size < PortDef->nBufferSize) + { + DEBUG_PRINT_ERROR("ERROR: %s, (new,old) buffer count (%d, %d)", + __FUNCTION__, *actual_buff_count, PortDef->nBufferCountMin); + RETURN(false); + } + } + + RETURN(true); +} + +bool omx_venc::dev_is_video_session_supported(OMX_U32 width, OMX_U32 height) +{ + ENTER_FUNC(); + + if ( (width * height < m_capability.min_width * m_capability.min_height) || + (width * height > m_capability.max_width * m_capability.max_height) + ) + { + DEBUG_PRINT_ERROR( + "Unsupported Resolution WxH = (%u)x(%u) Supported Range = min (%d)x(%d) - max (%d)x(%d)", + width, height, + m_capability.min_width, m_capability.min_height, + m_capability.max_width, m_capability.max_height); + RETURN(false); + } + + RETURN(true); +} + +bool omx_venc::dev_buffer_ready_to_queue(OMX_BUFFERHEADERTYPE *buffer) +{ + ENTER_FUNC(); + + (void)buffer; + RETURN(true); +} +int omx_venc::dev_handle_output_extradata(void *buffer, int fd) +{ + ENTER_FUNC(); + + (void)buffer; + (void)fd; + + RETURN(true); +} + +int omx_venc::dev_handle_input_extradata(void *buffer, int fd, int index) +{ + ENTER_FUNC(); + + (void)buffer; + (void)fd; + (void)index; + + RETURN(true); +} + +void omx_venc::dev_set_extradata_cookie(void *buffer) +{ + ENTER_FUNC(); + + (void)buffer; +} + +int omx_venc::dev_set_format(int color) +{ + ENTER_FUNC(); + + (void)color; + + RETURN(true); + //return handle->venc_set_format(color); +} + +bool omx_venc::dev_color_align(OMX_BUFFERHEADERTYPE *buffer, + OMX_U32 width, OMX_U32 height) +{ + ENTER_FUNC(); + + if(secure_session) { + DEBUG_PRINT_ERROR("Cannot align colors in secure session."); + RETURN(OMX_FALSE); + } + return swvenc_color_align(buffer, width,height); +} + +bool omx_venc::is_secure_session() +{ + ENTER_FUNC(); + + RETURN(secure_session); +} + +bool omx_venc::dev_get_output_log_flag() +{ + ENTER_FUNC(); + + RETURN(m_debug.out_buffer_log == 1); +} + +int omx_venc::dev_output_log_buffers(const char *buffer, int bufferlen) +{ + ENTER_FUNC(); + + if (m_debug.out_buffer_log && !m_debug.outfile) + { + int size = 0; + int width = m_sInPortDef.format.video.nFrameWidth; + int height = m_sInPortDef.format.video.nFrameHeight; + if(SWVENC_CODEC_MPEG4 == m_codec) + { + size = snprintf(m_debug.outfile_name, PROPERTY_VALUE_MAX, + "%s/output_enc_%d_%d_%p.m4v", + m_debug.log_loc, width, height, this); + } + else if(SWVENC_CODEC_H263 == m_codec) + { + size = snprintf(m_debug.outfile_name, PROPERTY_VALUE_MAX, + "%s/output_enc_%d_%d_%p.263", + m_debug.log_loc, width, height, this); + } + if ((size > PROPERTY_VALUE_MAX) || (size < 0)) + { + DEBUG_PRINT_ERROR("Failed to open output file: %s for logging as size:%d", + m_debug.outfile_name, size); + RETURN(-1); + } + DEBUG_PRINT_LOW("output filename = %s", m_debug.outfile_name); + m_debug.outfile = fopen(m_debug.outfile_name, "ab"); + if (!m_debug.outfile) + { + DEBUG_PRINT_ERROR("Failed to open output file: %s for logging errno:%d", + m_debug.outfile_name, errno); + m_debug.outfile_name[0] = '\0'; + RETURN(-1); + } + } + if (m_debug.outfile && buffer && bufferlen) + { + DEBUG_PRINT_LOW("%s buffer length: %d", __func__, bufferlen); + fwrite(buffer, bufferlen, 1, m_debug.outfile); + } + + RETURN(0); +} + +int omx_venc::swvenc_input_log_buffers(const char *buffer, int bufferlen) +{ + int width = m_sInPortDef.format.video.nFrameWidth; + int height = m_sInPortDef.format.video.nFrameHeight; + int stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, width); + int scanlines = VENUS_Y_SCANLINES(COLOR_FMT_NV12, height); + char *temp = (char*)buffer; + + if (!m_debug.infile) + { + int size = snprintf(m_debug.infile_name, PROPERTY_VALUE_MAX, + "%s/input_enc_%d_%d_%p.yuv", + m_debug.log_loc, width, height, this); + if ((size > PROPERTY_VALUE_MAX) || (size < 0)) + { + DEBUG_PRINT_ERROR("Failed to open input file: %s for logging size:%d", + m_debug.infile_name, size); + RETURN(-1); + } + DEBUG_PRINT_LOW("input filename = %s", m_debug.infile_name); + m_debug.infile = fopen (m_debug.infile_name, "ab"); + if (!m_debug.infile) + { + DEBUG_PRINT_HIGH("Failed to open input file: %s for logging", + m_debug.infile_name); + m_debug.infile_name[0] = '\0'; + RETURN(-1); + } + } + if (m_debug.infile && buffer && bufferlen) + { + DEBUG_PRINT_LOW("%s buffer length: %d", __func__, bufferlen); + for (int i = 0; i < height; i++) + { + fwrite(temp, width, 1, m_debug.infile); + temp += stride; + } + for(int i = 0; i < height/2; i++) + { + fwrite(temp, width, 1, m_debug.infile); + temp += stride; + } + } + + RETURN(0); +} + +int omx_venc::dev_extradata_log_buffers(char *buffer) +{ + ENTER_FUNC(); + + (void)buffer; + + RETURN(true); + //return handle->venc_extradata_log_buffers(buffer); +} + +SWVENC_STATUS omx_venc::swvenc_get_buffer_req +( + OMX_U32 *min_buff_count, + OMX_U32 *actual_buff_count, + OMX_U32 *buff_size, + OMX_U32 *buff_alignment, + OMX_U32 port +) +{ + ENTER_FUNC(); + + SWVENC_PROPERTY Prop; + SWVENC_STATUS Ret; + OMX_PARAM_PORTDEFINITIONTYPE *PortDef; + + Prop.id = SWVENC_PROPERTY_ID_BUFFER_REQ; + if (PORT_INDEX_IN == port) + { + Prop.info.buffer_req.type = SWVENC_BUFFER_INPUT; + } + else if (PORT_INDEX_OUT == port) + { + Prop.info.buffer_req.type = SWVENC_BUFFER_OUTPUT; + } + else + { + DEBUG_PRINT_ERROR("ERROR: %s, Unsupported parameter", __FUNCTION__); + RETURN(SWVENC_S_INVALID_PARAMETERS); + } + + Ret = swvenc_getproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("ERROR: %s, swvenc_setproperty failed (%d)", __FUNCTION__, + Ret); + RETURN(SWVENC_S_INVALID_PARAMETERS); + } + + *buff_size = Prop.info.buffer_req.size; + *min_buff_count = Prop.info.buffer_req.mincount; + *actual_buff_count = Prop.info.buffer_req.mincount; + *buff_alignment = Prop.info.buffer_req.alignment; + + RETURN(Ret); +} + +SWVENC_STATUS omx_venc::swvenc_empty_buffer_done_cb +( + SWVENC_HANDLE swvenc, + SWVENC_IPBUFFER *p_ipbuffer, + void *p_client +) +{ + ENTER_FUNC(); + + (void)swvenc; + SWVENC_STATUS eRet = SWVENC_S_SUCCESS; + omx_venc *omx = reinterpret_cast<omx_venc*>(p_client); + + if (p_ipbuffer == NULL) + { + eRet = SWVENC_S_FAILURE; + } + else + { + omx->swvenc_empty_buffer_done(p_ipbuffer); + } + return eRet; +} + +SWVENC_STATUS omx_venc::swvenc_empty_buffer_done +( + SWVENC_IPBUFFER *p_ipbuffer +) +{ + SWVENC_STATUS eRet = SWVENC_S_SUCCESS; + OMX_ERRORTYPE error = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE* omxhdr = NULL; + + //omx_video *omx = reinterpret_cast<omx_video*>(p_client); + omxhdr = (OMX_BUFFERHEADERTYPE*)p_ipbuffer->p_client_data; + + DEBUG_PRINT_LOW("EBD: clientData (%p)", p_ipbuffer->p_client_data); + + if ( (omxhdr == NULL) || + ( ((OMX_U32)(omxhdr - m_inp_mem_ptr) >m_sInPortDef.nBufferCountActual) && + ((OMX_U32)(omxhdr - meta_buffer_hdr) >m_sInPortDef.nBufferCountActual) + ) + ) + { + omxhdr = NULL; + error = OMX_ErrorUndefined; + } + + if (omxhdr != NULL) + { + // unmap the input buffer->pBuffer + omx_release_meta_buffer(omxhdr); +#ifdef _ANDROID_ICS_ + if (meta_mode_enable) + { + LEGACY_CAM_METADATA_TYPE *meta_buf = NULL; + unsigned int size = 0; + meta_buf = (LEGACY_CAM_METADATA_TYPE *)omxhdr->pBuffer; + if (meta_buf) + { + if (meta_buf->buffer_type == LEGACY_CAM_SOURCE) + { + size = meta_buf->meta_handle->data[2]; + } + else if (meta_buf->buffer_type == kMetadataBufferTypeGrallocSource) + { + VideoGrallocMetadata *meta_buf = (VideoGrallocMetadata *)omxhdr->pBuffer; + private_handle_t *handle = (private_handle_t *)meta_buf->pHandle; + size = handle->size; + } + } + int status = munmap(p_ipbuffer->p_buffer, size); + DEBUG_PRINT_HIGH("Unmapped pBuffer <%p> size <%d> status <%d>", p_ipbuffer->p_buffer, size, status); + } +#endif + post_event ((unsigned long)omxhdr,error,OMX_COMPONENT_GENERATE_EBD); + } + + RETURN(eRet); +} + +SWVENC_STATUS omx_venc::swvenc_fill_buffer_done_cb +( + SWVENC_HANDLE swvenc, + SWVENC_OPBUFFER *p_opbuffer, + void *p_client +) +{ + ENTER_FUNC(); + + SWVENC_STATUS eRet = SWVENC_S_SUCCESS; + OMX_ERRORTYPE error = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE* omxhdr = NULL; + omx_video *omx = reinterpret_cast<omx_video*>(p_client); + + (void)swvenc; + + if (p_opbuffer != NULL) + { + omxhdr = (OMX_BUFFERHEADERTYPE*)p_opbuffer->p_client_data; + } + + if ( (p_opbuffer != NULL) && + ((OMX_U32)(omxhdr - omx->m_out_mem_ptr) < omx->m_sOutPortDef.nBufferCountActual) + ) + { + DEBUG_PRINT_LOW("FBD: clientData (%p) buffer (%p) filled_lengh (%d) flags (0x%x) ts (%lld)", + p_opbuffer->p_client_data, + p_opbuffer->p_buffer, + p_opbuffer->filled_length, + p_opbuffer->flags, + p_opbuffer->timestamp); + + if (p_opbuffer->filled_length <= omxhdr->nAllocLen) + { + omxhdr->pBuffer = p_opbuffer->p_buffer; + omxhdr->nFilledLen = p_opbuffer->filled_length; + omxhdr->nOffset = 0; + omxhdr->nTimeStamp = p_opbuffer->timestamp; + omxhdr->nFlags = 0; + if (SWVENC_FRAME_TYPE_I == p_opbuffer->frame_type) + { + omxhdr->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; + } + if (SWVENC_FLAG_EOS & p_opbuffer->flags) + { + omxhdr->nFlags |= OMX_BUFFERFLAG_EOS; + } + if(omxhdr->nFilledLen) + { + omxhdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; + } + DEBUG_PRINT_LOW("o/p flag = 0x%x", omxhdr->nFlags); + + /* Use buffer case */ + if (omx->output_use_buffer && !omx->m_use_output_pmem) + { + DEBUG_PRINT_LOW("memcpy() for o/p Heap UseBuffer"); + memcpy( omxhdr->pBuffer, + (p_opbuffer->p_buffer), + p_opbuffer->filled_length ); + } + } + else + { + omxhdr->nFilledLen = 0; + } + + } + else + { + omxhdr = NULL; + error = OMX_ErrorUndefined; + } + + omx->post_event ((unsigned long)omxhdr,error,OMX_COMPONENT_GENERATE_FBD); + + RETURN(eRet); +} + +SWVENC_STATUS omx_venc::swvenc_handle_event_cb +( + SWVENC_HANDLE swvenc, + SWVENC_EVENT event, + void *p_client +) +{ + ENTER_FUNC(); + + SWVENC_STATUS eRet = SWVENC_S_SUCCESS; + omx_video *omx = reinterpret_cast<omx_video*>(p_client); + + OMX_BUFFERHEADERTYPE* omxhdr = NULL; + + (void)swvenc; + + if (omx == NULL || p_client == NULL) + { + DEBUG_PRINT_ERROR("ERROR: %s invalid i/p params", __FUNCTION__); + RETURN(SWVENC_S_NULL_POINTER); + } + + DEBUG_PRINT_LOW("swvenc_handle_event_cb - event = %d", event); + + switch (event) + { + case SWVENC_EVENT_FLUSH_DONE: + { + DEBUG_PRINT_ERROR("SWVENC_EVENT_FLUSH_DONE input_flush_progress %d output_flush_progress %d", + omx->input_flush_progress, omx->output_flush_progress); + if (omx->input_flush_progress) + { + omx->post_event ((unsigned)NULL, SWVENC_S_SUCCESS, + OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH); + } + if (omx->output_flush_progress) + { + omx->post_event ((unsigned)NULL, SWVENC_S_SUCCESS, + OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH); + } + break; + } + + case SWVENC_EVENT_FATAL_ERROR: + { + DEBUG_PRINT_ERROR("ERROR: SWVENC_EVENT_FATAL_ERROR"); + omx->omx_report_error(); + break; + } + + default: + DEBUG_PRINT_HIGH("Unknown event received : %d", event); + break; + } + + RETURN(eRet); +} + +SWVENC_STATUS omx_venc::swvenc_set_rc_mode +( + OMX_VIDEO_CONTROLRATETYPE eControlRate +) +{ + ENTER_FUNC(); + + SWVENC_STATUS Ret = SWVENC_S_SUCCESS; + SWVENC_RC_MODE rc_mode; + SWVENC_PROPERTY Prop; + + switch (eControlRate) + { + case OMX_Video_ControlRateDisable: + rc_mode = SWVENC_RC_MODE_NONE; + break; + case OMX_Video_ControlRateVariableSkipFrames: + rc_mode = SWVENC_RC_MODE_VBR_VFR; + break; + case OMX_Video_ControlRateVariable: + rc_mode = SWVENC_RC_MODE_VBR_CFR; + break; + case OMX_Video_ControlRateConstantSkipFrames: + rc_mode = SWVENC_RC_MODE_CBR_VFR; + break; + case OMX_Video_ControlRateConstant: + rc_mode = SWVENC_RC_MODE_CBR_CFR; + break; + default: + DEBUG_PRINT_ERROR("ERROR: UNKNOWN RC MODE"); + Ret = SWVENC_S_FAILURE; + break; + } + + if (SWVENC_S_SUCCESS == Ret) + { + Prop.id = SWVENC_PROPERTY_ID_RC_MODE; + Prop.info.rc_mode = rc_mode; + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(SWVENC_S_FAILURE); + } + } + + RETURN(Ret); +} + +SWVENC_STATUS omx_venc::swvenc_set_profile_level +( + OMX_U32 eProfile, + OMX_U32 eLevel +) +{ + ENTER_FUNC(); + + SWVENC_STATUS Ret = SWVENC_S_SUCCESS; + SWVENC_PROPERTY Prop; + SWVENC_PROFILE Profile; + SWVENC_LEVEL Level; + + /* set the profile */ + if (SWVENC_CODEC_MPEG4 == m_codec) + { + switch (eProfile) + { + case OMX_VIDEO_MPEG4ProfileSimple: + Profile.mpeg4 = SWVENC_PROFILE_MPEG4_SIMPLE; + break; + case OMX_VIDEO_MPEG4ProfileAdvancedSimple: + Profile.mpeg4 = SWVENC_PROFILE_MPEG4_ADVANCED_SIMPLE; + break; + default: + DEBUG_PRINT_ERROR("ERROR: UNKNOWN PROFILE"); + Ret = SWVENC_S_FAILURE; + break; + } + switch (eLevel) + { + case OMX_VIDEO_MPEG4Level0: + Level.mpeg4 = SWVENC_LEVEL_MPEG4_0; + break; + case OMX_VIDEO_MPEG4Level0b: + Level.mpeg4 = SWVENC_LEVEL_MPEG4_0B; + break; + case OMX_VIDEO_MPEG4Level1: + Level.mpeg4 = SWVENC_LEVEL_MPEG4_1; + break; + case OMX_VIDEO_MPEG4Level2: + Level.mpeg4 = SWVENC_LEVEL_MPEG4_2; + break; + case OMX_VIDEO_MPEG4Level3: + Level.mpeg4 = SWVENC_LEVEL_MPEG4_3; + break; + case OMX_VIDEO_MPEG4Level4: + Level.mpeg4 = SWVENC_LEVEL_MPEG4_4; + break; + case OMX_VIDEO_MPEG4Level4a: + Level.mpeg4 = SWVENC_LEVEL_MPEG4_4A; + break; + case OMX_VIDEO_MPEG4Level5: + Level.mpeg4 = SWVENC_LEVEL_MPEG4_5; + break; + default: + DEBUG_PRINT_ERROR("ERROR: UNKNOWN LEVEL"); + Ret = SWVENC_S_FAILURE; + break; + } + } + else if (SWVENC_CODEC_H263 == m_codec) + { + switch (eProfile) + { + case OMX_VIDEO_H263ProfileBaseline: + Profile.h263 = SWVENC_PROFILE_H263_BASELINE; + break; + default: + DEBUG_PRINT_ERROR("ERROR: UNKNOWN PROFILE"); + Ret = SWVENC_S_FAILURE; + break; + } + switch (eLevel) + { + case OMX_VIDEO_H263Level10: + Level.h263 = SWVENC_LEVEL_H263_10; + break; + case OMX_VIDEO_H263Level20: + Level.h263 = SWVENC_LEVEL_H263_20; + break; + case OMX_VIDEO_H263Level30: + Level.h263 = SWVENC_LEVEL_H263_30; + break; + case OMX_VIDEO_H263Level40: + Level.h263 = SWVENC_LEVEL_H263_40; + break; + case OMX_VIDEO_H263Level50: + Level.h263 = SWVENC_LEVEL_H263_50; + break; + case OMX_VIDEO_H263Level60: + Level.h263 = SWVENC_LEVEL_H263_60; + break; + case OMX_VIDEO_H263Level70: + Level.h263 = SWVENC_LEVEL_H263_70; + break; + default: + DEBUG_PRINT_ERROR("ERROR: UNKNOWN LEVEL"); + Ret = SWVENC_S_FAILURE; + break; + } + } + else + { + DEBUG_PRINT_ERROR("ERROR: UNSUPPORTED CODEC"); + Ret = SWVENC_S_FAILURE; + } + + if (SWVENC_S_SUCCESS == Ret) + { + Prop.id = SWVENC_PROPERTY_ID_PROFILE; + Prop.info.profile = Profile; + + /* set the profile */ + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(SWVENC_S_FAILURE); + } + + /* set the level */ + Prop.id = SWVENC_PROPERTY_ID_LEVEL; + Prop.info.level = Level; + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + RETURN(SWVENC_S_FAILURE); + } + } + + RETURN(Ret); +} + +SWVENC_STATUS omx_venc::swvenc_set_intra_refresh +( + OMX_VIDEO_PARAM_INTRAREFRESHTYPE *IntraRefresh +) +{ + ENTER_FUNC(); + + SWVENC_STATUS Ret = SWVENC_S_SUCCESS; + SWVENC_IR_CONFIG ir_config; + SWVENC_PROPERTY Prop; + + switch (IntraRefresh->eRefreshMode) + { + case OMX_VIDEO_IntraRefreshCyclic: + Prop.info.ir_config.mode = SWVENC_IR_MODE_CYCLIC; + break; + case OMX_VIDEO_IntraRefreshAdaptive: + Prop.info.ir_config.mode = SWVENC_IR_MODE_ADAPTIVE; + break; + case OMX_VIDEO_IntraRefreshBoth: + Prop.info.ir_config.mode = SWVENC_IR_MODE_CYCLIC_ADAPTIVE; + break; + case OMX_VIDEO_IntraRefreshRandom: + Prop.info.ir_config.mode = SWVENC_IR_MODE_RANDOM; + break; + default: + DEBUG_PRINT_ERROR("ERROR: UNKNOWN INTRA REFRESH MODE"); + Ret = SWVENC_S_FAILURE; + break; + } + + if (SWVENC_S_SUCCESS == Ret) + { + Prop.id = SWVENC_PROPERTY_ID_IR_CONFIG; + Prop.info.ir_config.cir_mbs = IntraRefresh->nCirMBs; + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + Ret = SWVENC_S_FAILURE; + } + } + + RETURN(Ret); +} + +SWVENC_STATUS omx_venc::swvenc_set_frame_rate +( + OMX_U32 nFrameRate +) +{ + ENTER_FUNC(); + + SWVENC_STATUS Ret = SWVENC_S_SUCCESS; + SWVENC_PROPERTY Prop; + + Prop.id = SWVENC_PROPERTY_ID_FRAME_RATE; + Prop.info.frame_rate = nFrameRate; + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + Ret = SWVENC_S_FAILURE; + } + + RETURN(Ret); +} + +SWVENC_STATUS omx_venc::swvenc_set_bit_rate +( + OMX_U32 nTargetBitrate +) +{ + ENTER_FUNC(); + + SWVENC_STATUS Ret = SWVENC_S_SUCCESS; + SWVENC_PROPERTY Prop; + + Prop.id = SWVENC_PROPERTY_ID_TARGET_BITRATE; + Prop.info.target_bitrate = nTargetBitrate; + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + Ret = SWVENC_S_FAILURE; + } + + RETURN(Ret); +} + +SWVENC_STATUS omx_venc::swvenc_set_intra_period +( + OMX_U32 nPFrame, + OMX_U32 nBFrame +) +{ + ENTER_FUNC(); + + SWVENC_STATUS Ret = SWVENC_S_SUCCESS; + SWVENC_PROPERTY Prop; + + Prop.id = SWVENC_PROPERTY_ID_INTRA_PERIOD; + Prop.info.intra_period.pframes = nPFrame; + Prop.info.intra_period.bframes = nBFrame; + + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + Ret = SWVENC_S_FAILURE; + } + + RETURN(Ret); +} + +bool omx_venc::swvenc_color_align(OMX_BUFFERHEADERTYPE *buffer, OMX_U32 width, + OMX_U32 height) +{ + OMX_U32 y_stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, width), + y_scanlines = VENUS_Y_SCANLINES(COLOR_FMT_NV12, height), + uv_stride = VENUS_UV_STRIDE(COLOR_FMT_NV12, width), + uv_scanlines = VENUS_UV_SCANLINES(COLOR_FMT_NV12, height), + src_chroma_offset = width * height; + + if (buffer->nAllocLen >= VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height)) { + OMX_U8* src_buf = buffer->pBuffer, *dst_buf = buffer->pBuffer; + //Do chroma first, so that we can convert it in-place + src_buf += width * height; + dst_buf += y_stride * y_scanlines; + for (int line = height / 2 - 1; line >= 0; --line) { + memmove(dst_buf + line * uv_stride, + src_buf + line * width, + width); + } + + dst_buf = src_buf = buffer->pBuffer; + //Copy the Y next + for (int line = height - 1; line > 0; --line) { + memmove(dst_buf + line * y_stride, + src_buf + line * width, + width); + } + } else { + DEBUG_PRINT_ERROR("Failed to align Chroma. from %u to %u : \ + Insufficient bufferLen=%u v/s Required=%u", + (unsigned int)(width*height), (unsigned int)src_chroma_offset, (unsigned int)buffer->nAllocLen, + VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height)); + return false; + } + + return true; +} + +SWVENC_STATUS omx_venc::swvenc_set_color_format +( + OMX_COLOR_FORMATTYPE color_format +) +{ + ENTER_FUNC(); + SWVENC_STATUS Ret = SWVENC_S_SUCCESS; + SWVENC_COLOR_FORMAT swvenc_color_format; + SWVENC_PROPERTY Prop; + if ((color_format == OMX_COLOR_FormatYUV420SemiPlanar) || + (color_format == ((OMX_COLOR_FORMATTYPE) QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m))) + { + swvenc_color_format = SWVENC_COLOR_FORMAT_NV12; + } + else if (color_format == ((OMX_COLOR_FORMATTYPE) QOMX_COLOR_FormatYVU420SemiPlanar)) + { + swvenc_color_format = SWVENC_COLOR_FORMAT_NV21; + } + else + { + DEBUG_PRINT_ERROR("%s: color_format %d invalid",__FUNCTION__,color_format); + RETURN(SWVENC_S_FAILURE); + } + /* set the input color format */ + Prop.id = SWVENC_PROPERTY_ID_COLOR_FORMAT; + Prop.info.color_format = swvenc_color_format; + Ret = swvenc_setproperty(m_hSwVenc, &Prop); + if (Ret != SWVENC_S_SUCCESS) + { + DEBUG_PRINT_ERROR("%s, swvenc_setproperty failed (%d)", + __FUNCTION__, Ret); + Ret = SWVENC_S_FAILURE; + } + RETURN(Ret); +} diff --git a/msm8998/mm-video-v4l2/vidc/venc/src/omx_video_base.cpp b/msm8998/mm-video-v4l2/vidc/venc/src/omx_video_base.cpp new file mode 100644 index 0000000..7563ae3 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/src/omx_video_base.cpp @@ -0,0 +1,5438 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2016, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +/*============================================================================ + O p e n M A X w r a p p e r s + O p e n M A X C o r e + +*//** @file omx_video_base.cpp + This module contains the implementation of the OpenMAX core & component. + +*//*========================================================================*/ + +////////////////////////////////////////////////////////////////////////////// +// Include Files +////////////////////////////////////////////////////////////////////////////// + +#define __STDC_FORMAT_MACROS //enables the format specifiers in inttypes.h +#include <inttypes.h> +#include <string.h> +#include "omx_video_base.h" +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/prctl.h> +#include <sys/ioctl.h> +#ifdef _ANDROID_ICS_ +#include <media/hardware/HardwareAPI.h> +#include <gralloc_priv.h> +#endif +#ifdef _USE_GLIB_ +#include <glib.h> +#define strlcpy g_strlcpy +#endif +#define H264_SUPPORTED_WIDTH (480) +#define H264_SUPPORTED_HEIGHT (368) + +#define MPEG4_SUPPORTED_WIDTH (480) +#define MPEG4_SUPPORTED_HEIGHT (368) + +#define VC1_SP_MP_START_CODE 0xC5000000 +#define VC1_SP_MP_START_CODE_MASK 0xFF000000 +#define VC1_AP_START_CODE 0x00000100 +#define VC1_AP_START_CODE_MASK 0xFFFFFF00 +#define VC1_STRUCT_C_PROFILE_MASK 0xF0 +#define VC1_STRUCT_B_LEVEL_MASK 0xE0000000 +#define VC1_SIMPLE_PROFILE 0 +#define VC1_MAIN_PROFILE 1 +#define VC1_ADVANCE_PROFILE 3 +#define VC1_SIMPLE_PROFILE_LOW_LEVEL 0 +#define VC1_SIMPLE_PROFILE_MED_LEVEL 2 +#define VC1_STRUCT_C_LEN 4 +#define VC1_STRUCT_C_POS 8 +#define VC1_STRUCT_A_POS 12 +#define VC1_STRUCT_B_POS 24 +#define VC1_SEQ_LAYER_SIZE 36 + +#define SZ_4K 0x1000 +#define SZ_1M 0x100000 +#define ALIGN(x, to_align) ((((unsigned long) x) + (to_align - 1)) & ~(to_align - 1)) + +#ifndef ION_FLAG_CP_BITSTREAM +#define ION_FLAG_CP_BITSTREAM 0 +#endif + +#ifndef ION_FLAG_CP_PIXEL +#define ION_FLAG_CP_PIXEL 0 +#endif + +#undef MEM_HEAP_ID + +#ifdef MASTER_SIDE_CP + +#define MEM_HEAP_ID ION_SECURE_HEAP_ID +#define SECURE_ALIGN SZ_4K +#define SECURE_FLAGS_INPUT_BUFFER (ION_SECURE | ION_FLAG_CP_PIXEL) +#define SECURE_FLAGS_OUTPUT_BUFFER (ION_SECURE | ION_FLAG_CP_BITSTREAM) + +#else //SLAVE_SIDE_CP + +#define MEM_HEAP_ID ION_CP_MM_HEAP_ID +#define SECURE_ALIGN SZ_1M +#define SECURE_FLAGS_INPUT_BUFFER ION_SECURE +#define SECURE_FLAGS_OUTPUT_BUFFER ION_SECURE + +#endif + +typedef struct OMXComponentCapabilityFlagsType { + ////////////////// OMX COMPONENT CAPABILITY RELATED MEMBERS + OMX_U32 nSize; + OMX_VERSIONTYPE nVersion; + OMX_BOOL iIsOMXComponentMultiThreaded; + OMX_BOOL iOMXComponentSupportsExternalOutputBufferAlloc; + OMX_BOOL iOMXComponentSupportsExternalInputBufferAlloc; + OMX_BOOL iOMXComponentSupportsMovableInputBuffers; + OMX_BOOL iOMXComponentSupportsPartialFrames; + OMX_BOOL iOMXComponentUsesNALStartCodes; + OMX_BOOL iOMXComponentCanHandleIncompleteFrames; + OMX_BOOL iOMXComponentUsesFullAVCFrames; + +} OMXComponentCapabilityFlagsType; +#define OMX_COMPONENT_CAPABILITY_TYPE_INDEX 0xFF7A347 + +void* message_thread_enc(void *input) +{ + omx_video* omx = reinterpret_cast<omx_video*>(input); + unsigned char id; + int n; + + fd_set readFds; + int res = 0; + struct timeval tv; + + DEBUG_PRINT_HIGH("omx_venc: message thread start"); + prctl(PR_SET_NAME, (unsigned long)"VideoEncMsgThread", 0, 0, 0); + while (!omx->msg_thread_stop) { + + tv.tv_sec = 2; + tv.tv_usec = 0; + + FD_ZERO(&readFds); + FD_SET(omx->m_pipe_in, &readFds); + + res = select(omx->m_pipe_in + 1, &readFds, NULL, NULL, &tv); + if (res < 0) { + DEBUG_PRINT_ERROR("select() ERROR: %s", strerror(errno)); + continue; + } else if (res == 0 /*timeout*/ || omx->msg_thread_stop) { + continue; + } + + n = read(omx->m_pipe_in, &id, 1); + if (0 == n) { + break; + } + + if (1 == n) { + omx->process_event_cb(omx, id); + } +#ifdef QLE_BUILD + if (n < 0) break; +#else + if ((n < 0) && (errno != EINTR)) { + DEBUG_PRINT_LOW("ERROR: read from pipe failed, ret %d errno %d", n, errno); + break; + } +#endif + } + DEBUG_PRINT_HIGH("omx_venc: message thread stop"); + return 0; +} + +void post_message(omx_video *omx, unsigned char id) +{ + DEBUG_PRINT_LOW("omx_venc: post_message %d", id); + int ret_value; + ret_value = write(omx->m_pipe_out, &id, 1); + if (ret_value <= 0) { + DEBUG_PRINT_ERROR("post_message to pipe failed : %s", strerror(errno)); + } else { + DEBUG_PRINT_LOW("post_message to pipe done %d",ret_value); + } +} + +// omx_cmd_queue destructor +omx_video::omx_cmd_queue::~omx_cmd_queue() +{ + // Nothing to do +} + +// omx cmd queue constructor +omx_video::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0) +{ + memset(m_q,0,sizeof(omx_event)*OMX_CORE_CONTROL_CMDQ_SIZE); +} + +// omx cmd queue insert +bool omx_video::omx_cmd_queue::insert_entry(unsigned long p1, unsigned long p2, unsigned long id) +{ + bool ret = true; + if (m_size < OMX_CORE_CONTROL_CMDQ_SIZE) { + m_q[m_write].id = id; + m_q[m_write].param1 = p1; + m_q[m_write].param2 = p2; + m_write++; + m_size ++; + if (m_write >= OMX_CORE_CONTROL_CMDQ_SIZE) { + m_write = 0; + } + } else { + ret = false; + DEBUG_PRINT_ERROR("ERROR!!! Command Queue Full"); + } + return ret; +} + +// omx cmd queue pop +bool omx_video::omx_cmd_queue::pop_entry(unsigned long *p1, unsigned long *p2, unsigned long *id) +{ + bool ret = true; + if (m_size > 0) { + *id = m_q[m_read].id; + *p1 = m_q[m_read].param1; + *p2 = m_q[m_read].param2; + // Move the read pointer ahead + ++m_read; + --m_size; + if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE) { + m_read = 0; + } + } else { + ret = false; + } + return ret; +} + +// Retrieve the first mesg type in the queue +unsigned omx_video::omx_cmd_queue::get_q_msg_type() +{ + return m_q[m_read].id; +} + + + +#ifdef _ANDROID_ +VideoHeap::VideoHeap(int fd, size_t size, void* base) +{ + // dup file descriptor, map once, use pmem + init(dup(fd), base, size, 0 , MEM_DEVICE); +} +#endif // _ANDROID_ + +/* ====================================================================== + FUNCTION + omx_venc::omx_venc + + DESCRIPTION + Constructor + + PARAMETERS + None + + RETURN VALUE + None. + ========================================================================== */ +omx_video::omx_video(): + c2d_opened(false), + psource_frame(NULL), + pdest_frame(NULL), + secure_session(false), + mEmptyEosBuffer(NULL), + m_pipe_in(-1), + m_pipe_out(-1), + m_pInput_pmem(NULL), + m_pOutput_pmem(NULL), +#ifdef USE_ION + m_pInput_ion(NULL), + m_pOutput_ion(NULL), +#endif + m_error_propogated(false), + m_state(OMX_StateInvalid), + m_app_data(NULL), + m_use_input_pmem(OMX_FALSE), + m_use_output_pmem(OMX_FALSE), + m_sExtraData(0), + m_input_msg_id(OMX_COMPONENT_GENERATE_ETB), + m_inp_mem_ptr(NULL), + m_out_mem_ptr(NULL), + input_flush_progress (false), + output_flush_progress (false), + input_use_buffer (false), + output_use_buffer (false), + pending_input_buffers(0), + pending_output_buffers(0), + m_out_bm_count(0), + m_inp_bm_count(0), + m_flags(0), + m_etb_count(0), + m_fbd_count(0), + m_event_port_settings_sent(false), + hw_overload(false), + m_graphicbuffer_size(0) +{ + DEBUG_PRINT_HIGH("omx_video(): Inside Constructor()"); + memset(&m_cmp,0,sizeof(m_cmp)); + memset(&m_pCallbacks,0,sizeof(m_pCallbacks)); + async_thread_created = false; + msg_thread_created = false; + msg_thread_stop = false; + + OMX_INIT_STRUCT(&m_blurInfo, OMX_QTI_VIDEO_CONFIG_BLURINFO); + m_blurInfo.nPortIndex == (OMX_U32)PORT_INDEX_IN; + + mUsesColorConversion = false; + pthread_mutex_init(&m_lock, NULL); + pthread_mutex_init(×tamp.m_lock, NULL); + timestamp.is_buffer_pending = false; + sem_init(&m_cmd_lock,0,0); + DEBUG_PRINT_LOW("meta_buffer_hdr = %p", meta_buffer_hdr); + + memset(m_platform, 0, sizeof(m_platform)); +#ifdef _ANDROID_ + char platform_name[PROPERTY_VALUE_MAX] = {0}; + property_get("ro.board.platform", platform_name, "0"); + strlcpy(m_platform, platform_name, sizeof(m_platform)); +#endif +} + + +/* ====================================================================== + FUNCTION + omx_venc::~omx_venc + + DESCRIPTION + Destructor + + PARAMETERS + None + + RETURN VALUE + None. + ========================================================================== */ +omx_video::~omx_video() +{ + DEBUG_PRINT_HIGH("~omx_video(): Inside Destructor()"); + if (msg_thread_created) { + msg_thread_stop = true; + post_message(this, OMX_COMPONENT_CLOSE_MSG); + DEBUG_PRINT_HIGH("omx_video: Waiting on Msg Thread exit"); + pthread_join(msg_thread_id,NULL); + } + close(m_pipe_in); + close(m_pipe_out); + m_pipe_in = -1; + m_pipe_out = -1; + DEBUG_PRINT_HIGH("omx_video: Waiting on Async Thread exit"); + /*For V4L2 based drivers, pthread_join is done in device_close + * so no need to do it here*/ +#ifndef _MSM8974_ + if (async_thread_created) + pthread_join(async_thread_id,NULL); +#endif + pthread_mutex_destroy(&m_lock); + pthread_mutex_destroy(×tamp.m_lock); + sem_destroy(&m_cmd_lock); + DEBUG_PRINT_HIGH("m_etb_count = %" PRIu64 ", m_fbd_count = %" PRIu64, m_etb_count, + m_fbd_count); + DEBUG_PRINT_HIGH("omx_video: Destructor exit"); + DEBUG_PRINT_HIGH("Exiting OMX Video Encoder ..."); +} + +/* ====================================================================== + FUNCTION + omx_venc::OMXCntrlProcessMsgCb + + DESCRIPTION + IL Client callbacks are generated through this routine. The decoder + provides the thread context for this routine. + + PARAMETERS + ctxt -- Context information related to the self. + id -- Event identifier. This could be any of the following: + 1. Command completion event + 2. Buffer done callback event + 3. Frame done callback event + + RETURN VALUE + None. + + ========================================================================== */ +void omx_video::process_event_cb(void *ctxt, unsigned char id) +{ + unsigned long p1; // Parameter - 1 + unsigned long p2; // Parameter - 2 + unsigned long ident; + unsigned qsize=0; // qsize + omx_video *pThis = (omx_video *) ctxt; + + if (!pThis) { + DEBUG_PRINT_ERROR("ERROR:ProcessMsgCb:Context is incorrect; bailing out"); + return; + } + + // Protect the shared queue data structure + do { + /*Read the message id's from the queue*/ + + pthread_mutex_lock(&pThis->m_lock); + qsize = pThis->m_cmd_q.m_size; + if (qsize) { + pThis->m_cmd_q.pop_entry(&p1,&p2,&ident); + } + + if (qsize == 0) { + qsize = pThis->m_ftb_q.m_size; + if (qsize) { + pThis->m_ftb_q.pop_entry(&p1,&p2,&ident); + } + } + + if (qsize == 0) { + qsize = pThis->m_etb_q.m_size; + if (qsize) { + pThis->m_etb_q.pop_entry(&p1,&p2,&ident); + } + } + + pthread_mutex_unlock(&pThis->m_lock); + + /*process message if we have one*/ + if (qsize > 0) { + id = ident; + switch (id) { + case OMX_COMPONENT_GENERATE_EVENT: + if (pThis->m_pCallbacks.EventHandler) { + switch (p1) { + case OMX_CommandStateSet: + pThis->m_state = (OMX_STATETYPE) p2; + DEBUG_PRINT_LOW("Process -> state set to %d", pThis->m_state); + pThis->m_pCallbacks.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete, p1, p2, NULL); + break; + + case OMX_EventError: + DEBUG_PRINT_ERROR("ERROR: OMX_EventError: p2 = %lu", p2); + if (p2 == (unsigned)OMX_ErrorHardware) { + pThis->m_pCallbacks.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventError,OMX_ErrorHardware,0,NULL); + } else { + pThis->m_pCallbacks.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventError, p2, 0, 0); + + } + break; + + case OMX_CommandPortDisable: + DEBUG_PRINT_LOW("Process -> Port %lu set to PORT_STATE_DISABLED" \ + "state", p2); + pThis->m_pCallbacks.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete, p1, p2, NULL ); + break; + case OMX_CommandPortEnable: + DEBUG_PRINT_LOW("Process ->Port %lu set PORT_STATE_ENABLED state" \ + , p2); + pThis->m_pCallbacks.EventHandler(&pThis->m_cmp, pThis->m_app_data,\ + OMX_EventCmdComplete, p1, p2, NULL ); + break; + + default: + DEBUG_PRINT_LOW("process_event_cb forwarding EventCmdComplete %lu", p1); + pThis->m_pCallbacks.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete, p1, p2, NULL ); + break; + + } + } else { + DEBUG_PRINT_ERROR("ERROR: ProcessMsgCb NULL callbacks"); + } + break; + case OMX_COMPONENT_GENERATE_ETB_OPQ: + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_ETB_OPQ"); + if (pThis->empty_this_buffer_opaque((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("ERROR: ETBProxy() failed!"); + pThis->omx_report_error (); + } + break; + case OMX_COMPONENT_GENERATE_ETB: { + OMX_ERRORTYPE iret; + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_ETB"); + iret = pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1, (OMX_BUFFERHEADERTYPE *)p2); + if (iret == OMX_ErrorInsufficientResources) { + DEBUG_PRINT_ERROR("empty_this_buffer_proxy failure due to HW overload"); + pThis->omx_report_hw_overload (); + } else if (iret != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("empty_this_buffer_proxy failure"); + pThis->omx_report_error (); + } + } + break; + + case OMX_COMPONENT_GENERATE_FTB: + if ( pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)p1,\ + (OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("ERROR: FTBProxy() failed!"); + pThis->omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_COMMAND: + pThis->send_command_proxy(&pThis->m_cmp,(OMX_COMMANDTYPE)p1,\ + (OMX_U32)p2,(OMX_PTR)NULL); + break; + + case OMX_COMPONENT_GENERATE_EBD: + if ( pThis->empty_buffer_done(&pThis->m_cmp, + (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("ERROR: empty_buffer_done() failed!"); + pThis->omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_FBD: + if ( pThis->fill_buffer_done(&pThis->m_cmp, + (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone ) { + DEBUG_PRINT_ERROR("ERROR: fill_buffer_done() failed!"); + pThis->omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH: + + pThis->input_flush_progress = false; + DEBUG_PRINT_HIGH("m_etb_count at i/p flush = %" PRIu64, m_etb_count); + m_etb_count = 0; + if (pThis->m_pCallbacks.EventHandler) { + /*Check if we need generate event for Flush done*/ + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_INPUT_FLUSH_PENDING)) { + BITMASK_CLEAR (&pThis->m_flags,OMX_COMPONENT_INPUT_FLUSH_PENDING); + pThis->m_pCallbacks.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandFlush, + PORT_INDEX_IN,NULL ); + } else if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_IDLE_PENDING)) { + if (!pThis->output_flush_progress) { + DEBUG_PRINT_LOW("dev_stop called after input flush complete"); + if (dev_stop() != 0) { + DEBUG_PRINT_ERROR("ERROR: dev_stop() failed in i/p flush!"); + pThis->omx_report_error (); + } + } + } + } + + break; + + case OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH: + + pThis->output_flush_progress = false; + DEBUG_PRINT_HIGH("m_fbd_count at o/p flush = %" PRIu64, m_fbd_count); + m_fbd_count = 0; + if (pThis->m_pCallbacks.EventHandler) { + /*Check if we need generate event for Flush done*/ + if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_OUTPUT_FLUSH_PENDING)) { + BITMASK_CLEAR (&pThis->m_flags,OMX_COMPONENT_OUTPUT_FLUSH_PENDING); + + pThis->m_pCallbacks.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandFlush, + PORT_INDEX_OUT,NULL ); + } else if (BITMASK_PRESENT(&pThis->m_flags ,OMX_COMPONENT_IDLE_PENDING)) { + DEBUG_PRINT_LOW("dev_stop called after Output flush complete"); + if (!pThis->input_flush_progress) { + if (dev_stop() != 0) { + DEBUG_PRINT_ERROR("ERROR: dev_stop() failed in o/p flush!"); + pThis->omx_report_error (); + } + } + } + } + break; + + case OMX_COMPONENT_GENERATE_START_DONE: + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_START_DONE msg"); + + if (pThis->m_pCallbacks.EventHandler) { + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_START_DONE Success"); + if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_EXECUTE_PENDING)) { + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_START_DONE Move to \ + executing"); + // Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_EXECUTE_PENDING); + pThis->m_state = OMX_StateExecuting; + pThis->m_pCallbacks.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StateExecuting, NULL); + } else if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_PAUSE_PENDING)) { + if (dev_pause()) { + DEBUG_PRINT_ERROR("ERROR: dev_pause() failed in Start Done!"); + pThis->omx_report_error (); + } + } else if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_LOADED_START_PENDING)) { + if (dev_loaded_start_done()) { + DEBUG_PRINT_LOW("successful loaded Start Done!"); + } else { + DEBUG_PRINT_ERROR("ERROR: failed in loaded Start Done!"); + pThis->omx_report_error (); + } + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_LOADED_START_PENDING); + } else { + DEBUG_PRINT_LOW("ERROR: unknown flags=%" PRIx64, pThis->m_flags); + } + } else { + DEBUG_PRINT_LOW("Event Handler callback is NULL"); + } + break; + + case OMX_COMPONENT_GENERATE_PAUSE_DONE: + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_PAUSE_DONE msg"); + if (pThis->m_pCallbacks.EventHandler) { + if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_PAUSE_PENDING)) { + //Send the callback now + pThis->complete_pending_buffer_done_cbs(); + DEBUG_PRINT_LOW("omx_video::process_event_cb() Sending PAUSE complete after all pending EBD/FBD"); + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_PAUSE_PENDING); + pThis->m_state = OMX_StatePause; + pThis->m_pCallbacks.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StatePause, NULL); + } + } + + break; + + case OMX_COMPONENT_GENERATE_RESUME_DONE: + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_RESUME_DONE msg"); + if (pThis->m_pCallbacks.EventHandler) { + if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_EXECUTE_PENDING)) { + // Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_EXECUTE_PENDING); + pThis->m_state = OMX_StateExecuting; + pThis->m_pCallbacks.EventHandler(&pThis->m_cmp, pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StateExecuting,NULL); + } + } + + break; + + case OMX_COMPONENT_GENERATE_STOP_DONE: + DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_STOP_DONE msg"); + if (pThis->m_pCallbacks.EventHandler) { + pThis->complete_pending_buffer_done_cbs(); + if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_IDLE_PENDING)) { + // Send the callback now + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_IDLE_PENDING); + pThis->m_state = OMX_StateIdle; + pThis->m_pCallbacks.EventHandler(&pThis->m_cmp,pThis->m_app_data, + OMX_EventCmdComplete,OMX_CommandStateSet, + OMX_StateIdle,NULL); + } else if (BITMASK_PRESENT(&pThis->m_flags, + OMX_COMPONENT_LOADED_STOP_PENDING)) { + if (dev_loaded_stop_done()) { + DEBUG_PRINT_LOW("successful loaded Stop Done!"); + } else { + DEBUG_PRINT_ERROR("ERROR: failed in loaded Stop Done!"); + pThis->omx_report_error (); + } + BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_LOADED_STOP_PENDING); + } else { + DEBUG_PRINT_LOW("ERROR: unknown flags=%" PRIx64, pThis->m_flags); + } + } + + break; + + case OMX_COMPONENT_GENERATE_HARDWARE_ERROR: + DEBUG_PRINT_ERROR("ERROR: OMX_COMPONENT_GENERATE_HARDWARE_ERROR!"); + pThis->omx_report_error (); + break; +#ifndef _MSM8974_ + case OMX_COMPONENT_GENERATE_LTRUSE_FAILED: + DEBUG_PRINT_ERROR("ERROR: OMX_COMPONENT_GENERATE_LTRUSE_FAILED!"); + if (pThis->m_pCallbacks.EventHandler) { + DEBUG_PRINT_ERROR("Sending QOMX_ErrorLTRUseFailed, p2 = 0x%x", p2); + pThis->m_pCallbacks.EventHandler( + &pThis->m_cmp, pThis->m_app_data, + OMX_EventError, QOMX_ErrorLTRUseFailed, NULL, NULL); + } + break; +#endif + case OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING: + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING"); + pThis->omx_report_unsupported_setting(); + break; + + case OMX_COMPONENT_GENERATE_HARDWARE_OVERLOAD: + DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_HARDWARE_OVERLOAD"); + pThis->omx_report_hw_overload(); + break; + + default: + DEBUG_PRINT_LOW("process_event_cb unknown msg id 0x%02x", id); + break; + } + } + + pthread_mutex_lock(&pThis->m_lock); + qsize = pThis->m_cmd_q.m_size + pThis->m_ftb_q.m_size +\ + pThis->m_etb_q.m_size; + + pthread_mutex_unlock(&pThis->m_lock); + + } while (qsize>0); + DEBUG_PRINT_LOW("exited the while loop"); + +} + + + + +/* ====================================================================== + FUNCTION + omx_venc::GetComponentVersion + + DESCRIPTION + Returns the component version. + + PARAMETERS + TBD. + + RETURN VALUE + OMX_ErrorNone. + + ========================================================================== */ +OMX_ERRORTYPE omx_video::get_component_version +( + OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STRING componentName, + OMX_OUT OMX_VERSIONTYPE* componentVersion, + OMX_OUT OMX_VERSIONTYPE* specVersion, + OMX_OUT OMX_UUIDTYPE* componentUUID + ) +{ + (void)hComp; + (void)componentName; + (void)componentVersion; + (void)componentUUID; + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: Get Comp Version in Invalid State"); + return OMX_ErrorInvalidState; + } + /* TBD -- Return the proper version */ + if (specVersion) { + specVersion->nVersion = OMX_SPEC_VERSION; + } + return OMX_ErrorNone; +} +/* ====================================================================== + FUNCTION + omx_venc::SendCommand + + DESCRIPTION + Returns zero if all the buffers released.. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_video::send_command(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData + ) +{ + (void)hComp; + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: Send Command in Invalid State"); + return OMX_ErrorInvalidState; + } + + if (cmd == OMX_CommandFlush || cmd == OMX_CommandPortDisable || cmd == OMX_CommandPortEnable) { + if ((param1 != (OMX_U32)PORT_INDEX_IN) && (param1 != (OMX_U32)PORT_INDEX_OUT) && (param1 != (OMX_U32)PORT_INDEX_BOTH)) { + DEBUG_PRINT_ERROR("ERROR: omx_video::send_command-->bad port index"); + return OMX_ErrorBadPortIndex; + } + } + if (cmd == OMX_CommandMarkBuffer) { + if (param1 != PORT_INDEX_IN) { + DEBUG_PRINT_ERROR("ERROR: omx_video::send_command-->bad port index"); + return OMX_ErrorBadPortIndex; + } + if (!cmdData) { + DEBUG_PRINT_ERROR("ERROR: omx_video::send_command-->param is null"); + return OMX_ErrorBadParameter; + } + } + + post_event((unsigned long)cmd,(unsigned long)param1,OMX_COMPONENT_GENERATE_COMMAND); + sem_wait(&m_cmd_lock); + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_venc::SendCommand + + DESCRIPTION + Returns zero if all the buffers released.. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_video::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_COMMANDTYPE cmd, + OMX_IN OMX_U32 param1, + OMX_IN OMX_PTR cmdData + ) +{ + (void)hComp; + (void)cmdData; + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_STATETYPE eState = (OMX_STATETYPE) param1; + int bFlag = 1; + + if (cmd == OMX_CommandStateSet) { + /***************************/ + /* Current State is Loaded */ + /***************************/ + if (m_state == OMX_StateLoaded) { + if (eState == OMX_StateIdle) { + //if all buffers are allocated or all ports disabled + if (allocate_done() || + ( m_sInPortDef.bEnabled == OMX_FALSE && m_sOutPortDef.bEnabled == OMX_FALSE)) { + DEBUG_PRINT_LOW("OMXCORE-SM: Loaded-->Idle"); + } else { + DEBUG_PRINT_LOW("OMXCORE-SM: Loaded-->Idle-Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING); + // Skip the event notification + bFlag = 0; + } + } + /* Requesting transition from Loaded to Loaded */ + else if (eState == OMX_StateLoaded) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Loaded-->Loaded"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Loaded to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + /* Since error is None , we will post an event + at the end of this function definition */ + DEBUG_PRINT_LOW("OMXCORE-SM: Loaded-->WaitForResources"); + } + /* Requesting transition from Loaded to Executing */ + else if (eState == OMX_StateExecuting) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Loaded-->Executing"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Loaded to Pause */ + else if (eState == OMX_StatePause) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Loaded-->Pause"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Loaded to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Loaded-->Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } else { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Loaded-->%d Not Handled",\ + eState); + eRet = OMX_ErrorBadParameter; + } + } + + /***************************/ + /* Current State is IDLE */ + /***************************/ + else if (m_state == OMX_StateIdle) { + if (eState == OMX_StateLoaded) { + if (release_done()) { + /* + Since error is None , we will post an event at the end + of this function definition + */ + DEBUG_PRINT_LOW("OMXCORE-SM: Idle-->Loaded"); + if (dev_stop() != 0) { + DEBUG_PRINT_ERROR("ERROR: dev_stop() failed at Idle --> Loaded"); + eRet = OMX_ErrorHardware; + } + } else { + DEBUG_PRINT_LOW("OMXCORE-SM: Idle-->Loaded-Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING); + // Skip the event notification + bFlag = 0; + } + } + /* Requesting transition from Idle to Executing */ + else if (eState == OMX_StateExecuting) { + if ( dev_start() ) { + DEBUG_PRINT_ERROR("ERROR: dev_start() failed in SCP on Idle --> Exe"); + omx_report_error (); + eRet = OMX_ErrorHardware; + } else { + BITMASK_SET(&m_flags,OMX_COMPONENT_EXECUTE_PENDING); + DEBUG_PRINT_LOW("OMXCORE-SM: Idle-->Executing"); + bFlag = 0; + } + + dev_start_done(); + } + /* Requesting transition from Idle to Idle */ + else if (eState == OMX_StateIdle) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Idle-->Idle"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Idle to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Idle-->WaitForResources"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Idle to Pause */ + else if (eState == OMX_StatePause) { + /*To pause the Video core we need to start the driver*/ + if ( dev_start() ) { + DEBUG_PRINT_ERROR("ERROR: dev_start() failed in SCP on Idle --> Pause"); + omx_report_error (); + eRet = OMX_ErrorHardware; + } else { + BITMASK_SET(&m_flags,OMX_COMPONENT_PAUSE_PENDING); + DEBUG_PRINT_LOW("OMXCORE-SM: Idle-->Pause"); + bFlag = 0; + } + } + /* Requesting transition from Idle to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Idle-->Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } else { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Idle --> %d Not Handled",eState); + eRet = OMX_ErrorBadParameter; + } + } + + /******************************/ + /* Current State is Executing */ + /******************************/ + else if (m_state == OMX_StateExecuting) { + /* Requesting transition from Executing to Idle */ + if (eState == OMX_StateIdle) { + /* Since error is None , we will post an event + at the end of this function definition + */ + DEBUG_PRINT_LOW("OMXCORE-SM: Executing --> Idle"); + //here this should be Pause-Idle pending and should be cleared when flush is complete and change the state to Idle + BITMASK_SET(&m_flags,OMX_COMPONENT_IDLE_PENDING); + execute_omx_flush(OMX_ALL); + bFlag = 0; + } + /* Requesting transition from Executing to Paused */ + else if (eState == OMX_StatePause) { + + if (dev_pause()) { + DEBUG_PRINT_ERROR("ERROR: dev_pause() failed in SCP on Exe --> Pause"); + post_event(OMX_EventError,OMX_ErrorHardware,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorHardware; + } else { + BITMASK_SET(&m_flags,OMX_COMPONENT_PAUSE_PENDING); + DEBUG_PRINT_LOW("OMXCORE-SM: Executing-->Pause"); + bFlag = 0; + } + } + /* Requesting transition from Executing to Loaded */ + else if (eState == OMX_StateLoaded) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Executing --> Loaded"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Executing to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Executing --> WaitForResources"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Executing to Executing */ + else if (eState == OMX_StateExecuting) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Executing --> Executing"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Executing to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Executing --> Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } else { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Executing --> %d Not Handled",eState); + eRet = OMX_ErrorBadParameter; + } + } + /***************************/ + /* Current State is Pause */ + /***************************/ + else if (m_state == OMX_StatePause) { + /* Requesting transition from Pause to Executing */ + if (eState == OMX_StateExecuting) { + DEBUG_PRINT_LOW("Pause --> Executing"); + if ( dev_resume() ) { + post_event(OMX_EventError,OMX_ErrorHardware,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorHardware; + } else { + BITMASK_SET(&m_flags,OMX_COMPONENT_EXECUTE_PENDING); + DEBUG_PRINT_LOW("OMXCORE-SM: Pause-->Executing"); + post_event (0, 0, OMX_COMPONENT_GENERATE_RESUME_DONE); + bFlag = 0; + } + } + /* Requesting transition from Pause to Idle */ + else if (eState == OMX_StateIdle) { + /* Since error is None , we will post an event + at the end of this function definition */ + DEBUG_PRINT_LOW("Pause --> Idle"); + BITMASK_SET(&m_flags,OMX_COMPONENT_IDLE_PENDING); + execute_omx_flush(OMX_ALL); + bFlag = 0; + } + /* Requesting transition from Pause to loaded */ + else if (eState == OMX_StateLoaded) { + DEBUG_PRINT_ERROR("ERROR: Pause --> loaded"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Pause to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + DEBUG_PRINT_ERROR("ERROR: Pause --> WaitForResources"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from Pause to Pause */ + else if (eState == OMX_StatePause) { + DEBUG_PRINT_ERROR("ERROR: Pause --> Pause"); + post_event(OMX_EventError,OMX_ErrorSameState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from Pause to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: Pause --> Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } else { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Paused --> %d Not Handled",eState); + eRet = OMX_ErrorBadParameter; + } + } + /***************************/ + /* Current State is WaitForResources */ + /***************************/ + else if (m_state == OMX_StateWaitForResources) { + /* Requesting transition from WaitForResources to Loaded */ + if (eState == OMX_StateLoaded) { + /* Since error is None , we will post an event + at the end of this function definition */ + DEBUG_PRINT_LOW("OMXCORE-SM: WaitForResources-->Loaded"); + } + /* Requesting transition from WaitForResources to WaitForResources */ + else if (eState == OMX_StateWaitForResources) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: WaitForResources-->WaitForResources"); + post_event(OMX_EventError,OMX_ErrorSameState, + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorSameState; + } + /* Requesting transition from WaitForResources to Executing */ + else if (eState == OMX_StateExecuting) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: WaitForResources-->Executing"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from WaitForResources to Pause */ + else if (eState == OMX_StatePause) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: WaitForResources-->Pause"); + post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorIncorrectStateTransition; + } + /* Requesting transition from WaitForResources to Invalid */ + else if (eState == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: WaitForResources-->Invalid"); + post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } + /* Requesting transition from WaitForResources to Loaded - + is NOT tested by Khronos TS */ + + } else { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: %d --> %d(Not Handled)",m_state,eState); + eRet = OMX_ErrorBadParameter; + } + } + /********************************/ + /* Current State is Invalid */ + /*******************************/ + else if (m_state == OMX_StateInvalid) { + /* State Transition from Inavlid to any state */ + if (eState == (OMX_StateLoaded || OMX_StateWaitForResources + || OMX_StateIdle || OMX_StateExecuting + || OMX_StatePause || OMX_StateInvalid)) { + DEBUG_PRINT_ERROR("ERROR: OMXCORE-SM: Invalid -->Loaded"); + post_event(OMX_EventError,OMX_ErrorInvalidState,\ + OMX_COMPONENT_GENERATE_EVENT); + eRet = OMX_ErrorInvalidState; + } + } else if (cmd == OMX_CommandFlush) { + if (0 == param1 || OMX_ALL == param1) { + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_FLUSH_PENDING); + } + if (1 == param1 || OMX_ALL == param1) { + //generate output flush event only. + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_FLUSH_PENDING); + } + + execute_omx_flush(param1); + bFlag = 0; + } else if ( cmd == OMX_CommandPortEnable) { + if (param1 == PORT_INDEX_IN || param1 == OMX_ALL) { + m_sInPortDef.bEnabled = OMX_TRUE; + + if ( (m_state == OMX_StateLoaded && + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || allocate_input_done()) { + post_event(OMX_CommandPortEnable,PORT_INDEX_IN, + OMX_COMPONENT_GENERATE_EVENT); + } else { + DEBUG_PRINT_LOW("OMXCORE-SM: Disabled-->Enabled Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING); + // Skip the event notification + bFlag = 0; + } + } + if (param1 == PORT_INDEX_OUT || param1 == OMX_ALL) { + m_sOutPortDef.bEnabled = OMX_TRUE; + + if ( (m_state == OMX_StateLoaded && + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) + || (allocate_output_done())) { + post_event(OMX_CommandPortEnable,PORT_INDEX_OUT, + OMX_COMPONENT_GENERATE_EVENT); + + } else { + DEBUG_PRINT_LOW("OMXCORE-SM: Disabled-->Enabled Pending"); + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + // Skip the event notification + bFlag = 0; + } + } + } else if (cmd == OMX_CommandPortDisable) { + if (param1 == PORT_INDEX_IN || param1 == OMX_ALL) { + m_sInPortDef.bEnabled = OMX_FALSE; + if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_input_done()) { + post_event(OMX_CommandPortDisable,PORT_INDEX_IN, + OMX_COMPONENT_GENERATE_EVENT); + } else { + BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING); + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) { + execute_omx_flush(PORT_INDEX_IN); + } + + // Skip the event notification + bFlag = 0; + } + } + if (param1 == PORT_INDEX_OUT || param1 == OMX_ALL) { + m_sOutPortDef.bEnabled = OMX_FALSE; + + if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) + && release_output_done()) { + post_event(OMX_CommandPortDisable,PORT_INDEX_OUT,\ + OMX_COMPONENT_GENERATE_EVENT); + } else { + BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) { + execute_omx_flush(PORT_INDEX_OUT); + } + // Skip the event notification + bFlag = 0; + + } + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Command received other than StateSet (%d)",cmd); + eRet = OMX_ErrorNotImplemented; + } + if (eRet == OMX_ErrorNone && bFlag) { + post_event(cmd,eState,OMX_COMPONENT_GENERATE_EVENT); + } + sem_post(&m_cmd_lock); + return eRet; +} + +/* ====================================================================== + FUNCTION + omx_venc::ExecuteOmxFlush + + DESCRIPTION + Executes the OMX flush. + + PARAMETERS + flushtype - input flush(1)/output flush(0)/ both. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_video::execute_omx_flush(OMX_U32 flushType) +{ + bool bRet = false; + DEBUG_PRINT_LOW("execute_omx_flush - %u", (unsigned int)flushType); +#ifdef _MSM8974_ + /* XXX: The driver/hardware does not support flushing of individual ports + * in all states. So we pretty much need to flush both ports internally, + * but client should only get the FLUSH_(INPUT|OUTPUT)_DONE for the one it + * requested. Since OMX_COMPONENT_(OUTPUT|INPUT)_FLUSH_PENDING isn't set, + * we automatically omit sending the FLUSH done for the "opposite" port. */ + + input_flush_progress = true; + output_flush_progress = true; + bRet = execute_flush_all(); +#else + if (flushType == 0 || flushType == OMX_ALL) { + input_flush_progress = true; + //flush input only + bRet = execute_input_flush(); + } + if (flushType == 1 || flushType == OMX_ALL) { + //flush output only + output_flush_progress = true; + bRet = execute_output_flush(); + } +#endif + return bRet; +} +/*========================================================================= +FUNCTION : execute_output_flush + +DESCRIPTION +Executes the OMX flush at OUTPUT PORT. + +PARAMETERS +None. + +RETURN VALUE +true/false +==========================================================================*/ +bool omx_video::execute_output_flush(void) +{ + unsigned long p1 = 0; // Parameter - 1 + unsigned long p2 = 0; // Parameter - 2 + unsigned long ident = 0; + bool bRet = true; + + /*Generate FBD for all Buffers in the FTBq*/ + DEBUG_PRINT_LOW("execute_output_flush"); + pthread_mutex_lock(&m_lock); + while (m_ftb_q.m_size) { + m_ftb_q.pop_entry(&p1,&p2,&ident); + + if (ident == OMX_COMPONENT_GENERATE_FTB ) { + pending_output_buffers++; + VIDC_TRACE_INT_LOW("FTB-pending", pending_output_buffers); + fill_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p2); + } else if (ident == OMX_COMPONENT_GENERATE_FBD) { + fill_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1); + } + } + + pthread_mutex_unlock(&m_lock); + /*Check if there are buffers with the Driver*/ + if (dev_flush(PORT_INDEX_OUT)) { + DEBUG_PRINT_ERROR("ERROR: o/p dev_flush() Failed"); + return false; + } + + return bRet; +} +/*========================================================================= +FUNCTION : execute_input_flush + +DESCRIPTION +Executes the OMX flush at INPUT PORT. + +PARAMETERS +None. + +RETURN VALUE +true/false +==========================================================================*/ +bool omx_video::execute_input_flush(void) +{ + unsigned long p1 = 0; // Parameter - 1 + unsigned long p2 = 0; // Parameter - 2 + unsigned long ident = 0; + bool bRet = true; + + /*Generate EBD for all Buffers in the ETBq*/ + DEBUG_PRINT_LOW("execute_input_flush"); + + pthread_mutex_lock(&m_lock); + while (m_etb_q.m_size) { + m_etb_q.pop_entry(&p1,&p2,&ident); + if (ident == OMX_COMPONENT_GENERATE_ETB) { + pending_input_buffers++; + VIDC_TRACE_INT_LOW("ETB-pending", pending_input_buffers); + empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p2); + } else if (ident == OMX_COMPONENT_GENERATE_EBD) { + empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1); + } else if (ident == OMX_COMPONENT_GENERATE_ETB_OPQ) { + m_pCallbacks.EmptyBufferDone(&m_cmp,m_app_data,(OMX_BUFFERHEADERTYPE *)p2); + } + } + if (mUseProxyColorFormat) { + if (psource_frame) { + m_pCallbacks.EmptyBufferDone(&m_cmp,m_app_data,psource_frame); + psource_frame = NULL; + } + while (m_opq_meta_q.m_size) { + unsigned long p1,p2,id; + m_opq_meta_q.pop_entry(&p1,&p2,&id); + m_pCallbacks.EmptyBufferDone(&m_cmp,m_app_data, + (OMX_BUFFERHEADERTYPE *)p1); + } + if (pdest_frame) { + m_opq_pmem_q.insert_entry((unsigned long)pdest_frame,0,0); + pdest_frame = NULL; + } + } + pthread_mutex_unlock(&m_lock); + /*Check if there are buffers with the Driver*/ + if (dev_flush(PORT_INDEX_IN)) { + DEBUG_PRINT_ERROR("ERROR: i/p dev_flush() Failed"); + return false; + } + + return bRet; +} + + +/*========================================================================= +FUNCTION : execute_flush + +DESCRIPTION +Executes the OMX flush at INPUT & OUTPUT PORT. + +PARAMETERS +None. + +RETURN VALUE +true/false +==========================================================================*/ +#ifdef _MSM8974_ +bool omx_video::execute_flush_all(void) +{ + unsigned long p1 = 0; // Parameter - 1 + unsigned long p2 = 0; // Parameter - 2 + unsigned long ident = 0; + bool bRet = true; + + DEBUG_PRINT_LOW("execute_flush_all"); + + /*Generate EBD for all Buffers in the ETBq*/ + pthread_mutex_lock(&m_lock); + while (m_etb_q.m_size) { + m_etb_q.pop_entry(&p1,&p2,&ident); + if (ident == OMX_COMPONENT_GENERATE_ETB) { + pending_input_buffers++; + VIDC_TRACE_INT_LOW("ETB-pending", pending_input_buffers); + empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p2); + } else if (ident == OMX_COMPONENT_GENERATE_EBD) { + empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1); + } else if(ident == OMX_COMPONENT_GENERATE_ETB_OPQ) { + m_pCallbacks.EmptyBufferDone(&m_cmp,m_app_data,(OMX_BUFFERHEADERTYPE *)p2); + } + } + if(mUseProxyColorFormat) { + if(psource_frame) { + m_pCallbacks.EmptyBufferDone(&m_cmp,m_app_data,psource_frame); + psource_frame = NULL; + } + while(m_opq_meta_q.m_size) { + unsigned long p1,p2,id; + m_opq_meta_q.pop_entry(&p1,&p2,&id); + m_pCallbacks.EmptyBufferDone(&m_cmp,m_app_data, + (OMX_BUFFERHEADERTYPE *)p1); + } + if(pdest_frame){ + m_opq_pmem_q.insert_entry((unsigned long)pdest_frame,0,0); + pdest_frame = NULL; + } + } + + /*Generate FBD for all Buffers in the FTBq*/ + DEBUG_PRINT_LOW("execute_output_flush"); + while (m_ftb_q.m_size) { + m_ftb_q.pop_entry(&p1,&p2,&ident); + + if (ident == OMX_COMPONENT_GENERATE_FTB ) { + pending_output_buffers++; + VIDC_TRACE_INT_LOW("FTB-pending", pending_output_buffers); + fill_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p2); + } else if (ident == OMX_COMPONENT_GENERATE_FBD) { + fill_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1); + } + } + + pthread_mutex_unlock(&m_lock); + + /*Check if there are buffers with the Driver*/ + if (dev_flush(PORT_INDEX_BOTH)) { + DEBUG_PRINT_ERROR("ERROR: dev_flush() Failed"); + return false; + } + return bRet; +} + +#endif + +/* ====================================================================== + FUNCTION + omx_venc::SendCommandEvent + + DESCRIPTION + Send the event to decoder pipe. This is needed to generate the callbacks + in decoder thread context. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_video::post_event(unsigned long p1, + unsigned long p2, + unsigned long id) +{ + bool bRet = false; + + pthread_mutex_lock(&m_lock); + + if ((id == OMX_COMPONENT_GENERATE_FTB) || + (id == OMX_COMPONENT_GENERATE_FBD) || + (id == OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH)) { + m_ftb_q.insert_entry(p1,p2,id); + } else if ((id == OMX_COMPONENT_GENERATE_ETB) || + (id == OMX_COMPONENT_GENERATE_EBD) || + (id == OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH)) { + m_etb_q.insert_entry(p1,p2,id); + } else { + m_cmd_q.insert_entry(p1,p2,id); + } + + bRet = true; + DEBUG_PRINT_LOW("Value of this pointer in post_event %p",this); + post_message(this, id); + pthread_mutex_unlock(&m_lock); + + return bRet; +} + +/* ====================================================================== + FUNCTION + omx_venc::GetParameter + + DESCRIPTION + OMX Get Parameter method implementation + + PARAMETERS + <TBD>. + + RETURN VALUE + Error None if successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_video::get_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_INOUT OMX_PTR paramData) +{ + (void)hComp; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned int height=0,width = 0; + + DEBUG_PRINT_LOW("get_parameter:"); + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: Get Param in Invalid State"); + return OMX_ErrorInvalidState; + } + if (paramData == NULL) { + DEBUG_PRINT_ERROR("ERROR: Get Param in Invalid paramData"); + return OMX_ErrorBadParameter; + } + switch ((int)paramIndex) { + case OMX_IndexParamPortDefinition: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_PORTDEFINITIONTYPE); + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamPortDefinition"); + if (portDefn->nPortIndex == (OMX_U32) PORT_INDEX_IN) { + dev_get_buf_req (&m_sInPortDef.nBufferCountMin, + &m_sInPortDef.nBufferCountActual, + &m_sInPortDef.nBufferSize, + m_sInPortDef.nPortIndex); + DEBUG_PRINT_LOW("m_sInPortDef: size = %u, min cnt = %u, actual cnt = %u", + (unsigned int)m_sInPortDef.nBufferSize, (unsigned int)m_sInPortDef.nBufferCountMin, + (unsigned int)m_sInPortDef.nBufferCountActual); + memcpy(portDefn, &m_sInPortDef, sizeof(m_sInPortDef)); +#ifdef _ANDROID_ICS_ + if (meta_mode_enable) { + // request size of largest metadata (happens to be NativeHandleSource) since + // we do not know the exact metadata-type yet + portDefn->nBufferSize = sizeof(LEGACY_CAM_METADATA_TYPE); + } + if (mUseProxyColorFormat) { + portDefn->format.video.eColorFormat = + (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FormatAndroidOpaque; + } +#endif + } else if (portDefn->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (m_state != OMX_StateExecuting) { + dev_get_buf_req (&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + m_sOutPortDef.nPortIndex); + } + DEBUG_PRINT_LOW("m_sOutPortDef: size = %u, min cnt = %u, actual cnt = %u", + (unsigned int)m_sOutPortDef.nBufferSize, (unsigned int)m_sOutPortDef.nBufferCountMin, + (unsigned int)m_sOutPortDef.nBufferCountActual); + memcpy(portDefn, &m_sOutPortDef, sizeof(m_sOutPortDef)); + } else { + DEBUG_PRINT_ERROR("ERROR: GetParameter called on Bad Port Index"); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamVideoInit: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PORT_PARAM_TYPE); + OMX_PORT_PARAM_TYPE *portParamType = + (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoInit"); + + memcpy(portParamType, &m_sPortParam, sizeof(m_sPortParam)); + break; + } + case OMX_IndexParamVideoPortFormat: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_PORTFORMATTYPE); + OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoPortFormat"); + + if (portFmt->nPortIndex == (OMX_U32) PORT_INDEX_IN) { + unsigned index = portFmt->nIndex; + +#ifdef _UBWC_ + //we support following formats + //index 0 - Compressed (UBWC) Venus flavour of YUV420SP + //index 1 - Venus flavour of YUV420SP + //index 2 - Compressed (UBWC) Venus flavour of RGBA8888 + //index 3 - Venus flavour of RGBA8888 + //index 4 - opaque which internally maps to YUV420SP. + //index 5 - vannilla YUV420SP + //this can be extended in the future + int supportedFormats[] = { + [0] = QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed, + [1] = QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m, + [2] = QOMX_COLOR_Format32bitRGBA8888Compressed, + [3] = QOMX_COLOR_Format32bitRGBA8888, + [4] = QOMX_COLOR_FormatAndroidOpaque, + [5] = OMX_COLOR_FormatYUV420SemiPlanar, + }; +#else + //we support two formats + //index 0 - Venus flavour of YUV420SP + //index 1 - opaque which internally maps to YUV420SP. + //index 2 - vannilla YUV420SP + //this can be extended in the future + int supportedFormats[] = { + [0] = QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m, + [1] = QOMX_COLOR_FormatAndroidOpaque, + [2] = OMX_COLOR_FormatYUV420SemiPlanar, + }; +#endif + if (index > (sizeof(supportedFormats)/sizeof(*supportedFormats) - 1)) + eRet = OMX_ErrorNoMore; + else { + memcpy(portFmt, &m_sInPortFormat, sizeof(m_sInPortFormat)); + portFmt->nIndex = index; //restore index set from client + portFmt->eColorFormat = (OMX_COLOR_FORMATTYPE)supportedFormats[index]; + } + } else if (portFmt->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + memcpy(portFmt, &m_sOutPortFormat, sizeof(m_sOutPortFormat)); + } else { + DEBUG_PRINT_ERROR("ERROR: GetParameter called on Bad Port Index"); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexParamVideoBitrate: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_BITRATETYPE); + OMX_VIDEO_PARAM_BITRATETYPE* pParam = (OMX_VIDEO_PARAM_BITRATETYPE*)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoBitrate"); + + if (pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + memcpy(pParam, &m_sParamBitrate, sizeof(m_sParamBitrate)); + } else { + DEBUG_PRINT_ERROR("ERROR: GetParameter called on Bad Port Index"); + eRet = OMX_ErrorBadPortIndex; + } + + break; + } + case OMX_IndexParamVideoMpeg4: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_MPEG4TYPE); + OMX_VIDEO_PARAM_MPEG4TYPE* pParam = (OMX_VIDEO_PARAM_MPEG4TYPE*)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoMpeg4"); + memcpy(pParam, &m_sParamMPEG4, sizeof(m_sParamMPEG4)); + break; + } + case OMX_IndexParamVideoH263: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_H263TYPE); + OMX_VIDEO_PARAM_H263TYPE* pParam = (OMX_VIDEO_PARAM_H263TYPE*)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoH263"); + memcpy(pParam, &m_sParamH263, sizeof(m_sParamH263)); + break; + } + case OMX_IndexParamVideoAvc: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_AVCTYPE); + OMX_VIDEO_PARAM_AVCTYPE* pParam = (OMX_VIDEO_PARAM_AVCTYPE*)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoAvc"); + memcpy(pParam, &m_sParamAVC, sizeof(m_sParamAVC)); + break; + } + case (OMX_INDEXTYPE)OMX_IndexParamVideoVp8: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_VP8TYPE); + OMX_VIDEO_PARAM_VP8TYPE* pParam = (OMX_VIDEO_PARAM_VP8TYPE*)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoVp8"); + memcpy(pParam, &m_sParamVP8, sizeof(m_sParamVP8)); + break; + } + case (OMX_INDEXTYPE)OMX_IndexParamVideoHevc: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_HEVCTYPE); + OMX_VIDEO_PARAM_HEVCTYPE* pParam = (OMX_VIDEO_PARAM_HEVCTYPE*)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoHevc"); + memcpy(pParam, &m_sParamHEVC, sizeof(m_sParamHEVC)); + break; + } + case OMX_IndexParamVideoProfileLevelQuerySupported: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_PROFILELEVELTYPE); + OMX_VIDEO_PARAM_PROFILELEVELTYPE* pParam = (OMX_VIDEO_PARAM_PROFILELEVELTYPE*)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported"); + eRet = get_supported_profile_level(pParam); + if (eRet && eRet != OMX_ErrorNoMore) + DEBUG_PRINT_ERROR("Invalid entry returned from get_supported_profile_level %u, %u", + (unsigned int)pParam->eProfile, (unsigned int)pParam->eLevel); + break; + } + case OMX_IndexParamVideoProfileLevelCurrent: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_PROFILELEVELTYPE); + OMX_VIDEO_PARAM_PROFILELEVELTYPE* pParam = (OMX_VIDEO_PARAM_PROFILELEVELTYPE*)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelCurrent"); + memcpy(pParam, &m_sParamProfileLevel, sizeof(m_sParamProfileLevel)); + break; + } + case OMX_QcomIndexConfigH264EntropyCodingCabac: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_VIDEO_H264ENTROPYCODINGTYPE); + QOMX_VIDEO_H264ENTROPYCODINGTYPE * pParam = (QOMX_VIDEO_H264ENTROPYCODINGTYPE*)paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_QcomIndexConfigH264EntropyCodingCabac"); + memcpy(pParam, &m_sParamEntropy, sizeof(m_sParamEntropy)); + break; + } + /*Component should support this port definition*/ + case OMX_IndexParamAudioInit: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PORT_PARAM_TYPE); + OMX_PORT_PARAM_TYPE *audioPortParamType = (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamAudioInit"); + memcpy(audioPortParamType, &m_sPortParam_audio, sizeof(m_sPortParam_audio)); + break; + } + /*Component should support this port definition*/ + case OMX_IndexParamImageInit: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PORT_PARAM_TYPE); + OMX_PORT_PARAM_TYPE *imagePortParamType = (OMX_PORT_PARAM_TYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamImageInit"); + memcpy(imagePortParamType, &m_sPortParam_img, sizeof(m_sPortParam_img)); + break; + + } + /*Component should support this port definition*/ + case OMX_IndexParamOtherInit: + { + DEBUG_PRINT_ERROR("ERROR: get_parameter: OMX_IndexParamOtherInit %08x", paramIndex); + eRet =OMX_ErrorUnsupportedIndex; + break; + } + case OMX_IndexParamStandardComponentRole: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_COMPONENTROLETYPE); + OMX_PARAM_COMPONENTROLETYPE *comp_role; + comp_role = (OMX_PARAM_COMPONENTROLETYPE *) paramData; + comp_role->nVersion.nVersion = OMX_SPEC_VERSION; + comp_role->nSize = sizeof(*comp_role); + + DEBUG_PRINT_LOW("Getparameter: OMX_IndexParamStandardComponentRole %d",paramIndex); + strlcpy((char*)comp_role->cRole,(const char*)m_cRole,OMX_MAX_STRINGNAME_SIZE); + break; + } + /* Added for parameter test */ + case OMX_IndexParamPriorityMgmt: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PRIORITYMGMTTYPE); + OMX_PRIORITYMGMTTYPE *priorityMgmType = (OMX_PRIORITYMGMTTYPE *) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamPriorityMgmt"); + memcpy(priorityMgmType, &m_sPriorityMgmt, sizeof(m_sPriorityMgmt)); + break; + } + /* Added for parameter test */ + case OMX_IndexParamCompBufferSupplier: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_BUFFERSUPPLIERTYPE); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamCompBufferSupplier"); + if (bufferSupplierType->nPortIndex ==(OMX_U32) PORT_INDEX_IN) { + memcpy(bufferSupplierType, &m_sInBufSupplier, sizeof(m_sInBufSupplier)); + } else if (bufferSupplierType->nPortIndex ==(OMX_U32) PORT_INDEX_OUT) { + memcpy(bufferSupplierType, &m_sOutBufSupplier, sizeof(m_sOutBufSupplier)); + } else { + DEBUG_PRINT_ERROR("ERROR: GetParameter called on Bad Port Index"); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_IndexParamVideoQuantization: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_QUANTIZATIONTYPE); + OMX_VIDEO_PARAM_QUANTIZATIONTYPE *session_qp = (OMX_VIDEO_PARAM_QUANTIZATIONTYPE*) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoQuantization"); + memcpy(session_qp, &m_sSessionQuantization, sizeof(m_sSessionQuantization)); + break; + } + + case OMX_QcomIndexParamVideoQPRange: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_VIDEO_PARAM_QPRANGETYPE); + OMX_QCOM_VIDEO_PARAM_QPRANGETYPE *qp_range = (OMX_QCOM_VIDEO_PARAM_QPRANGETYPE*) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_QcomIndexParamVideoQPRange"); + memcpy(qp_range, &m_sSessionQPRange, sizeof(m_sSessionQPRange)); + break; + } + + case OMX_QcomIndexParamVideoIPBQPRange: + { + OMX_QCOM_VIDEO_PARAM_IPB_QPRANGETYPE *qp_range = (OMX_QCOM_VIDEO_PARAM_IPB_QPRANGETYPE*) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_QCOM_VIDEO_PARAM_IPB_QPRANGETYPE"); + memcpy(qp_range, &m_sSessionIPBQPRange, sizeof(m_sSessionIPBQPRange)); + break; + } + + case OMX_IndexParamVideoErrorCorrection: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE); + OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE* errorresilience = (OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE*)paramData; + DEBUG_PRINT_LOW("OMX_IndexParamVideoErrorCorrection"); + errorresilience->bEnableHEC = m_sErrorCorrection.bEnableHEC; + errorresilience->bEnableResync = m_sErrorCorrection.bEnableResync; + errorresilience->nResynchMarkerSpacing = m_sErrorCorrection.nResynchMarkerSpacing; + break; + } + case OMX_IndexParamVideoIntraRefresh: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_INTRAREFRESHTYPE); + OMX_VIDEO_PARAM_INTRAREFRESHTYPE* intrarefresh = (OMX_VIDEO_PARAM_INTRAREFRESHTYPE*)paramData; + DEBUG_PRINT_LOW("OMX_IndexParamVideoIntraRefresh"); + DEBUG_PRINT_ERROR("OMX_IndexParamVideoIntraRefresh GET"); + intrarefresh->eRefreshMode = m_sIntraRefresh.eRefreshMode; + intrarefresh->nCirMBs = m_sIntraRefresh.nCirMBs; + break; + } + case OMX_QcomIndexPortDefn: + //TODO + break; + case OMX_COMPONENT_CAPABILITY_TYPE_INDEX: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMXComponentCapabilityFlagsType); + OMXComponentCapabilityFlagsType *pParam = reinterpret_cast<OMXComponentCapabilityFlagsType*>(paramData); + DEBUG_PRINT_LOW("get_parameter: OMX_COMPONENT_CAPABILITY_TYPE_INDEX"); + pParam->iIsOMXComponentMultiThreaded = OMX_TRUE; + pParam->iOMXComponentSupportsExternalOutputBufferAlloc = OMX_FALSE; + pParam->iOMXComponentSupportsExternalInputBufferAlloc = OMX_TRUE; + pParam->iOMXComponentSupportsMovableInputBuffers = OMX_TRUE; + pParam->iOMXComponentUsesNALStartCodes = OMX_TRUE; + pParam->iOMXComponentSupportsPartialFrames = OMX_FALSE; + pParam->iOMXComponentCanHandleIncompleteFrames = OMX_FALSE; + pParam->iOMXComponentUsesFullAVCFrames = OMX_FALSE; + m_use_input_pmem = OMX_TRUE; + DEBUG_PRINT_LOW("Supporting capability index in encoder node"); + break; + } +#if !defined(MAX_RES_720P) || defined(_MSM8974_) + case OMX_QcomIndexParamIndexExtraDataType: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_INDEXEXTRADATATYPE); + DEBUG_PRINT_LOW("get_parameter: OMX_QcomIndexParamIndexExtraDataType"); + QOMX_INDEXEXTRADATATYPE *pParam = (QOMX_INDEXEXTRADATATYPE *)paramData; + if (pParam->nIndex == (OMX_INDEXTYPE)OMX_ExtraDataVideoEncoderSliceInfo) { + if (pParam->nPortIndex == PORT_INDEX_OUT) { + pParam->bEnabled = + (OMX_BOOL)(m_sExtraData & VENC_EXTRADATA_SLICEINFO); + DEBUG_PRINT_HIGH("Slice Info extradata %d", pParam->bEnabled); + } else { + DEBUG_PRINT_ERROR("get_parameter: slice information is " + "valid for output port only"); + eRet = OMX_ErrorUnsupportedIndex; + } + } else if (pParam->nIndex == (OMX_INDEXTYPE)OMX_ExtraDataVideoEncoderMBInfo) { + if (pParam->nPortIndex == PORT_INDEX_OUT) { + pParam->bEnabled = + (OMX_BOOL)(m_sExtraData & VENC_EXTRADATA_MBINFO); + DEBUG_PRINT_HIGH("MB Info extradata %d", pParam->bEnabled); + } else { + DEBUG_PRINT_ERROR("get_parameter: MB information is " + "valid for output port only"); + eRet = OMX_ErrorUnsupportedIndex; + } + } else if (pParam->nIndex == (OMX_INDEXTYPE)OMX_ExtraDataFrameDimension) { + if (pParam->nPortIndex == PORT_INDEX_IN) { + pParam->bEnabled = + (OMX_BOOL)((m_sExtraData & VENC_EXTRADATA_FRAMEDIMENSION) ? 1 : 0); + DEBUG_PRINT_HIGH("Frame dimension extradata %d", pParam->bEnabled); + } else { + DEBUG_PRINT_ERROR("get_parameter: frame dimension is " + "valid for input port only"); + eRet = OMX_ErrorUnsupportedIndex; + } + } +#ifndef _MSM8974_ + else if (pParam->nIndex == (OMX_INDEXTYPE)OMX_ExtraDataVideoLTRInfo) { + if (pParam->nPortIndex == PORT_INDEX_OUT) { + pParam->bEnabled = + (OMX_BOOL)(m_sExtraData & VEN_EXTRADATA_LTRINFO); + DEBUG_PRINT_HIGH("LTR Info extradata %d", pParam->bEnabled); + } else { + DEBUG_PRINT_ERROR("get_parameter: LTR information is " + "valid for output port only"); + eRet = OMX_ErrorUnsupportedIndex; + } + } +#endif + else { + DEBUG_PRINT_ERROR("get_parameter: unsupported extradata index (0x%x)", + pParam->nIndex); + eRet = OMX_ErrorUnsupportedIndex; + } + break; + } + case QOMX_IndexParamVideoLTRCountRangeSupported: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_EXTNINDEX_RANGETYPE); + DEBUG_PRINT_HIGH("get_parameter: QOMX_IndexParamVideoLTRCountRangeSupported"); + QOMX_EXTNINDEX_RANGETYPE *pParam = (QOMX_EXTNINDEX_RANGETYPE *)paramData; + if (pParam->nPortIndex == PORT_INDEX_OUT) { + OMX_U32 min = 0, max = 0, step_size = 0; + if (dev_get_capability_ltrcount(&min, &max, &step_size)) { + pParam->nMin = min; + pParam->nMax = max; + pParam->nStepSize = step_size; + } else { + DEBUG_PRINT_ERROR("get_parameter: get_capability_ltrcount failed"); + eRet = OMX_ErrorUndefined; + } + } else { + DEBUG_PRINT_ERROR("LTR count range is valid for output port only"); + eRet = OMX_ErrorUnsupportedIndex; + } + } + break; + case OMX_QcomIndexParamVideoLTRCount: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_VIDEO_PARAM_LTRCOUNT_TYPE); + DEBUG_PRINT_LOW("get_parameter: OMX_QcomIndexParamVideoLTRCount"); + OMX_QCOM_VIDEO_PARAM_LTRCOUNT_TYPE *pParam = + reinterpret_cast<OMX_QCOM_VIDEO_PARAM_LTRCOUNT_TYPE*>(paramData); + memcpy(pParam, &m_sParamLTRCount, sizeof(m_sParamLTRCount)); + break; + } +#endif + case QOMX_IndexParamVideoSyntaxHdr: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_EXTNINDEX_PARAMTYPE); + DEBUG_PRINT_HIGH("QOMX_IndexParamVideoSyntaxHdr"); + QOMX_EXTNINDEX_PARAMTYPE* pParam = + reinterpret_cast<QOMX_EXTNINDEX_PARAMTYPE*>(paramData); + if (pParam->pData == NULL) { + DEBUG_PRINT_ERROR("Error: Data buffer is NULL"); + eRet = OMX_ErrorBadParameter; + break; + } + if (get_syntaxhdr_enable == false) { + DEBUG_PRINT_ERROR("ERROR: get_parameter: Get syntax header disabled"); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + BITMASK_SET(&m_flags, OMX_COMPONENT_LOADED_START_PENDING); + if (dev_loaded_start()) { + DEBUG_PRINT_LOW("device start successful"); + } else { + DEBUG_PRINT_ERROR("device start failed"); + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_LOADED_START_PENDING); + return OMX_ErrorHardware; + } + if (dev_get_seq_hdr(pParam->pData, + (unsigned)(pParam->nSize - sizeof(QOMX_EXTNINDEX_PARAMTYPE)), + (unsigned *)(void *)&pParam->nDataSize)) { + DEBUG_PRINT_HIGH("get syntax header successful (hdrlen = %u)", + (unsigned int)pParam->nDataSize); + for (unsigned i = 0; i < pParam->nDataSize; i++) { + DEBUG_PRINT_LOW("Header[%d] = %x", i, *((char *)pParam->pData + i)); + } + } else { + DEBUG_PRINT_ERROR("Error returned from GetSyntaxHeader()"); + eRet = OMX_ErrorHardware; + } + BITMASK_SET(&m_flags, OMX_COMPONENT_LOADED_STOP_PENDING); + if (dev_loaded_stop()) { + DEBUG_PRINT_LOW("device stop successful"); + } else { + DEBUG_PRINT_ERROR("device stop failed"); + BITMASK_CLEAR(&m_flags, OMX_COMPONENT_LOADED_STOP_PENDING); + eRet = OMX_ErrorHardware; + } + break; + } + case OMX_QcomIndexHierarchicalStructure: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_VIDEO_HIERARCHICALLAYERS); + QOMX_VIDEO_HIERARCHICALLAYERS* hierp = (QOMX_VIDEO_HIERARCHICALLAYERS*) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_QcomIndexHierarchicalStructure"); + memcpy(hierp, &m_sHierLayers, sizeof(m_sHierLayers)); + break; + } + case OMX_QcomIndexParamMBIStatisticsMode: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QOMX_VIDEO_MBI_STATISTICS); + OMX_QOMX_VIDEO_MBI_STATISTICS* mbi_mode = (OMX_QOMX_VIDEO_MBI_STATISTICS*) paramData; + DEBUG_PRINT_LOW("get_parameter: OMX_QcomIndexParamMBIStatisticsMode"); + memcpy(mbi_mode, &m_sMBIStatistics, sizeof(m_sMBIStatistics)); + break; + } + case OMX_QcomIndexParamPerfLevel: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_VIDEO_PARAM_PERF_LEVEL); + OMX_U32 perflevel; + OMX_QCOM_VIDEO_PARAM_PERF_LEVEL *pParam = + reinterpret_cast<OMX_QCOM_VIDEO_PARAM_PERF_LEVEL*>(paramData); + DEBUG_PRINT_LOW("get_parameter: OMX_QcomIndexParamPerfLevel"); + if (!dev_get_performance_level(&perflevel)) { + DEBUG_PRINT_ERROR("Invalid entry returned from get_performance_level %d", + pParam->ePerfLevel); + } else { + pParam->ePerfLevel = (QOMX_VIDEO_PERF_LEVEL)perflevel; + } + break; + } + case OMX_QcomIndexParamH264VUITimingInfo: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_VIDEO_PARAM_VUI_TIMING_INFO); + OMX_U32 enabled; + OMX_QCOM_VIDEO_PARAM_VUI_TIMING_INFO *pParam = + reinterpret_cast<OMX_QCOM_VIDEO_PARAM_VUI_TIMING_INFO*>(paramData); + DEBUG_PRINT_LOW("get_parameter: OMX_QcomIndexParamH264VUITimingInfo"); + if (!dev_get_vui_timing_info(&enabled)) { + DEBUG_PRINT_ERROR("Invalid entry returned from get_vui_Timing_info %d", + pParam->bEnable); + } else { + pParam->bEnable = (OMX_BOOL)enabled; + } + break; + } + case OMX_QTIIndexParamVQZIPSEIType: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QTI_VIDEO_PARAM_VQZIP_SEI_TYPE); + OMX_U32 enabled; + OMX_QTI_VIDEO_PARAM_VQZIP_SEI_TYPE *pParam = + reinterpret_cast<OMX_QTI_VIDEO_PARAM_VQZIP_SEI_TYPE*>(paramData); + DEBUG_PRINT_LOW("get_parameter: OMX_QTIIndexParamVQZIPSEIType"); + if (!dev_get_vqzip_sei_info(&enabled)) { + DEBUG_PRINT_ERROR("Invalid entry returned from get_vqzip_sei_type %d", + pParam->bEnable); + } else { + pParam->bEnable = (OMX_BOOL)enabled; + } + break; + } + case OMX_QcomIndexParamPeakBitrate: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_VIDEO_PARAM_PEAK_BITRATE); + OMX_U32 peakbitrate; + OMX_QCOM_VIDEO_PARAM_PEAK_BITRATE *pParam = + reinterpret_cast<OMX_QCOM_VIDEO_PARAM_PEAK_BITRATE*>(paramData); + DEBUG_PRINT_LOW("get_parameter: OMX_QcomIndexParamPeakBitrate"); + if (!dev_get_peak_bitrate(&peakbitrate)) { + DEBUG_PRINT_ERROR("Invalid entry returned from get_peak_bitrate %u", + (unsigned int)pParam->nPeakBitrate); + } else { + pParam->nPeakBitrate = peakbitrate; + } + break; + } + case QOMX_IndexParamVideoInitialQp: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_EXTNINDEX_VIDEO_INITIALQP); + QOMX_EXTNINDEX_VIDEO_INITIALQP* initqp = + reinterpret_cast<QOMX_EXTNINDEX_VIDEO_INITIALQP *>(paramData); + memcpy(initqp, &m_sParamInitqp, sizeof(m_sParamInitqp)); + break; + } + case OMX_QcomIndexParamBatchSize: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_U32TYPE); + OMX_PARAM_U32TYPE* batch = + reinterpret_cast<OMX_PARAM_U32TYPE *>(paramData); + + DEBUG_PRINT_LOW("get_parameter: OMX_QcomIndexParamBatchSize"); + if (!dev_get_batch_size(&batch->nU32)) { + DEBUG_PRINT_ERROR("Invalid entry returned from dev_get_batch_size %u", + (unsigned int)batch->nSize); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + + batch->nPortIndex = PORT_INDEX_IN; + break; + } + case OMX_QcomIndexParamSequenceHeaderWithIDR: + { + VALIDATE_OMX_PARAM_DATA(paramData, PrependSPSPPSToIDRFramesParams); + PrependSPSPPSToIDRFramesParams * pParam = + reinterpret_cast<PrependSPSPPSToIDRFramesParams *>(paramData); + DEBUG_PRINT_LOW("get_parameter: OMX_QcomIndexParamSequenceHeaderWithIDR"); + memcpy(pParam, &m_sPrependSPSPPS, sizeof(m_sPrependSPSPPS)); + break; + } + case OMX_QcomIndexParamVencAspectRatio: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_EXTNINDEX_VIDEO_VENC_SAR); + QOMX_EXTNINDEX_VIDEO_VENC_SAR * pParam = + reinterpret_cast<QOMX_EXTNINDEX_VIDEO_VENC_SAR *>(paramData); + memcpy(pParam, &m_sSar, sizeof(m_sSar)); + break; + } + case OMX_QTIIndexParamLowLatencyMode: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_EXTNINDEX_VIDEO_VENC_LOW_LATENCY_MODE); + QOMX_EXTNINDEX_VIDEO_VENC_LOW_LATENCY_MODE * pParam = + reinterpret_cast<QOMX_EXTNINDEX_VIDEO_VENC_LOW_LATENCY_MODE *>(paramData); + memcpy(pParam, &m_slowLatencyMode, sizeof(m_slowLatencyMode)); + break; + } + case OMX_IndexParamAndroidVideoTemporalLayering: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE); + OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE *pLayerInfo = + reinterpret_cast<OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE*>(paramData); + if (!dev_get_temporal_layer_caps(&m_sParamTemporalLayers.nLayerCountMax, + &m_sParamTemporalLayers.nBLayerCountMax)) { + DEBUG_PRINT_ERROR("Failed to get temporal layer capabilities"); + eRet = OMX_ErrorHardware; + } + memcpy(pLayerInfo, &m_sParamTemporalLayers, sizeof(m_sParamTemporalLayers)); + break; + } + case OMX_IndexParamVideoSliceFMO: + default: + { + DEBUG_PRINT_LOW("ERROR: get_parameter: unknown param %08x", paramIndex); + eRet =OMX_ErrorUnsupportedIndex; + break; + } + + } + + return eRet; + +} +/* ====================================================================== + FUNCTION + omx_video::GetConfig + + DESCRIPTION + OMX Get Config Method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_video::get_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_INOUT OMX_PTR configData) +{ + (void)hComp; + //////////////////////////////////////////////////////////////// + // Supported Config Index Type + // ============================================================= + // OMX_IndexConfigVideoBitrate OMX_VIDEO_CONFIG_BITRATETYPE + // OMX_IndexConfigVideoFramerate OMX_CONFIG_FRAMERATETYPE + // OMX_IndexConfigCommonRotate OMX_CONFIG_ROTATIONTYPE + //////////////////////////////////////////////////////////////// + + if (configData == NULL) { + DEBUG_PRINT_ERROR("ERROR: param is null"); + return OMX_ErrorBadParameter; + } + + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: can't be in invalid state"); + return OMX_ErrorIncorrectStateOperation; + } + + //@todo need to validate params + switch ((int)configIndex) { + case OMX_IndexConfigVideoBitrate: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_BITRATETYPE); + OMX_VIDEO_CONFIG_BITRATETYPE* pParam = reinterpret_cast<OMX_VIDEO_CONFIG_BITRATETYPE*>(configData); + memcpy(pParam, &m_sConfigBitrate, sizeof(m_sConfigBitrate)); + break; + } + case OMX_IndexConfigVideoFramerate: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_CONFIG_FRAMERATETYPE); + OMX_CONFIG_FRAMERATETYPE* pParam = reinterpret_cast<OMX_CONFIG_FRAMERATETYPE*>(configData); + memcpy(pParam, &m_sConfigFramerate, sizeof(m_sConfigFramerate)); + break; + } + case OMX_IndexConfigCommonRotate: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_CONFIG_ROTATIONTYPE); + OMX_CONFIG_ROTATIONTYPE* pParam = reinterpret_cast<OMX_CONFIG_ROTATIONTYPE*>(configData); + memcpy(pParam, &m_sConfigFrameRotation, sizeof(m_sConfigFrameRotation)); + break; + } + case QOMX_IndexConfigVideoIntraperiod: + { + DEBUG_PRINT_LOW("get_config:QOMX_IndexConfigVideoIntraperiod"); + VALIDATE_OMX_PARAM_DATA(configData, QOMX_VIDEO_INTRAPERIODTYPE); + QOMX_VIDEO_INTRAPERIODTYPE* pParam = reinterpret_cast<QOMX_VIDEO_INTRAPERIODTYPE*>(configData); + memcpy(pParam, &m_sIntraperiod, sizeof(m_sIntraperiod)); + break; + } + case OMX_IndexConfigVideoAVCIntraPeriod: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_AVCINTRAPERIOD); + OMX_VIDEO_CONFIG_AVCINTRAPERIOD *pParam = + reinterpret_cast<OMX_VIDEO_CONFIG_AVCINTRAPERIOD*>(configData); + DEBUG_PRINT_LOW("get_config: OMX_IndexConfigVideoAVCIntraPeriod"); + memcpy(pParam, &m_sConfigAVCIDRPeriod, sizeof(m_sConfigAVCIDRPeriod)); + break; + } + case OMX_IndexConfigCommonDeinterlace: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_DEINTERLACE); + OMX_VIDEO_CONFIG_DEINTERLACE *pParam = + reinterpret_cast<OMX_VIDEO_CONFIG_DEINTERLACE*>(configData); + DEBUG_PRINT_LOW("get_config: OMX_IndexConfigCommonDeinterlace"); + memcpy(pParam, &m_sConfigDeinterlace, sizeof(m_sConfigDeinterlace)); + break; + } + case OMX_IndexConfigVideoVp8ReferenceFrame: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_VP8REFERENCEFRAMETYPE); + OMX_VIDEO_VP8REFERENCEFRAMETYPE* pParam = + reinterpret_cast<OMX_VIDEO_VP8REFERENCEFRAMETYPE*>(configData); + DEBUG_PRINT_LOW("get_config: OMX_IndexConfigVideoVp8ReferenceFrame"); + memcpy(pParam, &m_sConfigVp8ReferenceFrame, sizeof(m_sConfigVp8ReferenceFrame)); + break; + } + case OMX_QcomIndexConfigPerfLevel: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_QCOM_VIDEO_CONFIG_PERF_LEVEL); + OMX_U32 perflevel; + OMX_QCOM_VIDEO_CONFIG_PERF_LEVEL *pParam = + reinterpret_cast<OMX_QCOM_VIDEO_CONFIG_PERF_LEVEL*>(configData); + DEBUG_PRINT_LOW("get_config: OMX_QcomIndexConfigPerfLevel"); + if (!dev_get_performance_level(&perflevel)) { + DEBUG_PRINT_ERROR("Invalid entry returned from get_performance_level %d", + pParam->ePerfLevel); + } else { + pParam->ePerfLevel = (QOMX_VIDEO_PERF_LEVEL)perflevel; + } + break; + } + case OMX_QcomIndexConfigNumHierPLayers: + { + VALIDATE_OMX_PARAM_DATA(configData, QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS); + QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS* pParam = + reinterpret_cast<QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS*>(configData); + DEBUG_PRINT_LOW("get_config: OMX_QcomIndexConfigNumHierPLayers"); + memcpy(pParam, &m_sHPlayers, sizeof(m_sHPlayers)); + break; + } + case OMX_QcomIndexConfigQp: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_SKYPE_VIDEO_CONFIG_QP); + OMX_SKYPE_VIDEO_CONFIG_QP* pParam = + reinterpret_cast<OMX_SKYPE_VIDEO_CONFIG_QP*>(configData); + DEBUG_PRINT_LOW("get_config: OMX_QcomIndexConfigQp"); + memcpy(pParam, &m_sConfigQP, sizeof(m_sConfigQP)); + break; + } + case OMX_QcomIndexConfigBaseLayerId: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_SKYPE_VIDEO_CONFIG_BASELAYERPID); + OMX_SKYPE_VIDEO_CONFIG_BASELAYERPID* pParam = + reinterpret_cast<OMX_SKYPE_VIDEO_CONFIG_BASELAYERPID*>(configData); + DEBUG_PRINT_LOW("get_config: OMX_QcomIndexConfigBaseLayerId"); + memcpy(pParam, &m_sBaseLayerID, sizeof(m_sBaseLayerID)); + break; + } +#ifdef SUPPORT_CONFIG_INTRA_REFRESH + case OMX_IndexConfigAndroidIntraRefresh: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE); + OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE* pParam = + reinterpret_cast<OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE*>(configData); + DEBUG_PRINT_LOW("get_config: OMX_IndexConfigAndroidIntraRefresh"); + memcpy(pParam, &m_sConfigIntraRefresh, sizeof(m_sConfigIntraRefresh)); + break; + } +#endif + case OMX_QTIIndexConfigVideoBlurResolution: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_QTI_VIDEO_CONFIG_BLURINFO); + OMX_QTI_VIDEO_CONFIG_BLURINFO* pParam = + reinterpret_cast<OMX_QTI_VIDEO_CONFIG_BLURINFO*>(configData); + DEBUG_PRINT_LOW("get_config: OMX_QTIIndexConfigVideoBlurResolution"); + memcpy(pParam, &m_blurInfo, sizeof(m_blurInfo)); + break; + } + case OMX_QTIIndexConfigDescribeColorAspects: + { + VALIDATE_OMX_PARAM_DATA(configData, DescribeColorAspectsParams); + DescribeColorAspectsParams* pParam = + reinterpret_cast<DescribeColorAspectsParams*>(configData); + DEBUG_PRINT_LOW("get_config: OMX_QTIIndexConfigDescribeColorAspects"); + if (pParam->bRequestingDataSpace) { + DEBUG_PRINT_ERROR("Does not handle dataspace request"); + return OMX_ErrorUnsupportedSetting; + } + if (pParam->bDataSpaceChanged == OMX_TRUE) { + + print_debug_color_aspects(&(pParam->sAspects), "get_config (dataspace changed) Client says"); + // If the dataspace says RGB, recommend 601-limited; + // since that is the destination colorspace that C2D or Venus will convert to. + if (pParam->nPixelFormat == HAL_PIXEL_FORMAT_RGBA_8888) { + DEBUG_PRINT_INFO("get_config (dataspace changed): ColorSpace: Recommend 601-limited for RGBA8888"); + pParam->sAspects.mPrimaries = ColorAspects::PrimariesBT601_6_625; + pParam->sAspects.mRange = ColorAspects::RangeLimited; + pParam->sAspects.mTransfer = ColorAspects::TransferSMPTE170M; + pParam->sAspects.mMatrixCoeffs = ColorAspects::MatrixBT601_6; + } else { + // For IMPLEMENTATION_DEFINED (or anything else), stick to client's defaults. + DEBUG_PRINT_INFO("get_config (dataspace changed): ColorSpace: use client-default for format=%x", + pParam->nPixelFormat); + } + print_debug_color_aspects(&(pParam->sAspects), "get_config (dataspace changed) recommended"); + } else { + memcpy(pParam, &m_sConfigColorAspects, sizeof(m_sConfigColorAspects)); + print_debug_color_aspects(&(pParam->sAspects), "get_config"); + } + break; + } + case OMX_IndexParamAndroidVideoTemporalLayering: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE); + OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE *layerConfig = + (OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE *)configData; + DEBUG_PRINT_LOW("get_config: OMX_IndexConfigAndroidVideoTemporalLayering"); + memcpy(configData, &m_sConfigTemporalLayers, sizeof(m_sConfigTemporalLayers)); + break; + } + + default: + DEBUG_PRINT_ERROR("ERROR: unsupported index %d", (int) configIndex); + return OMX_ErrorUnsupportedIndex; + } + return OMX_ErrorNone; + +} + +#define extn_equals(param, extn) (!strcmp(param, extn)) + +/* ====================================================================== + FUNCTION + omx_video::GetExtensionIndex + + DESCRIPTION + OMX GetExtensionIndex method implementaion. <TBD> + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_video::get_extension_index(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_STRING paramName, + OMX_OUT OMX_INDEXTYPE* indexType) +{ + (void)hComp; + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: Get Extension Index in Invalid State"); + return OMX_ErrorInvalidState; + } +#ifdef MAX_RES_1080P + if (extn_equals(paramName, "OMX.QCOM.index.param.SliceDeliveryMode")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexEnableSliceDeliveryMode; + return OMX_ErrorNone; + } +#endif +#ifdef _ANDROID_ICS_ + if (extn_equals(paramName, "OMX.google.android.index.storeMetaDataInBuffers")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoMetaBufferMode; + return OMX_ErrorNone; + } +#endif + if (extn_equals(paramName, "OMX.google.android.index.prependSPSPPSToIDRFrames")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamSequenceHeaderWithIDR; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, "OMX.QCOM.index.param.video.HierStructure")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexHierarchicalStructure; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, "OMX.QCOM.index.param.video.LTRCount")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoLTRCount; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, "OMX.QCOM.index.param.video.LTRPeriod")) { + return OMX_ErrorNone; + } + + if (extn_equals(paramName, "OMX.QCOM.index.config.video.LTRUse")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexConfigVideoLTRUse; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, "OMX.QCOM.index.config.video.LTRMark")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexConfigVideoLTRMark; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, "OMX.QCOM.index.config.video.hierplayers")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexConfigNumHierPLayers; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, "OMX.QCOM.index.param.video.baselayerid")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexConfigBaseLayerId; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, "OMX.QCOM.index.config.video.qp")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexConfigQp; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, "OMX.QCOM.index.param.video.sar")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVencAspectRatio; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, "OMX.QCOM.index.param.video.InputBatch")) { + *indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamBatchSize; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, "OMX.QTI.index.param.video.LowLatency")) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexParamLowLatencyMode; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, OMX_QTI_INDEX_CONFIG_VIDEO_SETTIMEDATA)) { + *indexType = (OMX_INDEXTYPE)OMX_IndexConfigTimePosition; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, OMX_QTI_INDEX_PARAM_VIDEO_ENABLE_ROIINFO)) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexParamVideoEnableRoiInfo; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, OMX_QTI_INDEX_CONFIG_VIDEO_ROIINFO)) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexConfigVideoRoiInfo; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, OMX_QTI_INDEX_CONFIG_VIDEO_BLURINFO)) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexConfigVideoBlurResolution; + return OMX_ErrorNone; + } + + if (extn_equals(paramName, "OMX.google.android.index.describeColorAspects")) { + *indexType = (OMX_INDEXTYPE)OMX_QTIIndexConfigDescribeColorAspects; + return OMX_ErrorNone; + } + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== + FUNCTION + omx_video::GetState + + DESCRIPTION + Returns the state information back to the caller.<TBD> + + PARAMETERS + <TBD>. + + RETURN VALUE + Error None if everything is successful. + ========================================================================== */ +OMX_ERRORTYPE omx_video::get_state(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_STATETYPE* state) +{ + (void)hComp; + *state = m_state; + DEBUG_PRINT_LOW("get_state: Returning the state %d",*state); + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_video::ComponentTunnelRequest + + DESCRIPTION + OMX Component Tunnel Request method implementation. <TBD> + + PARAMETERS + None. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_video::component_tunnel_request(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_HANDLETYPE peerComponent, + OMX_IN OMX_U32 peerPort, + OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup) +{ + (void) hComp, (void) port, (void) peerComponent, (void) peerPort, (void) tunnelSetup; + DEBUG_PRINT_ERROR("ERROR: component_tunnel_request Not Implemented"); + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== + FUNCTION + omx_video::UseInputBuffer + + DESCRIPTION + Helper function for Use buffer in the input pin + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_video::use_input_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + (void) hComp; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + unsigned i = 0; + unsigned char *buf_addr = NULL; + + DEBUG_PRINT_HIGH("use_input_buffer: port = %u appData = %p bytes = %u buffer = %p",(unsigned int)port,appData,(unsigned int)bytes,buffer); + if (bytes < m_sInPortDef.nBufferSize) { + DEBUG_PRINT_ERROR("ERROR: use_input_buffer: Size Mismatch!! " + "bytes[%u] < Port.nBufferSize[%u]", (unsigned int)bytes, (unsigned int)m_sInPortDef.nBufferSize); + return OMX_ErrorBadParameter; + } + + if (!m_inp_mem_ptr) { + input_use_buffer = true; + m_inp_mem_ptr = (OMX_BUFFERHEADERTYPE*) \ + calloc( (sizeof(OMX_BUFFERHEADERTYPE)), m_sInPortDef.nBufferCountActual); + if (m_inp_mem_ptr == NULL) { + DEBUG_PRINT_ERROR("ERROR: calloc() Failed for m_inp_mem_ptr"); + return OMX_ErrorInsufficientResources; + } + DEBUG_PRINT_LOW("Successfully allocated m_inp_mem_ptr = %p", m_inp_mem_ptr); + + + m_pInput_pmem = (struct pmem *) calloc(sizeof (struct pmem), m_sInPortDef.nBufferCountActual); + if (m_pInput_pmem == NULL) { + DEBUG_PRINT_ERROR("ERROR: calloc() Failed for m_pInput_pmem"); + return OMX_ErrorInsufficientResources; + } +#ifdef USE_ION + m_pInput_ion = (struct venc_ion *) calloc(sizeof (struct venc_ion), m_sInPortDef.nBufferCountActual); + if (m_pInput_ion == NULL) { + DEBUG_PRINT_ERROR("ERROR: calloc() Failed for m_pInput_ion"); + return OMX_ErrorInsufficientResources; + } +#endif + + for (i=0; i< m_sInPortDef.nBufferCountActual; i++) { + m_pInput_pmem[i].fd = -1; +#ifdef USE_ION + m_pInput_ion[i].ion_device_fd =-1; + m_pInput_ion[i].fd_ion_data.fd =-1; + m_pInput_ion[i].ion_alloc_data.handle = 0; +#endif + } + + } + + for (i=0; i< m_sInPortDef.nBufferCountActual; i++) { + if (BITMASK_ABSENT(&m_inp_bm_count,i)) { + break; + } + } + + if (i < m_sInPortDef.nBufferCountActual) { + + *bufferHdr = (m_inp_mem_ptr + i); + BITMASK_SET(&m_inp_bm_count,i); + + (*bufferHdr)->pBuffer = (OMX_U8 *)buffer; + (*bufferHdr)->nSize = sizeof(OMX_BUFFERHEADERTYPE); + (*bufferHdr)->nVersion.nVersion = OMX_SPEC_VERSION; + (*bufferHdr)->nAllocLen = m_sInPortDef.nBufferSize; + (*bufferHdr)->pAppPrivate = appData; + (*bufferHdr)->nInputPortIndex = PORT_INDEX_IN; + + if (!m_use_input_pmem) { +#ifdef USE_ION +#ifdef _MSM8974_ + m_pInput_ion[i].ion_device_fd = alloc_map_ion_memory(m_sInPortDef.nBufferSize, + &m_pInput_ion[i].ion_alloc_data, + &m_pInput_ion[i].fd_ion_data, + secure_session ? SECURE_FLAGS_INPUT_BUFFER : 0); +#else + m_pInput_ion[i].ion_device_fd = alloc_map_ion_memory(m_sInPortDef.nBufferSize, + &m_pInput_ion[i].ion_alloc_data, + &m_pInput_ion[i].fd_ion_data, ION_FLAG_CACHED); +#endif + if (m_pInput_ion[i].ion_device_fd < 0) { + DEBUG_PRINT_ERROR("ERROR:ION device open() Failed"); + return OMX_ErrorInsufficientResources; + } + m_pInput_pmem[i].fd = m_pInput_ion[i].fd_ion_data.fd; +#else + m_pInput_pmem[i].fd = open (MEM_DEVICE,O_RDWR); + if (m_pInput_pmem[i].fd == 0) { + m_pInput_pmem[i].fd = open (MEM_DEVICE,O_RDWR); + } + + if (m_pInput_pmem[i] .fd < 0) { + DEBUG_PRINT_ERROR("ERROR: /dev/pmem_adsp open() Failed"); + return OMX_ErrorInsufficientResources; + } +#endif + m_pInput_pmem[i].size = m_sInPortDef.nBufferSize; + m_pInput_pmem[i].offset = 0; + + m_pInput_pmem[i].buffer = NULL; + if(!secure_session) { + m_pInput_pmem[i].buffer = (unsigned char *)mmap( + NULL,m_pInput_pmem[i].size,PROT_READ|PROT_WRITE, + MAP_SHARED,m_pInput_pmem[i].fd,0); + + if (m_pInput_pmem[i].buffer == MAP_FAILED) { + DEBUG_PRINT_ERROR("ERROR: mmap() Failed"); + m_pInput_pmem[i].buffer = NULL; + close(m_pInput_pmem[i].fd); +#ifdef USE_ION + free_ion_memory(&m_pInput_ion[i]); +#endif + return OMX_ErrorInsufficientResources; + } + } + + } else { + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pParam = reinterpret_cast<OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *>((*bufferHdr)->pAppPrivate); + DEBUG_PRINT_LOW("Inside qcom_ext with luma:(fd:%lu,offset:0x%x)", pParam->pmem_fd, (unsigned)pParam->offset); + + if (pParam) { + m_pInput_pmem[i].fd = pParam->pmem_fd; + m_pInput_pmem[i].offset = pParam->offset; + m_pInput_pmem[i].size = m_sInPortDef.nBufferSize; + m_pInput_pmem[i].buffer = (unsigned char *)buffer; + DEBUG_PRINT_LOW("DBG:: pParam->pmem_fd = %u, pParam->offset = %u", + (unsigned int)pParam->pmem_fd, (unsigned int)pParam->offset); + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid AppData given for PMEM i/p UseBuffer case"); + return OMX_ErrorBadParameter; + } + } + + DEBUG_PRINT_LOW("use_inp:: bufhdr = %p, pBuffer = %p, m_pInput_pmem[i].buffer = %p", + (*bufferHdr), (*bufferHdr)->pBuffer, m_pInput_pmem[i].buffer); + if ( dev_use_buf(&m_pInput_pmem[i],PORT_INDEX_IN,i) != true) { + DEBUG_PRINT_ERROR("ERROR: dev_use_buf() Failed for i/p buf"); + return OMX_ErrorInsufficientResources; + } + } else { + DEBUG_PRINT_ERROR("ERROR: All buffers are already used, invalid use_buf call for " + "index = %u", i); + eRet = OMX_ErrorInsufficientResources; + } + + return eRet; +} + + + +/* ====================================================================== + FUNCTION + omx_video::UseOutputBuffer + + DESCRIPTION + Helper function for Use buffer in the input pin + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_video::use_output_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + (void)hComp, (void)port; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr= NULL; // buffer header + unsigned i= 0; // Temporary counter + unsigned char *buf_addr = NULL; +#ifdef _MSM8974_ + int align_size; +#endif + + DEBUG_PRINT_HIGH("Inside use_output_buffer()"); + if (bytes < m_sOutPortDef.nBufferSize) { + DEBUG_PRINT_ERROR("ERROR: use_output_buffer: Size Mismatch!! " + "bytes[%u] < Port.nBufferSize[%u]", (unsigned int)bytes, (unsigned int)m_sOutPortDef.nBufferSize); + return OMX_ErrorBadParameter; + } + + if (!m_out_mem_ptr) { + output_use_buffer = true; + int nBufHdrSize = 0; + + DEBUG_PRINT_LOW("Allocating First Output Buffer(%u)",(unsigned int)m_sOutPortDef.nBufferCountActual); + nBufHdrSize = m_sOutPortDef.nBufferCountActual * sizeof(OMX_BUFFERHEADERTYPE); + /* + * Memory for output side involves the following: + * 1. Array of Buffer Headers + * 2. Bitmask array to hold the buffer allocation details + * In order to minimize the memory management entire allocation + * is done in one step. + */ + //OMX Buffer header + m_out_mem_ptr = (OMX_BUFFERHEADERTYPE *)calloc(nBufHdrSize,1); + if (m_out_mem_ptr == NULL) { + DEBUG_PRINT_ERROR("ERROR: calloc() Failed for m_out_mem_ptr"); + return OMX_ErrorInsufficientResources; + } + + m_pOutput_pmem = (struct pmem *) calloc(sizeof (struct pmem), m_sOutPortDef.nBufferCountActual); + if (m_pOutput_pmem == NULL) { + DEBUG_PRINT_ERROR("ERROR: calloc() Failed for m_pOutput_pmem"); + return OMX_ErrorInsufficientResources; + } +#ifdef USE_ION + m_pOutput_ion = (struct venc_ion *) calloc(sizeof (struct venc_ion), m_sOutPortDef.nBufferCountActual); + if (m_pOutput_ion == NULL) { + DEBUG_PRINT_ERROR("ERROR: calloc() Failed for m_pOutput_ion"); + return OMX_ErrorInsufficientResources; + } +#endif + if (m_out_mem_ptr) { + bufHdr = m_out_mem_ptr; + DEBUG_PRINT_LOW("Memory Allocation Succeeded for OUT port%p",m_out_mem_ptr); + // Settting the entire storage nicely + for (i=0; i < m_sOutPortDef.nBufferCountActual ; i++) { + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + bufHdr->nAllocLen = bytes; + bufHdr->nFilledLen = 0; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = PORT_INDEX_OUT; + bufHdr->pBuffer = NULL; + bufHdr++; + m_pOutput_pmem[i].fd = -1; +#ifdef USE_ION + m_pOutput_ion[i].ion_device_fd =-1; + m_pOutput_ion[i].fd_ion_data.fd=-1; + m_pOutput_ion[i].ion_alloc_data.handle = 0; +#endif + } + } else { + DEBUG_PRINT_ERROR("ERROR: Output buf mem alloc failed[0x%p]",m_out_mem_ptr); + eRet = OMX_ErrorInsufficientResources; + } + } + + for (i=0; i< m_sOutPortDef.nBufferCountActual; i++) { + if (BITMASK_ABSENT(&m_out_bm_count,i)) { + break; + } + } + + if (eRet == OMX_ErrorNone) { + if (i < m_sOutPortDef.nBufferCountActual) { + *bufferHdr = (m_out_mem_ptr + i ); + (*bufferHdr)->pBuffer = (OMX_U8 *)buffer; + (*bufferHdr)->pAppPrivate = appData; + + if (!m_use_output_pmem) { +#ifdef USE_ION +#ifdef _MSM8974_ + align_size = (m_sOutPortDef.nBufferSize + (SZ_4K - 1)) & ~(SZ_4K - 1); + m_pOutput_ion[i].ion_device_fd = alloc_map_ion_memory(align_size, + &m_pOutput_ion[i].ion_alloc_data, + &m_pOutput_ion[i].fd_ion_data, + secure_session ? SECURE_FLAGS_OUTPUT_BUFFER : 0); +#else + m_pOutput_ion[i].ion_device_fd = alloc_map_ion_memory( + m_sOutPortDef.nBufferSize, + &m_pOutput_ion[i].ion_alloc_data, + &m_pOutput_ion[i].fd_ion_data, ION_FLAG_CACHED); +#endif + if (m_pOutput_ion[i].ion_device_fd < 0) { + DEBUG_PRINT_ERROR("ERROR:ION device open() Failed"); + return OMX_ErrorInsufficientResources; + } + m_pOutput_pmem[i].fd = m_pOutput_ion[i].fd_ion_data.fd; +#else + m_pOutput_pmem[i].fd = open (MEM_DEVICE,O_RDWR); + + if (m_pOutput_pmem[i].fd == 0) { + m_pOutput_pmem[i].fd = open (MEM_DEVICE,O_RDWR); + } + + if (m_pOutput_pmem[i].fd < 0) { + DEBUG_PRINT_ERROR("ERROR: /dev/pmem_adsp open() Failed"); + return OMX_ErrorInsufficientResources; + } +#endif + m_pOutput_pmem[i].size = m_sOutPortDef.nBufferSize; + m_pOutput_pmem[i].offset = 0; + + m_pOutput_pmem[i].buffer = NULL; + if(!secure_session) { +#ifdef _MSM8974_ + m_pOutput_pmem[i].buffer = (unsigned char *)mmap(NULL, + align_size,PROT_READ|PROT_WRITE, + MAP_SHARED,m_pOutput_pmem[i].fd,0); +#else + m_pOutput_pmem[i].buffer = (unsigned char *)mmap(NULL, + m_pOutput_pmem[i].size,PROT_READ|PROT_WRITE, + MAP_SHARED,m_pOutput_pmem[i].fd,0); +#endif + if (m_pOutput_pmem[i].buffer == MAP_FAILED) { + DEBUG_PRINT_ERROR("ERROR: mmap() Failed"); + m_pOutput_pmem[i].buffer = NULL; + close(m_pOutput_pmem[i].fd); +#ifdef USE_ION + free_ion_memory(&m_pOutput_ion[i]); +#endif + return OMX_ErrorInsufficientResources; + } + } + } else { + OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pParam = reinterpret_cast<OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO*>((*bufferHdr)->pAppPrivate); + DEBUG_PRINT_LOW("Inside qcom_ext pParam: %p", pParam); + + if (pParam) { + DEBUG_PRINT_LOW("Inside qcom_ext with luma:(fd:%lu,offset:0x%x)", pParam->pmem_fd, (int)pParam->offset); + m_pOutput_pmem[i].fd = pParam->pmem_fd; + m_pOutput_pmem[i].offset = pParam->offset; + m_pOutput_pmem[i].size = m_sOutPortDef.nBufferSize; + m_pOutput_pmem[i].buffer = (unsigned char *)buffer; + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid AppData given for PMEM o/p UseBuffer case"); + return OMX_ErrorBadParameter; + } + buf_addr = (unsigned char *)buffer; + } + + DEBUG_PRINT_LOW("use_out:: bufhdr = %p, pBuffer = %p, m_pOutput_pmem[i].buffer = %p", + (*bufferHdr), (*bufferHdr)->pBuffer, m_pOutput_pmem[i].buffer); + if (dev_use_buf(&m_pOutput_pmem[i],PORT_INDEX_OUT,i) != true) { + DEBUG_PRINT_ERROR("ERROR: dev_use_buf Failed for o/p buf"); + return OMX_ErrorInsufficientResources; + } + + BITMASK_SET(&m_out_bm_count,i); + } else { + DEBUG_PRINT_ERROR("ERROR: All o/p Buffers have been Used, invalid use_buf call for " + "index = %u", i); + eRet = OMX_ErrorInsufficientResources; + } + } + return eRet; +} + + +/* ====================================================================== + FUNCTION + omx_video::UseBuffer + + DESCRIPTION + OMX Use Buffer method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None , if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_video::use_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes, + OMX_IN OMX_U8* buffer) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: Use Buffer in Invalid State"); + return OMX_ErrorInvalidState; + } + if (port == PORT_INDEX_IN) { + eRet = use_input_buffer(hComp,bufferHdr,port,appData,bytes,buffer); + } else if (port == PORT_INDEX_OUT) { + eRet = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer); + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index received %d",(int)port); + eRet = OMX_ErrorBadPortIndex; + } + + if (eRet == OMX_ErrorNone) { + if (allocate_done()) { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) { + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_IDLE_PENDING); + post_event(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == PORT_INDEX_IN && m_sInPortDef.bPopulated) { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + PORT_INDEX_IN, + OMX_COMPONENT_GENERATE_EVENT); + } + + } else if (port == PORT_INDEX_OUT && m_sOutPortDef.bPopulated) { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + PORT_INDEX_OUT, + OMX_COMPONENT_GENERATE_EVENT); + m_event_port_settings_sent = false; + } + } + } + return eRet; +} + +OMX_ERRORTYPE omx_video::free_input_buffer(OMX_BUFFERHEADERTYPE *bufferHdr) +{ + unsigned int index = 0; + OMX_U8 *temp_buff ; + + if (bufferHdr == NULL || m_inp_mem_ptr == NULL) { + DEBUG_PRINT_ERROR("ERROR: free_input: Invalid bufferHdr[%p] or m_inp_mem_ptr[%p]", + bufferHdr, m_inp_mem_ptr); + return OMX_ErrorBadParameter; + } + + index = bufferHdr - ((!meta_mode_enable)?m_inp_mem_ptr:meta_buffer_hdr); +#ifdef _ANDROID_ICS_ + if (meta_mode_enable) { + if (index < m_sInPortDef.nBufferCountActual) { + memset(&meta_buffer_hdr[index], 0, sizeof(meta_buffer_hdr[index])); + memset(&meta_buffers[index], 0, sizeof(meta_buffers[index])); + } + if (!mUseProxyColorFormat) + return OMX_ErrorNone; + else { + c2d_conv.close(); + opaque_buffer_hdr[index] = NULL; + } + } +#endif + if (index < m_sInPortDef.nBufferCountActual && !mUseProxyColorFormat && + dev_free_buf(&m_pInput_pmem[index],PORT_INDEX_IN) != true) { + DEBUG_PRINT_LOW("ERROR: dev_free_buf() Failed for i/p buf"); + } + + if (index < m_sInPortDef.nBufferCountActual && m_pInput_pmem) { + auto_lock l(m_lock); + + if (m_pInput_pmem[index].fd > 0 && input_use_buffer == false) { + DEBUG_PRINT_LOW("FreeBuffer:: i/p AllocateBuffer case"); + if(!secure_session) { + munmap (m_pInput_pmem[index].buffer,m_pInput_pmem[index].size); + } else { + free(m_pInput_pmem[index].buffer); + } + m_pInput_pmem[index].buffer = NULL; + close (m_pInput_pmem[index].fd); +#ifdef USE_ION + free_ion_memory(&m_pInput_ion[index]); +#endif + m_pInput_pmem[index].fd = -1; + } else if (m_pInput_pmem[index].fd > 0 && (input_use_buffer == true && + m_use_input_pmem == OMX_FALSE)) { + DEBUG_PRINT_LOW("FreeBuffer:: i/p Heap UseBuffer case"); + if (dev_free_buf(&m_pInput_pmem[index],PORT_INDEX_IN) != true) { + DEBUG_PRINT_ERROR("ERROR: dev_free_buf() Failed for i/p buf"); + } + if(!secure_session) { + munmap (m_pInput_pmem[index].buffer,m_pInput_pmem[index].size); + m_pInput_pmem[index].buffer = NULL; + } + close (m_pInput_pmem[index].fd); +#ifdef USE_ION + free_ion_memory(&m_pInput_ion[index]); +#endif + m_pInput_pmem[index].fd = -1; + } else { + DEBUG_PRINT_ERROR("FreeBuffer:: fd is invalid or i/p PMEM UseBuffer case"); + } + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_video::free_output_buffer(OMX_BUFFERHEADERTYPE *bufferHdr) +{ + unsigned int index = 0; + OMX_U8 *temp_buff ; + + if (bufferHdr == NULL || m_out_mem_ptr == NULL) { + DEBUG_PRINT_ERROR("ERROR: free_output: Invalid bufferHdr[%p] or m_out_mem_ptr[%p]", + bufferHdr, m_out_mem_ptr); + return OMX_ErrorBadParameter; + } + index = bufferHdr - m_out_mem_ptr; + + if (index < m_sOutPortDef.nBufferCountActual && + dev_free_buf(&m_pOutput_pmem[index],PORT_INDEX_OUT) != true) { + DEBUG_PRINT_ERROR("ERROR: dev_free_buf Failed for o/p buf"); + } + + if (index < m_sOutPortDef.nBufferCountActual && m_pOutput_pmem) { + if (m_pOutput_pmem[index].fd > 0 && output_use_buffer == false ) { + DEBUG_PRINT_LOW("FreeBuffer:: o/p AllocateBuffer case"); + if(!secure_session) { + munmap (m_pOutput_pmem[index].buffer, + m_pOutput_pmem[index].size); + } else { + char *data = (char*) m_pOutput_pmem[index].buffer; + native_handle_t *handle = NULL; + memcpy(&handle, data + sizeof(OMX_U32), sizeof(native_handle_t*)); + native_handle_delete(handle); + free(m_pOutput_pmem[index].buffer); + } + close (m_pOutput_pmem[index].fd); +#ifdef USE_ION + free_ion_memory(&m_pOutput_ion[index]); +#endif + m_pOutput_pmem[index].fd = -1; + } else if ( m_pOutput_pmem[index].fd > 0 && (output_use_buffer == true + && m_use_output_pmem == OMX_FALSE)) { + DEBUG_PRINT_LOW("FreeBuffer:: o/p Heap UseBuffer case"); + if (dev_free_buf(&m_pOutput_pmem[index],PORT_INDEX_OUT) != true) { + DEBUG_PRINT_ERROR("ERROR: dev_free_buf Failed for o/p buf"); + } + if(!secure_session) { + munmap (m_pOutput_pmem[index].buffer, + m_pOutput_pmem[index].size); + } + close (m_pOutput_pmem[index].fd); +#ifdef USE_ION + free_ion_memory(&m_pOutput_ion[index]); +#endif + m_pOutput_pmem[index].fd = -1; + } else { + DEBUG_PRINT_LOW("FreeBuffer:: fd is invalid or o/p PMEM UseBuffer case"); + } + } + return OMX_ErrorNone; +} +#ifdef _ANDROID_ICS_ +OMX_ERRORTYPE omx_video::allocate_input_meta_buffer( + OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE **bufferHdr, + OMX_PTR appData, + OMX_U32 bytes) +{ + unsigned index = 0; + // In meta-mode alloc-length is not known conclusively + // Allow allocation for atleast gralloc metadata handles + // and check for size in ETB + if (!bufferHdr || bytes < sizeof(VideoGrallocMetadata)) { + DEBUG_PRINT_ERROR("wrong params allocate_input_meta_buffer Hdr %p len %u", + bufferHdr, (unsigned int)bytes); + return OMX_ErrorBadParameter; + } + + if (!m_inp_mem_ptr && !mUseProxyColorFormat) { + m_inp_mem_ptr = meta_buffer_hdr; + DEBUG_PRINT_LOW("use meta_buffer_hdr (%p) as m_inp_mem_ptr = %p", + meta_buffer_hdr, m_inp_mem_ptr); + } + for (index = 0; ((index < m_sInPortDef.nBufferCountActual) && + meta_buffer_hdr[index].pBuffer); index++); + if (index == m_sInPortDef.nBufferCountActual) { + DEBUG_PRINT_ERROR("All buffers are allocated input_meta_buffer"); + return OMX_ErrorBadParameter; + } + if (mUseProxyColorFormat) { + if (opaque_buffer_hdr[index]) { + DEBUG_PRINT_ERROR("All buffers are allocated opaque_buffer_hdr"); + return OMX_ErrorBadParameter; + } + if (allocate_input_buffer(hComp,&opaque_buffer_hdr[index], + PORT_INDEX_IN,appData,m_sInPortDef.nBufferSize) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("All buffers are allocated opaque_buffer_hdr"); + return OMX_ErrorBadParameter; + } + } + BITMASK_SET(&m_inp_bm_count,index); + *bufferHdr = &meta_buffer_hdr[index]; + memset(&meta_buffer_hdr[index], 0, sizeof(meta_buffer_hdr[index])); + meta_buffer_hdr[index].nSize = sizeof(meta_buffer_hdr[index]); + meta_buffer_hdr[index].nAllocLen = bytes; + meta_buffer_hdr[index].nVersion.nVersion = OMX_SPEC_VERSION; + meta_buffer_hdr[index].nInputPortIndex = PORT_INDEX_IN; + meta_buffer_hdr[index].pBuffer = (OMX_U8*)&meta_buffers[index]; + meta_buffer_hdr[index].pAppPrivate = appData; + if (mUseProxyColorFormat) { + m_opq_pmem_q.insert_entry((unsigned long)opaque_buffer_hdr[index],0,0); + DEBUG_PRINT_HIGH("opaque_buffer_hdr insert %p", opaque_buffer_hdr[index]); + } + return OMX_ErrorNone; +} +#endif +/* ====================================================================== + FUNCTION + omx_venc::AllocateInputBuffer + + DESCRIPTION + Helper function for allocate buffer in the input pin + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_video::allocate_input_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + (void)hComp, (void)port; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned i = 0; + + DEBUG_PRINT_HIGH("allocate_input_buffer()::"); + if (bytes < m_sInPortDef.nBufferSize) { + DEBUG_PRINT_ERROR("ERROR: Buffer size mismatch error: bytes[%u] < nBufferSize[%u]", + (unsigned int)bytes, (unsigned int)m_sInPortDef.nBufferSize); + return OMX_ErrorBadParameter; + } + + if (!m_inp_mem_ptr) { + DEBUG_PRINT_HIGH("%s: size = %u, actual cnt %u", __FUNCTION__, + (unsigned int)m_sInPortDef.nBufferSize, (unsigned int)m_sInPortDef.nBufferCountActual); + m_inp_mem_ptr = (OMX_BUFFERHEADERTYPE*) \ + calloc( (sizeof(OMX_BUFFERHEADERTYPE)), m_sInPortDef.nBufferCountActual); + if (m_inp_mem_ptr == NULL) { + DEBUG_PRINT_ERROR("ERROR: calloc() Failed for m_inp_mem_ptr"); + return OMX_ErrorInsufficientResources; + } + + DEBUG_PRINT_LOW("Successfully allocated m_inp_mem_ptr = %p", m_inp_mem_ptr); + m_pInput_pmem = (struct pmem *) calloc(sizeof (struct pmem), m_sInPortDef.nBufferCountActual); + + if (m_pInput_pmem == NULL) { + DEBUG_PRINT_ERROR("ERROR: calloc() Failed for m_pInput_pmem"); + return OMX_ErrorInsufficientResources; + } +#ifdef USE_ION + m_pInput_ion = (struct venc_ion *) calloc(sizeof (struct venc_ion), m_sInPortDef.nBufferCountActual); + if (m_pInput_ion == NULL) { + DEBUG_PRINT_ERROR("ERROR: calloc() Failed for m_pInput_ion"); + return OMX_ErrorInsufficientResources; + } +#endif + for (i=0; i< m_sInPortDef.nBufferCountActual; i++) { + m_pInput_pmem[i].fd = -1; +#ifdef USE_ION + m_pInput_ion[i].ion_device_fd =-1; + m_pInput_ion[i].fd_ion_data.fd =-1; + m_pInput_ion[i].ion_alloc_data.handle = 0; +#endif + } + } + + for (i=0; i< m_sInPortDef.nBufferCountActual; i++) { + if (BITMASK_ABSENT(&m_inp_bm_count,i)) { + break; + } + } + if (i < m_sInPortDef.nBufferCountActual) { + + *bufferHdr = (m_inp_mem_ptr + i); + (*bufferHdr)->nSize = sizeof(OMX_BUFFERHEADERTYPE); + (*bufferHdr)->nVersion.nVersion = OMX_SPEC_VERSION; + (*bufferHdr)->nAllocLen = m_sInPortDef.nBufferSize; + (*bufferHdr)->pAppPrivate = appData; + (*bufferHdr)->nInputPortIndex = PORT_INDEX_IN; + // make fd available to app layer, help with testing + (*bufferHdr)->pInputPortPrivate = (OMX_PTR)&m_pInput_pmem[i]; + +#ifdef USE_ION +#ifdef _MSM8974_ + m_pInput_ion[i].ion_device_fd = alloc_map_ion_memory(m_sInPortDef.nBufferSize, + &m_pInput_ion[i].ion_alloc_data, + &m_pInput_ion[i].fd_ion_data, + secure_session ? SECURE_FLAGS_INPUT_BUFFER : 0); +#else + m_pInput_ion[i].ion_device_fd = alloc_map_ion_memory(m_sInPortDef.nBufferSize, + &m_pInput_ion[i].ion_alloc_data, + &m_pInput_ion[i].fd_ion_data, ION_FLAG_CACHED); +#endif + if (m_pInput_ion[i].ion_device_fd < 0) { + DEBUG_PRINT_ERROR("ERROR:ION device open() Failed"); + return OMX_ErrorInsufficientResources; + } + + m_pInput_pmem[i].fd = m_pInput_ion[i].fd_ion_data.fd; +#else + m_pInput_pmem[i].fd = open (MEM_DEVICE,O_RDWR); + + if (m_pInput_pmem[i].fd == 0) { + m_pInput_pmem[i].fd = open (MEM_DEVICE,O_RDWR); + } + + if (m_pInput_pmem[i].fd < 0) { + DEBUG_PRINT_ERROR("ERROR: /dev/pmem_adsp open() Failed"); + return OMX_ErrorInsufficientResources; + } +#endif + m_pInput_pmem[i].size = m_sInPortDef.nBufferSize; + m_pInput_pmem[i].offset = 0; + + m_pInput_pmem[i].buffer = NULL; + if(!secure_session) { + m_pInput_pmem[i].buffer = (unsigned char *)mmap(NULL, + m_pInput_pmem[i].size,PROT_READ|PROT_WRITE, + MAP_SHARED,m_pInput_pmem[i].fd,0); + if (m_pInput_pmem[i].buffer == MAP_FAILED) { + DEBUG_PRINT_ERROR("ERROR: mmap FAILED= %d", errno); + m_pInput_pmem[i].buffer = NULL; + close(m_pInput_pmem[i].fd); +#ifdef USE_ION + free_ion_memory(&m_pInput_ion[i]); +#endif + return OMX_ErrorInsufficientResources; + } + } else { + //This should only be used for passing reference to source type and + //secure handle fd struct native_handle_t* + m_pInput_pmem[i].buffer = malloc(sizeof(OMX_U32) + sizeof(native_handle_t*)); + if (m_pInput_pmem[i].buffer == NULL) { + DEBUG_PRINT_ERROR("%s: failed to allocate native-handle", __func__); + return OMX_ErrorInsufficientResources; + } + (*bufferHdr)->nAllocLen = sizeof(OMX_U32) + sizeof(native_handle_t*); + } + + (*bufferHdr)->pBuffer = (OMX_U8 *)m_pInput_pmem[i].buffer; + DEBUG_PRINT_LOW("Virtual address in allocate buffer is %p", m_pInput_pmem[i].buffer); + BITMASK_SET(&m_inp_bm_count,i); + //here change the I/P param here from buf_adr to pmem + if (!mUseProxyColorFormat && (dev_use_buf(&m_pInput_pmem[i],PORT_INDEX_IN,i) != true)) { + DEBUG_PRINT_ERROR("ERROR: dev_use_buf FAILED for i/p buf"); + return OMX_ErrorInsufficientResources; + } + } else { + DEBUG_PRINT_ERROR("ERROR: All i/p buffers are allocated, invalid allocate buf call" + "for index [%d]", i); + eRet = OMX_ErrorInsufficientResources; + } + + return eRet; +} + + +/* ====================================================================== + FUNCTION + omx_venc::AllocateOutputBuffer + + DESCRIPTION + Helper fn for AllocateBuffer in the output pin + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything went well. + + ========================================================================== */ +OMX_ERRORTYPE omx_video::allocate_output_buffer( + OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + (void)hComp, (void)port; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + OMX_BUFFERHEADERTYPE *bufHdr= NULL; // buffer header + unsigned i= 0; // Temporary counter +#ifdef _MSM8974_ + int align_size; +#endif + DEBUG_PRINT_HIGH("allocate_output_buffer()for %u bytes", (unsigned int)bytes); + if (!m_out_mem_ptr) { + int nBufHdrSize = 0; + DEBUG_PRINT_HIGH("%s: size = %u, actual cnt %u", __FUNCTION__, + (unsigned int)m_sOutPortDef.nBufferSize, (unsigned int)m_sOutPortDef.nBufferCountActual); + nBufHdrSize = m_sOutPortDef.nBufferCountActual * sizeof(OMX_BUFFERHEADERTYPE); + + /* + * Memory for output side involves the following: + * 1. Array of Buffer Headers + * 2. Bitmask array to hold the buffer allocation details + * In order to minimize the memory management entire allocation + * is done in one step. + */ + m_out_mem_ptr = (OMX_BUFFERHEADERTYPE *)calloc(nBufHdrSize,1); + +#ifdef USE_ION + m_pOutput_ion = (struct venc_ion *) calloc(sizeof (struct venc_ion), m_sOutPortDef.nBufferCountActual); + if (m_pOutput_ion == NULL) { + DEBUG_PRINT_ERROR("ERROR: calloc() Failed for m_pOutput_ion"); + return OMX_ErrorInsufficientResources; + } +#endif + m_pOutput_pmem = (struct pmem *) calloc(sizeof(struct pmem), m_sOutPortDef.nBufferCountActual); + if (m_pOutput_pmem == NULL) { + DEBUG_PRINT_ERROR("ERROR: calloc() Failed for m_pOutput_pmem"); + return OMX_ErrorInsufficientResources; + } + if (m_out_mem_ptr && m_pOutput_pmem) { + bufHdr = m_out_mem_ptr; + + for (i=0; i < m_sOutPortDef.nBufferCountActual ; i++) { + bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + bufHdr->nVersion.nVersion = OMX_SPEC_VERSION; + // Set the values when we determine the right HxW param + bufHdr->nAllocLen = bytes; + bufHdr->nFilledLen = 0; + bufHdr->pAppPrivate = appData; + bufHdr->nOutputPortIndex = PORT_INDEX_OUT; + // make fd available to app layer, help with testing + bufHdr->pOutputPortPrivate = (OMX_PTR)&m_pOutput_pmem[i]; + bufHdr->pBuffer = NULL; + bufHdr++; + m_pOutput_pmem[i].fd = -1; +#ifdef USE_ION + m_pOutput_ion[i].ion_device_fd =-1; + m_pOutput_ion[i].fd_ion_data.fd=-1; + m_pOutput_ion[i].ion_alloc_data.handle = 0; +#endif + } + } else { + DEBUG_PRINT_ERROR("ERROR: calloc() failed for m_out_mem_ptr/m_pOutput_pmem"); + eRet = OMX_ErrorInsufficientResources; + } + } + + DEBUG_PRINT_HIGH("actual cnt = %u", (unsigned int)m_sOutPortDef.nBufferCountActual); + for (i=0; i< m_sOutPortDef.nBufferCountActual; i++) { + if (BITMASK_ABSENT(&m_out_bm_count,i)) { + DEBUG_PRINT_LOW("Found a Free Output Buffer %d",i); + break; + } + } + if (eRet == OMX_ErrorNone) { + if (i < m_sOutPortDef.nBufferCountActual) { +#ifdef USE_ION +#ifdef _MSM8974_ + align_size = ALIGN(m_sOutPortDef.nBufferSize, 4096); + m_pOutput_ion[i].ion_device_fd = alloc_map_ion_memory(align_size, + &m_pOutput_ion[i].ion_alloc_data, + &m_pOutput_ion[i].fd_ion_data, + secure_session ? SECURE_FLAGS_OUTPUT_BUFFER : ION_FLAG_CACHED); +#else + m_pOutput_ion[i].ion_device_fd = alloc_map_ion_memory(m_sOutPortDef.nBufferSize, + &m_pOutput_ion[i].ion_alloc_data, + &m_pOutput_ion[i].fd_ion_data, ION_FLAG_CACHED); +#endif + if (m_pOutput_ion[i].ion_device_fd < 0) { + DEBUG_PRINT_ERROR("ERROR:ION device open() Failed"); + return OMX_ErrorInsufficientResources; + } + + m_pOutput_pmem[i].fd = m_pOutput_ion[i].fd_ion_data.fd; +#else + m_pOutput_pmem[i].fd = open (MEM_DEVICE,O_RDWR); + if (m_pOutput_pmem[i].fd == 0) { + m_pOutput_pmem[i].fd = open (MEM_DEVICE,O_RDWR); + } + + if (m_pOutput_pmem[i].fd < 0) { + DEBUG_PRINT_ERROR("ERROR: /dev/pmem_adsp open() failed"); + return OMX_ErrorInsufficientResources; + } +#endif + m_pOutput_pmem[i].size = m_sOutPortDef.nBufferSize; + m_pOutput_pmem[i].offset = 0; + + m_pOutput_pmem[i].buffer = NULL; + *bufferHdr = (m_out_mem_ptr + i ); + + if(!secure_session) { +#ifdef _MSM8974_ + m_pOutput_pmem[i].buffer = (unsigned char *)mmap(NULL, + align_size,PROT_READ|PROT_WRITE, + MAP_SHARED,m_pOutput_pmem[i].fd,0); +#else + m_pOutput_pmem[i].buffer = (unsigned char *)mmap(NULL, + m_pOutput_pmem[i].size,PROT_READ|PROT_WRITE, + MAP_SHARED,m_pOutput_pmem[i].fd,0); +#endif + if (m_pOutput_pmem[i].buffer == MAP_FAILED) { + DEBUG_PRINT_ERROR("ERROR: MMAP_FAILED in o/p alloc buffer"); + m_pOutput_pmem[i].buffer = NULL; + close (m_pOutput_pmem[i].fd); +#ifdef USE_ION + free_ion_memory(&m_pOutput_ion[i]); +#endif + return OMX_ErrorInsufficientResources; + } + } + else { + //This should only be used for passing reference to source type and + //secure handle fd struct native_handle_t* + native_handle_t *handle = native_handle_create(1, 3); //fd, offset, size, alloc length + if (!handle) { + DEBUG_PRINT_ERROR("ERROR: native handle creation failed"); + return OMX_ErrorInsufficientResources; + } + m_pOutput_pmem[i].buffer = malloc(sizeof(output_metabuffer)); + if (m_pOutput_pmem[i].buffer == NULL) { + DEBUG_PRINT_ERROR("%s: Failed to allocate meta buffer", __func__); + return OMX_ErrorInsufficientResources; + } + (*bufferHdr)->nAllocLen = sizeof(output_metabuffer); + handle->data[0] = m_pOutput_pmem[i].fd; + handle->data[1] = 0; + handle->data[2] = 0; + handle->data[3] = ALIGN(m_sOutPortDef.nBufferSize, 4096); + output_metabuffer *buffer = (output_metabuffer*) m_pOutput_pmem[i].buffer; + buffer->type = 1; + buffer->nh = handle; + } + + (*bufferHdr)->pBuffer = (OMX_U8 *)m_pOutput_pmem[i].buffer; + (*bufferHdr)->pAppPrivate = appData; + + BITMASK_SET(&m_out_bm_count,i); + + if (dev_use_buf(&m_pOutput_pmem[i],PORT_INDEX_OUT,i) != true) { + DEBUG_PRINT_ERROR("ERROR: dev_use_buf FAILED for o/p buf"); + return OMX_ErrorInsufficientResources; + } + } else { + DEBUG_PRINT_ERROR("ERROR: All o/p buffers are allocated, invalid allocate buf call" + "for index [%d] actual: %u", i, (unsigned int)m_sOutPortDef.nBufferCountActual); + } + } + + return eRet; +} + + +// AllocateBuffer -- API Call +/* ====================================================================== + FUNCTION + omx_video::AllocateBuffer + + DESCRIPTION + Returns zero if all the buffers released.. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_video::allocate_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN OMX_U32 bytes) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type + + DEBUG_PRINT_LOW("Allocate buffer of size = %u on port %d", (unsigned int)bytes, (int)port); + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: Allocate Buf in Invalid State"); + return OMX_ErrorInvalidState; + } + + // What if the client calls again. + if (port == PORT_INDEX_IN) { +#ifdef _ANDROID_ICS_ + if (meta_mode_enable) + eRet = allocate_input_meta_buffer(hComp,bufferHdr,appData,bytes); + else +#endif + eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes); + } else if (port == PORT_INDEX_OUT) { + eRet = allocate_output_buffer(hComp,bufferHdr,port,appData,bytes); + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index received %d",(int)port); + eRet = OMX_ErrorBadPortIndex; + } + DEBUG_PRINT_LOW("Checking for Output Allocate buffer Done"); + if (eRet == OMX_ErrorNone) { + if (allocate_done()) { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) { + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_IDLE_PENDING); + post_event(OMX_CommandStateSet,OMX_StateIdle, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == PORT_INDEX_IN && m_sInPortDef.bPopulated) { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING)) { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + PORT_INDEX_IN, + OMX_COMPONENT_GENERATE_EVENT); + } + } + if (port == PORT_INDEX_OUT && m_sOutPortDef.bPopulated) { + if (BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING)) { + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING); + post_event(OMX_CommandPortEnable, + PORT_INDEX_OUT, + OMX_COMPONENT_GENERATE_EVENT); + m_event_port_settings_sent = false; + } + } + } + DEBUG_PRINT_LOW("Allocate Buffer exit with ret Code %d",eRet); + return eRet; +} + + +// Free Buffer - API call +/* ====================================================================== + FUNCTION + omx_video::FreeBuffer + + DESCRIPTION + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_video::free_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_U32 port, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + (void)hComp; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + unsigned int nPortIndex; + + DEBUG_PRINT_LOW("In for encoder free_buffer"); + + if (m_state == OMX_StateIdle && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) { + DEBUG_PRINT_LOW(" free buffer while Component in Loading pending"); + } else if ((m_sInPortDef.bEnabled == OMX_FALSE && port == PORT_INDEX_IN)|| + (m_sOutPortDef.bEnabled == OMX_FALSE && port == PORT_INDEX_OUT)) { + DEBUG_PRINT_LOW("Free Buffer while port %u disabled", (unsigned int)port); + } else if (m_state == OMX_StateExecuting || m_state == OMX_StatePause) { + DEBUG_PRINT_ERROR("ERROR: Invalid state to free buffer,ports need to be disabled"); + post_event(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + return eRet; + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid state to free buffer,port lost Buffers"); + post_event(OMX_EventError, + OMX_ErrorPortUnpopulated, + OMX_COMPONENT_GENERATE_EVENT); + } + + if (port == PORT_INDEX_IN) { + // check if the buffer is valid + nPortIndex = buffer - ((!meta_mode_enable)?m_inp_mem_ptr:meta_buffer_hdr); + + DEBUG_PRINT_LOW("free_buffer on i/p port - Port idx %u, actual cnt %u", + nPortIndex, (unsigned int)m_sInPortDef.nBufferCountActual); + if (nPortIndex < m_sInPortDef.nBufferCountActual && + BITMASK_PRESENT(&m_inp_bm_count, nPortIndex)) { + // Clear the bit associated with it. + BITMASK_CLEAR(&m_inp_bm_count,nPortIndex); + free_input_buffer (buffer); + m_sInPortDef.bPopulated = OMX_FALSE; + + /*Free the Buffer Header*/ + if (release_input_done()) { + input_use_buffer = false; + // "m_inp_mem_ptr" may point to "meta_buffer_hdr" in some modes, + // in which case, it was not explicitly allocated + if (m_inp_mem_ptr && m_inp_mem_ptr != meta_buffer_hdr) { + DEBUG_PRINT_LOW("Freeing m_inp_mem_ptr"); + free (m_inp_mem_ptr); + } + m_inp_mem_ptr = NULL; + if (m_pInput_pmem) { + DEBUG_PRINT_LOW("Freeing m_pInput_pmem"); + free(m_pInput_pmem); + m_pInput_pmem = NULL; + } +#ifdef USE_ION + if (m_pInput_ion) { + DEBUG_PRINT_LOW("Freeing m_pInput_ion"); + free(m_pInput_ion); + m_pInput_ion = NULL; + } +#endif + } + } else { + DEBUG_PRINT_ERROR("ERROR: free_buffer ,Port Index Invalid"); + eRet = OMX_ErrorBadPortIndex; + } + + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING) + && release_input_done()) { + DEBUG_PRINT_LOW("MOVING TO DISABLED STATE"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING); + post_event(OMX_CommandPortDisable, + PORT_INDEX_IN, + OMX_COMPONENT_GENERATE_EVENT); + } + } else if (port == PORT_INDEX_OUT) { + // check if the buffer is valid + nPortIndex = buffer - (OMX_BUFFERHEADERTYPE*)m_out_mem_ptr; + + DEBUG_PRINT_LOW("free_buffer on o/p port - Port idx %u, actual cnt %u", + nPortIndex, (unsigned int)m_sOutPortDef.nBufferCountActual); + if (nPortIndex < m_sOutPortDef.nBufferCountActual && + BITMASK_PRESENT(&m_out_bm_count, nPortIndex)) { + // Clear the bit associated with it. + BITMASK_CLEAR(&m_out_bm_count,nPortIndex); + m_sOutPortDef.bPopulated = OMX_FALSE; + free_output_buffer (buffer); + + if (release_output_done()) { + output_use_buffer = false; + if (m_out_mem_ptr) { + DEBUG_PRINT_LOW("Freeing m_out_mem_ptr"); + free (m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + if (m_pOutput_pmem) { + DEBUG_PRINT_LOW("Freeing m_pOutput_pmem"); + free(m_pOutput_pmem); + m_pOutput_pmem = NULL; + } +#ifdef USE_ION + if (m_pOutput_ion) { + DEBUG_PRINT_LOW("Freeing m_pOutput_ion"); + free(m_pOutput_ion); + m_pOutput_ion = NULL; + } +#endif + } + } else { + DEBUG_PRINT_ERROR("ERROR: free_buffer , Port Index Invalid"); + eRet = OMX_ErrorBadPortIndex; + } + if (BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING) + && release_output_done() ) { + DEBUG_PRINT_LOW("FreeBuffer : If any Disable event pending,post it"); + + DEBUG_PRINT_LOW("MOVING TO DISABLED STATE"); + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING); + post_event(OMX_CommandPortDisable, + PORT_INDEX_OUT, + OMX_COMPONENT_GENERATE_EVENT); + + } + } else { + eRet = OMX_ErrorBadPortIndex; + } + if ((eRet == OMX_ErrorNone) && + (BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING))) { + if (release_done()) { + if (dev_stop() != 0) { + DEBUG_PRINT_ERROR("ERROR: dev_stop() FAILED"); + eRet = OMX_ErrorHardware; + } + // Send the callback now + BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING); + post_event(OMX_CommandStateSet, OMX_StateLoaded, + OMX_COMPONENT_GENERATE_EVENT); + } else { + DEBUG_PRINT_HIGH("in free buffer, release not done, need to free more buffers output %" PRIx64" input %" PRIx64, + m_out_bm_count, m_inp_bm_count); + } + } + + return eRet; +} + + +/* ====================================================================== + FUNCTION + omx_video::EmptyThisBuffer + + DESCRIPTION + This routine is used to push the encoded video frames to + the video decoder. + + PARAMETERS + None. + + RETURN VALUE + OMX Error None if everything went successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_video::empty_this_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + OMX_ERRORTYPE ret1 = OMX_ErrorNone; + unsigned int nBufferIndex ; + + DEBUG_PRINT_LOW("ETB: buffer = %p, buffer->pBuffer[%p]", buffer, buffer->pBuffer); + if (m_state != OMX_StateExecuting && + m_state != OMX_StatePause && + m_state != OMX_StateIdle) { + DEBUG_PRINT_ERROR("ERROR: Empty this buffer in Invalid State"); + return OMX_ErrorInvalidState; + } + + if (buffer == NULL || (buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE))) { + DEBUG_PRINT_ERROR("ERROR: omx_video::etb--> buffer is null or buffer size is invalid"); + return OMX_ErrorBadParameter; + } + + if (buffer->nVersion.nVersion != OMX_SPEC_VERSION) { + DEBUG_PRINT_ERROR("ERROR: omx_video::etb--> OMX Version Invalid"); + return OMX_ErrorVersionMismatch; + } + + if (buffer->nInputPortIndex != (OMX_U32)PORT_INDEX_IN) { + DEBUG_PRINT_ERROR("ERROR: Bad port index to call empty_this_buffer"); + return OMX_ErrorBadPortIndex; + } + if (!m_sInPortDef.bEnabled) { + DEBUG_PRINT_ERROR("ERROR: Cannot call empty_this_buffer while I/P port is disabled"); + return OMX_ErrorIncorrectStateOperation; + } + + nBufferIndex = buffer - ((!meta_mode_enable)?m_inp_mem_ptr:meta_buffer_hdr); + + if (nBufferIndex > m_sInPortDef.nBufferCountActual ) { + DEBUG_PRINT_ERROR("ERROR: ETB: Invalid buffer index[%d]", nBufferIndex); + return OMX_ErrorBadParameter; + } + + m_etb_count++; + DEBUG_PRINT_LOW("DBG: i/p nTimestamp = %u", (unsigned)buffer->nTimeStamp); + post_event ((unsigned long)hComp,(unsigned long)buffer,m_input_msg_id); + return OMX_ErrorNone; +} +/* ====================================================================== + FUNCTION + omx_video::empty_this_buffer_proxy + + DESCRIPTION + This routine is used to push the encoded video frames to + the video decoder. + + PARAMETERS + None. + + RETURN VALUE + OMX Error None if everything went successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_video::empty_this_buffer_proxy(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + VIDC_TRACE_NAME_HIGH("ETB"); + (void)hComp; + OMX_U8 *pmem_data_buf = NULL; + int push_cnt = 0; + unsigned nBufIndex = 0; + OMX_ERRORTYPE ret = OMX_ErrorNone; + LEGACY_CAM_METADATA_TYPE *media_buffer = NULL; + +#ifdef _MSM8974_ + int fd = 0; +#endif + DEBUG_PRINT_LOW("ETBProxy: buffer->pBuffer[%p]", buffer->pBuffer); + if (buffer == NULL) { + DEBUG_PRINT_ERROR("ERROR: ETBProxy: Invalid buffer[%p]", buffer); + return OMX_ErrorBadParameter; + } + + // Buffer sanity checks + if (meta_mode_enable && !mUsesColorConversion) { + //For color-conversion case, we have an internal buffer and not a meta buffer + bool met_error = false; + nBufIndex = buffer - meta_buffer_hdr; + if (nBufIndex >= m_sInPortDef.nBufferCountActual) { + DEBUG_PRINT_ERROR("ERROR: ETBProxy: Invalid meta-bufIndex = %u", nBufIndex); + return OMX_ErrorBadParameter; + } + media_buffer = (LEGACY_CAM_METADATA_TYPE *)meta_buffer_hdr[nBufIndex].pBuffer; + if (!media_buffer) { + DEBUG_PRINT_ERROR("%s: invalid media_buffer",__FUNCTION__); + return OMX_ErrorBadParameter; + } + if ((media_buffer->buffer_type == LEGACY_CAM_SOURCE) + && buffer->nAllocLen != sizeof(LEGACY_CAM_METADATA_TYPE)) { + DEBUG_PRINT_ERROR("Invalid metadata size expected(%u) v/s recieved(%zu)", + buffer->nAllocLen, sizeof(LEGACY_CAM_METADATA_TYPE)); + met_error = true; + } else if (media_buffer) { + if (media_buffer->buffer_type != LEGACY_CAM_SOURCE && + media_buffer->buffer_type != kMetadataBufferTypeGrallocSource) { + met_error = true; + } else { + if (media_buffer->buffer_type == LEGACY_CAM_SOURCE) { + if (media_buffer->meta_handle == NULL) + met_error = true; + else { + // TBD: revisit this check ! + int nFds = media_buffer->meta_handle->numFds, + nInt = media_buffer->meta_handle->numInts; + met_error = ((nFds == 1 && nInt >= 2) /*normal*/ || + (nFds < 16 && nInt >= nFds*3) /*batch*/) ? false : true; + if (met_error) { + DEBUG_PRINT_ERROR("Unbalanced fds in handle: fds=%d ints=%d", + nFds, nInt); + } + } + } + } + } else + met_error = true; + if (met_error) { + DEBUG_PRINT_ERROR("ERROR: Unkown source/metahandle in ETB call"); + post_event ((unsigned long)buffer,0,OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorBadParameter; + } + } else { + nBufIndex = buffer - ((OMX_BUFFERHEADERTYPE *)m_inp_mem_ptr); + if (nBufIndex >= m_sInPortDef.nBufferCountActual) { + DEBUG_PRINT_ERROR("ERROR: ETBProxy: Invalid bufIndex = %u", nBufIndex); + return OMX_ErrorBadParameter; + } + } + + pending_input_buffers++; + VIDC_TRACE_INT_LOW("ETB-pending", pending_input_buffers); + if (input_flush_progress == true) { + post_event ((unsigned long)buffer,0, + OMX_COMPONENT_GENERATE_EBD); + DEBUG_PRINT_ERROR("ERROR: ETBProxy: Input flush in progress"); + return OMX_ErrorNone; + } +#ifdef _MSM8974_ + if (!meta_mode_enable) { + fd = m_pInput_pmem[nBufIndex].fd; + } +#endif +#ifdef _ANDROID_ICS_ + if (meta_mode_enable && !mUsesColorConversion) { + // Camera or Gralloc-source meta-buffers queued with encodeable color-format + struct pmem Input_pmem_info; + if (!media_buffer) { + DEBUG_PRINT_ERROR("%s: invalid media_buffer",__FUNCTION__); + return OMX_ErrorBadParameter; + } + if (media_buffer->buffer_type == LEGACY_CAM_SOURCE) { + Input_pmem_info.buffer = media_buffer; + Input_pmem_info.fd = MetaBufferUtil::getFdAt(media_buffer->meta_handle, 0); +#ifdef _MSM8974_ + fd = Input_pmem_info.fd; +#endif + int offset = MetaBufferUtil::getIntAt(media_buffer->meta_handle, 0, MetaBufferUtil::INT_OFFSET); + int size = MetaBufferUtil::getIntAt(media_buffer->meta_handle, 0, MetaBufferUtil::INT_SIZE); + if (offset < 0 || size < 0) { + DEBUG_PRINT_ERROR("meta-buffer is invalid!"); + return OMX_ErrorBadParameter; + } + Input_pmem_info.offset = offset; + Input_pmem_info.size = size; + DEBUG_PRINT_INFO("ETB (meta-Camera) fd = %d, offset = %d, size = %d", + Input_pmem_info.fd, Input_pmem_info.offset, + Input_pmem_info.size); + } else { + VideoGrallocMetadata *media_buffer = (VideoGrallocMetadata *)meta_buffer_hdr[nBufIndex].pBuffer; + private_handle_t *handle = (private_handle_t *)media_buffer->pHandle; + Input_pmem_info.buffer = media_buffer; + Input_pmem_info.fd = handle->fd; +#ifdef _MSM8974_ + fd = Input_pmem_info.fd; +#endif + Input_pmem_info.offset = 0; + Input_pmem_info.size = handle->size; + DEBUG_PRINT_LOW("ETB (meta-gralloc) fd = %d, offset = %d, size = %d", + Input_pmem_info.fd, Input_pmem_info.offset, + Input_pmem_info.size); + } + if (dev_use_buf(&Input_pmem_info,PORT_INDEX_IN,nBufIndex) != true) { + DEBUG_PRINT_ERROR("ERROR: in dev_use_buf"); + post_event ((unsigned long)buffer,0,OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorBadParameter; + } + } else if (input_use_buffer && !m_use_input_pmem && m_pInput_pmem[nBufIndex].buffer) +#else + if (input_use_buffer && !m_use_input_pmem && m_pInput_pmem[nBufIndex].buffer) +#endif + { + DEBUG_PRINT_LOW("Heap UseBuffer case, so memcpy the data"); + + auto_lock l(m_lock); + pmem_data_buf = (OMX_U8 *)m_pInput_pmem[nBufIndex].buffer; + if (pmem_data_buf) { + memcpy (pmem_data_buf, (buffer->pBuffer + buffer->nOffset), + buffer->nFilledLen); + } + DEBUG_PRINT_LOW("memcpy() done in ETBProxy for i/p Heap UseBuf"); + } else if (mUseProxyColorFormat) { + // Gralloc-source buffers with color-conversion + fd = m_pInput_pmem[nBufIndex].fd; + DEBUG_PRINT_LOW("ETB (color-converted) fd = %d, size = %u", + fd, (unsigned int)buffer->nFilledLen); + } else if (m_sInPortDef.format.video.eColorFormat == + OMX_COLOR_FormatYUV420SemiPlanar) { + //For the case where YUV420SP buffers are qeueued to component + //by sources other than camera (Apps via MediaCodec), conversion + //to vendor flavoured NV12 color format is required. + if (!dev_color_align(buffer, m_sInPortDef.format.video.nFrameWidth, + m_sInPortDef.format.video.nFrameHeight)) { + DEBUG_PRINT_ERROR("Failed to adjust buffer color"); + post_event((unsigned long)buffer, 0, OMX_COMPONENT_GENERATE_EBD); + return OMX_ErrorUndefined; + } + } +#ifdef _MSM8974_ + if (dev_empty_buf(buffer, pmem_data_buf,nBufIndex,fd) != true) +#else + if (dev_empty_buf(buffer, pmem_data_buf,0,0) != true) +#endif + { + DEBUG_PRINT_ERROR("ERROR: ETBProxy: dev_empty_buf failed"); +#ifdef _ANDROID_ICS_ + omx_release_meta_buffer(buffer); +#endif + post_event ((unsigned long)buffer,0,OMX_COMPONENT_GENERATE_EBD); + /*Generate an async error and move to invalid state*/ + pending_input_buffers--; + VIDC_TRACE_INT_LOW("ETB-pending", pending_input_buffers); + if (hw_overload) { + return OMX_ErrorInsufficientResources; + } + return OMX_ErrorBadParameter; + } + return ret; +} + +/* ====================================================================== + FUNCTION + omx_video::FillThisBuffer + + DESCRIPTION + IL client uses this method to release the frame buffer + after displaying them. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_video::fill_this_buffer(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + DEBUG_PRINT_LOW("FTB: buffer->pBuffer[%p]", buffer->pBuffer); + if (m_state != OMX_StateExecuting && + m_state != OMX_StatePause && + m_state != OMX_StateIdle) { + DEBUG_PRINT_ERROR("ERROR: FTB in Invalid State"); + return OMX_ErrorInvalidState; + } + + if (buffer == NULL ||(buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE))) { + DEBUG_PRINT_ERROR("ERROR: omx_video::ftb-->Invalid buffer or size"); + return OMX_ErrorBadParameter; + } + + if (buffer->nVersion.nVersion != OMX_SPEC_VERSION) { + DEBUG_PRINT_ERROR("ERROR: omx_video::ftb-->OMX Version Invalid"); + return OMX_ErrorVersionMismatch; + } + + if (buffer->nOutputPortIndex != (OMX_U32)PORT_INDEX_OUT) { + DEBUG_PRINT_ERROR("ERROR: omx_video::ftb-->Bad port index"); + return OMX_ErrorBadPortIndex; + } + + if (!m_sOutPortDef.bEnabled) { + DEBUG_PRINT_ERROR("ERROR: omx_video::ftb-->port is disabled"); + return OMX_ErrorIncorrectStateOperation; + } + + post_event((unsigned long) hComp, (unsigned long)buffer,OMX_COMPONENT_GENERATE_FTB); + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_video::fill_this_buffer_proxy + + DESCRIPTION + IL client uses this method to release the frame buffer + after displaying them. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +OMX_ERRORTYPE omx_video::fill_this_buffer_proxy( + OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* bufferAdd) +{ + VIDC_TRACE_NAME_HIGH("FTB"); + (void)hComp; + OMX_U8 *pmem_data_buf = NULL; + OMX_ERRORTYPE nRet = OMX_ErrorNone; + + DEBUG_PRINT_LOW("FTBProxy: bufferAdd->pBuffer[%p]", bufferAdd->pBuffer); + + if (bufferAdd == NULL || ((bufferAdd - m_out_mem_ptr) >= (int)m_sOutPortDef.nBufferCountActual) ) { + DEBUG_PRINT_ERROR("ERROR: FTBProxy: Invalid i/p params"); + return OMX_ErrorBadParameter; + } + + pending_output_buffers++; + VIDC_TRACE_INT_LOW("FTB-pending", pending_output_buffers); + /*Return back the output buffer to client*/ + if ( m_sOutPortDef.bEnabled != OMX_TRUE || output_flush_progress == true) { + DEBUG_PRINT_LOW("o/p port is Disabled or Flush in Progress"); + post_event ((unsigned long)bufferAdd,0, + OMX_COMPONENT_GENERATE_FBD); + return OMX_ErrorNone; + } + + if (output_use_buffer && !m_use_output_pmem) { + DEBUG_PRINT_LOW("Heap UseBuffer case"); + pmem_data_buf = (OMX_U8 *)m_pOutput_pmem[bufferAdd - m_out_mem_ptr].buffer; + } + + if (dev_fill_buf(bufferAdd, pmem_data_buf,(bufferAdd - m_out_mem_ptr),m_pOutput_pmem[bufferAdd - m_out_mem_ptr].fd) != true) { + DEBUG_PRINT_ERROR("ERROR: dev_fill_buf() Failed"); + post_event ((unsigned long)bufferAdd,0,OMX_COMPONENT_GENERATE_FBD); + pending_output_buffers--; + VIDC_TRACE_INT_LOW("FTB-pending", pending_output_buffers); + return OMX_ErrorBadParameter; + } + + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_video::SetCallbacks + + DESCRIPTION + Set the callbacks. + + PARAMETERS + None. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_video::set_callbacks(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_CALLBACKTYPE* callbacks, + OMX_IN OMX_PTR appData) +{ + (void)hComp; + m_pCallbacks = *callbacks; + DEBUG_PRINT_LOW("Callbacks Set %p %p %p",m_pCallbacks.EmptyBufferDone,\ + m_pCallbacks.EventHandler,m_pCallbacks.FillBufferDone); + m_app_data = appData; + return OMX_ErrorNotImplemented; +} + + +/* ====================================================================== + FUNCTION + omx_venc::UseEGLImage + + DESCRIPTION + OMX Use EGL Image method implementation <TBD>. + + PARAMETERS + <TBD>. + + RETURN VALUE + Not Implemented error. + + ========================================================================== */ +OMX_ERRORTYPE omx_video::use_EGL_image(OMX_IN OMX_HANDLETYPE hComp, + OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr, + OMX_IN OMX_U32 port, + OMX_IN OMX_PTR appData, + OMX_IN void* eglImage) +{ + (void)hComp, (void)bufferHdr, (void)port, (void)appData, (void)eglImage; + DEBUG_PRINT_ERROR("ERROR: use_EGL_image: Not Implemented"); + return OMX_ErrorNotImplemented; +} + +/* ====================================================================== + FUNCTION + omx_venc::ComponentRoleEnum + + DESCRIPTION + OMX Component Role Enum method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything is successful. + ========================================================================== */ +OMX_ERRORTYPE omx_video::component_role_enum(OMX_IN OMX_HANDLETYPE hComp, + OMX_OUT OMX_U8* role, + OMX_IN OMX_U32 index) +{ + (void)hComp; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (!strncmp((char*)m_nkind, "OMX.qcom.video.decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp((char*)m_nkind, "OMX.qcom.video.decoder.h263",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.h263",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_ERROR("ERROR: No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp((char*)m_nkind, "OMX.qcom.video.decoder.avc",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.avc",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_ERROR("ERROR: No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp((char*)m_nkind, "OMX.qcom.video.decoder.vc1",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_ERROR("ERROR: No more roles"); + eRet = OMX_ErrorNoMore; + } + } + if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.mpeg4",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_encoder.mpeg4",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.h263",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_encoder.h263",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_ERROR("ERROR: No more roles"); + eRet = OMX_ErrorNoMore; + } + } else if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.avc",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_encoder.avc",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_ERROR("ERROR: No more roles"); + eRet = OMX_ErrorNoMore; + } + } +#ifdef _MSM8974_ + else if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.vp8",OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_encoder.vp8",OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s",role); + } else { + DEBUG_PRINT_ERROR("ERROR: No more roles"); + eRet = OMX_ErrorNoMore; + } + } +#endif + else if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.hevc", OMX_MAX_STRINGNAME_SIZE)) { + if ((0 == index) && role) { + strlcpy((char *)role, "video_encoder.hevc", OMX_MAX_STRINGNAME_SIZE); + DEBUG_PRINT_LOW("component_role_enum: role %s", role); + } else { + DEBUG_PRINT_ERROR("ERROR: No more roles"); + eRet = OMX_ErrorNoMore; + } + } + else { + DEBUG_PRINT_ERROR("ERROR: Querying Role on Unknown Component"); + eRet = OMX_ErrorInvalidComponentName; + } + return eRet; +} + + + + +/* ====================================================================== + FUNCTION + omx_venc::AllocateDone + + DESCRIPTION + Checks if entire buffer pool is allocated by IL Client or not. + Need this to move to IDLE state. + + PARAMETERS + None. + + RETURN VALUE + true/false. + + ========================================================================== */ +bool omx_video::allocate_done(void) +{ + bool bRet = false; + bool bRet_In = false; + bool bRet_Out = false; + + bRet_In = allocate_input_done(); + bRet_Out = allocate_output_done(); + + if (bRet_In && bRet_Out) { + bRet = true; + } + + return bRet; +} +/* ====================================================================== + FUNCTION + omx_venc::AllocateInputDone + + DESCRIPTION + Checks if I/P buffer pool is allocated by IL Client or not. + + PARAMETERS + None. + + RETURN VALUE + true/false. + + ========================================================================== */ +bool omx_video::allocate_input_done(void) +{ + bool bRet = false; + unsigned i=0; + + if (m_inp_mem_ptr == NULL) { + return bRet; + } + if (m_inp_mem_ptr ) { + for (; i<m_sInPortDef.nBufferCountActual; i++) { + if (BITMASK_ABSENT(&m_inp_bm_count,i)) { + break; + } + } + } + if (i==m_sInPortDef.nBufferCountActual) { + bRet = true; + } + if (i==m_sInPortDef.nBufferCountActual && m_sInPortDef.bEnabled) { + m_sInPortDef.bPopulated = OMX_TRUE; + } + return bRet; +} +/* ====================================================================== + FUNCTION + omx_venc::AllocateOutputDone + + DESCRIPTION + Checks if entire O/P buffer pool is allocated by IL Client or not. + + PARAMETERS + None. + + RETURN VALUE + true/false. + + ========================================================================== */ +bool omx_video::allocate_output_done(void) +{ + bool bRet = false; + unsigned j=0; + + if (m_out_mem_ptr == NULL) { + return bRet; + } + + if (m_out_mem_ptr ) { + for (; j<m_sOutPortDef.nBufferCountActual; j++) { + if (BITMASK_ABSENT(&m_out_bm_count,j)) { + break; + } + } + } + + if (j==m_sOutPortDef.nBufferCountActual) { + bRet = true; + } + + if (j==m_sOutPortDef.nBufferCountActual && m_sOutPortDef.bEnabled) { + m_sOutPortDef.bPopulated = OMX_TRUE; + } + return bRet; +} + +/* ====================================================================== + FUNCTION + omx_venc::ReleaseDone + + DESCRIPTION + Checks if IL client has released all the buffers. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_video::release_done(void) +{ + bool bRet = false; + DEBUG_PRINT_LOW("Inside release_done()"); + if (release_input_done()) { + if (release_output_done()) { + bRet = true; + } + } + return bRet; +} + + +/* ====================================================================== + FUNCTION + omx_venc::ReleaseOutputDone + + DESCRIPTION + Checks if IL client has released all the buffers. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_video::release_output_done(void) +{ + bool bRet = false; + unsigned i=0,j=0; + + DEBUG_PRINT_LOW("Inside release_output_done()"); + if (m_out_mem_ptr) { + for (; j<m_sOutPortDef.nBufferCountActual; j++) { + if (BITMASK_PRESENT(&m_out_bm_count,j)) { + break; + } + } + if (j==m_sOutPortDef.nBufferCountActual) { + bRet = true; + } + } else { + bRet = true; + } + return bRet; +} +/* ====================================================================== + FUNCTION + omx_venc::ReleaseInputDone + + DESCRIPTION + Checks if IL client has released all the buffers. + + PARAMETERS + None. + + RETURN VALUE + true/false + + ========================================================================== */ +bool omx_video::release_input_done(void) +{ + bool bRet = false; + unsigned i=0,j=0; + + DEBUG_PRINT_LOW("Inside release_input_done()"); + if (m_inp_mem_ptr) { + for (; j<m_sInPortDef.nBufferCountActual; j++) { + if ( BITMASK_PRESENT(&m_inp_bm_count,j)) { + break; + } + } + if (j==m_sInPortDef.nBufferCountActual) { + bRet = true; + } + } else { + bRet = true; + } + return bRet; +} + +OMX_ERRORTYPE omx_video::fill_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE * buffer) +{ + VIDC_TRACE_NAME_HIGH("FBD"); +#ifdef _MSM8974_ + int index = buffer - m_out_mem_ptr; +#endif + DEBUG_PRINT_LOW("fill_buffer_done: buffer->pBuffer[%p], flags=0x%x size = %u", + buffer->pBuffer, (unsigned)buffer->nFlags, (unsigned int)buffer->nFilledLen); + if (buffer == NULL || ((buffer - m_out_mem_ptr) > (int)m_sOutPortDef.nBufferCountActual)) { + return OMX_ErrorBadParameter; + } + + pending_output_buffers--; + VIDC_TRACE_INT_LOW("FTB-pending", pending_output_buffers); + VIDC_TRACE_INT_LOW("FBD-TS", buffer->nTimeStamp / 1000); + VIDC_TRACE_INT_LOW("FBD-size", buffer->nFilledLen); + + if (secure_session && m_pCallbacks.FillBufferDone) { + if (buffer->nFilledLen > 0) + m_fbd_count++; + m_pCallbacks.FillBufferDone (hComp,m_app_data,buffer); + return OMX_ErrorNone; + } + if(!secure_session) { + extra_data_handle.create_extra_data(buffer); +#ifndef _MSM8974_ + if (buffer->nFlags & OMX_BUFFERFLAG_EXTRADATA) { + DEBUG_PRINT_LOW("parsing extradata"); + extra_data_handle.parse_extra_data(buffer); + } +#endif + } + + /* For use buffer we need to copy the data */ + if (m_pCallbacks.FillBufferDone) { + if (buffer->nFilledLen > 0) { + m_fbd_count++; + + if (dev_get_output_log_flag()) { + dev_output_log_buffers((const char*)buffer->pBuffer, buffer->nFilledLen); + } + } + if (buffer->nFlags & OMX_BUFFERFLAG_EXTRADATA) { + if (!dev_handle_output_extradata((void *)buffer, index)) + DEBUG_PRINT_ERROR("Failed to parse output extradata"); + + dev_extradata_log_buffers((char *)(((unsigned long)buffer->pBuffer + buffer->nOffset + + buffer->nFilledLen + 3) & (~3))); + } + m_pCallbacks.FillBufferDone (hComp,m_app_data,buffer); + } else { + return OMX_ErrorBadParameter; + } + return OMX_ErrorNone; +} + +OMX_ERRORTYPE omx_video::empty_buffer_done(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) +{ + VIDC_TRACE_NAME_HIGH("EBD"); + int buffer_index = -1; + + buffer_index = buffer - ((mUseProxyColorFormat && !mUsesColorConversion) ? meta_buffer_hdr : m_inp_mem_ptr); + DEBUG_PRINT_LOW("empty_buffer_done: buffer[%p]", buffer); + if (buffer == NULL || + ((buffer_index > (int)m_sInPortDef.nBufferCountActual))) { + DEBUG_PRINT_ERROR("ERROR in empty_buffer_done due to index buffer"); + return OMX_ErrorBadParameter; + } + + pending_input_buffers--; + VIDC_TRACE_INT_LOW("ETB-pending", pending_input_buffers); + + if (mUseProxyColorFormat && + (buffer_index >= 0 && (buffer_index < (int)m_sInPortDef.nBufferCountActual))) { + if (!pdest_frame && !input_flush_progress && mUsesColorConversion) { + pdest_frame = buffer; + DEBUG_PRINT_LOW("empty_buffer_done pdest_frame address is %p",pdest_frame); + return push_input_buffer(hComp); + } + //check if empty-EOS-buffer is being returned, treat this same as the + //color-conversion case as we queued a color-conversion buffer to encoder + bool handleEmptyEosBuffer = (mEmptyEosBuffer == buffer); + if (mUsesColorConversion || handleEmptyEosBuffer) { + if (handleEmptyEosBuffer) { + mEmptyEosBuffer = NULL; + } + // return color-conversion buffer back to the pool + DEBUG_PRINT_LOW("empty_buffer_done insert address is %p",buffer); + if (!m_opq_pmem_q.insert_entry((unsigned long)buffer, 0, 0)) { + DEBUG_PRINT_ERROR("empty_buffer_done: pmem queue is full"); + return OMX_ErrorBadParameter; + } + } else { + // We are not dealing with color-conversion, Buffer being returned + // here is client's buffer, return it back to client + if (m_pCallbacks.EmptyBufferDone && buffer) { + m_pCallbacks.EmptyBufferDone(hComp, m_app_data, buffer); + DEBUG_PRINT_LOW("empty_buffer_done: Returning client buf %p", buffer); + } + } + } else if (m_pCallbacks.EmptyBufferDone) { + m_pCallbacks.EmptyBufferDone(hComp ,m_app_data, buffer); + } + return OMX_ErrorNone; +} + +void omx_video::complete_pending_buffer_done_cbs() +{ + unsigned long p1; + unsigned long p2; + unsigned long ident; + omx_cmd_queue tmp_q, pending_bd_q; + pthread_mutex_lock(&m_lock); + // pop all pending GENERATE FDB from ftb queue + while (m_ftb_q.m_size) { + m_ftb_q.pop_entry(&p1,&p2,&ident); + if (ident == OMX_COMPONENT_GENERATE_FBD) { + pending_bd_q.insert_entry(p1,p2,ident); + } else { + tmp_q.insert_entry(p1,p2,ident); + } + } + //return all non GENERATE FDB to ftb queue + while (tmp_q.m_size) { + tmp_q.pop_entry(&p1,&p2,&ident); + m_ftb_q.insert_entry(p1,p2,ident); + } + // pop all pending GENERATE EDB from etb queue + while (m_etb_q.m_size) { + m_etb_q.pop_entry(&p1,&p2,&ident); + if (ident == OMX_COMPONENT_GENERATE_EBD) { + pending_bd_q.insert_entry(p1,p2,ident); + } else { + tmp_q.insert_entry(p1,p2,ident); + } + } + //return all non GENERATE FDB to etb queue + while (tmp_q.m_size) { + tmp_q.pop_entry(&p1,&p2,&ident); + m_etb_q.insert_entry(p1,p2,ident); + } + pthread_mutex_unlock(&m_lock); + // process all pending buffer dones + while (pending_bd_q.m_size) { + pending_bd_q.pop_entry(&p1,&p2,&ident); + switch (ident) { + case OMX_COMPONENT_GENERATE_EBD: + if (empty_buffer_done(&m_cmp, (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("ERROR: empty_buffer_done() failed!"); + omx_report_error (); + } + break; + + case OMX_COMPONENT_GENERATE_FBD: + if (fill_buffer_done(&m_cmp, (OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone ) { + DEBUG_PRINT_ERROR("ERROR: fill_buffer_done() failed!"); + omx_report_error (); + } + break; + } + } +} + +#ifdef MAX_RES_720P +OMX_ERRORTYPE omx_video::get_supported_profile_level(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (!profileLevelType) + return OMX_ErrorBadParameter; + + if (profileLevelType->nPortIndex == 1) { + if (m_sOutPortDef.format.video.eCompressionFormat == OMX_VIDEO_CodingAVC) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileBaseline; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel31; + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileMain; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel31; + } else if (profileLevelType->nProfileIndex == 2) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileHigh; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel31; + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %d", + (int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if (m_sOutPortDef.format.video.eCompressionFormat == OMX_VIDEO_CodingH263) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_H263ProfileBaseline; + profileLevelType->eLevel = OMX_VIDEO_H263Level70; + } else { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %d", (int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if (m_sOutPortDef.format.video.eCompressionFormat == OMX_VIDEO_CodingMPEG4) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_MPEG4ProfileSimple; + profileLevelType->eLevel = OMX_VIDEO_MPEG4Level5; + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple; + profileLevelType->eLevel = OMX_VIDEO_MPEG4Level5; + } else { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %d", (int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } + } else { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported should be queried on Input port only %d", (int)profileLevelType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported for Input port returned Profile:%d, Level:%d", + (int)profileLevelType->eProfile, (int)profileLevelType->eLevel); + return eRet; +} +#endif + +#ifdef MAX_RES_1080P +OMX_ERRORTYPE omx_video::get_supported_profile_level(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + if (!profileLevelType) + return OMX_ErrorBadParameter; + + if (profileLevelType->nPortIndex == 1) { + if (m_sOutPortDef.format.video.eCompressionFormat == OMX_VIDEO_CodingAVC) { +#if defined _MSM8974_ && !defined _MSM8226_ + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileBaseline; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel52; + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileMain; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel52; + } else if (profileLevelType->nProfileIndex == 2) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileHigh; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel52; + } else if (profileLevelType->nProfileIndex == 3) { + profileLevelType->eProfile = QOMX_VIDEO_AVCProfileConstrainedBaseline; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel52; + } else if (profileLevelType->nProfileIndex == 4) { + profileLevelType->eProfile = QOMX_VIDEO_AVCProfileConstrainedHigh; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel52; + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u", + (unsigned int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } +#else + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileBaseline; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel4; + + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileMain; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel4; + } else if (profileLevelType->nProfileIndex == 2) { + profileLevelType->eProfile = OMX_VIDEO_AVCProfileHigh; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel4; +#ifdef _MSM8226_ + } else if (profileLevelType->nProfileIndex == 3) { + profileLevelType->eProfile = QOMX_VIDEO_AVCProfileConstrainedBaseline; + profileLevelType->eLevel = OMX_VIDEO_AVCLevel4; +#endif + } else { + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %d", + (int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } +#endif + } else if (m_sOutPortDef.format.video.eCompressionFormat == OMX_VIDEO_CodingH263) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_H263ProfileBaseline; + profileLevelType->eLevel = OMX_VIDEO_H263Level70; + } else { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u", (unsigned int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if (m_sOutPortDef.format.video.eCompressionFormat == OMX_VIDEO_CodingMPEG4) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_MPEG4ProfileSimple; + profileLevelType->eLevel = OMX_VIDEO_MPEG4Level5; + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple; + profileLevelType->eLevel = OMX_VIDEO_MPEG4Level5; + } else { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u", (unsigned int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if (m_sOutPortDef.format.video.eCompressionFormat == OMX_VIDEO_CodingVP8) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_VP8ProfileMain; + profileLevelType->eLevel = OMX_VIDEO_VP8Level_Version0; + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_VP8ProfileMain; + profileLevelType->eLevel = OMX_VIDEO_VP8Level_Version1; + } else { + DEBUG_PRINT_LOW("VP8: get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u", + (unsigned int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else if (m_sOutPortDef.format.video.eCompressionFormat == OMX_VIDEO_CodingHEVC) { + if (profileLevelType->nProfileIndex == 0) { + profileLevelType->eProfile = OMX_VIDEO_HEVCProfileMain; + profileLevelType->eLevel = OMX_VIDEO_HEVCMainTierLevel52; + } else if (profileLevelType->nProfileIndex == 1) { + profileLevelType->eProfile = OMX_VIDEO_HEVCProfileMain10; + profileLevelType->eLevel = OMX_VIDEO_HEVCMainTierLevel52; + } else { + DEBUG_PRINT_LOW("HEVC: get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u", + (unsigned int)profileLevelType->nProfileIndex); + eRet = OMX_ErrorNoMore; + } + } else { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported ret NoMore"); + eRet = OMX_ErrorNoMore; + } + } else { + DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported should be queried on Input port only %u", (unsigned int)profileLevelType->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported for Input port returned Profile:%u, Level:%u", + (unsigned int)profileLevelType->eProfile, (unsigned int)profileLevelType->eLevel); + return eRet; +} +#endif + +#ifdef USE_ION +int omx_video::alloc_map_ion_memory(int size, + struct ion_allocation_data *alloc_data, + struct ion_fd_data *fd_data,int flag) +{ + struct venc_ion buf_ion_info; + int ion_device_fd =-1,rc=0,ion_dev_flags = 0; + if (size <=0 || !alloc_data || !fd_data) { + DEBUG_PRINT_ERROR("Invalid input to alloc_map_ion_memory"); + return -EINVAL; + } + + ion_dev_flags = O_RDONLY; + ion_device_fd = open (MEM_DEVICE,ion_dev_flags); + if (ion_device_fd < 0) { + DEBUG_PRINT_ERROR("ERROR: ION Device open() Failed"); + return ion_device_fd; + } + + if(secure_session) { + alloc_data->len = (size + (SECURE_ALIGN - 1)) & ~(SECURE_ALIGN - 1); + alloc_data->align = SECURE_ALIGN; + alloc_data->flags = flag; + alloc_data->heap_id_mask = ION_HEAP(MEM_HEAP_ID); + if (alloc_data->flags & ION_FLAG_CP_BITSTREAM) { + alloc_data->heap_id_mask |= ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID); + } + DEBUG_PRINT_HIGH("ION ALLOC sec buf: size %u align %u flags %x", + (unsigned int)alloc_data->len, (unsigned int)alloc_data->align, + alloc_data->flags); + } else { + alloc_data->len = (size + (SZ_4K - 1)) & ~(SZ_4K - 1); + alloc_data->align = SZ_4K; + alloc_data->flags = (flag & ION_FLAG_CACHED ? ION_FLAG_CACHED : 0); +#ifdef MAX_RES_720P + alloc_data->heap_id_mask = ION_HEAP(MEM_HEAP_ID); +#else + alloc_data->heap_id_mask = (ION_HEAP(MEM_HEAP_ID) | + ION_HEAP(ION_IOMMU_HEAP_ID)); +#endif + DEBUG_PRINT_HIGH("ION ALLOC unsec buf: size %u align %u flags %x", + (unsigned int)alloc_data->len, (unsigned int)alloc_data->align, + alloc_data->flags); + } + + rc = ioctl(ion_device_fd,ION_IOC_ALLOC,alloc_data); + if (rc || !alloc_data->handle) { + DEBUG_PRINT_ERROR("ION ALLOC memory failed 0x%x", rc); + alloc_data->handle = 0; + close(ion_device_fd); + ion_device_fd = -1; + return ion_device_fd; + } + fd_data->handle = alloc_data->handle; + rc = ioctl(ion_device_fd,ION_IOC_MAP,fd_data); + if (rc) { + DEBUG_PRINT_ERROR("ION MAP failed "); + buf_ion_info.ion_alloc_data = *alloc_data; + buf_ion_info.ion_device_fd = ion_device_fd; + buf_ion_info.fd_ion_data = *fd_data; + free_ion_memory(&buf_ion_info); + fd_data->fd =-1; + ion_device_fd =-1; + } + return ion_device_fd; +} + +void omx_video::free_ion_memory(struct venc_ion *buf_ion_info) +{ + if (!buf_ion_info) { + DEBUG_PRINT_ERROR("Invalid input to free_ion_memory"); + return; + } + if (ioctl(buf_ion_info->ion_device_fd,ION_IOC_FREE, + &buf_ion_info->ion_alloc_data.handle)) { + DEBUG_PRINT_ERROR("ION free failed "); + return; + } + close(buf_ion_info->ion_device_fd); + buf_ion_info->ion_alloc_data.handle = 0; + buf_ion_info->ion_device_fd = -1; + buf_ion_info->fd_ion_data.fd = -1; +} +#endif + +#ifdef _ANDROID_ICS_ +void omx_video::omx_release_meta_buffer(OMX_BUFFERHEADERTYPE *buffer) +{ + if (buffer && meta_mode_enable) { + LEGACY_CAM_METADATA_TYPE *media_ptr; + struct pmem Input_pmem; + unsigned int index_pmem = 0; + bool meta_error = false; + + index_pmem = (buffer - m_inp_mem_ptr); + if (mUsesColorConversion && + (index_pmem < m_sInPortDef.nBufferCountActual)) { + if (!dev_free_buf((&m_pInput_pmem[index_pmem]),PORT_INDEX_IN)) { + DEBUG_PRINT_ERROR("omx_release_meta_buffer dev free failed"); + } + } else { + media_ptr = (LEGACY_CAM_METADATA_TYPE *) buffer->pBuffer; + if (media_ptr && media_ptr->meta_handle) { + if (media_ptr->buffer_type == LEGACY_CAM_SOURCE) { + Input_pmem.buffer = media_ptr; + Input_pmem.fd = MetaBufferUtil::getFdAt(media_ptr->meta_handle, 0); + int size = MetaBufferUtil::getIntAt(media_ptr->meta_handle, 0, MetaBufferUtil::INT_SIZE); + int offset = MetaBufferUtil::getIntAt(media_ptr->meta_handle, 0, MetaBufferUtil::INT_OFFSET); + if (Input_pmem.fd < 0 || size < 0 || offset < 0) { + DEBUG_PRINT_ERROR("Invalid meta buffer"); + meta_error = true; + } + Input_pmem.size = size; + Input_pmem.offset = offset; + DEBUG_PRINT_LOW("EBD fd = %d, offset = %d, size = %d",Input_pmem.fd, + Input_pmem.offset, + Input_pmem.size); + } else if (media_ptr->buffer_type == kMetadataBufferTypeGrallocSource) { + VideoGrallocMetadata *media_ptr = (VideoGrallocMetadata *)buffer->pBuffer; + private_handle_t *handle = (private_handle_t *)media_ptr->pHandle; + Input_pmem.buffer = media_ptr; + Input_pmem.fd = handle->fd; + Input_pmem.offset = 0; + Input_pmem.size = handle->size; + } else { + meta_error = true; + } + if (!meta_error) + meta_error = !dev_free_buf(&Input_pmem,PORT_INDEX_IN); + if (meta_error) { + DEBUG_PRINT_HIGH("In batchmode or dev_free_buf failed, flush %d", + input_flush_progress); + } + } + } + } +} +#endif +omx_video::omx_c2d_conv::omx_c2d_conv() +{ + c2dcc = NULL; + mLibHandle = NULL; + mConvertOpen = NULL; + mConvertClose = NULL; + src_format = NV12_128m; + pthread_mutex_init(&c_lock, NULL); +} + +bool omx_video::omx_c2d_conv::init() +{ + bool status = true; + if (mLibHandle || mConvertOpen || mConvertClose) { + DEBUG_PRINT_ERROR("omx_c2d_conv::init called twice"); + status = false; + } + if (status) { + mLibHandle = dlopen("libc2dcolorconvert.so", RTLD_LAZY); + if (mLibHandle) { + mConvertOpen = (createC2DColorConverter_t *) + dlsym(mLibHandle,"createC2DColorConverter"); + mConvertClose = (destroyC2DColorConverter_t *) + dlsym(mLibHandle,"destroyC2DColorConverter"); + if (!mConvertOpen || !mConvertClose) + status = false; + } else + status = false; + } + if (!status && mLibHandle) { + dlclose(mLibHandle); + mLibHandle = NULL; + mConvertOpen = NULL; + mConvertClose = NULL; + } + return status; +} + +bool omx_video::omx_c2d_conv::convert(int src_fd, void *src_base, void *src_viraddr, + int dest_fd, void *dest_base, void *dest_viraddr) +{ + int result; + if (!src_viraddr || !dest_viraddr || !c2dcc || !src_base || !dest_base) { + DEBUG_PRINT_ERROR("Invalid arguments omx_c2d_conv::convert"); + return false; + } + pthread_mutex_lock(&c_lock); + result = c2dcc->convertC2D(src_fd, src_base, src_viraddr, + dest_fd, dest_base, dest_viraddr); + pthread_mutex_unlock(&c_lock); + DEBUG_PRINT_LOW("Color convert status %d",result); + return ((result < 0)?false:true); +} + +bool omx_video::omx_c2d_conv::open(unsigned int height,unsigned int width, + ColorConvertFormat src, ColorConvertFormat dest, unsigned int src_stride, + unsigned int flags) +{ + bool status = false; + pthread_mutex_lock(&c_lock); + if (!c2dcc) { + c2dcc = mConvertOpen(width, height, width, height, + src, dest, flags, src_stride); + if (c2dcc) { + src_format = src; + status = true; + } else + DEBUG_PRINT_ERROR("mConvertOpen failed"); + } + pthread_mutex_unlock(&c_lock); + return status; +} + +void omx_video::omx_c2d_conv::close() +{ + if (mLibHandle) { + pthread_mutex_lock(&c_lock); + if (mConvertClose && c2dcc) + mConvertClose(c2dcc); + pthread_mutex_unlock(&c_lock); + c2dcc = NULL; + } +} +omx_video::omx_c2d_conv::~omx_c2d_conv() +{ + DEBUG_PRINT_HIGH("Destroy C2D instance"); + if (mLibHandle) { + if (mConvertClose && c2dcc) { + pthread_mutex_lock(&c_lock); + mConvertClose(c2dcc); + pthread_mutex_unlock(&c_lock); + } + dlclose(mLibHandle); + } + c2dcc = NULL; + mLibHandle = NULL; + mConvertOpen = NULL; + mConvertClose = NULL; + pthread_mutex_destroy(&c_lock); +} + +int omx_video::omx_c2d_conv::get_src_format() +{ + int format = -1; + if (src_format == NV12_128m) { + format = HAL_PIXEL_FORMAT_NV12_ENCODEABLE; + } else if (src_format == RGBA8888) { + format = HAL_PIXEL_FORMAT_RGBA_8888; + } + return format; +} + +bool omx_video::omx_c2d_conv::get_buffer_size(int port,unsigned int &buf_size) +{ + int cret = 0; + bool ret = false; + C2DBuffReq bufferreq; + if (c2dcc) { + bufferreq.size = 0; + pthread_mutex_lock(&c_lock); + cret = c2dcc->getBuffReq(port,&bufferreq); + pthread_mutex_unlock(&c_lock); + DEBUG_PRINT_LOW("Status of getbuffer is %d", cret); + ret = (cret)?false:true; + buf_size = bufferreq.size; + } + return ret; +} + +bool omx_video::is_conv_needed(int hal_fmt, int hal_flags) +{ + bool bRet = false; + + if (!strncmp(m_platform, "msm8996", 7)) { + bRet = hal_fmt == HAL_PIXEL_FORMAT_RGBA_8888 && + !(hal_flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED); + } else { + bRet = hal_fmt == HAL_PIXEL_FORMAT_RGBA_8888; + } + +#ifdef _HW_RGBA + bRet = false; +#endif + DEBUG_PRINT_LOW("RGBA conversion %s", bRet ? "Needed":"Not-Needed"); + return bRet; +} + +void omx_video::print_debug_color_aspects(ColorAspects *aspects, const char *prefix) { + DEBUG_PRINT_HIGH("%s : Color aspects : Primaries = %d Range = %d Transfer = %d MatrixCoeffs = %d", + prefix, aspects->mPrimaries, aspects->mRange, aspects->mTransfer, aspects->mMatrixCoeffs); +} + +OMX_ERRORTYPE omx_video::empty_this_buffer_opaque(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_BUFFERHEADERTYPE* buffer) +{ + VIDC_TRACE_NAME_LOW("ETB-Opaque"); + unsigned nBufIndex = 0; + OMX_ERRORTYPE ret = OMX_ErrorNone; + VideoGrallocMetadata *media_buffer; // This method primarily assumes gralloc-metadata + private_handle_t *handle = NULL; + DEBUG_PRINT_LOW("ETBProxyOpaque: buffer[%p]", buffer); + + if (buffer == NULL) { + DEBUG_PRINT_ERROR("ERROR: ETBProxyA: Invalid buffer[%p]",buffer); + return OMX_ErrorBadParameter; + } + + if (!dev_buffer_ready_to_queue(buffer)) { + DEBUG_PRINT_HIGH("Info: ETBProxyA: buffer[%p] is deffered", buffer); + return OMX_ErrorNone; + } + + nBufIndex = buffer - meta_buffer_hdr; + if (nBufIndex >= m_sInPortDef.nBufferCountActual) { + DEBUG_PRINT_ERROR("ERROR: ETBProxyA: Invalid bufindex = %u", + nBufIndex); + return OMX_ErrorBadParameter; + } + + media_buffer = (VideoGrallocMetadata *)buffer->pBuffer; + if (!media_buffer) { + DEBUG_PRINT_ERROR("%s: invalid media_buffer",__FUNCTION__); + return OMX_ErrorBadParameter; + } + if ((media_buffer->eType == LEGACY_CAM_SOURCE) + && buffer->nAllocLen != sizeof(LEGACY_CAM_METADATA_TYPE)) { + DEBUG_PRINT_ERROR("Invalid metadata size expected(%u) v/s recieved(%zu)", + buffer->nAllocLen, sizeof(LEGACY_CAM_METADATA_TYPE)); + return OMX_ErrorBadParameter; + } + + if (media_buffer && media_buffer->eType == LEGACY_CAM_SOURCE) { + return empty_this_buffer_proxy(hComp, buffer); + } + + if ((!media_buffer || !media_buffer->pHandle || media_buffer->eType != kMetadataBufferTypeGrallocSource) && + !(buffer->nFlags & OMX_BUFFERFLAG_EOS)) { + DEBUG_PRINT_ERROR("Incorrect Buffer queued media buffer = %p", + media_buffer); + m_pCallbacks.EmptyBufferDone(hComp, m_app_data, buffer); + return OMX_ErrorBadParameter; + } else if (media_buffer) { + handle = (private_handle_t *)media_buffer->pHandle; + } + + /*Enable following code once private handle color format is + updated correctly*/ + + if (buffer->nFilledLen > 0 && handle) { + if (c2d_opened && handle->format != c2d_conv.get_src_format()) { + c2d_conv.close(); + c2d_opened = false; + } + + if (!c2d_opened) { + mUsesColorConversion = is_conv_needed(handle->format, handle->flags); + if (mUsesColorConversion) { + DEBUG_PRINT_INFO("open Color conv forW: %u, H: %u", + (unsigned int)m_sInPortDef.format.video.nFrameWidth, + (unsigned int)m_sInPortDef.format.video.nFrameHeight); + if (!c2d_conv.open(m_sInPortDef.format.video.nFrameHeight, + m_sInPortDef.format.video.nFrameWidth, + RGBA8888, NV12_128m, handle->width, handle->flags)) { + m_pCallbacks.EmptyBufferDone(hComp,m_app_data,buffer); + DEBUG_PRINT_ERROR("Color conv open failed"); + return OMX_ErrorBadParameter; + } + c2d_opened = true; +#ifdef _MSM8974_ + if (!dev_set_format(NV12_128m)) + DEBUG_PRINT_ERROR("cannot set color format"); + + dev_get_buf_req (&m_sInPortDef.nBufferCountMin, + &m_sInPortDef.nBufferCountActual, + &m_sInPortDef.nBufferSize, + m_sInPortDef.nPortIndex); + +#endif + } + } + } + if (input_flush_progress == true) { + m_pCallbacks.EmptyBufferDone(hComp,m_app_data,buffer); + DEBUG_PRINT_ERROR("ERROR: ETBProxyA: Input flush in progress"); + return OMX_ErrorNone; + } + + if (!psource_frame) { + psource_frame = buffer; + ret = push_input_buffer(hComp); + } else { + if (!m_opq_meta_q.insert_entry((unsigned long)buffer,0,0)) { + DEBUG_PRINT_ERROR("ERROR: ETBProxy: Queue is full"); + m_pCallbacks.EmptyBufferDone(hComp,m_app_data,buffer); + ret = OMX_ErrorBadParameter; + } + } + return ret; +} + +OMX_ERRORTYPE omx_video::queue_meta_buffer(OMX_HANDLETYPE hComp, + struct pmem &Input_pmem_info) +{ + + OMX_ERRORTYPE ret = OMX_ErrorNone; + unsigned long address = 0,p2,id; + + DEBUG_PRINT_LOW("In queue Meta Buffer"); + if (!psource_frame || !pdest_frame) { + DEBUG_PRINT_ERROR("convert_queue_buffer invalid params"); + return OMX_ErrorBadParameter; + } + + if (psource_frame->nFilledLen > 0) { + if (dev_use_buf(&Input_pmem_info,PORT_INDEX_IN,0) != true) { + DEBUG_PRINT_ERROR("ERROR: in dev_use_buf"); + post_event ((unsigned long)psource_frame,0,OMX_COMPONENT_GENERATE_EBD); + ret = OMX_ErrorBadParameter; + } + } + + if (ret == OMX_ErrorNone) + ret = empty_this_buffer_proxy(hComp,psource_frame); + + if (ret == OMX_ErrorNone) { + psource_frame = NULL; + if (!psource_frame && m_opq_meta_q.m_size) { + m_opq_meta_q.pop_entry(&address,&p2,&id); + psource_frame = (OMX_BUFFERHEADERTYPE* ) address; + } + } else { + // there has been an error and source frame has been scheduled for an EBD + psource_frame = NULL; + } + return ret; +} + +OMX_ERRORTYPE omx_video::convert_queue_buffer(OMX_HANDLETYPE hComp, + struct pmem &Input_pmem_info,unsigned long &index) +{ + + unsigned char *uva; + OMX_ERRORTYPE ret = OMX_ErrorNone; + unsigned long address = 0,p2,id; + + DEBUG_PRINT_LOW("In Convert and queue Meta Buffer"); + if (!psource_frame || !pdest_frame) { + DEBUG_PRINT_ERROR("convert_queue_buffer invalid params"); + return OMX_ErrorBadParameter; + } + if (secure_session) { + DEBUG_PRINT_ERROR("cannot convert buffer during secure session"); + return OMX_ErrorInvalidState; + } + + if (!psource_frame->nFilledLen) { + if(psource_frame->nFlags & OMX_BUFFERFLAG_EOS) { + pdest_frame->nFilledLen = psource_frame->nFilledLen; + pdest_frame->nTimeStamp = psource_frame->nTimeStamp; + pdest_frame->nFlags = psource_frame->nFlags; + DEBUG_PRINT_HIGH("Skipping color conversion for empty EOS Buffer " + "header=%p filled-len=%u", pdest_frame, (unsigned int)pdest_frame->nFilledLen); + } else { + pdest_frame->nOffset = 0; + pdest_frame->nFilledLen = 0; + pdest_frame->nTimeStamp = psource_frame->nTimeStamp; + pdest_frame->nFlags = psource_frame->nFlags; + DEBUG_PRINT_LOW("Buffer header %p Filled len size %u", + pdest_frame, (unsigned int)pdest_frame->nFilledLen); + } + } else { + uva = (unsigned char *)mmap(NULL, Input_pmem_info.size, + PROT_READ|PROT_WRITE, + MAP_SHARED,Input_pmem_info.fd,0); + if (uva == MAP_FAILED) { + ret = OMX_ErrorBadParameter; + } else { + if (!c2d_conv.convert(Input_pmem_info.fd, uva, uva, + m_pInput_pmem[index].fd, pdest_frame->pBuffer, pdest_frame->pBuffer)) { + DEBUG_PRINT_ERROR("Color Conversion failed"); + ret = OMX_ErrorBadParameter; + } else { + unsigned int buf_size = 0; + if (!c2d_conv.get_buffer_size(C2D_OUTPUT,buf_size)) + ret = OMX_ErrorBadParameter; + else { + pdest_frame->nOffset = 0; + pdest_frame->nFilledLen = buf_size; + pdest_frame->nTimeStamp = psource_frame->nTimeStamp; + pdest_frame->nFlags = psource_frame->nFlags; + DEBUG_PRINT_LOW("Buffer header %p Filled len size %u", + pdest_frame, (unsigned int)pdest_frame->nFilledLen); + } + } + munmap(uva,Input_pmem_info.size); + } + } + if (dev_use_buf(&m_pInput_pmem[index],PORT_INDEX_IN,0) != true) { + DEBUG_PRINT_ERROR("ERROR: in dev_use_buf"); + post_event ((unsigned long)pdest_frame,0,OMX_COMPONENT_GENERATE_EBD); + ret = OMX_ErrorBadParameter; + } + if (ret == OMX_ErrorNone) + ret = empty_this_buffer_proxy(hComp,pdest_frame); + if (ret == OMX_ErrorNone) { + m_pCallbacks.EmptyBufferDone(hComp ,m_app_data, psource_frame); + psource_frame = NULL; + pdest_frame = NULL; + if (!psource_frame && m_opq_meta_q.m_size) { + m_opq_meta_q.pop_entry(&address,&p2,&id); + psource_frame = (OMX_BUFFERHEADERTYPE* ) address; + } + if (!pdest_frame && m_opq_pmem_q.m_size) { + m_opq_pmem_q.pop_entry(&address,&p2,&id); + pdest_frame = (OMX_BUFFERHEADERTYPE* ) address; + DEBUG_PRINT_LOW("pdest_frame pop address is %p",pdest_frame); + } + } else { + // there has been an error and source frame has been scheduled for an EBD + psource_frame = NULL; + } + return ret; +} + +OMX_ERRORTYPE omx_video::push_input_buffer(OMX_HANDLETYPE hComp) +{ + unsigned long address = 0,p2,id, index = 0; + OMX_ERRORTYPE ret = OMX_ErrorNone; + + DEBUG_PRINT_LOW("In push input buffer"); + if (!psource_frame && m_opq_meta_q.m_size) { + m_opq_meta_q.pop_entry(&address,&p2,&id); + psource_frame = (OMX_BUFFERHEADERTYPE* ) address; + } + if (!pdest_frame && m_opq_pmem_q.m_size) { + m_opq_pmem_q.pop_entry(&address,&p2,&id); + pdest_frame = (OMX_BUFFERHEADERTYPE* ) address; + } + while (psource_frame != NULL && pdest_frame != NULL && + ret == OMX_ErrorNone) { + struct pmem Input_pmem_info; + LEGACY_CAM_METADATA_TYPE *media_buffer; + index = pdest_frame - m_inp_mem_ptr; + if (index >= m_sInPortDef.nBufferCountActual) { + DEBUG_PRINT_ERROR("Output buffer index is wrong %u act count %u", + (unsigned int)index, (unsigned int)m_sInPortDef.nBufferCountActual); + return OMX_ErrorBadParameter; + } + + //Meta-Buffer with empty filled-length can contain garbage handle + //Some clients queue such buffers to signal EOS. Handle this case + // separately by queueing an intermediate color-conversion buffer + // and propagate the EOS. + if (psource_frame->nFilledLen == 0 && (psource_frame->nFlags & OMX_BUFFERFLAG_EOS)) { + return push_empty_eos_buffer(hComp, psource_frame); + } + media_buffer = (LEGACY_CAM_METADATA_TYPE *)psource_frame->pBuffer; + /*Will enable to verify camcorder in current TIPS can be removed*/ + if (media_buffer->buffer_type == LEGACY_CAM_SOURCE) { + Input_pmem_info.buffer = media_buffer; + Input_pmem_info.fd = MetaBufferUtil::getFdAt(media_buffer->meta_handle, 0); + Input_pmem_info.offset = MetaBufferUtil::getIntAt(media_buffer->meta_handle, 0, MetaBufferUtil::INT_OFFSET); + Input_pmem_info.size = MetaBufferUtil::getIntAt(media_buffer->meta_handle, 0, MetaBufferUtil::INT_SIZE); + m_graphicbuffer_size = Input_pmem_info.size; + DEBUG_PRINT_LOW("ETB fd = %d, offset = %d, size = %d",Input_pmem_info.fd, + Input_pmem_info.offset, + Input_pmem_info.size); + ret = queue_meta_buffer(hComp,Input_pmem_info); + } else { + VideoGrallocMetadata *media_buffer = (VideoGrallocMetadata *)psource_frame->pBuffer; + private_handle_t *handle = (private_handle_t *)media_buffer->pHandle; + Input_pmem_info.buffer = media_buffer; + Input_pmem_info.fd = handle->fd; + Input_pmem_info.offset = 0; + Input_pmem_info.size = handle->size; + m_graphicbuffer_size = Input_pmem_info.size; + if (is_conv_needed(handle->format, handle->flags)) + ret = convert_queue_buffer(hComp,Input_pmem_info,index); + else if (handle->format == HAL_PIXEL_FORMAT_NV12_ENCODEABLE || + handle->format == QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m || + handle->format == QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed || + handle->format == HAL_PIXEL_FORMAT_RGBA_8888 || + handle->format == QOMX_COLOR_Format32bitRGBA8888Compressed) + ret = queue_meta_buffer(hComp,Input_pmem_info); + else + ret = OMX_ErrorBadParameter; + } + } + return ret; +} + +OMX_ERRORTYPE omx_video::push_empty_eos_buffer(OMX_HANDLETYPE hComp, + OMX_BUFFERHEADERTYPE* buffer) { + OMX_BUFFERHEADERTYPE* opqBuf = NULL; + OMX_ERRORTYPE retVal = OMX_ErrorNone; + unsigned index = 0; + + DEBUG_PRINT_LOW("In push empty eos buffer"); + do { + if (mUsesColorConversion) { + if (pdest_frame) { + //[1] use a checked out conversion buffer, if one is available + opqBuf = pdest_frame; + pdest_frame = NULL; + } else if (m_opq_pmem_q.m_size) { + //[2] else pop out one from the queue, if available + unsigned long address = 0, p2, id; + m_opq_pmem_q.pop_entry(&address,&p2,&id); + opqBuf = (OMX_BUFFERHEADERTYPE* ) address; + } + index = opqBuf - m_inp_mem_ptr; + } else { + opqBuf = (OMX_BUFFERHEADERTYPE* ) buffer; + index = opqBuf - meta_buffer_hdr; + } + + if (!opqBuf || index >= m_sInPortDef.nBufferCountActual) { + DEBUG_PRINT_ERROR("push_empty_eos_buffer: Could not find a " + "color-conversion buffer to queue ! defer until available"); + //[3] else, returning back will defer calling this function again + //until a conversion buffer is returned by the encoder and also + //hold on to the client's buffer + return OMX_ErrorNone; + } + struct pmem Input_pmem_info; + Input_pmem_info.buffer = opqBuf; + Input_pmem_info.fd = m_pInput_pmem[index].fd; + Input_pmem_info.offset = 0; + Input_pmem_info.size = m_pInput_pmem[index].size; + + if (dev_use_buf(&Input_pmem_info, PORT_INDEX_IN, 0) != true) { + DEBUG_PRINT_ERROR("ERROR: in dev_use_buf for empty eos buffer"); + retVal = OMX_ErrorBadParameter; + break; + } + + //Queue with null pBuffer, as pBuffer in client's hdr can be junk + //Clone the color-conversion buffer to avoid overwriting original buffer + OMX_BUFFERHEADERTYPE emptyEosBufHdr; + memcpy(&emptyEosBufHdr, opqBuf, sizeof(OMX_BUFFERHEADERTYPE)); + emptyEosBufHdr.nFilledLen = 0; + emptyEosBufHdr.nTimeStamp = buffer->nTimeStamp; + emptyEosBufHdr.nFlags = buffer->nFlags; + emptyEosBufHdr.pBuffer = NULL; + if (!mUsesColorConversion) + emptyEosBufHdr.nAllocLen = + m_graphicbuffer_size ? m_graphicbuffer_size : m_sInPortDef.nBufferSize; + + if (dev_empty_buf(&emptyEosBufHdr, 0, index, m_pInput_pmem[index].fd) != true) { + DEBUG_PRINT_ERROR("ERROR: in dev_empty_buf for empty eos buffer"); + dev_free_buf(&Input_pmem_info, PORT_INDEX_IN); + retVal = OMX_ErrorBadParameter; + break; + } + mEmptyEosBuffer = opqBuf; + } while(false); + + //return client's buffer regardless since intermediate color-conversion + //buffer is sent to the the encoder + m_pCallbacks.EmptyBufferDone(hComp, m_app_data, buffer); + --pending_input_buffers; + VIDC_TRACE_INT_LOW("ETB-pending", pending_input_buffers); + return retVal; +} diff --git a/msm8998/mm-video-v4l2/vidc/venc/src/omx_video_encoder.cpp b/msm8998/mm-video-v4l2/vidc/venc/src/omx_video_encoder.cpp new file mode 100644 index 0000000..d5ac1d9 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/src/omx_video_encoder.cpp @@ -0,0 +1,2678 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2016, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#include "omx_video_encoder.h" +#include <string.h> +#include <stdio.h> +#include <fcntl.h> +#include <dlfcn.h> +#ifdef _ANDROID_ICS_ +#include <media/hardware/HardwareAPI.h> +#endif +#ifdef _ANDROID_ +#include <cutils/properties.h> +#endif +#ifdef _USE_GLIB_ +#include <glib.h> +#define strlcpy g_strlcpy +#endif + +extern int m_pipe; +static int bframes; +static int entropy; +static int lowlatency; +// factory function executed by the core to create instances +void *get_omx_component_factory_fn(void) +{ + return(new omx_venc); +} + +omx_venc::perf_control::perf_control() +{ + m_perf_lib = NULL; + m_perf_lock_acquire = NULL; + m_perf_lock_release = NULL; + m_perf_handle = 0; +} + +omx_venc::perf_control::~perf_control() +{ + if (m_perf_handle != 0 && m_perf_lock_release) { + m_perf_lock_release(m_perf_handle); + } + if (m_perf_lib) { + dlclose(m_perf_lib); + } +} + +void omx_venc::perf_control::send_hint_to_mpctl(bool state) +{ + if (load_lib() == false) { + return; + } + /* 0x4601 maps to video encode callback in + * perflock, 46 is the enum number, 01 is + * the state being sent when perflock + * acquire succeeds + */ + int arg = 0x4601; + + if (m_perf_lock_acquire && state == true) { + m_perf_handle = m_perf_lock_acquire(0, 0, &arg, sizeof(arg) / sizeof(int)); + DEBUG_PRINT_INFO("Video encode perflock acquired,handle=%d",m_perf_handle); + } else if (m_perf_lock_release && state == false) { + m_perf_lock_release(m_perf_handle); + DEBUG_PRINT_INFO("Video encode perflock released"); + } +} + +bool omx_venc::perf_control::load_lib() +{ + char perf_lib_path[PROPERTY_VALUE_MAX] = {0}; + if (m_perf_lib) + return true; + + if ((property_get("ro.vendor.extension_library", perf_lib_path, NULL) <= 0)) { + DEBUG_PRINT_ERROR("vendor library not set in ro.vendor.extension_library"); + goto handle_err; + } + if ((m_perf_lib = dlopen(perf_lib_path, RTLD_NOW)) == NULL) { + DEBUG_PRINT_ERROR("Failed to open %s : %s",perf_lib_path, dlerror()); + goto handle_err; + } else { + m_perf_lock_acquire = (perf_lock_acquire_t)dlsym(m_perf_lib, "perf_lock_acq"); + if (m_perf_lock_acquire == NULL) { + DEBUG_PRINT_ERROR("Failed to load symbol: perf_lock_acq"); + goto handle_err; + } + m_perf_lock_release = (perf_lock_release_t)dlsym(m_perf_lib, "perf_lock_rel"); + if (m_perf_lock_release == NULL) { + DEBUG_PRINT_ERROR("Failed to load symbol: perf_lock_rel"); + goto handle_err; + } + } + return true; + +handle_err: + if(m_perf_lib != NULL) { + dlclose(m_perf_lib); + } + return false; +} + +//constructor + +omx_venc::omx_venc() +{ +#ifdef _ANDROID_ICS_ + meta_mode_enable = false; + memset(meta_buffer_hdr,0,sizeof(meta_buffer_hdr)); + memset(meta_buffers,0,sizeof(meta_buffers)); + memset(opaque_buffer_hdr,0,sizeof(opaque_buffer_hdr)); + mUseProxyColorFormat = false; + get_syntaxhdr_enable = false; +#endif + bframes = entropy = 0; + char property_value[PROPERTY_VALUE_MAX] = {0}; + property_get("vidc.debug.level", property_value, "1"); + debug_level = strtoul(property_value, NULL, 16); + property_value[0] = '\0'; + property_get("vidc.debug.bframes", property_value, "0"); + bframes = atoi(property_value); + property_value[0] = '\0'; + property_get("vidc.debug.entropy", property_value, "1"); + entropy = !!atoi(property_value); + property_value[0] = '\0'; + handle = NULL; + property_get("vidc.debug.lowlatency", property_value, "0"); + lowlatency = atoi(property_value); + property_value[0] = '\0'; + m_perf_control.send_hint_to_mpctl(true); +} + +omx_venc::~omx_venc() +{ + get_syntaxhdr_enable = false; + m_perf_control.send_hint_to_mpctl(false); + //nothing to do +} + +/* ====================================================================== + FUNCTION + omx_venc::ComponentInit + + DESCRIPTION + Initialize the component. + + PARAMETERS + ctxt -- Context information related to the self. + id -- Event identifier. This could be any of the following: + 1. Command completion event + 2. Buffer done callback event + 3. Frame done callback event + + RETURN VALUE + None. + + ========================================================================== */ +OMX_ERRORTYPE omx_venc::component_init(OMX_STRING role) +{ + + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + int fds[2]; + int r; + + OMX_VIDEO_CODINGTYPE codec_type; + + DEBUG_PRINT_HIGH("omx_venc(): Inside component_init()"); + // Copy the role information which provides the decoder m_nkind + strlcpy((char *)m_nkind,role,OMX_MAX_STRINGNAME_SIZE); + secure_session = false; + + if (!strncmp((char *)m_nkind,"OMX.qcom.video.encoder.mpeg4",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_encoder.mpeg4",\ + OMX_MAX_STRINGNAME_SIZE); + codec_type = OMX_VIDEO_CodingMPEG4; + } else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.h263",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_encoder.h263",OMX_MAX_STRINGNAME_SIZE); + codec_type = OMX_VIDEO_CodingH263; + } else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.avc",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_encoder.avc",OMX_MAX_STRINGNAME_SIZE); + codec_type = OMX_VIDEO_CodingAVC; + } else if(!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.avc.secure",\ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_encoder.avc",OMX_MAX_STRINGNAME_SIZE); + codec_type = OMX_VIDEO_CodingAVC; + secure_session = true; + } +#ifdef _MSM8974_ + else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.vp8", \ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_encoder.vp8",OMX_MAX_STRINGNAME_SIZE); + codec_type = OMX_VIDEO_CodingVP8; + } +#endif + else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.hevc", \ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_encoder.hevc", OMX_MAX_STRINGNAME_SIZE); + codec_type = OMX_VIDEO_CodingHEVC; + } else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.hevc.secure", \ + OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char *)m_cRole, "video_encoder.hevc", OMX_MAX_STRINGNAME_SIZE); + codec_type = OMX_VIDEO_CodingHEVC; + secure_session = true; + } else { + DEBUG_PRINT_ERROR("ERROR: Unknown Component"); + eRet = OMX_ErrorInvalidComponentName; + } + + if (eRet != OMX_ErrorNone) { + return eRet; + } +#ifdef ENABLE_GET_SYNTAX_HDR + get_syntaxhdr_enable = true; + DEBUG_PRINT_HIGH("Get syntax header enabled"); +#endif + + handle = new venc_dev(this); + + if (handle == NULL) { + DEBUG_PRINT_ERROR("ERROR: handle is NULL"); + return OMX_ErrorInsufficientResources; + } + + if (handle->venc_open(codec_type) != true) { + DEBUG_PRINT_ERROR("ERROR: venc_open failed"); + eRet = OMX_ErrorInsufficientResources; + goto init_error; + } + + //Intialise the OMX layer variables + memset(&m_pCallbacks,0,sizeof(OMX_CALLBACKTYPE)); + + OMX_INIT_STRUCT(&m_sPortParam, OMX_PORT_PARAM_TYPE); + m_sPortParam.nPorts = 0x2; + m_sPortParam.nStartPortNumber = (OMX_U32) PORT_INDEX_IN; + + OMX_INIT_STRUCT(&m_sPortParam_audio, OMX_PORT_PARAM_TYPE); + m_sPortParam_audio.nPorts = 0; + m_sPortParam_audio.nStartPortNumber = 0; + + OMX_INIT_STRUCT(&m_sPortParam_img, OMX_PORT_PARAM_TYPE); + m_sPortParam_img.nPorts = 0; + m_sPortParam_img.nStartPortNumber = 0; + + OMX_INIT_STRUCT(&m_sParamBitrate, OMX_VIDEO_PARAM_BITRATETYPE); + m_sParamBitrate.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamBitrate.eControlRate = OMX_Video_ControlRateVariableSkipFrames; + m_sParamBitrate.nTargetBitrate = 64000; + + OMX_INIT_STRUCT(&m_sConfigBitrate, OMX_VIDEO_CONFIG_BITRATETYPE); + m_sConfigBitrate.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigBitrate.nEncodeBitrate = 64000; + + OMX_INIT_STRUCT(&m_sConfigFramerate, OMX_CONFIG_FRAMERATETYPE); + m_sConfigFramerate.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigFramerate.xEncodeFramerate = 30 << 16; + + OMX_INIT_STRUCT(&m_sConfigIntraRefreshVOP, OMX_CONFIG_INTRAREFRESHVOPTYPE); + m_sConfigIntraRefreshVOP.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigIntraRefreshVOP.IntraRefreshVOP = OMX_FALSE; + + OMX_INIT_STRUCT(&m_sConfigFrameRotation, OMX_CONFIG_ROTATIONTYPE); + m_sConfigFrameRotation.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigFrameRotation.nRotation = 0; + + OMX_INIT_STRUCT(&m_sConfigAVCIDRPeriod, OMX_VIDEO_CONFIG_AVCINTRAPERIOD); + m_sConfigAVCIDRPeriod.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + + OMX_INIT_STRUCT(&m_sPrependSPSPPS, PrependSPSPPSToIDRFramesParams); + m_sPrependSPSPPS.bEnable = OMX_FALSE; + + OMX_INIT_STRUCT(&m_sSessionQuantization, OMX_VIDEO_PARAM_QUANTIZATIONTYPE); + m_sSessionQuantization.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sSessionQuantization.nQpI = 9; + m_sSessionQuantization.nQpP = 6; + m_sSessionQuantization.nQpB = 2; + + OMX_INIT_STRUCT(&m_sSessionQPRange, OMX_QCOM_VIDEO_PARAM_QPRANGETYPE); + OMX_INIT_STRUCT(&m_sSessionIPBQPRange, OMX_QCOM_VIDEO_PARAM_IPB_QPRANGETYPE); + m_sSessionQPRange.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sSessionIPBQPRange.nPortIndex = (OMX_U32)PORT_INDEX_OUT; + m_sSessionQPRange.minQP = 2; + if (codec_type == OMX_VIDEO_CodingAVC) { + m_sSessionQPRange.maxQP = 51; + } else { + m_sSessionQPRange.maxQP = 31; + } + m_sSessionIPBQPRange.minIQP = + m_sSessionIPBQPRange.minPQP = + m_sSessionIPBQPRange.minBQP = m_sSessionQPRange.minQP; + m_sSessionIPBQPRange.maxIQP = + m_sSessionIPBQPRange.maxPQP = + m_sSessionIPBQPRange.maxBQP = m_sSessionQPRange.maxQP; + OMX_INIT_STRUCT(&m_sAVCSliceFMO, OMX_VIDEO_PARAM_AVCSLICEFMO); + m_sAVCSliceFMO.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sAVCSliceFMO.eSliceMode = OMX_VIDEO_SLICEMODE_AVCDefault; + m_sAVCSliceFMO.nNumSliceGroups = 0; + m_sAVCSliceFMO.nSliceGroupMapType = 0; + OMX_INIT_STRUCT(&m_sParamProfileLevel, OMX_VIDEO_PARAM_PROFILELEVELTYPE); + m_sParamProfileLevel.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + + OMX_INIT_STRUCT(&m_sIntraperiod, QOMX_VIDEO_INTRAPERIODTYPE); + m_sIntraperiod.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sIntraperiod.nPFrames = (m_sConfigFramerate.xEncodeFramerate * 2) - 1; + + OMX_INIT_STRUCT(&m_sErrorCorrection, OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE); + m_sErrorCorrection.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sErrorCorrection.bEnableDataPartitioning = OMX_FALSE; + m_sErrorCorrection.bEnableHEC = OMX_FALSE; + m_sErrorCorrection.bEnableResync = OMX_FALSE; + m_sErrorCorrection.bEnableRVLC = OMX_FALSE; + m_sErrorCorrection.nResynchMarkerSpacing = 0; + + OMX_INIT_STRUCT(&m_sIntraRefresh, OMX_VIDEO_PARAM_INTRAREFRESHTYPE); + m_sIntraRefresh.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sIntraRefresh.eRefreshMode = OMX_VIDEO_IntraRefreshMax; + +#ifdef SUPPORT_CONFIG_INTRA_REFRESH + OMX_INIT_STRUCT(&m_sConfigIntraRefresh, OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE); + m_sConfigIntraRefresh.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigIntraRefresh.nRefreshPeriod = 0; +#endif + + OMX_INIT_STRUCT(&m_sConfigColorAspects, DescribeColorAspectsParams); + m_sConfigColorAspects.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigColorAspects.sAspects.mRange = ColorAspects::RangeUnspecified; + m_sConfigColorAspects.sAspects.mPrimaries = ColorAspects::PrimariesUnspecified; + m_sConfigColorAspects.sAspects.mMatrixCoeffs = ColorAspects::MatrixUnspecified; + m_sConfigColorAspects.sAspects.mTransfer = ColorAspects::TransferUnspecified; + + if (codec_type == OMX_VIDEO_CodingMPEG4) { + m_sParamProfileLevel.eProfile = (OMX_U32) OMX_VIDEO_MPEG4ProfileSimple; + m_sParamProfileLevel.eLevel = (OMX_U32) OMX_VIDEO_MPEG4Level0; + } else if (codec_type == OMX_VIDEO_CodingH263) { + m_sParamProfileLevel.eProfile = (OMX_U32) OMX_VIDEO_H263ProfileBaseline; + m_sParamProfileLevel.eLevel = (OMX_U32) OMX_VIDEO_H263Level10; + } else if (codec_type == OMX_VIDEO_CodingAVC) { + m_sParamProfileLevel.eProfile = (OMX_U32) OMX_VIDEO_AVCProfileBaseline; + m_sParamProfileLevel.eLevel = (OMX_U32) OMX_VIDEO_AVCLevel1; + } else if (codec_type == OMX_VIDEO_CodingVP8) { + m_sParamProfileLevel.eProfile = (OMX_U32) OMX_VIDEO_VP8ProfileMain; + m_sParamProfileLevel.eLevel = (OMX_U32) OMX_VIDEO_VP8Level_Version0; + } else if (codec_type == OMX_VIDEO_CodingHEVC) { + m_sParamProfileLevel.eProfile = (OMX_U32) OMX_VIDEO_HEVCProfileMain; + m_sParamProfileLevel.eLevel = (OMX_U32) OMX_VIDEO_HEVCMainTierLevel1; + } + + OMX_INIT_STRUCT(&m_sParamEntropy, QOMX_VIDEO_H264ENTROPYCODINGTYPE); + m_sParamEntropy.bCabac = OMX_FALSE; + + // Initialize the video parameters for input port + OMX_INIT_STRUCT(&m_sInPortDef, OMX_PARAM_PORTDEFINITIONTYPE); + m_sInPortDef.nPortIndex= (OMX_U32) PORT_INDEX_IN; + m_sInPortDef.bEnabled = OMX_TRUE; + m_sInPortDef.bPopulated = OMX_FALSE; + m_sInPortDef.eDomain = OMX_PortDomainVideo; + m_sInPortDef.eDir = OMX_DirInput; + m_sInPortDef.format.video.cMIMEType = (char *)"YUV420"; + m_sInPortDef.format.video.nFrameWidth = OMX_CORE_QCIF_WIDTH; + m_sInPortDef.format.video.nFrameHeight = OMX_CORE_QCIF_HEIGHT; + m_sInPortDef.format.video.nStride = OMX_CORE_QCIF_WIDTH; + m_sInPortDef.format.video.nSliceHeight = OMX_CORE_QCIF_HEIGHT; + m_sInPortDef.format.video.nBitrate = 64000; + m_sInPortDef.format.video.xFramerate = 15 << 16; + m_sInPortDef.format.video.eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_DEFAULT_COLOR_FMT; + m_sInPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; + + if (dev_get_buf_req(&m_sInPortDef.nBufferCountMin, + &m_sInPortDef.nBufferCountActual, + &m_sInPortDef.nBufferSize, + m_sInPortDef.nPortIndex) != true) { + eRet = OMX_ErrorUndefined; + goto init_error; + } + + // Initialize the video parameters for output port + OMX_INIT_STRUCT(&m_sOutPortDef, OMX_PARAM_PORTDEFINITIONTYPE); + m_sOutPortDef.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sOutPortDef.bEnabled = OMX_TRUE; + m_sOutPortDef.bPopulated = OMX_FALSE; + m_sOutPortDef.eDomain = OMX_PortDomainVideo; + m_sOutPortDef.eDir = OMX_DirOutput; + m_sOutPortDef.format.video.nFrameWidth = OMX_CORE_QCIF_WIDTH; + m_sOutPortDef.format.video.nFrameHeight = OMX_CORE_QCIF_HEIGHT; + m_sOutPortDef.format.video.nBitrate = 64000; + m_sOutPortDef.format.video.xFramerate = 15 << 16; + m_sOutPortDef.format.video.eColorFormat = OMX_COLOR_FormatUnused; + if (codec_type == OMX_VIDEO_CodingMPEG4) { + m_sOutPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4; + } else if (codec_type == OMX_VIDEO_CodingH263) { + m_sOutPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingH263; + } else if (codec_type == OMX_VIDEO_CodingAVC) { + m_sOutPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC; + } else if (codec_type == OMX_VIDEO_CodingVP8) { + m_sOutPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingVP8; + } else if (codec_type == OMX_VIDEO_CodingHEVC) { + m_sOutPortDef.format.video.eCompressionFormat = OMX_VIDEO_CodingHEVC; + } + + if (dev_get_buf_req(&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + m_sOutPortDef.nPortIndex) != true) { + eRet = OMX_ErrorUndefined; + } + + // Initialize the video color format for input port + OMX_INIT_STRUCT(&m_sInPortFormat, OMX_VIDEO_PARAM_PORTFORMATTYPE); + m_sInPortFormat.nPortIndex = (OMX_U32) PORT_INDEX_IN; + m_sInPortFormat.nIndex = 0; + m_sInPortFormat.eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_DEFAULT_COLOR_FMT; + m_sInPortFormat.eCompressionFormat = OMX_VIDEO_CodingUnused; + + + // Initialize the compression format for output port + OMX_INIT_STRUCT(&m_sOutPortFormat, OMX_VIDEO_PARAM_PORTFORMATTYPE); + m_sOutPortFormat.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sOutPortFormat.nIndex = 0; + m_sOutPortFormat.eColorFormat = OMX_COLOR_FormatUnused; + if (codec_type == OMX_VIDEO_CodingMPEG4) { + m_sOutPortFormat.eCompressionFormat = OMX_VIDEO_CodingMPEG4; + } else if (codec_type == OMX_VIDEO_CodingH263) { + m_sOutPortFormat.eCompressionFormat = OMX_VIDEO_CodingH263; + } else if (codec_type == OMX_VIDEO_CodingAVC) { + m_sOutPortFormat.eCompressionFormat = OMX_VIDEO_CodingAVC; + } else if (codec_type == OMX_VIDEO_CodingVP8) { + m_sOutPortFormat.eCompressionFormat = OMX_VIDEO_CodingVP8; + } else if (codec_type == OMX_VIDEO_CodingHEVC) { + m_sOutPortFormat.eCompressionFormat = OMX_VIDEO_CodingHEVC; + } + + // mandatory Indices for kronos test suite + OMX_INIT_STRUCT(&m_sPriorityMgmt, OMX_PRIORITYMGMTTYPE); + + OMX_INIT_STRUCT(&m_sInBufSupplier, OMX_PARAM_BUFFERSUPPLIERTYPE); + m_sInBufSupplier.nPortIndex = (OMX_U32) PORT_INDEX_IN; + + OMX_INIT_STRUCT(&m_sOutBufSupplier, OMX_PARAM_BUFFERSUPPLIERTYPE); + m_sOutBufSupplier.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + + OMX_INIT_STRUCT(&m_sParamInitqp, QOMX_EXTNINDEX_VIDEO_INITIALQP); + m_sParamInitqp.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + + // mp4 specific init + OMX_INIT_STRUCT(&m_sParamMPEG4, OMX_VIDEO_PARAM_MPEG4TYPE); + m_sParamMPEG4.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamMPEG4.eProfile = OMX_VIDEO_MPEG4ProfileSimple; + m_sParamMPEG4.eLevel = OMX_VIDEO_MPEG4Level0; + m_sParamMPEG4.nSliceHeaderSpacing = 0; + m_sParamMPEG4.bSVH = OMX_FALSE; + m_sParamMPEG4.bGov = OMX_FALSE; + m_sParamMPEG4.nPFrames = (m_sOutPortFormat.xFramerate * 2 - 1); // 2 second intra period for default outport fps + m_sParamMPEG4.bACPred = OMX_TRUE; + m_sParamMPEG4.nTimeIncRes = 30; // delta = 2 @ 15 fps + m_sParamMPEG4.nAllowedPictureTypes = 2; // pframe and iframe + m_sParamMPEG4.nHeaderExtension = 1; // number of video packet headers per vop + m_sParamMPEG4.bReversibleVLC = OMX_FALSE; + + // h263 specific init + OMX_INIT_STRUCT(&m_sParamH263, OMX_VIDEO_PARAM_H263TYPE); + m_sParamH263.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamH263.nPFrames = (m_sOutPortFormat.xFramerate * 2 - 1); // 2 second intra period for default outport fps + m_sParamH263.nBFrames = 0; + m_sParamH263.eProfile = OMX_VIDEO_H263ProfileBaseline; + m_sParamH263.eLevel = OMX_VIDEO_H263Level10; + m_sParamH263.bPLUSPTYPEAllowed = OMX_FALSE; + m_sParamH263.nAllowedPictureTypes = 2; + m_sParamH263.bForceRoundingTypeToZero = OMX_TRUE; + m_sParamH263.nPictureHeaderRepetition = 0; + m_sParamH263.nGOBHeaderInterval = 1; + + // h264 specific init + OMX_INIT_STRUCT(&m_sParamAVC, OMX_VIDEO_PARAM_AVCTYPE); + m_sParamAVC.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamAVC.nSliceHeaderSpacing = 0; + m_sParamAVC.nPFrames = (m_sOutPortFormat.xFramerate * 2 - 1); // 2 second intra period for default outport fps + m_sParamAVC.nBFrames = 0; + m_sParamAVC.bUseHadamard = OMX_FALSE; + m_sParamAVC.nRefIdx10ActiveMinus1 = 1; + m_sParamAVC.nRefIdx11ActiveMinus1 = 0; + m_sParamAVC.bEnableUEP = OMX_FALSE; + m_sParamAVC.bEnableFMO = OMX_FALSE; + m_sParamAVC.bEnableASO = OMX_FALSE; + m_sParamAVC.bEnableRS = OMX_FALSE; + m_sParamAVC.eProfile = OMX_VIDEO_AVCProfileBaseline; + m_sParamAVC.eLevel = OMX_VIDEO_AVCLevel1; + m_sParamAVC.nAllowedPictureTypes = 2; + m_sParamAVC.bFrameMBsOnly = OMX_FALSE; + m_sParamAVC.bMBAFF = OMX_FALSE; + m_sParamAVC.bEntropyCodingCABAC = OMX_FALSE; + m_sParamAVC.bWeightedPPrediction = OMX_FALSE; + m_sParamAVC.nWeightedBipredicitonMode = 0; + m_sParamAVC.bconstIpred = OMX_FALSE; + m_sParamAVC.bDirect8x8Inference = OMX_FALSE; + m_sParamAVC.bDirectSpatialTemporal = OMX_FALSE; + m_sParamAVC.nCabacInitIdc = 0; + m_sParamAVC.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable; + + // VP8 specific init + OMX_INIT_STRUCT(&m_sParamVP8, OMX_VIDEO_PARAM_VP8TYPE); + m_sParamVP8.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamVP8.eProfile = OMX_VIDEO_VP8ProfileMain; + m_sParamVP8.eLevel = OMX_VIDEO_VP8Level_Version0; + m_sParamVP8.nDCTPartitions = 0; + m_sParamVP8.bErrorResilientMode = OMX_FALSE; + + // HEVC specific init + OMX_INIT_STRUCT(&m_sParamHEVC, OMX_VIDEO_PARAM_HEVCTYPE); + m_sParamHEVC.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamHEVC.eProfile = OMX_VIDEO_HEVCProfileMain; + m_sParamHEVC.eLevel = OMX_VIDEO_HEVCMainTierLevel1; + + OMX_INIT_STRUCT(&m_sParamLTRMode, QOMX_VIDEO_PARAM_LTRMODE_TYPE); + m_sParamLTRMode.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamLTRMode.eLTRMode = QOMX_VIDEO_LTRMode_Disable; + + OMX_INIT_STRUCT(&m_sParamLTRCount, QOMX_VIDEO_PARAM_LTRCOUNT_TYPE); + m_sParamLTRCount.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sParamLTRCount.nCount = 0; + + OMX_INIT_STRUCT(&m_sConfigDeinterlace, OMX_VIDEO_CONFIG_DEINTERLACE); + m_sConfigDeinterlace.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sConfigDeinterlace.nEnable = OMX_FALSE; + + OMX_INIT_STRUCT(&m_sHierLayers, QOMX_VIDEO_HIERARCHICALLAYERS); + m_sHierLayers.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sHierLayers.nNumLayers = 0; + m_sHierLayers.eHierarchicalCodingType = QOMX_HIERARCHICALCODING_P; + + OMX_INIT_STRUCT(&m_sMBIStatistics, OMX_QOMX_VIDEO_MBI_STATISTICS); + m_sMBIStatistics.nPortIndex = (OMX_U32) PORT_INDEX_OUT; + m_sMBIStatistics.eMBIStatisticsType = QOMX_MBI_STATISTICS_MODE_DEFAULT; + + OMX_INIT_STRUCT(&m_slowLatencyMode, QOMX_EXTNINDEX_VIDEO_VENC_LOW_LATENCY_MODE); + m_slowLatencyMode.bLowLatencyMode = OMX_FALSE; + + OMX_INIT_STRUCT(&m_sParamTemporalLayers, OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE); + m_sParamTemporalLayers.eSupportedPatterns = OMX_VIDEO_AndroidTemporalLayeringPatternAndroid; + + OMX_INIT_STRUCT(&m_sConfigTemporalLayers, OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE); + + m_state = OMX_StateLoaded; + m_sExtraData = 0; + + if (eRet == OMX_ErrorNone) { + if (pipe(fds)) { + DEBUG_PRINT_ERROR("ERROR: pipe creation failed"); + eRet = OMX_ErrorInsufficientResources; + } else { + if (fds[0] == 0 || fds[1] == 0) { + if (pipe(fds)) { + DEBUG_PRINT_ERROR("ERROR: pipe creation failed"); + eRet = OMX_ErrorInsufficientResources; + } + } + if (eRet == OMX_ErrorNone) { + m_pipe_in = fds[0]; + m_pipe_out = fds[1]; + } + } + msg_thread_created = true; + r = pthread_create(&msg_thread_id,0, message_thread_enc, this); + if (r < 0) { + eRet = OMX_ErrorInsufficientResources; + msg_thread_created = false; + } else { + async_thread_created = true; + r = pthread_create(&async_thread_id,0, venc_dev::async_venc_message_thread, this); + if (r < 0) { + eRet = OMX_ErrorInsufficientResources; + async_thread_created = false; + } else + dev_set_message_thread_id(async_thread_id); + } + } + + if (lowlatency) + { + QOMX_ENABLETYPE low_latency; + low_latency.bEnable = OMX_TRUE; + DEBUG_PRINT_LOW("Enable lowlatency mode"); + if (!handle->venc_set_param(&low_latency, + (OMX_INDEXTYPE)OMX_QcomIndexConfigVideoVencLowLatencyMode)) { + DEBUG_PRINT_ERROR("Failed enabling low latency mode"); + } + } + DEBUG_PRINT_INFO("Component_init : %s : return = 0x%x", m_nkind, eRet); + return eRet; +init_error: + handle->venc_close(); + delete handle; + handle = NULL; + return eRet; +} + + +/* ====================================================================== + FUNCTION + omx_venc::Setparameter + + DESCRIPTION + OMX Set Parameter method implementation. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_venc::set_parameter(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE paramIndex, + OMX_IN OMX_PTR paramData) +{ + (void)hComp; + OMX_ERRORTYPE eRet = OMX_ErrorNone; + + + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: Set Param in Invalid State"); + return OMX_ErrorInvalidState; + } + if (paramData == NULL) { + DEBUG_PRINT_ERROR("ERROR: Get Param in Invalid paramData"); + return OMX_ErrorBadParameter; + } + + /*set_parameter can be called in loaded state + or disabled port */ + if (m_state == OMX_StateLoaded + || m_sInPortDef.bEnabled == OMX_FALSE + || m_sOutPortDef.bEnabled == OMX_FALSE) { + DEBUG_PRINT_LOW("Set Parameter called in valid state"); + } else { + DEBUG_PRINT_ERROR("ERROR: Set Parameter called in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + + switch ((int)paramIndex) { + case OMX_IndexParamPortDefinition: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_PORTDEFINITIONTYPE); + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition H= %d, W = %d", + (int)portDefn->format.video.nFrameHeight, + (int)portDefn->format.video.nFrameWidth); + + if (PORT_INDEX_IN == portDefn->nPortIndex) { + if (!dev_is_video_session_supported(portDefn->format.video.nFrameWidth, + portDefn->format.video.nFrameHeight)) { + DEBUG_PRINT_ERROR("video session not supported"); + omx_report_unsupported_setting(); + return OMX_ErrorUnsupportedSetting; + } + DEBUG_PRINT_LOW("i/p actual cnt requested = %u", (unsigned int)portDefn->nBufferCountActual); + DEBUG_PRINT_LOW("i/p min cnt requested = %u", (unsigned int)portDefn->nBufferCountMin); + DEBUG_PRINT_LOW("i/p buffersize requested = %u", (unsigned int)portDefn->nBufferSize); + if (portDefn->nBufferCountActual > MAX_NUM_INPUT_BUFFERS) { + DEBUG_PRINT_ERROR("ERROR: (In_PORT) actual count (%u) exceeds max(%u)", + (unsigned int)portDefn->nBufferCountActual, (unsigned int)MAX_NUM_INPUT_BUFFERS); + return OMX_ErrorUnsupportedSetting; + } + if (m_inp_mem_ptr && + (portDefn->nBufferCountActual != m_sInPortDef.nBufferCountActual || + portDefn->nBufferSize != m_sInPortDef.nBufferSize)) { + DEBUG_PRINT_ERROR("ERROR: (In_PORT) buffer count/size can change only if port is unallocated !"); + return OMX_ErrorInvalidState; + } + if (portDefn->nBufferCountMin > portDefn->nBufferCountActual) { + DEBUG_PRINT_ERROR("ERROR: (In_PORT) Min buffers (%u) > actual count (%u)", + (unsigned int)portDefn->nBufferCountMin, (unsigned int)portDefn->nBufferCountActual); + return OMX_ErrorUnsupportedSetting; + } + if (handle->venc_set_param(paramData,OMX_IndexParamPortDefinition) != true) { + DEBUG_PRINT_ERROR("ERROR: venc_set_param input failed"); + return handle->hw_overload ? OMX_ErrorInsufficientResources : + OMX_ErrorUnsupportedSetting; + } + + DEBUG_PRINT_LOW("i/p previous actual cnt = %u", (unsigned int)m_sInPortDef.nBufferCountActual); + DEBUG_PRINT_LOW("i/p previous min cnt = %u", (unsigned int)m_sInPortDef.nBufferCountMin); + memcpy(&m_sInPortDef, portDefn,sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); + +#ifdef _ANDROID_ICS_ + if (portDefn->format.video.eColorFormat == + (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FormatAndroidOpaque) { + m_sInPortDef.format.video.eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_DEFAULT_COLOR_FMT; + if (!mUseProxyColorFormat) { + if (!c2d_conv.init()) { + DEBUG_PRINT_ERROR("C2D init failed"); + return OMX_ErrorUnsupportedSetting; + } + DEBUG_PRINT_HIGH("C2D init is successful"); + } + mUseProxyColorFormat = true; + m_input_msg_id = OMX_COMPONENT_GENERATE_ETB_OPQ; + } else + mUseProxyColorFormat = false; +#endif + /*Query Input Buffer Requirements*/ + dev_get_buf_req (&m_sInPortDef.nBufferCountMin, + &m_sInPortDef.nBufferCountActual, + &m_sInPortDef.nBufferSize, + m_sInPortDef.nPortIndex); + + /*Query ouput Buffer Requirements*/ + dev_get_buf_req (&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + m_sOutPortDef.nPortIndex); + m_sInPortDef.nBufferCountActual = portDefn->nBufferCountActual; + } else if (PORT_INDEX_OUT == portDefn->nPortIndex) { + DEBUG_PRINT_LOW("o/p actual cnt requested = %u", (unsigned int)portDefn->nBufferCountActual); + DEBUG_PRINT_LOW("o/p min cnt requested = %u", (unsigned int)portDefn->nBufferCountMin); + DEBUG_PRINT_LOW("o/p buffersize requested = %u", (unsigned int)portDefn->nBufferSize); + + if (portDefn->nBufferCountActual > MAX_NUM_OUTPUT_BUFFERS) { + DEBUG_PRINT_ERROR("ERROR: (Out_PORT) actual count (%u) exceeds max(%u)", + (unsigned int)portDefn->nBufferCountActual, (unsigned int)MAX_NUM_OUTPUT_BUFFERS); + return OMX_ErrorUnsupportedSetting; + } + if (m_out_mem_ptr && + (portDefn->nBufferCountActual != m_sOutPortDef.nBufferCountActual || + portDefn->nBufferSize != m_sOutPortDef.nBufferSize)) { + DEBUG_PRINT_ERROR("ERROR: (Out_PORT) buffer count/size can change only if port is unallocated !"); + return OMX_ErrorInvalidState; + } + + if (portDefn->nBufferCountMin > portDefn->nBufferCountActual) { + DEBUG_PRINT_ERROR("ERROR: (Out_PORT) Min buffers (%u) > actual count (%u)", + (unsigned int)portDefn->nBufferCountMin, (unsigned int)portDefn->nBufferCountActual); + return OMX_ErrorUnsupportedSetting; + } + if (handle->venc_set_param(paramData,OMX_IndexParamPortDefinition) != true) { + DEBUG_PRINT_ERROR("ERROR: venc_set_param output failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sOutPortDef,portDefn,sizeof(struct OMX_PARAM_PORTDEFINITIONTYPE)); +#ifdef _MSM8974_ + /*Query ouput Buffer Requirements*/ + dev_get_buf_req(&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + m_sOutPortDef.nPortIndex); +#endif + update_profile_level(); //framerate , bitrate + + DEBUG_PRINT_LOW("o/p previous actual cnt = %u", (unsigned int)m_sOutPortDef.nBufferCountActual); + DEBUG_PRINT_LOW("o/p previous min cnt = %u", (unsigned int)m_sOutPortDef.nBufferCountMin); + m_sOutPortDef.nBufferCountActual = portDefn->nBufferCountActual; + } else { + DEBUG_PRINT_ERROR("ERROR: Set_parameter: Bad Port idx %d", + (int)portDefn->nPortIndex); + eRet = OMX_ErrorBadPortIndex; + } + m_sConfigFramerate.xEncodeFramerate = portDefn->format.video.xFramerate; + m_sConfigBitrate.nEncodeBitrate = portDefn->format.video.nBitrate; + m_sParamBitrate.nTargetBitrate = portDefn->format.video.nBitrate; + } + break; + + case OMX_IndexParamVideoPortFormat: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_PORTFORMATTYPE); + OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoPortFormat %d", + portFmt->eColorFormat); + //set the driver with the corresponding values + if (PORT_INDEX_IN == portFmt->nPortIndex) { + if (handle->venc_set_param(paramData,OMX_IndexParamVideoPortFormat) != true) { + return OMX_ErrorUnsupportedSetting; + } + + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoPortFormat %d", + portFmt->eColorFormat); + update_profile_level(); //framerate + +#ifdef _ANDROID_ICS_ + if (portFmt->eColorFormat == + (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FormatAndroidOpaque) { + m_sInPortFormat.eColorFormat = (OMX_COLOR_FORMATTYPE) + QOMX_DEFAULT_COLOR_FMT; + if (!mUseProxyColorFormat) { + if (!c2d_conv.init()) { + DEBUG_PRINT_ERROR("C2D init failed"); + return OMX_ErrorUnsupportedSetting; + } + DEBUG_PRINT_HIGH("C2D init is successful"); + } + mUseProxyColorFormat = true; + m_input_msg_id = OMX_COMPONENT_GENERATE_ETB_OPQ; + } else +#endif + { + m_sInPortFormat.eColorFormat = portFmt->eColorFormat; + m_sInPortDef.format.video.eColorFormat = portFmt->eColorFormat; + m_input_msg_id = OMX_COMPONENT_GENERATE_ETB; + mUseProxyColorFormat = false; + } + m_sInPortFormat.xFramerate = portFmt->xFramerate; + } + //TODO if no use case for O/P port,delet m_sOutPortFormat + } + break; + case OMX_IndexParamVideoInit: + { //TODO, do we need this index set param + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PORT_PARAM_TYPE); + OMX_PORT_PARAM_TYPE* pParam = (OMX_PORT_PARAM_TYPE*)(paramData); + DEBUG_PRINT_LOW("Set OMX_IndexParamVideoInit called"); + break; + } + + case OMX_IndexParamVideoBitrate: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_BITRATETYPE); + OMX_VIDEO_PARAM_BITRATETYPE* pParam = (OMX_VIDEO_PARAM_BITRATETYPE*)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoBitrate"); + if (handle->venc_set_param(paramData,OMX_IndexParamVideoBitrate) != true) { + return OMX_ErrorUnsupportedSetting; + } + m_sParamBitrate.nTargetBitrate = pParam->nTargetBitrate; + m_sParamBitrate.eControlRate = pParam->eControlRate; + update_profile_level(); //bitrate + m_sConfigBitrate.nEncodeBitrate = pParam->nTargetBitrate; + m_sInPortDef.format.video.nBitrate = pParam->nTargetBitrate; + m_sOutPortDef.format.video.nBitrate = pParam->nTargetBitrate; + /* RC mode chan chage buffer requirements on Input port */ + dev_get_buf_req(&m_sInPortDef.nBufferCountMin, + &m_sInPortDef.nBufferCountActual, + &m_sInPortDef.nBufferSize, + m_sInPortDef.nPortIndex); + DEBUG_PRINT_LOW("bitrate = %u", (unsigned int)m_sOutPortDef.format.video.nBitrate); + break; + } + case OMX_IndexParamVideoMpeg4: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_MPEG4TYPE); + OMX_VIDEO_PARAM_MPEG4TYPE* pParam = (OMX_VIDEO_PARAM_MPEG4TYPE*)paramData; + OMX_VIDEO_PARAM_MPEG4TYPE mp4_param; + memcpy(&mp4_param, pParam, sizeof(struct OMX_VIDEO_PARAM_MPEG4TYPE)); + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoMpeg4"); + if (pParam->eProfile == OMX_VIDEO_MPEG4ProfileAdvancedSimple) { +#ifdef _MSM8974_ + if (pParam->nBFrames || bframes) + mp4_param.nBFrames = 1; + else + mp4_param.nBFrames = 0; + DEBUG_PRINT_HIGH("MPEG4: %u BFrames are being set", (unsigned int)mp4_param.nBFrames); +#endif + } else { + if (pParam->nBFrames) { + DEBUG_PRINT_ERROR("Warning: B frames not supported"); + mp4_param.nBFrames = 0; + } + } + if (handle->venc_set_param(&mp4_param,OMX_IndexParamVideoMpeg4) != true) { + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sParamMPEG4,pParam, sizeof(struct OMX_VIDEO_PARAM_MPEG4TYPE)); + m_sIntraperiod.nPFrames = m_sParamMPEG4.nPFrames; + if (pParam->nBFrames || bframes) + m_sIntraperiod.nBFrames = m_sParamMPEG4.nBFrames = mp4_param.nBFrames; + else + m_sIntraperiod.nBFrames = m_sParamMPEG4.nBFrames; + break; + } + case OMX_IndexParamVideoH263: + { + OMX_VIDEO_PARAM_H263TYPE* pParam = (OMX_VIDEO_PARAM_H263TYPE*)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoH263"); + if (handle->venc_set_param(paramData,OMX_IndexParamVideoH263) != true) { + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sParamH263,pParam, sizeof(struct OMX_VIDEO_PARAM_H263TYPE)); + m_sIntraperiod.nPFrames = m_sParamH263.nPFrames; + m_sIntraperiod.nBFrames = m_sParamH263.nBFrames; + break; + } + case OMX_IndexParamVideoAvc: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_AVCTYPE); + OMX_VIDEO_PARAM_AVCTYPE* pParam = (OMX_VIDEO_PARAM_AVCTYPE*)paramData; + OMX_VIDEO_PARAM_AVCTYPE avc_param; + memcpy(&avc_param, pParam, sizeof( struct OMX_VIDEO_PARAM_AVCTYPE)); + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoAvc"); + + avc_param.nBFrames = 0; + if ((pParam->eProfile == OMX_VIDEO_AVCProfileHigh)|| + (pParam->eProfile == OMX_VIDEO_AVCProfileMain)) { + + if (pParam->nBFrames) { + avc_param.nBFrames = pParam->nBFrames; + DEBUG_PRINT_LOW("B frames set using Client setparam to %d", + avc_param.nBFrames); + } + + if (bframes ) { + avc_param.nBFrames = bframes; + DEBUG_PRINT_LOW("B frames set using setprop to %d", + avc_param.nBFrames); + } + + DEBUG_PRINT_HIGH("AVC: BFrames: %u", (unsigned int)avc_param.nBFrames); + avc_param.bEntropyCodingCABAC = (OMX_BOOL)(avc_param.bEntropyCodingCABAC && entropy); + avc_param.nCabacInitIdc = entropy ? avc_param.nCabacInitIdc : 0; + } else { + if (pParam->nBFrames) { + DEBUG_PRINT_ERROR("Warning: B frames not supported"); + } + } + + if (handle->venc_set_param(&avc_param,OMX_IndexParamVideoAvc) != true) { + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sParamAVC,pParam, sizeof(struct OMX_VIDEO_PARAM_AVCTYPE)); + m_sIntraperiod.nPFrames = m_sParamAVC.nPFrames; + if (pParam->nBFrames || bframes) + m_sIntraperiod.nBFrames = m_sParamAVC.nBFrames = avc_param.nBFrames; + else + m_sIntraperiod.nBFrames = m_sParamAVC.nBFrames; + break; + } + case (OMX_INDEXTYPE)OMX_IndexParamVideoVp8: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_VP8TYPE); + OMX_VIDEO_PARAM_VP8TYPE* pParam = (OMX_VIDEO_PARAM_VP8TYPE*)paramData; + OMX_VIDEO_PARAM_VP8TYPE vp8_param; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoVp8"); + if (pParam->nDCTPartitions != m_sParamVP8.nDCTPartitions || + pParam->bErrorResilientMode != m_sParamVP8.bErrorResilientMode) { + DEBUG_PRINT_ERROR("VP8 doesn't support nDCTPartitions or bErrorResilientMode"); + } + memcpy(&vp8_param, pParam, sizeof( struct OMX_VIDEO_PARAM_VP8TYPE)); + if (handle->venc_set_param(&vp8_param, (OMX_INDEXTYPE)OMX_IndexParamVideoVp8) != true) { + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sParamVP8,pParam, sizeof(struct OMX_VIDEO_PARAM_VP8TYPE)); + break; + } + case (OMX_INDEXTYPE)OMX_IndexParamVideoHevc: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_HEVCTYPE); + OMX_VIDEO_PARAM_HEVCTYPE* pParam = (OMX_VIDEO_PARAM_HEVCTYPE*)paramData; + OMX_VIDEO_PARAM_HEVCTYPE hevc_param; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoHevc"); + memcpy(&hevc_param, pParam, sizeof( struct OMX_VIDEO_PARAM_HEVCTYPE)); + if (handle->venc_set_param(&hevc_param, (OMX_INDEXTYPE)OMX_IndexParamVideoHevc) != true) { + DEBUG_PRINT_ERROR("Failed : set_parameter: OMX_IndexParamVideoHevc"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sParamHEVC, pParam, sizeof(struct OMX_VIDEO_PARAM_HEVCTYPE)); + break; + } + case OMX_IndexParamVideoProfileLevelCurrent: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_PROFILELEVELTYPE); + OMX_VIDEO_PARAM_PROFILELEVELTYPE* pParam = (OMX_VIDEO_PARAM_PROFILELEVELTYPE*)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoProfileLevelCurrent"); + if (handle->venc_set_param(pParam,OMX_IndexParamVideoProfileLevelCurrent) != true) { + DEBUG_PRINT_ERROR("set_parameter: OMX_IndexParamVideoProfileLevelCurrent failed for Profile: %u " + "Level :%u", (unsigned int)pParam->eProfile, (unsigned int)pParam->eLevel); + return OMX_ErrorUnsupportedSetting; + } + m_sParamProfileLevel.eProfile = pParam->eProfile; + m_sParamProfileLevel.eLevel = pParam->eLevel; + + if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.mpeg4",\ + OMX_MAX_STRINGNAME_SIZE)) { + m_sParamMPEG4.eProfile = (OMX_VIDEO_MPEG4PROFILETYPE)m_sParamProfileLevel.eProfile; + m_sParamMPEG4.eLevel = (OMX_VIDEO_MPEG4LEVELTYPE)m_sParamProfileLevel.eLevel; + DEBUG_PRINT_LOW("MPEG4 profile = %d, level = %d", m_sParamMPEG4.eProfile, + m_sParamMPEG4.eLevel); + } else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.h263",\ + OMX_MAX_STRINGNAME_SIZE)) { + m_sParamH263.eProfile = (OMX_VIDEO_H263PROFILETYPE)m_sParamProfileLevel.eProfile; + m_sParamH263.eLevel = (OMX_VIDEO_H263LEVELTYPE)m_sParamProfileLevel.eLevel; + DEBUG_PRINT_LOW("H263 profile = %d, level = %d", m_sParamH263.eProfile, + m_sParamH263.eLevel); + } else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.avc",\ + OMX_MAX_STRINGNAME_SIZE)) { + m_sParamAVC.eProfile = (OMX_VIDEO_AVCPROFILETYPE)m_sParamProfileLevel.eProfile; + m_sParamAVC.eLevel = (OMX_VIDEO_AVCLEVELTYPE)m_sParamProfileLevel.eLevel; + DEBUG_PRINT_LOW("AVC profile = %d, level = %d", m_sParamAVC.eProfile, + m_sParamAVC.eLevel); + } else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.avc.secure",\ + OMX_MAX_STRINGNAME_SIZE)) { + m_sParamAVC.eProfile = (OMX_VIDEO_AVCPROFILETYPE)m_sParamProfileLevel.eProfile; + m_sParamAVC.eLevel = (OMX_VIDEO_AVCLEVELTYPE)m_sParamProfileLevel.eLevel; + DEBUG_PRINT_LOW("\n AVC profile = %d, level = %d", m_sParamAVC.eProfile, + m_sParamAVC.eLevel); + } + else if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.vp8",\ + OMX_MAX_STRINGNAME_SIZE)) { + m_sParamVP8.eProfile = (OMX_VIDEO_VP8PROFILETYPE)m_sParamProfileLevel.eProfile; + m_sParamVP8.eLevel = (OMX_VIDEO_VP8LEVELTYPE)m_sParamProfileLevel.eLevel; + DEBUG_PRINT_LOW("VP8 profile = %d, level = %d", m_sParamVP8.eProfile, + m_sParamVP8.eLevel); + } + else if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.hevc",\ + OMX_MAX_STRINGNAME_SIZE)) { + m_sParamHEVC.eProfile = (OMX_VIDEO_HEVCPROFILETYPE)m_sParamProfileLevel.eProfile; + m_sParamHEVC.eLevel = (OMX_VIDEO_HEVCLEVELTYPE)m_sParamProfileLevel.eLevel; + DEBUG_PRINT_LOW("HEVC profile = %d, level = %d", m_sParamHEVC.eProfile, + m_sParamHEVC.eLevel); + } + + break; + } + case OMX_IndexParamStandardComponentRole: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_COMPONENTROLETYPE); + OMX_PARAM_COMPONENTROLETYPE *comp_role; + comp_role = (OMX_PARAM_COMPONENTROLETYPE *) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamStandardComponentRole %s", + comp_role->cRole); + + if ((m_state == OMX_StateLoaded)&& + !BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING)) { + DEBUG_PRINT_LOW("Set Parameter called in valid state"); + } else { + DEBUG_PRINT_ERROR("Set Parameter called in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + + if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.avc",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((char*)comp_role->cRole,"video_encoder.avc",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_encoder.avc",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.avc.secure",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((char*)comp_role->cRole,"video_encoder.avc",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_encoder.avc",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown Index %s\n", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.mpeg4",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole,"video_encoder.mpeg4",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_encoder.mpeg4",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown Index %s", comp_role->cRole); + eRet = OMX_ErrorUnsupportedSetting; + } + } else if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.h263",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole,"video_encoder.h263",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_encoder.h263",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } +#ifdef _MSM8974_ + else if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.vp8",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole,"video_encoder.vp8",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_encoder.vp8",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown Index %s", comp_role->cRole); + eRet =OMX_ErrorUnsupportedSetting; + } + } +#endif + else if (!strncmp((char*)m_nkind, "OMX.qcom.video.encoder.hevc",OMX_MAX_STRINGNAME_SIZE)) { + if (!strncmp((const char*)comp_role->cRole,"video_encoder.hevc",OMX_MAX_STRINGNAME_SIZE)) { + strlcpy((char*)m_cRole,"video_encoder.hevc",OMX_MAX_STRINGNAME_SIZE); + } else { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown Index %s", comp_role->cRole); + eRet = OMX_ErrorUnsupportedSetting; + } + } + + else { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown param %s", m_nkind); + eRet = OMX_ErrorInvalidComponentName; + } + break; + } + + case OMX_IndexParamPriorityMgmt: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PRIORITYMGMTTYPE); + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPriorityMgmt"); + if (m_state != OMX_StateLoaded) { + DEBUG_PRINT_ERROR("ERROR: Set Parameter called in Invalid State"); + return OMX_ErrorIncorrectStateOperation; + } + OMX_PRIORITYMGMTTYPE *priorityMgmtype = (OMX_PRIORITYMGMTTYPE*) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPriorityMgmt %u", + (unsigned int)priorityMgmtype->nGroupID); + + DEBUG_PRINT_LOW("set_parameter: priorityMgmtype %u", + (unsigned int)priorityMgmtype->nGroupPriority); + + m_sPriorityMgmt.nGroupID = priorityMgmtype->nGroupID; + m_sPriorityMgmt.nGroupPriority = priorityMgmtype->nGroupPriority; + + break; + } + + case OMX_IndexParamCompBufferSupplier: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_BUFFERSUPPLIERTYPE); + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamCompBufferSupplier"); + OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamCompBufferSupplier %d", + bufferSupplierType->eBufferSupplier); + if (bufferSupplierType->nPortIndex == 0 || bufferSupplierType->nPortIndex ==1) + m_sInBufSupplier.eBufferSupplier = bufferSupplierType->eBufferSupplier; + + else + + eRet = OMX_ErrorBadPortIndex; + + break; + + } + case OMX_IndexParamVideoQuantization: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_QUANTIZATIONTYPE); + DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoQuantization"); + OMX_VIDEO_PARAM_QUANTIZATIONTYPE *session_qp = (OMX_VIDEO_PARAM_QUANTIZATIONTYPE*) paramData; + if (session_qp->nPortIndex == PORT_INDEX_OUT) { + if (handle->venc_set_param(paramData, OMX_IndexParamVideoQuantization) != true) { + return OMX_ErrorUnsupportedSetting; + } + m_sSessionQuantization.nQpI = session_qp->nQpI; + m_sSessionQuantization.nQpP = session_qp->nQpP; + m_sSessionQuantization.nQpB = session_qp->nQpB; + } else { + DEBUG_PRINT_ERROR("ERROR: Unsupported port Index for Session QP setting"); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_QcomIndexParamVideoQPRange: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_VIDEO_PARAM_QPRANGETYPE); + DEBUG_PRINT_LOW("set_parameter: OMX_QcomIndexParamVideoQPRange"); + OMX_QCOM_VIDEO_PARAM_QPRANGETYPE *qp_range = (OMX_QCOM_VIDEO_PARAM_QPRANGETYPE*) paramData; + if (qp_range->nPortIndex == PORT_INDEX_OUT) { + if (handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexParamVideoQPRange) != true) { + return OMX_ErrorUnsupportedSetting; + } + m_sSessionQPRange.minQP= qp_range->minQP; + m_sSessionQPRange.maxQP= qp_range->maxQP; + } else { + DEBUG_PRINT_ERROR("ERROR: Unsupported port Index for QP range setting"); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_QcomIndexParamVideoIPBQPRange: + { + DEBUG_PRINT_LOW("set_parameter: OMX_QCOM_VIDEO_PARAM_IPB_QPRANGETYPE"); + OMX_QCOM_VIDEO_PARAM_IPB_QPRANGETYPE *qp_range = (OMX_QCOM_VIDEO_PARAM_IPB_QPRANGETYPE*) paramData; + if (qp_range->nPortIndex == PORT_INDEX_OUT) { + if (handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexParamVideoIPBQPRange) != true) { + return OMX_ErrorUnsupportedSetting; + } + m_sSessionIPBQPRange.minIQP = qp_range->minIQP; + m_sSessionIPBQPRange.maxIQP = qp_range->maxIQP; + m_sSessionIPBQPRange.minPQP = qp_range->minPQP; + m_sSessionIPBQPRange.maxPQP = qp_range->maxPQP; + m_sSessionIPBQPRange.minBQP = qp_range->minBQP; + m_sSessionIPBQPRange.maxBQP = qp_range->maxBQP; + } else { + DEBUG_PRINT_ERROR("Unsupported port Index for IPB QP range setting"); + eRet = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_QcomIndexPortDefn: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_PARAM_PORTDEFINITIONTYPE); + OMX_QCOM_PARAM_PORTDEFINITIONTYPE* pParam = + (OMX_QCOM_PARAM_PORTDEFINITIONTYPE*)paramData; + DEBUG_PRINT_LOW("set_parameter: OMX_QcomIndexPortDefn"); + if (pParam->nPortIndex == (OMX_U32)PORT_INDEX_IN) { + if (pParam->nMemRegion > OMX_QCOM_MemRegionInvalid && + pParam->nMemRegion < OMX_QCOM_MemRegionMax) { + m_use_input_pmem = OMX_TRUE; + } else { + m_use_input_pmem = OMX_FALSE; + } + } else if (pParam->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { + if (pParam->nMemRegion > OMX_QCOM_MemRegionInvalid && + pParam->nMemRegion < OMX_QCOM_MemRegionMax) { + m_use_output_pmem = OMX_TRUE; + } else { + m_use_output_pmem = OMX_FALSE; + } + } else { + DEBUG_PRINT_ERROR("ERROR: SetParameter called on unsupported Port Index for QcomPortDefn"); + return OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_IndexParamVideoErrorCorrection: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE); + DEBUG_PRINT_LOW("OMX_IndexParamVideoErrorCorrection"); + OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE* pParam = + (OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE*)paramData; + if (!handle->venc_set_param(paramData, OMX_IndexParamVideoErrorCorrection)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting Error Resilience failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sErrorCorrection,pParam, sizeof(m_sErrorCorrection)); + break; + } + case OMX_IndexParamVideoIntraRefresh: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_INTRAREFRESHTYPE); + DEBUG_PRINT_LOW("set_param:OMX_IndexParamVideoIntraRefresh"); + OMX_VIDEO_PARAM_INTRAREFRESHTYPE* pParam = + (OMX_VIDEO_PARAM_INTRAREFRESHTYPE*)paramData; + if (!handle->venc_set_param(paramData,OMX_IndexParamVideoIntraRefresh)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting intra refresh failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sIntraRefresh, pParam, sizeof(m_sIntraRefresh)); + break; + } +#ifdef _ANDROID_ICS_ + case OMX_QcomIndexParamVideoMetaBufferMode: + { + VALIDATE_OMX_PARAM_DATA(paramData, StoreMetaDataInBuffersParams); + StoreMetaDataInBuffersParams *pParam = + (StoreMetaDataInBuffersParams*)paramData; + DEBUG_PRINT_HIGH("set_parameter:OMX_QcomIndexParamVideoMetaBufferMode: " + "port_index = %u, meta_mode = %d", (unsigned int)pParam->nPortIndex, pParam->bStoreMetaData); + if (pParam->nPortIndex == PORT_INDEX_IN) { + if (pParam->bStoreMetaData != meta_mode_enable) { + if (!handle->venc_set_meta_mode(pParam->bStoreMetaData)) { + DEBUG_PRINT_ERROR("ERROR: set Metabuffer mode %d fail", + pParam->bStoreMetaData); + return OMX_ErrorUnsupportedSetting; + } + meta_mode_enable = pParam->bStoreMetaData; + if (meta_mode_enable) { + m_sInPortDef.nBufferCountActual = m_sInPortDef.nBufferCountMin; + if (handle->venc_set_param(&m_sInPortDef,OMX_IndexParamPortDefinition) != true) { + DEBUG_PRINT_ERROR("ERROR: venc_set_param input failed"); + return OMX_ErrorUnsupportedSetting; + } + } else { + /*TODO: reset encoder driver Meta mode*/ + dev_get_buf_req (&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + m_sOutPortDef.nPortIndex); + } + } + } else if (pParam->nPortIndex == PORT_INDEX_OUT && secure_session) { + if (pParam->bStoreMetaData != meta_mode_enable) { + if (!handle->venc_set_meta_mode(pParam->bStoreMetaData)) { + DEBUG_PRINT_ERROR("\nERROR: set Metabuffer mode %d fail", + pParam->bStoreMetaData); + return OMX_ErrorUnsupportedSetting; + } + meta_mode_enable = pParam->bStoreMetaData; + } + } else { + DEBUG_PRINT_ERROR("set_parameter: metamode is " + "valid for input port only"); + eRet = OMX_ErrorUnsupportedIndex; + } + } + break; +#endif +#if !defined(MAX_RES_720P) || defined(_MSM8974_) + case OMX_QcomIndexParamIndexExtraDataType: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_INDEXEXTRADATATYPE); + DEBUG_PRINT_HIGH("set_parameter: OMX_QcomIndexParamIndexExtraDataType"); + QOMX_INDEXEXTRADATATYPE *pParam = (QOMX_INDEXEXTRADATATYPE *)paramData; + bool enable = false; + OMX_U32 mask = 0; + + if (pParam->nIndex == (OMX_INDEXTYPE)OMX_ExtraDataVideoEncoderSliceInfo) { + if (pParam->nPortIndex == PORT_INDEX_OUT) { + mask = VENC_EXTRADATA_SLICEINFO; + + DEBUG_PRINT_HIGH("SliceInfo extradata %s", + ((pParam->bEnabled == OMX_TRUE) ? "enabled" : "disabled")); + } else { + DEBUG_PRINT_ERROR("set_parameter: Slice information is " + "valid for output port only"); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + } else if (pParam->nIndex == (OMX_INDEXTYPE)OMX_ExtraDataVideoEncoderMBInfo) { + if (pParam->nPortIndex == PORT_INDEX_OUT) { + mask = VENC_EXTRADATA_MBINFO; + + DEBUG_PRINT_HIGH("MBInfo extradata %s", + ((pParam->bEnabled == OMX_TRUE) ? "enabled" : "disabled")); + } else { + DEBUG_PRINT_ERROR("set_parameter: MB information is " + "valid for output port only"); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + } else if (pParam->nIndex == (OMX_INDEXTYPE)OMX_ExtraDataFrameDimension) { + if (pParam->nPortIndex == PORT_INDEX_IN) { + mask = VENC_EXTRADATA_FRAMEDIMENSION; + DEBUG_PRINT_HIGH("Frame dimension extradata %s", + ((pParam->bEnabled == OMX_TRUE) ? "enabled" : "disabled")); + } else { + DEBUG_PRINT_ERROR("set_parameter: Frame Dimension is " + "valid for input port only"); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + } else if (pParam->nIndex == (OMX_INDEXTYPE)OMX_QTIIndexParamVQZipSEIExtraData) { + if (pParam->nPortIndex == PORT_INDEX_IN) { + mask = VENC_EXTRADATA_VQZIP; + DEBUG_PRINT_HIGH("VQZIP extradata %s", + ((pParam->bEnabled == OMX_TRUE) ? "enabled" : "disabled")); + } else { + DEBUG_PRINT_ERROR("set_parameter: VQZIP is " + "valid for input port only"); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + } + +#ifndef _MSM8974_ + else if (pParam->nIndex == (OMX_INDEXTYPE)OMX_ExtraDataVideoLTRInfo) { + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (pParam->bEnabled == OMX_TRUE) + mask = VEN_EXTRADATA_LTRINFO; + + DEBUG_PRINT_HIGH("LTRInfo extradata %s", + ((pParam->bEnabled == OMX_TRUE) ? "enabled" : "disabled")); + } else { + DEBUG_PRINT_ERROR("set_parameter: LTR information is " + "valid for output port only"); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + } +#endif + else { + DEBUG_PRINT_ERROR("set_parameter: unsupported extrdata index (%x)", + pParam->nIndex); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + + + if (pParam->bEnabled == OMX_TRUE) + m_sExtraData |= mask; + else + m_sExtraData &= ~mask; + + enable = !!(m_sExtraData & mask); + if (handle->venc_set_param(&enable, + (OMX_INDEXTYPE)pParam->nIndex) != true) { + DEBUG_PRINT_ERROR("ERROR: Setting Extradata (%x) failed", pParam->nIndex); + return OMX_ErrorUnsupportedSetting; + } + + if (pParam->nPortIndex == PORT_INDEX_IN) { + m_sInPortDef.nPortIndex = PORT_INDEX_IN; + dev_get_buf_req(&m_sInPortDef.nBufferCountMin, + &m_sInPortDef.nBufferCountActual, + &m_sInPortDef.nBufferSize, + m_sInPortDef.nPortIndex); + DEBUG_PRINT_HIGH("updated in_buf_req: buffer cnt=%u, " + "count min=%u, buffer size=%u", + (unsigned int)m_sOutPortDef.nBufferCountActual, + (unsigned int)m_sOutPortDef.nBufferCountMin, + (unsigned int)m_sOutPortDef.nBufferSize); + + } else { + m_sOutPortDef.nPortIndex = PORT_INDEX_OUT; + dev_get_buf_req(&m_sOutPortDef.nBufferCountMin, + &m_sOutPortDef.nBufferCountActual, + &m_sOutPortDef.nBufferSize, + m_sOutPortDef.nPortIndex); + DEBUG_PRINT_HIGH("updated out_buf_req: buffer cnt=%u, " + "count min=%u, buffer size=%u", + (unsigned int)m_sOutPortDef.nBufferCountActual, + (unsigned int)m_sOutPortDef.nBufferCountMin, + (unsigned int)m_sOutPortDef.nBufferSize); + } + break; + } + case QOMX_IndexParamVideoLTRMode: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_VIDEO_PARAM_LTRMODE_TYPE); + QOMX_VIDEO_PARAM_LTRMODE_TYPE* pParam = + (QOMX_VIDEO_PARAM_LTRMODE_TYPE*)paramData; + if (!handle->venc_set_param(paramData, (OMX_INDEXTYPE)QOMX_IndexParamVideoLTRMode)) { + DEBUG_PRINT_ERROR("ERROR: Setting LTR mode failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sParamLTRMode, pParam, sizeof(m_sParamLTRMode)); + break; + } + case QOMX_IndexParamVideoLTRCount: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_VIDEO_PARAM_LTRCOUNT_TYPE); + QOMX_VIDEO_PARAM_LTRCOUNT_TYPE* pParam = + (QOMX_VIDEO_PARAM_LTRCOUNT_TYPE*)paramData; + if (!handle->venc_set_param(paramData, (OMX_INDEXTYPE)QOMX_IndexParamVideoLTRCount)) { + DEBUG_PRINT_ERROR("ERROR: Setting LTR count failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sParamLTRCount, pParam, sizeof(m_sParamLTRCount)); + break; + } +#endif + case OMX_QcomIndexParamVideoMaxAllowedBitrateCheck: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_EXTNINDEX_PARAMTYPE); + QOMX_EXTNINDEX_PARAMTYPE* pParam = + (QOMX_EXTNINDEX_PARAMTYPE*)paramData; + if (pParam->nPortIndex == PORT_INDEX_OUT) { + handle->m_max_allowed_bitrate_check = + ((pParam->bEnable == OMX_TRUE) ? true : false); + DEBUG_PRINT_HIGH("set_parameter: max allowed bitrate check %s", + ((pParam->bEnable == OMX_TRUE) ? "enabled" : "disabled")); + } else { + DEBUG_PRINT_ERROR("ERROR: OMX_QcomIndexParamVideoMaxAllowedBitrateCheck " + " called on wrong port(%u)", (unsigned int)pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + break; + } +#ifdef MAX_RES_1080P + case OMX_QcomIndexEnableSliceDeliveryMode: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_EXTNINDEX_PARAMTYPE); + QOMX_EXTNINDEX_PARAMTYPE* pParam = + (QOMX_EXTNINDEX_PARAMTYPE*)paramData; + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexEnableSliceDeliveryMode)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting slice delivery mode failed"); + return OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_ERROR("ERROR: OMX_QcomIndexEnableSliceDeliveryMode " + "called on wrong port(%u)", (unsigned int)pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + break; + } +#endif + case OMX_QcomIndexEnableH263PlusPType: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_EXTNINDEX_PARAMTYPE); + QOMX_EXTNINDEX_PARAMTYPE* pParam = + (QOMX_EXTNINDEX_PARAMTYPE*)paramData; + DEBUG_PRINT_LOW("OMX_QcomIndexEnableH263PlusPType"); + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexEnableH263PlusPType)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting PlusPType failed"); + return OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_ERROR("ERROR: OMX_QcomIndexEnableH263PlusPType " + "called on wrong port(%u)", (unsigned int)pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + break; + } + case OMX_QcomIndexParamSequenceHeaderWithIDR: + { + VALIDATE_OMX_PARAM_DATA(paramData, PrependSPSPPSToIDRFramesParams); + if(!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexParamSequenceHeaderWithIDR)) { + DEBUG_PRINT_ERROR("%s: %s", + "OMX_QComIndexParamSequenceHeaderWithIDR:", + "request for inband sps/pps failed."); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sPrependSPSPPS, paramData, sizeof(m_sPrependSPSPPS)); + break; + } + case OMX_QcomIndexParamH264AUDelimiter: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_VIDEO_CONFIG_H264_AUD); + if(!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexParamH264AUDelimiter)) { + DEBUG_PRINT_ERROR("%s: %s", + "OMX_QComIndexParamh264AUDelimiter:", + "request for AU Delimiters failed."); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QcomIndexParamMBIStatisticsMode: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QOMX_VIDEO_MBI_STATISTICS); + if(!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexParamMBIStatisticsMode)) { + DEBUG_PRINT_ERROR("%s: %s", + "OMX_QcomIndexParamMBIStatisticsMode:", + "MBI Statistics mode setting failed."); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QcomIndexHierarchicalStructure: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_VIDEO_HIERARCHICALLAYERS); + QOMX_VIDEO_HIERARCHICALLAYERS* pParam = + (QOMX_VIDEO_HIERARCHICALLAYERS*)paramData; + DEBUG_PRINT_LOW("OMX_QcomIndexHierarchicalStructure"); + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexHierarchicalStructure)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting PlusPType failed"); + return OMX_ErrorUnsupportedSetting; + } + if((pParam->eHierarchicalCodingType == QOMX_HIERARCHICALCODING_B) && pParam->nNumLayers) + hier_b_enabled = true; + m_sHierLayers.nNumLayers = pParam->nNumLayers; + m_sHierLayers.eHierarchicalCodingType = pParam->eHierarchicalCodingType; + } else { + DEBUG_PRINT_ERROR("ERROR: OMX_QcomIndexHierarchicalStructure called on wrong port(%u)", + (unsigned int)pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + break; + + } + case OMX_QcomIndexParamPerfLevel: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_VIDEO_PARAM_PERF_LEVEL); + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE) OMX_QcomIndexParamPerfLevel)) { + DEBUG_PRINT_ERROR("ERROR: Setting performance level"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QcomIndexParamH264VUITimingInfo: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_VIDEO_PARAM_VUI_TIMING_INFO); + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE) OMX_QcomIndexParamH264VUITimingInfo)) { + DEBUG_PRINT_ERROR("ERROR: Setting VUI timing info"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QcomIndexParamPeakBitrate: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QCOM_VIDEO_PARAM_PEAK_BITRATE); + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE) OMX_QcomIndexParamPeakBitrate)) { + DEBUG_PRINT_ERROR("ERROR: Setting peak bitrate"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case QOMX_IndexParamVideoInitialQp: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_EXTNINDEX_VIDEO_INITIALQP); + if(!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)QOMX_IndexParamVideoInitialQp)) { + DEBUG_PRINT_ERROR("Request to Enable initial QP failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sParamInitqp, paramData, sizeof(m_sParamInitqp)); + break; + } + case OMX_QcomIndexParamSetMVSearchrange: + { + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE) OMX_QcomIndexParamSetMVSearchrange)) { + DEBUG_PRINT_ERROR("ERROR: Setting Searchrange"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QcomIndexParamVideoHybridHierpMode: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_EXTNINDEX_VIDEO_HYBRID_HP_MODE); + if(!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexParamVideoHybridHierpMode)) { + DEBUG_PRINT_ERROR("Request to Enable Hybrid Hier-P failed"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QcomIndexParamBatchSize: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_PARAM_U32TYPE); + if(!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexParamBatchSize)) { + DEBUG_PRINT_ERROR("Attempting to set batch size failed"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QcomIndexConfigH264EntropyCodingCabac: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_VIDEO_H264ENTROPYCODINGTYPE); + if(!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexConfigH264EntropyCodingCabac)) { + DEBUG_PRINT_ERROR("Attempting to set Entropy failed"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QTIIndexParamVQZIPSEIType: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_QTI_VIDEO_PARAM_VQZIP_SEI_TYPE); + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE) OMX_QTIIndexParamVQZIPSEIType)) { + DEBUG_PRINT_ERROR("ERROR: Setting VQZIP SEI type"); + return OMX_ErrorUnsupportedSetting; + } + m_sExtraData |= VENC_EXTRADATA_VQZIP; + break; + } + case OMX_QcomIndexParamVencAspectRatio: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_EXTNINDEX_VIDEO_VENC_SAR); + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexParamVencAspectRatio)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_QcomIndexParamVencAspectRatio failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sSar, paramData, sizeof(m_sSar)); + break; + } + case OMX_QTIIndexParamLowLatencyMode: + { + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QTIIndexParamLowLatencyMode)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_QTIIndexParamLowLatencyMode failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_slowLatencyMode, paramData, sizeof(m_slowLatencyMode)); + break; + } + case OMX_QcomIndexConfigVideoVencLowLatencyMode: + { + if(!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QcomIndexConfigVideoVencLowLatencyMode)) { + DEBUG_PRINT_ERROR("Request to Enable Low latency mode failed"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QTIIndexParamVideoEnableRoiInfo: + { + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QTIIndexParamVideoEnableRoiInfo)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_QTIIndexParamVideoEnableRoiInfo failed"); + return OMX_ErrorUnsupportedSetting; + } + m_sExtraData |= VENC_EXTRADATA_ROI; + break; + } + case OMX_IndexParamAndroidVideoTemporalLayering: + { + VALIDATE_OMX_PARAM_DATA(paramData, OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE); + if (!handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_IndexParamAndroidVideoTemporalLayering)) { + DEBUG_PRINT_ERROR("Failed to configure temporal layers"); + return OMX_ErrorUnsupportedSetting; + } + // save the actual configuration applied + memcpy(&m_sParamTemporalLayers, paramData, sizeof(m_sParamTemporalLayers)); + // keep the config data in sync + m_sConfigTemporalLayers.ePattern = m_sParamTemporalLayers.ePattern; + m_sConfigTemporalLayers.nBLayerCountActual = m_sParamTemporalLayers.nBLayerCountActual; + m_sConfigTemporalLayers.nPLayerCountActual = m_sParamTemporalLayers.nPLayerCountActual; + m_sConfigTemporalLayers.bBitrateRatiosSpecified = m_sParamTemporalLayers.bBitrateRatiosSpecified; + memcpy(&m_sConfigTemporalLayers.nBitrateRatios[0], + &m_sParamTemporalLayers.nBitrateRatios[0], + OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS * sizeof(OMX_U32)); + break; + } + case OMX_QTIIndexParamDisablePQ: + { + VALIDATE_OMX_PARAM_DATA(paramData, QOMX_DISABLETYPE); + handle->venc_set_param(paramData, + (OMX_INDEXTYPE)OMX_QTIIndexParamDisablePQ); + break; + } + case OMX_IndexParamVideoSliceFMO: + default: + { + DEBUG_PRINT_ERROR("ERROR: Setparameter: unknown param %d", paramIndex); + eRet = OMX_ErrorUnsupportedIndex; + break; + } + } + return eRet; +} + +bool omx_venc::update_profile_level() +{ + OMX_U32 eProfile, eLevel; + + if (!handle->venc_get_profile_level(&eProfile,&eLevel)) { + DEBUG_PRINT_ERROR("Failed to update the profile_level"); + return false; + } + + m_sParamProfileLevel.eProfile = (OMX_VIDEO_MPEG4PROFILETYPE)eProfile; + m_sParamProfileLevel.eLevel = (OMX_VIDEO_MPEG4LEVELTYPE)eLevel; + + if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.mpeg4",\ + OMX_MAX_STRINGNAME_SIZE)) { + m_sParamMPEG4.eProfile = (OMX_VIDEO_MPEG4PROFILETYPE)eProfile; + m_sParamMPEG4.eLevel = (OMX_VIDEO_MPEG4LEVELTYPE)eLevel; + DEBUG_PRINT_LOW("MPEG4 profile = %d, level = %d", m_sParamMPEG4.eProfile, + m_sParamMPEG4.eLevel); + } else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.h263",\ + OMX_MAX_STRINGNAME_SIZE)) { + m_sParamH263.eProfile = (OMX_VIDEO_H263PROFILETYPE)eProfile; + m_sParamH263.eLevel = (OMX_VIDEO_H263LEVELTYPE)eLevel; + DEBUG_PRINT_LOW("H263 profile = %d, level = %d", m_sParamH263.eProfile, + m_sParamH263.eLevel); + } else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.avc",\ + OMX_MAX_STRINGNAME_SIZE)) { + m_sParamAVC.eProfile = (OMX_VIDEO_AVCPROFILETYPE)eProfile; + m_sParamAVC.eLevel = (OMX_VIDEO_AVCLEVELTYPE)eLevel; + DEBUG_PRINT_LOW("AVC profile = %d, level = %d", m_sParamAVC.eProfile, + m_sParamAVC.eLevel); + } else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.avc.secure",\ + OMX_MAX_STRINGNAME_SIZE)) { + m_sParamAVC.eProfile = (OMX_VIDEO_AVCPROFILETYPE)eProfile; + m_sParamAVC.eLevel = (OMX_VIDEO_AVCLEVELTYPE)eLevel; + DEBUG_PRINT_LOW("\n AVC profile = %d, level = %d", m_sParamAVC.eProfile, + m_sParamAVC.eLevel); + } + else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.vp8",\ + OMX_MAX_STRINGNAME_SIZE)) { + m_sParamVP8.eProfile = (OMX_VIDEO_VP8PROFILETYPE)eProfile; + m_sParamVP8.eLevel = (OMX_VIDEO_VP8LEVELTYPE)eLevel; + DEBUG_PRINT_LOW("VP8 profile = %d, level = %d", m_sParamVP8.eProfile, + m_sParamVP8.eLevel); + } + else if (!strncmp((char *)m_nkind, "OMX.qcom.video.encoder.hevc",\ + OMX_MAX_STRINGNAME_SIZE)) { + m_sParamHEVC.eProfile = (OMX_VIDEO_HEVCPROFILETYPE)eProfile; + m_sParamHEVC.eLevel = (OMX_VIDEO_HEVCLEVELTYPE)eLevel; + DEBUG_PRINT_LOW("HEVC profile = %d, level = %d", m_sParamHEVC.eProfile, + m_sParamHEVC.eLevel); + } + + return true; +} +/* ====================================================================== + FUNCTION + omx_video::SetConfig + + DESCRIPTION + OMX Set Config method implementation + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if successful. + ========================================================================== */ +OMX_ERRORTYPE omx_venc::set_config(OMX_IN OMX_HANDLETYPE hComp, + OMX_IN OMX_INDEXTYPE configIndex, + OMX_IN OMX_PTR configData) +{ + (void)hComp; + if (configData == NULL) { + DEBUG_PRINT_ERROR("ERROR: param is null"); + return OMX_ErrorBadParameter; + } + + if (m_state == OMX_StateInvalid) { + DEBUG_PRINT_ERROR("ERROR: config called in Invalid state"); + return OMX_ErrorIncorrectStateOperation; + } + + // params will be validated prior to venc_init + switch ((int)configIndex) { + case OMX_IndexConfigVideoBitrate: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_BITRATETYPE); + OMX_VIDEO_CONFIG_BITRATETYPE* pParam = + reinterpret_cast<OMX_VIDEO_CONFIG_BITRATETYPE*>(configData); + DEBUG_PRINT_HIGH("set_config(): OMX_IndexConfigVideoBitrate (%u)", (unsigned int)pParam->nEncodeBitrate); + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (handle->venc_set_config(configData, OMX_IndexConfigVideoBitrate) != true) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_IndexConfigVideoBitrate failed"); + return OMX_ErrorUnsupportedSetting; + } + + m_sConfigBitrate.nEncodeBitrate = pParam->nEncodeBitrate; + m_sParamBitrate.nTargetBitrate = pParam->nEncodeBitrate; + m_sOutPortDef.format.video.nBitrate = pParam->nEncodeBitrate; + } else { + DEBUG_PRINT_ERROR("ERROR: Unsupported port index: %u", (unsigned int)pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + break; + } + case OMX_IndexConfigVideoFramerate: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_CONFIG_FRAMERATETYPE); + OMX_CONFIG_FRAMERATETYPE* pParam = + reinterpret_cast<OMX_CONFIG_FRAMERATETYPE*>(configData); + DEBUG_PRINT_HIGH("set_config(): OMX_IndexConfigVideoFramerate (0x%x)", (unsigned int)pParam->xEncodeFramerate); + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (handle->venc_set_config(configData, OMX_IndexConfigVideoFramerate) != true) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_IndexConfigVideoFramerate failed"); + return OMX_ErrorUnsupportedSetting; + } + + m_sConfigFramerate.xEncodeFramerate = pParam->xEncodeFramerate; + m_sOutPortDef.format.video.xFramerate = pParam->xEncodeFramerate; + m_sOutPortFormat.xFramerate = pParam->xEncodeFramerate; + /* + * Frame rate can change buffer requirements. If query is not allowed, + * failure is not FATAL here. + */ + dev_get_buf_req(&m_sInPortDef.nBufferCountMin, + &m_sInPortDef.nBufferCountActual, + &m_sInPortDef.nBufferSize, + m_sInPortDef.nPortIndex); + } else { + DEBUG_PRINT_ERROR("ERROR: Unsupported port index: %u", (unsigned int)pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + case QOMX_IndexConfigVideoIntraperiod: + { + VALIDATE_OMX_PARAM_DATA(configData, QOMX_VIDEO_INTRAPERIODTYPE); + QOMX_VIDEO_INTRAPERIODTYPE* pParam = + reinterpret_cast<QOMX_VIDEO_INTRAPERIODTYPE*>(configData); + + DEBUG_PRINT_HIGH("set_config(): QOMX_IndexConfigVideoIntraperiod"); + if (pParam->nPortIndex == PORT_INDEX_OUT) { +#ifdef MAX_RES_720P + if (pParam->nBFrames > 0) { + DEBUG_PRINT_ERROR("B frames not supported"); + return OMX_ErrorUnsupportedSetting; + } +#endif + DEBUG_PRINT_HIGH("Old: P/B frames = %u/%u, New: P/B frames = %u/%u", + (unsigned int)m_sIntraperiod.nPFrames, (unsigned int)m_sIntraperiod.nBFrames, + (unsigned int)pParam->nPFrames, (unsigned int)pParam->nBFrames); + if (m_sIntraperiod.nBFrames != pParam->nBFrames) { + if(hier_b_enabled && m_state == OMX_StateLoaded) { + DEBUG_PRINT_INFO("B-frames setting is supported if HierB is enabled"); + } + } + if (handle->venc_set_config(configData, (OMX_INDEXTYPE) QOMX_IndexConfigVideoIntraperiod) != true) { + DEBUG_PRINT_ERROR("ERROR: Setting QOMX_IndexConfigVideoIntraperiod failed"); + return OMX_ErrorUnsupportedSetting; + } + m_sIntraperiod.nPFrames = pParam->nPFrames; + m_sIntraperiod.nBFrames = pParam->nBFrames; + m_sIntraperiod.nIDRPeriod = pParam->nIDRPeriod; + + if (m_sOutPortFormat.eCompressionFormat == OMX_VIDEO_CodingMPEG4) { + m_sParamMPEG4.nPFrames = pParam->nPFrames; + if (m_sParamMPEG4.eProfile != OMX_VIDEO_MPEG4ProfileSimple) + m_sParamMPEG4.nBFrames = pParam->nBFrames; + else + m_sParamMPEG4.nBFrames = 0; + } else if (m_sOutPortFormat.eCompressionFormat == OMX_VIDEO_CodingH263) { + m_sParamH263.nPFrames = pParam->nPFrames; + } else { + m_sParamAVC.nPFrames = pParam->nPFrames; + if ((m_sParamAVC.eProfile != OMX_VIDEO_AVCProfileBaseline) && + (m_sParamAVC.eProfile != (OMX_VIDEO_AVCPROFILETYPE) QOMX_VIDEO_AVCProfileConstrainedBaseline)) + m_sParamAVC.nBFrames = pParam->nBFrames; + else + m_sParamAVC.nBFrames = 0; + } + } else { + DEBUG_PRINT_ERROR("ERROR: (QOMX_IndexConfigVideoIntraperiod) Unsupported port index: %u", (unsigned int)pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + + case OMX_IndexConfigVideoIntraVOPRefresh: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_CONFIG_INTRAREFRESHVOPTYPE); + OMX_CONFIG_INTRAREFRESHVOPTYPE* pParam = + reinterpret_cast<OMX_CONFIG_INTRAREFRESHVOPTYPE*>(configData); + + DEBUG_PRINT_HIGH("set_config(): OMX_IndexConfigVideoIntraVOPRefresh"); + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (handle->venc_set_config(configData, + OMX_IndexConfigVideoIntraVOPRefresh) != true) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_IndexConfigVideoIntraVOPRefresh failed"); + return OMX_ErrorUnsupportedSetting; + } + + m_sConfigIntraRefreshVOP.IntraRefreshVOP = pParam->IntraRefreshVOP; + } else { + DEBUG_PRINT_ERROR("ERROR: Unsupported port index: %u", (unsigned int)pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + case OMX_IndexConfigCommonRotate: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_CONFIG_ROTATIONTYPE); + OMX_CONFIG_ROTATIONTYPE *pParam = + reinterpret_cast<OMX_CONFIG_ROTATIONTYPE*>(configData); + OMX_S32 nRotation; + + if (pParam->nPortIndex != PORT_INDEX_OUT) { + DEBUG_PRINT_ERROR("ERROR: Unsupported port index: %u", (unsigned int)pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + if ( pParam->nRotation == 0 || + pParam->nRotation == 90 || + pParam->nRotation == 180 || + pParam->nRotation == 270 ) { + DEBUG_PRINT_HIGH("set_config: Rotation Angle %u", (unsigned int)pParam->nRotation); + } else { + DEBUG_PRINT_ERROR("ERROR: un supported Rotation %u", (unsigned int)pParam->nRotation); + return OMX_ErrorUnsupportedSetting; + } + nRotation = pParam->nRotation - m_sConfigFrameRotation.nRotation; + if (nRotation < 0) + nRotation = -nRotation; + + DEBUG_PRINT_HIGH("set_config: updating device Dims"); + + if (handle->venc_set_config(configData, + OMX_IndexConfigCommonRotate) != true) { + DEBUG_PRINT_ERROR("ERROR: Set OMX_IndexConfigCommonRotate failed"); + return OMX_ErrorUnsupportedSetting; + } + m_sConfigFrameRotation.nRotation = pParam->nRotation; + break; + } + case OMX_QcomIndexConfigVideoFramePackingArrangement: + { + DEBUG_PRINT_HIGH("set_config(): OMX_QcomIndexConfigVideoFramePackingArrangement"); + if (m_sOutPortFormat.eCompressionFormat == OMX_VIDEO_CodingAVC) { + VALIDATE_OMX_PARAM_DATA(configData, OMX_QCOM_FRAME_PACK_ARRANGEMENT); + OMX_QCOM_FRAME_PACK_ARRANGEMENT *configFmt = + (OMX_QCOM_FRAME_PACK_ARRANGEMENT *) configData; + extra_data_handle.set_frame_pack_data(configFmt); + } else { + DEBUG_PRINT_ERROR("ERROR: FramePackingData not supported for non AVC compression"); + } + break; + } + case QOMX_IndexConfigVideoLTRPeriod: + { + VALIDATE_OMX_PARAM_DATA(configData, QOMX_VIDEO_CONFIG_LTRPERIOD_TYPE); + QOMX_VIDEO_CONFIG_LTRPERIOD_TYPE* pParam = (QOMX_VIDEO_CONFIG_LTRPERIOD_TYPE*)configData; + if (!handle->venc_set_config(configData, (OMX_INDEXTYPE)QOMX_IndexConfigVideoLTRPeriod)) { + DEBUG_PRINT_ERROR("ERROR: Setting LTR period failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sConfigLTRPeriod, pParam, sizeof(m_sConfigLTRPeriod)); + break; + } + + case OMX_IndexConfigVideoVp8ReferenceFrame: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_VP8REFERENCEFRAMETYPE); + OMX_VIDEO_VP8REFERENCEFRAMETYPE* pParam = (OMX_VIDEO_VP8REFERENCEFRAMETYPE*) configData; + if (!handle->venc_set_config(pParam, (OMX_INDEXTYPE) OMX_IndexConfigVideoVp8ReferenceFrame)) { + DEBUG_PRINT_ERROR("ERROR: Setting VP8 reference frame"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sConfigVp8ReferenceFrame, pParam, sizeof(m_sConfigVp8ReferenceFrame)); + break; + } + + case QOMX_IndexConfigVideoLTRUse: + { + VALIDATE_OMX_PARAM_DATA(configData, QOMX_VIDEO_CONFIG_LTRUSE_TYPE); + QOMX_VIDEO_CONFIG_LTRUSE_TYPE* pParam = (QOMX_VIDEO_CONFIG_LTRUSE_TYPE*)configData; + if (!handle->venc_set_config(pParam, (OMX_INDEXTYPE)QOMX_IndexConfigVideoLTRUse)) { + DEBUG_PRINT_ERROR("ERROR: Setting LTR use failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sConfigLTRUse, pParam, sizeof(m_sConfigLTRUse)); + break; + } + case QOMX_IndexConfigVideoLTRMark: + { + VALIDATE_OMX_PARAM_DATA(configData, QOMX_VIDEO_CONFIG_LTRMARK_TYPE); + QOMX_VIDEO_CONFIG_LTRMARK_TYPE* pParam = (QOMX_VIDEO_CONFIG_LTRMARK_TYPE*)configData; + if (!handle->venc_set_config(pParam, (OMX_INDEXTYPE)QOMX_IndexConfigVideoLTRMark)) { + DEBUG_PRINT_ERROR("ERROR: Setting LTR mark failed"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_IndexConfigVideoAVCIntraPeriod: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_AVCINTRAPERIOD); + OMX_VIDEO_CONFIG_AVCINTRAPERIOD *pParam = (OMX_VIDEO_CONFIG_AVCINTRAPERIOD*) configData; + DEBUG_PRINT_LOW("set_config: OMX_IndexConfigVideoAVCIntraPeriod"); + if (!handle->venc_set_config(pParam, (OMX_INDEXTYPE)OMX_IndexConfigVideoAVCIntraPeriod)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_IndexConfigVideoAVCIntraPeriod failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sConfigAVCIDRPeriod, pParam, sizeof(m_sConfigAVCIDRPeriod)); + break; + } + case OMX_IndexConfigCommonDeinterlace: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_DEINTERLACE); + OMX_VIDEO_CONFIG_DEINTERLACE *pParam = (OMX_VIDEO_CONFIG_DEINTERLACE*) configData; + DEBUG_PRINT_LOW("set_config: OMX_IndexConfigCommonDeinterlace"); + if (!handle->venc_set_config(pParam, (OMX_INDEXTYPE)OMX_IndexConfigCommonDeinterlace)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_IndexConfigCommonDeinterlace failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sConfigDeinterlace, pParam, sizeof(m_sConfigDeinterlace)); + break; + } + case OMX_QcomIndexConfigVideoVencPerfMode: + { + VALIDATE_OMX_PARAM_DATA(configData, QOMX_EXTNINDEX_VIDEO_PERFMODE); + QOMX_EXTNINDEX_VIDEO_PERFMODE* pParam = (QOMX_EXTNINDEX_VIDEO_PERFMODE*)configData; + if (!handle->venc_set_config(pParam, (OMX_INDEXTYPE)OMX_QcomIndexConfigVideoVencPerfMode)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_QcomIndexConfigVideoVencPerfMode failed"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QcomIndexConfigNumHierPLayers: + { + VALIDATE_OMX_PARAM_DATA(configData, QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS); + QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS* pParam = + (QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS*)configData; + if (!handle->venc_set_config(pParam, (OMX_INDEXTYPE)OMX_QcomIndexConfigNumHierPLayers)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_QcomIndexConfigNumHierPLayers failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sHPlayers, pParam, sizeof(m_sHPlayers)); + break; + } + case OMX_QcomIndexConfigBaseLayerId: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_SKYPE_VIDEO_CONFIG_BASELAYERPID); + OMX_SKYPE_VIDEO_CONFIG_BASELAYERPID* pParam = + (OMX_SKYPE_VIDEO_CONFIG_BASELAYERPID*) configData; + if (!handle->venc_set_config(pParam, (OMX_INDEXTYPE)OMX_QcomIndexConfigBaseLayerId)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_QcomIndexConfigBaseLayerId failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sBaseLayerID, pParam, sizeof(m_sBaseLayerID)); + break; + } + case OMX_QcomIndexConfigQp: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_SKYPE_VIDEO_CONFIG_QP); + OMX_SKYPE_VIDEO_CONFIG_QP* pParam = + (OMX_SKYPE_VIDEO_CONFIG_QP*) configData; + if (!handle->venc_set_config(pParam, (OMX_INDEXTYPE)OMX_QcomIndexConfigQp)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_QcomIndexConfigQp failed"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sConfigQP, pParam, sizeof(m_sConfigQP)); + break; + } + case OMX_IndexConfigPriority: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_PARAM_U32TYPE); + if (!handle->venc_set_config(configData, (OMX_INDEXTYPE)OMX_IndexConfigPriority)) { + DEBUG_PRINT_ERROR("Failed to set OMX_IndexConfigPriority"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_IndexConfigOperatingRate: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_PARAM_U32TYPE); + if (!handle->venc_set_config(configData, (OMX_INDEXTYPE)OMX_IndexConfigOperatingRate)) { + DEBUG_PRINT_ERROR("Failed to set OMX_IndexConfigOperatingRate"); + return handle->hw_overload ? OMX_ErrorInsufficientResources : + OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QTIIndexConfigVideoRoiInfo: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_QTI_VIDEO_CONFIG_ROIINFO); + if (!handle->venc_set_config(configData, (OMX_INDEXTYPE)OMX_QTIIndexConfigVideoRoiInfo)) { + DEBUG_PRINT_ERROR("Failed to set OMX_QTIIndexConfigVideoRoiInfo"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_IndexConfigTimePosition: + { + OMX_TIME_CONFIG_TIMESTAMPTYPE* pParam = + (OMX_TIME_CONFIG_TIMESTAMPTYPE*) configData; + pthread_mutex_lock(×tamp.m_lock); + timestamp.m_TimeStamp = (OMX_U64)pParam->nTimestamp; + DEBUG_PRINT_LOW("Buffer = %p, Timestamp = %llu", timestamp.pending_buffer, (OMX_U64)pParam->nTimestamp); + if (timestamp.is_buffer_pending && (OMX_U64)timestamp.pending_buffer->nTimeStamp == timestamp.m_TimeStamp) { + DEBUG_PRINT_INFO("Queueing back pending buffer %p", timestamp.pending_buffer); + this->post_event((unsigned long)hComp,(unsigned long)timestamp.pending_buffer,m_input_msg_id); + timestamp.pending_buffer = NULL; + timestamp.is_buffer_pending = false; + } + pthread_mutex_unlock(×tamp.m_lock); + break; + } +#ifdef SUPPORT_CONFIG_INTRA_REFRESH + case OMX_IndexConfigAndroidIntraRefresh: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE); + OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE* pParam = + (OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE*) configData; + if (m_state == OMX_StateLoaded + || m_sInPortDef.bEnabled == OMX_FALSE + || m_sOutPortDef.bEnabled == OMX_FALSE) { + if (!handle->venc_set_config(configData, (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh)) { + DEBUG_PRINT_ERROR("Failed to set OMX_IndexConfigVideoIntraRefreshType"); + return OMX_ErrorUnsupportedSetting; + } + m_sConfigIntraRefresh.nRefreshPeriod = pParam->nRefreshPeriod; + } else { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_IndexConfigAndroidIntraRefresh supported only at start of session"); + return OMX_ErrorUnsupportedSetting; + } + break; + } +#endif + case OMX_QTIIndexConfigVideoBlurResolution: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_QTI_VIDEO_CONFIG_BLURINFO); + OMX_QTI_VIDEO_CONFIG_BLURINFO* pParam = + (OMX_QTI_VIDEO_CONFIG_BLURINFO*) configData; + if (!handle->venc_set_config(configData, (OMX_INDEXTYPE)OMX_QTIIndexConfigVideoBlurResolution)) { + DEBUG_PRINT_ERROR("Failed to set OMX_QTIIndexConfigVideoBlurResolution"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_blurInfo, pParam, sizeof(m_blurInfo)); + break; + } + case OMX_QcomIndexConfigH264Transform8x8: + { + if (!handle->venc_set_config(configData, (OMX_INDEXTYPE)OMX_QcomIndexConfigH264Transform8x8)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_QcomIndexConfigH264Transform8x8 failed"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QTIIndexConfigDescribeColorAspects: + { + VALIDATE_OMX_PARAM_DATA(configData, DescribeColorAspectsParams); + DescribeColorAspectsParams *params = (DescribeColorAspectsParams *)configData; + print_debug_color_aspects(&(params->sAspects), "set_config"); + if (!handle->venc_set_config(configData, (OMX_INDEXTYPE)OMX_QTIIndexConfigDescribeColorAspects)) { + DEBUG_PRINT_ERROR("Failed to set OMX_QTIIndexConfigDescribeColorAspects"); + return OMX_ErrorUnsupportedSetting; + } + memcpy(&m_sConfigColorAspects, configData, sizeof(m_sConfigColorAspects)); + break; + } + case OMX_IndexConfigAndroidVideoTemporalLayering: + { + VALIDATE_OMX_PARAM_DATA(configData, OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE); + DEBUG_PRINT_ERROR("Setting/modifying Temporal layers at run-time is not supported !"); + return OMX_ErrorUnsupportedSetting; + } + default: + DEBUG_PRINT_ERROR("ERROR: unsupported index %d", (int) configIndex); + break; + } + + return OMX_ErrorNone; +} + +/* ====================================================================== + FUNCTION + omx_venc::ComponentDeInit + + DESCRIPTION + Destroys the component and release memory allocated to the heap. + + PARAMETERS + <TBD>. + + RETURN VALUE + OMX Error None if everything successful. + + ========================================================================== */ +OMX_ERRORTYPE omx_venc::component_deinit(OMX_IN OMX_HANDLETYPE hComp) +{ + (void) hComp; + OMX_U32 i = 0; + DEBUG_PRINT_HIGH("omx_venc(): Inside component_deinit()"); + if (OMX_StateLoaded != m_state) { + DEBUG_PRINT_ERROR("WARNING:Rxd DeInit,OMX not in LOADED state %d",\ + m_state); + } + if (m_out_mem_ptr) { + DEBUG_PRINT_LOW("Freeing the Output Memory"); + for (i=0; i< m_sOutPortDef.nBufferCountActual; i++ ) { + if (BITMASK_PRESENT(&m_out_bm_count, i)) { + BITMASK_CLEAR(&m_out_bm_count, i); + free_output_buffer (&m_out_mem_ptr[i]); + } + + if (release_output_done()) { + break; + } + } + free(m_out_mem_ptr); + m_out_mem_ptr = NULL; + } + + /*Check if the input buffers have to be cleaned up*/ + if (m_inp_mem_ptr +#ifdef _ANDROID_ICS_ + && !meta_mode_enable +#endif + ) { + DEBUG_PRINT_LOW("Freeing the Input Memory"); + for (i=0; i<m_sInPortDef.nBufferCountActual; i++ ) { + if (BITMASK_PRESENT(&m_inp_bm_count, i)) { + BITMASK_CLEAR(&m_inp_bm_count, i); + free_input_buffer (&m_inp_mem_ptr[i]); + } + + if (release_input_done()) { + break; + } + } + + + free(m_inp_mem_ptr); + m_inp_mem_ptr = NULL; + } + + // Reset counters in mesg queues + m_ftb_q.m_size=0; + m_cmd_q.m_size=0; + m_etb_q.m_size=0; + m_ftb_q.m_read = m_ftb_q.m_write =0; + m_cmd_q.m_read = m_cmd_q.m_write =0; + m_etb_q.m_read = m_etb_q.m_write =0; + +#ifdef _ANDROID_ + // Clear the strong reference + DEBUG_PRINT_HIGH("Calling m_heap_ptr.clear()"); + m_heap_ptr.clear(); +#endif // _ANDROID_ + DEBUG_PRINT_HIGH("Calling venc_close()"); + if (handle) { + handle->venc_close(); + DEBUG_PRINT_HIGH("Deleting HANDLE[%p]", handle); + delete (handle); + handle = NULL; + } + DEBUG_PRINT_INFO("Component Deinit"); + return OMX_ErrorNone; +} + + +OMX_U32 omx_venc::dev_stop( void) +{ + return handle->venc_stop(); +} + + +OMX_U32 omx_venc::dev_pause(void) +{ + return handle->venc_pause(); +} + +OMX_U32 omx_venc::dev_start(void) +{ + return handle->venc_start(); +} + +OMX_U32 omx_venc::dev_flush(unsigned port) +{ + return handle->venc_flush(port); +} +OMX_U32 omx_venc::dev_resume(void) +{ + return handle->venc_resume(); +} + +OMX_U32 omx_venc::dev_start_done(void) +{ + return handle->venc_start_done(); +} + +OMX_U32 omx_venc::dev_set_message_thread_id(pthread_t tid) +{ + return handle->venc_set_message_thread_id(tid); +} + +bool omx_venc::dev_use_buf(void *buf_addr,unsigned port,unsigned index) +{ + return handle->venc_use_buf(buf_addr,port,index); +} + +bool omx_venc::dev_buffer_ready_to_queue(OMX_BUFFERHEADERTYPE *buffer) +{ + bool bRet = true; + + pthread_mutex_lock(×tamp.m_lock); + + if ((!m_slowLatencyMode.bLowLatencyMode) || ((OMX_U64)buffer->nTimeStamp == (OMX_U64)timestamp.m_TimeStamp)) { + DEBUG_PRINT_LOW("ETB is ready to be queued"); + } else { + DEBUG_PRINT_INFO("ETB is defeffed due to timeStamp mismatch"); + timestamp.is_buffer_pending = true; + timestamp.pending_buffer = buffer; + bRet = false; + } + pthread_mutex_unlock(×tamp.m_lock); + return bRet; +} + +bool omx_venc::dev_free_buf(void *buf_addr,unsigned port) +{ + return handle->venc_free_buf(buf_addr,port); +} + +bool omx_venc::dev_empty_buf(void *buffer, void *pmem_data_buf,unsigned index,unsigned fd) +{ + bool bret = false; + bret = handle->venc_empty_buf(buffer, pmem_data_buf,index,fd); + hw_overload = handle->hw_overload; + return bret; +} + +bool omx_venc::dev_fill_buf(void *buffer, void *pmem_data_buf,unsigned index,unsigned fd) +{ + return handle->venc_fill_buf(buffer, pmem_data_buf,index,fd); +} + +bool omx_venc::dev_get_seq_hdr(void *buffer, unsigned size, unsigned *hdrlen) +{ + return handle->venc_get_seq_hdr(buffer, size, hdrlen); +} + +bool omx_venc::dev_get_capability_ltrcount(OMX_U32 *min, OMX_U32 *max, OMX_U32 *step_size) +{ +#ifdef _MSM8974_ + (void) min; + (void) max; + (void) step_size; + DEBUG_PRINT_ERROR("Get Capability LTR Count is not supported"); + return false; +#else + return handle->venc_get_capability_ltrcount(min, max, step_size); +#endif +} + +bool omx_venc::dev_get_performance_level(OMX_U32 *perflevel) +{ +#ifdef _MSM8974_ + return handle->venc_get_performance_level(perflevel); +#else + DEBUG_PRINT_ERROR("Get performance level is not supported"); + return false; +#endif +} + +bool omx_venc::dev_get_vui_timing_info(OMX_U32 *enabled) +{ +#ifdef _MSM8974_ + return handle->venc_get_vui_timing_info(enabled); +#else + DEBUG_PRINT_ERROR("Get vui timing information is not supported"); + return false; +#endif +} + +bool omx_venc::dev_get_vqzip_sei_info(OMX_U32 *enabled) +{ + return handle->venc_get_vqzip_sei_info(enabled); +} + +bool omx_venc::dev_get_peak_bitrate(OMX_U32 *peakbitrate) +{ +#ifdef _MSM8974_ + return handle->venc_get_peak_bitrate(peakbitrate); +#else + DEBUG_PRINT_ERROR("Get peak bitrate is not supported"); + return false; +#endif +} + +bool omx_venc::dev_get_batch_size(OMX_U32 *size) +{ +#ifdef _MSM8974_ + return handle->venc_get_batch_size(size); +#else + DEBUG_PRINT_ERROR("Get batch size is not supported"); + return false; +#endif +} + +bool omx_venc::dev_get_temporal_layer_caps(OMX_U32 *nMaxLayers, + OMX_U32 *nMaxBLayers) { + return handle->venc_get_temporal_layer_caps(nMaxLayers, nMaxBLayers); +} + +bool omx_venc::dev_loaded_start() +{ + return handle->venc_loaded_start(); +} + +bool omx_venc::dev_loaded_stop() +{ + return handle->venc_loaded_stop(); +} + +bool omx_venc::dev_loaded_start_done() +{ + return handle->venc_loaded_start_done(); +} + +bool omx_venc::dev_loaded_stop_done() +{ + return handle->venc_loaded_stop_done(); +} + +bool omx_venc::dev_get_buf_req(OMX_U32 *min_buff_count, + OMX_U32 *actual_buff_count, + OMX_U32 *buff_size, + OMX_U32 port) +{ + return handle->venc_get_buf_req(min_buff_count, + actual_buff_count, + buff_size, + port); + +} + +bool omx_venc::dev_set_buf_req(OMX_U32 *min_buff_count, + OMX_U32 *actual_buff_count, + OMX_U32 *buff_size, + OMX_U32 port) +{ + return handle->venc_set_buf_req(min_buff_count, + actual_buff_count, + buff_size, + port); + +} + +bool omx_venc::dev_is_video_session_supported(OMX_U32 width, OMX_U32 height) +{ +#ifdef _MSM8974_ + return handle->venc_is_video_session_supported(width,height); +#else + DEBUG_PRINT_LOW("Check against video capability not supported"); + return true; +#endif +} + +int omx_venc::dev_handle_output_extradata(void *buffer, int index) +{ + return handle->handle_output_extradata(buffer, index); +} + +int omx_venc::dev_set_format(int color) +{ + return handle->venc_set_format(color); +} + +int omx_venc::async_message_process (void *context, void* message) +{ + omx_video* omx = NULL; + struct venc_msg *m_sVenc_msg = NULL; + OMX_BUFFERHEADERTYPE* omxhdr = NULL; + struct venc_buffer *temp_buff = NULL; + native_handle_t *nh = NULL; + + if (context == NULL || message == NULL) { + DEBUG_PRINT_ERROR("ERROR: omx_venc::async_message_process invalid i/p params"); + return -1; + } + m_sVenc_msg = (struct venc_msg *)message; + + omx = reinterpret_cast<omx_video*>(context); + + if (m_sVenc_msg->statuscode != VEN_S_SUCCESS) { + DEBUG_PRINT_ERROR("ERROR: async_msg_process() - Error statuscode = %lu", + m_sVenc_msg->statuscode); + if(m_sVenc_msg->msgcode == VEN_MSG_HW_OVERLOAD) { + omx->post_event (0, m_sVenc_msg->statuscode,\ + OMX_COMPONENT_GENERATE_HARDWARE_OVERLOAD); + } else { + omx->post_event (0, m_sVenc_msg->statuscode,\ + OMX_COMPONENT_GENERATE_HARDWARE_ERROR); + } + } + + DEBUG_PRINT_LOW("omx_venc::async_message_process- msgcode = %lu", + m_sVenc_msg->msgcode); + switch (m_sVenc_msg->msgcode) { + case VEN_MSG_START: + omx->post_event (0,m_sVenc_msg->statuscode,\ + OMX_COMPONENT_GENERATE_START_DONE); + break; + case VEN_MSG_STOP: + omx->post_event (0,m_sVenc_msg->statuscode,\ + OMX_COMPONENT_GENERATE_STOP_DONE); + break; + case VEN_MSG_RESUME: + omx->post_event (0,m_sVenc_msg->statuscode,\ + OMX_COMPONENT_GENERATE_RESUME_DONE); + break; + case VEN_MSG_PAUSE: + omx->post_event (0,m_sVenc_msg->statuscode,\ + OMX_COMPONENT_GENERATE_PAUSE_DONE); + break; + case VEN_MSG_FLUSH_INPUT_DONE: + + omx->post_event (0,m_sVenc_msg->statuscode,\ + OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH); + break; + case VEN_MSG_FLUSH_OUPUT_DONE: + omx->post_event (0,m_sVenc_msg->statuscode,\ + OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH); + break; + case VEN_MSG_INPUT_BUFFER_DONE: + omxhdr = (OMX_BUFFERHEADERTYPE* )\ + m_sVenc_msg->buf.clientdata; + + if (omxhdr == NULL || + (((OMX_U32)(omxhdr - omx->m_inp_mem_ptr) > omx->m_sInPortDef.nBufferCountActual) && + ((OMX_U32)(omxhdr - omx->meta_buffer_hdr) > omx->m_sInPortDef.nBufferCountActual))) { + omxhdr = NULL; + m_sVenc_msg->statuscode = VEN_S_EFAIL; + } + +#ifdef _ANDROID_ICS_ + omx->omx_release_meta_buffer(omxhdr); +#endif + omx->post_event ((unsigned long)omxhdr,m_sVenc_msg->statuscode, + OMX_COMPONENT_GENERATE_EBD); + break; + case VEN_MSG_OUTPUT_BUFFER_DONE: + omxhdr = (OMX_BUFFERHEADERTYPE*)m_sVenc_msg->buf.clientdata; + + if ( (omxhdr != NULL) && + ((OMX_U32)(omxhdr - omx->m_out_mem_ptr) < omx->m_sOutPortDef.nBufferCountActual)) { + if (!omx->is_secure_session() && (m_sVenc_msg->buf.len <= omxhdr->nAllocLen)) { + omxhdr->nFilledLen = m_sVenc_msg->buf.len; + omxhdr->nOffset = m_sVenc_msg->buf.offset; + omxhdr->nTimeStamp = m_sVenc_msg->buf.timestamp; + DEBUG_PRINT_LOW("o/p TS = %u", (unsigned int)m_sVenc_msg->buf.timestamp); + omxhdr->nFlags = m_sVenc_msg->buf.flags; + + /*Use buffer case*/ + if (omx->output_use_buffer && !omx->m_use_output_pmem && !omx->is_secure_session()) { + DEBUG_PRINT_LOW("memcpy() for o/p Heap UseBuffer"); + memcpy(omxhdr->pBuffer, + (m_sVenc_msg->buf.ptrbuffer), + m_sVenc_msg->buf.len); + } + } else if (omx->is_secure_session()) { + output_metabuffer *meta_buf = (output_metabuffer *)(omxhdr->pBuffer); + native_handle_t *nh = meta_buf->nh; + nh->data[1] = m_sVenc_msg->buf.offset; + nh->data[2] = m_sVenc_msg->buf.len; + omxhdr->nFilledLen = sizeof(output_metabuffer); + omxhdr->nTimeStamp = m_sVenc_msg->buf.timestamp; + omxhdr->nFlags = m_sVenc_msg->buf.flags; + } else { + omxhdr->nFilledLen = 0; + } + + } else { + omxhdr = NULL; + m_sVenc_msg->statuscode = VEN_S_EFAIL; + } + omx->post_event ((unsigned long)omxhdr,m_sVenc_msg->statuscode, + OMX_COMPONENT_GENERATE_FBD); + break; + case VEN_MSG_NEED_OUTPUT_BUFFER: + //TBD what action needs to be done here?? + break; +#ifndef _MSM8974_ + case VEN_MSG_LTRUSE_FAILED: + DEBUG_PRINT_ERROR("LTRUSE Failed!"); + omx->post_event (NULL,m_sVenc_msg->statuscode, + OMX_COMPONENT_GENERATE_LTRUSE_FAILED); + break; +#endif + default: + DEBUG_PRINT_HIGH("Unknown msg received : %lu", m_sVenc_msg->msgcode); + break; + } + return 0; +} + +bool omx_venc::dev_color_align(OMX_BUFFERHEADERTYPE *buffer, + OMX_U32 width, OMX_U32 height) +{ + if(secure_session) { + DEBUG_PRINT_ERROR("Cannot align colors in secure session."); + return OMX_FALSE; + } + return handle->venc_color_align(buffer, width,height); +} + +bool omx_venc::is_secure_session() +{ + return secure_session; +} + +bool omx_venc::dev_get_output_log_flag() +{ + return handle->venc_get_output_log_flag(); +} + +int omx_venc::dev_output_log_buffers(const char *buffer, int bufferlen) +{ + return handle->venc_output_log_buffers(buffer, bufferlen); +} + +int omx_venc::dev_extradata_log_buffers(char *buffer) +{ + return handle->venc_extradata_log_buffers(buffer); +} diff --git a/msm8998/mm-video-v4l2/vidc/venc/src/video_encoder_device.cpp b/msm8998/mm-video-v4l2/vidc/venc/src/video_encoder_device.cpp new file mode 100644 index 0000000..855c79f --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/src/video_encoder_device.cpp @@ -0,0 +1,3149 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2013, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ +#include<string.h> +#include <sys/ioctl.h> +#include <sys/prctl.h> +#include<unistd.h> +#include <fcntl.h> +#include "video_encoder_device.h" +#include "omx_video_encoder.h" +#include <linux/android_pmem.h> +#ifdef USE_ION +#include <linux/msm_ion.h> +#endif + +#define MPEG4_SP_START 0 +#define MPEG4_ASP_START (MPEG4_SP_START + 8) +#define MPEG4_720P_LEVEL 6 +#define H263_BP_START 0 +#define H264_BP_START 0 +#define H264_HP_START (H264_BP_START + 13) +#define H264_MP_START (H264_BP_START + 26) + +/* MPEG4 profile and level table*/ +static const unsigned int mpeg4_profile_level_table[][5]= { + /*max mb per frame, max mb per sec, max bitrate, level, profile*/ + {99,1485,64000,OMX_VIDEO_MPEG4Level0,OMX_VIDEO_MPEG4ProfileSimple}, + {99,1485,64000,OMX_VIDEO_MPEG4Level1,OMX_VIDEO_MPEG4ProfileSimple}, + {396,5940,128000,OMX_VIDEO_MPEG4Level2,OMX_VIDEO_MPEG4ProfileSimple}, + {396,11880,384000,OMX_VIDEO_MPEG4Level3,OMX_VIDEO_MPEG4ProfileSimple}, + {1200,36000,4000000,OMX_VIDEO_MPEG4Level4a,OMX_VIDEO_MPEG4ProfileSimple}, + {1620,40500,8000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileSimple}, + {3600,108000,12000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileSimple}, + {0,0,0,0,0}, + + {99,1485,128000,OMX_VIDEO_MPEG4Level0,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, + {99,1485,128000,OMX_VIDEO_MPEG4Level1,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, + {396,5940,384000,OMX_VIDEO_MPEG4Level2,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, + {396,11880,768000,OMX_VIDEO_MPEG4Level3,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, + {792,23760,3000000,OMX_VIDEO_MPEG4Level4,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, + {1620,48600,8000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, + {0,0,0,0,0}, +}; + +/* H264 profile and level table*/ +static const unsigned int h264_profile_level_table[][5]= { + /*max mb per frame, max mb per sec, max bitrate, level, profile*/ + {99,1485,64000,OMX_VIDEO_AVCLevel1,OMX_VIDEO_AVCProfileBaseline}, + {99,1485,128000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileBaseline}, + {396,3000,192000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileBaseline}, + {396,6000,384000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileBaseline}, + {396,11880,768000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileBaseline}, + {396,11880,2000000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileBaseline}, + {792,19800,4000000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileBaseline}, + {1620,20250,4000000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileBaseline}, + {1620,40500,10000000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileBaseline}, + {3600,108000,14000000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileBaseline}, + {5120,216000,20000000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileBaseline}, + {8192,245760,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileBaseline}, + {0,0,0,0,0}, + + {99,1485,64000,OMX_VIDEO_AVCLevel1,OMX_VIDEO_AVCProfileHigh}, + {99,1485,160000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileHigh}, + {396,3000,240000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileHigh}, + {396,6000,480000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileHigh}, + {396,11880,960000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileHigh}, + {396,11880,2500000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileHigh}, + {792,19800,5000000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileHigh}, + {1620,20250,5000000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileHigh}, + {1620,40500,12500000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileHigh}, + {3600,108000,17500000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileHigh}, + {5120,216000,25000000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileHigh}, + {8192,245760,25000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileHigh}, + {0,0,0,0,0}, + + {99,1485,64000,OMX_VIDEO_AVCLevel1,OMX_VIDEO_AVCProfileMain}, + {99,1485,128000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileMain}, + {396,3000,192000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileMain}, + {396,6000,384000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileMain}, + {396,11880,768000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileMain}, + {396,11880,2000000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileMain}, + {792,19800,4000000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileMain}, + {1620,20250,4000000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileMain}, + {1620,40500,10000000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileMain}, + {3600,108000,14000000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileMain}, + {5120,216000,20000000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileMain}, + {8192,245760,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileMain}, + {0,0,0,0,0} + +}; + +/* H263 profile and level table*/ +static const unsigned int h263_profile_level_table[][5]= { + /*max mb per frame, max mb per sec, max bitrate, level, profile*/ + {99,1485,64000,OMX_VIDEO_H263Level10,OMX_VIDEO_H263ProfileBaseline}, + {396,5940,128000,OMX_VIDEO_H263Level20,OMX_VIDEO_H263ProfileBaseline}, + {396,11880,384000,OMX_VIDEO_H263Level30,OMX_VIDEO_H263ProfileBaseline}, + {396,11880,2048000,OMX_VIDEO_H263Level40,OMX_VIDEO_H263ProfileBaseline}, + {99,1485,128000,OMX_VIDEO_H263Level45,OMX_VIDEO_H263ProfileBaseline}, + {396,19800,4096000,OMX_VIDEO_H263Level50,OMX_VIDEO_H263ProfileBaseline}, + {810,40500,8192000,OMX_VIDEO_H263Level60,OMX_VIDEO_H263ProfileBaseline}, + {1620,81000,16384000,OMX_VIDEO_H263Level70,OMX_VIDEO_H263ProfileBaseline}, + {0,0,0,0,0} +}; + +#define Log2(number, power) { OMX_U32 temp = number; power = 0; while( (0 == (temp & 0x1)) && power < 16) { temp >>=0x1; power++; } } +#define Q16ToFraction(q,num,den) { OMX_U32 power; Log2(q,power); num = q >> power; den = 0x1 << (16 - power); } + +#define BUFFER_LOG_LOC "/data/misc/media" + +//constructor +venc_dev::venc_dev(class omx_venc *venc_class) +{ + m_max_allowed_bitrate_check = false; + m_eLevel = 0; + m_eProfile = 0; + pthread_mutex_init(&loaded_start_stop_mlock, NULL); + pthread_cond_init (&loaded_start_stop_cond, NULL); + memset(&m_debug,0,sizeof(m_debug)); + + char property_value[PROPERTY_VALUE_MAX] = {0}; + property_value[0] = '\0'; + property_get("vidc.enc.log.in", property_value, "0"); + m_debug.in_buffer_log = atoi(property_value); + + property_value[0] = '\0'; + property_get("vidc.enc.log.out", property_value, "0"); + m_debug.out_buffer_log = atoi(property_value); + snprintf(m_debug.log_loc, PROPERTY_VAL_MAX, + "%s", BUFFER_LOG_LOC); + + DEBUG_PRINT_LOW("venc_dev constructor"); +} + +venc_dev::~venc_dev() +{ + pthread_cond_destroy(&loaded_start_stop_cond); + pthread_mutex_destroy(&loaded_start_stop_mlock); + DEBUG_PRINT_LOW("venc_dev distructor"); +} + +void* async_venc_message_thread (void *input) +{ + struct venc_ioctl_msg ioctl_msg ={NULL,NULL}; + struct venc_timeout timeout; + struct venc_msg venc_msg; + int error_code = 0; + omx_venc *omx = reinterpret_cast<omx_venc*>(input); + + prctl(PR_SET_NAME, (unsigned long)"VideoEncCallBackThread", 0, 0, 0); + timeout.millisec = VEN_TIMEOUT_INFINITE; + + while (1) { + ioctl_msg.in = NULL; + ioctl_msg.out = (void*)&venc_msg; + + /*Wait for a message from the video decoder driver*/ + error_code = ioctl(omx->handle->m_nDriver_fd,VEN_IOCTL_CMD_READ_NEXT_MSG,(void *)&ioctl_msg); + + if (error_code == -512) { // ERESTARTSYS + DEBUG_PRINT_ERROR("ERESTARTSYS received in ioctl read next msg!"); + } else if (error_code <0) { + DEBUG_PRINT_LOW("ioctl VEN_IOCTL_CMD_READ_NEXT_MSG failed"); + break; + } else if (omx->async_message_process(input,&venc_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Wrong ioctl message"); + break; + } + } + DEBUG_PRINT_HIGH("omx_venc: Async Thread exit"); + return NULL; +} + +int venc_dev::venc_extradata_log_buffers(char *buffer_addr) +{ + return OMX_ErrorUnsupportedSetting; +} + +int venc_dev::venc_output_log_buffers(const char *buffer_addr, int buffer_len) +{ + if (m_debug.out_buffer_log && !m_debug.outfile) { + int size = 0; + if(m_sVenc_cfg.codectype == VEN_CODEC_MPEG4) { + size = snprintf(m_debug.outfile_name, PROPERTY_VALUE_MAX, "%s/output_enc_%d_%d_%p.m4v", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } else if(m_sVenc_cfg.codectype == VEN_CODEC_H264) { + size = snprintf(m_debug.outfile_name, PROPERTY_VALUE_MAX, "%s/output_enc_%d_%d_%p.264", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } else if(m_sVenc_cfg.codectype == VENC_CODEC_H263) { + size = snprintf(m_debug.outfile_name, PROPERTY_VALUE_MAX, "%s/output_enc_%d_%d_%p.263", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } else if(m_sVenc_cfg.codectype == VENC_CODEC_VP8) { + size = snprintf(m_debug.outfile_name, PROPERTY_VALUE_MAX, "%s/output_enc_%d_%d_%p.ivf", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } + if ((size > PROPERTY_VALUE_MAX) || (size < 0)) { + DEBUG_PRINT_ERROR("Failed to open output file: %s for logging as size:%d", + m_debug.outfile_name, size); + return -1; + } + m_debug.outfile = fopen(m_debug.outfile_name, "ab"); + if (!m_debug.outfile) { + DEBUG_PRINT_ERROR("Failed to open output file: %s for logging errno:%d", + m_debug.outfile_name, errno); + m_debug.outfile_name[0] = '\0'; + return -1; + } + } + if (m_debug.outfile && buffer_len) { + DEBUG_PRINT_LOW("%s buffer_len:%d", __func__, buffer_len); + fwrite(buffer_addr, buffer_len, 1, m_debug.outfile); + } + return 0; +} + +bool venc_dev::venc_get_output_log_flag() +{ + return (m_debug.out_buffer_log == 1); +} + +int venc_dev::venc_input_log_buffers(OMX_BUFFERHEADERTYPE *pbuffer, void *pmem_data_buf, int framelen) { + if (!m_debug.infile) { + int size = snprintf(m_debug.infile_name, PROPERTY_VALUE_MAX, "%s/input_enc_%d_%d_%p.yuv", + m_debug.log_loc, m_sVenc_cfg.input_width, + m_sVenc_cfg.input_height, this); + if ((size > PROPERTY_VALUE_MAX) || (size < 0)) { + DEBUG_PRINT_ERROR("Failed to open input file: %s for logging size:%d", + m_debug.infile_name, size); + return -1; + } + m_debug.infile = fopen (m_debug.infile_name, "ab"); + if (!m_debug.infile) { + DEBUG_PRINT_HIGH("Failed to open input file: %s for logging", m_debug.infile); + m_debug.infile_name[0] = '\0'; + return -1; + } + } + if (m_debug.infile && pbuffer && pbuffer->nFilledLen) { +#ifdef MAX_RES_1080P + int y_size = 0; + int c_offset = 0; + unsigned char *buf_addr = NULL; + + y_size = m_sVenc_cfg.input_width * m_sVenc_cfg.input_height; + //chroma offset is y_size aligned to the 2k boundary + c_offset= (y_size + 2047) & (~(2047)); + + if (pmem_data_buf) { + DEBUG_PRINT_LOW("Internal PMEM addr for i/p Heap UseBuf: %p", pmem_data_buf); + buf_addr = (OMX_U8 *)pmem_data_buf; + } else { + DEBUG_PRINT_LOW("Shared PMEM addr for i/p PMEM UseBuf/AllocateBuf: %p", bufhdr->pBuffer); + buf_addr = (unsigned char *)mmap(NULL, + ((encoder_media_buffer_type *)pbuffer->pBuffer)->meta_handle->data[2], + PROT_READ|PROT_WRITE, MAP_SHARED, + ((encoder_media_buffer_type *)pbuffer->pBuffer)->meta_handle->data[0], 0); + } + + if (m_debug.infile) { + fwrite((const char *)buf_addr, y_size, 1, m_debug.infile); + fwrite((const char *)(buf_addr + c_offset), (y_size>>1), 1, m_debug.infile); + } + + if (!pmem_data_buf) { + munmap (buf_addr, ((encoder_media_buffer_type *)pbuffer->pBuffer)->meta_handle->data[2]); + } +#else + if (m_debug.infile) { + OMX_U8* ptrbuffer = NULL; + if (pmem_data_buf) { + DEBUG_PRINT_LOW("Internal PMEM addr for i/p Heap UseBuf: %p", pmem_data_buf); + ptrbuffer = (OMX_U8 *)pmem_data_buf; + } else { + DEBUG_PRINT_LOW("Shared PMEM addr for i/p PMEM UseBuf/AllocateBuf: %p", bufhdr->pBuffer); + ptrbuffer = (OMX_U8 *)bufhdr->pBuffer; + } + fwrite((const char *)ptrbuffer, framelen, 1, m_debug.infile); + } + +#endif + } + return 0; +} + +bool venc_dev::venc_open(OMX_U32 codec) +{ + struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; + int r; + unsigned int alignment = 0,buffer_size = 0, temp =0; + + m_nDriver_fd = open ("/dev/msm_vidc_enc",O_RDWR|O_NONBLOCK); + + if (m_nDriver_fd == 0) { + DEBUG_PRINT_ERROR("ERROR: Got fd as 0 for msm_vidc_enc, Opening again"); + m_nDriver_fd = open ("/dev/msm_vidc_enc",O_RDWR|O_NONBLOCK); + } + + if ((int)m_nDriver_fd < 0) { + DEBUG_PRINT_ERROR("ERROR: Omx_venc::Comp Init Returning failure"); + return false; + } + + DEBUG_PRINT_LOW("m_nDriver_fd = %d", m_nDriver_fd); +#ifdef SINGLE_ENCODER_INSTANCE + OMX_U32 num_instances = 0; + ioctl_msg.in = NULL; + ioctl_msg.out = &num_instances; + + if (ioctl (m_nDriver_fd, VEN_IOCTL_GET_NUMBER_INSTANCES, (void*)&ioctl_msg) < 0 ) { + DEBUG_PRINT_ERROR("ERROR: Request number of encoder instances failed"); + } else if (num_instances > 1) { + DEBUG_PRINT_ERROR("Second encoder instance rejected!"); + venc_close(); + return false; + } + +#endif + // set the basic configuration of the video encoder driver + m_sVenc_cfg.input_width = OMX_CORE_QCIF_WIDTH; + m_sVenc_cfg.input_height= OMX_CORE_QCIF_HEIGHT; + m_sVenc_cfg.dvs_width = OMX_CORE_QCIF_WIDTH; + m_sVenc_cfg.dvs_height = OMX_CORE_QCIF_HEIGHT; + m_sVenc_cfg.fps_num = 30; + m_sVenc_cfg.fps_den = 1; + m_sVenc_cfg.targetbitrate = 64000; +#ifdef MAX_RES_1080P + m_sVenc_cfg.inputformat= VEN_INPUTFMT_NV12_16M2KA; +#else + m_sVenc_cfg.inputformat= VEN_INPUTFMT_NV12; +#endif + // initializing QP range parameters + qp_range.minqp = 2; + + if (codec == OMX_VIDEO_CodingAVC) + qp_range.maxqp = 51; + else + qp_range.maxqp = 31; + + if (codec == OMX_VIDEO_CodingMPEG4) { + m_sVenc_cfg.codectype = VEN_CODEC_MPEG4; + codec_profile.profile = VEN_PROFILE_MPEG4_SP; + profile_level.level = VEN_LEVEL_MPEG4_2; + } else if (codec == OMX_VIDEO_CodingH263) { + m_sVenc_cfg.codectype = VEN_CODEC_H263; + codec_profile.profile = VEN_PROFILE_H263_BASELINE; + profile_level.level = VEN_LEVEL_H263_20; + } + + if (codec == OMX_VIDEO_CodingAVC) { + m_sVenc_cfg.codectype = VEN_CODEC_H264; + codec_profile.profile = VEN_PROFILE_H264_BASELINE; + profile_level.level = VEN_LEVEL_H264_1p1; + } + + ioctl_msg.in = (void*)&m_sVenc_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_BASE_CFG,(void*)&ioctl_msg) < 0 ) { + DEBUG_PRINT_ERROR("ERROR: Request for setting base configuration failed"); + return false; + } + + // Get the I/P and O/P buffer requirements + ioctl_msg.in = NULL; + ioctl_msg.out = (void*)&m_sInput_buff_property; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_GET_INPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for getting i/p buffer requirement failed"); + return false; + } + + ioctl_msg.in = NULL; + ioctl_msg.out = (void*)&m_sOutput_buff_property; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_GET_OUTPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for getting o/p buffer requirement failed"); + return false; + } + + m_profile_set = false; + m_level_set = false; + + if (venc_set_profile_level(0, 0)) { + DEBUG_PRINT_HIGH("%s(): Init Profile/Level setting success", + __func__); + } + + recon_buffers_count = MAX_RECON_BUFFERS; + ltrmode.ltr_mode = 0; + ltrcount.ltr_count = 0; + ltrperiod.ltr_period = 0; + + return true; +} + +void venc_dev::venc_close() +{ + DEBUG_PRINT_LOW("venc_close: fd = %d", m_nDriver_fd); + + if ((int)m_nDriver_fd >= 0) { + DEBUG_PRINT_HIGH("venc_close(): Calling VEN_IOCTL_CMD_STOP_READ_MSG"); + (void)ioctl(m_nDriver_fd, VEN_IOCTL_CMD_STOP_READ_MSG, + NULL); + DEBUG_PRINT_LOW("Calling close()"); + close(m_nDriver_fd); + m_nDriver_fd = -1; + } + + if (m_debug.infile) { + fclose(m_debug.infile); + m_debug.infile = NULL; + } + if (m_debug.outfile) { + fclose(m_debug.outfile); + m_debug.outfile = NULL; + } + +} + +bool venc_dev::venc_set_buf_req(unsigned long *min_buff_count, + unsigned long *actual_buff_count, + unsigned long *buff_size, + unsigned long port) +{ + struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; + unsigned long temp_count = 0; + + if (port == 0) { + if (*actual_buff_count > m_sInput_buff_property.mincount) { + temp_count = m_sInput_buff_property.actualcount; + m_sInput_buff_property.actualcount = *actual_buff_count; + ioctl_msg.in = (void*)&m_sInput_buff_property; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_INPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting i/p buffer requirement failed"); + m_sInput_buff_property.actualcount = temp_count; + return false; + } + + DEBUG_PRINT_LOW("I/P Count set to %lu", *actual_buff_count); + } + } else { + if (*actual_buff_count > m_sOutput_buff_property.mincount) { + temp_count = m_sOutput_buff_property.actualcount; + m_sOutput_buff_property.actualcount = *actual_buff_count; + ioctl_msg.in = (void*)&m_sOutput_buff_property; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_OUTPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting o/p buffer requirement failed"); + m_sOutput_buff_property.actualcount = temp_count; + return false; + } + + DEBUG_PRINT_LOW("O/P Count set to %lu", *actual_buff_count); + } + } + + return true; + +} + +bool venc_dev::venc_loaded_start() +{ + struct timespec ts; + int status = 0; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_CMD_START, NULL) < 0) { + DEBUG_PRINT_ERROR("ERROR: VEN_IOCTL_CMD_START failed"); + return false; + } + + if (clock_gettime(CLOCK_REALTIME, &ts) < 0) { + DEBUG_PRINT_ERROR("%s: clock_gettime failed", __func__); + return false; + } + + ts.tv_sec += 1; + pthread_mutex_lock(&loaded_start_stop_mlock); + DEBUG_PRINT_LOW("%s: wait on start done", __func__); + status = pthread_cond_timedwait(&loaded_start_stop_cond, + &loaded_start_stop_mlock, &ts); + + if (status != 0) { + DEBUG_PRINT_ERROR("%s: error status = %d, %s", __func__, + status, strerror(status)); + pthread_mutex_unlock(&loaded_start_stop_mlock); + return false; + } + + DEBUG_PRINT_LOW("%s: wait over on start done", __func__); + pthread_mutex_unlock(&loaded_start_stop_mlock); + DEBUG_PRINT_LOW("%s: venc_loaded_start success", __func__); + return true; +} + +bool venc_dev::venc_loaded_stop() +{ + struct timespec ts; + int status = 0; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_CMD_STOP, NULL) < 0) { + DEBUG_PRINT_ERROR("ERROR: VEN_IOCTL_CMD_STOP failed"); + return false; + } + + if (clock_gettime(CLOCK_REALTIME, &ts) < 0) { + DEBUG_PRINT_ERROR("%s: clock_gettime failed", __func__); + return false; + } + + ts.tv_sec += 1; + pthread_mutex_lock(&loaded_start_stop_mlock); + DEBUG_PRINT_LOW("%s: wait on stop done", __func__); + status = pthread_cond_timedwait(&loaded_start_stop_cond, + &loaded_start_stop_mlock, &ts); + + if (status != 0) { + DEBUG_PRINT_ERROR("%s: error status = %d, %s", __func__, + status, strerror(status)); + pthread_mutex_unlock(&loaded_start_stop_mlock); + return false; + } + + DEBUG_PRINT_LOW("%s: wait over on stop done", __func__); + pthread_mutex_unlock(&loaded_start_stop_mlock); + DEBUG_PRINT_LOW("%s: venc_loaded_stop success", __func__); + return true; +} + +bool venc_dev::venc_loaded_start_done() +{ + pthread_mutex_lock(&loaded_start_stop_mlock); + DEBUG_PRINT_LOW("%s: signal start done", __func__); + pthread_cond_signal(&loaded_start_stop_cond); + pthread_mutex_unlock(&loaded_start_stop_mlock); + return true; +} + +bool venc_dev::venc_loaded_stop_done() +{ + pthread_mutex_lock(&loaded_start_stop_mlock); + DEBUG_PRINT_LOW("%s: signal stop done", __func__); + pthread_cond_signal(&loaded_start_stop_cond); + pthread_mutex_unlock(&loaded_start_stop_mlock); + return true; +} + +bool venc_dev::venc_get_seq_hdr(void *buffer, + unsigned buffer_size, unsigned *header_len) +{ + struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; + int i = 0; + DEBUG_PRINT_HIGH("venc_dev::venc_get_seq_hdr"); + venc_seqheader seq_in, seq_out; + seq_in.hdrlen = 0; + seq_in.bufsize = buffer_size; + seq_in.hdrbufptr = (unsigned char*)buffer; + + if (seq_in.hdrbufptr == NULL) { + DEBUG_PRINT_ERROR("ERROR: malloc for sequence header failed"); + return false; + } + + DEBUG_PRINT_LOW("seq_in: buf=%x, sz=%d, hdrlen=%d", seq_in.hdrbufptr, + seq_in.bufsize, seq_in.hdrlen); + + ioctl_msg.in = (void*)&seq_in; + ioctl_msg.out = (void*)&seq_out; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_GET_SEQUENCE_HDR,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for getting sequence header failed"); + return false; + } + + if (seq_out.hdrlen == 0) { + DEBUG_PRINT_ERROR("ERROR: Seq header returned zero length header"); + DEBUG_PRINT_ERROR("seq_out: buf=%x, sz=%d, hdrlen=%d", seq_out.hdrbufptr, + seq_out.bufsize, seq_out.hdrlen); + return false; + } + + *header_len = seq_out.hdrlen; + DEBUG_PRINT_LOW("seq_out: buf=%x, sz=%d, hdrlen=%d", seq_out.hdrbufptr, + seq_out.bufsize, seq_out.hdrlen); + + return true; +} + +bool venc_dev::venc_get_capability_ltrcount(unsigned long *min, + unsigned long *max, unsigned long *step_size) +{ + struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; + venc_range cap_ltr_count; + ioctl_msg.in = NULL; + ioctl_msg.out = (void*)&cap_ltr_count; + + if (ioctl (m_nDriver_fd, VEN_IOCTL_GET_CAPABILITY_LTRCOUNT, + (void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Get LTR Capability failed"); + return false; + } else { + *min = cap_ltr_count.min; + *max = cap_ltr_count.max; + *step_size = cap_ltr_count.step_size; + DEBUG_PRINT_HIGH("LTR Capability: min=%x, max=%d, step_size=%d", + *min, *max, *step_size); + } + + return true; +} + +bool venc_dev::venc_get_buf_req(unsigned long *min_buff_count, + unsigned long *actual_buff_count, + unsigned long *buff_size, + unsigned long port) +{ + struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; + + if (port == 0) { + ioctl_msg.in = NULL; + ioctl_msg.out = (void*)&m_sInput_buff_property; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_GET_INPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for getting i/p buffer requirement failed"); + return false; + } + + *min_buff_count = m_sInput_buff_property.mincount; + *actual_buff_count = m_sInput_buff_property.actualcount; +#ifdef USE_ION + // For ION memory allocations of the allocated buffer size + // must be 4k aligned, hence aligning the input buffer + // size to 4k. + m_sInput_buff_property.datasize = (m_sInput_buff_property.datasize + 4095) + & (~4095); +#endif + *buff_size = m_sInput_buff_property.datasize; + } else { + ioctl_msg.in = NULL; + ioctl_msg.out = (void*)&m_sOutput_buff_property; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_GET_OUTPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for getting o/p buffer requirement failed"); + return false; + } + + *min_buff_count = m_sOutput_buff_property.mincount; + *actual_buff_count = m_sOutput_buff_property.actualcount; + *buff_size = m_sOutput_buff_property.datasize; + } + + return true; + +} + +bool venc_dev::venc_set_param(void *paramData,OMX_INDEXTYPE index ) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + DEBUG_PRINT_LOW("venc_set_param:: venc-720p"); + + switch (index) { + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + DEBUG_PRINT_HIGH("venc_set_param: OMX_IndexParamPortDefinition"); + + if (portDefn->nPortIndex == PORT_INDEX_IN) { + + if (!venc_set_encode_framerate(portDefn->format.video.xFramerate, 0)) { + return false; + } + + if (!venc_set_color_format(portDefn->format.video.eColorFormat)) { + return false; + } + + DEBUG_PRINT_LOW("Basic parameter has changed"); + m_sVenc_cfg.input_height = portDefn->format.video.nFrameHeight; + m_sVenc_cfg.input_width = portDefn->format.video.nFrameWidth; + + ioctl_msg.in = (void*)&m_sVenc_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_BASE_CFG,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting base config failed"); + return false; + } + + DEBUG_PRINT_HIGH("WxH (%dx%d), codec (%d), fps(nr/dr) (%d/%d), bitrate (%d), " + "color_format (%d)", m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, + m_sVenc_cfg.codectype, m_sVenc_cfg.fps_num, m_sVenc_cfg.fps_den, + m_sVenc_cfg.targetbitrate, m_sVenc_cfg.inputformat); + + DEBUG_PRINT_LOW("Updating the buffer count/size for the new resolution"); + ioctl_msg.in = NULL; + ioctl_msg.out = (void*)&m_sInput_buff_property; + + if (ioctl (m_nDriver_fd, VEN_IOCTL_GET_INPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for getting i/p bufreq failed"); + return false; + } + + DEBUG_PRINT_HIGH("Got updated m_sInput_buff_property values: " + "datasize = %u, maxcount = %u, actualcnt = %u, " + "mincount = %u", m_sInput_buff_property.datasize, + m_sInput_buff_property.maxcount, m_sInput_buff_property.actualcount, + m_sInput_buff_property.mincount); + + ioctl_msg.in = NULL; + ioctl_msg.out = (void*)&m_sOutput_buff_property; + + if (ioctl (m_nDriver_fd, VEN_IOCTL_GET_OUTPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for getting o/p bufreq failed"); + return false; + } + + DEBUG_PRINT_HIGH("Got updated m_sOutput_buff_property values: " + "datasize = %u, maxcount = %u, actualcnt = %u, " + "mincount = %u", m_sOutput_buff_property.datasize, + m_sOutput_buff_property.maxcount, m_sOutput_buff_property.actualcount, + m_sOutput_buff_property.mincount); + ioctl_msg.in = (void*)&m_sOutput_buff_property; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd, VEN_IOCTL_SET_OUTPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting o/p bufreq failed"); + return false; + } + + if ((portDefn->nBufferCountActual >= m_sInput_buff_property.mincount) && + (portDefn->nBufferCountActual <= m_sInput_buff_property.maxcount)) { + m_sInput_buff_property.actualcount = portDefn->nBufferCountActual; + ioctl_msg.in = (void*)&m_sInput_buff_property; + ioctl_msg.out = NULL; + + if (ioctl(m_nDriver_fd,VEN_IOCTL_SET_INPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting i/p buffer requirements failed"); + return false; + } + } + + if (m_sInput_buff_property.datasize != portDefn->nBufferSize) { + DEBUG_PRINT_ERROR("WARNING: Requested i/p bufsize[%u]," + "Driver's updated i/p bufsize = %u", portDefn->nBufferSize, + m_sInput_buff_property.datasize); + } + + m_level_set = false; + + if (venc_set_profile_level(0, 0)) { + DEBUG_PRINT_LOW("%s(): Profile/Level setting success", __func__); + } + } else if (portDefn->nPortIndex == PORT_INDEX_OUT) { + if (!venc_set_target_bitrate(portDefn->format.video.nBitrate, 0)) { + return false; + } + + if ( (portDefn->nBufferCountActual >= m_sOutput_buff_property.mincount) + && + (m_sOutput_buff_property.maxcount >= portDefn->nBufferCountActual) + && + (m_sOutput_buff_property.datasize == portDefn->nBufferSize) + ) { + m_sOutput_buff_property.actualcount = portDefn->nBufferCountActual; + ioctl_msg.in = (void*)&m_sOutput_buff_property; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_OUTPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: ioctl VEN_IOCTL_SET_OUTPUT_BUFFER_REQ failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Setting Output buffer requirements failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamPortDefinition"); + } + + break; + } + case OMX_IndexParamVideoPortFormat: + { + OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt; + portFmt =(OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; + DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoPortFormat"); + + if (portFmt->nPortIndex == (OMX_U32) PORT_INDEX_IN) { + if (!venc_set_color_format(portFmt->eColorFormat)) { + return false; + } + } else if (portFmt->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (!venc_set_encode_framerate(portFmt->xFramerate, 0)) { + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoPortFormat"); + } + + break; + } + case OMX_IndexParamVideoBitrate: + { + OMX_VIDEO_PARAM_BITRATETYPE* pParam; + pParam = (OMX_VIDEO_PARAM_BITRATETYPE*)paramData; + DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoBitrate"); + + if (pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (!venc_set_target_bitrate(pParam->nTargetBitrate, 0)) { + DEBUG_PRINT_ERROR("ERROR: Target Bit Rate setting failed"); + return false; + } + + if (!venc_set_ratectrl_cfg(pParam->eControlRate)) { + DEBUG_PRINT_ERROR("ERROR: Rate Control setting failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoBitrate"); + } + + break; + } + case OMX_IndexParamVideoMpeg4: + { + OMX_VIDEO_PARAM_MPEG4TYPE* pParam; + OMX_U32 bFrames = 0; + + pParam = (OMX_VIDEO_PARAM_MPEG4TYPE*)paramData; + DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoMpeg4"); + + if (pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (!venc_set_voptiming_cfg(pParam->nTimeIncRes)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting vop_timing failed"); + return false; + } + + m_profile_set = false; + m_level_set = false; + + if (!venc_set_profile_level (pParam->eProfile, pParam->eLevel)) { + DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating Profile and level"); + return false; + } + +#ifdef MAX_RES_1080P + else { + if (pParam->eProfile == OMX_VIDEO_MPEG4ProfileAdvancedSimple) { + if (pParam->nBFrames) { + DEBUG_PRINT_HIGH("INFO: Only 1 Bframe is supported"); + bFrames = 1; + } + } else { + if (pParam->nBFrames) { + DEBUG_PRINT_ERROR("Warning: B frames not supported"); + bFrames = 0; + } + } + } + +#endif + + if (!venc_set_intra_period (pParam->nPFrames,bFrames)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting intra period failed"); + return false; + } + + if (!venc_set_multislice_cfg(OMX_IndexParamVideoMpeg4,pParam->nSliceHeaderSpacing)) { + DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating slice_config"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoMpeg4"); + } + + break; + } + case OMX_IndexParamVideoH263: + { + OMX_VIDEO_PARAM_H263TYPE* pParam = (OMX_VIDEO_PARAM_H263TYPE*)paramData; + DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoH263"); + OMX_U32 bFrames = 0; + + if (pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + m_profile_set = false; + m_level_set = false; + + if (!venc_set_profile_level (pParam->eProfile, pParam->eLevel)) { + DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating Profile and level"); + return false; + } + + if (pParam->nBFrames) + DEBUG_PRINT_ERROR("WARNING: B frame not supported for H.263"); + + if (venc_set_intra_period (pParam->nPFrames, bFrames) == false) { + DEBUG_PRINT_ERROR("ERROR: Request for setting intra period failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoH263"); + } + + break; + } + case OMX_IndexParamVideoAvc: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoAvc"); + OMX_VIDEO_PARAM_AVCTYPE* pParam = (OMX_VIDEO_PARAM_AVCTYPE*)paramData; + OMX_U32 bFrames = 0; + + if (pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + DEBUG_PRINT_LOW("pParam->eProfile :%d ,pParam->eLevel %d", + pParam->eProfile,pParam->eLevel); + + m_profile_set = false; + m_level_set = false; + + if (!venc_set_profile_level (pParam->eProfile,pParam->eLevel)) { + DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating Profile and level %d, %d", + pParam->eProfile, pParam->eLevel); + return false; + } + +#ifdef MAX_RES_1080P + else { + if (pParam->eProfile != OMX_VIDEO_AVCProfileBaseline) { + if (pParam->nBFrames) { + DEBUG_PRINT_HIGH("INFO: Only 1 Bframe is supported"); + bFrames = 1; + } + } else { + if (pParam->nBFrames) { + DEBUG_PRINT_ERROR("Warning: B frames not supported"); + bFrames = 0; + } + } + } + +#endif + + if (!venc_set_intra_period (pParam->nPFrames, bFrames)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting intra period failed"); + return false; + } + + if (!venc_set_entropy_config (pParam->bEntropyCodingCABAC, pParam->nCabacInitIdc)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting Entropy failed"); + return false; + } + + if (!venc_set_inloop_filter (pParam->eLoopFilterMode)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting Inloop filter failed"); + return false; + } + + if (!venc_set_multislice_cfg(OMX_IndexParamVideoAvc, pParam->nSliceHeaderSpacing)) { + DEBUG_PRINT_ERROR("WARNING: Unsuccessful in updating slice_config"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoAvc"); + } + + //TBD, lot of other variables to be updated, yet to decide + break; + } + case OMX_IndexParamVideoIntraRefresh: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoIntraRefresh"); + OMX_VIDEO_PARAM_INTRAREFRESHTYPE *intra_refresh = + (OMX_VIDEO_PARAM_INTRAREFRESHTYPE *)paramData; + + if (intra_refresh->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (venc_set_intra_refresh(intra_refresh->eRefreshMode, intra_refresh->nCirMBs) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Intra refresh failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoIntraRefresh"); + } + + break; + } + case OMX_IndexParamVideoErrorCorrection: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoErrorCorrection"); + OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE *error_resilience = + (OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE *)paramData; + + if (error_resilience->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (venc_set_error_resilience(error_resilience) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Intra refresh failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoErrorCorrection"); + } + + break; + } + case OMX_IndexParamVideoProfileLevelCurrent: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoProfileLevelCurrent"); + OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = + (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)paramData; + + if (profile_level->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + m_profile_set = false; + m_level_set = false; + + if (!venc_set_profile_level (profile_level->eProfile, + profile_level->eLevel)) { + DEBUG_PRINT_ERROR("WARNING: Unsuccessful in updating Profile and level"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoProfileLevelCurrent"); + } + + break; + } + case OMX_IndexParamVideoQuantization: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoQuantization"); + OMX_VIDEO_PARAM_QUANTIZATIONTYPE *session_qp = + (OMX_VIDEO_PARAM_QUANTIZATIONTYPE *)paramData; + + if (session_qp->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (venc_set_session_qp (session_qp->nQpI, + session_qp->nQpP) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Session QP failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoQuantization"); + } + + break; + } + + case OMX_QcomIndexParamVideoQPRange: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_QcomIndexParamVideoQPRange"); + OMX_QCOM_VIDEO_PARAM_QPRANGETYPE *qp_range = + (OMX_QCOM_VIDEO_PARAM_QPRANGETYPE *)paramData; + + if (qp_range->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (venc_set_qp_range (qp_range->minQP, + qp_range->maxQP) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting QP Range failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_QcomIndexParamVideoQPRange"); + } + + break; + } + + case OMX_ExtraDataVideoEncoderSliceInfo: + { + DEBUG_PRINT_LOW("venc_set_param: OMX_ExtraDataVideoEncoderSliceInfo"); + OMX_U32 extra_data = *(OMX_U32 *)paramData; + + if (venc_set_extradata(extra_data) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting " + "OMX_ExtraDataVideoEncoderSliceInfo failed"); + return false; + } + + break; + } + case OMX_ExtraDataVideoLTRInfo: + { + DEBUG_PRINT_LOW("venc_set_param: OMX_ExtraDataVideoLTRInfo"); + OMX_U32 extra_data = *(OMX_U32 *)paramData; + + if (venc_set_extradata(extra_data) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting " + "OMX_ExtraDataVideoLTRInfo failed"); + return false; + } + + break; + } + case OMX_QcomIndexEnableSliceDeliveryMode: + { + QOMX_EXTNINDEX_PARAMTYPE* pParam = + (QOMX_EXTNINDEX_PARAMTYPE*)paramData; + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (venc_set_slice_delivery_mode(pParam->bEnable) == false) { + DEBUG_PRINT_ERROR("Setting slice delivery mode failed"); + return OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_ERROR("OMX_QcomIndexEnableSliceDeliveryMode " + "called on wrong port(%d)", pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + case OMX_QcomIndexEnableH263PlusPType: + { + QOMX_EXTNINDEX_PARAMTYPE* pParam = + (QOMX_EXTNINDEX_PARAMTYPE*)paramData; + DEBUG_PRINT_LOW("OMX_QcomIndexEnableH263PlusPType"); + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (venc_set_plusptype(pParam->bEnable) == false) { + DEBUG_PRINT_ERROR("Setting PlusPType failed for H263"); + return OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_ERROR("OMX_QcomIndexEnableH263PlusPType " + "called on wrong port(%d)", pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + case QOMX_IndexParamVideoLTRMode: + { + QOMX_VIDEO_PARAM_LTRMODE_TYPE* pParam = + (QOMX_VIDEO_PARAM_LTRMODE_TYPE*)paramData; + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (!venc_set_ltrmode(pParam->eLTRMode)) { + DEBUG_PRINT_ERROR("Setting ltr mode failed"); + return OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_ERROR("QOMX_IndexParamVideoLTRMode " + "called on wrong port(%d)", pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + case QOMX_IndexParamVideoLTRCount: + { + QOMX_VIDEO_PARAM_LTRCOUNT_TYPE* pParam = + (QOMX_VIDEO_PARAM_LTRCOUNT_TYPE*)paramData; + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (!venc_set_ltrcount(pParam->nCount)) { + DEBUG_PRINT_ERROR("Setting ltr count failed"); + return OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_ERROR("QOMX_IndexParamVideoLTRCount " + "called on wrong port(%d)", pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + case OMX_IndexParamVideoSliceFMO: + default: + DEBUG_PRINT_ERROR("venc_set_param: Unsupported index 0x%x", index); + break; + } + + return true; +} + +bool venc_dev::venc_set_config(void *configData, OMX_INDEXTYPE index) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + DEBUG_PRINT_LOW("Inside venc_set_config"); + + switch (index) { + case OMX_IndexConfigVideoBitrate: + { + OMX_VIDEO_CONFIG_BITRATETYPE *bit_rate = (OMX_VIDEO_CONFIG_BITRATETYPE *) + configData; + + if (m_max_allowed_bitrate_check && + !venc_max_allowed_bitrate_check(bit_rate->nEncodeBitrate)) { + DEBUG_PRINT_ERROR("Max Allowed Bitrate Check failed"); + return false; + } + + DEBUG_PRINT_LOW("venc_set_config: OMX_IndexConfigVideoBitrate"); + + if (bit_rate->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { + if (venc_set_target_bitrate(bit_rate->nEncodeBitrate, 1) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Target Bit rate failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexConfigVideoBitrate"); + } + + break; + } + case OMX_IndexConfigVideoFramerate: + { + OMX_CONFIG_FRAMERATETYPE *frame_rate = (OMX_CONFIG_FRAMERATETYPE *) + configData; + DEBUG_PRINT_LOW("venc_set_config: OMX_IndexConfigVideoFramerate"); + + if (frame_rate->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { + if (venc_set_encode_framerate(frame_rate->xEncodeFramerate, 1) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Encode Framerate failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexConfigVideoFramerate"); + } + + break; + } + case QOMX_IndexConfigVideoIntraperiod: + { + DEBUG_PRINT_LOW("venc_set_param:QOMX_IndexConfigVideoIntraperiod"); + QOMX_VIDEO_INTRAPERIODTYPE *intraperiod = + (QOMX_VIDEO_INTRAPERIODTYPE *)configData; + + if (intraperiod->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (venc_set_intra_period(intraperiod->nPFrames, intraperiod->nBFrames) == false) { + DEBUG_PRINT_ERROR("ERROR: Request for setting intra period failed"); + return false; + } + } + + break; + } + case OMX_IndexConfigVideoIntraVOPRefresh: + { + OMX_CONFIG_INTRAREFRESHVOPTYPE *intra_vop_refresh = (OMX_CONFIG_INTRAREFRESHVOPTYPE *) + configData; + DEBUG_PRINT_LOW("venc_set_config: OMX_IndexConfigVideoIntraVOPRefresh"); + + if (intra_vop_refresh->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { + if (venc_set_intra_vop_refresh(intra_vop_refresh->IntraRefreshVOP) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Encode Framerate failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexConfigVideoFramerate"); + } + + break; + } + case OMX_IndexConfigCommonRotate: + { + OMX_CONFIG_ROTATIONTYPE *config_rotation = + reinterpret_cast<OMX_CONFIG_ROTATIONTYPE*>(configData); + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + OMX_U32 nFrameWidth; + + DEBUG_PRINT_HIGH("venc_set_config: updating the new Dims"); + nFrameWidth = m_sVenc_cfg.input_width; + m_sVenc_cfg.input_width = m_sVenc_cfg.input_height; + m_sVenc_cfg.input_height = nFrameWidth; + ioctl_msg.in = (void*)&m_sVenc_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_BASE_CFG,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Dimension Change for Rotation failed"); + return false; + } + + break; + } + case QOMX_IndexConfigVideoLTRPeriod: + { + QOMX_VIDEO_CONFIG_LTRPERIOD_TYPE* pParam = + (QOMX_VIDEO_CONFIG_LTRPERIOD_TYPE*)configData; + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (!venc_set_ltrperiod(pParam->nFrames)) { + DEBUG_PRINT_ERROR("Setting ltr period failed"); + return OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_ERROR("QOMX_IndexConfigVideoLTRPeriod " + "called on wrong port(%d)", pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + case QOMX_IndexConfigVideoLTRUse: + { + QOMX_VIDEO_CONFIG_LTRUSE_TYPE* pParam = + (QOMX_VIDEO_CONFIG_LTRUSE_TYPE*)configData; + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (!venc_set_ltruse(pParam->nID, pParam->nFrames)) { + DEBUG_PRINT_ERROR("Setting ltr use failed"); + return OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_ERROR("QOMX_IndexConfigVideoLTRUse " + "called on wrong port(%d)", pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + default: + DEBUG_PRINT_ERROR("venc_set_config: Unsupported index = 0x%x", index); + break; + } + + return true; +} + +unsigned venc_dev::venc_stop( void) +{ +#ifdef MAX_RES_1080P + pmem_free(); +#endif + return ioctl(m_nDriver_fd,VEN_IOCTL_CMD_STOP,NULL); +} + +unsigned venc_dev::venc_pause(void) +{ + return ioctl(m_nDriver_fd,VEN_IOCTL_CMD_PAUSE,NULL); +} + +unsigned venc_dev::venc_resume(void) +{ + return ioctl(m_nDriver_fd,VEN_IOCTL_CMD_RESUME,NULL) ; +} + +unsigned venc_dev::venc_start_done(void) +{ + return 0; +} + +unsigned venc_dev::venc_set_message_thread_id(pthread_t) +{ + return 0; +} + +unsigned venc_dev::venc_start(void) +{ + DEBUG_PRINT_HIGH("%s(): Check Profile/Level set in driver before start", + __func__); + + if (!venc_set_profile_level(0, 0)) { + DEBUG_PRINT_ERROR("ERROR: %s(): Driver Profile/Level is NOT SET", + __func__); + } else { + DEBUG_PRINT_HIGH("%s(): Driver Profile[%lu]/Level[%lu] successfully SET", + __func__, codec_profile.profile, profile_level.level); + } + + if (m_max_allowed_bitrate_check && + !venc_max_allowed_bitrate_check(bitrate.target_bitrate)) { + DEBUG_PRINT_ERROR("Maximum Allowed Bitrate Check failed"); + return -1; + } + + venc_config_print(); + +#ifdef MAX_RES_1080P + + if ((codec_profile.profile == VEN_PROFILE_MPEG4_SP) || + (codec_profile.profile == VEN_PROFILE_H264_BASELINE) || + (codec_profile.profile == VEN_PROFILE_H263_BASELINE)) + recon_buffers_count = MAX_RECON_BUFFERS - 2; + else + recon_buffers_count = MAX_RECON_BUFFERS; + + if (ltrmode.ltr_mode == (unsigned long)QOMX_VIDEO_LTRMode_Auto) { + recon_buffers_count = MAX_RECON_BUFFERS; + DEBUG_PRINT_HIGH("ltr mode enabled, so set recon buffers " + "count to %d", recon_buffers_count); + } + + if (!venc_allocate_recon_buffers()) + return ioctl(m_nDriver_fd, VEN_IOCTL_CMD_START, NULL); + else { + DEBUG_PRINT_ERROR("Failed in creating Recon buffers"); + return -1; + } + +#else + return ioctl(m_nDriver_fd, VEN_IOCTL_CMD_START, NULL); +#endif +} + +#ifdef MAX_RES_1080P +OMX_U32 venc_dev::venc_allocate_recon_buffers() +{ + OMX_U32 yuv_size; + struct venc_ioctl_msg ioctl_msg; + struct venc_recon_buff_size recon_buff_size; + + recon_buff_size.width = ((m_sVenc_cfg.input_width + 15) / 16) * 16; + recon_buff_size.height = ((m_sVenc_cfg.input_height + 15) / 16 ) * 16; + + DEBUG_PRINT_LOW("Width %d, Height %d, w_round %d, h_round %d", m_sVenc_cfg.input_width, + m_sVenc_cfg.input_height, recon_buff_size.width, recon_buff_size.height); + + ioctl_msg.in = NULL; + ioctl_msg.out = (void*)&recon_buff_size; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_GET_RECON_BUFFER_SIZE, (void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("VEN_IOCTL_GET_RECON_BUFFER_SIZE Failed for width: %d, Height %d" , + recon_buff_size.width, recon_buff_size.height); + return OMX_ErrorInsufficientResources; + } + + DEBUG_PRINT_HIGH("Width %d, Height %d, w_round %d, h_round %d, yuv_size %d alignment %d count %d", + m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, recon_buff_size.width, + recon_buff_size.height, recon_buff_size.size, recon_buff_size.alignment, + recon_buffers_count); + + for (int i = 0; i < recon_buffers_count; i++) { + if (pmem_allocate(recon_buff_size.size, recon_buff_size.alignment,i)) { + DEBUG_PRINT_ERROR("Error returned in allocating recon buffers"); + return -1; + } + } + + return 0; +} +OMX_U32 venc_dev::pmem_allocate(OMX_U32 size, OMX_U32 alignment, OMX_U32 count) +{ + OMX_U32 pmem_fd = -1; + OMX_U32 width, height; + void *buf_addr = NULL; + struct venc_ioctl_msg ioctl_msg; + struct venc_recon_addr recon_addr; + int rc = 0; + +#ifdef USE_ION + recon_buff[count].ion_device_fd = open (MEM_DEVICE,O_RDONLY); + + if (recon_buff[count].ion_device_fd < 0) { + DEBUG_PRINT_ERROR("ERROR: ION Device open() Failed"); + return -1; + } + + recon_buff[count].alloc_data.len = size; +#ifdef MAX_RES_720P + recon_buff[count].alloc_data.heap_id_mask = ION_HEAP(MEM_HEAP_ID); +#else + recon_buff[count].alloc_data.heap_id_mask = (ION_HEAP(MEM_HEAP_ID) | + ION_HEAP(ION_IOMMU_HEAP_ID)); +#endif + recon_buff[count].alloc_data.flags = ION_FLAG_CACHED; + recon_buff[count].alloc_data.align = clip2(alignment); + + if (recon_buff[count].alloc_data.align != 8192) + recon_buff[count].alloc_data.align = 8192; + + rc = ioctl(recon_buff[count].ion_device_fd,ION_IOC_ALLOC,&recon_buff[count].alloc_data); + + if (rc || !recon_buff[count].alloc_data.handle) { + DEBUG_PRINT_ERROR("ION ALLOC memory failed "); + recon_buff[count].alloc_data.handle=NULL; + return -1; + } + + recon_buff[count].ion_alloc_fd.handle = recon_buff[count].alloc_data.handle; + rc = ioctl(recon_buff[count].ion_device_fd,ION_IOC_MAP,&recon_buff[count].ion_alloc_fd); + + if (rc) { + DEBUG_PRINT_ERROR("ION MAP failed "); + recon_buff[count].ion_alloc_fd.fd =-1; + recon_buff[count].ion_alloc_fd.fd =-1; + return -1; + } + + pmem_fd = recon_buff[count].ion_alloc_fd.fd; +#else + struct pmem_allocation allocation; + pmem_fd = open(MEM_DEVICE, O_RDWR); + + if ((int)(pmem_fd) < 0) { + DEBUG_PRINT_ERROR("Failed to get an pmem handle"); + return -1; + } + + allocation.size = size; + allocation.align = clip2(alignment); + + if (allocation.align != 8192) + allocation.align = 8192; + + if (ioctl(pmem_fd, PMEM_ALLOCATE_ALIGNED, &allocation) < 0) { + DEBUG_PRINT_ERROR("Aligment(%u) failed with pmem driver Sz(%lu)", + allocation.align, allocation.size); + return -1; + } + +#endif + buf_addr = mmap(NULL, size, + PROT_READ | PROT_WRITE, + MAP_SHARED, pmem_fd, 0); + + if (buf_addr == (void*) MAP_FAILED) { + close(pmem_fd); + pmem_fd = -1; + DEBUG_PRINT_ERROR("Error returned in allocating recon buffers buf_addr: %p",buf_addr); +#ifdef USE_ION + + if (ioctl(recon_buff[count].ion_device_fd,ION_IOC_FREE, + &recon_buff[count].alloc_data.handle)) { + DEBUG_PRINT_LOW("ion recon buffer free failed"); + } + + recon_buff[count].alloc_data.handle = NULL; + recon_buff[count].ion_alloc_fd.fd =-1; + close(recon_buff[count].ion_device_fd); + recon_buff[count].ion_device_fd =-1; +#endif + return -1; + } + + DEBUG_PRINT_HIGH("Allocated virt:%p, FD: %d of size %d", buf_addr, pmem_fd, size); + + recon_addr.buffer_size = size; + recon_addr.pmem_fd = pmem_fd; + recon_addr.offset = 0; + recon_addr.pbuffer = (unsigned char *)buf_addr; + + ioctl_msg.in = (void*)&recon_addr; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_RECON_BUFFER, (void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("Failed to set the Recon_buffers"); + return -1; + } + + recon_buff[count].virtual_address = (unsigned char *) buf_addr; + recon_buff[count].size = size; + recon_buff[count].offset = 0; + recon_buff[count].pmem_fd = pmem_fd; + + DEBUG_PRINT_ERROR("Allocated virt:%p, FD: %d of size %d at index: %d", recon_buff[count].virtual_address, + recon_buff[count].pmem_fd, recon_buff[count].size, count); + return 0; +} + +OMX_U32 venc_dev::pmem_free() +{ + int cnt = 0; + struct venc_ioctl_msg ioctl_msg; + struct venc_recon_addr recon_addr; + + for (cnt = 0; cnt < recon_buffers_count; cnt++) { + if (recon_buff[cnt].pmem_fd) { + recon_addr.pbuffer = recon_buff[cnt].virtual_address; + recon_addr.offset = recon_buff[cnt].offset; + recon_addr.pmem_fd = recon_buff[cnt].pmem_fd; + recon_addr.buffer_size = recon_buff[cnt].size; + ioctl_msg.in = (void*)&recon_addr; + ioctl_msg.out = NULL; + + if (ioctl(m_nDriver_fd, VEN_IOCTL_FREE_RECON_BUFFER ,&ioctl_msg) < 0) + DEBUG_PRINT_ERROR("VEN_IOCTL_FREE_RECON_BUFFER failed"); + + munmap(recon_buff[cnt].virtual_address, recon_buff[cnt].size); + close(recon_buff[cnt].pmem_fd); +#ifdef USE_ION + + if (ioctl(recon_buff[cnt].ion_device_fd,ION_IOC_FREE, + &recon_buff[cnt].alloc_data.handle)) { + DEBUG_PRINT_LOW("ion recon buffer free failed"); + } + + recon_buff[cnt].alloc_data.handle = NULL; + recon_buff[cnt].ion_alloc_fd.fd =-1; + close(recon_buff[cnt].ion_device_fd); + recon_buff[cnt].ion_device_fd =-1; +#endif + DEBUG_PRINT_LOW("cleaning Index %d of size %d",cnt,recon_buff[cnt].size); + recon_buff[cnt].pmem_fd = -1; + recon_buff[cnt].virtual_address = NULL; + recon_buff[cnt].offset = 0; + recon_buff[cnt].alignment = 0; + recon_buff[cnt].size = 0; + } + } + + return 0; +} +#endif + +void venc_dev::venc_config_print() +{ + + DEBUG_PRINT_HIGH("ENC_CONFIG: Codec: %d, Profile %d, level : %d", + m_sVenc_cfg.codectype, codec_profile.profile, profile_level.level); + + DEBUG_PRINT_HIGH("ENC_CONFIG: Width: %d, Height:%d, Fps: %d", + m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, + m_sVenc_cfg.fps_num/m_sVenc_cfg.fps_den); + + DEBUG_PRINT_HIGH("ENC_CONFIG: Bitrate: %d, RC: %d, I-Period: %d", + bitrate.target_bitrate, rate_ctrl.rcmode, intra_period.num_pframes); + + DEBUG_PRINT_HIGH("ENC_CONFIG: qpI: %d, qpP: %d, qpb: 0", + session_qp.iframeqp, session_qp.pframqp); + + DEBUG_PRINT_HIGH("ENC_CONFIG: minQP: %d, maxQP: %d", + qp_range.minqp, qp_range.maxqp); + + DEBUG_PRINT_HIGH("ENC_CONFIG: VOP_Resolution: %d, Slice-Mode: %d, Slize_Size: %d", + voptimecfg.voptime_resolution, multislice.mslice_mode, + multislice.mslice_size); + + DEBUG_PRINT_HIGH("ENC_CONFIG: EntropyMode: %d, CabacModel: %d", + entropy.longentropysel, entropy.cabacmodel); + + DEBUG_PRINT_HIGH("ENC_CONFIG: DB-Mode: %d, alpha: %d, Beta: %d", + dbkfilter.db_mode, dbkfilter.slicealpha_offset, + dbkfilter.slicebeta_offset); + + DEBUG_PRINT_HIGH("ENC_CONFIG: IntraMB/Frame: %d, HEC: %d", + intra_refresh.mbcount, hec.header_extension); +} + +unsigned venc_dev::venc_flush( unsigned port) +{ + struct venc_ioctl_msg ioctl_msg; + struct venc_bufferflush buffer_index; + + if (port == PORT_INDEX_IN) { + DEBUG_PRINT_HIGH("Calling Input Flush"); + buffer_index.flush_mode = VEN_FLUSH_INPUT; + ioctl_msg.in = (void*)&buffer_index; + ioctl_msg.out = NULL; + + return ioctl (m_nDriver_fd,VEN_IOCTL_CMD_FLUSH,(void*)&ioctl_msg); + } else if (port == PORT_INDEX_OUT) { + DEBUG_PRINT_HIGH("Calling Output Flush"); + buffer_index.flush_mode = VEN_FLUSH_OUTPUT; + ioctl_msg.in = (void*)&buffer_index; + ioctl_msg.out = NULL; + return ioctl (m_nDriver_fd,VEN_IOCTL_CMD_FLUSH,(void*)&ioctl_msg); + } else { + return -1; + } +} + +//allocating I/P memory from pmem and register with the device + + +bool venc_dev::venc_use_buf(void *buf_addr, unsigned port,unsigned) +{ + struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; + struct pmem *pmem_tmp; + struct venc_bufferpayload dev_buffer = {0}; + struct venc_allocatorproperty buff_alloc_property = {0}; + + pmem_tmp = (struct pmem *)buf_addr; + + DEBUG_PRINT_LOW("venc_use_buf:: pmem_tmp = %p", pmem_tmp); + + if (port == PORT_INDEX_IN) { + dev_buffer.pbuffer = (OMX_U8 *)pmem_tmp->buffer; + dev_buffer.fd = pmem_tmp->fd; + dev_buffer.maped_size = pmem_tmp->size; + dev_buffer.sz = pmem_tmp->size; + dev_buffer.offset = pmem_tmp->offset; + + if ((m_sVenc_cfg.input_height %16 !=0) || (m_sVenc_cfg.input_width%16 != 0)) { + unsigned long ht = m_sVenc_cfg.input_height; + unsigned long wd = m_sVenc_cfg.input_width; + unsigned int luma_size, luma_size_2k; + + ht = (ht + 15) & ~15; + wd = (wd + 15) & ~15; + + luma_size = ht * wd; + luma_size_2k = (luma_size + 2047) & ~2047; + + dev_buffer.sz = luma_size_2k + ((luma_size/2 + 2047) & ~2047); +#ifdef USE_ION + ioctl_msg.in = NULL; + ioctl_msg.out = (void*)&buff_alloc_property; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_GET_INPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: venc_use_buf:get input buffer failed "); + return false; + } + + if (buff_alloc_property.alignment < 4096) { + dev_buffer.sz = ((dev_buffer.sz + 4095) & ~4095); + } else { + dev_buffer.sz = ((dev_buffer.sz + (buff_alloc_property.alignment - 1)) & + ~(buff_alloc_property.alignment - 1)); + } + +#endif + dev_buffer.maped_size = dev_buffer.sz; + } + + ioctl_msg.in = (void*)&dev_buffer; + ioctl_msg.out = NULL; + + DEBUG_PRINT_LOW("venc_use_buf:pbuffer = %x,fd = %x, offset = %d, maped_size = %d", \ + dev_buffer.pbuffer, \ + dev_buffer.fd, \ + dev_buffer.offset, \ + dev_buffer.maped_size); + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_INPUT_BUFFER,&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: venc_use_buf:set input buffer failed "); + return false; + } + } else if (port == PORT_INDEX_OUT) { + dev_buffer.pbuffer = (OMX_U8 *)pmem_tmp->buffer; + dev_buffer.fd = pmem_tmp->fd; + dev_buffer.sz = pmem_tmp->size; + dev_buffer.maped_size = pmem_tmp->size; + dev_buffer.offset = pmem_tmp->offset; + ioctl_msg.in = (void*)&dev_buffer; + ioctl_msg.out = NULL; + + DEBUG_PRINT_LOW("venc_use_buf:pbuffer = %x,fd = %x, offset = %d, maped_size = %d", \ + dev_buffer.pbuffer, \ + dev_buffer.fd, \ + dev_buffer.offset, \ + dev_buffer.maped_size); + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_OUTPUT_BUFFER,&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: venc_use_buf:set output buffer failed "); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: venc_use_buf:Invalid Port Index "); + return false; + } + + return true; +} + +bool venc_dev::venc_free_buf(void *buf_addr, unsigned port) +{ + struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; + struct pmem *pmem_tmp; + struct venc_bufferpayload dev_buffer = {0}; + + pmem_tmp = (struct pmem *)buf_addr; + + DEBUG_PRINT_LOW("venc_use_buf:: pmem_tmp = %p", pmem_tmp); + + if (port == PORT_INDEX_IN) { + dev_buffer.pbuffer = (OMX_U8 *)pmem_tmp->buffer; + dev_buffer.fd = pmem_tmp->fd; + dev_buffer.maped_size = pmem_tmp->size; + dev_buffer.sz = pmem_tmp->size; + dev_buffer.offset = pmem_tmp->offset; + ioctl_msg.in = (void*)&dev_buffer; + ioctl_msg.out = NULL; + + DEBUG_PRINT_LOW("venc_free_buf:pbuffer = %x,fd = %x, offset = %d, maped_size = %d", \ + dev_buffer.pbuffer, \ + dev_buffer.fd, \ + dev_buffer.offset, \ + dev_buffer.maped_size); + + if (ioctl (m_nDriver_fd,VEN_IOCTL_CMD_FREE_INPUT_BUFFER,&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: venc_free_buf: free input buffer failed "); + return false; + } + } else if (port == PORT_INDEX_OUT) { + dev_buffer.pbuffer = (OMX_U8 *)pmem_tmp->buffer; + dev_buffer.fd = pmem_tmp->fd; + dev_buffer.sz = pmem_tmp->size; + dev_buffer.maped_size = pmem_tmp->size; + dev_buffer.offset = pmem_tmp->offset; + ioctl_msg.in = (void*)&dev_buffer; + ioctl_msg.out = NULL; + + DEBUG_PRINT_LOW("venc_free_buf:pbuffer = %x,fd = %x, offset = %d, maped_size = %d", \ + dev_buffer.pbuffer, \ + dev_buffer.fd, \ + dev_buffer.offset, \ + dev_buffer.maped_size); + + if (ioctl (m_nDriver_fd,VEN_IOCTL_CMD_FREE_OUTPUT_BUFFER,&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: venc_free_buf: free output buffer failed "); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: venc_free_buf:Invalid Port Index "); + return false; + } + + return true; +} + +bool venc_dev::venc_color_align(OMX_BUFFERHEADERTYPE *buffer, + OMX_U32 width, OMX_U32 height) +{ + DEBUG_PRINT_ERROR("%s not implemented!", __func__); + return OMX_ErrorUnsupportedSetting; +} + +bool venc_dev::venc_empty_buf(void *buffer, void *pmem_data_buf,unsigned,unsigned) +{ + struct venc_buffer frameinfo; + struct pmem *temp_buffer; + struct venc_ioctl_msg ioctl_msg; + struct OMX_BUFFERHEADERTYPE *bufhdr; + + if (buffer == NULL) { + DEBUG_PRINT_ERROR("ERROR: venc_etb: buffer is NULL"); + return false; + } + + bufhdr = (OMX_BUFFERHEADERTYPE *)buffer; + + DEBUG_PRINT_LOW("Input buffer length %d",bufhdr->nFilledLen); + + if (pmem_data_buf) { + DEBUG_PRINT_LOW("Internal PMEM addr for i/p Heap UseBuf: %p", pmem_data_buf); + frameinfo.ptrbuffer = (OMX_U8 *)pmem_data_buf; + } else { + DEBUG_PRINT_LOW("Shared PMEM addr for i/p PMEM UseBuf/AllocateBuf: %p", bufhdr->pBuffer); + frameinfo.ptrbuffer = (OMX_U8 *)bufhdr->pBuffer; + } + + frameinfo.clientdata = (void *) buffer; + frameinfo.sz = bufhdr->nFilledLen; + frameinfo.len = bufhdr->nFilledLen; + frameinfo.flags = bufhdr->nFlags; + frameinfo.offset = bufhdr->nOffset; + frameinfo.timestamp = bufhdr->nTimeStamp; + DEBUG_PRINT_LOW("i/p TS = %u", (OMX_U32)frameinfo.timestamp); + ioctl_msg.in = &frameinfo; + ioctl_msg.out = NULL; + + DEBUG_PRINT_LOW("DBG: i/p frameinfo: bufhdr->pBuffer = %p, ptrbuffer = %p, offset = %u, len = %u", + bufhdr->pBuffer, frameinfo.ptrbuffer, frameinfo.offset, frameinfo.len); + + if (ioctl(m_nDriver_fd,VEN_IOCTL_CMD_ENCODE_FRAME,&ioctl_msg) < 0) { + /*Generate an async error and move to invalid state*/ + return false; + } + + if (m_debug.in_buffer_log) { + venc_input_log_buffers(bufhdr, pmem_data_bufr, frameinfo.len); + } + + return true; +} +bool venc_dev::venc_fill_buf(void *buffer, void *pmem_data_buf,unsigned,unsigned) +{ + struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; + struct pmem *temp_buffer = NULL; + struct venc_buffer frameinfo; + struct OMX_BUFFERHEADERTYPE *bufhdr; + + if (buffer == NULL) { + return false; + } + + bufhdr = (OMX_BUFFERHEADERTYPE *)buffer; + + if (pmem_data_buf) { + DEBUG_PRINT_LOW("Internal PMEM addr for o/p Heap UseBuf: %p", pmem_data_buf); + frameinfo.ptrbuffer = (OMX_U8 *)pmem_data_buf; + } else { + DEBUG_PRINT_LOW("Shared PMEM addr for o/p PMEM UseBuf/AllocateBuf: %p", bufhdr->pBuffer); + frameinfo.ptrbuffer = (OMX_U8 *)bufhdr->pBuffer; + } + + frameinfo.clientdata = buffer; + frameinfo.sz = bufhdr->nAllocLen; + frameinfo.flags = bufhdr->nFlags; + frameinfo.offset = bufhdr->nOffset; + + ioctl_msg.in = &frameinfo; + ioctl_msg.out = NULL; + DEBUG_PRINT_LOW("DBG: o/p frameinfo: bufhdr->pBuffer = %p, ptrbuffer = %p, offset = %u, len = %u", + bufhdr->pBuffer, frameinfo.ptrbuffer, frameinfo.offset, frameinfo.len); + + if (ioctl (m_nDriver_fd,VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER,&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: ioctl VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER failed"); + return false; + } + + return true; +} + +bool venc_dev::venc_set_slice_delivery_mode(OMX_BOOL enable) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + DEBUG_PRINT_HIGH("Set slice_delivery_mode: %d", enable); + + if (multislice.mslice_mode == VEN_MSLICE_CNT_MB) { + if (ioctl(m_nDriver_fd, VEN_IOCTL_SET_SLICE_DELIVERY_MODE) < 0) { + DEBUG_PRINT_ERROR("Request for setting slice delivery mode failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("WARNING: slice_mode[%d] is not VEN_MSLICE_CNT_MB to set " + "slice delivery mode to the driver.", multislice.mslice_mode); + } + + return true; +} + +bool venc_dev::venc_set_plusptype(OMX_BOOL enable) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + struct venc_plusptype plusptype = {0}; + DEBUG_PRINT_LOW("Set plusptype: %d", enable); + plusptype.plusptype_enable = enable; + ioctl_msg.in = (void*)&plusptype; + ioctl_msg.out = NULL; + + if (ioctl(m_nDriver_fd, VEN_IOCTL_SET_H263_PLUSPTYPE,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("Request for setting plusptype for h263 failed"); + return false; + } + + return true; +} + +bool venc_dev::venc_set_ltrmode(QOMX_VIDEO_LTRMODETYPE mode) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + venc_ltrmode ltr_mode; + ltr_mode.ltr_mode = (unsigned long)mode; + DEBUG_PRINT_HIGH("Set ltr mode: %d", mode); + ioctl_msg.in = (void*)<r_mode; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd, VEN_IOCTL_SET_LTRMODE, (void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Setting ltrmode failed"); + return false; + } + + ltrmode.ltr_mode = (unsigned long)mode; + return true; +} + +bool venc_dev::venc_set_ltrcount(OMX_U32 count) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + venc_ltrcount ltr_count; + ltr_count.ltr_count = (unsigned long)count; + DEBUG_PRINT_HIGH("Set ltr count: %d", count); + ioctl_msg.in = (void*)<r_count; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd, VEN_IOCTL_SET_LTRCOUNT, (void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Setting ltrcount failed"); + return false; + } + + ltrcount.ltr_count = (unsigned long)count; + return true; +} + +bool venc_dev::venc_set_ltrperiod(OMX_U32 period) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + venc_ltrperiod ltr_period; + ltr_period.ltr_period = (unsigned long)period; + DEBUG_PRINT_HIGH("Set ltr period: %d", period); + ioctl_msg.in = (void*)<r_period; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd, VEN_IOCTL_SET_LTRPERIOD, (void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Setting ltrperiod failed"); + return false; + } + + ltrperiod.ltr_period = (unsigned long)period; + return true; +} + +bool venc_dev::venc_set_ltruse(OMX_U32 id, OMX_U32 frames) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + venc_ltruse ltr_use; + ltr_use.ltr_id = (unsigned long)id; + ltr_use.ltr_frames = (unsigned long)frames; + DEBUG_PRINT_HIGH("Set ltr use: id = %d, ltr_frames = %d", id, frames); + ioctl_msg.in = (void*)<r_use; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd, VEN_IOCTL_SET_LTRUSE, (void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Setting ltruse failed"); + return false; + } + + return true; +} + +bool venc_dev::venc_set_extradata(OMX_U32 extra_data) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + DEBUG_PRINT_HIGH("venc_set_extradata:: %x", extra_data); + ioctl_msg.in = (void*)&extra_data; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd, VEN_IOCTL_SET_EXTRADATA, (void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting extradata failed"); + return false; + } + + return true; +} + +bool venc_dev::venc_set_session_qp(OMX_U32 i_frame_qp, OMX_U32 p_frame_qp) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + struct venc_sessionqp qp = {0, 0}; + DEBUG_PRINT_HIGH("venc_set_session_qp:: i_frame_qp = %d, p_frame_qp = %d", i_frame_qp, + p_frame_qp); + + qp.iframeqp = i_frame_qp; + qp.pframqp = p_frame_qp; + + ioctl_msg.in = (void*)&qp; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_SESSION_QP,(void*)&ioctl_msg)< 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting session qp failed"); + return false; + } + + session_qp.iframeqp = i_frame_qp; + session_qp.pframqp = p_frame_qp; + + return true; +} + +bool venc_dev::venc_set_qp_range(OMX_U32 min_qp, OMX_U32 max_qp) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + struct venc_qprange qp = {0, 0}; + DEBUG_PRINT_LOW("venc_set_qp_range:: min_qp = %d, max_qp = %d", min_qp, + max_qp); + + qp.minqp = min_qp; + qp.maxqp = max_qp; + + ioctl_msg.in = (void*)&qp; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_QP_RANGE,(void*)&ioctl_msg)< 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting qp range failed"); + return false; + } + + qp_range.minqp= min_qp; + qp_range.maxqp= max_qp; + + return true; +} + +bool venc_dev::venc_set_profile_level(OMX_U32 eProfile,OMX_U32 eLevel) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + struct venc_profile requested_profile; + struct ven_profilelevel requested_level; + unsigned const int *profile_tbl = NULL; + unsigned long mb_per_frame = 0, mb_per_sec = 0; + DEBUG_PRINT_HIGH("venc_set_profile_level:: eProfile = %d, Level = %d", + eProfile, eLevel); + mb_per_frame = ((m_sVenc_cfg.input_height + 15) >> 4)* + ((m_sVenc_cfg.input_width + 15) >> 4); + + if ((eProfile == 0) && (eLevel == 0) && m_profile_set && m_level_set) { + DEBUG_PRINT_HIGH("Set profile/level was done already"); + return true; + } + + if (eProfile && eLevel) { + /* non-zero values will be set by user, saving the same*/ + m_eProfile = eProfile; + m_eLevel = eLevel; + DEBUG_PRINT_HIGH("Save profile/level (%d/%d) for max allowed bitrate check", + m_eProfile, m_eLevel); + } + + DEBUG_PRINT_LOW("Validating Profile/Level from table"); + + if (!venc_validate_profile_level(&eProfile, &eLevel)) { + DEBUG_PRINT_LOW("ERROR: Profile/Level validation failed"); + return false; + } + + if (m_sVenc_cfg.codectype == VEN_CODEC_MPEG4) { + DEBUG_PRINT_LOW("eProfile = %d, OMX_VIDEO_MPEG4ProfileSimple = %d and " + "OMX_VIDEO_MPEG4ProfileAdvancedSimple = %d", eProfile, + OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4ProfileAdvancedSimple); + + if (eProfile == OMX_VIDEO_MPEG4ProfileSimple) { + requested_profile.profile = VEN_PROFILE_MPEG4_SP; + profile_tbl = (unsigned int const *) + (&mpeg4_profile_level_table[MPEG4_SP_START]); + profile_tbl += MPEG4_720P_LEVEL*5; + } else if (eProfile == OMX_VIDEO_MPEG4ProfileAdvancedSimple) { + requested_profile.profile = VEN_PROFILE_MPEG4_ASP; + profile_tbl = (unsigned int const *) + (&mpeg4_profile_level_table[MPEG4_ASP_START]); + profile_tbl += MPEG4_720P_LEVEL*5; + } else { + DEBUG_PRINT_LOW("ERROR: Unsupported MPEG4 profile = %u", + eProfile); + return false; + } + + DEBUG_PRINT_LOW("eLevel = %d, OMX_VIDEO_MPEG4Level0 = %d, OMX_VIDEO_MPEG4Level1 = %d," + "OMX_VIDEO_MPEG4Level2 = %d, OMX_VIDEO_MPEG4Level3 = %d, OMX_VIDEO_MPEG4Level4 = %d," + "OMX_VIDEO_MPEG4Level5 = %d", eLevel, OMX_VIDEO_MPEG4Level0, OMX_VIDEO_MPEG4Level1, + OMX_VIDEO_MPEG4Level2, OMX_VIDEO_MPEG4Level3, OMX_VIDEO_MPEG4Level4, OMX_VIDEO_MPEG4Level5); + + if (mb_per_frame >= 3600) { + if (requested_profile.profile == VEN_PROFILE_MPEG4_ASP) + requested_level.level = VEN_LEVEL_MPEG4_5; + + if (requested_profile.profile == VEN_PROFILE_MPEG4_SP) + requested_level.level = VEN_LEVEL_MPEG4_6; + } else { + switch (eLevel) { + case OMX_VIDEO_MPEG4Level0: + requested_level.level = VEN_LEVEL_MPEG4_0; + break; + case OMX_VIDEO_MPEG4Level1: + requested_level.level = VEN_LEVEL_MPEG4_1; + break; + case OMX_VIDEO_MPEG4Level2: + requested_level.level = VEN_LEVEL_MPEG4_2; + break; + case OMX_VIDEO_MPEG4Level3: + requested_level.level = VEN_LEVEL_MPEG4_3; + break; + case OMX_VIDEO_MPEG4Level4a: + requested_level.level = VEN_LEVEL_MPEG4_4; + break; + case OMX_VIDEO_MPEG4Level5: + mb_per_sec = mb_per_frame * (m_sVenc_cfg.fps_num / m_sVenc_cfg.fps_den); + + if ((requested_profile.profile == VEN_PROFILE_MPEG4_SP) && (mb_per_frame >= profile_tbl[0]) && + (mb_per_sec >= profile_tbl[1])) { + DEBUG_PRINT_LOW("MPEG4 Level 6 is set for 720p resolution"); + requested_level.level = VEN_LEVEL_MPEG4_6; + } else { + DEBUG_PRINT_LOW("MPEG4 Level 5 is set for non-720p resolution"); + requested_level.level = VEN_LEVEL_MPEG4_5; + } + + break; + default: + return false; + // TODO update corresponding levels for MPEG4_LEVEL_3b,MPEG4_LEVEL_6 + break; + } + } + } else if (m_sVenc_cfg.codectype == VEN_CODEC_H263) { + if (eProfile == OMX_VIDEO_H263ProfileBaseline) { + requested_profile.profile = VEN_PROFILE_H263_BASELINE; + } else { + DEBUG_PRINT_LOW("ERROR: Unsupported H.263 profile = %u", + requested_profile.profile); + return false; + } + + //profile level + switch (eLevel) { + case OMX_VIDEO_H263Level10: + requested_level.level = VEN_LEVEL_H263_10; + break; + case OMX_VIDEO_H263Level20: + requested_level.level = VEN_LEVEL_H263_20; + break; + case OMX_VIDEO_H263Level30: + requested_level.level = VEN_LEVEL_H263_30; + break; + case OMX_VIDEO_H263Level40: + requested_level.level = VEN_LEVEL_H263_40; + break; + case OMX_VIDEO_H263Level45: + requested_level.level = VEN_LEVEL_H263_45; + break; + case OMX_VIDEO_H263Level50: + requested_level.level = VEN_LEVEL_H263_50; + break; + case OMX_VIDEO_H263Level60: + requested_level.level = VEN_LEVEL_H263_60; + break; + case OMX_VIDEO_H263Level70: + requested_level.level = VEN_LEVEL_H263_70; + break; + default: + return false; + break; + } + } else if (m_sVenc_cfg.codectype == VEN_CODEC_H264) { + if (eProfile == OMX_VIDEO_AVCProfileBaseline) { + requested_profile.profile = VEN_PROFILE_H264_BASELINE; + } else if (eProfile == OMX_VIDEO_AVCProfileMain) { + requested_profile.profile = VEN_PROFILE_H264_MAIN; + } else if (eProfile == OMX_VIDEO_AVCProfileHigh) { + requested_profile.profile = VEN_PROFILE_H264_HIGH; + } else { + DEBUG_PRINT_LOW("ERROR: Unsupported H.264 profile = %u", + requested_profile.profile); + return false; + } + + //profile level + switch (eLevel) { + case OMX_VIDEO_AVCLevel1: + requested_level.level = VEN_LEVEL_H264_1; + break; + case OMX_VIDEO_AVCLevel1b: + requested_level.level = VEN_LEVEL_H264_1b; + break; + case OMX_VIDEO_AVCLevel11: + requested_level.level = VEN_LEVEL_H264_1p1; + break; + case OMX_VIDEO_AVCLevel12: + requested_level.level = VEN_LEVEL_H264_1p2; + break; + case OMX_VIDEO_AVCLevel13: + requested_level.level = VEN_LEVEL_H264_1p3; + break; + case OMX_VIDEO_AVCLevel2: + requested_level.level = VEN_LEVEL_H264_2; + break; + case OMX_VIDEO_AVCLevel21: + requested_level.level = VEN_LEVEL_H264_2p1; + break; + case OMX_VIDEO_AVCLevel22: + requested_level.level = VEN_LEVEL_H264_2p2; + break; + case OMX_VIDEO_AVCLevel3: + requested_level.level = VEN_LEVEL_H264_3; + break; + case OMX_VIDEO_AVCLevel31: + requested_level.level = VEN_LEVEL_H264_3p1; + break; + case OMX_VIDEO_AVCLevel32: + requested_level.level = VEN_LEVEL_H264_3p2; + break; + case OMX_VIDEO_AVCLevel4: + requested_level.level = VEN_LEVEL_H264_4; + break; + default : + DEBUG_PRINT_ERROR("ERROR: Unsupported H.264 level= %u", + requested_level.level); + return false; + break; + } + } + + if (!m_profile_set) { + ioctl_msg.in = (void*)&requested_profile; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_CODEC_PROFILE,(void*)&ioctl_msg)< 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting profile failed"); + return false; + } + + codec_profile.profile = requested_profile.profile; + m_profile_set = true; + DEBUG_PRINT_HIGH("Set codec profile = 0x%x", codec_profile.profile); + } + + if (!m_level_set) { + ioctl_msg.in = (void*)&requested_level; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_PROFILE_LEVEL,(void*)&ioctl_msg)< 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting profile level failed"); + return false; + } + + profile_level.level = requested_level.level; + m_level_set = true; + DEBUG_PRINT_HIGH("Set codec level = 0x%x", profile_level.level); + } + + return true; +} + +bool venc_dev::venc_set_voptiming_cfg( OMX_U32 TimeIncRes) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + struct venc_voptimingcfg vop_timing_cfg; + + DEBUG_PRINT_HIGH("venc_set_voptiming_cfg: TimeRes = %u", + TimeIncRes); + + vop_timing_cfg.voptime_resolution = TimeIncRes; + + ioctl_msg.in = (void*)&vop_timing_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_VOP_TIMING_CFG,(void*)&ioctl_msg)< 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting Vop Timing failed"); + return false; + } + + voptimecfg.voptime_resolution = vop_timing_cfg.voptime_resolution; + return true; +} + +bool venc_dev::venc_set_intra_period(OMX_U32 nPFrames, OMX_U32 nBFrames) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + struct venc_intraperiod intraperiod_cfg; + + DEBUG_PRINT_LOW("venc_set_intra_period: nPFrames = %u", + nPFrames); + intraperiod_cfg.num_pframes = nPFrames; + + if ((codec_profile.profile == VEN_PROFILE_MPEG4_ASP) || + (codec_profile.profile == VEN_PROFILE_H264_MAIN) || + (codec_profile.profile == VEN_PROFILE_H264_HIGH)) { +#ifdef MAX_RES_1080P + + if (nBFrames) { + DEBUG_PRINT_HIGH("INFO: Only 1 Bframe is supported"); + intraperiod_cfg.num_bframes = 1; + } else + intraperiod_cfg.num_bframes = 0; + +#else + + if (nBFrames) { + DEBUG_PRINT_ERROR("B frames not supported"); + intraperiod_cfg.num_bframes = 0; + } else { + DEBUG_PRINT_ERROR("B frames not supported"); + intraperiod_cfg.num_bframes = 0; + } + +#endif + } else + intraperiod_cfg.num_bframes = 0; + + DEBUG_PRINT_HIGH("venc_set_intra_period: nPFrames = %u nBFrames = %u", + intraperiod_cfg.num_pframes, intraperiod_cfg.num_bframes); + ioctl_msg.in = (void*)&intraperiod_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_INTRA_PERIOD,(void*)&ioctl_msg)< 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting intra period failed"); + return false; + } + + intra_period.num_pframes = intraperiod_cfg.num_pframes; + intra_period.num_bframes = intraperiod_cfg.num_bframes; + return true; +} + +bool venc_dev::venc_set_entropy_config(OMX_BOOL enable, OMX_U32 i_cabac_level) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + struct venc_entropycfg entropy_cfg; + + memset(&entropy_cfg,0,sizeof(entropy_cfg)); + DEBUG_PRINT_LOW("venc_set_entropy_config: CABAC = %u level: %u", enable, i_cabac_level); + + if (enable &&(codec_profile.profile != VEN_PROFILE_H264_BASELINE)) { + entropy_cfg.longentropysel = VEN_ENTROPY_MODEL_CABAC; + + if (i_cabac_level == 0) { + entropy_cfg.cabacmodel = VEN_CABAC_MODEL_0; + } + +#ifdef MAX_RES_1080P + else { + DEBUG_PRINT_HIGH("Invalid model set (%d) defaulting to model 0",i_cabac_level); + entropy_cfg.cabacmodel = VEN_CABAC_MODEL_0; + } + +#else + else if (i_cabac_level == 1) { + entropy_cfg.cabacmodel = VEN_CABAC_MODEL_1; + } else if (i_cabac_level == 2) { + entropy_cfg.cabacmodel = VEN_CABAC_MODEL_2; + } + +#endif + } else if (!enable) { + entropy_cfg.longentropysel = VEN_ENTROPY_MODEL_CAVLC; + } else { + DEBUG_PRINT_ERROR("Invalid Entropy mode for Baseline Profile"); + return false; + } + + ioctl_msg.in = (void*)&entropy_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_ENTROPY_CFG,(void*)&ioctl_msg)< 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting entropy config failed"); + return false; + } + + entropy.longentropysel = entropy_cfg.longentropysel; + entropy.cabacmodel = entropy_cfg.cabacmodel; + return true; +} + +bool venc_dev::venc_set_multislice_cfg(OMX_INDEXTYPE Codec, OMX_U32 nSlicesize) // MB +{ + venc_ioctl_msg ioctl_msg = {NULL, NULL}; + bool status = true; + struct venc_multiclicecfg multislice_cfg; + + if ((Codec != OMX_IndexParamVideoH263) && (nSlicesize)) { + multislice_cfg.mslice_mode = VEN_MSLICE_CNT_MB; + multislice_cfg.mslice_size = nSlicesize; + } else { + multislice_cfg.mslice_mode = VEN_MSLICE_OFF; + multislice_cfg.mslice_size = 0; + } + + DEBUG_PRINT_LOW("%s(): mode = %u, size = %u", __func__, multislice_cfg.mslice_mode, + multislice_cfg.mslice_size); + + ioctl_msg.in = (void*)&multislice_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd, VEN_IOCTL_SET_MULTI_SLICE_CFG,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting multi-slice cfg failed"); + status = false; + } else { + multislice.mslice_mode = multislice_cfg.mslice_mode; + multislice.mslice_size = nSlicesize; + } + + return status; +} + +bool venc_dev::venc_set_intra_refresh(OMX_VIDEO_INTRAREFRESHTYPE ir_mode, OMX_U32 irMBs) +{ + venc_ioctl_msg ioctl_msg = {NULL, NULL}; + bool status = true; + struct venc_intrarefresh intraRefresh_cfg; + + // There is no disabled mode. Disabled mode is indicated by a 0 count. + if (irMBs == 0 || ir_mode == OMX_VIDEO_IntraRefreshMax) { + intraRefresh_cfg.irmode = VEN_IR_OFF; + intraRefresh_cfg.mbcount = 0; + } else if ((ir_mode == OMX_VIDEO_IntraRefreshCyclic) && + (irMBs < ((m_sVenc_cfg.input_width * m_sVenc_cfg.input_height)>>8))) { + intraRefresh_cfg.irmode = VEN_IR_CYCLIC; + intraRefresh_cfg.mbcount = irMBs; + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid IntraRefresh Parameters:" + "mb count: %d, mb mode:%d", irMBs, ir_mode); + return false; + } + + ioctl_msg.in = (void*)&intraRefresh_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_INTRA_REFRESH,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting Intra Refresh failed"); + status = false; + } else { + intra_refresh.irmode = intraRefresh_cfg.irmode; + intra_refresh.mbcount = intraRefresh_cfg.mbcount; + } + + return status; +} + +bool venc_dev::venc_set_error_resilience(OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE* error_resilience) +{ + venc_ioctl_msg ioctl_msg = {NULL, NULL}; + bool status = true; + struct venc_headerextension hec_cfg; + struct venc_multiclicecfg multislice_cfg; + + if (m_sVenc_cfg.codectype == OMX_VIDEO_CodingMPEG4) { + if (error_resilience->bEnableHEC) { + hec_cfg.header_extension = 1; + } else { + hec_cfg.header_extension = 0; + } + + ioctl_msg.in = (void*)&hec_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_HEC,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting HEader Error correction failed"); + return false; + } + + hec.header_extension = error_resilience->bEnableHEC; + } + + if (error_resilience->bEnableRVLC) { + DEBUG_PRINT_ERROR("RVLC is not Supported"); + return false; + } + + if (( m_sVenc_cfg.codectype != OMX_VIDEO_CodingH263) && + (error_resilience->bEnableDataPartitioning)) { + DEBUG_PRINT_ERROR("DataPartioning are not Supported for MPEG4/H264"); + return false; + } + + if (( m_sVenc_cfg.codectype != OMX_VIDEO_CodingH263) && + (error_resilience->nResynchMarkerSpacing)) { + multislice_cfg.mslice_mode = VEN_MSLICE_CNT_BYTE; + multislice_cfg.mslice_size = error_resilience->nResynchMarkerSpacing; + } else if (m_sVenc_cfg.codectype == OMX_VIDEO_CodingH263 && + error_resilience->bEnableDataPartitioning) { + multislice_cfg.mslice_mode = VEN_MSLICE_GOB; + multislice_cfg.mslice_size = 0; + } else { + multislice_cfg.mslice_mode = VEN_MSLICE_OFF; + multislice_cfg.mslice_size = 0; + } + + DEBUG_PRINT_LOW("%s(): mode = %u, size = %u", __func__, multislice_cfg.mslice_mode, + multislice_cfg.mslice_size); + ioctl_msg.in = (void*)&multislice_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_MULTI_SLICE_CFG,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting multi-slice cfg failed"); + status = false; + } else { + multislice.mslice_mode = multislice_cfg.mslice_mode ; + multislice.mslice_size = multislice_cfg.mslice_size; + + } + + return status; +} + +bool venc_dev::venc_set_inloop_filter(OMX_VIDEO_AVCLOOPFILTERTYPE loopfilter) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + struct venc_dbcfg filter_cfg; + + memset(&filter_cfg, 0, sizeof(filter_cfg)); + DEBUG_PRINT_LOW("venc_set_inloop_filter: %u",loopfilter); + + if (loopfilter == OMX_VIDEO_AVCLoopFilterEnable) { + filter_cfg.db_mode = VEN_DB_ALL_BLKG_BNDRY; + } else if (loopfilter == OMX_VIDEO_AVCLoopFilterDisable) { + filter_cfg.db_mode = VEN_DB_DISABLE; + } else if (loopfilter == OMX_VIDEO_AVCLoopFilterDisableSliceBoundary) { + filter_cfg.db_mode = VEN_DB_SKIP_SLICE_BNDRY; + } + + filter_cfg.slicealpha_offset = filter_cfg.slicebeta_offset = 0; + + ioctl_msg.in = (void*)&filter_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_DEBLOCKING_CFG,(void*)&ioctl_msg)< 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting inloop filter failed"); + return false; + } + + dbkfilter.db_mode = filter_cfg.db_mode; + dbkfilter.slicealpha_offset = dbkfilter.slicebeta_offset = 0; + return true; +} + +bool venc_dev::venc_set_target_bitrate(OMX_U32 nTargetBitrate, OMX_U32 config) +{ + venc_ioctl_msg ioctl_msg = {NULL, NULL}; + struct venc_targetbitrate bitrate_cfg; + + DEBUG_PRINT_HIGH("venc_set_target_bitrate: bitrate = %u", + nTargetBitrate); + bitrate_cfg.target_bitrate = nTargetBitrate ; + ioctl_msg.in = (void*)&bitrate_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_TARGET_BITRATE,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting bit rate failed"); + return false; + } + + m_sVenc_cfg.targetbitrate = nTargetBitrate; + bitrate.target_bitrate = nTargetBitrate; + + if (!config) { + m_level_set = false; + + if (venc_set_profile_level(0, 0)) { + DEBUG_PRINT_LOW("Calling set level (Bitrate) with %d",profile_level.level); + } + } + + return true; +} + +bool venc_dev::venc_set_encode_framerate(OMX_U32 encode_framerate, OMX_U32 config) +{ + venc_ioctl_msg ioctl_msg = {NULL, NULL}; + struct venc_framerate frame_rate_cfg; + + Q16ToFraction(encode_framerate,frame_rate_cfg.fps_numerator,frame_rate_cfg.fps_denominator); + + DEBUG_PRINT_HIGH("venc_set_encode_framerate: framerate(Q16) = %u, NR: %d, DR: %d", + encode_framerate,frame_rate_cfg.fps_numerator,frame_rate_cfg.fps_denominator); + + ioctl_msg.in = (void*)&frame_rate_cfg; + ioctl_msg.out = NULL; + + if (ioctl(m_nDriver_fd, VEN_IOCTL_SET_FRAME_RATE, + (void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting framerate failed"); + return false; + } + + m_sVenc_cfg.fps_den = frame_rate_cfg.fps_denominator; + m_sVenc_cfg.fps_num = frame_rate_cfg.fps_numerator; + + if (!config) { + m_level_set = false; + + if (venc_set_profile_level(0, 0)) { + DEBUG_PRINT_LOW("Calling set level (Framerate) with %d",profile_level.level); + } + } + + return true; +} + +bool venc_dev::venc_set_color_format(OMX_COLOR_FORMATTYPE color_format) +{ + venc_ioctl_msg ioctl_msg = {NULL, NULL}; + + if (color_format == OMX_COLOR_FormatYUV420SemiPlanar) { +#ifdef MAX_RES_1080P + m_sVenc_cfg.inputformat= VEN_INPUTFMT_NV12_16M2KA; +#else + m_sVenc_cfg.inputformat = VEN_INPUTFMT_NV12; +#endif + } else { + DEBUG_PRINT_ERROR("WARNING: Unsupported Color format [%d]", color_format); +#ifdef MAX_RES_1080P + m_sVenc_cfg.inputformat= VEN_INPUTFMT_NV12_16M2KA; +#else + m_sVenc_cfg.inputformat = VEN_INPUTFMT_NV12; +#endif + DEBUG_PRINT_HIGH("Default color format YUV420SemiPlanar is set"); + } + + ioctl_msg.in = (void*)&m_sVenc_cfg; + ioctl_msg.out = NULL; + + if (ioctl(m_nDriver_fd, VEN_IOCTL_SET_BASE_CFG, (void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting color format failed"); + return false; + } + + return true; +} + +bool venc_dev::venc_set_intra_vop_refresh(OMX_BOOL intra_vop_refresh) +{ + DEBUG_PRINT_LOW("venc_set_intra_vop_refresh: intra_vop = %uc", intra_vop_refresh); + + if (intra_vop_refresh == OMX_TRUE) { + if (ioctl(m_nDriver_fd, VEN_IOCTL_CMD_REQUEST_IFRAME, NULL) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting Intra VOP Refresh failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: VOP Refresh is False, no effect"); + } + + return true; +} + +bool venc_dev::venc_set_ratectrl_cfg(OMX_VIDEO_CONTROLRATETYPE eControlRate) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + bool status = true; + struct venc_ratectrlcfg ratectrl_cfg; + + //rate control + switch (eControlRate) { + case OMX_Video_ControlRateDisable: + ratectrl_cfg.rcmode = VEN_RC_OFF; + break; + case OMX_Video_ControlRateVariableSkipFrames: + ratectrl_cfg.rcmode = VEN_RC_VBR_VFR; + break; + case OMX_Video_ControlRateVariable: + ratectrl_cfg.rcmode = VEN_RC_VBR_CFR; + break; + case OMX_Video_ControlRateConstantSkipFrames: + ratectrl_cfg.rcmode = VEN_RC_CBR_VFR; + break; + case OMX_Video_ControlRateConstant: + ratectrl_cfg.rcmode = VEN_RC_CBR_CFR; + break; + default: + status = false; + break; + } + + if (status) { + ioctl_msg.in = (void*)&ratectrl_cfg; + ioctl_msg.out = NULL; + + if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_RATE_CTRL_CFG,(void*)&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Request for setting rate control failed"); + status = false; + } else + rate_ctrl.rcmode = ratectrl_cfg.rcmode; + } + + return status; +} + +bool venc_dev::venc_get_profile_level(OMX_U32 *eProfile,OMX_U32 *eLevel) +{ + bool status = true; + + if (eProfile == NULL || eLevel == NULL) { + return false; + } + + if (m_sVenc_cfg.codectype == VEN_CODEC_MPEG4) { + switch (codec_profile.profile) { + case VEN_PROFILE_MPEG4_SP: + *eProfile = OMX_VIDEO_MPEG4ProfileSimple; + break; + case VEN_PROFILE_MPEG4_ASP: + *eProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple; + break; + default: + *eProfile = OMX_VIDEO_MPEG4ProfileMax; + status = false; + break; + } + + if (!status) { + return status; + } + + //profile level + switch (profile_level.level) { + case VEN_LEVEL_MPEG4_0: + *eLevel = OMX_VIDEO_MPEG4Level0; + break; + case VEN_LEVEL_MPEG4_1: + *eLevel = OMX_VIDEO_MPEG4Level1; + break; + case VEN_LEVEL_MPEG4_2: + *eLevel = OMX_VIDEO_MPEG4Level2; + break; + case VEN_LEVEL_MPEG4_3: + *eLevel = OMX_VIDEO_MPEG4Level3; + break; + case VEN_LEVEL_MPEG4_4: + *eLevel = OMX_VIDEO_MPEG4Level4a; + break; + case VEN_LEVEL_MPEG4_5: + case VEN_LEVEL_MPEG4_6: + *eLevel = OMX_VIDEO_MPEG4Level5; + break; + default: + *eLevel = OMX_VIDEO_MPEG4LevelMax; + status = false; + break; + } + } else if (m_sVenc_cfg.codectype == VEN_CODEC_H263) { + if (codec_profile.profile == VEN_PROFILE_H263_BASELINE) { + *eProfile = OMX_VIDEO_H263ProfileBaseline; + } else { + *eProfile = OMX_VIDEO_H263ProfileMax; + return false; + } + + switch (profile_level.level) { + case VEN_LEVEL_H263_10: + *eLevel = OMX_VIDEO_H263Level10; + break; + case VEN_LEVEL_H263_20: + *eLevel = OMX_VIDEO_H263Level20; + break; + case VEN_LEVEL_H263_30: + *eLevel = OMX_VIDEO_H263Level30; + break; + case VEN_LEVEL_H263_40: + *eLevel = OMX_VIDEO_H263Level40; + break; + case VEN_LEVEL_H263_45: + *eLevel = OMX_VIDEO_H263Level45; + break; + case VEN_LEVEL_H263_50: + *eLevel = OMX_VIDEO_H263Level50; + break; + case VEN_LEVEL_H263_60: + *eLevel = OMX_VIDEO_H263Level60; + break; + case VEN_LEVEL_H263_70: + *eLevel = OMX_VIDEO_H263Level70; + break; + default: + *eLevel = OMX_VIDEO_H263LevelMax; + status = false; + break; + } + } else if (m_sVenc_cfg.codectype == VEN_CODEC_H264) { + switch (codec_profile.profile) { + case VEN_PROFILE_H264_BASELINE: + *eProfile = OMX_VIDEO_AVCProfileBaseline; + break; + case VEN_PROFILE_H264_MAIN: + *eProfile = OMX_VIDEO_AVCProfileMain; + break; + case VEN_PROFILE_H264_HIGH: + *eProfile = OMX_VIDEO_AVCProfileHigh; + break; + default: + *eProfile = OMX_VIDEO_AVCProfileMax; + status = false; + break; + } + + if (!status) { + return status; + } + + switch (profile_level.level) { + case VEN_LEVEL_H264_1: + *eLevel = OMX_VIDEO_AVCLevel1; + break; + case VEN_LEVEL_H264_1b: + *eLevel = OMX_VIDEO_AVCLevel1b; + break; + case VEN_LEVEL_H264_1p1: + *eLevel = OMX_VIDEO_AVCLevel11; + break; + case VEN_LEVEL_H264_1p2: + *eLevel = OMX_VIDEO_AVCLevel12; + break; + case VEN_LEVEL_H264_1p3: + *eLevel = OMX_VIDEO_AVCLevel13; + break; + case VEN_LEVEL_H264_2: + *eLevel = OMX_VIDEO_AVCLevel2; + break; + case VEN_LEVEL_H264_2p1: + *eLevel = OMX_VIDEO_AVCLevel21; + break; + case VEN_LEVEL_H264_2p2: + *eLevel = OMX_VIDEO_AVCLevel22; + break; + case VEN_LEVEL_H264_3: + *eLevel = OMX_VIDEO_AVCLevel3; + break; + case VEN_LEVEL_H264_3p1: + *eLevel = OMX_VIDEO_AVCLevel31; + break; + case VEN_LEVEL_H264_3p2: + *eLevel = OMX_VIDEO_AVCLevel32; + break; + case VEN_LEVEL_H264_4: + *eLevel = OMX_VIDEO_AVCLevel4; + break; + default : + *eLevel = OMX_VIDEO_AVCLevelMax; + status = false; + break; + } + } + + return status; +} + +bool venc_dev::venc_validate_profile_level(OMX_U32 *eProfile, OMX_U32 *eLevel) +{ + OMX_U32 new_profile = 0, new_level = 0; + unsigned const int *profile_tbl = NULL; + OMX_U32 mb_per_frame, mb_per_sec; + bool profile_level_found = false; + + DEBUG_PRINT_LOW("Init profile table for respective codec"); + + //validate the ht,width,fps,bitrate and set the appropriate profile and level + if (m_sVenc_cfg.codectype == VEN_CODEC_MPEG4) { + if (*eProfile == 0) { + if (!m_profile_set) { + *eProfile = OMX_VIDEO_MPEG4ProfileSimple; + } else { + switch (codec_profile.profile) { + case VEN_PROFILE_MPEG4_ASP: + *eProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple; + break; + case VEN_PROFILE_MPEG4_SP: + *eProfile = OMX_VIDEO_MPEG4ProfileSimple; + break; + default: + DEBUG_PRINT_LOW("%s(): Unknown Error", __func__); + return false; + } + } + } + + if (*eLevel == 0 && !m_level_set) { + *eLevel = OMX_VIDEO_MPEG4LevelMax; + } + + if (*eProfile == OMX_VIDEO_MPEG4ProfileSimple) { + profile_tbl = (unsigned int const *)mpeg4_profile_level_table; + } else if (*eProfile == OMX_VIDEO_MPEG4ProfileAdvancedSimple) { + profile_tbl = (unsigned int const *) + (&mpeg4_profile_level_table[MPEG4_ASP_START]); + } else { + DEBUG_PRINT_LOW("Unsupported MPEG4 profile type %lu", *eProfile); + return false; + } + } else if (m_sVenc_cfg.codectype == VEN_CODEC_H264) { + if (*eProfile == 0) { + if (!m_profile_set) { + *eProfile = OMX_VIDEO_AVCProfileBaseline; + } else { + switch (codec_profile.profile) { + case VEN_PROFILE_H264_BASELINE: + *eProfile = OMX_VIDEO_AVCProfileBaseline; + break; +#ifndef _MSM8610_ + case VEN_PROFILE_H264_MAIN: + *eProfile = OMX_VIDEO_AVCProfileMain; + break; + case VEN_PROFILE_H264_HIGH: + *eProfile = OMX_VIDEO_AVCProfileHigh; + break; +#endif + default: + DEBUG_PRINT_LOW("%s(): Unsupported profile %x", __func__, codec_profile.profile); + return false; + } + } + } + + if (*eLevel == 0 && !m_level_set) { + *eLevel = OMX_VIDEO_AVCLevelMax; + } + + if (*eProfile == OMX_VIDEO_AVCProfileBaseline) { + profile_tbl = (unsigned int const *)h264_profile_level_table; + } else if (*eProfile == OMX_VIDEO_AVCProfileHigh) { + profile_tbl = (unsigned int const *) + (&h264_profile_level_table[H264_HP_START]); + } else if (*eProfile == OMX_VIDEO_AVCProfileMain) { + profile_tbl = (unsigned int const *) + (&h264_profile_level_table[H264_MP_START]); + } else { + DEBUG_PRINT_LOW("Unsupported AVC profile type %lu", *eProfile); + return false; + } + } else if (m_sVenc_cfg.codectype == VEN_CODEC_H263) { + if (*eProfile == 0) { + if (!m_profile_set) { + *eProfile = OMX_VIDEO_H263ProfileBaseline; + } else { + switch (codec_profile.profile) { + case VEN_PROFILE_H263_BASELINE: + *eProfile = OMX_VIDEO_H263ProfileBaseline; + break; + default: + DEBUG_PRINT_LOW("%s(): Unknown Error", __func__); + return false; + } + } + } + + if (*eLevel == 0 && !m_level_set) { + *eLevel = OMX_VIDEO_H263LevelMax; + } + + if (*eProfile == OMX_VIDEO_H263ProfileBaseline) { + profile_tbl = (unsigned int const *)h263_profile_level_table; + } else { + DEBUG_PRINT_LOW("Unsupported H.263 profile type %lu", *eProfile); + return false; + } + } else { + DEBUG_PRINT_LOW("Invalid codec type"); + return false; + } + + mb_per_frame = ((m_sVenc_cfg.input_height + 15) >> 4)* + ((m_sVenc_cfg.input_width + 15)>> 4); + + if ((mb_per_frame >= 3600) && (m_sVenc_cfg.codectype == VEN_CODEC_MPEG4)) { + if (codec_profile.profile == VEN_PROFILE_MPEG4_ASP) + profile_level.level = VEN_LEVEL_MPEG4_5; + + if (codec_profile.profile == VEN_PROFILE_MPEG4_SP) + profile_level.level = VEN_LEVEL_MPEG4_6; + + { + new_level = profile_level.level; + new_profile = codec_profile.profile; + return true; + } + } + + mb_per_sec = mb_per_frame * m_sVenc_cfg.fps_num / m_sVenc_cfg.fps_den; + + do { + if (mb_per_frame <= (int)profile_tbl[0]) { + if (mb_per_sec <= (int)profile_tbl[1]) { + if (m_sVenc_cfg.targetbitrate <= (int)profile_tbl[2]) { + new_level = (int)profile_tbl[3]; + new_profile = (int)profile_tbl[4]; + profile_level_found = true; + DEBUG_PRINT_LOW("Appropriate profile/level found %d/%d", new_profile, new_level); + break; + } + } + } + + profile_tbl = profile_tbl + 5; + } while (profile_tbl[0] != 0); + + if (profile_level_found != true) { + DEBUG_PRINT_LOW("ERROR: Unsupported profile/level"); + return false; + } + + if ((*eLevel == OMX_VIDEO_MPEG4LevelMax) || (*eLevel == OMX_VIDEO_AVCLevelMax) + || (*eLevel == OMX_VIDEO_H263LevelMax)) { + *eLevel = new_level; + } + + DEBUG_PRINT_LOW("%s: Returning with eProfile = %lu" + "Level = %lu", __func__, *eProfile, *eLevel); + + return true; +} + +bool venc_dev::venc_max_allowed_bitrate_check(OMX_U32 nTargetBitrate) +{ + unsigned const int *profile_tbl = NULL; + + switch (m_sVenc_cfg.codectype) { + case VEN_CODEC_MPEG4: + + if (m_eProfile == OMX_VIDEO_MPEG4ProfileSimple) { + profile_tbl = (unsigned int const *)mpeg4_profile_level_table; + } else if (m_eProfile == OMX_VIDEO_MPEG4ProfileAdvancedSimple) { + profile_tbl = (unsigned int const *) + (&mpeg4_profile_level_table[MPEG4_ASP_START]); + } else { + DEBUG_PRINT_ERROR("Unsupported MPEG4 profile type %lu", m_eProfile); + return false; + } + + break; + case VEN_CODEC_H264: + + if (m_eProfile == OMX_VIDEO_AVCProfileBaseline) { + profile_tbl = (unsigned int const *)h264_profile_level_table; + } else if (m_eProfile == OMX_VIDEO_AVCProfileHigh) { + profile_tbl = (unsigned int const *) + (&h264_profile_level_table[H264_HP_START]); + } else if (m_eProfile == OMX_VIDEO_AVCProfileMain) { + profile_tbl = (unsigned int const *) + (&h264_profile_level_table[H264_MP_START]); + } else { + DEBUG_PRINT_ERROR("Unsupported AVC profile type %lu", m_eProfile); + return false; + } + + break; + case VEN_CODEC_H263: + + if (m_eProfile == OMX_VIDEO_H263ProfileBaseline) { + profile_tbl = (unsigned int const *)h263_profile_level_table; + } else { + DEBUG_PRINT_ERROR("Unsupported H.263 profile type %lu", m_eProfile); + return false; + } + + break; + default: + DEBUG_PRINT_ERROR("%s: unknown codec type", __func__); + return false; + } + + while (profile_tbl[0] != 0) { + if (profile_tbl[3] == m_eLevel) { + if (nTargetBitrate > profile_tbl[2]) { + DEBUG_PRINT_ERROR("Max. supported bitrate for Profile[%d] & Level[%d]" + " is %u", m_eProfile, m_eLevel, profile_tbl[2]); + return false; + } + } + + profile_tbl += 5; + } + + return true; +} + +#ifdef _ANDROID_ICS_ +bool venc_dev::venc_set_meta_mode(bool mode) +{ + venc_ioctl_msg ioctl_msg = {NULL,NULL}; + ioctl_msg.in = &mode; + DEBUG_PRINT_HIGH("Set meta buffer mode: %d", mode); + + if (ioctl(m_nDriver_fd,VEN_IOCTL_SET_METABUFFER_MODE,&ioctl_msg) < 0) { + DEBUG_PRINT_ERROR(" Set meta buffer mode failed"); + return false; + } + + return true; +} +#endif diff --git a/msm8998/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp b/msm8998/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp new file mode 100644 index 0000000..73e7cf7 --- /dev/null +++ b/msm8998/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp @@ -0,0 +1,8086 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2010-2016, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. +--------------------------------------------------------------------------*/ + +#include <string.h> +#include <sys/ioctl.h> +#include <sys/prctl.h> +#include <sys/eventfd.h> +#include <unistd.h> +#include <fcntl.h> +#include "video_encoder_device_v4l2.h" +#include "omx_video_encoder.h" +#include <media/msm_vidc.h> +#ifdef USE_ION +#include <linux/msm_ion.h> +#endif +#include <math.h> +#include <media/msm_media_info.h> +#include <cutils/properties.h> +#include <media/hardware/HardwareAPI.h> + +#ifdef _ANDROID_ +#include <media/hardware/HardwareAPI.h> +#include <gralloc_priv.h> +#endif + +#include <qdMetaData.h> + +#define ATRACE_TAG ATRACE_TAG_VIDEO +#include <utils/Trace.h> + +#define YUV_STATS_LIBRARY_NAME "libgpustats.so" // UBWC case: use GPU library + +#define ALIGN(x, to_align) ((((unsigned long) x) + (to_align - 1)) & ~(to_align - 1)) +#define EXTRADATA_IDX(__num_planes) ((__num_planes) ? (__num_planes) - 1 : 0) +#define MAXDPB 16 +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) +#define ROUND(__sz, __align) (((__sz) + ((__align>>1))) & (~(__align-1))) +#define MAX_PROFILE_PARAMS 6 +#define MPEG4_SP_START 0 +#define MPEG4_ASP_START (MPEG4_SP_START + 10) +#define H263_BP_START 0 +#define HEVC_MAIN_START 0 +#define HEVC_MAIN10_START (HEVC_MAIN_START + 13) +#define POLL_TIMEOUT 1000 +#define MAX_SUPPORTED_SLICES_PER_FRAME 28 /* Max supported slices with 32 output buffers */ + +#define SZ_4K 0x1000 +#define SZ_1M 0x100000 + +/* MPEG4 profile and level table*/ +static const unsigned int mpeg4_profile_level_table[][MAX_PROFILE_PARAMS]= { + /*max mb per frame, max mb per sec, max bitrate, level, profile, dpbmbs*/ + {99,1485,64000,OMX_VIDEO_MPEG4Level0,OMX_VIDEO_MPEG4ProfileSimple,0}, + {99,1485,64000,OMX_VIDEO_MPEG4Level1,OMX_VIDEO_MPEG4ProfileSimple,0}, + {396,5940,128000,OMX_VIDEO_MPEG4Level2,OMX_VIDEO_MPEG4ProfileSimple,0}, + {396,11880,384000,OMX_VIDEO_MPEG4Level3,OMX_VIDEO_MPEG4ProfileSimple,0}, + {1200,36000,4000000,OMX_VIDEO_MPEG4Level4a,OMX_VIDEO_MPEG4ProfileSimple,0}, + {1620,40500,8000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileSimple,0}, + {3600,108000,12000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileSimple,0}, + {32400,972000,20000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileSimple,0}, + {34560,1036800,20000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileSimple,0}, + /* Please update MPEG4_ASP_START accordingly, while adding new element */ + {0,0,0,0,0,0}, + + {99,1485,128000,OMX_VIDEO_MPEG4Level0,OMX_VIDEO_MPEG4ProfileAdvancedSimple,0}, + {99,1485,128000,OMX_VIDEO_MPEG4Level1,OMX_VIDEO_MPEG4ProfileAdvancedSimple,0}, + {396,5940,384000,OMX_VIDEO_MPEG4Level2,OMX_VIDEO_MPEG4ProfileAdvancedSimple,0}, + {396,11880,768000,OMX_VIDEO_MPEG4Level3,OMX_VIDEO_MPEG4ProfileAdvancedSimple,0}, + {792,23760,3000000,OMX_VIDEO_MPEG4Level4,OMX_VIDEO_MPEG4ProfileAdvancedSimple,0}, + {1620,48600,8000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileAdvancedSimple,0}, + {32400,972000,20000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileAdvancedSimple,0}, + {34560,1036800,20000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileAdvancedSimple,0}, + {0,0,0,0,0,0}, +}; + +/* H264 profile and level table*/ +static const unsigned int h264_profile_level_table[][MAX_PROFILE_PARAMS]= { + /*max mb per frame, max mb per sec, max bitrate, profile, ignore for h264, dpbmbs*/ + {99,1485,64000,OMX_VIDEO_AVCLevel1,0,396}, + {99,1485,128000,OMX_VIDEO_AVCLevel1b,0,396}, + {396,3000,192000,OMX_VIDEO_AVCLevel11,0,900}, + {396,6000,384000,OMX_VIDEO_AVCLevel12,0,2376}, + {396,11880,768000,OMX_VIDEO_AVCLevel13,0,2376}, + {396,11880,2000000,OMX_VIDEO_AVCLevel2,0,2376}, + {792,19800,4000000,OMX_VIDEO_AVCLevel21,0,4752}, + {1620,20250,4000000,OMX_VIDEO_AVCLevel22,0,8100}, + {1620,40500,10000000,OMX_VIDEO_AVCLevel3,0,8100}, + {3600,108000,14000000,OMX_VIDEO_AVCLevel31,0,18000}, + {5120,216000,20000000,OMX_VIDEO_AVCLevel32,0,20480}, + {8192,245760,20000000,OMX_VIDEO_AVCLevel4,0,32768}, + {8192,245760,50000000,OMX_VIDEO_AVCLevel41,0,32768}, + {8704,522240,50000000,OMX_VIDEO_AVCLevel42,0,34816}, + {22080,589824,135000000,OMX_VIDEO_AVCLevel5,0,110400}, + {36864,983040,240000000,OMX_VIDEO_AVCLevel51,0,184320}, + {36864,2073600,240000000,OMX_VIDEO_AVCLevel52,0,184320}, + /* Please update H264_HP_START accordingly, while adding new element */ + {0,0,0,0,0,0}, +}; + +/* H263 profile and level table*/ +static const unsigned int h263_profile_level_table[][MAX_PROFILE_PARAMS]= { + /*max mb per frame, max mb per sec, max bitrate, level, profile, dpbmbs*/ + {99,1485,64000,OMX_VIDEO_H263Level10,OMX_VIDEO_H263ProfileBaseline,0}, + {396,5940,128000,OMX_VIDEO_H263Level20,OMX_VIDEO_H263ProfileBaseline,0}, + {396,11880,384000,OMX_VIDEO_H263Level30,OMX_VIDEO_H263ProfileBaseline,0}, + {396,11880,2048000,OMX_VIDEO_H263Level40,OMX_VIDEO_H263ProfileBaseline,0}, + {99,1485,128000,OMX_VIDEO_H263Level45,OMX_VIDEO_H263ProfileBaseline,0}, + {396,19800,4096000,OMX_VIDEO_H263Level50,OMX_VIDEO_H263ProfileBaseline,0}, + {810,40500,8192000,OMX_VIDEO_H263Level60,OMX_VIDEO_H263ProfileBaseline,0}, + {1620,81000,16384000,OMX_VIDEO_H263Level70,OMX_VIDEO_H263ProfileBaseline,0}, + {32400,972000,20000000,OMX_VIDEO_H263Level70,OMX_VIDEO_H263ProfileBaseline,0}, + {34560,1036800,20000000,OMX_VIDEO_H263Level70,OMX_VIDEO_H263ProfileBaseline,0}, + {0,0,0,0,0,0} +}; + +/* HEVC profile and level table*/ +static const unsigned int hevc_profile_level_table[][MAX_PROFILE_PARAMS]= { + /*max mb per frame, max mb per sec, max bitrate, level, ignore profile and dpbmbs for HEVC */ + {99,1485,128000,OMX_VIDEO_HEVCMainTierLevel1,0,0}, + {396,11880,1500000,OMX_VIDEO_HEVCMainTierLevel2,0,0}, + {900,27000,3000000,OMX_VIDEO_HEVCMainTierLevel21,0,0}, + {2025,60750,6000000,OMX_VIDEO_HEVCMainTierLevel3,0,0}, + {8640,259200,10000000,OMX_VIDEO_HEVCMainTierLevel31,0,0}, + {34560,1166400,12000000,OMX_VIDEO_HEVCMainTierLevel4,0,0}, + {138240,4147200,20000000,OMX_VIDEO_HEVCMainTierLevel41,0,0}, + {138240,8294400,25000000,OMX_VIDEO_HEVCMainTierLevel5,0,0}, + {138240,4147200,40000000,OMX_VIDEO_HEVCMainTierLevel51,0,0}, + {138240,4147200,50000000,OMX_VIDEO_HEVCHighTierLevel41,0,0}, + {138240,4147200,100000000,OMX_VIDEO_HEVCHighTierLevel5,0,0}, + {138240,4147200,160000000,OMX_VIDEO_HEVCHighTierLevel51,0,0}, + {138240,4147200,240000000,OMX_VIDEO_HEVCHighTierLevel52,0,0}, + /* Please update HEVC_MAIN_START accordingly, while adding new element */ + {0,0,0,0,0}, + +}; + + +#define Log2(number, power) { OMX_U32 temp = number; power = 0; while( (0 == (temp & 0x1)) && power < 16) { temp >>=0x1; power++; } } +#define Q16ToFraction(q,num,den) { OMX_U32 power; Log2(q,power); num = q >> power; den = 0x1 << (16 - power); } + +#define BUFFER_LOG_LOC "/data/misc/media" + +//constructor +venc_dev::venc_dev(class omx_venc *venc_class) +{ + //nothing to do + int i = 0; + venc_handle = venc_class; + etb = ebd = ftb = fbd = 0; + m_poll_efd = -1; + + struct v4l2_control control; + for (i = 0; i < MAX_PORT; i++) + streaming[i] = false; + + stopped = 1; + paused = false; + async_thread_created = false; + async_thread_force_stop = false; + color_format = 0; + hw_overload = false; + mBatchSize = 0; + deinterlace_enabled = false; + pthread_mutex_init(&pause_resume_mlock, NULL); + pthread_cond_init(&pause_resume_cond, NULL); + memset(&input_extradata_info, 0, sizeof(input_extradata_info)); + memset(&output_extradata_info, 0, sizeof(output_extradata_info)); + memset(&idrperiod, 0, sizeof(idrperiod)); + memset(&multislice, 0, sizeof(multislice)); + memset (&slice_mode, 0 , sizeof(slice_mode)); + memset(&m_sVenc_cfg, 0, sizeof(m_sVenc_cfg)); + memset(&rate_ctrl, 0, sizeof(rate_ctrl)); + memset(&bitrate, 0, sizeof(bitrate)); + memset(&intra_period, 0, sizeof(intra_period)); + memset(&codec_profile, 0, sizeof(codec_profile)); + memset(&set_param, 0, sizeof(set_param)); + memset(&time_inc, 0, sizeof(time_inc)); + memset(&m_sInput_buff_property, 0, sizeof(m_sInput_buff_property)); + memset(&m_sOutput_buff_property, 0, sizeof(m_sOutput_buff_property)); + memset(&session_qp, 0, sizeof(session_qp)); + memset(&session_ipb_qp_values, 0, sizeof(session_ipb_qp_values)); + memset(&entropy, 0, sizeof(entropy)); + memset(&dbkfilter, 0, sizeof(dbkfilter)); + memset(&intra_refresh, 0, sizeof(intra_refresh)); + memset(&hec, 0, sizeof(hec)); + memset(&voptimecfg, 0, sizeof(voptimecfg)); + memset(&capability, 0, sizeof(capability)); + memset(&m_debug,0,sizeof(m_debug)); + memset(&hier_layers,0,sizeof(hier_layers)); + is_searchrange_set = false; + enable_mv_narrow_searchrange = false; + supported_rc_modes = RC_ALL; + memset(&vqzip_sei_info, 0, sizeof(vqzip_sei_info)); + memset(<rinfo, 0, sizeof(ltrinfo)); + memset(&fd_list, 0, sizeof(fd_list)); + memset(&hybrid_hp, 0, sizeof(hybrid_hp)); + memset(&roi, 0, sizeof(roi)); + sess_priority.priority = 1; + operating_rate = 0; + low_latency_mode = OMX_FALSE; + memset(&color_space, 0x0, sizeof(color_space)); + memset(&temporal_layers_config, 0x0, sizeof(temporal_layers_config)); + + char property_value[PROPERTY_VALUE_MAX] = {0}; + property_get("vidc.enc.log.in", property_value, "0"); + m_debug.in_buffer_log = atoi(property_value); + + property_get("vidc.enc.log.out", property_value, "0"); + m_debug.out_buffer_log = atoi(property_value); + + property_get("vidc.enc.log.extradata", property_value, "0"); + m_debug.extradata_log = atoi(property_value); + +#ifdef _UBWC_ + property_get("debug.gralloc.gfx_ubwc_disable", property_value, "0"); + if(!(strncmp(property_value, "1", PROPERTY_VALUE_MAX)) || + !(strncmp(property_value, "true", PROPERTY_VALUE_MAX))) { + is_gralloc_source_ubwc = 0; + } else { + is_gralloc_source_ubwc = 1; + } +#else + is_gralloc_source_ubwc = 0; +#endif + + property_get("persist.vidc.enc.csc.enable", property_value, "0"); + if(!(strncmp(property_value, "1", PROPERTY_VALUE_MAX)) || + !(strncmp(property_value, "true", PROPERTY_VALUE_MAX))) { + is_csc_enabled = 1; + } else { + is_csc_enabled = 0; + } + +#ifdef _PQ_ + property_get("vidc.enc.disable.pq", property_value, "0"); + if(!(strncmp(property_value, "1", PROPERTY_VALUE_MAX)) || + !(strncmp(property_value, "true", PROPERTY_VALUE_MAX))) { + m_pq.is_pq_force_disable = 1; + } else { + m_pq.is_pq_force_disable = 0; + } +#endif // _PQ_ + + snprintf(m_debug.log_loc, PROPERTY_VALUE_MAX, + "%s", BUFFER_LOG_LOC); +} + +venc_dev::~venc_dev() +{ + //nothing to do +} + +void* venc_dev::async_venc_message_thread (void *input) +{ + struct venc_msg venc_msg; + omx_video* omx_venc_base = NULL; + omx_venc *omx = reinterpret_cast<omx_venc*>(input); + omx_venc_base = reinterpret_cast<omx_video*>(input); + OMX_BUFFERHEADERTYPE* omxhdr = NULL; + + prctl(PR_SET_NAME, (unsigned long)"VideoEncCallBackThread", 0, 0, 0); + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + struct pollfd pfds[2]; + struct v4l2_buffer v4l2_buf; + struct v4l2_event dqevent; + struct statistics stats; + pfds[0].events = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLRDBAND | POLLPRI; + pfds[1].events = POLLIN | POLLERR; + pfds[0].fd = omx->handle->m_nDriver_fd; + pfds[1].fd = omx->handle->m_poll_efd; + int error_code = 0,rc=0; + + memset(&stats, 0, sizeof(statistics)); + memset(&v4l2_buf, 0, sizeof(v4l2_buf)); + + while (!omx->handle->async_thread_force_stop) { + pthread_mutex_lock(&omx->handle->pause_resume_mlock); + + if (omx->handle->paused) { + venc_msg.msgcode = VEN_MSG_PAUSE; + venc_msg.statuscode = VEN_S_SUCCESS; + + if (omx->async_message_process(input, &venc_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Failed to process pause msg"); + pthread_mutex_unlock(&omx->handle->pause_resume_mlock); + break; + } + + /* Block here until the IL client resumes us again */ + pthread_cond_wait(&omx->handle->pause_resume_cond, + &omx->handle->pause_resume_mlock); + + venc_msg.msgcode = VEN_MSG_RESUME; + venc_msg.statuscode = VEN_S_SUCCESS; + + if (omx->async_message_process(input, &venc_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Failed to process resume msg"); + pthread_mutex_unlock(&omx->handle->pause_resume_mlock); + break; + } + memset(&stats, 0, sizeof(statistics)); + } + + pthread_mutex_unlock(&omx->handle->pause_resume_mlock); + + rc = poll(pfds, 2, POLL_TIMEOUT); + + if (!rc) { + DEBUG_PRINT_HIGH("Poll timedout, pipeline stalled due to client/firmware ETB: %d, EBD: %d, FTB: %d, FBD: %d", + omx->handle->etb, omx->handle->ebd, omx->handle->ftb, omx->handle->fbd); + continue; + } else if (rc < 0 && errno != EINTR && errno != EAGAIN) { + DEBUG_PRINT_ERROR("Error while polling: %d, errno = %d", rc, errno); + break; + } + + if ((pfds[1].revents & POLLIN) || (pfds[1].revents & POLLERR)) { + DEBUG_PRINT_ERROR("async_venc_message_thread interrupted to be exited"); + break; + } + + if ((pfds[0].revents & POLLIN) || (pfds[0].revents & POLLRDNORM)) { + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.length = omx->handle->num_output_planes; + v4l2_buf.m.planes = plane; + + while (!ioctl(pfds[0].fd, VIDIOC_DQBUF, &v4l2_buf)) { + venc_msg.msgcode=VEN_MSG_OUTPUT_BUFFER_DONE; + venc_msg.statuscode=VEN_S_SUCCESS; + omxhdr=omx_venc_base->m_out_mem_ptr+v4l2_buf.index; + venc_msg.buf.len= v4l2_buf.m.planes->bytesused; + venc_msg.buf.offset = v4l2_buf.m.planes->data_offset; + venc_msg.buf.flags = 0; + venc_msg.buf.ptrbuffer = (OMX_U8 *)omx_venc_base->m_pOutput_pmem[v4l2_buf.index].buffer; + venc_msg.buf.clientdata=(void*)omxhdr; + venc_msg.buf.timestamp = (uint64_t) v4l2_buf.timestamp.tv_sec * (uint64_t) 1000000 + (uint64_t) v4l2_buf.timestamp.tv_usec; + + /* TODO: ideally report other types of frames as well + * for now it doesn't look like IL client cares about + * other types + */ + if (v4l2_buf.flags & V4L2_QCOM_BUF_FLAG_IDRFRAME) + venc_msg.buf.flags |= QOMX_VIDEO_PictureTypeIDR; + + if (v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) + venc_msg.buf.flags |= OMX_BUFFERFLAG_SYNCFRAME; + + if (v4l2_buf.flags & V4L2_QCOM_BUF_FLAG_CODECCONFIG) + venc_msg.buf.flags |= OMX_BUFFERFLAG_CODECCONFIG; + + if (v4l2_buf.flags & V4L2_QCOM_BUF_FLAG_EOS) + venc_msg.buf.flags |= OMX_BUFFERFLAG_EOS; + + if (omx->handle->num_output_planes > 1 && v4l2_buf.m.planes->bytesused) + venc_msg.buf.flags |= OMX_BUFFERFLAG_EXTRADATA; + + if (omxhdr->nFilledLen) + venc_msg.buf.flags |= OMX_BUFFERFLAG_ENDOFFRAME; + + omx->handle->fbd++; + stats.bytes_generated += venc_msg.buf.len; + + if (omx->async_message_process(input,&venc_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Wrong ioctl message"); + break; + } + } + } + + if ((pfds[0].revents & POLLOUT) || (pfds[0].revents & POLLWRNORM)) { + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.m.planes = plane; + v4l2_buf.length = omx->handle->num_input_planes; + + while (!ioctl(pfds[0].fd, VIDIOC_DQBUF, &v4l2_buf)) { + venc_msg.msgcode=VEN_MSG_INPUT_BUFFER_DONE; + venc_msg.statuscode=VEN_S_SUCCESS; + omx->handle->ebd++; + + if (omx->handle->mBatchSize) { + int bufIndex = omx->handle->mBatchInfo.retrieveBufferAt(v4l2_buf.index); + if (bufIndex < 0) { + DEBUG_PRINT_ERROR("Retrieved invalid buffer %d", v4l2_buf.index); + break; + } + if (omx->handle->mBatchInfo.isPending(bufIndex)) { + DEBUG_PRINT_LOW(" EBD for %d [v4l2-id=%d].. batch still pending", + bufIndex, v4l2_buf.index); + //do not return to client yet + continue; + } + v4l2_buf.index = bufIndex; + } + if (omx_venc_base->mUseProxyColorFormat && !omx_venc_base->mUsesColorConversion) + omxhdr = &omx_venc_base->meta_buffer_hdr[v4l2_buf.index]; + else + omxhdr = &omx_venc_base->m_inp_mem_ptr[v4l2_buf.index]; + + venc_msg.buf.clientdata=(void*)omxhdr; + + DEBUG_PRINT_LOW("sending EBD %p [id=%d]", omxhdr, v4l2_buf.index); + if (omx->async_message_process(input,&venc_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Wrong ioctl message"); + break; + } + } + } + + if (pfds[0].revents & POLLPRI) { + rc = ioctl(pfds[0].fd, VIDIOC_DQEVENT, &dqevent); + + if (dqevent.type == V4L2_EVENT_MSM_VIDC_FLUSH_DONE) { + venc_msg.msgcode = VEN_MSG_FLUSH_INPUT_DONE; + venc_msg.statuscode = VEN_S_SUCCESS; + + if (omx->async_message_process(input,&venc_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Wrong ioctl message"); + break; + } + + venc_msg.msgcode = VEN_MSG_FLUSH_OUPUT_DONE; + venc_msg.statuscode = VEN_S_SUCCESS; + + if (omx->async_message_process(input,&venc_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Wrong ioctl message"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_HW_OVERLOAD) { + DEBUG_PRINT_ERROR("HW Overload received"); + venc_msg.statuscode = VEN_S_EFAIL; + venc_msg.msgcode = VEN_MSG_HW_OVERLOAD; + + if (omx->async_message_process(input,&venc_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Wrong ioctl message"); + break; + } + } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_SYS_ERROR){ + DEBUG_PRINT_ERROR("ERROR: Encoder is in bad state"); + venc_msg.msgcode = VEN_MSG_INDICATION; + venc_msg.statuscode=VEN_S_EFAIL; + + if (omx->async_message_process(input,&venc_msg) < 0) { + DEBUG_PRINT_ERROR("ERROR: Wrong ioctl message"); + break; + } + } + } + + /* calc avg. fps, bitrate */ + struct timeval tv; + gettimeofday(&tv,NULL); + OMX_U64 time_diff = (OMX_U32)((tv.tv_sec * 1000000 + tv.tv_usec) - + (stats.prev_tv.tv_sec * 1000000 + stats.prev_tv.tv_usec)); + if (time_diff >= 5000000) { + if (stats.prev_tv.tv_sec) { + OMX_U32 num_fbd = omx->handle->fbd - stats.prev_fbd; + float framerate = num_fbd * 1000000/(float)time_diff; + OMX_U32 bitrate = (stats.bytes_generated * 8/num_fbd) * framerate; + DEBUG_PRINT_HIGH("stats: avg. fps %0.2f, bitrate %d", + framerate, bitrate); + } + stats.prev_tv = tv; + stats.bytes_generated = 0; + stats.prev_fbd = omx->handle->fbd; + } + + } + + DEBUG_PRINT_HIGH("omx_venc: Async Thread exit"); + return NULL; +} + +static const int event_type[] = { + V4L2_EVENT_MSM_VIDC_FLUSH_DONE, + V4L2_EVENT_MSM_VIDC_SYS_ERROR +}; + +static OMX_ERRORTYPE subscribe_to_events(int fd) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_event_subscription sub; + int array_sz = sizeof(event_type)/sizeof(int); + int i,rc; + memset(&sub, 0, sizeof(sub)); + + if (fd < 0) { + DEBUG_PRINT_ERROR("Invalid input: %d", fd); + return OMX_ErrorBadParameter; + } + + for (i = 0; i < array_sz; ++i) { + memset(&sub, 0, sizeof(sub)); + sub.type = event_type[i]; + rc = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to subscribe event: 0x%x", sub.type); + break; + } + } + + if (i < array_sz) { + for (--i; i >=0 ; i--) { + memset(&sub, 0, sizeof(sub)); + sub.type = event_type[i]; + rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub); + + if (rc) + DEBUG_PRINT_ERROR("Failed to unsubscribe event: 0x%x", sub.type); + } + + eRet = OMX_ErrorNotImplemented; + } + + return eRet; +} + +int venc_dev::append_mbi_extradata(void *dst, struct msm_vidc_extradata_header* src) +{ + OMX_QCOM_EXTRADATA_MBINFO *mbi = (OMX_QCOM_EXTRADATA_MBINFO *)dst; + + if (!dst || !src) + return 0; + + /* TODO: Once Venus 3XX target names are known, nFormat should 2 for those + * targets, since the payload format will be different */ + mbi->nFormat = 2; + mbi->nDataSize = src->data_size; + memcpy(&mbi->data, &src->data, src->data_size); + + return mbi->nDataSize + sizeof(*mbi); +} + +bool venc_dev::handle_input_extradata(struct v4l2_buffer buf) +{ + OMX_OTHER_EXTRADATATYPE *p_extra = NULL; + unsigned int consumed_len = 0, index = 0; + int enable = 0, i = 0; + int height = 0, width = 0; + OMX_TICKS nTimeStamp = buf.timestamp.tv_sec * 1000000 + buf.timestamp.tv_usec; + int fd = buf.m.planes[0].reserved[0]; + bool unknown_extradata = false; + + if (!EXTRADATA_IDX(num_input_planes)) { + DEBUG_PRINT_LOW("Input extradata not enabled"); + return true; + } + + if (!input_extradata_info.uaddr) { + DEBUG_PRINT_ERROR("Extradata buffers not allocated\n"); + return false; + } + + /* + * At this point encoder component doesn't know where the extradata is + * located in YUV buffer. For all practical usecases, decoder appends + * extradata after nFilledLen which is calcualted as 32 aligned height + * and width * 3 / 2. Hence start looking for extradata from this point. + */ + + DEBUG_PRINT_HIGH("Processing Extradata for Buffer = %lld", nTimeStamp); // Useful for debugging + + height = ALIGN(m_sVenc_cfg.input_height, 32); + width = ALIGN(m_sVenc_cfg.input_width, 32); + + index = venc_get_index_from_fd(input_extradata_info.m_ion_dev,fd); + + unsigned char *pVirt; + int size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height); + pVirt= (unsigned char *)mmap(NULL, size, PROT_READ|PROT_WRITE,MAP_SHARED, fd, 0); + + p_extra = (OMX_OTHER_EXTRADATATYPE *) ((unsigned long)(pVirt + ((width * height * 3) / 2) + 3)&(~3)); + char *p_extradata = input_extradata_info.uaddr + index * input_extradata_info.buffer_size; + OMX_OTHER_EXTRADATATYPE *data = (struct OMX_OTHER_EXTRADATATYPE *)p_extradata; + memset((void *)(data), 0, (input_extradata_info.buffer_size)); // clear stale data in current buffer + if (p_extra) { + bool vqzip_sei_found = false; + + while ((consumed_len < input_extradata_info.buffer_size) + && (p_extra->eType != (OMX_EXTRADATATYPE)MSM_VIDC_EXTRADATA_NONE) + && !unknown_extradata) { + DEBUG_PRINT_LOW("Extradata Type = 0x%x", (OMX_QCOM_EXTRADATATYPE)p_extra->eType); + switch ((OMX_QCOM_EXTRADATATYPE)p_extra->eType) { + case OMX_ExtraDataFrameDimension: + { + struct msm_vidc_extradata_index *payload; + OMX_QCOM_EXTRADATA_FRAMEDIMENSION *framedimension_format; + data->nSize = (sizeof(OMX_OTHER_EXTRADATATYPE) + sizeof(struct msm_vidc_extradata_index) + 3)&(~3); + data->nVersion.nVersion = OMX_SPEC_VERSION; + data->nPortIndex = 0; + data->eType = (OMX_EXTRADATATYPE)MSM_VIDC_EXTRADATA_INDEX; + data->nDataSize = sizeof(struct msm_vidc_input_crop_payload); + framedimension_format = (OMX_QCOM_EXTRADATA_FRAMEDIMENSION *)p_extra->data; + payload = (struct msm_vidc_extradata_index *)(data->data); + payload->type = (msm_vidc_extradata_type)MSM_VIDC_EXTRADATA_INPUT_CROP; + payload->input_crop.left = framedimension_format->nDecWidth; + payload->input_crop.top = framedimension_format->nDecHeight; + payload->input_crop.width = framedimension_format->nActualWidth; + payload->input_crop.height = framedimension_format->nActualHeight; + DEBUG_PRINT_LOW("Height = %d Width = %d Actual Height = %d Actual Width = %d", + framedimension_format->nDecWidth, framedimension_format->nDecHeight, + framedimension_format->nActualWidth, framedimension_format->nActualHeight); + data = (OMX_OTHER_EXTRADATATYPE *)((char *)data + data->nSize); + break; + } + case OMX_ExtraDataQP: + { + OMX_QCOM_EXTRADATA_QP * qp_payload = NULL; + struct msm_vidc_frame_qp_payload *payload; + data->nSize = (sizeof(OMX_OTHER_EXTRADATATYPE) + sizeof(struct msm_vidc_frame_qp_payload) + 3)&(~3); + data->nVersion.nVersion = OMX_SPEC_VERSION; + data->nPortIndex = 0; + data->eType = (OMX_EXTRADATATYPE)MSM_VIDC_EXTRADATA_FRAME_QP; + data->nDataSize = sizeof(struct msm_vidc_frame_qp_payload); + qp_payload = (OMX_QCOM_EXTRADATA_QP *)p_extra->data; + payload = (struct msm_vidc_frame_qp_payload *)(data->data); + payload->frame_qp = qp_payload->nQP; + DEBUG_PRINT_LOW("Frame QP = %d", payload->frame_qp); + data = (OMX_OTHER_EXTRADATATYPE *)((char *)data + data->nSize); + break; + } + case OMX_ExtraDataVQZipSEI: + DEBUG_PRINT_LOW("VQZIP SEI Found "); + input_extradata_info.vqzip_sei_found = true; + break; + default: + unknown_extradata = true; + break; + } + if (!unknown_extradata) { + consumed_len += p_extra->nSize; + p_extra = (OMX_OTHER_EXTRADATATYPE *)((char *)p_extra + p_extra->nSize); + } else { + DEBUG_PRINT_HIGH(" Unknown Extradata. Exiting parsing "); + break; + } + } + + /* + * Below code is based on these points. + * 1) _PQ_ not defined : + * a) Send data to Venus as ROI. + * b) ROI enabled : Processed under unlocked context. + * c) ROI disabled : Nothing to fill. + * d) pq enabled : Not possible. + * 2) _PQ_ defined, but pq is not enabled : + * a) Send data to Venus as ROI. + * b) ROI enabled and dirty : Copy the data to Extradata buffer here + * b) ROI enabled and no dirty : Nothing to fill + * d) ROI disabled : Nothing to fill + * 3) _PQ_ defined and pq is enabled : + * a) Send data to Venus as PQ. + * b) ROI enabled and dirty : Copy the ROI contents to pq_roi buffer + * c) ROI enabled and no dirty : pq_roi is already memset. Hence nothing to do here + * d) ROI disabled : Just PQ data will be filled by GPU. + * 4) Normal ROI handling is in #else part as PQ can introduce delays. + * By this time if client sets next ROI, then we shouldn't process new ROI here. + */ + +#ifdef _PQ_ + pthread_mutex_lock(&m_pq.lock); + if (m_pq.is_pq_enabled) { + if (roi.dirty) { + struct msm_vidc_roi_qp_payload *roiData = + (struct msm_vidc_roi_qp_payload *)(m_pq.roi_extradata_info.uaddr); + roiData->upper_qp_offset = roi.info.nUpperQpOffset; + roiData->lower_qp_offset = roi.info.nLowerQpOffset; + roiData->b_roi_info = roi.info.bUseRoiInfo; + roiData->mbi_info_size = roi.info.nRoiMBInfoSize; + DEBUG_PRINT_HIGH("Using PQ + ROI QP map: Enable = %d", roiData->b_roi_info); + memcpy(roiData->data, roi.info.pRoiMBInfo, roi.info.nRoiMBInfoSize); + roi.dirty = false; + } + consumed_len += sizeof(msm_vidc_extradata_header) - sizeof(unsigned int); + data->nDataSize = m_pq.fill_pq_stats(buf, consumed_len); + data->nSize = ALIGN(sizeof(msm_vidc_extradata_header) + data->nDataSize, 4); + data->eType = (OMX_EXTRADATATYPE)MSM_VIDC_EXTRADATA_PQ_INFO; + } else { + data->nSize = ALIGN(sizeof(OMX_OTHER_EXTRADATATYPE) + + sizeof(struct msm_vidc_roi_qp_payload) + + roi.info.nRoiMBInfoSize - 2 * sizeof(unsigned int), 4); + data->nVersion.nVersion = OMX_SPEC_VERSION; + data->nPortIndex = 0; + data->eType = (OMX_EXTRADATATYPE)MSM_VIDC_EXTRADATA_ROI_QP; + data->nDataSize = sizeof(struct msm_vidc_roi_qp_payload); + + struct msm_vidc_roi_qp_payload *roiData = + (struct msm_vidc_roi_qp_payload *)(data->data); + roiData->upper_qp_offset = roi.info.nUpperQpOffset; + roiData->lower_qp_offset = roi.info.nLowerQpOffset; + roiData->b_roi_info = roi.info.bUseRoiInfo; + roiData->mbi_info_size = roi.info.nRoiMBInfoSize; + DEBUG_PRINT_HIGH("Using ROI QP map: Enable = %d", roiData->b_roi_info); + memcpy(roiData->data, roi.info.pRoiMBInfo, roi.info.nRoiMBInfoSize); + roi.dirty = false; + } + pthread_mutex_unlock(&m_pq.lock); + data = (OMX_OTHER_EXTRADATATYPE *)((char *)data + data->nSize); +#else // _PQ_ + if (roi.dirty) { + data->nSize = ALIGN(sizeof(OMX_OTHER_EXTRADATATYPE) + + sizeof(struct msm_vidc_roi_qp_payload) + + roi.info.nRoiMBInfoSize - 2 * sizeof(unsigned int), 4); + data->nVersion.nVersion = OMX_SPEC_VERSION; + data->nPortIndex = 0; + data->eType = (OMX_EXTRADATATYPE)MSM_VIDC_EXTRADATA_ROI_QP; + data->nDataSize = sizeof(struct msm_vidc_roi_qp_payload); + + struct msm_vidc_roi_qp_payload *roiData = + (struct msm_vidc_roi_qp_payload *)(data->data); + roiData->upper_qp_offset = roi.info.nUpperQpOffset; + roiData->lower_qp_offset = roi.info.nLowerQpOffset; + roiData->b_roi_info = roi.info.bUseRoiInfo; + roiData->mbi_info_size = roi.info.nRoiMBInfoSize; + DEBUG_PRINT_HIGH("Using ROI QP map: Enable = %d", roiData->b_roi_info); + memcpy(roiData->data, roi.info.pRoiMBInfo, roi.info.nRoiMBInfoSize); + + roi.dirty = false; + data = (OMX_OTHER_EXTRADATATYPE *)((char *)data + data->nSize); + } +#endif // _PQ_ + +#ifdef _VQZIP_ + if (vqzip_sei_info.enabled && !input_extradata_info.vqzip_sei_found) { + DEBUG_PRINT_ERROR("VQZIP is enabled, But no VQZIP SEI found. Rejecting the session"); + munmap(pVirt, size); + return false; + } + if (vqzip_sei_info.enabled) { + data->nSize = (sizeof(OMX_OTHER_EXTRADATATYPE) + sizeof(struct VQZipStats) + 3)&(~3); + data->nVersion.nVersion = OMX_SPEC_VERSION; + data->nPortIndex = 0; + data->eType = (OMX_EXTRADATATYPE)MSM_VIDC_EXTRADATA_YUVSTATS_INFO; + data->nDataSize = sizeof(struct VQZipStats); + vqzip.fill_stats_data((void*)pVirt, (void*) data->data); + data = (OMX_OTHER_EXTRADATATYPE *)((char *)data + data->nSize); + } +#endif + + data->nSize = sizeof(OMX_OTHER_EXTRADATATYPE); + data->nVersion.nVersion = OMX_SPEC_VERSION; + data->eType = OMX_ExtraDataNone; + data->nDataSize = 0; + data->data[0] = 0; + + } + munmap(pVirt, size); + return true; +} + +bool venc_dev::handle_output_extradata(void *buffer, int index) +{ + OMX_BUFFERHEADERTYPE *p_bufhdr = (OMX_BUFFERHEADERTYPE *) buffer; + OMX_OTHER_EXTRADATATYPE *p_extra = NULL; + + if (!output_extradata_info.uaddr) { + DEBUG_PRINT_ERROR("Extradata buffers not allocated\n"); + return false; + } + + p_extra = (OMX_OTHER_EXTRADATATYPE *)ALIGN(p_bufhdr->pBuffer + + p_bufhdr->nOffset + p_bufhdr->nFilledLen, 4); + + if (output_extradata_info.buffer_size > + p_bufhdr->nAllocLen - ALIGN(p_bufhdr->nOffset + p_bufhdr->nFilledLen, 4)) { + DEBUG_PRINT_ERROR("Insufficient buffer size for extradata"); + p_extra = NULL; + return false; + } else if (sizeof(msm_vidc_extradata_header) != sizeof(OMX_OTHER_EXTRADATATYPE)) { + /* A lot of the code below assumes this condition, so error out if it's not met */ + DEBUG_PRINT_ERROR("Extradata ABI mismatch"); + return false; + } + + struct msm_vidc_extradata_header *p_extradata = NULL; + do { + p_extradata = (struct msm_vidc_extradata_header *) (p_extradata ? + ((char *)p_extradata) + p_extradata->size : + output_extradata_info.uaddr + index * output_extradata_info.buffer_size); + + switch (p_extradata->type) { + case MSM_VIDC_EXTRADATA_METADATA_MBI: + { + OMX_U32 payloadSize = append_mbi_extradata(&p_extra->data, p_extradata); + p_extra->nSize = ALIGN(sizeof(OMX_OTHER_EXTRADATATYPE) + payloadSize, 4); + p_extra->nVersion.nVersion = OMX_SPEC_VERSION; + p_extra->nPortIndex = OMX_DirOutput; + p_extra->eType = (OMX_EXTRADATATYPE)OMX_ExtraDataVideoEncoderMBInfo; + p_extra->nDataSize = payloadSize; + break; + } + case MSM_VIDC_EXTRADATA_METADATA_LTR: + { + *p_extra->data = *p_extradata->data; + p_extra->nSize = ALIGN(sizeof(OMX_OTHER_EXTRADATATYPE) + p_extradata->data_size, 4); + p_extra->nVersion.nVersion = OMX_SPEC_VERSION; + p_extra->nPortIndex = OMX_DirOutput; + p_extra->eType = (OMX_EXTRADATATYPE) OMX_ExtraDataVideoLTRInfo; + p_extra->nDataSize = p_extradata->data_size; + break; + } + case MSM_VIDC_EXTRADATA_NONE: + p_extra->nSize = ALIGN(sizeof(OMX_OTHER_EXTRADATATYPE), 4); + p_extra->nVersion.nVersion = OMX_SPEC_VERSION; + p_extra->nPortIndex = OMX_DirOutput; + p_extra->eType = OMX_ExtraDataNone; + p_extra->nDataSize = 0; + break; + default: + /* No idea what this stuff is, just skip over it */ + DEBUG_PRINT_HIGH("Found an unrecognised extradata (%x) ignoring it", + p_extradata->type); + continue; + } + + p_extra = (OMX_OTHER_EXTRADATATYPE *)(((char *)p_extra) + p_extra->nSize); + } while (p_extradata->type != MSM_VIDC_EXTRADATA_NONE); + + /* Just for debugging: Traverse the list of extra datas and spit it out onto log */ + p_extra = (OMX_OTHER_EXTRADATATYPE *)ALIGN(p_bufhdr->pBuffer + + p_bufhdr->nOffset + p_bufhdr->nFilledLen, 4); + while(p_extra->eType != OMX_ExtraDataNone) + { + DEBUG_PRINT_LOW("[%p/%u] found extradata type %x of size %u (%u) at %p", + p_bufhdr->pBuffer, (unsigned int)p_bufhdr->nFilledLen, p_extra->eType, + (unsigned int)p_extra->nSize, (unsigned int)p_extra->nDataSize, p_extra); + + p_extra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) p_extra) + + p_extra->nSize); + } + + return true; +} + +int venc_dev::venc_set_format(int format) +{ + int rc = true; + + if (format) { + color_format = format; + + switch (color_format) { + case NV12_128m: + return venc_set_color_format((OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m); + default: + return false; + } + + } else { + color_format = 0; + rc = false; + } + + return rc; +} + +OMX_ERRORTYPE venc_dev::allocate_extradata(struct extradata_buffer_info *extradata_info, int flags) +{ + if (extradata_info->allocated) { + DEBUG_PRINT_HIGH("2nd allocation return for port = %d",extradata_info->port_index); + return OMX_ErrorNone; + } + +#ifdef USE_ION + + if (extradata_info->buffer_size) { + if (extradata_info->ion.ion_alloc_data.handle) { + munmap((void *)extradata_info->uaddr, extradata_info->size); + close(extradata_info->ion.fd_ion_data.fd); + venc_handle->free_ion_memory(&extradata_info->ion); + } + + extradata_info->size = (extradata_info->size + 4095) & (~4095); + + extradata_info->ion.ion_device_fd = venc_handle->alloc_map_ion_memory( + extradata_info->size, + &extradata_info->ion.ion_alloc_data, + &extradata_info->ion.fd_ion_data, flags); + + + if (extradata_info->ion.ion_device_fd < 0) { + DEBUG_PRINT_ERROR("Failed to alloc extradata memory\n"); + return OMX_ErrorInsufficientResources; + } + + extradata_info->uaddr = (char *)mmap(NULL, + extradata_info->size, + PROT_READ|PROT_WRITE, MAP_SHARED, + extradata_info->ion.fd_ion_data.fd , 0); + + if (extradata_info->uaddr == MAP_FAILED) { + DEBUG_PRINT_ERROR("Failed to map extradata memory\n"); + close(extradata_info->ion.fd_ion_data.fd); + venc_handle->free_ion_memory(&extradata_info->ion); + return OMX_ErrorInsufficientResources; + } + extradata_info->m_ion_dev = open("/dev/ion", O_RDONLY); + } + +#endif + extradata_info->allocated = OMX_TRUE; + return OMX_ErrorNone; +} + +void venc_dev::free_extradata(struct extradata_buffer_info *extradata_info) +{ +#ifdef USE_ION + + if (extradata_info == NULL) { + return; + } + + if (extradata_info->uaddr) { + munmap((void *)extradata_info->uaddr, extradata_info->size); + extradata_info->uaddr = NULL; + close(extradata_info->ion.fd_ion_data.fd); + venc_handle->free_ion_memory(&extradata_info->ion); + } + + if (extradata_info->m_ion_dev) + close(extradata_info->m_ion_dev); + + memset(extradata_info, 0, sizeof(*extradata_info)); + extradata_info->ion.fd_ion_data.fd = -1; + extradata_info->allocated = OMX_FALSE; + +#endif // USE_ION +} + +void venc_dev::free_extradata_all() +{ + free_extradata(&output_extradata_info); + free_extradata(&input_extradata_info); +#ifdef _PQ_ + free_extradata(&m_pq.roi_extradata_info); +#endif // _PQ_ +} + +bool venc_dev::venc_get_output_log_flag() +{ + return (m_debug.out_buffer_log == 1); +} + +int venc_dev::venc_output_log_buffers(const char *buffer_addr, int buffer_len) +{ + if (venc_handle->is_secure_session()) { + DEBUG_PRINT_ERROR("logging secure output buffers is not allowed!"); + return -1; + } + + if (!m_debug.outfile) { + int size = 0; + if(m_sVenc_cfg.codectype == V4L2_PIX_FMT_MPEG4) { + size = snprintf(m_debug.outfile_name, PROPERTY_VALUE_MAX, "%s/output_enc_%lu_%lu_%p.m4v", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } else if(m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + size = snprintf(m_debug.outfile_name, PROPERTY_VALUE_MAX, "%s/output_enc_%lu_%lu_%p.264", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } else if(m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) { + size = snprintf(m_debug.outfile_name, PROPERTY_VALUE_MAX, "%s/output_enc_%ld_%ld_%p.265", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } else if(m_sVenc_cfg.codectype == V4L2_PIX_FMT_H263) { + size = snprintf(m_debug.outfile_name, PROPERTY_VALUE_MAX, "%s/output_enc_%lu_%lu_%p.263", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } else if(m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) { + size = snprintf(m_debug.outfile_name, PROPERTY_VALUE_MAX, "%s/output_enc_%lu_%lu_%p.ivf", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } + if ((size > PROPERTY_VALUE_MAX) && (size < 0)) { + DEBUG_PRINT_ERROR("Failed to open output file: %s for logging size:%d", + m_debug.outfile_name, size); + } + m_debug.outfile = fopen(m_debug.outfile_name, "ab"); + if (!m_debug.outfile) { + DEBUG_PRINT_ERROR("Failed to open output file: %s for logging errno:%d", + m_debug.outfile_name, errno); + m_debug.outfile_name[0] = '\0'; + return -1; + } + } + if (m_debug.outfile && buffer_len) { + DEBUG_PRINT_LOW("%s buffer_len:%d", __func__, buffer_len); + fwrite(buffer_addr, buffer_len, 1, m_debug.outfile); + } + return 0; +} + +int venc_dev::venc_extradata_log_buffers(char *buffer_addr) +{ + if (!m_debug.extradatafile && m_debug.extradata_log) { + int size = 0; + if(m_sVenc_cfg.codectype == V4L2_PIX_FMT_MPEG4) { + size = snprintf(m_debug.extradatafile_name, PROPERTY_VALUE_MAX, "%s/extradata_enc_%lu_%lu_%p.bin", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } else if(m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + size = snprintf(m_debug.extradatafile_name, PROPERTY_VALUE_MAX, "%s/extradata_enc_%lu_%lu_%p.bin", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } else if(m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) { + size = snprintf(m_debug.extradatafile_name, PROPERTY_VALUE_MAX, "%s/extradata_enc_%lu_%lu_%p.bin", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } else if(m_sVenc_cfg.codectype == V4L2_PIX_FMT_H263) { + size = snprintf(m_debug.extradatafile_name, PROPERTY_VALUE_MAX, "%s/extradata_enc_%lu_%lu_%p.bin", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } else if(m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) { + size = snprintf(m_debug.extradatafile_name, PROPERTY_VALUE_MAX, "%s/extradata_enc_%lu_%lu_%p.bin", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + } + if ((size > PROPERTY_VALUE_MAX) && (size < 0)) { + DEBUG_PRINT_ERROR("Failed to open extradata file: %s for logging size:%d", + m_debug.extradatafile_name, size); + } + + m_debug.extradatafile = fopen(m_debug.extradatafile_name, "ab"); + if (!m_debug.extradatafile) { + DEBUG_PRINT_ERROR("Failed to open extradata file: %s for logging errno:%d", + m_debug.extradatafile_name, errno); + m_debug.extradatafile_name[0] = '\0'; + return -1; + } + } + + if (m_debug.extradatafile && buffer_addr) { + OMX_OTHER_EXTRADATATYPE *p_extra = NULL; + do { + p_extra = (OMX_OTHER_EXTRADATATYPE *)(!p_extra ? buffer_addr : + ((char *)p_extra) + p_extra->nSize); + fwrite(p_extra, p_extra->nSize, 1, m_debug.extradatafile); + } while (p_extra->eType != OMX_ExtraDataNone); + } + return 0; +} + +int venc_dev::venc_input_log_buffers(OMX_BUFFERHEADERTYPE *pbuffer, int fd, int plane_offset, + unsigned long inputformat) { + if (venc_handle->is_secure_session()) { + DEBUG_PRINT_ERROR("logging secure input buffers is not allowed!"); + return -1; + } + + if (!m_debug.infile) { + int size = snprintf(m_debug.infile_name, PROPERTY_VALUE_MAX, "%s/input_enc_%lu_%lu_%p.yuv", + m_debug.log_loc, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, this); + if ((size > PROPERTY_VALUE_MAX) && (size < 0)) { + DEBUG_PRINT_ERROR("Failed to open output file: %s for logging size:%d", + m_debug.infile_name, size); + } + m_debug.infile = fopen (m_debug.infile_name, "ab"); + if (!m_debug.infile) { + DEBUG_PRINT_HIGH("Failed to open input file: %s for logging", m_debug.infile_name); + m_debug.infile_name[0] = '\0'; + return -1; + } + } + + if (m_debug.infile && pbuffer && pbuffer->nFilledLen) { + int stride, scanlines; + int color_format; + unsigned long i, msize; + unsigned char *pvirt = NULL, *ptemp = NULL; + unsigned char *temp = (unsigned char *)pbuffer->pBuffer; + + switch (inputformat) { + case V4L2_PIX_FMT_NV12: + color_format = COLOR_FMT_NV12; + break; + case V4L2_PIX_FMT_NV12_UBWC: + color_format = COLOR_FMT_NV12_UBWC; + break; + case V4L2_PIX_FMT_RGB32: + color_format = COLOR_FMT_RGBA8888; + break; + case V4L2_PIX_FMT_RGBA8888_UBWC: + color_format = COLOR_FMT_RGBA8888_UBWC; + break; + default: + color_format = COLOR_FMT_NV12; + DEBUG_PRINT_LOW("Default format NV12 is set for logging [%lu]", inputformat); + break; + } + + msize = VENUS_BUFFER_SIZE(color_format, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height); + const unsigned int extra_size = VENUS_EXTRADATA_SIZE(m_sVenc_cfg.input_width, m_sVenc_cfg.input_height); + + if (metadatamode == 1) { + pvirt= (unsigned char *)mmap(NULL, msize, PROT_READ|PROT_WRITE,MAP_SHARED, fd, plane_offset); + if (pvirt == MAP_FAILED) { + DEBUG_PRINT_ERROR("%s mmap failed", __func__); + return -1; + } + ptemp = pvirt; + } else { + ptemp = temp; + } + + if (color_format == COLOR_FMT_NV12) { + stride = VENUS_Y_STRIDE(color_format, m_sVenc_cfg.input_width); + scanlines = VENUS_Y_SCANLINES(color_format, m_sVenc_cfg.input_height); + + for (i = 0; i < m_sVenc_cfg.input_height; i++) { + fwrite(ptemp, m_sVenc_cfg.input_width, 1, m_debug.infile); + ptemp += stride; + } + if (metadatamode == 1) { + ptemp = pvirt + (stride * scanlines); + } else { + ptemp = (unsigned char *)pbuffer->pBuffer + (stride * scanlines); + } + for (i = 0; i < m_sVenc_cfg.input_height/2; i++) { + fwrite(ptemp, m_sVenc_cfg.input_width, 1, m_debug.infile); + ptemp += stride; + } + } else if (color_format == COLOR_FMT_RGBA8888) { + stride = VENUS_RGB_STRIDE(color_format, m_sVenc_cfg.input_width); + scanlines = VENUS_RGB_SCANLINES(color_format, m_sVenc_cfg.input_height); + + for (i = 0; i < m_sVenc_cfg.input_height; i++) { + fwrite(ptemp, m_sVenc_cfg.input_width * 4, 1, m_debug.infile); + ptemp += stride; + } + } else if (color_format == COLOR_FMT_NV12_UBWC || color_format == COLOR_FMT_RGBA8888_UBWC) { + if (color_format == COLOR_FMT_NV12_UBWC) { + msize -= 2 * extra_size; + } + fwrite(ptemp, msize, 1, m_debug.infile); + } + + if (metadatamode == 1 && pvirt) { + munmap(pvirt, msize); + } + } + + return 0; +} + +bool venc_dev::venc_open(OMX_U32 codec) +{ + int r; + unsigned int alignment = 0,buffer_size = 0, temp =0; + struct v4l2_control control; + OMX_STRING device_name = (OMX_STRING)"/dev/video33"; + char property_value[PROPERTY_VALUE_MAX] = {0}; + char platform_name[PROPERTY_VALUE_MAX] = {0}; + FILE *soc_file = NULL; + char buffer[10]; + + property_get("ro.board.platform", platform_name, "0"); + property_get("vidc.enc.narrow.searchrange", property_value, "0"); + enable_mv_narrow_searchrange = atoi(property_value); + + if (!strncmp(platform_name, "msm8610", 7)) { + device_name = (OMX_STRING)"/dev/video/q6_enc"; + supported_rc_modes = (RC_ALL & ~RC_CBR_CFR); + } + m_nDriver_fd = open (device_name, O_RDWR); + if ((int)m_nDriver_fd < 0) { + DEBUG_PRINT_ERROR("ERROR: Omx_venc::Comp Init Returning failure"); + return false; + } + m_poll_efd = eventfd(0, 0); + if (m_poll_efd < 0) { + DEBUG_PRINT_ERROR("Failed to open event fd(%s)", strerror(errno)); + return false; + } + DEBUG_PRINT_LOW("m_nDriver_fd = %u", (unsigned int)m_nDriver_fd); + + // set the basic configuration of the video encoder driver + m_sVenc_cfg.input_width = OMX_CORE_QCIF_WIDTH; + m_sVenc_cfg.input_height= OMX_CORE_QCIF_HEIGHT; + m_sVenc_cfg.dvs_width = OMX_CORE_QCIF_WIDTH; + m_sVenc_cfg.dvs_height = OMX_CORE_QCIF_HEIGHT; + m_sVenc_cfg.fps_num = 30; + m_sVenc_cfg.fps_den = 1; + m_sVenc_cfg.targetbitrate = 64000; + m_sVenc_cfg.inputformat= V4L2_DEFAULT_OUTPUT_COLOR_FMT; + + m_codec = codec; + + if (codec == OMX_VIDEO_CodingMPEG4) { + m_sVenc_cfg.codectype = V4L2_PIX_FMT_MPEG4; + codec_profile.profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE; + profile_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_2; + session_qp_range.minqp = 1; + session_qp_range.maxqp = 31; + } else if (codec == OMX_VIDEO_CodingH263) { + m_sVenc_cfg.codectype = V4L2_PIX_FMT_H263; + codec_profile.profile = VEN_PROFILE_H263_BASELINE; + profile_level.level = VEN_LEVEL_H263_20; + session_qp_range.minqp = 1; + session_qp_range.maxqp = 31; + } else if (codec == OMX_VIDEO_CodingAVC) { + m_sVenc_cfg.codectype = V4L2_PIX_FMT_H264; + codec_profile.profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; + profile_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0; + session_qp_range.minqp = 1; + session_qp_range.maxqp = 51; + } else if (codec == OMX_VIDEO_CodingVP8) { + m_sVenc_cfg.codectype = V4L2_PIX_FMT_VP8; + codec_profile.profile = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED; + profile_level.level = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0; + session_qp_range.minqp = 1; + session_qp_range.maxqp = 128; + } else if (codec == OMX_VIDEO_CodingHEVC) { + m_sVenc_cfg.codectype = V4L2_PIX_FMT_HEVC; + session_qp_range.minqp = 1; + session_qp_range.maxqp = 51; + codec_profile.profile = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN; + profile_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1; + } + session_qp_values.minqp = session_qp_range.minqp; + session_qp_values.maxqp = session_qp_range.maxqp; + session_ipb_qp_values.min_i_qp = session_qp_range.minqp; + session_ipb_qp_values.max_i_qp = session_qp_range.maxqp; + session_ipb_qp_values.min_p_qp = session_qp_range.minqp; + session_ipb_qp_values.max_p_qp = session_qp_range.maxqp; + session_ipb_qp_values.min_b_qp = session_qp_range.minqp; + session_ipb_qp_values.max_b_qp = session_qp_range.maxqp; + + int ret; + ret = subscribe_to_events(m_nDriver_fd); + + if (ret) { + DEBUG_PRINT_ERROR("Subscribe Event Failed"); + return false; + } + + struct v4l2_fmtdesc fdesc; + struct v4l2_format fmt; + struct v4l2_requestbuffers bufreq; + struct v4l2_capability cap; + + ret = ioctl(m_nDriver_fd, VIDIOC_QUERYCAP, &cap); + + if (ret) { + DEBUG_PRINT_ERROR("Failed to query capabilities"); + } else { + DEBUG_PRINT_LOW("Capabilities: driver_name = %s, card = %s, bus_info = %s," + " version = %d, capabilities = %x", cap.driver, cap.card, + cap.bus_info, cap.version, cap.capabilities); + } + + ret=0; + fdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fdesc.index=0; + + while (ioctl(m_nDriver_fd, VIDIOC_ENUM_FMT, &fdesc) == 0) { + DEBUG_PRINT_LOW("fmt: description: %s, fmt: %x, flags = %x", fdesc.description, + fdesc.pixelformat, fdesc.flags); + fdesc.index++; + } + + fdesc.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fdesc.index=0; + + while (ioctl(m_nDriver_fd, VIDIOC_ENUM_FMT, &fdesc) == 0) { + DEBUG_PRINT_LOW("fmt: description: %s, fmt: %x, flags = %x", fdesc.description, + fdesc.pixelformat, fdesc.flags); + fdesc.index++; + } + + is_thulium_v1 = false; + soc_file= fopen("/sys/devices/soc0/soc_id", "r"); + if (soc_file) { + fread(buffer, 1, 4, soc_file); + fclose(soc_file); + if (atoi(buffer) == 246) { + soc_file = fopen("/sys/devices/soc0/revision", "r"); + if (soc_file) { + fread(buffer, 1, 4, soc_file); + fclose(soc_file); + if (atoi(buffer) == 1) { + is_thulium_v1 = true; + DEBUG_PRINT_HIGH("is_thulium_v1 = TRUE"); + } + } + } + } + + if (venc_handle->is_secure_session()) { + m_sOutput_buff_property.alignment = SZ_1M; + m_sInput_buff_property.alignment = SZ_1M; + } else { + m_sOutput_buff_property.alignment = SZ_4K; + m_sInput_buff_property.alignment = SZ_4K; + } + + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.height = m_sVenc_cfg.dvs_height; + fmt.fmt.pix_mp.width = m_sVenc_cfg.dvs_width; + fmt.fmt.pix_mp.pixelformat = m_sVenc_cfg.codectype; + + /*TODO: Return values not handled properly in this function anywhere. + * Need to handle those.*/ + ret = ioctl(m_nDriver_fd, VIDIOC_S_FMT, &fmt); + + if (ret) { + DEBUG_PRINT_ERROR("Failed to set format on capture port"); + return false; + } + + m_sOutput_buff_property.datasize=fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = m_sVenc_cfg.input_height; + fmt.fmt.pix_mp.width = m_sVenc_cfg.input_width; + fmt.fmt.pix_mp.pixelformat = V4L2_DEFAULT_OUTPUT_COLOR_FMT; + fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + + ret = ioctl(m_nDriver_fd, VIDIOC_S_FMT, &fmt); + m_sInput_buff_property.datasize=fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = 2; + + bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + ret = ioctl(m_nDriver_fd,VIDIOC_REQBUFS, &bufreq); + m_sInput_buff_property.mincount = m_sInput_buff_property.actualcount = bufreq.count; + + bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + bufreq.count = 2; + ret = ioctl(m_nDriver_fd,VIDIOC_REQBUFS, &bufreq); + m_sOutput_buff_property.mincount = m_sOutput_buff_property.actualcount = bufreq.count; + + if(venc_handle->is_secure_session()) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE; + control.value = 1; + DEBUG_PRINT_HIGH("ioctl: open secure device"); + ret=ioctl(m_nDriver_fd, VIDIOC_S_CTRL,&control); + if (ret) { + DEBUG_PRINT_ERROR("ioctl: open secure dev fail, rc %d", ret); + return false; + } + } + + resume_in_stopped = 0; + metadatamode = 0; + + control.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE; + control.value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE; + + DEBUG_PRINT_LOW("Calling IOCTL to disable seq_hdr in sync_frame id=%d, val=%d", control.id, control.value); + + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) + DEBUG_PRINT_ERROR("Failed to set control"); + + struct v4l2_frmsizeenum frmsize; + + //Get the hardware capabilities + memset((void *)&frmsize,0,sizeof(frmsize)); + frmsize.index = 0; + frmsize.pixel_format = m_sVenc_cfg.codectype; + ret = ioctl(m_nDriver_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize); + + if (ret || frmsize.type != V4L2_FRMSIZE_TYPE_STEPWISE) { + DEBUG_PRINT_ERROR("Failed to get framesizes"); + return false; + } + + if (frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) { + capability.min_width = frmsize.stepwise.min_width; + capability.max_width = frmsize.stepwise.max_width; + capability.min_height = frmsize.stepwise.min_height; + capability.max_height = frmsize.stepwise.max_height; + } + + //Initialize non-default parameters + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES; + control.value = 0x7fffffff; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) + DEBUG_PRINT_ERROR("Failed to set V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAME\n"); + } + + property_get("vidc.debug.turbo", property_value, "0"); + if (atoi(property_value)) { + DEBUG_PRINT_HIGH("Turbo mode debug property enabled"); + control.id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL; + control.value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set turbo mode"); + } + } + +#ifdef _PQ_ + if (codec == OMX_VIDEO_CodingAVC && !m_pq.is_pq_force_disable) { + m_pq.init(V4L2_DEFAULT_OUTPUT_COLOR_FMT); + m_pq.get_caps(); + } +#endif // _PQ_ + + /* Enable Low power mode by default for better power */ + + if (venc_set_perf_mode(V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE) == false) { + DEBUG_PRINT_HIGH("Failed to set Perf Mode"); + } + + input_extradata_info.port_index = OUTPUT_PORT; + output_extradata_info.port_index = CAPTURE_PORT; + + return true; +} + +static OMX_ERRORTYPE unsubscribe_to_events(int fd) +{ + OMX_ERRORTYPE eRet = OMX_ErrorNone; + struct v4l2_event_subscription sub; + int array_sz = sizeof(event_type)/sizeof(int); + int i,rc; + + if (fd < 0) { + DEBUG_PRINT_ERROR("Invalid input: %d", fd); + return OMX_ErrorBadParameter; + } + + for (i = 0; i < array_sz; ++i) { + memset(&sub, 0, sizeof(sub)); + sub.type = event_type[i]; + rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to unsubscribe event: 0x%x", sub.type); + break; + } + } + + return eRet; +} + +void venc_dev::venc_close() +{ + DEBUG_PRINT_LOW("venc_close: fd = %u", (unsigned int)m_nDriver_fd); + + if ((int)m_nDriver_fd >= 0) { + DEBUG_PRINT_HIGH("venc_close E"); + + if(eventfd_write(m_poll_efd, 1)) { + DEBUG_PRINT_ERROR("eventfd_write failed for fd: %d, errno = %d, force stop async_thread", m_poll_efd, errno); + async_thread_force_stop = true; + } + + if (async_thread_created) + pthread_join(m_tid,NULL); + + DEBUG_PRINT_HIGH("venc_close X"); + unsubscribe_to_events(m_nDriver_fd); + close(m_poll_efd); + close(m_nDriver_fd); + m_nDriver_fd = -1; + } + +#ifdef _PQ_ + m_pq.deinit(); +#endif // _PQ_ + +#ifdef _VQZIP_ + vqzip.deinit(); +#endif + + if (m_debug.infile) { + fclose(m_debug.infile); + m_debug.infile = NULL; + } + + if (m_debug.outfile) { + fclose(m_debug.outfile); + m_debug.outfile = NULL; + } + + if (m_debug.extradatafile) { + fclose(m_debug.extradatafile); + m_debug.extradatafile = NULL; + } +} + +bool venc_dev::venc_set_buf_req(OMX_U32 *min_buff_count, + OMX_U32 *actual_buff_count, + OMX_U32 *buff_size, + OMX_U32 port) +{ + (void)min_buff_count, (void)buff_size; + unsigned long temp_count = 0; + + if (port == 0) { + if (*actual_buff_count > m_sInput_buff_property.mincount) { + temp_count = m_sInput_buff_property.actualcount; + m_sInput_buff_property.actualcount = *actual_buff_count; + DEBUG_PRINT_LOW("I/P Count set to %u", (unsigned int)*actual_buff_count); + } + } else { + if (*actual_buff_count > m_sOutput_buff_property.mincount) { + temp_count = m_sOutput_buff_property.actualcount; + m_sOutput_buff_property.actualcount = *actual_buff_count; + DEBUG_PRINT_LOW("O/P Count set to %u", (unsigned int)*actual_buff_count); + } + } + + return true; + +} + +bool venc_dev::venc_loaded_start() +{ + return true; +} + +bool venc_dev::venc_loaded_stop() +{ + return true; +} + +bool venc_dev::venc_loaded_start_done() +{ + return true; +} + +bool venc_dev::venc_loaded_stop_done() +{ + return true; +} + +bool venc_dev::venc_get_seq_hdr(void *buffer, + unsigned buffer_size, unsigned *header_len) +{ + (void) buffer, (void) buffer_size, (void) header_len; + return true; +} + +bool venc_dev::venc_get_buf_req(OMX_U32 *min_buff_count, + OMX_U32 *actual_buff_count, + OMX_U32 *buff_size, + OMX_U32 port) +{ + struct v4l2_format fmt; + struct v4l2_requestbuffers bufreq; + unsigned int buf_size = 0, extra_data_size = 0, client_extra_data_size = 0; + int ret; + int extra_idx = 0; + + if (port == 0) { + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = m_sVenc_cfg.input_height; + fmt.fmt.pix_mp.width = m_sVenc_cfg.input_width; + fmt.fmt.pix_mp.pixelformat = m_sVenc_cfg.inputformat; + fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + ret = ioctl(m_nDriver_fd, VIDIOC_G_FMT, &fmt); + m_sInput_buff_property.datasize=fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + bufreq.memory = V4L2_MEMORY_USERPTR; + + if (*actual_buff_count) + bufreq.count = *actual_buff_count; + else + bufreq.count = 2; + + // Increase buffer-header count for metadata-mode on input port + // to improve buffering and reduce bottlenecks in clients + if (metadatamode && (bufreq.count < 9)) { + DEBUG_PRINT_LOW("FW returned buffer count = %d , overwriting with 9", + bufreq.count); + bufreq.count = 9; + } + if (m_sVenc_cfg.input_height * m_sVenc_cfg.input_width >= 3840*2160) { + DEBUG_PRINT_LOW("Increasing buffer count = %d to 11", bufreq.count); + bufreq.count = 11; + } + + int actualCount = bufreq.count; + // Request MAX_V4L2_BUFS from V4L2 in batch mode. + // Keep the original count for the client + if (metadatamode && mBatchSize) { + bufreq.count = MAX_V4L2_BUFS; + } + + bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + ret = ioctl(m_nDriver_fd,VIDIOC_REQBUFS, &bufreq); + + if (ret) { + DEBUG_PRINT_ERROR("VIDIOC_REQBUFS OUTPUT_MPLANE Failed"); + return false; + } + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = m_sVenc_cfg.input_height; + fmt.fmt.pix_mp.width = m_sVenc_cfg.input_width; + fmt.fmt.pix_mp.pixelformat = m_sVenc_cfg.inputformat; + ret = ioctl(m_nDriver_fd, VIDIOC_G_FMT, &fmt); + m_sInput_buff_property.datasize=fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + + if (metadatamode && mBatchSize) { + m_sInput_buff_property.mincount = m_sInput_buff_property.actualcount = actualCount; + } else { + m_sInput_buff_property.mincount = m_sInput_buff_property.actualcount = bufreq.count; + } + + *min_buff_count = m_sInput_buff_property.mincount; + *actual_buff_count = m_sInput_buff_property.actualcount; +#ifdef USE_ION + // For ION memory allocations of the allocated buffer size + // must be 4k aligned, hence aligning the input buffer + // size to 4k. + m_sInput_buff_property.datasize = ALIGN(m_sInput_buff_property.datasize, SZ_4K); +#endif + *buff_size = m_sInput_buff_property.datasize; + num_input_planes = fmt.fmt.pix_mp.num_planes; + extra_idx = EXTRADATA_IDX(num_input_planes); + + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + extra_data_size = fmt.fmt.pix_mp.plane_fmt[extra_idx].sizeimage; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index is more than allowed: %d\n", extra_idx); + return OMX_ErrorBadParameter; + } + input_extradata_info.buffer_size = ALIGN(extra_data_size, SZ_4K); + input_extradata_info.count = MAX_V4L2_BUFS; + input_extradata_info.size = input_extradata_info.buffer_size * input_extradata_info.count; + + } else { + unsigned int extra_idx = 0; + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.height = m_sVenc_cfg.dvs_height; + fmt.fmt.pix_mp.width = m_sVenc_cfg.dvs_width; + fmt.fmt.pix_mp.pixelformat = m_sVenc_cfg.codectype; + + ret = ioctl(m_nDriver_fd, VIDIOC_S_FMT, &fmt); + m_sOutput_buff_property.datasize=fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.height = m_sVenc_cfg.dvs_height; + fmt.fmt.pix_mp.width = m_sVenc_cfg.dvs_width; + fmt.fmt.pix_mp.pixelformat = m_sVenc_cfg.codectype; + + ret = ioctl(m_nDriver_fd, VIDIOC_G_FMT, &fmt); + m_sOutput_buff_property.datasize=fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + bufreq.memory = V4L2_MEMORY_USERPTR; + + if (mBatchSize) { + // If we're in batch mode, we'd like to end up in a situation where + // driver is able to own mBatchSize buffers and we'd also own atleast + // mBatchSize buffers + bufreq.count = MAX(*actual_buff_count, mBatchSize) + mBatchSize; + } else if (*actual_buff_count) { + bufreq.count = *actual_buff_count; + } else { + bufreq.count = 2; + } + + bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + ret = ioctl(m_nDriver_fd,VIDIOC_REQBUFS, &bufreq); + + if (ret) { + DEBUG_PRINT_ERROR("VIDIOC_REQBUFS CAPTURE_MPLANE Failed"); + return false; + } + + m_sOutput_buff_property.mincount = m_sOutput_buff_property.actualcount = bufreq.count; + *min_buff_count = m_sOutput_buff_property.mincount; + *actual_buff_count = m_sOutput_buff_property.actualcount; + *buff_size = m_sOutput_buff_property.datasize; + num_output_planes = fmt.fmt.pix_mp.num_planes; + extra_idx = EXTRADATA_IDX(num_output_planes); + + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + extra_data_size = fmt.fmt.pix_mp.plane_fmt[extra_idx].sizeimage; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index is more than allowed: %d", extra_idx); + return OMX_ErrorBadParameter; + } + + output_extradata_info.buffer_size = extra_data_size; + output_extradata_info.count = m_sOutput_buff_property.actualcount; + output_extradata_info.size = output_extradata_info.buffer_size * output_extradata_info.count; + } + + return true; +} + +bool venc_dev::venc_set_param(void *paramData, OMX_INDEXTYPE index) +{ + DEBUG_PRINT_LOW("venc_set_param:: venc-720p"); + struct v4l2_format fmt; + struct v4l2_requestbuffers bufreq; + int ret; + + switch ((int)index) { + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *portDefn; + portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; + DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamPortDefinition"); + + if (portDefn->nPortIndex == PORT_INDEX_IN) { + if (!venc_set_encode_framerate(portDefn->format.video.xFramerate, 0)) { + return false; + } + + if (!venc_set_color_format(portDefn->format.video.eColorFormat)) { + return false; + } +#ifdef _PQ_ + venc_try_enable_pq(); + #endif // _PQ_ + + if (enable_mv_narrow_searchrange && + (m_sVenc_cfg.input_width * m_sVenc_cfg.input_height) >= + (OMX_CORE_1080P_WIDTH * OMX_CORE_1080P_HEIGHT)) { + if (venc_set_searchrange() == false) { + DEBUG_PRINT_ERROR("ERROR: Failed to set search range"); + } + } + if (m_sVenc_cfg.input_height != portDefn->format.video.nFrameHeight || + m_sVenc_cfg.input_width != portDefn->format.video.nFrameWidth) { + DEBUG_PRINT_LOW("Basic parameter has changed"); + m_sVenc_cfg.input_height = portDefn->format.video.nFrameHeight; + m_sVenc_cfg.input_width = portDefn->format.video.nFrameWidth; + + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.height = m_sVenc_cfg.input_height; + fmt.fmt.pix_mp.width = m_sVenc_cfg.input_width; + fmt.fmt.pix_mp.pixelformat = m_sVenc_cfg.inputformat; + fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + + if (ioctl(m_nDriver_fd, VIDIOC_S_FMT, &fmt)) { + DEBUG_PRINT_ERROR("VIDIOC_S_FMT OUTPUT_MPLANE Failed"); + hw_overload = errno == EBUSY; + return false; + } + + m_sInput_buff_property.datasize=fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = portDefn->nBufferCountActual; + bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + + if (ioctl(m_nDriver_fd,VIDIOC_REQBUFS, &bufreq)) { + DEBUG_PRINT_ERROR("VIDIOC_REQBUFS OUTPUT_MPLANE Failed"); + return false; + } + + if (bufreq.count == portDefn->nBufferCountActual) + m_sInput_buff_property.mincount = m_sInput_buff_property.actualcount = bufreq.count; + + if (portDefn->nBufferCountActual >= m_sInput_buff_property.mincount) + m_sInput_buff_property.actualcount = portDefn->nBufferCountActual; + if (num_input_planes > 1) + input_extradata_info.count = m_sInput_buff_property.actualcount + 1; + + } + + DEBUG_PRINT_LOW("input: actual: %u, min: %u, count_req: %u", + (unsigned int)portDefn->nBufferCountActual, (unsigned int)m_sInput_buff_property.mincount, bufreq.count); + } else if (portDefn->nPortIndex == PORT_INDEX_OUT) { + m_sVenc_cfg.dvs_height = portDefn->format.video.nFrameHeight; + m_sVenc_cfg.dvs_width = portDefn->format.video.nFrameWidth; + + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.height = m_sVenc_cfg.dvs_height; + fmt.fmt.pix_mp.width = m_sVenc_cfg.dvs_width; + fmt.fmt.pix_mp.pixelformat = m_sVenc_cfg.codectype; + + if (ioctl(m_nDriver_fd, VIDIOC_S_FMT, &fmt)) { + DEBUG_PRINT_ERROR("VIDIOC_S_FMT CAPTURE_MPLANE Failed"); + hw_overload = errno == EBUSY; + return false; + } + + m_sOutput_buff_property.datasize = fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + + if (!venc_set_target_bitrate(portDefn->format.video.nBitrate, 0)) { + return false; + } + + m_sOutput_buff_property.actualcount = portDefn->nBufferCountActual; + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = portDefn->nBufferCountActual; + bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + if (ioctl(m_nDriver_fd,VIDIOC_REQBUFS, &bufreq)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting o/p buffer count failed: requested: %u, current: %u", + (unsigned int)portDefn->nBufferCountActual, (unsigned int)m_sOutput_buff_property.actualcount); + return false; + } + + if (bufreq.count == portDefn->nBufferCountActual) + m_sOutput_buff_property.mincount = m_sOutput_buff_property.actualcount = bufreq.count; + + if (portDefn->nBufferCountActual >= m_sOutput_buff_property.mincount) + m_sOutput_buff_property.actualcount = portDefn->nBufferCountActual; + + if (num_output_planes > 1) + output_extradata_info.count = m_sOutput_buff_property.actualcount; + + DEBUG_PRINT_LOW("Output: actual: %u, min: %u, count_req: %u", + (unsigned int)portDefn->nBufferCountActual, (unsigned int)m_sOutput_buff_property.mincount, bufreq.count); + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamPortDefinition"); + } + + break; + } + case OMX_IndexParamVideoPortFormat: + { + OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt; + portFmt =(OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; + DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoPortFormat"); + + if (portFmt->nPortIndex == (OMX_U32) PORT_INDEX_IN) { + if (!venc_set_color_format(portFmt->eColorFormat)) { + return false; + } + } else if (portFmt->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (!venc_set_encode_framerate(portFmt->xFramerate, 0)) { + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoPortFormat"); + } +#ifdef _PQ_ + venc_try_enable_pq(); +#endif // _PQ_ + + break; + } + case OMX_IndexParamVideoBitrate: + { + OMX_VIDEO_PARAM_BITRATETYPE* pParam; + pParam = (OMX_VIDEO_PARAM_BITRATETYPE*)paramData; + DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoBitrate"); + + if (pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (!venc_set_target_bitrate(pParam->nTargetBitrate, 0)) { + DEBUG_PRINT_ERROR("ERROR: Target Bit Rate setting failed"); + return false; + } + + if (!venc_set_ratectrl_cfg(pParam->eControlRate)) { + DEBUG_PRINT_ERROR("ERROR: Rate Control setting failed"); + return false; + } +#ifdef _PQ_ + venc_try_enable_pq(); +#endif // _PQ_ + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoBitrate"); + } + + break; + } + case OMX_IndexParamVideoMpeg4: + { + OMX_VIDEO_PARAM_MPEG4TYPE* pParam; + OMX_U32 bFrames = 0; + + pParam = (OMX_VIDEO_PARAM_MPEG4TYPE*)paramData; + DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoMpeg4"); + + if (pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (!venc_set_voptiming_cfg(pParam->nTimeIncRes)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting vop_timing failed"); + return false; + } + + m_profile_set = false; + m_level_set = false; + rc_off_level = (int)pParam->eLevel; + if (!venc_set_profile_level (pParam->eProfile, pParam->eLevel)) { + DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating Profile and level"); + return false; + } else { + if (pParam->eProfile == OMX_VIDEO_MPEG4ProfileAdvancedSimple) { + if (pParam->nBFrames) { + bFrames = pParam->nBFrames; + } + } else { + if (pParam->nBFrames) { + DEBUG_PRINT_ERROR("Warning: B frames not supported"); + bFrames = 0; + } + } + } + + if (!venc_set_intra_period (pParam->nPFrames,bFrames)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting intra period failed"); + return false; + } + + if (!venc_set_multislice_cfg(OMX_IndexParamVideoMpeg4,pParam->nSliceHeaderSpacing)) { + DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating slice_config"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoMpeg4"); + } + + break; + } + case OMX_IndexParamVideoH263: + { + OMX_VIDEO_PARAM_H263TYPE* pParam = (OMX_VIDEO_PARAM_H263TYPE*)paramData; + DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoH263"); + OMX_U32 bFrames = 0; + + if (pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + m_profile_set = false; + m_level_set = false; + rc_off_level = (int)pParam->eLevel; + if (!venc_set_profile_level (pParam->eProfile, pParam->eLevel)) { + DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating Profile and level"); + return false; + } + + if (pParam->nBFrames) + DEBUG_PRINT_ERROR("WARNING: B frame not supported for H.263"); + + if (venc_set_intra_period (pParam->nPFrames, bFrames) == false) { + DEBUG_PRINT_ERROR("ERROR: Request for setting intra period failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoH263"); + } + + break; + } + case OMX_IndexParamVideoAvc: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoAvc"); + OMX_VIDEO_PARAM_AVCTYPE* pParam = (OMX_VIDEO_PARAM_AVCTYPE*)paramData; + OMX_U32 bFrames = 0; + + if (pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + DEBUG_PRINT_LOW("pParam->eProfile :%d ,pParam->eLevel %d", + pParam->eProfile,pParam->eLevel); + + m_profile_set = false; + m_level_set = false; + rc_off_level = (int)pParam->eLevel; + if (!venc_set_profile_level (pParam->eProfile,pParam->eLevel)) { + DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating Profile and level %d, %d", + pParam->eProfile, pParam->eLevel); + return false; + } else { + if ((pParam->eProfile != OMX_VIDEO_AVCProfileBaseline) && + (pParam->eProfile != (OMX_VIDEO_AVCPROFILETYPE) QOMX_VIDEO_AVCProfileConstrainedBaseline)) { + if (pParam->nBFrames) { + bFrames = pParam->nBFrames; + } + } else { + if (pParam->nBFrames) { + DEBUG_PRINT_ERROR("Warning: B frames not supported"); + bFrames = 0; + } + } + } + + if (!venc_set_intra_period (pParam->nPFrames, bFrames)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting intra period failed"); + return false; + } + + if (!venc_set_entropy_config (pParam->bEntropyCodingCABAC, pParam->nCabacInitIdc)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting Entropy failed"); + return false; + } + + if (!venc_set_inloop_filter (pParam->eLoopFilterMode)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting Inloop filter failed"); + return false; + } + + if (!venc_set_multislice_cfg(OMX_IndexParamVideoAvc, pParam->nSliceHeaderSpacing)) { + DEBUG_PRINT_ERROR("WARNING: Unsuccessful in updating slice_config"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoAvc"); + } + + //TBD, lot of other variables to be updated, yet to decide + break; + } + case (OMX_INDEXTYPE)OMX_IndexParamVideoVp8: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoVp8"); + OMX_VIDEO_PARAM_VP8TYPE* pParam = (OMX_VIDEO_PARAM_VP8TYPE*)paramData; + rc_off_level = (int)pParam->eLevel; + if (!venc_set_profile_level (pParam->eProfile, pParam->eLevel)) { + DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating Profile and level %d, %d", + pParam->eProfile, pParam->eLevel); + return false; + } + if(venc_set_vpx_error_resilience(pParam->bErrorResilientMode) == false) { + DEBUG_PRINT_ERROR("ERROR: Failed to set vpx error resilience"); + return false; + } + if(!venc_set_ltrmode(1, ltrinfo.count)) { + DEBUG_PRINT_ERROR("ERROR: Failed to enable ltrmode"); + return false; + } + + // For VP8, hier-p and ltr are mutually exclusive features in firmware + // Disable hier-p if ltr is enabled. + if (m_codec == OMX_VIDEO_CodingVP8) { + DEBUG_PRINT_LOW("Disable Hier-P as LTR is being set"); + if (!venc_set_hier_layers(QOMX_HIERARCHICALCODING_P, 0)) { + DEBUG_PRINT_ERROR("Disabling Hier P count failed"); + } + } + + break; + } + case (OMX_INDEXTYPE)OMX_IndexParamVideoHevc: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoHevc"); + OMX_VIDEO_PARAM_HEVCTYPE* pParam = (OMX_VIDEO_PARAM_HEVCTYPE*)paramData; + rc_off_level = (int)pParam->eLevel; + if (!venc_set_profile_level (pParam->eProfile, pParam->eLevel)) { + DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating Profile and level %d, %d", + pParam->eProfile, pParam->eLevel); + return false; + } + if (!venc_set_inloop_filter(OMX_VIDEO_AVCLoopFilterEnable)) + DEBUG_PRINT_HIGH("WARN: Request for setting Inloop filter failed for HEVC encoder"); + + OMX_U32 fps = m_sVenc_cfg.fps_num ? m_sVenc_cfg.fps_num / m_sVenc_cfg.fps_den : 30; + OMX_U32 nPFrames = pParam->nKeyFrameInterval > 0 ? pParam->nKeyFrameInterval - 1 : fps - 1; + if (!venc_set_intra_period (nPFrames, 0 /* nBFrames */)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting intra period failed"); + return false; + } + break; + } + case OMX_IndexParamVideoIntraRefresh: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoIntraRefresh"); + OMX_VIDEO_PARAM_INTRAREFRESHTYPE *intra_refresh = + (OMX_VIDEO_PARAM_INTRAREFRESHTYPE *)paramData; + + if (intra_refresh->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (venc_set_intra_refresh(intra_refresh->eRefreshMode, intra_refresh->nCirMBs) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Intra refresh failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoIntraRefresh"); + } + + break; + } + case OMX_IndexParamVideoErrorCorrection: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoErrorCorrection"); + OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE *error_resilience = + (OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE *)paramData; + + if (error_resilience->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (venc_set_error_resilience(error_resilience) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Intra refresh failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoErrorCorrection"); + } + + break; + } + case OMX_IndexParamVideoProfileLevelCurrent: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoProfileLevelCurrent"); + OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = + (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)paramData; + + if (profile_level->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + m_profile_set = false; + m_level_set = false; + rc_off_level = (int)profile_level->eLevel; + if (!venc_set_profile_level (profile_level->eProfile, + profile_level->eLevel)) { + DEBUG_PRINT_ERROR("WARNING: Unsuccessful in updating Profile and level"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoProfileLevelCurrent"); + } + + break; + } + case OMX_IndexParamVideoQuantization: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoQuantization"); + OMX_VIDEO_PARAM_QUANTIZATIONTYPE *session_qp = + (OMX_VIDEO_PARAM_QUANTIZATIONTYPE *)paramData; + if (session_qp->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (venc_set_session_qp (session_qp->nQpI, + session_qp->nQpP, + session_qp->nQpB) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Session QP failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoQuantization"); + } + + break; + } + case QOMX_IndexParamVideoInitialQp: + { + QOMX_EXTNINDEX_VIDEO_INITIALQP * initqp = + (QOMX_EXTNINDEX_VIDEO_INITIALQP *)paramData; + if (initqp->bEnableInitQp) { + DEBUG_PRINT_LOW("Enable initial QP: %d", (int)initqp->bEnableInitQp); + if(venc_enable_initial_qp(initqp) == false) { + DEBUG_PRINT_ERROR("ERROR: Failed to enable initial QP"); + return OMX_ErrorUnsupportedSetting; + } + } else + DEBUG_PRINT_ERROR("ERROR: setting QOMX_IndexParamVideoEnableInitialQp"); + break; + } + case OMX_QcomIndexParamVideoQPRange: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_QcomIndexParamVideoQPRange"); + OMX_QCOM_VIDEO_PARAM_QPRANGETYPE *session_qp_range = + (OMX_QCOM_VIDEO_PARAM_QPRANGETYPE *)paramData; + + if(session_qp_range->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { + if(venc_set_session_qp_range (session_qp_range->minQP, + session_qp_range->maxQP) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting QP Range[%u %u] failed", + (unsigned int)session_qp_range->minQP, (unsigned int)session_qp_range->maxQP); + return false; + } else { + session_qp_values.minqp = session_qp_range->minQP; + session_qp_values.maxqp = session_qp_range->maxQP; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_QcomIndexParamVideoQPRange"); + } + + break; + } + case OMX_QcomIndexParamVideoIPBQPRange: + { + DEBUG_PRINT_LOW("venc_set_param:OMX_QcomIndexParamVideoIPBQPRange"); + OMX_QCOM_VIDEO_PARAM_IPB_QPRANGETYPE *qp = + (OMX_QCOM_VIDEO_PARAM_IPB_QPRANGETYPE *)paramData; + OMX_U32 min_IPB_packed_QP = 0; + OMX_U32 max_IPB_packed_QP = 0; + if (((qp->minIQP >= session_qp_range.minqp) && (qp->maxIQP <= session_qp_range.maxqp)) && + ((qp->minPQP >= session_qp_range.minqp) && (qp->maxPQP <= session_qp_range.maxqp)) && + ((qp->minBQP >= session_qp_range.minqp) && (qp->maxBQP <= session_qp_range.maxqp))) { + + /* When creating the packet, pack the qp value as + * 0xbbppii, where ii = qp range for I-frames, + * pp = qp range for P-frames, etc. */ + min_IPB_packed_QP = qp->minIQP | qp->minPQP << 8 | qp->minBQP << 16; + max_IPB_packed_QP = qp->maxIQP | qp->maxPQP << 8 | qp->maxBQP << 16; + + if (qp->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { + if (venc_set_session_qp_range_packed(min_IPB_packed_QP, + max_IPB_packed_QP) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting IPB QP Range[%d %d] failed", + min_IPB_packed_QP, max_IPB_packed_QP); + return false; + } else { + session_ipb_qp_values.min_i_qp = qp->minIQP; + session_ipb_qp_values.max_i_qp = qp->maxIQP; + session_ipb_qp_values.min_p_qp = qp->minPQP; + session_ipb_qp_values.max_p_qp = qp->maxPQP; + session_ipb_qp_values.min_b_qp = qp->minBQP; + session_ipb_qp_values.max_b_qp = qp->maxBQP; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_QcomIndexParamVideoIPBQPRange"); + } + } else { + DEBUG_PRINT_ERROR("Wrong qp values: IQP range[%u %u], PQP range[%u,%u], BQP[%u,%u] range allowed range[%u %u]", + (unsigned int)qp->minIQP, (unsigned int)qp->maxIQP , (unsigned int)qp->minPQP, + (unsigned int)qp->maxPQP, (unsigned int)qp->minBQP, (unsigned int)qp->maxBQP, + (unsigned int)session_qp_range.minqp, (unsigned int)session_qp_range.maxqp); + } + break; + } + case OMX_QcomIndexEnableSliceDeliveryMode: + { + QOMX_EXTNINDEX_PARAMTYPE* pParam = + (QOMX_EXTNINDEX_PARAMTYPE*)paramData; + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (venc_set_slice_delivery_mode(pParam->bEnable) == false) { + DEBUG_PRINT_ERROR("Setting slice delivery mode failed"); + return OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_ERROR("OMX_QcomIndexEnableSliceDeliveryMode " + "called on wrong port(%u)", (unsigned int)pParam->nPortIndex); + return OMX_ErrorBadPortIndex; + } + + break; + } + case OMX_ExtraDataFrameDimension: + { + DEBUG_PRINT_LOW("venc_set_param: OMX_ExtraDataFrameDimension"); + OMX_BOOL extra_data = *(OMX_BOOL *)(paramData); + + if (venc_set_extradata(OMX_ExtraDataFrameDimension, extra_data) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_ExtraDataFrameDimension failed"); + return false; + } + + extradata = true; + break; + } + case OMX_ExtraDataVideoEncoderSliceInfo: + { + DEBUG_PRINT_LOW("venc_set_param: OMX_ExtraDataVideoEncoderSliceInfo"); + OMX_BOOL extra_data = *(OMX_BOOL *)(paramData); + + if (venc_set_extradata(OMX_ExtraDataVideoEncoderSliceInfo, extra_data) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_ExtraDataVideoEncoderSliceInfo failed"); + return false; + } + + extradata = true; + break; + } + case OMX_ExtraDataVideoEncoderMBInfo: + { + DEBUG_PRINT_LOW("venc_set_param: OMX_ExtraDataVideoEncoderMBInfo"); + OMX_BOOL extra_data = *(OMX_BOOL *)(paramData); + + if (venc_set_extradata(OMX_ExtraDataVideoEncoderMBInfo, extra_data) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_ExtraDataVideoEncoderMBInfo failed"); + return false; + } + + extradata = true; + break; + } + case OMX_QcomIndexParamSequenceHeaderWithIDR: + { + PrependSPSPPSToIDRFramesParams * pParam = + (PrependSPSPPSToIDRFramesParams *)paramData; + + DEBUG_PRINT_LOW("set inband sps/pps: %d", pParam->bEnable); + if(venc_set_inband_video_header(pParam->bEnable) == false) { + DEBUG_PRINT_ERROR("ERROR: set inband sps/pps failed"); + return OMX_ErrorUnsupportedSetting; + } + + break; + } + case OMX_QcomIndexParamH264AUDelimiter: + { + OMX_QCOM_VIDEO_CONFIG_H264_AUD * pParam = + (OMX_QCOM_VIDEO_CONFIG_H264_AUD *)paramData; + + DEBUG_PRINT_LOW("set AU delimiters: %d", pParam->bEnable); + if(venc_set_au_delimiter(pParam->bEnable) == false) { + DEBUG_PRINT_ERROR("ERROR: set H264 AU delimiter failed"); + return OMX_ErrorUnsupportedSetting; + } + + break; + } + case OMX_QcomIndexParamMBIStatisticsMode: + { + OMX_QOMX_VIDEO_MBI_STATISTICS * pParam = + (OMX_QOMX_VIDEO_MBI_STATISTICS *)paramData; + + DEBUG_PRINT_LOW("set MBI Dump mode: %d", pParam->eMBIStatisticsType); + if(venc_set_mbi_statistics_mode(pParam->eMBIStatisticsType) == false) { + DEBUG_PRINT_ERROR("ERROR: set MBI Statistics mode failed"); + return OMX_ErrorUnsupportedSetting; + } + + break; + } + + case OMX_QcomIndexConfigH264EntropyCodingCabac: + { + QOMX_VIDEO_H264ENTROPYCODINGTYPE * pParam = + (QOMX_VIDEO_H264ENTROPYCODINGTYPE *)paramData; + + DEBUG_PRINT_LOW("set Entropy info : %d", pParam->bCabac); + if(venc_set_entropy_config (pParam->bCabac, 0) == false) { + DEBUG_PRINT_ERROR("ERROR: set Entropy failed"); + return OMX_ErrorUnsupportedSetting; + } + + break; + } + + case OMX_QcomIndexHierarchicalStructure: + { + QOMX_VIDEO_HIERARCHICALLAYERS* pParam = + (QOMX_VIDEO_HIERARCHICALLAYERS*)paramData; + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + if (!venc_set_hier_layers(pParam->eHierarchicalCodingType, pParam->nNumLayers)) { + DEBUG_PRINT_ERROR("Setting Hier P count failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("OMX_QcomIndexHierarchicalStructure called on wrong port(%d)", (int)pParam->nPortIndex); + return false; + } + + // For VP8, hier-p and ltr are mutually exclusive features in firmware + // Disable ltr if hier-p is enabled. + if (m_codec == OMX_VIDEO_CodingVP8) { + DEBUG_PRINT_LOW("Disable LTR as HIER-P is being set"); + if(!venc_set_ltrmode(0, 0)) { + DEBUG_PRINT_ERROR("ERROR: Failed to disable ltrmode"); + } + } + break; + } + case OMX_QcomIndexParamPerfLevel: + { + OMX_QCOM_VIDEO_PARAM_PERF_LEVEL *pParam = + (OMX_QCOM_VIDEO_PARAM_PERF_LEVEL *)paramData; + DEBUG_PRINT_LOW("Set perf level: %d", pParam->ePerfLevel); + if (!venc_set_perf_level(pParam->ePerfLevel)) { + DEBUG_PRINT_ERROR("ERROR: Failed to set perf level to %d", pParam->ePerfLevel); + return false; + } else { + performance_level.perflevel = (unsigned int) pParam->ePerfLevel; + } + break; + } + case OMX_QcomIndexParamH264VUITimingInfo: + { + OMX_QCOM_VIDEO_PARAM_VUI_TIMING_INFO *pParam = + (OMX_QCOM_VIDEO_PARAM_VUI_TIMING_INFO *)paramData; + DEBUG_PRINT_LOW("Set VUI timing info: %d", pParam->bEnable); + if(venc_set_vui_timing_info(pParam->bEnable) == false) { + DEBUG_PRINT_ERROR("ERROR: Failed to set vui timing info to %d", pParam->bEnable); + return false; + } else { + vui_timing_info.enabled = (unsigned int) pParam->bEnable; + } + break; + } + case OMX_QTIIndexParamVQZIPSEIType: + { + OMX_QTI_VIDEO_PARAM_VQZIP_SEI_TYPE*pParam = + (OMX_QTI_VIDEO_PARAM_VQZIP_SEI_TYPE *)paramData; + DEBUG_PRINT_LOW("Enable VQZIP SEI: %d", pParam->bEnable); + if(venc_set_vqzip_sei_type(pParam->bEnable) == false) { + DEBUG_PRINT_ERROR("ERROR: Failed to set VQZIP SEI type %d", pParam->bEnable); + return false; + } + break; + } + case OMX_QcomIndexParamPeakBitrate: + { + OMX_QCOM_VIDEO_PARAM_PEAK_BITRATE *pParam = + (OMX_QCOM_VIDEO_PARAM_PEAK_BITRATE *)paramData; + DEBUG_PRINT_LOW("Set peak bitrate: %u", (unsigned int)pParam->nPeakBitrate); + if(venc_set_peak_bitrate(pParam->nPeakBitrate) == false) { + DEBUG_PRINT_ERROR("ERROR: Failed to set peak bitrate to %u", (unsigned int)pParam->nPeakBitrate); + return false; + } else { + peak_bitrate.peakbitrate = (unsigned int) pParam->nPeakBitrate; + } + break; + } + case OMX_QcomIndexParamSetMVSearchrange: + { + DEBUG_PRINT_LOW("venc_set_config: OMX_QcomIndexParamSetMVSearchrange"); + is_searchrange_set = true; + if (!venc_set_searchrange()) { + DEBUG_PRINT_ERROR("ERROR: Failed to set search range"); + return false; + } + } + break; + case OMX_QcomIndexParamVideoLTRCount: + { + DEBUG_PRINT_LOW("venc_set_param: OMX_QcomIndexParamVideoLTRCount"); + OMX_QCOM_VIDEO_PARAM_LTRCOUNT_TYPE* pParam = + (OMX_QCOM_VIDEO_PARAM_LTRCOUNT_TYPE*)paramData; + if (pParam->nCount > 0) { + if (venc_set_ltrmode(1, pParam->nCount) == false) { + DEBUG_PRINT_ERROR("ERROR: Enable LTR mode failed"); + return false; + } + } else { + if (venc_set_ltrmode(0, 0) == false) { + DEBUG_PRINT_ERROR("ERROR: Disable LTR mode failed"); + return false; + } + } + break; + } + case OMX_QcomIndexParamVideoHybridHierpMode: + { + if (!venc_set_hybrid_hierp((QOMX_EXTNINDEX_VIDEO_HYBRID_HP_MODE*)paramData)) { + DEBUG_PRINT_ERROR("Setting hybrid Hier-P mode failed"); + return false; + } + break; + } + case OMX_QcomIndexParamBatchSize: + { + OMX_PARAM_U32TYPE* pParam = + (OMX_PARAM_U32TYPE*)paramData; + + if (pParam->nPortIndex == PORT_INDEX_OUT) { + DEBUG_PRINT_ERROR("For the moment, client-driven batching not supported" + " on output port"); + return OMX_ErrorUnsupportedSetting; + } + + if (!venc_set_batch_size(pParam->nU32)) { + DEBUG_PRINT_ERROR("Failed setting batch size as %d", pParam->nU32); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QcomIndexParamVencAspectRatio: + { + if (!venc_set_aspectratio(paramData)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_QcomIndexParamVencAspectRatio failed"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QTIIndexParamLowLatencyMode: + { + QOMX_EXTNINDEX_VIDEO_VENC_LOW_LATENCY_MODE* pParam = + (QOMX_EXTNINDEX_VIDEO_VENC_LOW_LATENCY_MODE*)paramData; + if (!venc_set_low_latency(pParam->bLowLatencyMode)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_QTIIndexParamLowLatencyMode failed"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_QTIIndexParamVideoEnableRoiInfo: + { + struct v4l2_control control; + if (m_sVenc_cfg.codectype != V4L2_PIX_FMT_H264 && + m_sVenc_cfg.codectype != V4L2_PIX_FMT_HEVC) { + DEBUG_PRINT_ERROR("OMX_QTIIndexParamVideoEnableRoiInfo is not supported for %lu codec", m_sVenc_cfg.codectype); + return OMX_ErrorUnsupportedSetting; + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + control.value = V4L2_MPEG_VIDC_EXTRADATA_ROI_QP; + DEBUG_PRINT_LOW("Setting param OMX_QTIIndexParamVideoEnableRoiInfo"); + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("ERROR: Setting OMX_QTIIndexParamVideoEnableRoiInfo failed"); + return OMX_ErrorUnsupportedSetting; + } +#ifdef _PQ_ + m_pq.pConfig.a_qp.roi_enabled = (OMX_U32)true; + allocate_extradata(&m_pq.roi_extradata_info, ION_FLAG_CACHED); + m_pq.configure(m_sVenc_cfg.input_width, m_sVenc_cfg.input_height); +#endif // _PQ_ + break; + } + case OMX_QcomIndexConfigVideoVencLowLatencyMode: + { + QOMX_ENABLETYPE *pParam = (QOMX_ENABLETYPE*)paramData; + + if (!venc_set_lowlatency_mode(pParam->bEnable)) { + DEBUG_PRINT_ERROR("Setting low latency mode failed"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_IndexParamAndroidVideoTemporalLayering: + { + if (venc_set_temporal_layers( + (OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE*)paramData) != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("set_param: Failed to configure temporal layers"); + return false; + } + break; + } + case OMX_QTIIndexParamDisablePQ: + { + QOMX_DISABLETYPE * pParam = (QOMX_DISABLETYPE *)paramData; + DEBUG_PRINT_LOW("venc_set_param: OMX_QTIIndexParamDisablePQ: %d", pParam->bDisable); +#ifdef _PQ_ + if (pParam->bDisable) + m_pq.is_pq_force_disable = true; +#endif + break; + } + case OMX_IndexParamVideoSliceFMO: + default: + DEBUG_PRINT_ERROR("ERROR: Unsupported parameter in venc_set_param: %u", + index); + break; + //case + } + + return true; +} + +bool venc_dev::venc_check_valid_config() +{ + if (streaming[OUTPUT_PORT] && streaming[CAPTURE_PORT] && + ((m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264 && hier_layers.hier_mode == HIER_P_HYBRID) || + (m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC && hier_layers.hier_mode == HIER_P))) { + DEBUG_PRINT_ERROR("venc_set_config not allowed run time for following usecases"); + DEBUG_PRINT_ERROR("For H264 : When Hybrid Hier P enabled"); + DEBUG_PRINT_ERROR("For H265 : When Hier P enabled"); + return false; + } + return true; +} + +bool venc_dev::venc_set_config(void *configData, OMX_INDEXTYPE index) +{ + + DEBUG_PRINT_LOW("Inside venc_set_config"); + + if(!venc_check_valid_config()) { + DEBUG_PRINT_ERROR("venc_set_config not allowed for this configuration"); + return false; + } + + switch ((int)index) { + case OMX_IndexConfigVideoBitrate: + { + OMX_VIDEO_CONFIG_BITRATETYPE *bit_rate = (OMX_VIDEO_CONFIG_BITRATETYPE *) + configData; + DEBUG_PRINT_LOW("venc_set_config: OMX_IndexConfigVideoBitrate"); + + if (bit_rate->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { + if (venc_set_target_bitrate(bit_rate->nEncodeBitrate, 1) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Target Bit rate failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexConfigVideoBitrate"); + } + + break; + } + case OMX_IndexConfigVideoFramerate: + { + OMX_CONFIG_FRAMERATETYPE *frame_rate = (OMX_CONFIG_FRAMERATETYPE *) + configData; + DEBUG_PRINT_LOW("venc_set_config: OMX_IndexConfigVideoFramerate"); + + if (frame_rate->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { + if (venc_set_encode_framerate(frame_rate->xEncodeFramerate, 1) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Encode Framerate failed"); + return false; + } +#ifdef _PQ_ + venc_try_enable_pq(); +#endif // _PQ_ + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexConfigVideoFramerate"); + } + + break; + } + case QOMX_IndexConfigVideoIntraperiod: + { + DEBUG_PRINT_LOW("venc_set_param:QOMX_IndexConfigVideoIntraperiod"); + QOMX_VIDEO_INTRAPERIODTYPE *intraperiod = + (QOMX_VIDEO_INTRAPERIODTYPE *)configData; + + if (intraperiod->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + if (venc_set_intra_period(intraperiod->nPFrames, intraperiod->nBFrames) == false) { + DEBUG_PRINT_ERROR("ERROR: Request for setting intra period failed"); + return false; + } + } + + break; + } + case OMX_IndexConfigVideoIntraVOPRefresh: + { + OMX_CONFIG_INTRAREFRESHVOPTYPE *intra_vop_refresh = (OMX_CONFIG_INTRAREFRESHVOPTYPE *) + configData; + DEBUG_PRINT_LOW("venc_set_config: OMX_IndexConfigVideoIntraVOPRefresh"); + + if (intra_vop_refresh->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { + if (venc_set_intra_vop_refresh(intra_vop_refresh->IntraRefreshVOP) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Encode Framerate failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexConfigVideoFramerate"); + } + + break; + } + case OMX_IndexConfigCommonRotate: + { + OMX_CONFIG_ROTATIONTYPE *config_rotation = + reinterpret_cast<OMX_CONFIG_ROTATIONTYPE*>(configData); + OMX_U32 nFrameWidth; + if (!config_rotation) { + return false; + } + if (true == deinterlace_enabled) { + DEBUG_PRINT_ERROR("ERROR: Rotation is not supported with deinterlacing"); + return false; + } + if(venc_set_vpe_rotation(config_rotation->nRotation) == false) { + DEBUG_PRINT_ERROR("ERROR: Dimension Change for Rotation failed"); + return false; + } + + break; + } + case OMX_IndexConfigVideoAVCIntraPeriod: + { + OMX_VIDEO_CONFIG_AVCINTRAPERIOD *avc_iperiod = (OMX_VIDEO_CONFIG_AVCINTRAPERIOD*) configData; + DEBUG_PRINT_LOW("venc_set_param: OMX_IndexConfigVideoAVCIntraPeriod"); + + if (venc_set_idr_period(avc_iperiod->nPFrames, avc_iperiod->nIDRPeriod) + == false) { + DEBUG_PRINT_ERROR("ERROR: Setting " + "OMX_IndexConfigVideoAVCIntraPeriod failed"); + return false; + } + break; + } + case OMX_IndexConfigCommonDeinterlace: + { + OMX_VIDEO_CONFIG_DEINTERLACE *deinterlace = (OMX_VIDEO_CONFIG_DEINTERLACE *) configData; + DEBUG_PRINT_LOW("venc_set_config: OMX_IndexConfigCommonDeinterlace"); + if(deinterlace->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { + if (m_sVenc_cfg.dvs_width == m_sVenc_cfg.input_height && + m_sVenc_cfg.dvs_height == m_sVenc_cfg.input_width) + { + DEBUG_PRINT_ERROR("ERROR: Deinterlace not supported with rotation"); + return false; + } + if(venc_set_deinterlace(deinterlace->nEnable) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Deinterlace failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexConfigCommonDeinterlace"); + } + break; + } + case OMX_IndexConfigVideoVp8ReferenceFrame: + { + OMX_VIDEO_VP8REFERENCEFRAMETYPE* vp8refframe = (OMX_VIDEO_VP8REFERENCEFRAMETYPE*) configData; + DEBUG_PRINT_LOW("venc_set_config: OMX_IndexConfigVideoVp8ReferenceFrame"); + if ((vp8refframe->nPortIndex == (OMX_U32)PORT_INDEX_IN) && + (vp8refframe->bUseGoldenFrame)) { + if(venc_set_useltr(0x1) == false) { + DEBUG_PRINT_ERROR("ERROR: use goldenframe failed"); + return false; + } + } else if((vp8refframe->nPortIndex == (OMX_U32)PORT_INDEX_IN) && + (vp8refframe->bGoldenFrameRefresh)) { + if(venc_set_markltr(0x1) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting goldenframe failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexConfigVideoVp8ReferenceFrame"); + } + break; + } + case OMX_QcomIndexConfigVideoLTRUse: + { + OMX_QCOM_VIDEO_CONFIG_LTRUSE_TYPE* pParam = (OMX_QCOM_VIDEO_CONFIG_LTRUSE_TYPE*)configData; + DEBUG_PRINT_LOW("venc_set_config: OMX_QcomIndexConfigVideoLTRUse"); + if (pParam->nPortIndex == (OMX_U32)PORT_INDEX_IN) { + if (venc_set_useltr(pParam->nID) == false) { + DEBUG_PRINT_ERROR("ERROR: Use LTR failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_QcomIndexConfigVideoLTRUse"); + } + break; + } + case OMX_QcomIndexConfigVideoLTRMark: + { + OMX_QCOM_VIDEO_CONFIG_LTRMARK_TYPE* pParam = (OMX_QCOM_VIDEO_CONFIG_LTRMARK_TYPE*)configData; + DEBUG_PRINT_LOW("venc_set_config: OMX_QcomIndexConfigVideoLTRMark"); + if (pParam->nPortIndex == (OMX_U32)PORT_INDEX_IN) { + if (venc_set_markltr(pParam->nID) == false) { + DEBUG_PRINT_ERROR("ERROR: Mark LTR failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_QcomIndexConfigVideoLTRMark"); + } + break; + } + case OMX_QcomIndexConfigPerfLevel: + { + OMX_QCOM_VIDEO_CONFIG_PERF_LEVEL *perf = + (OMX_QCOM_VIDEO_CONFIG_PERF_LEVEL *)configData; + DEBUG_PRINT_LOW("Set perf level: %d", perf->ePerfLevel); + if (!venc_set_perf_level(perf->ePerfLevel)) { + DEBUG_PRINT_ERROR("ERROR: Failed to set perf level to %d", perf->ePerfLevel); + return false; + } else { + performance_level.perflevel = (unsigned int) perf->ePerfLevel; + } + break; + } + case OMX_QcomIndexConfigVideoVencPerfMode: + { + QOMX_EXTNINDEX_VIDEO_PERFMODE *pParam = (QOMX_EXTNINDEX_VIDEO_PERFMODE *) configData; + DEBUG_PRINT_LOW("venc_set_config: OMX_QcomIndexConfigVideoVencPerfMode"); + if (venc_set_perf_mode(pParam->nPerfMode) == false) { + DEBUG_PRINT_ERROR("Failed to set V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE"); + return false; + } + break; + } + case OMX_QcomIndexConfigNumHierPLayers: + { + QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS *pParam = + (QOMX_EXTNINDEX_VIDEO_HIER_P_LAYERS *) configData; + DEBUG_PRINT_LOW("venc_set_config: OMX_QcomIndexConfigNumHierPLayers"); + if (venc_set_hierp_layers(pParam->nNumHierLayers) == false) { + DEBUG_PRINT_ERROR("Failed to set OMX_QcomIndexConfigNumHierPLayers"); + return false; + } + break; + } + case OMX_QcomIndexConfigBaseLayerId: + { + OMX_SKYPE_VIDEO_CONFIG_BASELAYERPID* pParam = + (OMX_SKYPE_VIDEO_CONFIG_BASELAYERPID*) configData; + if (venc_set_baselayerid(pParam->nPID) == false) { + DEBUG_PRINT_ERROR("Failed to set OMX_QcomIndexConfigBaseLayerId failed"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_IndexParamAndroidVideoTemporalLayering: + { + DEBUG_PRINT_ERROR("TemporalLayer: Changing layer-configuration dynamically is not supported!"); + return false; + } + case OMX_QcomIndexConfigQp: + { + OMX_SKYPE_VIDEO_CONFIG_QP* pParam = + (OMX_SKYPE_VIDEO_CONFIG_QP*) configData; + if (venc_set_qp(pParam->nQP) == false) { + DEBUG_PRINT_ERROR("Failed to set OMX_QcomIndexConfigQp failed"); + return OMX_ErrorUnsupportedSetting; + } + break; + } + case OMX_IndexConfigPriority: + { + OMX_PARAM_U32TYPE *priority = (OMX_PARAM_U32TYPE *)configData; + DEBUG_PRINT_LOW("Set_config: priority %d",priority->nU32); + if (!venc_set_priority(priority->nU32)) { + DEBUG_PRINT_ERROR("Failed to set priority"); + return false; + } + break; + } + case OMX_IndexConfigOperatingRate: + { + OMX_PARAM_U32TYPE *rate = (OMX_PARAM_U32TYPE *)configData; + DEBUG_PRINT_LOW("Set_config: operating rate %d", rate->nU32); + if (!venc_set_operatingrate(rate->nU32)) { + DEBUG_PRINT_ERROR("Failed to set operating rate"); + return false; + } + break; + } +#ifdef SUPPORT_CONFIG_INTRA_REFRESH + case OMX_IndexConfigAndroidIntraRefresh: + { + OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *intra_refresh = (OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *)configData; + DEBUG_PRINT_LOW("OMX_IndexConfigAndroidIntraRefresh : num frames = %d", intra_refresh->nRefreshPeriod); + + if (intra_refresh->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { + OMX_U32 mb_size = m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC ? 32 : 16; + OMX_U32 num_mbs_per_frame = (ALIGN(m_sVenc_cfg.dvs_height, mb_size)/mb_size) * (ALIGN(m_sVenc_cfg.dvs_width, mb_size)/mb_size); + OMX_U32 num_intra_refresh_mbs = ceil(num_mbs_per_frame / intra_refresh->nRefreshPeriod); + + if (venc_set_intra_refresh(OMX_VIDEO_IntraRefreshRandom, num_intra_refresh_mbs) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting Intra refresh failed"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexConfigVideoIntraRefreshType"); + } + break; + } +#endif + case OMX_QTIIndexConfigVideoBlurResolution: + { + OMX_QTI_VIDEO_CONFIG_BLURINFO *blur = (OMX_QTI_VIDEO_CONFIG_BLURINFO *)configData; + if (blur->nPortIndex == (OMX_U32)PORT_INDEX_IN) { + DEBUG_PRINT_LOW("Set_config: blur resolution: %d", blur->eTargetResol); + if(!venc_set_blur_resolution(blur)) { + DEBUG_PRINT_ERROR("Failed to set Blur Resolution"); + return false; + } + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_QTIIndexConfigVideoBlurResolution"); + return false; + } + break; + } + case OMX_QcomIndexConfigH264Transform8x8: + { + OMX_CONFIG_BOOLEANTYPE *pEnable = (OMX_CONFIG_BOOLEANTYPE *) configData; + DEBUG_PRINT_LOW("venc_set_config: OMX_QcomIndexConfigH264Transform8x8"); + if (venc_h264_transform_8x8(pEnable->bEnabled) == false) { + DEBUG_PRINT_ERROR("Failed to set OMX_QcomIndexConfigH264Transform8x8"); + return false; + } + break; + } + case OMX_QTIIndexConfigDescribeColorAspects: + { + DescribeColorAspectsParams *params = (DescribeColorAspectsParams *)configData; + + OMX_U32 color_space = MSM_VIDC_BT601_6_625; + OMX_U32 full_range = 0; + OMX_U32 matrix_coeffs = MSM_VIDC_MATRIX_601_6_625; + OMX_U32 transfer_chars = MSM_VIDC_TRANSFER_601_6_625; + + switch((ColorAspects::Primaries)(params->sAspects.mPrimaries)) { + case ColorAspects::PrimariesBT709_5: + color_space = MSM_VIDC_BT709_5; + break; + case ColorAspects::PrimariesBT470_6M: + color_space = MSM_VIDC_BT470_6_M; + break; + case ColorAspects::PrimariesBT601_6_625: + color_space = MSM_VIDC_BT601_6_625; + break; + case ColorAspects::PrimariesBT601_6_525: + color_space = MSM_VIDC_BT601_6_525; + break; + case ColorAspects::PrimariesGenericFilm: + color_space = MSM_VIDC_GENERIC_FILM; + break; + case ColorAspects::PrimariesBT2020: + color_space = MSM_VIDC_BT2020; + break; + default: + color_space = MSM_VIDC_BT601_6_625; + //params->sAspects.mPrimaries = ColorAspects::PrimariesBT601_6_625; + break; + } + switch((ColorAspects::Range)params->sAspects.mRange) { + case ColorAspects::RangeFull: + full_range = 1; + break; + case ColorAspects::RangeLimited: + full_range = 0; + break; + default: + break; + } + switch((ColorAspects::Transfer)params->sAspects.mTransfer) { + case ColorAspects::TransferSMPTE170M: + transfer_chars = MSM_VIDC_TRANSFER_601_6_525; + break; + case ColorAspects::TransferUnspecified: + transfer_chars = MSM_VIDC_TRANSFER_UNSPECIFIED; + break; + case ColorAspects::TransferGamma22: + transfer_chars = MSM_VIDC_TRANSFER_BT_470_6_M; + break; + case ColorAspects::TransferGamma28: + transfer_chars = MSM_VIDC_TRANSFER_BT_470_6_BG; + break; + case ColorAspects::TransferSMPTE240M: + transfer_chars = MSM_VIDC_TRANSFER_SMPTE_240M; + break; + case ColorAspects::TransferLinear: + transfer_chars = MSM_VIDC_TRANSFER_LINEAR; + break; + case ColorAspects::TransferXvYCC: + transfer_chars = MSM_VIDC_TRANSFER_IEC_61966; + break; + case ColorAspects::TransferBT1361: + transfer_chars = MSM_VIDC_TRANSFER_BT_1361; + break; + case ColorAspects::TransferSRGB: + transfer_chars = MSM_VIDC_TRANSFER_SRGB; + break; + default: + //params->sAspects.mTransfer = ColorAspects::TransferSMPTE170M; + transfer_chars = MSM_VIDC_TRANSFER_601_6_625; + break; + } + switch((ColorAspects::MatrixCoeffs)params->sAspects.mMatrixCoeffs) { + case ColorAspects::MatrixUnspecified: + matrix_coeffs = MSM_VIDC_MATRIX_UNSPECIFIED; + break; + case ColorAspects::MatrixBT709_5: + matrix_coeffs = MSM_VIDC_MATRIX_BT_709_5; + break; + case ColorAspects::MatrixBT470_6M: + matrix_coeffs = MSM_VIDC_MATRIX_FCC_47; + break; + case ColorAspects::MatrixBT601_6: + matrix_coeffs = MSM_VIDC_MATRIX_601_6_525; + break; + case ColorAspects::MatrixSMPTE240M: + transfer_chars = MSM_VIDC_MATRIX_SMPTE_240M; + break; + case ColorAspects::MatrixBT2020: + matrix_coeffs = MSM_VIDC_MATRIX_BT_2020; + break; + case ColorAspects::MatrixBT2020Constant: + matrix_coeffs = MSM_VIDC_MATRIX_BT_2020_CONST; + break; + default: + //params->sAspects.mMatrixCoeffs = ColorAspects::MatrixBT601_6; + matrix_coeffs = MSM_VIDC_MATRIX_601_6_625; + break; + } + if (!venc_set_colorspace(color_space, full_range, + transfer_chars, matrix_coeffs)) { + + DEBUG_PRINT_ERROR("Failed to set operating rate"); + return false; + } + break; + } + case OMX_QTIIndexConfigVideoRoiInfo: + { + if(!venc_set_roi_qp_info((OMX_QTI_VIDEO_CONFIG_ROIINFO *)configData)) { + DEBUG_PRINT_ERROR("Failed to set ROI QP info"); + return false; + } + break; + } + default: + DEBUG_PRINT_ERROR("Unsupported config index = %u", index); + break; + } + + return true; +} + +unsigned venc_dev::venc_stop( void) +{ + struct venc_msg venc_msg; + struct v4l2_requestbuffers bufreq; + int rc = 0, ret = 0; + + if (!stopped) { + enum v4l2_buf_type cap_type; + + if (streaming[OUTPUT_PORT]) { + cap_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + rc = ioctl(m_nDriver_fd, VIDIOC_STREAMOFF, &cap_type); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to call streamoff on driver: capability: %d, %d", + cap_type, rc); + } else + streaming[OUTPUT_PORT] = false; + + DEBUG_PRINT_LOW("Releasing registered buffers from driver on o/p port"); + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = 0; + bufreq.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + ret = ioctl(m_nDriver_fd, VIDIOC_REQBUFS, &bufreq); + + if (ret) { + DEBUG_PRINT_ERROR("ERROR: VIDIOC_REQBUFS OUTPUT MPLANE Failed"); + return false; + } + } + + if (!rc && streaming[CAPTURE_PORT]) { + cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + rc = ioctl(m_nDriver_fd, VIDIOC_STREAMOFF, &cap_type); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to call streamoff on driver: capability: %d, %d", + cap_type, rc); + } else + streaming[CAPTURE_PORT] = false; + + DEBUG_PRINT_LOW("Releasing registered buffers from driver on capture port"); + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = 0; + bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + ret = ioctl(m_nDriver_fd, VIDIOC_REQBUFS, &bufreq); + + if (ret) { + DEBUG_PRINT_ERROR("ERROR: VIDIOC_REQBUFS CAPTURE MPLANE Failed"); + return false; + } + } + + if (!rc && !ret) { + venc_stop_done(); + stopped = 1; + /*set flag to re-configure when started again*/ + resume_in_stopped = 1; + + } + } + + return rc; +} + +unsigned venc_dev::venc_pause(void) +{ + pthread_mutex_lock(&pause_resume_mlock); + paused = true; + pthread_mutex_unlock(&pause_resume_mlock); + return 0; +} + +unsigned venc_dev::venc_resume(void) +{ + pthread_mutex_lock(&pause_resume_mlock); + paused = false; + pthread_mutex_unlock(&pause_resume_mlock); + + return pthread_cond_signal(&pause_resume_cond); +} + +unsigned venc_dev::venc_start_done(void) +{ + struct venc_msg venc_msg; + venc_msg.msgcode = VEN_MSG_START; + venc_msg.statuscode = VEN_S_SUCCESS; + venc_handle->async_message_process(venc_handle,&venc_msg); + return 0; +} + +unsigned venc_dev::venc_stop_done(void) +{ + struct venc_msg venc_msg; + free_extradata_all(); + venc_msg.msgcode=VEN_MSG_STOP; + venc_msg.statuscode=VEN_S_SUCCESS; + venc_handle->async_message_process(venc_handle,&venc_msg); + return 0; +} + +unsigned venc_dev::venc_set_message_thread_id(pthread_t tid) +{ + async_thread_created = true; + m_tid=tid; + return 0; +} + +bool venc_dev::venc_set_vqzip_defaults() +{ + struct v4l2_control control; + int rc = 0, num_mbs_per_frame; + + num_mbs_per_frame = m_sVenc_cfg.input_height * m_sVenc_cfg.input_width; + + switch (num_mbs_per_frame) { + case OMX_CORE_720P_WIDTH * OMX_CORE_720P_HEIGHT: + case OMX_CORE_1080P_WIDTH * OMX_CORE_1080P_HEIGHT: + case OMX_CORE_4KUHD_WIDTH * OMX_CORE_4KUHD_HEIGHT: + case OMX_CORE_4KDCI_WIDTH * OMX_CORE_4KDCI_HEIGHT: + break; + default: + DEBUG_PRINT_ERROR("VQZIP is not supported for this resoultion : %lu X %lu", + m_sVenc_cfg.input_width, m_sVenc_cfg.input_height); + return false; + } + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL; + control.value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF; + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) + DEBUG_PRINT_ERROR("Failed to set Rate Control OFF for VQZIP"); + control.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES; + control.value = INT_MAX; + + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) + DEBUG_PRINT_ERROR("Failed to set P frame period for VQZIP"); + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES; + control.value = 0; + + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) + DEBUG_PRINT_ERROR("Failed to set B frame period for VQZIP"); + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE; + control.value = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY; + + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) + DEBUG_PRINT_ERROR("Failed to set Max quality for VQZIP"); + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD; + control.value = 1; + + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) + DEBUG_PRINT_ERROR("Failed to set IDR period for VQZIP"); + + return true; +} + +unsigned venc_dev::venc_start(void) +{ + enum v4l2_buf_type buf_type; + int ret, r; + struct v4l2_control control; + + memset(&control, 0, sizeof(control)); + + DEBUG_PRINT_HIGH("%s(): Check Profile/Level set in driver before start", + __func__); + m_level_set = false; + + if (!venc_set_profile_level(0, 0)) { + DEBUG_PRINT_ERROR("ERROR: %s(): Driver Profile/Level is NOT SET", + __func__); + } else { + DEBUG_PRINT_HIGH("%s(): Driver Profile[%lu]/Level[%lu] successfully SET", + __func__, codec_profile.profile, profile_level.level); + } + +#ifdef _PQ_ + /* + * Make sure that PQ is still applicable for given configuration. + * This call mainly disables PQ if current encoder configuration + * doesn't support PQ. PQ cann't enabled here as buffer allocation + * is already done by this time. + */ + venc_try_enable_pq(); +#endif // _PQ_ + + if (vqzip_sei_info.enabled && !venc_set_vqzip_defaults()) + return 1; + + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) + venc_set_low_latency((OMX_BOOL)!intra_period.num_bframes); + + // re-configure the temporal layers as RC-mode and key-frame interval + // might have changed since the client last configured the layers. + if (temporal_layers_config.nPLayers) { + if (venc_set_temporal_layers_internal() != OMX_ErrorNone) { + DEBUG_PRINT_ERROR("Re-configuring temporal layers failed !"); + } else { + // request buffers on capture port again since internal (scratch)- + // buffer requirements may change (i.e if we switch from non-hybrid + // to hybrid mode and vice-versa) + struct v4l2_requestbuffers bufreq; + + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = m_sOutput_buff_property.actualcount; + bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (ioctl(m_nDriver_fd, VIDIOC_REQBUFS, &bufreq)) { + DEBUG_PRINT_ERROR("Request bufs failed while reconfiguring layers"); + } + } + } + + venc_config_print(); + + if(resume_in_stopped){ + /*set buffercount when restarted*/ + venc_reconfig_reqbufs(); + resume_in_stopped = 0; + } + + /* Check if slice_delivery mode is enabled & max slices is sufficient for encoding complete frame */ + if (slice_mode.enable && multislice.mslice_size && + (m_sVenc_cfg.dvs_width * m_sVenc_cfg.dvs_height)/(256 * multislice.mslice_size) >= MAX_SUPPORTED_SLICES_PER_FRAME) { + DEBUG_PRINT_ERROR("slice_mode: %lu, max slices (%lu) should be less than (%d)", slice_mode.enable, + (m_sVenc_cfg.dvs_width * m_sVenc_cfg.dvs_height)/(256 * multislice.mslice_size), + MAX_SUPPORTED_SLICES_PER_FRAME); + return 1; + } + + buf_type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing"); + ret=ioctl(m_nDriver_fd, VIDIOC_STREAMON,&buf_type); + + if (ret) + return 1; + + streaming[CAPTURE_PORT] = true; + + /* + * Workaround for Skype usecase. Skpye doesn't like SPS\PPS come as + seperate buffer. It wants SPS\PPS with IDR frame FTB. + */ + + if (!venc_handle->m_slowLatencyMode.bLowLatencyMode) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER; + control.value = 1; + ret = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (ret) { + DEBUG_PRINT_ERROR("failed to request seq header"); + return 1; + } + } + + /* This is intentionally done after SEQ_HEADER check. Because + * PIC_ORDER_CNT is tightly coupled with lowlatency. Low latency + * flag is also overloaded not to send SPS in separate buffer. + * Hence lowlatency setting is done after SEQ_HEADER check. + * Don't change this sequence unless you know what you are doing. + */ + + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) + venc_set_low_latency((OMX_BOOL)!intra_period.num_bframes); + + stopped = 0; + return 0; +} + +inline const char* hiermode_string(int val) +{ + switch(val) + { + case HIER_NONE: + return "No Hier"; + case HIER_P: + return "Hier-P"; + case HIER_B: + return "Hier-B"; + case HIER_P_HYBRID: + return "Hybrid Hier-P"; + default: + return "No hier"; + } +} + +inline const char* bitrate_type_string(int val) +{ + switch(val) + { + case V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_DISABLE: + return "CUMULATIVE"; + case V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_ENABLE: + return "LAYER WISE"; + default: + return "Unknown Bitrate Type"; + } +} + +static const char *codec_as_string(unsigned long codec) { + switch (codec) { + case V4L2_PIX_FMT_H264: + return "H264"; + case V4L2_PIX_FMT_MPEG4: + return "MPEG4"; + case V4L2_PIX_FMT_H263: + return "H263"; + case V4L2_PIX_FMT_HEVC: + return "HEVC"; + case V4L2_PIX_FMT_VP8: + return "VP8"; + default: + return "UNKOWN"; + } +} + +void venc_dev::venc_config_print() +{ + + DEBUG_PRINT_HIGH("ENC_CONFIG: Codec: %s, Profile %ld, level : %ld", + codec_as_string(m_sVenc_cfg.codectype), codec_profile.profile, profile_level.level); + + DEBUG_PRINT_HIGH("ENC_CONFIG: Input Width: %ld, Height:%ld, Fps: %ld", + m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, + m_sVenc_cfg.fps_num/m_sVenc_cfg.fps_den); + + DEBUG_PRINT_HIGH("ENC_CONFIG: Output Width: %ld, Height:%ld, Fps: %ld", + m_sVenc_cfg.dvs_width, m_sVenc_cfg.dvs_height, + m_sVenc_cfg.fps_num/m_sVenc_cfg.fps_den); + + DEBUG_PRINT_HIGH("ENC_CONFIG: Color Space: Primaries = %u, Range = %u, Transfer Chars = %u, Matrix Coeffs = %u", + color_space.primaries, color_space.range, color_space.transfer_chars, color_space.matrix_coeffs); + + DEBUG_PRINT_HIGH("ENC_CONFIG: Bitrate: %ld, RC: %ld, P - Frames : %ld, B - Frames = %ld", + bitrate.target_bitrate, rate_ctrl.rcmode, intra_period.num_pframes, intra_period.num_bframes); + + DEBUG_PRINT_HIGH("ENC_CONFIG: qpI: %ld, qpP: %ld, qpb: %ld", + session_qp.iframeqp, session_qp.pframeqp, session_qp.bframeqp); + + DEBUG_PRINT_HIGH("ENC_CONFIG: Init_qpI: %ld, Init_qpP: %ld, Init_qpb: %ld", + init_qp.iframeqp, init_qp.pframeqp, init_qp.bframeqp); + + DEBUG_PRINT_HIGH("ENC_CONFIG: minQP: %lu, maxQP: %lu", + session_qp_values.minqp, session_qp_values.maxqp); + + DEBUG_PRINT_HIGH("ENC_CONFIG: VOP_Resolution: %ld, Slice-Mode: %ld, Slize_Size: %ld", + voptimecfg.voptime_resolution, multislice.mslice_mode, + multislice.mslice_size); + + DEBUG_PRINT_HIGH("ENC_CONFIG: EntropyMode: %d, CabacModel: %ld", + entropy.longentropysel, entropy.cabacmodel); + + DEBUG_PRINT_HIGH("ENC_CONFIG: DB-Mode: %ld, alpha: %ld, Beta: %ld", + dbkfilter.db_mode, dbkfilter.slicealpha_offset, + dbkfilter.slicebeta_offset); + + DEBUG_PRINT_HIGH("ENC_CONFIG: IntraMB/Frame: %ld, HEC: %ld, IDR Period: %ld", + intra_refresh.mbcount, hec.header_extension, idrperiod.idrperiod); + + DEBUG_PRINT_HIGH("ENC_CONFIG: LTR Enabled: %d, Count: %d", + ltrinfo.enabled, ltrinfo.count); + + if (temporal_layers_config.nPLayers) { + DEBUG_PRINT_HIGH("ENC_CONFIG: Temporal layers: P-layers: %u, B-layers: %u, Adjusted I-frame-interval: %lu", + temporal_layers_config.nPLayers, temporal_layers_config.nBLayers, + intra_period.num_pframes + intra_period.num_bframes + 1); + + for (OMX_U32 l = 0; temporal_layers_config.bIsBitrateRatioValid + && (l < temporal_layers_config.nPLayers + temporal_layers_config.nBLayers); ++l) { + DEBUG_PRINT_HIGH("ENC_CONFIG: Temporal layers: layer[%d] bitrate %% = %u%%", + l, temporal_layers_config.nTemporalLayerBitrateFraction[l]); + } + } else { + + DEBUG_PRINT_HIGH("ENC_CONFIG: Hier layers: %d, Hier Mode: %s VPX_ErrorResilience: %d", + hier_layers.numlayers, hiermode_string(hier_layers.hier_mode), vpx_err_resilience.enable); + + DEBUG_PRINT_HIGH("ENC_CONFIG: Hybrid_HP PARAMS: Layers: %d, Frame Interval : %d, MinQP: %d, Max_QP: %d", + hybrid_hp.nHpLayers, hybrid_hp.nKeyFrameInterval, hybrid_hp.nMinQuantizer, hybrid_hp.nMaxQuantizer); + + DEBUG_PRINT_HIGH("ENC_CONFIG: Hybrid_HP PARAMS: Layer0: %d, Layer1: %d, Later2: %d, Layer3: %d, Layer4: %d, Layer5: %d", + hybrid_hp.nTemporalLayerBitrateRatio[0], hybrid_hp.nTemporalLayerBitrateRatio[1], + hybrid_hp.nTemporalLayerBitrateRatio[2], hybrid_hp.nTemporalLayerBitrateRatio[3], + hybrid_hp.nTemporalLayerBitrateRatio[4], hybrid_hp.nTemporalLayerBitrateRatio[5]); + } + + DEBUG_PRINT_HIGH("ENC_CONFIG: Performace level: %d", performance_level.perflevel); + + DEBUG_PRINT_HIGH("ENC_CONFIG: VUI timing info enabled: %d", vui_timing_info.enabled); + + DEBUG_PRINT_HIGH("ENC_CONFIG: Peak bitrate: %d", peak_bitrate.peakbitrate); + + DEBUG_PRINT_HIGH("ENC_CONFIG: Session Priority: %u", sess_priority.priority); + +#ifdef _PQ_ + DEBUG_PRINT_HIGH("ENC_CONFIG: Adaptive QP (PQ): %u", m_pq.is_pq_enabled); + + DEBUG_PRINT_HIGH("ENC_CONFIG: ROI : %u", m_pq.pConfig.a_qp.roi_enabled); +#endif // _PQ_ + + DEBUG_PRINT_HIGH("ENC_CONFIG: Operating Rate: %u", operating_rate); +} + +bool venc_dev::venc_reconfig_reqbufs() +{ + struct v4l2_requestbuffers bufreq; + + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = m_sInput_buff_property.actualcount; + bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + if(ioctl(m_nDriver_fd,VIDIOC_REQBUFS, &bufreq)) { + DEBUG_PRINT_ERROR("VIDIOC_REQBUFS OUTPUT_MPLANE Failed when resume"); + return false; + } + + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = m_sOutput_buff_property.actualcount; + bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if(ioctl(m_nDriver_fd,VIDIOC_REQBUFS, &bufreq)) + { + DEBUG_PRINT_ERROR("ERROR: Request for setting o/p buffer count failed when resume"); + return false; + } + return true; +} + +unsigned venc_dev::venc_flush( unsigned port) +{ + struct v4l2_encoder_cmd enc; + DEBUG_PRINT_LOW("in %s", __func__); + + unsigned int cookie = 0; + for (unsigned int i = 0; i < (sizeof(fd_list)/sizeof(fd_list[0])); i++) { + cookie = fd_list[i]; + if (cookie != 0) { + if (!ioctl(input_extradata_info.m_ion_dev, ION_IOC_FREE, &cookie)) { + DEBUG_PRINT_HIGH("Freed handle = %u", cookie); + } + fd_list[i] = 0; + } + } + + enc.cmd = V4L2_ENC_QCOM_CMD_FLUSH; + enc.flags = V4L2_QCOM_CMD_FLUSH_OUTPUT | V4L2_QCOM_CMD_FLUSH_CAPTURE; + + if (ioctl(m_nDriver_fd, VIDIOC_ENCODER_CMD, &enc)) { + DEBUG_PRINT_ERROR("Flush Port (%d) Failed ", port); + return -1; + } + + return 0; + +} + +//allocating I/P memory from pmem and register with the device + + +bool venc_dev::venc_use_buf(void *buf_addr, unsigned port,unsigned index) +{ + + struct pmem *pmem_tmp; + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + int rc = 0; + unsigned int extra_idx; + int extradata_index = 0; + + pmem_tmp = (struct pmem *)buf_addr; + DEBUG_PRINT_LOW("venc_use_buf:: pmem_tmp = %p", pmem_tmp); + + if (port == PORT_INDEX_IN) { + extra_idx = EXTRADATA_IDX(num_input_planes); + + if ((num_input_planes > 1) && (extra_idx)) { + rc = allocate_extradata(&input_extradata_info, ION_FLAG_CACHED); + + if (rc) + DEBUG_PRINT_ERROR("Failed to allocate extradata: %d\n", rc); + } + buf.index = index; + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].length = pmem_tmp->size; + plane[0].m.userptr = (unsigned long)pmem_tmp->buffer; + plane[0].reserved[0] = pmem_tmp->fd; + plane[0].reserved[1] = 0; + plane[0].data_offset = pmem_tmp->offset; + buf.m.planes = plane; + buf.length = num_input_planes; + +if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + extradata_index = venc_get_index_from_fd(input_extradata_info.m_ion_dev, pmem_tmp->fd); + if (extradata_index < 0 ) { + DEBUG_PRINT_ERROR("Extradata index calculation went wrong for fd = %d", pmem_tmp->fd); + return OMX_ErrorBadParameter; + } + plane[extra_idx].length = input_extradata_info.buffer_size; + plane[extra_idx].m.userptr = (unsigned long) (input_extradata_info.uaddr + extradata_index * input_extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = input_extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = input_extradata_info.buffer_size * extradata_index; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index is more than allowed: %d\n", extra_idx); + return OMX_ErrorBadParameter; + } + + + DEBUG_PRINT_LOW("Registering [%d] fd=%d size=%d userptr=%lu", index, + pmem_tmp->fd, plane[0].length, plane[0].m.userptr); + rc = ioctl(m_nDriver_fd, VIDIOC_PREPARE_BUF, &buf); + + if (rc) + DEBUG_PRINT_LOW("VIDIOC_PREPARE_BUF Failed"); + } else if (port == PORT_INDEX_OUT) { + extra_idx = EXTRADATA_IDX(num_output_planes); + + if ((num_output_planes > 1) && (extra_idx)) { + rc = allocate_extradata(&output_extradata_info, 0); + + if (rc) + DEBUG_PRINT_ERROR("Failed to allocate extradata: %d", rc); + } + + buf.index = index; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].length = pmem_tmp->size; + plane[0].m.userptr = (unsigned long)pmem_tmp->buffer; + plane[0].reserved[0] = pmem_tmp->fd; + plane[0].reserved[1] = 0; + plane[0].data_offset = pmem_tmp->offset; + buf.m.planes = plane; + buf.length = num_output_planes; + + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].length = output_extradata_info.buffer_size; + plane[extra_idx].m.userptr = (unsigned long) (output_extradata_info.uaddr + index * output_extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = output_extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = output_extradata_info.buffer_size * index; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index is more than allowed: %d", extra_idx); + return OMX_ErrorBadParameter; + } + + rc = ioctl(m_nDriver_fd, VIDIOC_PREPARE_BUF, &buf); + + if (rc) + DEBUG_PRINT_LOW("VIDIOC_PREPARE_BUF Failed"); + } else { + DEBUG_PRINT_ERROR("ERROR: venc_use_buf:Invalid Port Index "); + return false; + } + + return true; +} + +bool venc_dev::venc_free_buf(void *buf_addr, unsigned port) +{ + struct pmem *pmem_tmp; + struct venc_bufferpayload dev_buffer; + + memset(&dev_buffer, 0, sizeof(dev_buffer)); + pmem_tmp = (struct pmem *)buf_addr; + + if (port == PORT_INDEX_IN) { + dev_buffer.pbuffer = (OMX_U8 *)pmem_tmp->buffer; + dev_buffer.fd = pmem_tmp->fd; + dev_buffer.maped_size = pmem_tmp->size; + dev_buffer.sz = pmem_tmp->size; + dev_buffer.offset = pmem_tmp->offset; + DEBUG_PRINT_LOW("venc_free_buf:pbuffer = %p,fd = %x, offset = %d, maped_size = %d", \ + dev_buffer.pbuffer, \ + dev_buffer.fd, \ + dev_buffer.offset, \ + dev_buffer.maped_size); + + } else if (port == PORT_INDEX_OUT) { + dev_buffer.pbuffer = (OMX_U8 *)pmem_tmp->buffer; + dev_buffer.fd = pmem_tmp->fd; + dev_buffer.sz = pmem_tmp->size; + dev_buffer.maped_size = pmem_tmp->size; + dev_buffer.offset = pmem_tmp->offset; + + DEBUG_PRINT_LOW("venc_free_buf:pbuffer = %p,fd = %x, offset = %d, maped_size = %d", \ + dev_buffer.pbuffer, \ + dev_buffer.fd, \ + dev_buffer.offset, \ + dev_buffer.maped_size); + } else { + DEBUG_PRINT_ERROR("ERROR: venc_free_buf:Invalid Port Index "); + return false; + } + + return true; +} + +bool venc_dev::venc_color_align(OMX_BUFFERHEADERTYPE *buffer, + OMX_U32 width, OMX_U32 height) +{ + OMX_U32 y_stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, width), + y_scanlines = VENUS_Y_SCANLINES(COLOR_FMT_NV12, height), + uv_stride = VENUS_UV_STRIDE(COLOR_FMT_NV12, width), + uv_scanlines = VENUS_UV_SCANLINES(COLOR_FMT_NV12, height), + src_chroma_offset = width * height; + + if (buffer->nAllocLen >= VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height)) { + OMX_U8* src_buf = buffer->pBuffer, *dst_buf = buffer->pBuffer; + //Do chroma first, so that we can convert it in-place + src_buf += width * height; + dst_buf += y_stride * y_scanlines; + for (int line = height / 2 - 1; line >= 0; --line) { + memmove(dst_buf + line * uv_stride, + src_buf + line * width, + width); + } + + dst_buf = src_buf = buffer->pBuffer; + //Copy the Y next + for (int line = height - 1; line > 0; --line) { + memmove(dst_buf + line * y_stride, + src_buf + line * width, + width); + } + } else { + DEBUG_PRINT_ERROR("Failed to align Chroma. from %u to %u : \ + Insufficient bufferLen=%u v/s Required=%u", + (unsigned int)(width*height), (unsigned int)src_chroma_offset, (unsigned int)buffer->nAllocLen, + VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height)); + return false; + } + + return true; +} + +bool venc_dev::venc_get_performance_level(OMX_U32 *perflevel) +{ + if (!perflevel) { + DEBUG_PRINT_ERROR("Null pointer error"); + return false; + } else { + *perflevel = performance_level.perflevel; + return true; + } +} + +bool venc_dev::venc_get_vui_timing_info(OMX_U32 *enabled) +{ + if (!enabled) { + DEBUG_PRINT_ERROR("Null pointer error"); + return false; + } else { + *enabled = vui_timing_info.enabled; + return true; + } +} + +bool venc_dev::venc_get_vqzip_sei_info(OMX_U32 *enabled) +{ + if (!enabled) { + DEBUG_PRINT_ERROR("Null pointer error"); + return false; + } else { + *enabled = vqzip_sei_info.enabled; + return true; + } +} + +bool venc_dev::venc_get_peak_bitrate(OMX_U32 *peakbitrate) +{ + if (!peakbitrate) { + DEBUG_PRINT_ERROR("Null pointer error"); + return false; + } else { + *peakbitrate = peak_bitrate.peakbitrate; + return true; + } +} + +bool venc_dev::venc_get_batch_size(OMX_U32 *size) +{ + if (!size) { + DEBUG_PRINT_ERROR("Null pointer error"); + return false; + } else { + *size = mBatchSize; + return true; + } +} + +bool venc_dev::venc_empty_buf(void *buffer, void *pmem_data_buf, unsigned index, unsigned fd) +{ + struct pmem *temp_buffer; + struct v4l2_buffer buf; + struct v4l2_requestbuffers bufreq; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + int rc = 0, extra_idx; + struct OMX_BUFFERHEADERTYPE *bufhdr; + LEGACY_CAM_METADATA_TYPE * meta_buf = NULL; + temp_buffer = (struct pmem *)buffer; + + memset (&buf, 0, sizeof(buf)); + memset (&plane, 0, sizeof(plane)); + + if (buffer == NULL) { + DEBUG_PRINT_ERROR("ERROR: venc_etb: buffer is NULL"); + return false; + } + + bufhdr = (OMX_BUFFERHEADERTYPE *)buffer; + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = m_sInput_buff_property.actualcount; + bufreq.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + + DEBUG_PRINT_LOW("Input buffer length %u, Timestamp = %lld", (unsigned int)bufhdr->nFilledLen, bufhdr->nTimeStamp); + + if (pmem_data_buf) { + DEBUG_PRINT_LOW("\n Internal PMEM addr for i/p Heap UseBuf: %p", pmem_data_buf); + plane[0].m.userptr = (unsigned long)pmem_data_buf; + plane[0].data_offset = bufhdr->nOffset; + plane[0].length = bufhdr->nAllocLen; + plane[0].bytesused = bufhdr->nFilledLen; + } else { + // -------------------------------------------------------------------------------------- + // [Usage] [metadatamode] [Type] [color_format] [Where is buffer info] + // --------------------------------------------------------------------------------------- + // Camera-2 1 CameraSource 0 meta-handle + // Camera-3 1 GrallocSource 0 gralloc-private-handle + // surface encode (RBG) 1 GrallocSource 1 bufhdr (color-converted) + // CPU (Eg: MediaCodec) 0 -- 0 bufhdr + // --------------------------------------------------------------------------------------- + if (metadatamode) { + plane[0].m.userptr = index; + meta_buf = (LEGACY_CAM_METADATA_TYPE *)bufhdr->pBuffer; + + if (!meta_buf) { + //empty EOS buffer + if (!bufhdr->nFilledLen && (bufhdr->nFlags & OMX_BUFFERFLAG_EOS)) { + plane[0].data_offset = bufhdr->nOffset; + plane[0].length = bufhdr->nAllocLen; + plane[0].bytesused = bufhdr->nFilledLen; + DEBUG_PRINT_LOW("venc_empty_buf: empty EOS buffer"); + } else { + return false; + } + } else if (!color_format) { + + if (meta_buf->buffer_type == LEGACY_CAM_SOURCE) { + native_handle_t *hnd = (native_handle_t*)meta_buf->meta_handle; + if (!hnd) { + DEBUG_PRINT_ERROR("ERROR: venc_etb: handle is NULL"); + return false; + } + + if (!streaming[OUTPUT_PORT] && !(m_sVenc_cfg.inputformat == V4L2_PIX_FMT_RGB32 || + m_sVenc_cfg.inputformat == V4L2_PIX_FMT_RGBA8888_UBWC)) { + int usage = 0; + struct v4l2_format fmt; + OMX_COLOR_FORMATTYPE color_format = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + + color_format = (OMX_COLOR_FORMATTYPE)MetaBufferUtil::getIntAt(hnd, 0, MetaBufferUtil::INT_COLORFORMAT); + usage = MetaBufferUtil::getIntAt(hnd, 0, MetaBufferUtil::INT_USAGE); + usage = usage > 0 ? usage : 0; + + memset(&fmt, 0, sizeof(fmt)); + if (usage & private_handle_t::PRIV_FLAGS_ITU_R_709 || + usage & private_handle_t::PRIV_FLAGS_ITU_R_601) { + DEBUG_PRINT_ERROR("Camera buffer color format is not 601_FR."); + DEBUG_PRINT_ERROR(" This leads to unknown color space"); + } + if (usage & private_handle_t::PRIV_FLAGS_ITU_R_601_FR) { + if (is_csc_enabled) { + buf.flags = V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP; + fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; + venc_set_colorspace(MSM_VIDC_BT709_5, 1, + MSM_VIDC_TRANSFER_BT709_5, MSM_VIDC_MATRIX_BT_709_5); + } else { + venc_set_colorspace(MSM_VIDC_BT601_6_525, 1, + MSM_VIDC_TRANSFER_601_6_525, MSM_VIDC_MATRIX_601_6_525); + fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + } + } + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + m_sVenc_cfg.inputformat = V4L2_PIX_FMT_NV12; + fmt.fmt.pix_mp.height = m_sVenc_cfg.input_height; + fmt.fmt.pix_mp.width = m_sVenc_cfg.input_width; + if (usage & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { + m_sVenc_cfg.inputformat = V4L2_PIX_FMT_NV12_UBWC; + } + + if (usage & private_handle_t::PRIV_FLAGS_ITU_R_709) { + buf.flags = V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP; + } + + if (color_format > 0 && !venc_set_color_format(color_format)) { + DEBUG_PRINT_ERROR("Failed setting color format in Camerasource %lx", m_sVenc_cfg.inputformat); + return false; + } + + if(ioctl(m_nDriver_fd,VIDIOC_REQBUFS, &bufreq)) { + DEBUG_PRINT_ERROR("VIDIOC_REQBUFS OUTPUT_MPLANE Failed"); + return false; + } + } + + // Setting batch mode is sticky. We do not expect camera to change + // between batch and normal modes at runtime. + if (mBatchSize) { + if ((unsigned int)MetaBufferUtil::getBatchSize(hnd) != mBatchSize) { + DEBUG_PRINT_ERROR("Don't support dynamic batch sizes (changed from %d->%d)", + mBatchSize, MetaBufferUtil::getBatchSize(hnd)); + return false; + } + + return venc_empty_batch ((OMX_BUFFERHEADERTYPE*)buffer, index); + } + + int offset = MetaBufferUtil::getIntAt(hnd, 0, MetaBufferUtil::INT_OFFSET); + int length = MetaBufferUtil::getIntAt(hnd, 0, MetaBufferUtil::INT_SIZE); + if (offset < 0 || length < 0) { + DEBUG_PRINT_ERROR("Invalid meta buffer handle!"); + return false; + } + plane[0].data_offset = offset; + plane[0].length = length; + plane[0].bytesused = length; + DEBUG_PRINT_LOW("venc_empty_buf: camera buf: fd = %d filled %d of %d flag 0x%x format 0x%lx", + fd, plane[0].bytesused, plane[0].length, buf.flags, m_sVenc_cfg.inputformat); + } else if (meta_buf->buffer_type == kMetadataBufferTypeGrallocSource) { + VideoGrallocMetadata *meta_buf = (VideoGrallocMetadata *)bufhdr->pBuffer; + private_handle_t *handle = (private_handle_t *)meta_buf->pHandle; + + if (!handle) { + DEBUG_PRINT_ERROR("%s : handle is null!", __FUNCTION__); + return false; + } + + if (!streaming[OUTPUT_PORT]) { + int color_space = 0; + // Moment of truth... actual colorspace is known here.. + ColorSpace_t colorSpace = ITU_R_601; + if (getMetaData(handle, GET_COLOR_SPACE, &colorSpace) == 0) { + DEBUG_PRINT_INFO("ENC_CONFIG: gralloc ColorSpace = %d (601=%d 601_FR=%d 709=%d)", + colorSpace, ITU_R_601, ITU_R_601_FR, ITU_R_709); + } + + struct v4l2_format fmt; + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + + bool isUBWC = (handle->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) && is_gralloc_source_ubwc; + if (handle->format == HAL_PIXEL_FORMAT_NV12_ENCODEABLE) { + m_sVenc_cfg.inputformat = isUBWC ? V4L2_PIX_FMT_NV12_UBWC : V4L2_PIX_FMT_NV12; + DEBUG_PRINT_INFO("ENC_CONFIG: Input Color = NV12 %s", isUBWC ? "UBWC" : "Linear"); + } else if (handle->format == HAL_PIXEL_FORMAT_RGBA_8888) { + // In case of RGB, conversion to YUV is handled within encoder. + // Disregard the Colorspace in gralloc-handle in case of RGB and use + // [a] 601 for non-UBWC case : C2D output is (apparently) 601-LR + // [b] 601 for UBWC case : Venus can convert to 601-LR or FR. use LR for now. + colorSpace = ITU_R_601; + m_sVenc_cfg.inputformat = isUBWC ? V4L2_PIX_FMT_RGBA8888_UBWC : V4L2_PIX_FMT_RGB32; + DEBUG_PRINT_INFO("ENC_CONFIG: Input Color = RGBA8888 %s", isUBWC ? "UBWC" : "Linear"); + } else if (handle->format == QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m) { + m_sVenc_cfg.inputformat = V4L2_PIX_FMT_NV12; + DEBUG_PRINT_INFO("ENC_CONFIG: Input Color = NV12 Linear"); + } + + // If device recommendation (persist.vidc.enc.csc.enable) is to use 709, force CSC + if (colorSpace == ITU_R_601_FR && is_csc_enabled) { + struct v4l2_control control; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC; + control.value = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("venc_empty_buf: Failed to set VPE CSC for 601_to_709"); + } else { + DEBUG_PRINT_INFO("venc_empty_buf: Will convert 601-FR to 709"); + buf.flags = V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP; + colorSpace = ITU_R_709; + } + } + + msm_vidc_h264_color_primaries_values primary; + msm_vidc_h264_transfer_chars_values transfer; + msm_vidc_h264_matrix_coeff_values matrix; + OMX_U32 range; + + switch (colorSpace) { + case ITU_R_601_FR: + { + primary = MSM_VIDC_BT601_6_525; + range = 1; // full + transfer = MSM_VIDC_TRANSFER_601_6_525; + matrix = MSM_VIDC_MATRIX_601_6_525; + + fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + } + case ITU_R_709: + { + primary = MSM_VIDC_BT709_5; + range = 0; // limited + transfer = MSM_VIDC_TRANSFER_BT709_5; + matrix = MSM_VIDC_MATRIX_BT_709_5; + + fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; + break; + } + default: + { + // 601 or something else ? assume 601 + primary = MSM_VIDC_BT601_6_625; + range = 0; //limited + transfer = MSM_VIDC_TRANSFER_601_6_625; + matrix = MSM_VIDC_MATRIX_601_6_625; + + fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + } + } + DEBUG_PRINT_INFO("ENC_CONFIG: selected ColorSpace = %d (601=%d 601_FR=%d 709=%d)", + colorSpace, ITU_R_601, ITU_R_601_FR, ITU_R_709); + venc_set_colorspace(primary, range, transfer, matrix); + + fmt.fmt.pix_mp.pixelformat = m_sVenc_cfg.inputformat; + fmt.fmt.pix_mp.height = m_sVenc_cfg.input_height; + fmt.fmt.pix_mp.width = m_sVenc_cfg.input_width; + if (ioctl(m_nDriver_fd, VIDIOC_S_FMT, &fmt)) { + DEBUG_PRINT_ERROR("Failed setting color format in Grallocsource %lx", m_sVenc_cfg.inputformat); + return false; + } + if(ioctl(m_nDriver_fd,VIDIOC_REQBUFS, &bufreq)) { + DEBUG_PRINT_ERROR("VIDIOC_REQBUFS OUTPUT_MPLANE Failed"); + return false; + } + } + + fd = handle->fd; + plane[0].data_offset = 0; + plane[0].length = handle->size; + plane[0].bytesused = handle->size; + DEBUG_PRINT_LOW("venc_empty_buf: Opaque camera buf: fd = %d " + ": filled %d of %d format 0x%lx", fd, plane[0].bytesused, plane[0].length, m_sVenc_cfg.inputformat); + } + } else { + plane[0].m.userptr = (unsigned long) bufhdr->pBuffer; + plane[0].data_offset = bufhdr->nOffset; + plane[0].length = bufhdr->nAllocLen; + plane[0].bytesused = bufhdr->nFilledLen; + DEBUG_PRINT_LOW("venc_empty_buf: Opaque non-camera buf: fd = %d filled %d of %d", + fd, plane[0].bytesused, plane[0].length); + } + } else { + plane[0].m.userptr = (unsigned long) bufhdr->pBuffer; + plane[0].data_offset = bufhdr->nOffset; + plane[0].length = bufhdr->nAllocLen; + plane[0].bytesused = bufhdr->nFilledLen; + DEBUG_PRINT_LOW("venc_empty_buf: non-camera buf: fd = %d filled %d of %d", + fd, plane[0].bytesused, plane[0].length); + } + } + + extra_idx = EXTRADATA_IDX(num_input_planes); + + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + int extradata_index = venc_get_index_from_fd(input_extradata_info.m_ion_dev,fd); + if (extradata_index < 0 ) { + DEBUG_PRINT_ERROR("Extradata index calculation went wrong for fd = %d", fd); + return OMX_ErrorBadParameter; + } + + plane[extra_idx].bytesused = 0; + plane[extra_idx].length = input_extradata_info.buffer_size; + plane[extra_idx].m.userptr = (unsigned long) (input_extradata_info.uaddr + extradata_index * input_extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = input_extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = input_extradata_info.buffer_size * extradata_index; + plane[extra_idx].reserved[2] = input_extradata_info.size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index higher than expected: %d\n", extra_idx); + return false; + } + +#ifdef _PQ_ + if (!streaming[OUTPUT_PORT]) { + m_pq.is_YUV_format_uncertain = false; + if(venc_check_for_pq()) { + /* + * This is the place where all parameters for deciding + * PQ enablement are available. Evaluate PQ for the final time. + */ + m_pq.reinit(m_sVenc_cfg.inputformat); + venc_configure_pq(); + } + } +#endif // _PQ_ + + buf.index = index; + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].reserved[0] = fd; + plane[0].reserved[1] = 0; + buf.m.planes = plane; + buf.length = num_input_planes; + + handle_input_extradata(buf); + + VIDC_TRACE_INT_LOW("ETB-TS", bufhdr->nTimeStamp / 1000); + + if (bufhdr->nFlags & OMX_BUFFERFLAG_EOS) + buf.flags |= V4L2_QCOM_BUF_FLAG_EOS; + + buf.timestamp.tv_sec = bufhdr->nTimeStamp / 1000000; + buf.timestamp.tv_usec = (bufhdr->nTimeStamp % 1000000); + if (m_debug.in_buffer_log) { + venc_input_log_buffers(bufhdr, fd, plane[0].data_offset, m_sVenc_cfg.inputformat); + } + if (m_debug.extradata_log && extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + DEBUG_PRINT_ERROR("Extradata Addr 0x%llx, Buffer Addr = 0x%x", (OMX_U64)input_extradata_info.uaddr, (unsigned int)plane[extra_idx].m.userptr); + venc_extradata_log_buffers((char *)plane[extra_idx].m.userptr); + } + rc = ioctl(m_nDriver_fd, VIDIOC_QBUF, &buf); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to qbuf (etb) to driver"); + return false; + } + + etb++; + + if (!streaming[OUTPUT_PORT]) { + enum v4l2_buf_type buf_type; + buf_type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + int ret; + + ret = ioctl(m_nDriver_fd, VIDIOC_STREAMON, &buf_type); + + if (ret) { + DEBUG_PRINT_ERROR("Failed to call streamon"); + if (errno == EBUSY) { + hw_overload = true; + } + return false; + } else { + streaming[OUTPUT_PORT] = true; + } + } + + return true; +} + +bool venc_dev::venc_empty_batch(OMX_BUFFERHEADERTYPE *bufhdr, unsigned index) +{ + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + int rc = 0, extra_idx, numBufs; + struct v4l2_control control; + LEGACY_CAM_METADATA_TYPE * meta_buf = NULL; + native_handle_t *hnd = NULL; + + if (bufhdr == NULL) { + DEBUG_PRINT_ERROR("ERROR: %s: buffer is NULL", __func__); + return false; + } + + bool status = true; + if (metadatamode) { + plane[0].m.userptr = index; + meta_buf = (LEGACY_CAM_METADATA_TYPE *)bufhdr->pBuffer; + + if (!color_format) { + if (meta_buf->buffer_type == LEGACY_CAM_SOURCE) { + hnd = (native_handle_t*)meta_buf->meta_handle; + if (!hnd) { + DEBUG_PRINT_ERROR("venc_empty_batch: invalid handle !"); + return false; + } else if (MetaBufferUtil::getBatchSize(hnd) > kMaxBuffersInBatch) { + DEBUG_PRINT_ERROR("venc_empty_batch: Too many buffers (%d) in batch. " + "Max = %d", MetaBufferUtil::getBatchSize(hnd), kMaxBuffersInBatch); + status = false; + } + DEBUG_PRINT_LOW("venc_empty_batch: Batch of %d bufs", MetaBufferUtil::getBatchSize(hnd)); + } else { + DEBUG_PRINT_ERROR("Batch supported for CameraSource buffers only !"); + status = false; + } + } else { + DEBUG_PRINT_ERROR("Batch supported for Camera buffers only !"); + status = false; + } + } else { + DEBUG_PRINT_ERROR("Batch supported for metabuffer mode only !"); + status = false; + } + + if (status) { + OMX_TICKS bufTimeStamp = 0ll; + int numBufs = MetaBufferUtil::getBatchSize(hnd); + int v4l2Ids[kMaxBuffersInBatch] = {-1}; + for (int i = 0; i < numBufs; ++i) { + v4l2Ids[i] = mBatchInfo.registerBuffer(index); + if (v4l2Ids[i] < 0) { + DEBUG_PRINT_ERROR("Failed to register buffer"); + // TODO: cleanup the map and purge all slots of current index + status = false; + break; + } + } + for (int i = 0; i < numBufs; ++i) { + int v4l2Id = v4l2Ids[i]; + + memset(&buf, 0, sizeof(buf)); + memset(&plane, 0, sizeof(plane)); + + DEBUG_PRINT_LOW("Batch: registering %d as %d", index, v4l2Id); + buf.index = (unsigned)v4l2Id; + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].reserved[0] = MetaBufferUtil::getFdAt(hnd, i); + plane[0].reserved[1] = 0; + plane[0].data_offset = MetaBufferUtil::getIntAt(hnd, i, MetaBufferUtil::INT_OFFSET); + plane[0].m.userptr = (unsigned long)meta_buf; + plane[0].length = plane[0].bytesused = MetaBufferUtil::getIntAt(hnd, i, MetaBufferUtil::INT_SIZE); + buf.m.planes = plane; + buf.length = num_input_planes; + + extra_idx = EXTRADATA_IDX(num_input_planes); + + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + int fd = plane[0].reserved[0]; + int extradata_index = venc_get_index_from_fd(input_extradata_info.m_ion_dev, fd); + if (extradata_index < 0) { + DEBUG_PRINT_ERROR("Extradata index calculation went wrong for fd = %d", fd); + return OMX_ErrorBadParameter; + } + + plane[extra_idx].bytesused = 0; + plane[extra_idx].length = input_extradata_info.buffer_size; + plane[extra_idx].m.userptr = (unsigned long) (input_extradata_info.uaddr + extradata_index * input_extradata_info.buffer_size); + plane[extra_idx].reserved[0] = input_extradata_info.ion.fd_ion_data.fd; + plane[extra_idx].reserved[1] = input_extradata_info.buffer_size * extradata_index; + plane[extra_idx].reserved[2] = input_extradata_info.size; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index higher than expected: %d\n", extra_idx); + return false; + } + +#ifdef _PQ_ + if (!streaming[OUTPUT_PORT]) { + m_pq.is_YUV_format_uncertain = false; + if(venc_check_for_pq()) { + m_pq.reinit(m_sVenc_cfg.inputformat); + venc_configure_pq(); + } + } +#endif // _PQ_ + + handle_input_extradata(buf); + + rc = ioctl(m_nDriver_fd, VIDIOC_PREPARE_BUF, &buf); + if (rc) + DEBUG_PRINT_LOW("VIDIOC_PREPARE_BUF Failed"); + + if (bufhdr->nFlags & OMX_BUFFERFLAG_EOS) + buf.flags |= V4L2_QCOM_BUF_FLAG_EOS; + if (i != numBufs - 1) { + buf.flags |= V4L2_MSM_BUF_FLAG_DEFER; + DEBUG_PRINT_LOW("for buffer %d (etb #%d) in batch of %d, marking as defer", + i, etb + 1, numBufs); + } + + // timestamp differences from camera are in nano-seconds + bufTimeStamp = bufhdr->nTimeStamp + MetaBufferUtil::getIntAt(hnd, i, MetaBufferUtil::INT_TIMESTAMP) / 1000; + + DEBUG_PRINT_LOW(" Q Batch [%d of %d] : buf=%p fd=%d len=%d TS=%lld", + i, numBufs, bufhdr, plane[0].reserved[0], plane[0].length, bufTimeStamp); + buf.timestamp.tv_sec = bufTimeStamp / 1000000; + buf.timestamp.tv_usec = (bufTimeStamp % 1000000); + + VIDC_TRACE_INT_LOW("ETB-TS", bufTimeStamp / 1000); + + rc = ioctl(m_nDriver_fd, VIDIOC_QBUF, &buf); + if (rc) { + DEBUG_PRINT_ERROR("%s: Failed to qbuf (etb) to driver", __func__); + return false; + } + + etb++; + } + } + + if (status && !streaming[OUTPUT_PORT]) { + enum v4l2_buf_type buf_type; + buf_type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + int ret; + ret = ioctl(m_nDriver_fd, VIDIOC_STREAMON, &buf_type); + if (ret) { + DEBUG_PRINT_ERROR("Failed to call streamon"); + if (errno == EBUSY) { + hw_overload = true; + } + status = false; + } else { + streaming[OUTPUT_PORT] = true; + } + } + + return status; +} + +bool venc_dev::venc_fill_buf(void *buffer, void *pmem_data_buf,unsigned index,unsigned fd) +{ + struct pmem *temp_buffer = NULL; + struct venc_buffer frameinfo; + struct v4l2_buffer buf; + struct v4l2_plane plane[VIDEO_MAX_PLANES]; + int rc = 0; + unsigned int extra_idx; + struct OMX_BUFFERHEADERTYPE *bufhdr; + + if (buffer == NULL) + return false; + + bufhdr = (OMX_BUFFERHEADERTYPE *)buffer; + + if (pmem_data_buf) { + DEBUG_PRINT_LOW("Internal PMEM addr for o/p Heap UseBuf: %p", pmem_data_buf); + plane[0].m.userptr = (unsigned long)pmem_data_buf; + } else { + DEBUG_PRINT_LOW("Shared PMEM addr for o/p PMEM UseBuf/AllocateBuf: %p", bufhdr->pBuffer); + plane[0].m.userptr = (unsigned long)bufhdr->pBuffer; + } + + memset(&buf, 0, sizeof(buf)); + memset(&plane, 0, sizeof(plane)); + + buf.index = index; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_USERPTR; + plane[0].length = bufhdr->nAllocLen; + plane[0].bytesused = bufhdr->nFilledLen; + plane[0].reserved[0] = fd; + plane[0].reserved[1] = 0; + plane[0].data_offset = bufhdr->nOffset; + buf.m.planes = plane; + buf.length = num_output_planes; + buf.flags = 0; + + if (venc_handle->is_secure_session()) { + output_metabuffer *meta_buf = (output_metabuffer *)(bufhdr->pBuffer); + native_handle_t *handle_t = meta_buf->nh; + plane[0].length = handle_t->data[3]; + } + + if (mBatchSize) { + // Should always mark first buffer as DEFER, since 0 % anything is 0, just offset by 1 + // This results in the first batch being of size mBatchSize + 1, but thats good because + // we need an extra FTB for the codec specific data. + + if (!ftb || ftb % mBatchSize) { + buf.flags |= V4L2_MSM_BUF_FLAG_DEFER; + DEBUG_PRINT_LOW("for ftb buffer %d marking as defer", ftb + 1); + } + } + + extra_idx = EXTRADATA_IDX(num_output_planes); + + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + plane[extra_idx].bytesused = 0; + plane[extra_idx].length = output_extradata_info.buffer_size; + plane[extra_idx].m.userptr = (unsigned long) (output_extradata_info.uaddr + index * output_extradata_info.buffer_size); +#ifdef USE_ION + plane[extra_idx].reserved[0] = output_extradata_info.ion.fd_ion_data.fd; +#endif + plane[extra_idx].reserved[1] = output_extradata_info.buffer_size * index; + plane[extra_idx].data_offset = 0; + } else if (extra_idx >= VIDEO_MAX_PLANES) { + DEBUG_PRINT_ERROR("Extradata index higher than expected: %d", extra_idx); + return false; + } + + rc = ioctl(m_nDriver_fd, VIDIOC_QBUF, &buf); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to qbuf (ftb) to driver"); + return false; + } + + ftb++; + return true; +} + +bool venc_dev::venc_set_inband_video_header(OMX_BOOL enable) +{ + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE; + if(enable) { + control.value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME; + } else { + control.value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE; + } + + DEBUG_PRINT_HIGH("Set inband sps/pps: %d", enable); + if(ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control) < 0) { + DEBUG_PRINT_ERROR("Request for inband sps/pps failed"); + return false; + } + return true; +} + +bool venc_dev::venc_set_au_delimiter(OMX_BOOL enable) +{ + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER; + if(enable) { + control.value = V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED; + } else { + control.value = V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED; + } + + DEBUG_PRINT_HIGH("Set au delimiter: %d", enable); + if(ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control) < 0) { + DEBUG_PRINT_ERROR("Request to set AU delimiter failed"); + return false; + } + return true; +} + +bool venc_dev::venc_set_mbi_statistics_mode(OMX_U32 mode) +{ + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_MBI_STATISTICS_MODE; + control.value = mode; + + DEBUG_PRINT_HIGH("Set MBI dumping mode: %d", mode); + if(ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control) < 0) { + DEBUG_PRINT_ERROR("Setting MBI mode failed"); + return false; + } + return true; +} + +int venc_dev::venc_get_index_from_fd(OMX_U32 ion_fd, OMX_U32 buffer_fd) +{ + unsigned int cookie = buffer_fd; + struct ion_fd_data fdData; + + memset(&fdData, 0, sizeof(fdData)); + fdData.fd = buffer_fd; + if (ion_fd && !ioctl(ion_fd, ION_IOC_IMPORT, &fdData)) { + cookie = fdData.handle; + DEBUG_PRINT_HIGH("FD = %u imported handle = %u", fdData.fd, fdData.handle); + } + + for (unsigned int i = 0; i < (sizeof(fd_list)/sizeof(fd_list[0])); i++) { + if (fd_list[i] == cookie) { + DEBUG_PRINT_HIGH("FD is present at index = %d", i); + if (ion_fd && !ioctl(ion_fd, ION_IOC_FREE, &fdData.handle)) { + DEBUG_PRINT_HIGH("freed handle = %u", cookie); + } + return i; + } + } + + for (unsigned int i = 0; i < (sizeof(fd_list)/sizeof(fd_list[0])); i++) + if (fd_list[i] == 0) { + DEBUG_PRINT_HIGH("FD added at index = %d", i); + fd_list[i] = cookie; + return i; + } + return -EINVAL; +} + +bool venc_dev::venc_set_vqzip_sei_type(OMX_BOOL enable) +{ + struct v4l2_control sei_control, yuvstats_control; + + DEBUG_PRINT_HIGH("Set VQZIP SEI: %d", enable); + sei_control.id = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI; + yuvstats_control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + + if (ioctl(m_nDriver_fd, VIDIOC_G_CTRL, &yuvstats_control) < 0) { + DEBUG_PRINT_HIGH("Non-Fatal: Request to set VQZIP failed"); + } + + if(enable) { + sei_control.value = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI_ENABLE; + yuvstats_control.value |= V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS; + } else { + sei_control.value = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI_DISABLE; + yuvstats_control.value &= ~V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS; + } + + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &sei_control) < 0) { + DEBUG_PRINT_HIGH("Non-Fatal: Request to set SEI failed"); + } + + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &yuvstats_control) < 0) { + DEBUG_PRINT_HIGH("Non-Fatal: Request to set YUVSTATS failed"); + } +#ifdef _VQZIP_ + vqzip.pConfig.nWidth = ALIGN(m_sVenc_cfg.input_width, 16); + vqzip.pConfig.nHeight = ALIGN(m_sVenc_cfg.input_height, 16); + vqzip.init(); + vqzip_sei_info.enabled = true; +#endif + + return true; +} + +bool venc_dev::venc_validate_hybridhp_params(OMX_U32 layers, OMX_U32 bFrames, OMX_U32 count, int mode) +{ + // Check for layers in Hier-p/hier-B with Hier-P-Hybrid + if (layers && (mode == HIER_P || mode == HIER_B) && hier_layers.hier_mode == HIER_P_HYBRID) + return false; + + // Check for bframes with Hier-P-Hybrid + if (bFrames && hier_layers.hier_mode == HIER_P_HYBRID) + return false; + + // Check for Hier-P-Hybrid with bframes/LTR/hier-p/Hier-B + if (layers && mode == HIER_P_HYBRID && (intra_period.num_bframes || hier_layers.hier_mode == HIER_P || + hier_layers.hier_mode == HIER_B || ltrinfo.count)) + return false; + + // Check for LTR with Hier-P-Hybrid + if (count && hier_layers.hier_mode == HIER_P_HYBRID) + return false; + + return true; +} + +bool venc_dev::venc_set_hier_layers(QOMX_VIDEO_HIERARCHICALCODINGTYPE type, + OMX_U32 num_layers) +{ + struct v4l2_control control; + + if (!venc_validate_hybridhp_params(num_layers, 0, 0, (int)type)){ + DEBUG_PRINT_ERROR("Invalid settings, Hier-pLayers enabled with HybridHP"); + return false; + } + + if (type == QOMX_HIERARCHICALCODING_P) { + // Reduce layer count by 1 before sending to driver. This avoids + // driver doing the same in multiple places. + control.id = V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS; + control.value = num_layers - 1; + DEBUG_PRINT_HIGH("Set MAX Hier P num layers: %u", (unsigned int)num_layers); + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Request to set MAX Hier P num layers failed"); + return false; + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS; + control.value = num_layers - 1; + DEBUG_PRINT_HIGH("Set Hier P num layers: %u", (unsigned int)num_layers); + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Request to set Hier P num layers failed"); + return false; + } + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + DEBUG_PRINT_LOW("Set H264_SVC_NAL"); + control.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC; + control.value = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to enable SVC_NAL"); + return false; + } + } + hier_layers.hier_mode = HIER_P; + } else if (type == QOMX_HIERARCHICALCODING_B) { + if (m_sVenc_cfg.codectype != V4L2_PIX_FMT_HEVC) { + DEBUG_PRINT_ERROR("Failed : Hier B layers supported only for HEVC encode"); + return false; + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS; + control.value = num_layers - 1; + DEBUG_PRINT_INFO("Set Hier B num layers: %u", (unsigned int)num_layers); + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Request to set Hier P num layers failed"); + return false; + } + hier_layers.hier_mode = HIER_B; + } else { + DEBUG_PRINT_ERROR("Request to set hier num layers failed for type: %d", type); + return false; + } + hier_layers.numlayers = num_layers; + return true; +} + +bool venc_dev::venc_set_extradata(OMX_U32 extra_data, OMX_BOOL enable) +{ + struct v4l2_control control; + + DEBUG_PRINT_HIGH("venc_set_extradata:: %x", (int) extra_data); + + if (enable == OMX_FALSE) { + /* No easy way to turn off extradata to the driver + * at the moment */ + return false; + } + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA; + switch (extra_data) { + case OMX_ExtraDataVideoEncoderSliceInfo: + control.value = V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO; + break; + case OMX_ExtraDataVideoEncoderMBInfo: + control.value = V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI; + break; + case OMX_ExtraDataFrameDimension: + control.value = V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP; + break; + case OMX_ExtraDataEncoderOverrideQPInfo: + control.value = V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO; + break; + default: + DEBUG_PRINT_ERROR("Unrecognized extradata index 0x%x", (unsigned int)extra_data); + return false; + } + + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("ERROR: Request for setting extradata (%x) failed %d", + (unsigned int)extra_data, errno); + return false; + } + + return true; +} + +bool venc_dev::venc_set_slice_delivery_mode(OMX_U32 enable) +{ + struct v4l2_control control; + + if (enable) { + control.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE; + control.value = 1; + DEBUG_PRINT_LOW("Set slice_delivery_mode: %d", control.value); + + if (multislice.mslice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB && m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Request for setting slice delivery mode failed"); + return false; + } else { + DEBUG_PRINT_LOW("Successfully set Slice delivery mode id: %d, value=%d", control.id, control.value); + slice_mode.enable = 1; + } + } else { + DEBUG_PRINT_ERROR("Failed to set slice delivery mode, slice_mode [%lu] " + "is not MB BASED or [%lu] is not H264 codec ", multislice.mslice_mode, + m_sVenc_cfg.codectype); + } + } else { + DEBUG_PRINT_ERROR("Slice_DELIVERY_MODE not enabled"); + } + + return true; +} + +bool venc_dev::venc_enable_initial_qp(QOMX_EXTNINDEX_VIDEO_INITIALQP* initqp) +{ + int rc; + struct v4l2_control control; + struct v4l2_ext_control ctrl[4]; + struct v4l2_ext_controls controls; + + ctrl[0].id = V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP; + ctrl[0].value = initqp->nQpI; + ctrl[1].id = V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP; + ctrl[1].value = initqp->nQpP; + ctrl[2].id = V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP; + ctrl[2].value = initqp->nQpB; + ctrl[3].id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP; + ctrl[3].value = initqp->bEnableInitQp; + + controls.count = 4; + controls.ctrl_class = V4L2_CTRL_CLASS_MPEG; + controls.controls = ctrl; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%x val=%d, id=%x val=%d, id=%x val=%d, id=%x val=%d", + controls.controls[0].id, controls.controls[0].value, + controls.controls[1].id, controls.controls[1].value, + controls.controls[2].id, controls.controls[2].value, + controls.controls[3].id, controls.controls[3].value); + + rc = ioctl(m_nDriver_fd, VIDIOC_S_EXT_CTRLS, &controls); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set session_qp %d", rc); + return false; + } + + init_qp.iframeqp = initqp->nQpI; + init_qp.pframeqp = initqp->nQpP; + init_qp.bframeqp = initqp->nQpB; + init_qp.enableinitqp = initqp->bEnableInitQp; + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%x val=%d, id=%x val=%d, id=%x val=%d, id=%x val=%d", + controls.controls[0].id, controls.controls[0].value, + controls.controls[1].id, controls.controls[1].value, + controls.controls[2].id, controls.controls[2].value, + controls.controls[3].id, controls.controls[3].value); + return true; +} + +bool venc_dev::venc_set_colorspace(OMX_U32 primaries, OMX_U32 range, + OMX_U32 transfer_chars, OMX_U32 matrix_coeffs) +{ + int rc; + struct v4l2_control control; + + DEBUG_PRINT_LOW("Setting color space : Primaries = %d, Range = %d, Trans = %d, Matrix = %d", + primaries, range, transfer_chars, matrix_coeffs); + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE; + control.value = primaries; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control : V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + color_space.primaries = control.value; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE; + control.value = range; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control : V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + color_space.range = control.value; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS; + control.value = transfer_chars; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control : V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + color_space.transfer_chars = control.value; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS; + control.value = matrix_coeffs; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control : V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + color_space.matrix_coeffs = control.value; + + return true; +} + +bool venc_dev::venc_set_session_qp(OMX_U32 i_frame_qp, OMX_U32 p_frame_qp,OMX_U32 b_frame_qp) +{ + int rc; + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP; + control.value = i_frame_qp; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + session_qp.iframeqp = control.value; + + control.id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP; + control.value = p_frame_qp; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + session_qp.pframeqp = control.value; + + if ((codec_profile.profile == V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) || + (codec_profile.profile == V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)) { + + control.id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP; + control.value = b_frame_qp; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + session_qp.bframeqp = control.value; + } + + return true; +} + +bool venc_dev::venc_set_session_qp_range(OMX_U32 min_qp, OMX_U32 max_qp) +{ + int rc; + struct v4l2_control control; + + if ((min_qp >= session_qp_range.minqp) && (max_qp <= session_qp_range.maxqp)) { + + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) + control.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP; + else + control.id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP; + control.value = min_qp; + + DEBUG_PRINT_LOW("Calling IOCTL set MIN_QP control id=%d, val=%d", + control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) + control.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP; + else + control.id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP; + control.value = max_qp; + + DEBUG_PRINT_LOW("Calling IOCTL set MAX_QP control id=%d, val=%d", + control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + } else { + DEBUG_PRINT_ERROR("Wrong qp values[%u %u], allowed range[%u %u]", + (unsigned int)min_qp, (unsigned int)max_qp, (unsigned int)session_qp_range.minqp, (unsigned int)session_qp_range.maxqp); + } + + return true; +} + +bool venc_dev::venc_set_session_qp_range_packed(OMX_U32 min_qp, OMX_U32 max_qp) +{ + int rc; + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED; + control.value = min_qp; + + DEBUG_PRINT_LOW("Calling IOCTL set MIN_QP_PACKED control id=%d, val=%d", + control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + control.id = V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED; + control.value = max_qp; + + DEBUG_PRINT_LOW("Calling IOCTL set MAX_QP_PACKED control id=%d, val=%d", + control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + return true; +} + +bool venc_dev::venc_set_profile_level(OMX_U32 eProfile,OMX_U32 eLevel) +{ + struct venc_profile requested_profile = {0}; + struct ven_profilelevel requested_level = {0}; + unsigned long mb_per_frame = 0; + DEBUG_PRINT_LOW("venc_set_profile_level:: eProfile = %u, Level = %u", + (unsigned int)eProfile, (unsigned int)eLevel); + mb_per_frame = ((m_sVenc_cfg.dvs_height + 15) >> 4)* + ((m_sVenc_cfg.dvs_width + 15) >> 4); + + if ((eProfile == 0) && (eLevel == 0) && m_profile_set && m_level_set) { + DEBUG_PRINT_LOW("Profile/Level setting complete before venc_start"); + return true; + } + + DEBUG_PRINT_LOW("Validating Profile/Level from table"); + + if (!venc_validate_profile_level(&eProfile, &eLevel)) { + DEBUG_PRINT_LOW("ERROR: Profile/Level validation failed"); + return false; + } + + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_MPEG4) { + DEBUG_PRINT_LOW("eProfile = %u, OMX_VIDEO_MPEG4ProfileSimple = %d and " + "OMX_VIDEO_MPEG4ProfileAdvancedSimple = %d", (unsigned int)eProfile, + OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4ProfileAdvancedSimple); + + if (eProfile == OMX_VIDEO_MPEG4ProfileSimple) { + requested_profile.profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE; + } else if (eProfile == OMX_VIDEO_MPEG4ProfileAdvancedSimple) { + requested_profile.profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE; + } else { + DEBUG_PRINT_LOW("ERROR: Unsupported MPEG4 profile = %u", + (unsigned int)eProfile); + return false; + } + + DEBUG_PRINT_LOW("eLevel = %u, OMX_VIDEO_MPEG4Level0 = %d, OMX_VIDEO_MPEG4Level1 = %d," + "OMX_VIDEO_MPEG4Level2 = %d, OMX_VIDEO_MPEG4Level3 = %d, OMX_VIDEO_MPEG4Level4 = %d," + "OMX_VIDEO_MPEG4Level5 = %d", (unsigned int)eLevel, OMX_VIDEO_MPEG4Level0, OMX_VIDEO_MPEG4Level1, + OMX_VIDEO_MPEG4Level2, OMX_VIDEO_MPEG4Level3, OMX_VIDEO_MPEG4Level4, OMX_VIDEO_MPEG4Level5); + + if (mb_per_frame >= 3600) { + if (requested_profile.profile == V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE) + requested_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5; + + if (requested_profile.profile == V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE) + requested_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5; + } else { + switch (eLevel) { + case OMX_VIDEO_MPEG4Level0: + requested_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0; + break; + case OMX_VIDEO_MPEG4Level0b: + requested_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B; + break; + case OMX_VIDEO_MPEG4Level1: + requested_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_1; + break; + case OMX_VIDEO_MPEG4Level2: + requested_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_2; + break; + case OMX_VIDEO_MPEG4Level3: + requested_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_3; + break; + case OMX_VIDEO_MPEG4Level4a: + requested_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_4; + break; + case OMX_VIDEO_MPEG4Level5: + case OMX_VIDEO_MPEG4LevelMax: + default: //Set max level possible as default so that invalid levels are non-fatal + requested_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5; + break; + } + } + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H263) { + + switch (eProfile) { + case OMX_VIDEO_H263ProfileBaseline: + requested_profile.profile = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE; + break; + case OMX_VIDEO_H263ProfileH320Coding: + requested_profile.profile = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING; + break; + case OMX_VIDEO_H263ProfileBackwardCompatible: + requested_profile.profile = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE; + break; + case OMX_VIDEO_H263ProfileISWV2: + requested_profile.profile = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2; + break; + case OMX_VIDEO_H263ProfileISWV3: + requested_profile.profile = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3; + break; + case OMX_VIDEO_H263ProfileHighCompression: + requested_profile.profile = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION; + break; + case OMX_VIDEO_H263ProfileInternet: + requested_profile.profile = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET; + break; + case OMX_VIDEO_H263ProfileInterlace: + requested_profile.profile = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE; + break; + case OMX_VIDEO_H263ProfileHighLatency: + requested_profile.profile = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY; + break; + default: + DEBUG_PRINT_LOW("ERROR: Unsupported H.263 profile = %lu", + requested_profile.profile); + return false; + } + + //profile level + switch (eLevel) { + case OMX_VIDEO_H263Level10: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0; + break; + case OMX_VIDEO_H263Level20: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0; + break; + case OMX_VIDEO_H263Level30: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0; + break; + case OMX_VIDEO_H263Level40: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0; + break; + case OMX_VIDEO_H263Level45: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5; + break; + case OMX_VIDEO_H263Level50: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0; + break; + case OMX_VIDEO_H263Level60: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0; + break; + case OMX_VIDEO_H263Level70: + case OMX_VIDEO_H263LevelMax: + default: //Set max level possible as default so that invalid levels are non-fatal + requested_level.level = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0; + break; + } + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + if (eProfile == OMX_VIDEO_AVCProfileBaseline) { + requested_profile.profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; + } else if(eProfile == QOMX_VIDEO_AVCProfileConstrainedBaseline) { + requested_profile.profile = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE; + } else if(eProfile == QOMX_VIDEO_AVCProfileConstrainedHigh) { + requested_profile.profile = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH; + } else if (eProfile == OMX_VIDEO_AVCProfileMain) { + requested_profile.profile = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; + } else if (eProfile == OMX_VIDEO_AVCProfileExtended) { + requested_profile.profile = V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED; + } else if (eProfile == OMX_VIDEO_AVCProfileHigh) { + requested_profile.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; + } else if (eProfile == OMX_VIDEO_AVCProfileHigh10) { + requested_profile.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10; + } else if (eProfile == OMX_VIDEO_AVCProfileHigh422) { + requested_profile.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422; + } else if (eProfile == OMX_VIDEO_AVCProfileHigh444) { + requested_profile.profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE; + } else { + DEBUG_PRINT_LOW("ERROR: Unsupported H.264 profile = %lu", + requested_profile.profile); + return false; + } + + //profile level + switch (eLevel) { + case OMX_VIDEO_AVCLevel1: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0; + break; + case OMX_VIDEO_AVCLevel1b: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_1B; + break; + case OMX_VIDEO_AVCLevel11: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_1_1; + break; + case OMX_VIDEO_AVCLevel12: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_1_2; + break; + case OMX_VIDEO_AVCLevel13: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_1_3; + break; + case OMX_VIDEO_AVCLevel2: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_2_0; + break; + case OMX_VIDEO_AVCLevel21: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_2_1; + break; + case OMX_VIDEO_AVCLevel22: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_2_2; + break; + case OMX_VIDEO_AVCLevel3: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_3_0; + break; + case OMX_VIDEO_AVCLevel31: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_3_1; + break; + case OMX_VIDEO_AVCLevel32: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_3_2; + break; + case OMX_VIDEO_AVCLevel4: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; + break; + case OMX_VIDEO_AVCLevel41: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_4_1; + break; + case OMX_VIDEO_AVCLevel42: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2; + break; + case OMX_VIDEO_AVCLevel5: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_0; + break; + case OMX_VIDEO_AVCLevel51: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1; + break; + case OMX_VIDEO_AVCLevel52: + case OMX_VIDEO_AVCLevelMax: + default: //Set max level possible as default so that invalid levels are non-fatal + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2; + break; + } + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) { + if (!(eProfile == OMX_VIDEO_VP8ProfileMain)) { + DEBUG_PRINT_ERROR("ERROR: Unsupported VP8 profile = %u", + (unsigned int)eProfile); + return false; + } + requested_profile.profile = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED; + m_profile_set = true; + switch(eLevel) { + case OMX_VIDEO_VP8Level_Version0: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0; + break; + case OMX_VIDEO_VP8Level_Version1: + case OMX_VIDEO_VP8LevelMax: + default: //Set max level possible as default so that invalid levels are non-fatal + requested_level.level = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1; + break; + } + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) { + if (eProfile == OMX_VIDEO_HEVCProfileMain) { + requested_profile.profile = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN; + } else if(eProfile == OMX_VIDEO_HEVCProfileMain10) { + requested_profile.profile = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10; + } else { + DEBUG_PRINT_ERROR("ERROR: Unsupported HEVC profile = %lu", + requested_profile.profile); + return false; + } + + //profile level + switch (eLevel) { + case OMX_VIDEO_HEVCMainTierLevel1: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1; + break; + case OMX_VIDEO_HEVCHighTierLevel1: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1; + break; + case OMX_VIDEO_HEVCMainTierLevel2: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2; + break; + case OMX_VIDEO_HEVCHighTierLevel2: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2; + break; + case OMX_VIDEO_HEVCMainTierLevel21: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1; + break; + case OMX_VIDEO_HEVCHighTierLevel21: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1; + break; + case OMX_VIDEO_HEVCMainTierLevel3: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3; + break; + case OMX_VIDEO_HEVCHighTierLevel3: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3; + break; + case OMX_VIDEO_HEVCMainTierLevel31: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1; + break; + case OMX_VIDEO_HEVCHighTierLevel31: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1; + break; + case OMX_VIDEO_HEVCMainTierLevel4: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4; + break; + case OMX_VIDEO_HEVCHighTierLevel4: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4; + break; + case OMX_VIDEO_HEVCMainTierLevel41: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1; + break; + case OMX_VIDEO_HEVCHighTierLevel41: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1; + break; + case OMX_VIDEO_HEVCMainTierLevel5: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5; + break; + case OMX_VIDEO_HEVCHighTierLevel5: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5; + break; + case OMX_VIDEO_HEVCMainTierLevel51: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1; + break; + case OMX_VIDEO_HEVCHighTierLevel51: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1; + break; + case OMX_VIDEO_HEVCMainTierLevel52: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2; + break; + case OMX_VIDEO_HEVCHighTierLevel52: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2; + break; + case OMX_VIDEO_HEVCMainTierLevel6: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6; + break; + case OMX_VIDEO_HEVCHighTierLevel6: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6; + break; + case OMX_VIDEO_HEVCMainTierLevel61: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1; + break; + case OMX_VIDEO_HEVCHighTierLevel61: + case OMX_VIDEO_HEVCLevelMax: + default: //Set max level possible as default so that invalid levels are non-fatal + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1; + break; + } + } + + if (!m_profile_set) { + int rc; + struct v4l2_control control; + + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + control.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE; + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_MPEG4) { + control.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE; + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H263) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE; + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE; + } else { + DEBUG_PRINT_ERROR("Wrong CODEC"); + return false; + } + + control.value = requested_profile.profile; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + codec_profile.profile = control.value; + m_profile_set = true; + } + + if (!m_level_set) { + int rc; + struct v4l2_control control; + + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + control.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL; + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_MPEG4) { + control.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL; + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H263) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL; + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL; + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL; + } else { + DEBUG_PRINT_ERROR("Wrong CODEC"); + return false; + } + + control.value = requested_level.level; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + profile_level.level = control.value; + m_level_set = true; + } + + return true; +} + +bool venc_dev::venc_set_voptiming_cfg( OMX_U32 TimeIncRes) +{ + + struct venc_voptimingcfg vop_timing_cfg; + + DEBUG_PRINT_LOW("venc_set_voptiming_cfg: TimeRes = %u", + (unsigned int)TimeIncRes); + + vop_timing_cfg.voptime_resolution = TimeIncRes; + + voptimecfg.voptime_resolution = vop_timing_cfg.voptime_resolution; + return true; +} + +bool venc_dev::venc_set_intra_period(OMX_U32 nPFrames, OMX_U32 nBFrames) +{ + + DEBUG_PRINT_LOW("venc_set_intra_period: nPFrames = %u, nBFrames: %u", (unsigned int)nPFrames, (unsigned int)nBFrames); + int rc; + struct v4l2_control control; + int pframe = 0, bframe = 0; + char property_value[PROPERTY_VALUE_MAX] = {0}; + + if ((codec_profile.profile != V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE) && + (codec_profile.profile != V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) && + (codec_profile.profile != V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN) && + (codec_profile.profile != V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10) && + (codec_profile.profile != V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)) { + nBFrames=0; + } + + if (!venc_validate_hybridhp_params(0, nBFrames, 0, 0) && !is_thulium_v1) { + DEBUG_PRINT_ERROR("Invalid settings, bframes cannot be enabled with HybridHP"); + return false; + } + + intra_period.num_pframes = nPFrames; + intra_period.num_bframes = nBFrames; + + if (!venc_calibrate_gop() && !is_thulium_v1) + { + DEBUG_PRINT_ERROR("Invalid settings, Hybrid HP enabled with LTR OR Hier-pLayers OR bframes"); + return false; + } + + if (m_sVenc_cfg.input_width * m_sVenc_cfg.input_height >= 3840 * 2160 && + (property_get("vidc.enc.disable_bframes", property_value, "0") && atoi(property_value))) { + intra_period.num_pframes = intra_period.num_pframes + intra_period.num_bframes; + intra_period.num_bframes = 0; + DEBUG_PRINT_LOW("Warning: Disabling B frames for UHD recording pFrames = %lu bFrames = %lu", + intra_period.num_pframes, intra_period.num_bframes); + } + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES; + control.value = intra_period.num_pframes; + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES; + control.value = intra_period.num_bframes; + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%lu", control.id, intra_period.num_bframes); + + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264 || + m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD; + control.value = 1; + + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + idrperiod.idrperiod = 1; + } + return true; +} + +bool venc_dev::venc_set_idr_period(OMX_U32 nPFrames, OMX_U32 nIDRPeriod) +{ + int rc = 0; + struct v4l2_control control; + DEBUG_PRINT_LOW("venc_set_idr_period: nPFrames = %u, nIDRPeriod: %u", + (unsigned int)nPFrames, (unsigned int)nIDRPeriod); + + if (m_sVenc_cfg.codectype != V4L2_PIX_FMT_H264) { + DEBUG_PRINT_ERROR("ERROR: IDR period valid for H264 only!!"); + return false; + } + + if (venc_set_intra_period (nPFrames, intra_period.num_bframes) == false) { + DEBUG_PRINT_ERROR("ERROR: Request for setting intra period failed"); + return false; + } + + if (!intra_period.num_bframes) + intra_period.num_pframes = nPFrames; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD; + control.value = nIDRPeriod; + + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + idrperiod.idrperiod = nIDRPeriod; + return true; +} + +bool venc_dev::venc_set_entropy_config(OMX_BOOL enable, OMX_U32 i_cabac_level) +{ + int rc = 0; + struct v4l2_control control; + + DEBUG_PRINT_LOW("venc_set_entropy_config: CABAC = %u level: %u", enable, (unsigned int)i_cabac_level); + + if (enable && (codec_profile.profile != V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) && + (codec_profile.profile != V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE)) { + + control.value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC; + control.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + entropy.longentropysel = control.value; + + if (i_cabac_level == 0) { + control.value = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0; + } else if (i_cabac_level == 1) { + control.value = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1; + } else if (i_cabac_level == 2) { + control.value = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2; + } + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL; + //control.value = entropy_cfg.cabacmodel; + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + entropy.cabacmodel=control.value; + } else if (!enable) { + control.value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC; + control.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE; + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + entropy.longentropysel=control.value; + } else { + DEBUG_PRINT_ERROR("Invalid Entropy mode for Baseline Profile"); + return false; + } + + return true; +} + +bool venc_dev::venc_set_multislice_cfg(OMX_INDEXTYPE Codec, OMX_U32 nSlicesize) // MB +{ + int rc; + struct v4l2_control control; + bool status = true; + + if ((Codec != OMX_IndexParamVideoH263) && (nSlicesize)) { + control.value = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB; + } else { + control.value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE; + } + + control.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE; + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + multislice.mslice_mode=control.value; + + if (multislice.mslice_mode!=V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) { + + control.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB; + control.value = nSlicesize; + DEBUG_PRINT_LOW("Calling SLICE_MB IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + multislice.mslice_size=control.value; + + } + + return status; +} + +bool venc_dev::venc_set_intra_refresh(OMX_VIDEO_INTRAREFRESHTYPE ir_mode, OMX_U32 irMBs) +{ + bool status = true; + int rc; + struct v4l2_control control_mode,control_mbs; + control_mode.id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE; + control_mbs.id = V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS; + control_mbs.value = 0; + // There is no disabled mode. Disabled mode is indicated by a 0 count. + if (irMBs == 0 || ir_mode == OMX_VIDEO_IntraRefreshMax) { + control_mode.value = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE; + return status; + } else if ((ir_mode == OMX_VIDEO_IntraRefreshCyclic) && + (irMBs < ((m_sVenc_cfg.dvs_width * m_sVenc_cfg.dvs_height)>>8))) { + control_mode.value = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC; + control_mbs.id=V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS; + control_mbs.value=irMBs; + } else if ((ir_mode == OMX_VIDEO_IntraRefreshAdaptive) && + (irMBs < ((m_sVenc_cfg.dvs_width * m_sVenc_cfg.dvs_height)>>8))) { + control_mode.value = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE; + control_mbs.id=V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS; + control_mbs.value=irMBs; + } else if ((ir_mode == OMX_VIDEO_IntraRefreshBoth) && + (irMBs < ((m_sVenc_cfg.dvs_width * m_sVenc_cfg.dvs_height)>>8))) { + control_mode.value = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE; + } else if ((ir_mode == OMX_VIDEO_IntraRefreshRandom) && + (irMBs < ((m_sVenc_cfg.dvs_width * m_sVenc_cfg.dvs_height)>>8))) { + control_mode.value = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM; + control_mbs.id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS; + control_mbs.value = irMBs; + } else { + DEBUG_PRINT_ERROR("ERROR: Invalid IntraRefresh Parameters:" + "mb count: %u, mb mode:%d", (unsigned int)irMBs, ir_mode); + return false; + } + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%u, val=%d", control_mode.id, control_mode.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control_mode); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control_mode.id, control_mode.value); + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control_mbs.id, control_mbs.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control_mbs); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control_mbs.id, control_mbs.value); + + intra_refresh.irmode = control_mode.value; + intra_refresh.mbcount = control_mbs.value; + + return status; +} + +bool venc_dev::venc_set_error_resilience(OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE* error_resilience) +{ + bool status = true; + struct venc_headerextension hec_cfg; + struct venc_multiclicecfg multislice_cfg; + int rc; + OMX_U32 resynchMarkerSpacingBytes = 0; + struct v4l2_control control; + + memset(&control, 0, sizeof(control)); + + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_MPEG4) { + if (error_resilience->bEnableHEC) { + hec_cfg.header_extension = 1; + } else { + hec_cfg.header_extension = 0; + } + + hec.header_extension = error_resilience->bEnableHEC; + } + + if (error_resilience->bEnableRVLC) { + DEBUG_PRINT_ERROR("RVLC is not Supported"); + return false; + } + + if (( m_sVenc_cfg.codectype != V4L2_PIX_FMT_H263) && + (error_resilience->bEnableDataPartitioning)) { + DEBUG_PRINT_ERROR("DataPartioning are not Supported for MPEG4/H264"); + return false; + } + + if (error_resilience->nResynchMarkerSpacing) { + resynchMarkerSpacingBytes = error_resilience->nResynchMarkerSpacing; + resynchMarkerSpacingBytes = ALIGN(resynchMarkerSpacingBytes, 8) >> 3; + } + if (( m_sVenc_cfg.codectype != V4L2_PIX_FMT_H263) && + (error_resilience->nResynchMarkerSpacing)) { + multislice_cfg.mslice_mode = VEN_MSLICE_CNT_BYTE; + multislice_cfg.mslice_size = resynchMarkerSpacingBytes; + control.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE; + control.value = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES; + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H263 && + error_resilience->bEnableDataPartitioning) { + multislice_cfg.mslice_mode = VEN_MSLICE_GOB; + multislice_cfg.mslice_size = resynchMarkerSpacingBytes; + control.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE; + control.value = V4L2_MPEG_VIDEO_MULTI_SLICE_GOB; + } else { + multislice_cfg.mslice_mode = VEN_MSLICE_OFF; + multislice_cfg.mslice_size = 0; + control.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE; + control.value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE; + } + + DEBUG_PRINT_LOW("%s(): mode = %lu, size = %lu", __func__, + multislice_cfg.mslice_mode, multislice_cfg.mslice_size); + DEBUG_PRINT_ERROR("Calling IOCTL set control for id=%x, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set Slice mode control"); + return false; + } + + DEBUG_PRINT_ERROR("Success IOCTL set control for id=%x, value=%d", control.id, control.value); + multislice.mslice_mode=control.value; + + control.id = (multislice_cfg.mslice_mode == VEN_MSLICE_GOB) ? + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB : V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES; + control.value = resynchMarkerSpacingBytes; + DEBUG_PRINT_ERROR("Calling IOCTL set control for id=%x, val=%d", control.id, control.value); + + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set MAX MB control"); + return false; + } + + DEBUG_PRINT_ERROR("Success IOCTL set control for id=%x, value=%d", control.id, control.value); + multislice.mslice_mode = multislice_cfg.mslice_mode; + multislice.mslice_size = multislice_cfg.mslice_size; + return status; +} + +bool venc_dev::venc_set_inloop_filter(OMX_VIDEO_AVCLOOPFILTERTYPE loopfilter) +{ + int rc; + struct v4l2_control control; + control.id=V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE; + control.value=0; + + if (loopfilter == OMX_VIDEO_AVCLoopFilterEnable) { + control.value=V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED; + } else if (loopfilter == OMX_VIDEO_AVCLoopFilterDisable) { + control.value=V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED; + } else if (loopfilter == OMX_VIDEO_AVCLoopFilterDisableSliceBoundary) { + control.value=V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY; + } + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + dbkfilter.db_mode=control.value; + + control.id=V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA; + control.value=0; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + control.id=V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA; + control.value=0; + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + + dbkfilter.slicealpha_offset = dbkfilter.slicebeta_offset = 0; + return true; +} + +bool venc_dev::venc_set_target_bitrate(OMX_U32 nTargetBitrate, OMX_U32 config) +{ + DEBUG_PRINT_LOW("venc_set_target_bitrate: bitrate = %u", + (unsigned int)nTargetBitrate); + struct v4l2_control control; + int rc = 0; + + if (vqzip_sei_info.enabled) { + DEBUG_PRINT_HIGH("For VQZIP 1.0, Bitrate setting is not supported"); + return true; + } + + control.id = V4L2_CID_MPEG_VIDEO_BITRATE; + control.value = nTargetBitrate; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + + m_sVenc_cfg.targetbitrate = control.value; + bitrate.target_bitrate = control.value; + + if (!config) { + m_level_set = false; + + if (venc_set_profile_level(0, 0)) { + DEBUG_PRINT_HIGH("Calling set level (Bitrate) with %lu",profile_level.level); + } + } + + // Configure layer-wise bitrate if temporal layers are enabled and layer-wise distribution + // has been specified + if (temporal_layers_config.bIsBitrateRatioValid && temporal_layers_config.nPLayers) { + OMX_U32 layerBitrates[OMX_VIDEO_MAX_HP_LAYERS] = {0}, + numLayers = temporal_layers_config.nPLayers + temporal_layers_config.nBLayers; + + DEBUG_PRINT_LOW("TemporalLayer: configuring layerwise bitrate"); + for (OMX_U32 i = 0; i < numLayers; ++i) { + layerBitrates[i] = + (temporal_layers_config.nTemporalLayerBitrateFraction[i] * bitrate.target_bitrate) / 100; + DEBUG_PRINT_LOW("TemporalLayer: layer[%u] ratio=%u%% bitrate=%u(of %ld)", + i, temporal_layers_config.nTemporalLayerBitrateFraction[i], + layerBitrates[i], bitrate.target_bitrate); + } + if (!venc_set_layer_bitrates((OMX_U32 *)layerBitrates, numLayers)) { + return false; + } + } + + return true; +} + +bool venc_dev::venc_set_encode_framerate(OMX_U32 encode_framerate, OMX_U32 config) +{ + struct v4l2_streamparm parm; + int rc = 0; + struct venc_framerate frame_rate_cfg; + Q16ToFraction(encode_framerate,frame_rate_cfg.fps_numerator,frame_rate_cfg.fps_denominator); + parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + parm.parm.output.timeperframe.numerator = frame_rate_cfg.fps_denominator; + parm.parm.output.timeperframe.denominator = frame_rate_cfg.fps_numerator; + + if (vqzip_sei_info.enabled) { + DEBUG_PRINT_HIGH("For VQZIP 1.0, Framerate setting is not supported"); + return true; + } + + + if (frame_rate_cfg.fps_numerator > 0) + rc = ioctl(m_nDriver_fd, VIDIOC_S_PARM, &parm); + + if (rc) { + DEBUG_PRINT_ERROR("ERROR: Request for setting framerate failed"); + return false; + } + + m_sVenc_cfg.fps_den = frame_rate_cfg.fps_denominator; + m_sVenc_cfg.fps_num = frame_rate_cfg.fps_numerator; + + if (!config) { + m_level_set = false; + + if (venc_set_profile_level(0, 0)) { + DEBUG_PRINT_HIGH("Calling set level (Framerate) with %lu",profile_level.level); + } + } + + return true; +} + +bool venc_dev::venc_set_color_format(OMX_COLOR_FORMATTYPE color_format) +{ + struct v4l2_format fmt; + int color_space = 0; + DEBUG_PRINT_LOW("venc_set_color_format: color_format = %u ", color_format); + + switch ((int)color_format) { + case OMX_COLOR_FormatYUV420SemiPlanar: + case QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m: + m_sVenc_cfg.inputformat = V4L2_PIX_FMT_NV12; + color_space = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + case QOMX_COLOR_FormatYVU420SemiPlanar: + m_sVenc_cfg.inputformat = V4L2_PIX_FMT_NV21; + color_space = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + case QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed: + m_sVenc_cfg.inputformat = V4L2_PIX_FMT_NV12_UBWC; + color_space = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + case QOMX_COLOR_Format32bitRGBA8888: + m_sVenc_cfg.inputformat = V4L2_PIX_FMT_RGB32; + break; + case QOMX_COLOR_Format32bitRGBA8888Compressed: + m_sVenc_cfg.inputformat = V4L2_PIX_FMT_RGBA8888_UBWC; + break; + default: + DEBUG_PRINT_HIGH("WARNING: Unsupported Color format [%d]", color_format); + m_sVenc_cfg.inputformat = V4L2_DEFAULT_OUTPUT_COLOR_FMT; + color_space = V4L2_COLORSPACE_470_SYSTEM_BG; + DEBUG_PRINT_HIGH("Default color format NV12 UBWC is set"); +#ifdef _PQ_ + /* + * If Client is using Opaque, YUV format will be informed with + * first ETB. Till that point, it is unknown. + */ + m_pq.is_YUV_format_uncertain = true; +#endif // _PQ_ + break; + } + + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.pixelformat = m_sVenc_cfg.inputformat; + fmt.fmt.pix_mp.colorspace = color_space; + fmt.fmt.pix_mp.height = m_sVenc_cfg.input_height; + fmt.fmt.pix_mp.width = m_sVenc_cfg.input_width; + + if (ioctl(m_nDriver_fd, VIDIOC_S_FMT, &fmt)) { + DEBUG_PRINT_ERROR("Failed setting color format %x", color_format); + return false; + } + + return true; +} + +bool venc_dev::venc_set_intra_vop_refresh(OMX_BOOL intra_vop_refresh) +{ + DEBUG_PRINT_LOW("venc_set_intra_vop_refresh: intra_vop = %uc", intra_vop_refresh); + + if (intra_vop_refresh == OMX_TRUE) { + struct v4l2_control control; + int rc; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME; + control.value = 1; + DEBUG_PRINT_ERROR("Calling IOCTL set control for id=%x, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set Intra Frame Request control"); + return false; + } + + DEBUG_PRINT_ERROR("Success IOCTL set control for id=%x, value=%d", control.id, control.value); + } else { + DEBUG_PRINT_ERROR("ERROR: VOP Refresh is False, no effect"); + } + + return true; +} + +bool venc_dev::venc_set_deinterlace(OMX_U32 enable) +{ + DEBUG_PRINT_LOW("venc_set_deinterlace: enable = %u", (unsigned int)enable); + struct v4l2_control control; + int rc; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE; + if (enable) + control.value = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED; + else + control.value = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%x, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set Deinterlcing control"); + return false; + } + DEBUG_PRINT_LOW("Success IOCTL set control for id=%x, value=%d", control.id, control.value); + deinterlace_enabled = true; + return true; +} + +bool venc_dev::venc_calibrate_gop() +{ + int ratio, sub_gop_size, gop_size, nPframes, nBframes, nLayers; + int num_sub_gops_in_a_gop; + nPframes = intra_period.num_pframes; + nBframes = intra_period.num_bframes; + nLayers = hier_layers.numlayers; + if (temporal_layers_config.nPLayers) { + nLayers = temporal_layers_config.nPLayers + temporal_layers_config.nBLayers; + } + + if (!nPframes && nLayers) { + DEBUG_PRINT_ERROR("nPframes should be non-zero when nLayers are present\n"); + return false; + } + + if (nLayers > 1) { /*Multi-layer encoding*/ + sub_gop_size = 1 << (nLayers - 1); + /* Actual GOP definition is nPframes + nBframes + 1 but for the sake of + * below calculations we are ignoring +1 . Ignoring +1 in below + * calculations is not a mistake but intentional. + */ + gop_size = MAX(sub_gop_size, ROUND(nPframes + nBframes, sub_gop_size)); + num_sub_gops_in_a_gop = gop_size/sub_gop_size; + if (nBframes) { /*Hier-B case*/ + /* + * Frame Type--> I B B B P B B B P I B B P ... + * Layer --> 0 2 1 2 0 2 1 2 0 0 2 1 2 ... + * nPframes = 2, nBframes = 6, nLayers = 3 + * + * Intention is to keep the intraperiod as close as possible to what is desired + * by the client while adjusting nPframes and nBframes to meet other constraints. + * eg1: Input by client: nPframes = 9, nBframes = 14, nLayers = 2 + * Output of this fn: nPframes = 12, nBframes = 12, nLayers = 2 + * + * eg2: Input by client: nPframes = 9, nBframes = 4, nLayers = 2 + * Output of this fn: nPframes = 7, nBframes = 7, nLayers = 2 + */ + nPframes = num_sub_gops_in_a_gop; + nBframes = gop_size - nPframes; + } else { /*Hier-P case*/ + /* + * Frame Type--> I P P P P P P P I P P P P ... + * Layer--> 0 2 1 2 0 2 1 2 0 2 1 2 0 ... + * nPframes = 7, nBframes = 0, nLayers = 3 + * + * Intention is to keep the intraperiod as close as possible to what is desired + * by the client while adjusting nPframes and nBframes to meet other constraints. + * eg1: Input by client: nPframes = 9, nBframes = 0, nLayers = 3 + * Output of this fn: nPframes = 7, nBframes = 0, nLayers = 3 + * + * eg2: Input by client: nPframes = 10, nBframes = 0, nLayers = 3 + * Output of this fn:nPframes = 12, nBframes = 0, nLayers = 3 + */ + nPframes = gop_size - 1; + } + } else { /*Single-layer encoding*/ + if (nBframes) { + /* I P B B B P B B B P B B B I P B B... + * 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17... + * nPframes = 3, nBframes = 9, nLayers = 0 + * + * ratio is rounded, + * eg1: nPframes = 9, nBframes = 11 => ratio = 1 + * eg2: nPframes = 9, nBframes = 16 => ratio = 2 + */ + ratio = MAX(1, MIN((nBframes + (nPframes >> 1))/nPframes, 3)); + nBframes = ratio * nPframes; + } + } + DEBUG_PRINT_LOW("P/B Frames changed from: %ld/%ld to %d/%d", + intra_period.num_pframes, intra_period.num_bframes, nPframes, nBframes); + intra_period.num_pframes = nPframes; + intra_period.num_bframes = nBframes; + hier_layers.numlayers = nLayers; + return true; +} + +bool venc_dev::venc_set_bitrate_type(OMX_U32 type) +{ + struct v4l2_control control; + int rc = 0; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE; + control.value = type; + DEBUG_PRINT_LOW("Set Bitrate type to %s for %d \n", bitrate_type_string(type), type); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Request to set Bitrate type to %s failed", + bitrate_type_string(type)); + return false; + } + return true; +} + +bool venc_dev::venc_set_layer_bitrates(OMX_U32 *layerBitrate, OMX_U32 numLayers) +{ + DEBUG_PRINT_LOW("venc_set_layer_bitrates"); + struct v4l2_ext_control ctrl[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS]; + struct v4l2_ext_controls controls; + int rc = 0; + OMX_U32 i; + + if (!venc_set_bitrate_type(V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_ENABLE)) { + DEBUG_PRINT_ERROR("Failed to set layerwise bitrate type %d", rc); + return false; + } + + for (OMX_U32 i = 0; i < numLayers && i < OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS; ++i) { + if (!layerBitrate[i]) { + DEBUG_PRINT_ERROR("Invalid bitrate settings for layer %d", i); + return false; + } else { + ctrl[i].id = V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE; + ctrl[i].value = layerBitrate[i]; + } + } + controls.count = numLayers; + controls.ctrl_class = V4L2_CTRL_CLASS_MPEG; + controls.controls = ctrl; + + rc = ioctl(m_nDriver_fd, VIDIOC_S_EXT_CTRLS, &controls); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set layerwise bitrate %d", rc); + return false; + } + + DEBUG_PRINT_LOW("Layerwise bitrate configured successfully"); + return true; +} + +bool venc_dev::venc_set_hybrid_hierp(QOMX_EXTNINDEX_VIDEO_HYBRID_HP_MODE* hhp) +{ + DEBUG_PRINT_LOW("venc_set_hybrid_hierp layers"); + struct v4l2_control control; + int rc; + + if (!venc_validate_hybridhp_params(hhp->nHpLayers, 0, 0, (int) HIER_P_HYBRID)) { + DEBUG_PRINT_ERROR("Invalid settings, Hybrid HP enabled with LTR OR Hier-pLayers OR bframes"); + return false; + } + + if (!hhp->nHpLayers || hhp->nHpLayers > MAX_HYB_HIERP_LAYERS) { + DEBUG_PRINT_ERROR("Invalid numbers of layers set: %d (max supported is 6)", hhp->nHpLayers); + return false; + } + if (!venc_set_intra_period(hhp->nKeyFrameInterval, 0)) { + DEBUG_PRINT_ERROR("Failed to set Intraperiod: %d", hhp->nKeyFrameInterval); + return false; + } + + hier_layers.numlayers = hhp->nHpLayers; + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + hier_layers.hier_mode = HIER_P_HYBRID; + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) { + hier_layers.hier_mode = HIER_P; + } + if (venc_calibrate_gop()) { + // Update the driver with the new nPframes and nBframes + control.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES; + control.value = intra_period.num_pframes; + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES; + control.value = intra_period.num_bframes; + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + DEBUG_PRINT_LOW("Updated nPframes (%ld) and nBframes (%ld)", + intra_period.num_pframes, intra_period.num_bframes); + } else { + DEBUG_PRINT_ERROR("Invalid settings, Hybrid HP enabled with LTR OR Hier-pLayers OR bframes"); + return false; + } + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE; + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS; + } + control.value = hhp->nHpLayers - 1; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%x, val=%d", + control.id, control.value); + + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set hybrid hierp/hierp %d", rc); + return false; + } + + DEBUG_PRINT_LOW("SUCCESS IOCTL set control for id=%x, val=%d", + control.id, control.value); + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC; + control.value = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to enable SVC_NAL"); + return false; + } + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS; + control.value = hhp->nHpLayers - 1; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to enable SVC_NAL"); + return false; + } + } else { + DEBUG_PRINT_ERROR("Failed : Unsupported codec for Hybrid Hier P : %lu", m_sVenc_cfg.codectype); + return false; + } + + if(venc_set_session_qp_range (hhp->nMinQuantizer, + hhp->nMaxQuantizer) == false) { + DEBUG_PRINT_ERROR("ERROR: Setting QP Range for hybridHP [%u %u] failed", + (unsigned int)hhp->nMinQuantizer, (unsigned int)hhp->nMaxQuantizer); + return false; + } else { + session_qp_values.minqp = hhp->nMinQuantizer; + session_qp_values.maxqp = hhp->nMaxQuantizer; + } + + OMX_U32 layerBitrates[OMX_VIDEO_MAX_HP_LAYERS] = {0}; + for (OMX_U32 i = 0; i < hhp->nHpLayers; i++) { + layerBitrates[i] = hhp->nTemporalLayerBitrateRatio[i]; + hybrid_hp.nTemporalLayerBitrateRatio[i] = hhp->nTemporalLayerBitrateRatio[i]; + DEBUG_PRINT_LOW("Setting Layer[%u] bitrate = %u", i, layerBitrates[i]); + } + if (!venc_set_layer_bitrates((OMX_U32 *)layerBitrates, hhp->nHpLayers)) { + DEBUG_PRINT_ERROR("Failed to set Layer wise bitrate: %d, %d, %d, %d, %d, %d", + hhp->nTemporalLayerBitrateRatio[0],hhp->nTemporalLayerBitrateRatio[1], + hhp->nTemporalLayerBitrateRatio[2],hhp->nTemporalLayerBitrateRatio[3], + hhp->nTemporalLayerBitrateRatio[4],hhp->nTemporalLayerBitrateRatio[5]); + return false; + } + hybrid_hp.nHpLayers = hhp->nHpLayers; + + // Set this or else the layer0 bitrate will be overwritten by + // default value in component + m_sVenc_cfg.targetbitrate = bitrate.target_bitrate = hhp->nTemporalLayerBitrateRatio[0]; + hybrid_hp.nHpLayers = hhp->nHpLayers; + hybrid_hp.nKeyFrameInterval = hhp->nKeyFrameInterval; + hybrid_hp.nMaxQuantizer = hhp->nMaxQuantizer; + hybrid_hp.nMinQuantizer = hhp->nMinQuantizer; + return true; +} + +bool venc_dev::venc_set_ltrmode(OMX_U32 enable, OMX_U32 count) +{ + DEBUG_PRINT_LOW("venc_set_ltrmode: enable = %u", (unsigned int)enable); + struct v4l2_ext_control ctrl[2]; + struct v4l2_ext_controls controls; + int rc; + + if (!venc_validate_hybridhp_params(0, 0, count, 0)) { + DEBUG_PRINT_ERROR("Invalid settings, LTR enabled with HybridHP"); + return false; + } + + ctrl[0].id = V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE; + if (enable) + ctrl[0].value = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_MANUAL; + else + ctrl[0].value = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE; + + ctrl[1].id = V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT; + if (enable && count > 0) + ctrl[1].value = count; + else if (enable) + ctrl[1].value = 1; + else + ctrl[1].value = 0; + + controls.count = 2; + controls.ctrl_class = V4L2_CTRL_CLASS_MPEG; + controls.controls = ctrl; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%x, val=%d id=%x, val=%d", + controls.controls[0].id, controls.controls[0].value, + controls.controls[1].id, controls.controls[1].value); + + rc = ioctl(m_nDriver_fd, VIDIOC_S_EXT_CTRLS, &controls); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set ltrmode %d", rc); + return false; + } + ltrinfo.enabled = enable; + ltrinfo.count = count; + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%x, val=%d id=%x, val=%d", + controls.controls[0].id, controls.controls[0].value, + controls.controls[1].id, controls.controls[1].value); + + if (!venc_set_profile_level(0, 0)) { + DEBUG_PRINT_ERROR("ERROR: %s(): Driver Profile/Level is NOT SET", + __func__); + } else { + DEBUG_PRINT_HIGH("%s(): Driver Profile[%lu]/Level[%lu] successfully SET", + __func__, codec_profile.profile, profile_level.level); + } + + return true; +} + +bool venc_dev::venc_set_useltr(OMX_U32 frameIdx) +{ + DEBUG_PRINT_LOW("venc_use_goldenframe"); + int rc = true; + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME; + control.value = frameIdx; + + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set use_ltr %d", rc); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%x, val=%d", + control.id, control.value); + return true; +} + +bool venc_dev::venc_set_markltr(OMX_U32 frameIdx) +{ + DEBUG_PRINT_LOW("venc_set_goldenframe"); + int rc = true; + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME; + control.value = frameIdx; + + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set ltrmode %d", rc); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%x, val=%d", + control.id, control.value); + return true; +} + +bool venc_dev::venc_set_vpe_rotation(OMX_S32 rotation_angle) +{ + DEBUG_PRINT_LOW("venc_set_vpe_rotation: rotation angle = %d", (int)rotation_angle); + struct v4l2_control control; + int rc; + struct v4l2_format fmt; + struct v4l2_requestbuffers bufreq; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION; + if (rotation_angle == 0) + control.value = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE; + else if (rotation_angle == 90) + control.value = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90; + else if (rotation_angle == 180) + control.value = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180; + else if (rotation_angle == 270) + control.value = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270; + else { + DEBUG_PRINT_ERROR("Failed to find valid rotation angle"); + return false; + } + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%x, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_HIGH("Failed to set VPE Rotation control"); + return false; + } + DEBUG_PRINT_LOW("Success IOCTL set control for id=%x, value=%d", control.id, control.value); + + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.height = m_sVenc_cfg.dvs_height; + fmt.fmt.pix_mp.width = m_sVenc_cfg.dvs_width; + fmt.fmt.pix_mp.pixelformat = m_sVenc_cfg.codectype; + if (ioctl(m_nDriver_fd, VIDIOC_S_FMT, &fmt)) { + DEBUG_PRINT_ERROR("Failed to set format on capture port"); + return false; + } + + m_sOutput_buff_property.datasize = fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + bufreq.memory = V4L2_MEMORY_USERPTR; + bufreq.count = m_sOutput_buff_property.actualcount; + bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + if (ioctl(m_nDriver_fd,VIDIOC_REQBUFS, &bufreq)) { + DEBUG_PRINT_ERROR("ERROR: Request for o/p buffer count failed for rotation"); + return false; + } + if (bufreq.count >= m_sOutput_buff_property.mincount) + m_sOutput_buff_property.actualcount = m_sOutput_buff_property.mincount = bufreq.count; + + return true; +} + +bool venc_dev::venc_set_searchrange() +{ + DEBUG_PRINT_LOW("venc_set_searchrange"); + struct v4l2_control control; + struct v4l2_ext_control ctrl[6]; + struct v4l2_ext_controls controls; + int rc; + + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_MPEG4) { + ctrl[0].id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE; + ctrl[0].value = 16; + ctrl[1].id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE; + ctrl[1].value = 4; + ctrl[2].id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE; + ctrl[2].value = 16; + ctrl[3].id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE; + ctrl[3].value = 4; + ctrl[4].id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE; + ctrl[4].value = 12; + ctrl[5].id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE; + ctrl[5].value = 4; + } else if ((m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) || + (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8)) { + ctrl[0].id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE; + ctrl[0].value = 16; + ctrl[1].id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE; + ctrl[1].value = 4; + ctrl[2].id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE; + ctrl[2].value = 16; + ctrl[3].id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE; + ctrl[3].value = 4; + ctrl[4].id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE; + ctrl[4].value = 12; + ctrl[5].id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE; + ctrl[5].value = 4; + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H263) { + ctrl[0].id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE; + ctrl[0].value = 4; + ctrl[1].id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE; + ctrl[1].value = 4; + ctrl[2].id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE; + ctrl[2].value = 4; + ctrl[3].id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE; + ctrl[3].value = 4; + ctrl[4].id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE; + ctrl[4].value = 4; + ctrl[5].id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE; + ctrl[5].value = 4; + } else { + DEBUG_PRINT_ERROR("Invalid codec type"); + return false; + } + controls.count = 6; + controls.ctrl_class = V4L2_CTRL_CLASS_MPEG; + controls.controls = ctrl; + + DEBUG_PRINT_LOW(" Calling IOCTL set control for" + "id=%x, val=%d id=%x, val=%d" + "id=%x, val=%d id=%x, val=%d" + "id=%x, val=%d id=%x, val=%d", + controls.controls[0].id, controls.controls[0].value, + controls.controls[1].id, controls.controls[1].value, + controls.controls[2].id, controls.controls[2].value, + controls.controls[3].id, controls.controls[3].value, + controls.controls[4].id, controls.controls[4].value, + controls.controls[5].id, controls.controls[5].value); + + rc = ioctl(m_nDriver_fd, VIDIOC_S_EXT_CTRLS, &controls); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set search range %d", rc); + return false; + } + return true; +} + +bool venc_dev::venc_set_ratectrl_cfg(OMX_VIDEO_CONTROLRATETYPE eControlRate) +{ + bool status = true; + struct v4l2_control control; + int rc = 0; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL; + + switch ((OMX_U32)eControlRate) { + case OMX_Video_ControlRateDisable: + control.value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF; + break; + case OMX_Video_ControlRateVariableSkipFrames: + (supported_rc_modes & RC_VBR_VFR) ? + control.value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR : + status = false; + break; + case OMX_Video_ControlRateVariable: + (supported_rc_modes & RC_VBR_CFR) ? + control.value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR : + status = false; + break; + case OMX_Video_ControlRateConstantSkipFrames: + (supported_rc_modes & RC_CBR_VFR) ? + control.value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR : + status = false; + break; + case OMX_Video_ControlRateConstant: + (supported_rc_modes & RC_CBR_CFR) ? + control.value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR : + status = false; + break; + case QOMX_Video_ControlRateMaxBitrate: + (supported_rc_modes & RC_MBR_CFR) ? + control.value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR: + status = false; + break; + case QOMX_Video_ControlRateMaxBitrateSkipFrames: + (supported_rc_modes & RC_MBR_VFR) ? + control.value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR: + status = false; + break; + default: + status = false; + break; + } + + if (status) { + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + rate_ctrl.rcmode = control.value; + } + +#ifdef _VQZIP_ + if (eControlRate == OMX_Video_ControlRateVariable && (supported_rc_modes & RC_VBR_CFR) + && m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + /* Enable VQZIP SEI by default for camcorder RC modes */ + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI; + control.value = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI_ENABLE; + DEBUG_PRINT_HIGH("Set VQZIP SEI:"); + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control) < 0) { + DEBUG_PRINT_HIGH("Non-Fatal: Request to set VQZIP failed"); + } + } +#endif + + return status; +} + +bool venc_dev::venc_set_perf_level(QOMX_VIDEO_PERF_LEVEL ePerfLevel) +{ + bool status = true; + struct v4l2_control control; + int rc = 0; + control.id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL; + + switch (ePerfLevel) { + case OMX_QCOM_PerfLevelNominal: + control.value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL; + break; + case OMX_QCOM_PerfLevelTurbo: + control.value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO; + break; + default: + status = false; + break; + } + + if (status) { + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set control for id=%d, val=%d", control.id, control.value); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + } + return status; +} + +bool venc_dev::venc_set_perf_mode(OMX_U32 mode) +{ + struct v4l2_control control; + if (mode && mode <= V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE; + control.value = mode; + DEBUG_PRINT_LOW("Going to set V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE"); + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE"); + return false; + } + return true; + } else { + DEBUG_PRINT_ERROR("Invalid mode set for V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE: %d", mode); + return false; + } +} + +bool venc_dev::venc_set_qp(OMX_U32 nQp) +{ + struct v4l2_control control; + if (nQp) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_CONFIG_QP; + control.value = nQp; + DEBUG_PRINT_LOW("Going to set V4L2_CID_MPEG_VIDC_VIDEO_CONFIG_QP"); + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set V4L2_CID_MPEG_VIDC_VIDEO_CONFIG_QP"); + return false; + } + } else { + DEBUG_PRINT_ERROR("Invalid qp set for V4L2_CID_MPEG_VIDC_VIDEO_CONFIG_QP: %d", nQp); + return false; + } + return true; +} + +bool venc_dev::venc_set_aspectratio(void *nSar) +{ + int rc; + struct v4l2_control control; + struct v4l2_ext_control ctrl[2]; + struct v4l2_ext_controls controls; + QOMX_EXTNINDEX_VIDEO_VENC_SAR *sar; + + sar = (QOMX_EXTNINDEX_VIDEO_VENC_SAR *) nSar; + + ctrl[0].id = V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH; + ctrl[0].value = sar->nSARWidth; + ctrl[1].id = V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_HEIGHT; + ctrl[1].value = sar->nSARHeight; + + controls.count = 2; + controls.ctrl_class = V4L2_CTRL_CLASS_MPEG; + controls.controls = ctrl; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%x val=%d, id=%x val=%d", + controls.controls[0].id, controls.controls[0].value, + controls.controls[1].id, controls.controls[1].value); + + rc = ioctl(m_nDriver_fd, VIDIOC_S_EXT_CTRLS, &controls); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set SAR %d", rc); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%x val=%d, id=%x val=%d", + controls.controls[0].id, controls.controls[0].value, + controls.controls[1].id, controls.controls[1].value); + return true; +} + +bool venc_dev::venc_set_hierp_layers(OMX_U32 hierp_layers) +{ + struct v4l2_control control; + if (hierp_layers && (hier_layers.hier_mode == HIER_P) && + (hierp_layers <= hier_layers.numlayers)) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS; + control.value = hierp_layers - 1; + DEBUG_PRINT_LOW("Going to set V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS"); + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set HIERP_LAYERS"); + return false; + } + return true; + } else { + DEBUG_PRINT_ERROR("Invalid layers set for HIERP_LAYERS: %d", + hierp_layers); + return false; + } +} + +bool venc_dev::venc_set_lowlatency_mode(OMX_BOOL enable) +{ + int rc = 0; + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE; + if (enable) + control.value = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_ENABLE; + else + control.value = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_DISABLE; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%x, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set lowlatency control"); + return false; + } + DEBUG_PRINT_LOW("Success IOCTL set control for id=%x, value=%d", control.id, control.value); + + return true; +} + +bool venc_dev::venc_set_low_latency(OMX_BOOL enable) +{ + struct v4l2_control control; + + if (m_sVenc_cfg.codectype != V4L2_PIX_FMT_H264) { + DEBUG_PRINT_ERROR("Low Latency mode is valid only for H264"); + return false; + } + + enable ? control.value = 2 : control.value = 0; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_PIC_ORDER_CNT; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set H264_PICORDER_CNT"); + return false; + } + + low_latency_mode = (OMX_BOOL) enable; + + return true; +} + +bool venc_dev::venc_set_baselayerid(OMX_U32 baseid) +{ + struct v4l2_control control; + if (hier_layers.hier_mode == HIER_P) { + control.id = V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID; + control.value = baseid; + DEBUG_PRINT_LOW("Going to set V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID"); + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID"); + return false; + } + return true; + } else { + DEBUG_PRINT_ERROR("Invalid mode set for V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID: %d", + hier_layers.hier_mode); + return false; + } +} + +bool venc_dev::venc_set_vui_timing_info(OMX_BOOL enable) +{ + struct v4l2_control control; + int rc = 0; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO; + + if (enable) + control.value = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED; + else + control.value = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED; + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%x, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set VUI timing info control"); + return false; + } + DEBUG_PRINT_LOW("Success IOCTL set control for id=%x, value=%d", control.id, control.value); + return true; +} + +bool venc_dev::venc_set_peak_bitrate(OMX_U32 nPeakBitrate) +{ + struct v4l2_control control; + int rc = 0; + control.id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK; + control.value = nPeakBitrate; + + DEBUG_PRINT_LOW("venc_set_peak_bitrate: bitrate = %u", (unsigned int)nPeakBitrate); + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + + if (rc) { + DEBUG_PRINT_ERROR("Failed to set peak bitrate control"); + return false; + } + + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + + return true; +} + +bool venc_dev::venc_set_vpx_error_resilience(OMX_BOOL enable) +{ + struct v4l2_control control; + int rc = 0; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE; + + if (enable) + control.value = 1; + else + control.value = 0; + + DEBUG_PRINT_LOW("venc_set_vpx_error_resilience: %d", control.value); + + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + + rc = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (rc) { + DEBUG_PRINT_ERROR("Failed to set VPX Error Resilience"); + return false; + } + vpx_err_resilience.enable = 1; + DEBUG_PRINT_LOW("Success IOCTL set control for id=%d, value=%d", control.id, control.value); + return true; +} + +bool venc_dev::venc_set_priority(OMX_U32 priority) { + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY; + if (priority == 0) + control.value = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_ENABLE; + else + control.value = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE; + + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_%s", + priority == 0 ? "ENABLE" : "DISABLE"); + return false; + } + return true; +} + +bool venc_dev::venc_set_operatingrate(OMX_U32 rate) { + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE; + control.value = rate; + + DEBUG_PRINT_LOW("venc_set_operating_rate: %d fps", rate >> 16); + DEBUG_PRINT_LOW("Calling IOCTL set control for id=%d, val=%d", control.id, control.value); + + if(ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + hw_overload = errno == EBUSY; + DEBUG_PRINT_ERROR("Failed to set operating rate %d fps (%s)", + rate >> 16, hw_overload ? "HW overload" : strerror(errno)); + return false; + } + operating_rate = rate; + DEBUG_PRINT_LOW("Operating Rate Set = %d fps", rate >> 16); + return true; +} + +bool venc_dev::venc_set_roi_qp_info(OMX_QTI_VIDEO_CONFIG_ROIINFO *roiInfo) { + if (!roiInfo) { + DEBUG_PRINT_ERROR("No ROI info present"); + return false; + } + if (m_sVenc_cfg.codectype != V4L2_PIX_FMT_H264 && + m_sVenc_cfg.codectype != V4L2_PIX_FMT_HEVC) { + DEBUG_PRINT_ERROR("OMX_QTIIndexConfigVideoRoiInfo is not supported for %d codec", (OMX_U32) m_sVenc_cfg.codectype); + return false; + } + +#ifdef _PQ_ + DEBUG_PRINT_HIGH("ROI QP info received"); + pthread_mutex_lock(&m_pq.lock); + roi.info = *roiInfo; + roi.dirty = true; + pthread_mutex_unlock(&m_pq.lock); +#else // _PQ_ + roi.info = *roiInfo; + roi.dirty = true; +#endif // _PQ_ + + return true; +} + +bool venc_dev::venc_set_blur_resolution(OMX_QTI_VIDEO_CONFIG_BLURINFO *blurInfo) +{ + struct v4l2_ext_control ctrl[2]; + struct v4l2_ext_controls controls; + + int blur_width = 0, blur_height = 0; + + switch (blurInfo->eTargetResol) { + case BLUR_RESOL_DISABLED: + blur_width = 0; + blur_height = 0; + break; + case BLUR_RESOL_240: + blur_width = 426; + blur_height = 240; + break; + case BLUR_RESOL_480: + blur_width = 854; + blur_height = 480; + break; + case BLUR_RESOL_720: + blur_width = 1280; + blur_height = 720; + break; + case BLUR_RESOL_1080: + blur_width = 1920; + blur_height = 1080; + break; + default: + DEBUG_PRINT_ERROR("Blur resolution not recognized"); + return false; + } + + ctrl[0].id = V4L2_CID_MPEG_VIDC_VIDEO_BLUR_WIDTH; + ctrl[0].value = blur_width; + + ctrl[1].id = V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT; + ctrl[1].value = blur_height; + + controls.count = 2; + controls.ctrl_class = V4L2_CTRL_CLASS_MPEG; + controls.controls = ctrl; + + if(ioctl(m_nDriver_fd, VIDIOC_S_EXT_CTRLS, &controls)) { + DEBUG_PRINT_ERROR("Failed to set blur resoltion"); + return false; + } + DEBUG_PRINT_LOW("Blur resolution set = %d x %d", blur_width, blur_height); + return true; + +} + +bool venc_dev::venc_h264_transform_8x8(OMX_BOOL enable) +{ + struct v4l2_control control; + + control.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8; + if (enable) + control.value = V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_ENABLE; + else + control.value = V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_DISABLE; + + DEBUG_PRINT_LOW("Set h264_transform_8x8 mode: %d", control.value); + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("set control: H264 transform 8x8 failed"); + return false; + } + + return true; +} + +bool venc_dev::venc_get_temporal_layer_caps(OMX_U32 *nMaxLayers, + OMX_U32 *nMaxBLayers) { + + // no B-layers for all cases + temporal_layers_config.nMaxBLayers = 0; + temporal_layers_config.nMaxLayers = 1; + + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264 + || m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) { + temporal_layers_config.nMaxLayers = MAX_HYB_HIERP_LAYERS; // TODO: get this count from codec + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) { + temporal_layers_config.nMaxLayers = 4; // TODO: get this count from codec + } + + *nMaxLayers = temporal_layers_config.nMaxLayers; + *nMaxBLayers = temporal_layers_config.nMaxBLayers; + return true; +} + +OMX_ERRORTYPE venc_dev::venc_set_temporal_layers( + OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE *pTemporalParams) { + + if (!(m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264 + || m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC + || m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8)) { + DEBUG_PRINT_ERROR("Temporal layers not supported for %s", codec_as_string(m_sVenc_cfg.codectype)); + return OMX_ErrorUnsupportedSetting; + } + + if (pTemporalParams->ePattern == OMX_VIDEO_AndroidTemporalLayeringPatternNone && + (pTemporalParams->nBLayerCountActual != 0 || + pTemporalParams->nPLayerCountActual != 1)) { + return OMX_ErrorBadParameter; + } else if (pTemporalParams->ePattern != OMX_VIDEO_AndroidTemporalLayeringPatternAndroid || + pTemporalParams->nPLayerCountActual < 1) { + return OMX_ErrorBadParameter; + } + + if (pTemporalParams->nBLayerCountActual > temporal_layers_config.nMaxBLayers) { + DEBUG_PRINT_ERROR("TemporalLayer: Requested B-layers(%u) exceeds supported max(%u)", + pTemporalParams->nBLayerCountActual, temporal_layers_config.nMaxBLayers); + return OMX_ErrorBadParameter; + } else if (pTemporalParams->nPLayerCountActual > + temporal_layers_config.nMaxLayers - pTemporalParams->nBLayerCountActual) { + DEBUG_PRINT_ERROR("TemporalLayer: Requested layers(%u) exceeds supported max(%u)", + pTemporalParams->nPLayerCountActual + pTemporalParams->nBLayerCountActual, + temporal_layers_config.nMaxLayers); + return OMX_ErrorBadParameter; + } + + // For AVC, if B-layer has not been configured and RC mode is VBR (camcorder), + // use hybrid-HP for best results + bool isAvc = m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264; + bool isVBR = rate_ctrl.rcmode == RC_VBR_CFR || rate_ctrl.rcmode == RC_VBR_VFR; + bool bUseHybridMode = isAvc && pTemporalParams->nBLayerCountActual == 0 && isVBR; + + // If there are more than 3 layers configured for AVC, normal HP will not work. force hybrid + bUseHybridMode |= (isAvc && pTemporalParams->nPLayerCountActual > MAX_AVC_HP_LAYERS); + + DEBUG_PRINT_LOW("TemporalLayer: RC-mode = %ld : %s hybrid-HP", + rate_ctrl.rcmode, bUseHybridMode ? "enable" : "disable"); + + if (bUseHybridMode && + !venc_validate_hybridhp_params(pTemporalParams->nPLayerCountActual, + pTemporalParams->nBLayerCountActual, + 0 /* LTR count */, (int) HIER_P_HYBRID)) { + bUseHybridMode = false; + DEBUG_PRINT_ERROR("Failed to validate Hybrid HP. Will try fallback to normal HP"); + } + + if (intra_period.num_bframes) { + DEBUG_PRINT_ERROR("TemporalLayer: B frames are not supported with layers"); + return OMX_ErrorUnsupportedSetting; + } + + if (!venc_set_intra_period(intra_period.num_pframes, intra_period.num_bframes)) { + DEBUG_PRINT_ERROR("TemporalLayer : Failed to set Intra-period nP(%lu)/pB(%lu)", + intra_period.num_pframes, intra_period.num_bframes); + return OMX_ErrorUnsupportedSetting; + } + + struct v4l2_control control; + // Num enhancements layers does not include the base-layer + control.value = pTemporalParams->nPLayerCountActual - 1; + + if (bUseHybridMode) { + DEBUG_PRINT_LOW("TemporalLayer: Try enabling hybrid HP with %u layers", control.value); + control.id = V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + bUseHybridMode = false; + DEBUG_PRINT_ERROR("Failed to set hybrid HP"); + } else { + // Disable normal HP if Hybrid mode is being enabled + control.id = V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS; + control.value = 0; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set max HP layers to %u", control.value); + return OMX_ErrorUnsupportedSetting; + } + control.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS; + control.value = 0; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set HP layers to %u", control.value); + return OMX_ErrorUnsupportedSetting; + } + } + } + + if (!bUseHybridMode) { + + // in case of normal HP, avc encoder cannot support more than MAX_AVC_HP_LAYERS + if (isAvc && pTemporalParams->nPLayerCountActual > MAX_AVC_HP_LAYERS) { + DEBUG_PRINT_ERROR("AVC supports only up to %d layers", MAX_AVC_HP_LAYERS); + return OMX_ErrorUnsupportedSetting; + } + + DEBUG_PRINT_LOW("TemporalLayer: Try enabling HP with %u layers", control.value); + control.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set hybrid hierp/hierp"); + return OMX_ErrorUnsupportedSetting; + } + + // configure max layers for a session.. Okay to use current num-layers as max + // since we do not plan to support dynamic changes to number of layers + control.id = V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS; + control.value = pTemporalParams->nPLayerCountActual - 1; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to set max HP layers to %u", control.value); + return OMX_ErrorUnsupportedSetting; + + } else if (temporal_layers_config.hier_mode == HIER_P_HYBRID) { + // Disable hybrid mode if it was enabled already + DEBUG_PRINT_LOW("TemporalLayer: disable hybrid HP (normal-HP preferred)"); + control.id = V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE; + control.value = 0; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to disable hybrid HP !"); + return OMX_ErrorUnsupportedSetting; + } + } + } + + // SVC-NALs to indicate layer-id in case of H264 needs explicit enablement.. + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + DEBUG_PRINT_LOW("TemporalLayer: Enable H264_SVC_NAL"); + control.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC; + control.value = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED; + if (ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control)) { + DEBUG_PRINT_ERROR("Failed to enable SVC_NAL"); + return OMX_ErrorUnsupportedSetting; + } + } + + temporal_layers_config.hier_mode = bUseHybridMode ? HIER_P_HYBRID : HIER_P; + temporal_layers_config.nPLayers = pTemporalParams->nPLayerCountActual; + temporal_layers_config.nBLayers = 0; + + temporal_layers_config.bIsBitrateRatioValid = OMX_FALSE; + if (pTemporalParams->bBitrateRatiosSpecified == OMX_FALSE) { + DEBUG_PRINT_LOW("TemporalLayer: layerwise bitrate ratio not specified. Will use cumulative.."); + return OMX_ErrorNone; + } + DEBUG_PRINT_LOW("TemporalLayer: layerwise bitrate ratio specified"); + + OMX_U32 layerBitrates[OMX_VIDEO_MAX_HP_LAYERS] = {0}, + numLayers = pTemporalParams->nPLayerCountActual + pTemporalParams->nBLayerCountActual; + + OMX_U32 i = 0; + for (; i < numLayers; ++i) { + OMX_U32 previousLayersAccumulatedBitrateRatio = i == 0 ? 0 : pTemporalParams->nBitrateRatios[i-1]; + OMX_U32 currentLayerBitrateRatio = pTemporalParams->nBitrateRatios[i] - previousLayersAccumulatedBitrateRatio; + if (previousLayersAccumulatedBitrateRatio > pTemporalParams->nBitrateRatios[i]) { + DEBUG_PRINT_ERROR("invalid bitrate ratio for layer %d.. Will fallback to cumulative", i); + return OMX_ErrorBadParameter; + } else { + layerBitrates[i] = (currentLayerBitrateRatio * bitrate.target_bitrate) / 100; + temporal_layers_config.nTemporalLayerBitrateRatio[i] = pTemporalParams->nBitrateRatios[i]; + temporal_layers_config.nTemporalLayerBitrateFraction[i] = currentLayerBitrateRatio; + DEBUG_PRINT_LOW("TemporalLayer: layer[%u] ratio=%u%% bitrate=%u(of %ld)", + i, currentLayerBitrateRatio, layerBitrates[i], bitrate.target_bitrate); + } + } + + temporal_layers_config.bIsBitrateRatioValid = OMX_TRUE; + + // Setting layerwise bitrate makes sense only if target bitrate is configured, else defer until later.. + if (bitrate.target_bitrate > 0) { + if (!venc_set_layer_bitrates((OMX_U32 *)layerBitrates, numLayers)) { + return OMX_ErrorUnsupportedSetting; + } + } else { + DEBUG_PRINT_HIGH("Defer setting layerwise bitrate since target bitrate is not yet set"); + } + + return OMX_ErrorNone; +} + +OMX_ERRORTYPE venc_dev::venc_set_temporal_layers_internal() { + OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE pTemporalParams; + memset(&pTemporalParams, 0x0, sizeof(OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE)); + + if (!temporal_layers_config.nPLayers) { + return OMX_ErrorNone; + } + pTemporalParams.eSupportedPatterns = OMX_VIDEO_AndroidTemporalLayeringPatternAndroid; + pTemporalParams.nLayerCountMax = temporal_layers_config.nMaxLayers; + pTemporalParams.nBLayerCountMax = temporal_layers_config.nMaxBLayers; + pTemporalParams.ePattern = OMX_VIDEO_AndroidTemporalLayeringPatternAndroid; + pTemporalParams.nPLayerCountActual = temporal_layers_config.nPLayers; + pTemporalParams.nBLayerCountActual = temporal_layers_config.nBLayers; + pTemporalParams.bBitrateRatiosSpecified = temporal_layers_config.bIsBitrateRatioValid; + if (temporal_layers_config.bIsBitrateRatioValid == OMX_TRUE) { + for (OMX_U32 i = 0; i < temporal_layers_config.nPLayers + temporal_layers_config.nBLayers; ++i) { + pTemporalParams.nBitrateRatios[i] = + temporal_layers_config.nTemporalLayerBitrateRatio[i]; + } + } + return venc_set_temporal_layers(&pTemporalParams); +} + +bool venc_dev::venc_get_profile_level(OMX_U32 *eProfile,OMX_U32 *eLevel) +{ + bool status = true; + + if (eProfile == NULL || eLevel == NULL) { + return false; + } + + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_MPEG4) { + switch (codec_profile.profile) { + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE: + *eProfile = OMX_VIDEO_MPEG4ProfileSimple; + break; + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE: + *eProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple; + break; + default: + *eProfile = OMX_VIDEO_MPEG4ProfileMax; + status = false; + break; + } + + if (!status) { + return status; + } + + //profile level + switch (profile_level.level) { + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0: + *eLevel = OMX_VIDEO_MPEG4Level0; + break; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B: + *eLevel = OMX_VIDEO_MPEG4Level0b; + break; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1: + *eLevel = OMX_VIDEO_MPEG4Level1; + break; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2: + *eLevel = OMX_VIDEO_MPEG4Level2; + break; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3: + *eLevel = OMX_VIDEO_MPEG4Level3; + break; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4: + *eLevel = OMX_VIDEO_MPEG4Level4; + break; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5: + *eLevel = OMX_VIDEO_MPEG4Level5; + break; + default: + *eLevel = OMX_VIDEO_MPEG4LevelMax; + status = false; + break; + } + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H263) { + if (codec_profile.profile == VEN_PROFILE_H263_BASELINE) { + *eProfile = OMX_VIDEO_H263ProfileBaseline; + } else { + *eProfile = OMX_VIDEO_H263ProfileMax; + return false; + } + + switch (profile_level.level) { + case VEN_LEVEL_H263_10: + *eLevel = OMX_VIDEO_H263Level10; + break; + case VEN_LEVEL_H263_20: + *eLevel = OMX_VIDEO_H263Level20; + break; + case VEN_LEVEL_H263_30: + *eLevel = OMX_VIDEO_H263Level30; + break; + case VEN_LEVEL_H263_40: + *eLevel = OMX_VIDEO_H263Level40; + break; + case VEN_LEVEL_H263_45: + *eLevel = OMX_VIDEO_H263Level45; + break; + case VEN_LEVEL_H263_50: + *eLevel = OMX_VIDEO_H263Level50; + break; + case VEN_LEVEL_H263_60: + *eLevel = OMX_VIDEO_H263Level60; + break; + case VEN_LEVEL_H263_70: + *eLevel = OMX_VIDEO_H263Level70; + break; + default: + *eLevel = OMX_VIDEO_H263LevelMax; + status = false; + break; + } + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + switch (codec_profile.profile) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + *eProfile = OMX_VIDEO_AVCProfileBaseline; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + *eProfile = QOMX_VIDEO_AVCProfileConstrainedBaseline; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH: + *eProfile = QOMX_VIDEO_AVCProfileConstrainedHigh; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + *eProfile = OMX_VIDEO_AVCProfileMain; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + *eProfile = OMX_VIDEO_AVCProfileHigh; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: + *eProfile = OMX_VIDEO_AVCProfileExtended; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: + *eProfile = OMX_VIDEO_AVCProfileHigh10; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: + *eProfile = OMX_VIDEO_AVCProfileHigh422; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: + *eProfile = OMX_VIDEO_AVCProfileHigh444; + break; + default: + *eProfile = OMX_VIDEO_AVCProfileMax; + status = false; + break; + } + + if (!status) { + return status; + } + + switch (profile_level.level) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + *eLevel = OMX_VIDEO_AVCLevel1; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + *eLevel = OMX_VIDEO_AVCLevel1b; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + *eLevel = OMX_VIDEO_AVCLevel11; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + *eLevel = OMX_VIDEO_AVCLevel12; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + *eLevel = OMX_VIDEO_AVCLevel13; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + *eLevel = OMX_VIDEO_AVCLevel2; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + *eLevel = OMX_VIDEO_AVCLevel21; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + *eLevel = OMX_VIDEO_AVCLevel22; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + *eLevel = OMX_VIDEO_AVCLevel3; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + *eLevel = OMX_VIDEO_AVCLevel31; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + *eLevel = OMX_VIDEO_AVCLevel32; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + *eLevel = OMX_VIDEO_AVCLevel4; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + *eLevel = OMX_VIDEO_AVCLevel41; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + *eLevel = OMX_VIDEO_AVCLevel42; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + *eLevel = OMX_VIDEO_AVCLevel5; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + *eLevel = OMX_VIDEO_AVCLevel51; + break; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_2: + *eLevel = OMX_VIDEO_AVCLevel52; + break; + default : + *eLevel = OMX_VIDEO_AVCLevelMax; + status = false; + break; + } + } + else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) { + switch (codec_profile.profile) { + case V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED: + *eProfile = OMX_VIDEO_VP8ProfileMain; + break; + default: + *eProfile = OMX_VIDEO_VP8ProfileMax; + status = false; + break; + } + if (!status) { + return status; + } + + switch (profile_level.level) { + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0: + *eLevel = OMX_VIDEO_VP8Level_Version0; + break; + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1: + *eLevel = OMX_VIDEO_VP8Level_Version1; + break; + default: + *eLevel = OMX_VIDEO_VP8LevelMax; + status = false; + break; + } + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) { + switch (codec_profile.profile) { + case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN: + *eProfile = OMX_VIDEO_HEVCProfileMain; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10: + *eProfile = OMX_VIDEO_HEVCProfileMain10; + break; + default: + *eProfile = OMX_VIDEO_HEVCProfileMax; + status = false; + break; + } + if (!status) { + return status; + } + + switch (profile_level.level) { + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1: + *eLevel = OMX_VIDEO_HEVCMainTierLevel1; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1: + *eLevel = OMX_VIDEO_HEVCHighTierLevel1; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2: + *eLevel = OMX_VIDEO_HEVCMainTierLevel2; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2: + *eLevel = OMX_VIDEO_HEVCHighTierLevel2; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1: + *eLevel = OMX_VIDEO_HEVCMainTierLevel21; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1: + *eLevel = OMX_VIDEO_HEVCHighTierLevel21; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3: + *eLevel = OMX_VIDEO_HEVCMainTierLevel3; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3: + *eLevel = OMX_VIDEO_HEVCHighTierLevel3; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1: + *eLevel = OMX_VIDEO_HEVCMainTierLevel31; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1: + *eLevel = OMX_VIDEO_HEVCHighTierLevel31; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4: + *eLevel = OMX_VIDEO_HEVCMainTierLevel4; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4: + *eLevel = OMX_VIDEO_HEVCHighTierLevel4; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1: + *eLevel = OMX_VIDEO_HEVCMainTierLevel41; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1: + *eLevel = OMX_VIDEO_HEVCHighTierLevel41; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5: + *eLevel = OMX_VIDEO_HEVCMainTierLevel5; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5: + *eLevel = OMX_VIDEO_HEVCHighTierLevel5; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1: + *eLevel = OMX_VIDEO_HEVCMainTierLevel51; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1: + *eLevel = OMX_VIDEO_HEVCHighTierLevel51; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2: + *eLevel = OMX_VIDEO_HEVCMainTierLevel52; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2: + *eLevel = OMX_VIDEO_HEVCHighTierLevel52; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6: + *eLevel = OMX_VIDEO_HEVCMainTierLevel6; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6: + *eLevel = OMX_VIDEO_HEVCHighTierLevel6; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1: + *eLevel = OMX_VIDEO_HEVCMainTierLevel61; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1: + *eLevel = OMX_VIDEO_HEVCHighTierLevel61; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2: + *eLevel = OMX_VIDEO_HEVCMainTierLevel62; + break; + default: + *eLevel = OMX_VIDEO_HEVCLevelMax; + status = false; + break; + } + } + + return status; +} + +bool venc_dev::venc_validate_profile_level(OMX_U32 *eProfile, OMX_U32 *eLevel) +{ + OMX_U32 new_level = 0; + unsigned const int *profile_tbl = NULL; + OMX_U32 mb_per_frame, mb_per_sec; + bool profile_level_found = false; + + if (vqzip_sei_info.enabled) { + DEBUG_PRINT_HIGH("VQZIP is enabled. Profile and Level set by client. Skipping validation"); + return true; + } + + DEBUG_PRINT_LOW("Init profile table for respective codec"); + + //validate the ht,width,fps,bitrate and set the appropriate profile and level + if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_MPEG4) { + if (*eProfile == 0) { + if (!m_profile_set) { + *eProfile = OMX_VIDEO_MPEG4ProfileSimple; + } else { + switch (codec_profile.profile) { + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE: + *eProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple; + break; + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE: + *eProfile = OMX_VIDEO_MPEG4ProfileSimple; + break; + default: + DEBUG_PRINT_LOW("%s(): Unknown Error", __func__); + return false; + } + } + } + + if (*eLevel == 0 && !m_level_set) { + *eLevel = OMX_VIDEO_MPEG4LevelMax; + } + + if (*eProfile == OMX_VIDEO_MPEG4ProfileSimple) { + profile_tbl = (unsigned int const *)mpeg4_profile_level_table; + } else if (*eProfile == OMX_VIDEO_MPEG4ProfileAdvancedSimple) { + profile_tbl = (unsigned int const *) + (&mpeg4_profile_level_table[MPEG4_ASP_START]); + } else { + DEBUG_PRINT_LOW("Unsupported MPEG4 profile type %u", (unsigned int)*eProfile); + return false; + } + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) { + if (*eProfile == 0) { + if (!m_profile_set) { + *eProfile = OMX_VIDEO_AVCProfileBaseline; + } else { + switch (codec_profile.profile) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + *eProfile = OMX_VIDEO_AVCProfileBaseline; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + *eProfile = QOMX_VIDEO_AVCProfileConstrainedBaseline; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH: + *eProfile = QOMX_VIDEO_AVCProfileConstrainedHigh; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + *eProfile = OMX_VIDEO_AVCProfileMain; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: + *eProfile = OMX_VIDEO_AVCProfileExtended; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + *eProfile = OMX_VIDEO_AVCProfileHigh; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: + *eProfile = OMX_VIDEO_AVCProfileHigh10; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: + *eProfile = OMX_VIDEO_AVCProfileHigh422; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: + *eProfile = OMX_VIDEO_AVCProfileHigh444; + break; + default: + DEBUG_PRINT_LOW("%s(): Unknown Error", __func__); + return false; + } + } + } + + if (*eLevel == 0 && !m_level_set) { + *eLevel = OMX_VIDEO_AVCLevelMax; + } + + profile_tbl = (unsigned int const *)h264_profile_level_table; + if ((*eProfile != OMX_VIDEO_AVCProfileBaseline) && + (*eProfile != QOMX_VIDEO_AVCProfileConstrainedBaseline) && + (*eProfile != OMX_VIDEO_AVCProfileHigh) && + (*eProfile != QOMX_VIDEO_AVCProfileConstrainedHigh) && + (*eProfile != OMX_VIDEO_AVCProfileMain)) { + DEBUG_PRINT_LOW("Unsupported AVC profile type %u", (unsigned int)*eProfile); + return false; + } + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H263) { + if (*eProfile == 0) { + if (!m_profile_set) { + *eProfile = OMX_VIDEO_H263ProfileBaseline; + } else { + switch (codec_profile.profile) { + case VEN_PROFILE_H263_BASELINE: + *eProfile = OMX_VIDEO_H263ProfileBaseline; + break; + default: + DEBUG_PRINT_LOW("%s(): Unknown Error", __func__); + return false; + } + } + } + + if (*eLevel == 0 && !m_level_set) { + *eLevel = OMX_VIDEO_H263LevelMax; + } + + if (*eProfile == OMX_VIDEO_H263ProfileBaseline) { + profile_tbl = (unsigned int const *)h263_profile_level_table; + } else { + DEBUG_PRINT_LOW("Unsupported H.263 profile type %u", (unsigned int)*eProfile); + return false; + } + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) { + if (*eProfile == 0) { + *eProfile = OMX_VIDEO_VP8ProfileMain; + } else { + switch (codec_profile.profile) { + case V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED: + *eProfile = OMX_VIDEO_VP8ProfileMain; + break; + default: + DEBUG_PRINT_ERROR("%s(): Unknown VP8 profile", __func__); + return false; + } + } + if (*eLevel == 0) { + switch (profile_level.level) { + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0: + *eLevel = OMX_VIDEO_VP8Level_Version0; + break; + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1: + *eLevel = OMX_VIDEO_VP8Level_Version1; + break; + default: + DEBUG_PRINT_ERROR("%s(): Unknown VP8 level", __func__); + return false; + } + } + return true; + } else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) { + if (*eProfile == 0) { + if (!m_profile_set) { + *eProfile = OMX_VIDEO_HEVCProfileMain; + } else { + switch (codec_profile.profile) { + case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN: + *eProfile = OMX_VIDEO_HEVCProfileMain; + break; + case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10: + *eProfile = OMX_VIDEO_HEVCProfileMain10; + break; + default: + DEBUG_PRINT_ERROR("%s(): Unknown Error", __func__); + return false; + } + } + } + + if (*eLevel == 0 && !m_level_set) { + *eLevel = OMX_VIDEO_HEVCLevelMax; + } + + profile_tbl = (unsigned int const *)hevc_profile_level_table; + if ((*eProfile != OMX_VIDEO_HEVCProfileMain) && + (*eProfile != OMX_VIDEO_HEVCProfileMain10)) { + DEBUG_PRINT_ERROR("Unsupported HEVC profile type %u", (unsigned int)*eProfile); + return false; + } + } else { + DEBUG_PRINT_ERROR("Invalid codec type"); + return false; + } + + mb_per_frame = ((m_sVenc_cfg.dvs_height + 15) >> 4)* + ((m_sVenc_cfg.dvs_width + 15)>> 4); + + if ((mb_per_frame >= 3600) && (m_sVenc_cfg.codectype == (unsigned long) V4L2_PIX_FMT_MPEG4)) { + if (codec_profile.profile == (unsigned long) V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE) + profile_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5; + + if (codec_profile.profile == (unsigned long) V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE) + profile_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5; + + { + new_level = profile_level.level; + return true; + } + } + + if (rate_ctrl.rcmode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF) { + *eLevel = rc_off_level; //No level calculation for RC_OFF + profile_level_found = true; + return true; + } + + mb_per_sec = mb_per_frame * m_sVenc_cfg.fps_num / m_sVenc_cfg.fps_den; + + bool h264, ltr, hlayers; + unsigned int hybridp = 0, maxDpb = profile_tbl[5] / mb_per_frame; + h264 = m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264; + ltr = ltrinfo.enabled && ((ltrinfo.count + 2) <= MIN((unsigned int) (profile_tbl[5] / mb_per_frame), MAXDPB)); + hlayers = hier_layers.numlayers && hier_layers.hier_mode == HIER_P && + ((intra_period.num_bframes + ltrinfo.count + hier_layers.numlayers + 1) <= (unsigned int) (profile_tbl[5] / profile_tbl[0])); + + /* Hybrid HP reference buffers: + layers = 1, 2 need 1 reference buffer + layers = 3, 4 need 2 reference buffers + layers = 5, 6 need 3 reference buffers + */ + + if(hier_layers.hier_mode == HIER_P_HYBRID) + hybridp = MIN(MAX(maxDpb, ((hier_layers.numlayers + 1) / 2)), 16); + + do { + if (mb_per_frame <= (unsigned int)profile_tbl[0]) { + if (mb_per_sec <= (unsigned int)profile_tbl[1]) { + if (m_sVenc_cfg.targetbitrate <= (unsigned int)profile_tbl[2]) { + if (h264 && (ltr || hlayers || hybridp)) { + // Update profile and level to adapt to the LTR and Hier-p/Hybrid-HP settings + new_level = (int)profile_tbl[3]; + profile_level_found = true; + DEBUG_PRINT_LOW("Appropriate profile/level for LTR count: %u OR Hier-p: %u is %u/%u, maxDPB: %u", + ltrinfo.count, hier_layers.numlayers, (int)*eProfile, (int)new_level, + MIN((unsigned int) (profile_tbl[5] / mb_per_frame), MAXDPB)); + break; + } else { + new_level = (int)profile_tbl[3]; + profile_level_found = true; + DEBUG_PRINT_LOW("Appropriate profile/level found %u/%u", (int) *eProfile, (int) new_level); + break; + } + } + } + } + profile_tbl = profile_tbl + MAX_PROFILE_PARAMS; + } while (profile_tbl[0] != 0); + + if (profile_level_found != true) { + DEBUG_PRINT_LOW("ERROR: Unsupported profile/level"); + return false; + } + + if ((*eLevel == OMX_VIDEO_MPEG4LevelMax) || (*eLevel == OMX_VIDEO_AVCLevelMax) + || (*eLevel == OMX_VIDEO_H263LevelMax) || (*eLevel == OMX_VIDEO_VP8ProfileMax) + || (*eLevel == OMX_VIDEO_HEVCLevelMax)) { + *eLevel = new_level; + } + + DEBUG_PRINT_LOW("%s: Returning with eProfile = %u" + "Level = %u", __func__, (unsigned int)*eProfile, (unsigned int)*eLevel); + + return true; +} +#ifdef _ANDROID_ICS_ +bool venc_dev::venc_set_meta_mode(bool mode) +{ + metadatamode = mode; + return true; +} +#endif + +bool venc_dev::venc_is_video_session_supported(unsigned long width, + unsigned long height) +{ + if ((width * height < capability.min_width * capability.min_height) || + (width * height > capability.max_width * capability.max_height)) { + DEBUG_PRINT_ERROR( + "Unsupported video resolution WxH = (%lu)x(%lu) supported range = min (%d)x(%d) - max (%d)x(%d)", + width, height, capability.min_width, capability.min_height, + capability.max_width, capability.max_height); + return false; + } + + DEBUG_PRINT_LOW("video session supported"); + return true; +} + +bool venc_dev::venc_set_batch_size(OMX_U32 batchSize) +{ + struct v4l2_control control; + int ret; + + control.id = V4L2_CID_VIDC_QBUF_MODE; + control.value = batchSize ? V4L2_VIDC_QBUF_BATCHED : V4L2_VIDC_QBUF_STANDARD; + + ret = ioctl(m_nDriver_fd, VIDIOC_S_CTRL, &control); + if (ret) { + DEBUG_PRINT_ERROR("Failed to set batching mode: %d", ret); + return false; + } + + mBatchSize = batchSize; + DEBUG_PRINT_HIGH("Using batch size of %d", mBatchSize); + return true; +} + +venc_dev::BatchInfo::BatchInfo() + : mNumPending(0) { + pthread_mutex_init(&mLock, NULL); + for (int i = 0; i < kMaxBufs; ++i) { + mBufMap[i] = kBufIDFree; + } +} + +int venc_dev::BatchInfo::registerBuffer(int bufferId) { + pthread_mutex_lock(&mLock); + int availId = 0; + for( ; availId < kMaxBufs && mBufMap[availId] != kBufIDFree; ++availId); + if (availId >= kMaxBufs) { + DEBUG_PRINT_ERROR("Failed to find free entry !"); + pthread_mutex_unlock(&mLock); + return -1; + } + mBufMap[availId] = bufferId; + mNumPending++; + pthread_mutex_unlock(&mLock); + return availId; +} + +int venc_dev::BatchInfo::retrieveBufferAt(int v4l2Id) { + pthread_mutex_lock(&mLock); + if (v4l2Id >= kMaxBufs || v4l2Id < 0) { + DEBUG_PRINT_ERROR("Batch: invalid index %d", v4l2Id); + pthread_mutex_unlock(&mLock); + return -1; + } + if (mBufMap[v4l2Id] == kBufIDFree) { + DEBUG_PRINT_ERROR("Batch: buffer @ %d was not registered !", v4l2Id); + pthread_mutex_unlock(&mLock); + return -1; + } + int bufferId = mBufMap[v4l2Id]; + mBufMap[v4l2Id] = kBufIDFree; + mNumPending--; + pthread_mutex_unlock(&mLock); + return bufferId; +} + +bool venc_dev::BatchInfo::isPending(int bufferId) { + pthread_mutex_lock(&mLock); + int existsId = 0; + for(; existsId < kMaxBufs && mBufMap[existsId] != bufferId; ++existsId); + pthread_mutex_unlock(&mLock); + return existsId < kMaxBufs; +} + +#ifdef _VQZIP_ +venc_dev::venc_dev_vqzip::venc_dev_vqzip() +{ + mLibHandle = NULL; + pthread_mutex_init(&lock, NULL); +} + +bool venc_dev::venc_dev_vqzip::init() +{ + bool status = true; + if (mLibHandle) { + DEBUG_PRINT_ERROR("VQZIP init called twice"); + status = false; + } + if (status) { + mLibHandle = dlopen("libvqzip.so", RTLD_NOW); + if (mLibHandle) { + mVQZIPInit = (vqzip_init_t) + dlsym(mLibHandle,"VQZipInit"); + mVQZIPDeInit = (vqzip_deinit_t) + dlsym(mLibHandle,"VQZipDeInit"); + mVQZIPComputeStats = (vqzip_compute_stats_t) + dlsym(mLibHandle,"VQZipComputeStats"); + if (!mVQZIPInit || !mVQZIPDeInit || !mVQZIPComputeStats) + status = false; + } else { + DEBUG_PRINT_ERROR("FATAL ERROR: could not dlopen libvqzip.so: %s", dlerror()); + status = false; + } + if (status) { + mVQZIPHandle = mVQZIPInit(); + } + } + if (!status && mLibHandle) { + dlclose(mLibHandle); + mLibHandle = NULL; + mVQZIPHandle = NULL; + mVQZIPInit = NULL; + mVQZIPDeInit = NULL; + mVQZIPComputeStats = NULL; + } + return status; +} + +int venc_dev::venc_dev_vqzip::fill_stats_data(void* pBuf, void* extraData) +{ + VQZipStatus result; + VQZipStats *pStats = (VQZipStats *)extraData; + pConfig.pSEIPayload = NULL; + unsigned long size; + + if (!pBuf || !pStats || !mVQZIPHandle) { + DEBUG_PRINT_ERROR("Invalid data passed to stats function"); + } + result = mVQZIPComputeStats(mVQZIPHandle, (void* )pBuf, &pConfig, pStats); + return result; +} + +void venc_dev::venc_dev_vqzip::deinit() +{ + if (mLibHandle) { + pthread_mutex_lock(&lock); + dlclose(mLibHandle); + mVQZIPDeInit(mVQZIPHandle); + mLibHandle = NULL; + mVQZIPHandle = NULL; + mVQZIPInit = NULL; + mVQZIPDeInit = NULL; + mVQZIPComputeStats = NULL; + pthread_mutex_unlock(&lock); + } +} + +venc_dev::venc_dev_vqzip::~venc_dev_vqzip() +{ + DEBUG_PRINT_HIGH("Destroy C2D instance"); + if (mLibHandle) { + dlclose(mLibHandle); + } + mLibHandle = NULL; + pthread_mutex_destroy(&lock); +} +#endif + +#ifdef _PQ_ +bool venc_dev::venc_check_for_pq(void) +{ + bool rc_mode_supported = false; + bool codec_supported = false; + bool resolution_supported = false; + bool frame_rate_supported = false; + bool yuv_format_supported = false; + bool is_non_secure_session = false; + bool is_pq_handle_valid = false; + bool is_non_vpe_session = false; + bool enable = false; + + codec_supported = m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264; + + rc_mode_supported = (rate_ctrl.rcmode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR) || + (rate_ctrl.rcmode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR) || + (rate_ctrl.rcmode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR); + + resolution_supported = m_sVenc_cfg.input_height * m_sVenc_cfg.input_width <= + m_pq.caps.max_width * m_pq.caps.max_height; + + frame_rate_supported = + (m_sVenc_cfg.fps_num / m_sVenc_cfg.fps_den) <= + (m_pq.caps.max_mb_per_sec / ((m_sVenc_cfg.input_height * m_sVenc_cfg.input_width) / 256)); + + yuv_format_supported = ((m_sVenc_cfg.inputformat == V4L2_PIX_FMT_NV12 && (m_pq.caps.color_formats & BIT(COLOR_FMT_NV12))) + || (m_sVenc_cfg.inputformat == V4L2_PIX_FMT_NV21 && (m_pq.caps.color_formats & BIT(COLOR_FMT_NV21))) + || (m_sVenc_cfg.inputformat == V4L2_PIX_FMT_NV12_UBWC && (m_pq.caps.color_formats & BIT(COLOR_FMT_NV12_UBWC)))); + + yuv_format_supported |= m_pq.is_YUV_format_uncertain; // When YUV format is uncertain, Let this condition pass + + is_non_secure_session = !venc_handle->is_secure_session(); + + is_non_vpe_session = (m_sVenc_cfg.input_height == m_sVenc_cfg.dvs_height && m_sVenc_cfg.input_width == m_sVenc_cfg.dvs_width); + + is_pq_handle_valid = m_pq.is_pq_handle_valid(); + + /* Add future PQ conditions here */ + + enable = (!m_pq.is_pq_force_disable && + codec_supported && + rc_mode_supported && + resolution_supported && + frame_rate_supported && + yuv_format_supported && + is_non_secure_session && + is_non_vpe_session && + is_pq_handle_valid); + + DEBUG_PRINT_HIGH("PQ Condition : Force disable = %d Codec = %d, RC = %d, RES = %d, FPS = %d, YUV = %d, Non - Secure = %d, PQ lib = %d Non - VPE = %d PQ enable = %d", + m_pq.is_pq_force_disable, codec_supported, rc_mode_supported, resolution_supported, frame_rate_supported, yuv_format_supported, + is_non_secure_session, is_pq_handle_valid, is_non_vpe_session, enable); + + m_pq.is_pq_enabled = enable; + + return enable; +} + +void venc_dev::venc_configure_pq() +{ + venc_set_extradata(OMX_ExtraDataEncoderOverrideQPInfo, (OMX_BOOL)true); + extradata |= true; + m_pq.configure(m_sVenc_cfg.input_width, m_sVenc_cfg.input_height); + return; +} + +void venc_dev::venc_try_enable_pq(void) +{ + if(venc_check_for_pq()) { + venc_configure_pq(); + } +} + +venc_dev::venc_dev_pq::venc_dev_pq() +{ + mLibHandle = NULL; + mPQHandle = NULL; + mPQInit = NULL; + mPQDeInit = NULL; + mPQGetCaps = NULL; + mPQConfigure = NULL; + mPQComputeStats = NULL; + configured_format = 0; + is_pq_force_disable = 0; + pthread_mutex_init(&lock, NULL); +} + +bool venc_dev::venc_dev_pq::init(unsigned long format) +{ + bool status = true; + enum color_compression_format yuv_format; + + if (mLibHandle) { + DEBUG_PRINT_ERROR("PQ init called twice"); + status = false; + } + + switch (format) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + yuv_format = color_compression_format::LINEAR_NV12; + break; + case V4L2_PIX_FMT_NV12_UBWC: + default: + yuv_format = color_compression_format::UBWC_NV12; + break; + } + + ATRACE_BEGIN("PQ init"); + if (status) { + mLibHandle = dlopen(YUV_STATS_LIBRARY_NAME, RTLD_NOW); + if (mLibHandle) { + mPQInit = (gpu_stats_lib_init_t) + dlsym(mLibHandle,"gpu_stats_lib_init"); + mPQDeInit = (gpu_stats_lib_deinit_t) + dlsym(mLibHandle,"gpu_stats_lib_deinit"); + mPQGetCaps = (gpu_stats_lib_get_caps_t) + dlsym(mLibHandle,"gpu_stats_lib_get_caps"); + mPQConfigure = (gpu_stats_lib_configure_t) + dlsym(mLibHandle,"gpu_stats_lib_configure"); + mPQComputeStats = (gpu_stats_lib_fill_data_t) + dlsym(mLibHandle,"gpu_stats_lib_fill_data"); + if (!mPQInit || !mPQDeInit || !mPQGetCaps || !mPQConfigure || !mPQComputeStats) + status = false; + } else { + DEBUG_PRINT_ERROR("FATAL ERROR: could not dlopen %s: %s", YUV_STATS_LIBRARY_NAME, dlerror()); + status = false; + } + if (status) { + mPQInit(&mPQHandle, perf_hint::NORMAL, yuv_format); + if (mPQHandle == NULL) { + DEBUG_PRINT_ERROR("Failed to get handle for PQ Library"); + status = false; + } else { + DEBUG_PRINT_HIGH("GPU PQ lib initialized successfully"); + } + + } + } + ATRACE_END(); + + if (!status && mLibHandle) { + if (mLibHandle) + dlclose(mLibHandle); + mLibHandle = NULL; + mPQHandle = NULL; + mPQInit = NULL; + mPQDeInit = NULL; + mPQGetCaps = NULL; + mPQConfigure = NULL; + mPQComputeStats = NULL; + } + memset(&pConfig, 0, sizeof(gpu_stats_lib_input_config)); + memset(&roi_extradata_info, 0, sizeof(extradata_buffer_info)); + roi_extradata_info.size = 16 * 1024; // Max size considering 4k + roi_extradata_info.buffer_size = 16 * 1024; // Max size considering 4k + roi_extradata_info.port_index = OUTPUT_PORT; + is_YUV_format_uncertain = false; + configured_format = format; + + return status; +} + +void venc_dev::venc_dev_pq::deinit() +{ + if (mLibHandle) { + mPQDeInit(mPQHandle); + dlclose(mLibHandle); + mPQHandle = NULL; + mLibHandle = NULL; + mPQInit = NULL; + mPQDeInit = NULL; + mPQGetCaps = NULL; + mPQConfigure = NULL; + mPQComputeStats = NULL; + configured_format = 0; + } +} + +bool venc_dev::venc_dev_pq::reinit(unsigned long format) +{ + bool status = false; + + if ((configured_format != format) && (is_color_format_supported(format))) { + DEBUG_PRINT_HIGH("New format (%lu) is different from configure format (%lu);" + " reinitializing PQ lib", format, configured_format); + deinit(); + status = init(format); + } else { + // ignore if new format is same as configured + } + + return status; +} + +void venc_dev::venc_dev_pq::get_caps() +{ + memset(&caps, 0, sizeof(gpu_stats_lib_caps_t)); + if (mPQHandle) + mPQGetCaps(mPQHandle, &caps); + DEBUG_PRINT_HIGH("GPU lib stats caps max (w,h) = (%u, %u)",caps.max_width, caps.max_height); + DEBUG_PRINT_HIGH("GPU lib stats caps max mb per sec = %u",caps.max_mb_per_sec); + DEBUG_PRINT_HIGH("GPU lib stats caps color_format = %u",caps.color_formats); +} + +bool venc_dev::venc_dev_pq::is_color_format_supported(unsigned long format) +{ + bool support = false; + int color_format = -1; + + switch (format) { + case V4L2_PIX_FMT_NV12: + color_format = COLOR_FMT_NV12; + break; + case V4L2_PIX_FMT_NV21: + color_format = COLOR_FMT_NV21; + break; + case V4L2_PIX_FMT_NV12_UBWC: + color_format = COLOR_FMT_NV12_UBWC; + break; + case V4L2_PIX_FMT_RGB32: + color_format = COLOR_FMT_RGBA8888; + break; + case V4L2_PIX_FMT_RGBA8888_UBWC: + color_format = COLOR_FMT_RGBA8888_UBWC; + break; + default: + color_format = -1; + break; + } + + if (color_format >= 0) { + support = (caps.color_formats & BIT(color_format)) ? true : false; + } + + if (support == true) + DEBUG_PRINT_HIGH("GPU lib supports this format %lu",format); + else + DEBUG_PRINT_HIGH("GPU lib doesn't support this format %lu",format); + + return support; +} + +int venc_dev::venc_dev_pq::configure(unsigned long width, unsigned long height) +{ + if (mPQHandle) { + pConfig.algo = ADAPTIVE_QP; + pConfig.height = height; + pConfig.width = width; + pConfig.mb_height = 16; + pConfig.mb_width = 16; + pConfig.a_qp.pq_enabled = true; + pConfig.stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, pConfig.width); + pConfig.a_qp.gain = 1.0397; + pConfig.a_qp.offset = 14.427; + if (pConfig.a_qp.roi_enabled) { + pConfig.a_qp.minDeltaQPlimit = -16; + pConfig.a_qp.maxDeltaQPlimit = 15; + } else { + pConfig.a_qp.minDeltaQPlimit = -6; + pConfig.a_qp.maxDeltaQPlimit = 9; + } + return mPQConfigure(mPQHandle, &pConfig); + } + return -EINVAL; +} + +bool venc_dev::venc_dev_pq::is_pq_handle_valid() +{ + return ((mPQHandle) ? true : false); +} + +int venc_dev::venc_dev_pq::fill_pq_stats(struct v4l2_buffer buf, + unsigned int data_offset) +{ + gpu_stats_lib_buffer_params_t input, output; + gpu_stats_lib_buffer_params_t roi_input; + + if (!mPQHandle || !is_pq_enabled) { + DEBUG_PRINT_HIGH("Invalid Usage : Handle = %p PQ = %d", + mPQHandle, is_pq_enabled); + return 0; + } + ATRACE_BEGIN("PQ Compute Stats"); + input.fd = buf.m.planes[0].reserved[0]; + input.data_offset = buf.m.planes[0].data_offset; + input.alloc_len = buf.m.planes[0].length; + input.filled_len = buf.m.planes[0].bytesused; + + output.fd = buf.m.planes[1].reserved[0]; + output.data_offset = buf.m.planes[1].reserved[1]; // This is current Extradata buffer + output.data_offset += data_offset; // Offset to start in current buffer + output.alloc_len = buf.m.planes[1].reserved[2]; + output.filled_len = buf.m.planes[1].bytesused; + + DEBUG_PRINT_HIGH("Input fd = %d, data_offset = %d", input.fd, input.data_offset); + DEBUG_PRINT_HIGH("Final Output fd = %d, data_offset = %d", output.fd, output.data_offset); + + if (pConfig.a_qp.roi_enabled) { + roi_input.fd = roi_extradata_info.ion.fd_ion_data.fd; + roi_input.data_offset = 0; + roi_input.alloc_len = roi_extradata_info.size; + roi_input.filled_len = 0; + DEBUG_PRINT_HIGH("ROI fd = %d, offset = %d Length = %d", roi_input.fd, roi_input.data_offset, roi_input.alloc_len); + mPQComputeStats(mPQHandle, &input, &roi_input, &output, NULL, NULL); + memset(roi_extradata_info.uaddr, 0, roi_extradata_info.size); + } else { + DEBUG_PRINT_HIGH("Output fd = %d, data_offset = %d", output.fd, output.data_offset); + mPQComputeStats(mPQHandle, &input, NULL, &output, NULL, NULL); + } + ATRACE_END(); + DEBUG_PRINT_HIGH("PQ data length = %d", output.filled_len); + return output.filled_len; +} + +venc_dev::venc_dev_pq::~venc_dev_pq() +{ + if (mLibHandle) { + mPQDeInit(mPQHandle); + dlclose(mLibHandle); + } + mLibHandle = NULL; + mPQHandle = NULL; + mPQInit = NULL; + mPQDeInit = NULL; + mPQGetCaps = NULL; + mPQConfigure = NULL; + mPQComputeStats = NULL; + pthread_mutex_destroy(&lock); +} +#endif // _PQ_ |