blob: cd909e7013f9e1d5a2ff2d013a5c69f42d30455f [file] [log] [blame]
/*--------------------------------------------------------------------------
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 <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
#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
/* 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},
{36864,2073600,240000000,OMX_VIDEO_AVCLevel52,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,OMX_VIDEO_AVCProfileHigh,396},
{99,1485,160000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileHigh,396},
{396,3000,240000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileHigh,900},
{396,6000,480000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileHigh,2376},
{396,11880,960000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileHigh,2376},
{396,11880,2500000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileHigh,2376},
{792,19800,5000000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileHigh,4752},
{1620,20250,5000000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileHigh,8100},
{1620,40500,12500000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileHigh,8100},
{3600,108000,17500000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileHigh,18000},
{5120,216000,25000000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileHigh,20480},
{8192,245760,25000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileHigh,32768},
{8192,245760,50000000,OMX_VIDEO_AVCLevel41,OMX_VIDEO_AVCProfileHigh,32768},
{8704,522240,50000000,OMX_VIDEO_AVCLevel42,OMX_VIDEO_AVCProfileHigh,34816},
{22080,589824,135000000,OMX_VIDEO_AVCLevel5,OMX_VIDEO_AVCProfileHigh,110400},
{36864,983040,240000000,OMX_VIDEO_AVCLevel51,OMX_VIDEO_AVCProfileHigh,184320},
{36864,2073600,240000000,OMX_VIDEO_AVCLevel52,OMX_VIDEO_AVCProfileHigh,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},
{36864,2073600,240000000,OMX_VIDEO_AVCLevel52,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):mInputExtradata(venc_class), mOutputExtradata(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;
pthread_mutex_init(&pause_resume_mlock, NULL);
pthread_cond_init(&pause_resume_cond, NULL);
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(&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(&ltrinfo, 0, sizeof(ltrinfo));
memset(&fd_list, 0, sizeof(fd_list));
memset(&hybrid_hp, 0, sizeof(hybrid_hp));
sess_priority.priority = 1;
operating_rate = 0;
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);
property_get("vidc.enc.log.roiqp", property_value, "0");
m_debug.roiqp_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
snprintf(m_debug.log_loc, PROPERTY_VALUE_MAX,
"%s", BUFFER_LOG_LOC);
}
venc_dev::~venc_dev()
{
}
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;
int extra_idx = EXTRADATA_IDX(v4l2_buf.length);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
omxhdr->pPlatformPrivate = (void *)v4l2_buf.m.planes[extra_idx].m.userptr;
} else {
omxhdr->pPlatformPrivate = 0;
}
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];
int extra_idx = EXTRADATA_IDX(v4l2_buf.length);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
omxhdr->pPlatformPrivate = (void *)v4l2_buf.m.planes[extra_idx].m.userptr;
omx->handle->mInputExtradata.put((char *)omxhdr->pPlatformPrivate);
} else {
omxhdr->pPlatformPrivate = 0;
}
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 = 1;
mbi->nDataSize = src->data_size;
memcpy(&mbi->data, &src->data, src->data_size);
return mbi->nDataSize + sizeof(*mbi);
}
bool venc_dev::handle_input_extradata(void *buffer, int fd)
{
OMX_BUFFERHEADERTYPE *p_bufhdr = (OMX_BUFFERHEADERTYPE *) buffer;
OMX_OTHER_EXTRADATATYPE *p_extra = NULL;
ssize_t consumed_len = 0;
int enable = 0, i = 0;
int height = 0, width = 0;
char *userptr;
int extra_fd;
unsigned offset;
ssize_t extra_size;
struct v4l2_control control;
memset(&control, 0, sizeof(control));
control.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA;
if (ioctl(m_nDriver_fd, VIDIOC_G_CTRL, &control) < 0) {
return false;
}
if (!(control.value == V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS ||
control.value == V4L2_MPEG_VIDC_EXTRADATA_VQZIP_SEI ||
control.value == V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP ||
control.value == V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP)) {
DEBUG_PRINT_LOW("Input extradata not enabled");
return true;
}
/*
* 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.
*/
height = ALIGN(m_sVenc_cfg.input_height, 32);
width = ALIGN(m_sVenc_cfg.input_width, 32);
int rc = mInputExtradata.get(buffer, &userptr, &extra_fd, &offset, &extra_size);
if (rc != OMX_ErrorNone) {
DEBUG_PRINT_ERROR("Unable to get extradata memory 4");
return false;
}
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 = userptr;
OMX_OTHER_EXTRADATATYPE *data = (struct OMX_OTHER_EXTRADATATYPE *)p_extradata;
if (p_extra) {
while ((consumed_len < extra_size)
&& (p_extra->eType != (OMX_EXTRADATATYPE)MSM_VIDC_EXTRADATA_NONE)) {
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 ");
mInputExtradata.vqzip_sei_found = true;
break;
default:
break;
}
consumed_len += p_extra->nSize;
p_extra = (OMX_OTHER_EXTRADATATYPE *)((char *)p_extra + p_extra->nSize);
}
if (control.value == V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS ||
control.value == V4L2_MPEG_VIDC_EXTRADATA_VQZIP_SEI) {
if (!mInputExtradata.vqzip_sei_found) {
DEBUG_PRINT_ERROR("VQZIP is enabled, But no VQZIP SEI found. Rejecting the session");
munmap(pVirt, size);
mInputExtradata.put(userptr);
return false;
}
#ifdef _VQZIP_
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);
mInputExtradata.put(userptr);
return true;
}
bool venc_dev::handle_output_extradata(void *buffer)
{
OMX_BUFFERHEADERTYPE *p_bufhdr = (OMX_BUFFERHEADERTYPE *) buffer;
OMX_OTHER_EXTRADATATYPE *p_extra = NULL;
char *extradata_uaddr = (char *)p_bufhdr->pPlatformPrivate;
p_extra = (OMX_OTHER_EXTRADATATYPE *)ALIGN(p_bufhdr->pBuffer +
p_bufhdr->nOffset + p_bufhdr->nFilledLen, 4);
if (mOutputExtradata.getBufferSize() >
(ssize_t)(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 : extradata_uaddr);
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);
}
mOutputExtradata.put(extradata_uaddr);
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;
}
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.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.extradatafile_name, PROPERTY_VALUE_MAX, "%s/extradata_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.extradatafile_name, PROPERTY_VALUE_MAX, "%s/extradata_enc_%lu_%lu_%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.extradatafile_name, PROPERTY_VALUE_MAX, "%s/extradata_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.extradatafile_name, PROPERTY_VALUE_MAX, "%s/extradata_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 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) {
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_roiqp_log_buffers(OMX_QTI_VIDEO_CONFIG_ROIINFO *roiInfo) {
int size = 0;
if (!roiInfo || !m_debug.roiqp_log) {
DEBUG_PRINT_LOW("Nothing to log");
return 0;
}
if (!m_debug.roiqpfile) {
size = snprintf(m_debug.roiqpfile_name, PROPERTY_VALUE_MAX, "%s/enc_%lu_%lu_%p.roiqp",
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 ROIQP file: %s for logging size:%d",
m_debug.roiqpfile_name, size);
m_debug.roiqpfile_name[0] = '\0';
return -1;
}
m_debug.roiqpfile = fopen(m_debug.roiqpfile_name, "ab");
if (!m_debug.roiqpfile) {
DEBUG_PRINT_ERROR("Failed to open ROI QP file: %s for logging errno:%d",
m_debug.roiqpfile_name, errno);
m_debug.roiqpfile_name[0] = '\0';
return -1;
}
}
if (m_debug.roiqpfile) {
if (fwrite(&mInputExtradata.mDbgEtbCount, sizeof(mInputExtradata.mDbgEtbCount), 1, m_debug.roiqpfile) != 1) {
DEBUG_PRINT_ERROR("Unable to write to QP file");
return -1;
}
if (fwrite(&roiInfo->nLowerQpOffset, sizeof(roiInfo->nLowerQpOffset), 1, m_debug.roiqpfile) != 1) {
DEBUG_PRINT_ERROR("Unable to write to QP file");
return -1;
}
if (fwrite(&roiInfo->nUpperQpOffset, sizeof(roiInfo->nUpperQpOffset), 1, m_debug.roiqpfile) != 1) {
DEBUG_PRINT_ERROR("Unable to write to QP file");
return -1;
}
if (fwrite((char *)roiInfo->pRoiMBInfo, roiInfo->nRoiMBInfoSize, 1, m_debug.roiqpfile) != 1) {
DEBUG_PRINT_ERROR("Unable to write to QP file");
return -1;
}
}
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;
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;
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");
}
}
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;
}
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;
}
if (m_debug.roiqpfile) {
fclose(m_debug.roiqpfile);
m_debug.roiqpfile = 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;
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;
m_sInput_buff_property.mincount = m_sInput_buff_property.actualcount = actualCount;
*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;
}
mInputExtradata.update(m_sInput_buff_property.actualcount + 1, extra_data_size);
} 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;
}
mOutputExtradata.update(m_sOutput_buff_property.actualcount, extra_data_size);
}
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;
}
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;
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;
}
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;
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");
}
break;
}
case OMX_IndexParamVideoBitrate:
{
OMX_VIDEO_PARAM_BITRATETYPE* pParam;
pParam = (OMX_VIDEO_PARAM_BITRATETYPE*)paramData;
DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoBitrate");
if (pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) {
if (!venc_set_target_bitrate(pParam->nTargetBitrate, 0)) {
DEBUG_PRINT_ERROR("ERROR: Target Bit Rate setting failed");
return false;
}
if (!venc_set_ratectrl_cfg(pParam->eControlRate)) {
DEBUG_PRINT_ERROR("ERROR: Rate Control setting failed");
return false;
}
} else {
DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoBitrate");
}
break;
}
case OMX_IndexParamVideoMpeg4:
{
OMX_VIDEO_PARAM_MPEG4TYPE* pParam;
OMX_U32 bFrames = 0;
pParam = (OMX_VIDEO_PARAM_MPEG4TYPE*)paramData;
DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoMpeg4");
if (pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) {
if (!venc_set_voptiming_cfg(pParam->nTimeIncRes)) {
DEBUG_PRINT_ERROR("ERROR: Request for setting vop_timing failed");
return false;
}
m_profile_set = false;
m_level_set = false;
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_config (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_config (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_config (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, 1)) {
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_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, 1)) {
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_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;
}
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;
}
} 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;
}
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) ==