diff options
Diffstat (limited to 'msmcobalt/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp')
-rw-r--r-- | msmcobalt/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp | 8199 |
1 files changed, 8199 insertions, 0 deletions
diff --git a/msmcobalt/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp b/msmcobalt/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp new file mode 100644 index 0000000..b2a00cd --- /dev/null +++ b/msmcobalt/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp @@ -0,0 +1,8199 @@ +/*-------------------------------------------------------------------------- +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 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 H264_BP_START 0 +#define H264_HP_START (H264_BP_START + 18) +#define H264_MP_START (H264_BP_START + 36) +#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 +#define MAX_FPS_PQ 60 + +/* 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, level, profile, dpbmbs*/ + {99,1485,64000,OMX_VIDEO_AVCLevel1,OMX_VIDEO_AVCProfileBaseline,396}, + {99,1485,128000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileBaseline,396}, + {396,3000,192000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileBaseline,900}, + {396,6000,384000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileBaseline,2376}, + {396,11880,768000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileBaseline,2376}, + {396,11880,2000000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileBaseline,2376}, + {792,19800,4000000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileBaseline,4752}, + {1620,20250,4000000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileBaseline,8100}, + {1620,40500,10000000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileBaseline,8100}, + {3600,108000,14000000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileBaseline,18000}, + {5120,216000,20000000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileBaseline,20480}, + {8192,245760,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileBaseline,32768}, + {8192,245760,50000000,OMX_VIDEO_AVCLevel41,OMX_VIDEO_AVCProfileBaseline,32768}, + {8704,522240,50000000,OMX_VIDEO_AVCLevel42,OMX_VIDEO_AVCProfileBaseline,34816}, + {22080,589824,135000000,OMX_VIDEO_AVCLevel5,OMX_VIDEO_AVCProfileBaseline,110400}, + {36864,983040,240000000,OMX_VIDEO_AVCLevel51,OMX_VIDEO_AVCProfileBaseline,184320}, + /* Please update H264_HP_START accordingly, while adding new element */ + {0,0,0,0,0,0}, + + {99,1485,64000,OMX_VIDEO_AVCLevel1, QOMX_VIDEO_AVCProfileConstrainedBaseline,396}, + {99,1485,128000,OMX_VIDEO_AVCLevel1b, QOMX_VIDEO_AVCProfileConstrainedBaseline,396}, + {396,3000,192000,OMX_VIDEO_AVCLevel11, QOMX_VIDEO_AVCProfileConstrainedBaseline,900}, + {396,6000,384000,OMX_VIDEO_AVCLevel12, QOMX_VIDEO_AVCProfileConstrainedBaseline,2376}, + {396,11880,768000,OMX_VIDEO_AVCLevel13, QOMX_VIDEO_AVCProfileConstrainedBaseline,2376}, + {396,11880,2000000,OMX_VIDEO_AVCLevel2, QOMX_VIDEO_AVCProfileConstrainedBaseline,2376}, + {792,19800,4000000,OMX_VIDEO_AVCLevel21, QOMX_VIDEO_AVCProfileConstrainedBaseline,4752}, + {1620,20250,4000000,OMX_VIDEO_AVCLevel22, QOMX_VIDEO_AVCProfileConstrainedBaseline,8100}, + {1620,40500,10000000,OMX_VIDEO_AVCLevel3, QOMX_VIDEO_AVCProfileConstrainedBaseline,8100}, + {3600,108000,14000000,OMX_VIDEO_AVCLevel31, QOMX_VIDEO_AVCProfileConstrainedBaseline,18000}, + {5120,216000,20000000,OMX_VIDEO_AVCLevel32, QOMX_VIDEO_AVCProfileConstrainedBaseline,20480}, + {8192,245760,20000000,OMX_VIDEO_AVCLevel4, QOMX_VIDEO_AVCProfileConstrainedBaseline,32768}, + {8192,245760,50000000,OMX_VIDEO_AVCLevel41, QOMX_VIDEO_AVCProfileConstrainedBaseline,32768}, + {8704,522240,50000000,OMX_VIDEO_AVCLevel42, QOMX_VIDEO_AVCProfileConstrainedBaseline,34816}, + {22080,589824,135000000,OMX_VIDEO_AVCLevel5, QOMX_VIDEO_AVCProfileConstrainedBaseline,110400}, + {36864,983040,240000000,OMX_VIDEO_AVCLevel51, QOMX_VIDEO_AVCProfileConstrainedBaseline,184320}, + /* Please update H264_HP_START accordingly, while adding new element */ + {0,0,0,0,0,0}, + + {99,1485,80000,OMX_VIDEO_AVCLevel1,OMX_VIDEO_AVCProfileHigh,396}, + {99,1485,200000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileHigh,396}, + {396,3000,300000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileHigh,900}, + {396,6000,600000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileHigh,2376}, + {396,11880,1200000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileHigh,2376}, + {396,11880,3125000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileHigh,2376}, + {792,19800,6250000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileHigh,4752}, + {1620,20250,6250000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileHigh,8100}, + {1620,40500,15625000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileHigh,8100}, + {3600,108000,21875000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileHigh,18000}, + {5120,216000,31250000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileHigh,20480}, + {8192,245760,31250000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileHigh,32768}, + {8192,245760,62500000,OMX_VIDEO_AVCLevel41,OMX_VIDEO_AVCProfileHigh,32768}, + {8704,522240,62500000,OMX_VIDEO_AVCLevel42,OMX_VIDEO_AVCProfileHigh,34816}, + {22080,589824,168750000,OMX_VIDEO_AVCLevel5,OMX_VIDEO_AVCProfileHigh,110400}, + {36864,983040,300000000,OMX_VIDEO_AVCLevel51,OMX_VIDEO_AVCProfileHigh,184320}, + /* Please update H264_MP_START accordingly, while adding new element */ + {0,0,0,0,0,0}, + + {99,1485,80000,OMX_VIDEO_AVCLevel1,QOMX_VIDEO_AVCProfileConstrainedHigh,396}, + {99,1485,200000,OMX_VIDEO_AVCLevel1b, QOMX_VIDEO_AVCProfileConstrainedHigh,396}, + {396,3000,300000,OMX_VIDEO_AVCLevel11, QOMX_VIDEO_AVCProfileConstrainedHigh,900}, + {396,6000,600000,OMX_VIDEO_AVCLevel12, QOMX_VIDEO_AVCProfileConstrainedHigh,2376}, + {396,11880,1200000,OMX_VIDEO_AVCLevel13, QOMX_VIDEO_AVCProfileConstrainedHigh,2376}, + {396,11880,3125000,OMX_VIDEO_AVCLevel2, QOMX_VIDEO_AVCProfileConstrainedHigh,2376}, + {792,19800,6250000,OMX_VIDEO_AVCLevel21, QOMX_VIDEO_AVCProfileConstrainedHigh,4752}, + {1620,20250,6250000,OMX_VIDEO_AVCLevel22, QOMX_VIDEO_AVCProfileConstrainedHigh,8100}, + {1620,40500,15625000,OMX_VIDEO_AVCLevel3, QOMX_VIDEO_AVCProfileConstrainedHigh,8100}, + {3600,108000,21875000,OMX_VIDEO_AVCLevel31, QOMX_VIDEO_AVCProfileConstrainedHigh,18000}, + {5120,216000,31250000,OMX_VIDEO_AVCLevel32, QOMX_VIDEO_AVCProfileConstrainedHigh,20480}, + {8192,245760,31250000,OMX_VIDEO_AVCLevel4, QOMX_VIDEO_AVCProfileConstrainedHigh,32768}, + {8192,245760,62500000,OMX_VIDEO_AVCLevel41, QOMX_VIDEO_AVCProfileConstrainedHigh,32768}, + {8704,522240,62500000,OMX_VIDEO_AVCLevel42, QOMX_VIDEO_AVCProfileConstrainedHigh,34816}, + {22080,589824,168750000,OMX_VIDEO_AVCLevel5, QOMX_VIDEO_AVCProfileConstrainedHigh,110400}, + {36864,983040,300000000,OMX_VIDEO_AVCLevel51, QOMX_VIDEO_AVCProfileConstrainedHigh,184320}, + /* Please update H264_MP_START accordingly, while adding new element */ + {0,0,0,0,0,0}, + + {99,1485,64000,OMX_VIDEO_AVCLevel1,OMX_VIDEO_AVCProfileMain,396}, + {99,1485,128000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileMain,396}, + {396,3000,192000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileMain,900}, + {396,6000,384000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileMain,2376}, + {396,11880,768000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileMain,2376}, + {396,11880,2000000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileMain,2376}, + {792,19800,4000000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileMain,4752}, + {1620,20250,4000000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileMain,8100}, + {1620,40500,10000000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileMain,8100}, + {3600,108000,14000000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileMain,18000}, + {5120,216000,20000000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileMain,20480}, + {8192,245760,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileMain,32768}, + {8192,245760,50000000,OMX_VIDEO_AVCLevel41,OMX_VIDEO_AVCProfileMain,32768}, + {8704,522240,50000000,OMX_VIDEO_AVCLevel42,OMX_VIDEO_AVCProfileMain,34816}, + {22080,589824,135000000,OMX_VIDEO_AVCLevel5,OMX_VIDEO_AVCProfileMain,110400}, + {36864,983040,240000000,OMX_VIDEO_AVCLevel51,OMX_VIDEO_AVCProfileMain,184320}, + {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, profile*/ + {99,1485,128000,OMX_VIDEO_HEVCMainTierLevel1,OMX_VIDEO_HEVCProfileMain,0}, + {396,11880,1500000,OMX_VIDEO_HEVCMainTierLevel2,OMX_VIDEO_HEVCProfileMain,0}, + {900,27000,3000000,OMX_VIDEO_HEVCMainTierLevel21,OMX_VIDEO_HEVCProfileMain,0}, + {2025,60750,6000000,OMX_VIDEO_HEVCMainTierLevel3,OMX_VIDEO_HEVCProfileMain,0}, + {8640,259200,10000000,OMX_VIDEO_HEVCMainTierLevel31,OMX_VIDEO_HEVCProfileMain,0}, + {34560,1166400,12000000,OMX_VIDEO_HEVCMainTierLevel4,OMX_VIDEO_HEVCProfileMain,0}, + {138240,4147200,20000000,OMX_VIDEO_HEVCMainTierLevel41,OMX_VIDEO_HEVCProfileMain,0}, + {138240,8294400,25000000,OMX_VIDEO_HEVCMainTierLevel5,OMX_VIDEO_HEVCProfileMain,0}, + {138240,4147200,40000000,OMX_VIDEO_HEVCMainTierLevel51,OMX_VIDEO_HEVCProfileMain,0}, + {138240,4147200,50000000,OMX_VIDEO_HEVCHighTierLevel41,OMX_VIDEO_HEVCProfileMain,0}, + {138240,4147200,100000000,OMX_VIDEO_HEVCHighTierLevel5,OMX_VIDEO_HEVCProfileMain,0}, + {138240,4147200,160000000,OMX_VIDEO_HEVCHighTierLevel51,OMX_VIDEO_HEVCProfileMain,0}, + {138240,4147200,240000000,OMX_VIDEO_HEVCHighTierLevel52,OMX_VIDEO_HEVCProfileMain,0}, + /* Please update HEVC_MAIN_START accordingly, while adding new element */ + {0,0,0,0,0}, + + {99,1485,128000,OMX_VIDEO_HEVCMainTierLevel1,OMX_VIDEO_HEVCProfileMain10,0}, + {396,11880,1500000,OMX_VIDEO_HEVCMainTierLevel2,OMX_VIDEO_HEVCProfileMain10,0}, + {900,27000,3000000,OMX_VIDEO_HEVCMainTierLevel21,OMX_VIDEO_HEVCProfileMain10,0}, + {2025,60750,6000000,OMX_VIDEO_HEVCMainTierLevel3,OMX_VIDEO_HEVCProfileMain10,0}, + {8640,259200,10000000,OMX_VIDEO_HEVCMainTierLevel31,OMX_VIDEO_HEVCProfileMain10,0}, + {34560,1166400,12000000,OMX_VIDEO_HEVCMainTierLevel4,OMX_VIDEO_HEVCProfileMain10,0}, + {138240,4147200,20000000,OMX_VIDEO_HEVCMainTierLevel41,OMX_VIDEO_HEVCProfileMain10,0}, + {138240,8294400,25000000,OMX_VIDEO_HEVCMainTierLevel5,OMX_VIDEO_HEVCProfileMain10,0}, + {138240,4147200,40000000,OMX_VIDEO_HEVCMainTierLevel51,OMX_VIDEO_HEVCProfileMain10,0}, + {138240,4147200,50000000,OMX_VIDEO_HEVCHighTierLevel41,OMX_VIDEO_HEVCProfileMain10,0}, + {138240,4147200,100000000,OMX_VIDEO_HEVCHighTierLevel5,OMX_VIDEO_HEVCProfileMain10,0}, + {138240,4147200,160000000,OMX_VIDEO_HEVCHighTierLevel51,OMX_VIDEO_HEVCProfileMain10,0}, + {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; + } + + is_pq_force_disable = 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))) { + is_pq_force_disable = 1; + } else { + 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) +{ + 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, 0); + + + 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() +{ +#ifdef USE_ION + + if (output_extradata_info.uaddr) { + munmap((void *)output_extradata_info.uaddr, output_extradata_info.size); + close(output_extradata_info.ion.fd_ion_data.fd); + venc_handle->free_ion_memory(&output_extradata_info.ion); + } + if (output_extradata_info.m_ion_dev) + close(output_extradata_info.m_ion_dev); + + memset(&output_extradata_info, 0, sizeof(output_extradata_info)); + output_extradata_info.ion.fd_ion_data.fd = -1; + + if (input_extradata_info.uaddr) { + munmap((void *)input_extradata_info.uaddr, input_extradata_info.size); + close(input_extradata_info.ion.fd_ion_data.fd); + venc_handle->free_ion_memory(&input_extradata_info.ion); + } + + if (input_extradata_info.m_ion_dev) + close(output_extradata_info.m_ion_dev); + + memset(&input_extradata_info, 0, sizeof(input_extradata_info)); + input_extradata_info.ion.fd_ion_data.fd = -1; + +#ifdef _PQ_ + if (m_pq.roi_extradata_info.uaddr) { + munmap((void *)m_pq.roi_extradata_info.uaddr, m_pq.roi_extradata_info.size); + close(m_pq.roi_extradata_info.ion.fd_ion_data.fd); + venc_handle->free_ion_memory(&m_pq.roi_extradata_info.ion); + } + + memset(&m_pq.roi_extradata_info, 0, sizeof(m_pq.roi_extradata_info)); + m_pq.roi_extradata_info.ion.fd_ion_data.fd = -1; +#endif // _PQ_ + +#endif +} + +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.init(V4L2_DEFAULT_OUTPUT_COLOR_FMT); + allocate_extradata(&m_pq.roi_extradata_info); + m_pq.get_caps(); + } +#endif // _PQ_ + + 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; + m_pq.configure(); +#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_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 (config_rotation->nRotation == 90 || config_rotation->nRotation == 270) { + DEBUG_PRINT_HIGH("venc_set_config: updating the new Dims"); + nFrameWidth = m_sVenc_cfg.dvs_width; + m_sVenc_cfg.dvs_width = m_sVenc_cfg.dvs_height; + m_sVenc_cfg.dvs_height = nFrameWidth; + } + 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(); + 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__); + + 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); + + 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); + + 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; + + if (!mBatchSize && hnd->numFds + hnd->numInts > 5) { + color_format = (OMX_COLOR_FORMATTYPE)hnd->data[5]; + } else if (mBatchSize) { + color_format = (OMX_COLOR_FORMATTYPE)BatchInfo::getColorFormatAt(hnd, 0); + } + + if (!mBatchSize && hnd->numFds + hnd->numInts > 3) { + usage = hnd->data[3]; + } else if (mBatchSize) { + usage = BatchInfo::getUsageAt(hnd, 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 (!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)hnd->numFds != mBatchSize) { + DEBUG_PRINT_ERROR("Don't support dynamic batch sizes (changed from %d->%d)", + mBatchSize, hnd->numFds); + return false; + } + + return venc_empty_batch ((OMX_BUFFERHEADERTYPE*)buffer, index); + } + + if (hnd->numFds + hnd->numInts > 2) { + plane[0].data_offset = hnd->data[1]; + plane[0].length = hnd->data[2]; + plane[0].bytesused = hnd->data[2]; + } + 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]) { + /* + * This is the place where all parameters for deciding + * PQ enablement are aailable. Evaluate PQ for the final time. + */ + m_pq.is_YUV_format_uncertain = false; + m_pq.reinit(m_sVenc_cfg.inputformat); + venc_try_enable_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); + + 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 (hnd->numFds > kMaxBuffersInBatch) { + DEBUG_PRINT_ERROR("venc_empty_batch: Too many buffers (%d) in batch. " + "Max = %d", hnd->numFds, kMaxBuffersInBatch); + status = false; + } + DEBUG_PRINT_LOW("venc_empty_batch: Batch of %d bufs", hnd->numFds); + } 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 = hnd->numFds; + 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] = BatchInfo::getFdAt(hnd, i); + plane[0].reserved[1] = 0; + plane[0].data_offset = BatchInfo::getOffsetAt(hnd, i); + plane[0].m.userptr = (unsigned long)meta_buf; + plane[0].length = plane[0].bytesused = BatchInfo::getSizeAt(hnd, i); + 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; + m_pq.reinit(m_sVenc_cfg.inputformat); + venc_try_enable_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 + BatchInfo::getTimeStampAt(hnd, i) / 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); + + 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; + } + + 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); + 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: + requested_level.level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5; + break; + default: + return false; + // TODO update corresponding levels for MPEG4_LEVEL_3b,MPEG4_LEVEL_6 + 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: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0; + break; + default: + return false; + 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: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2; + break; + case OMX_VIDEO_AVCLevelMax: + requested_level.level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2; + break; + default : + DEBUG_PRINT_ERROR("ERROR: Unsupported H.264 level= %lu", + requested_level.level); + return false; + 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: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1; + break; + default: + DEBUG_PRINT_ERROR("ERROR: Unsupported VP8 level= %u", + (unsigned int)eLevel); + return false; + 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: + requested_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1; + break; + default : + DEBUG_PRINT_ERROR("ERROR: Unsupported HEVC level= %lu", + requested_level.level); + return false; + } + } + + 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_profile = 0, 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; + } + + if ((*eProfile == OMX_VIDEO_AVCProfileBaseline) || + (*eProfile == QOMX_VIDEO_AVCProfileConstrainedBaseline)) { + profile_tbl = (unsigned int const *)h264_profile_level_table; + } else if ((*eProfile == OMX_VIDEO_AVCProfileHigh) || + (*eProfile == QOMX_VIDEO_AVCProfileConstrainedHigh)) { + 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 %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; + } + + if (*eProfile == OMX_VIDEO_HEVCProfileMain) { + profile_tbl = (unsigned int const *)hevc_profile_level_table; + } else if (*eProfile == OMX_VIDEO_HEVCProfileMain10) { + profile_tbl = (unsigned int const *) + (&hevc_profile_level_table[HEVC_MAIN10_START]); + } else { + 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; + new_profile = codec_profile.profile; + 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]; + new_profile = (int)profile_tbl[4]; + 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)new_profile, (int)new_level, + MIN((unsigned int) (profile_tbl[5] / mb_per_frame), MAXDPB)); + break; + } else { + new_level = (int)profile_tbl[3]; + new_profile = (int)profile_tbl[4]; + profile_level_found = true; + DEBUG_PRINT_LOW("Appropriate profile/level found %u/%u", (int) new_profile, (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; +} + +int venc_dev::BatchInfo::getFdAt(native_handle_t *hnd, int index) { + int fd = hnd && index < hnd->numFds ? hnd->data[index] : -1; + return fd; +} + +int venc_dev::BatchInfo::getOffsetAt(native_handle_t *hnd, int index) { + int off = hnd && index < hnd->numInts ? hnd->data[hnd->numFds + index] : -1; + return off; +} + +int venc_dev::BatchInfo::getSizeAt(native_handle_t *hnd, int index) { + int size = hnd && (index + hnd->numFds) < hnd->numInts ? + hnd->data[2*hnd->numFds + index] : -1; + return size; +} + +int venc_dev::BatchInfo::getUsageAt(native_handle_t *hnd, int index) { + int usage = hnd && (index + 2*hnd->numFds) < hnd->numInts ? + hnd->data[3*hnd->numFds + index] : 0; + return usage; +} + +int venc_dev::BatchInfo::getColorFormatAt(native_handle_t *hnd, int index) { + int usage = hnd && (index + 4*hnd->numFds) < hnd->numInts ? + hnd->data[5*hnd->numFds + index] : 0; + return usage; +} + +int venc_dev::BatchInfo::getTimeStampAt(native_handle_t *hnd, int index) { + int size = hnd && (index + 3*hnd->numFds) < hnd->numInts ? + hnd->data[4*hnd->numFds + index] : -1; + return size; +} + +#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_ +void venc_dev::venc_try_enable_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) <= MAX_FPS_PQ; + + 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 = (!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", + 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); + + venc_set_extradata(OMX_ExtraDataEncoderOverrideQPInfo, (OMX_BOOL)enable); + extradata |= enable; + + m_pq.pConfig.algo = ADAPTIVE_QP; + m_pq.pConfig.height = m_sVenc_cfg.input_height; + m_pq.pConfig.width = m_sVenc_cfg.input_width; + m_pq.pConfig.mb_height = 16; + m_pq.pConfig.mb_width = 16; + m_pq.pConfig.a_qp.pq_enabled = enable; + m_pq.pConfig.stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, m_sVenc_cfg.input_width); + m_pq.configure(); + m_pq.is_pq_enabled = enable; + + return; +} + +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; + 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; + } + + 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"); + } + + } + } + + 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) { + DEBUG_PRINT_HIGH("New format (%lu) is different from configure format (%lu);" + " reinitializing PQ lib", format, configured_format); + deinit(); + if (is_color_format_supported(format)) { + status = init(format); + get_caps(); + } + } 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() +{ + if (mPQHandle) { + 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; + } + + 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); + } + + 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_ |