blob: e798d4ffc893224ca6831c7a27220f699eb45987 [file] [log] [blame]
/*--------------------------------------------------------------------------
Copyright (c) 2010-2018, 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>
#include <color_metadata.h>
#include "PlatformConfig.h"
#define ATRACE_TAG ATRACE_TAG_VIDEO
#include <utils/Trace.h>
#define YUV_STATS_LIBRARY_NAME "libgpustats.so" // UBWC case: use GPU library
#undef ALIGN
#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 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 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/vendor/media"
#define OMX_VIDEO_LEVEL_UNKNOWN 0
#define VENC_BFRAME_MAX_COUNT 1
#define VENC_BFRAME_MAX_FPS 60
#define VENC_BFRAME_MAX_WIDTH 1920
#define VENC_BFRAME_MAX_HEIGHT 1088
#undef LOG_TAG
#define LOG_TAG "OMX-VENC: venc_dev"
//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;
m_roi_enabled = false;
pthread_mutex_init(&m_roilock, NULL);
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));
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));
sess_priority.priority = 1;
operating_rate = 30;
memset(&color_space, 0x0, sizeof(color_space));
memset(&temporal_layers_config, 0x0, sizeof(temporal_layers_config));
client_req_disable_bframe = false;
bframe_implicitly_enabled = false;
client_req_disable_temporal_layers = false;
client_req_turbo_mode = false;
intra_period.num_pframes = 29;
intra_period.num_bframes = 0;
Platform::Config::getInt32(Platform::vidc_enc_log_in,
(int32_t *)&m_debug.in_buffer_log, 0);
Platform::Config::getInt32(Platform::vidc_enc_log_out,
(int32_t *)&m_debug.out_buffer_log, 0);
Platform::Config::getInt32(Platform::vidc_enc_csc_custom_matrix,
(int32_t *)&is_csc_custom_matrix_enabled, 0);
char property_value[PROPERTY_VALUE_MAX] = {0};
property_get("vendor.vidc.enc.log.in", property_value, "0");
m_debug.in_buffer_log |= atoi(property_value);
property_value[0] = '\0';
property_get("vendor.vidc.enc.log.out", property_value, "0");
m_debug.out_buffer_log |= atoi(property_value);
property_get("vendor.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_value[0] = '\0';
property_get("vendor.vidc.log.loc", property_value, BUFFER_LOG_LOC);
if (*property_value)
strlcpy(m_debug.log_loc, property_value, PROPERTY_VALUE_MAX);
mUseAVTimerTimestamps = false;
profile_level_converter::init();
}
venc_dev::~venc_dev()
{
if (m_roi_enabled) {
std::list<roidata>::iterator iter;
pthread_mutex_lock(&m_roilock);
for (iter = m_roilist.begin(); iter != m_roilist.end(); iter++) {
DEBUG_PRINT_HIGH("roidata with timestamp (%lld) should have been removed already",
iter->timestamp);
free(iter->info.pRoiMBInfo);
}
m_roilist.clear();
pthread_mutex_unlock(&m_roilock);
}
pthread_mutex_destroy(&m_roilock);
}
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_BUF_FLAG_PFRAME) {
venc_msg.buf.flags |= OMX_VIDEO_PictureTypeP;
} else if (v4l2_buf.flags & V4L2_BUF_FLAG_BFRAME) {
venc_msg.buf.flags |= OMX_VIDEO_PictureTypeB;
}
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) {
OMX_U32 num_fbd = omx->handle->fbd - stats.prev_fbd;
if (stats.prev_tv.tv_sec && num_fbd && time_diff) {
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;
}
bool inline venc_dev::venc_query_cap(struct v4l2_queryctrl &cap) {
if (ioctl(m_nDriver_fd, VIDIOC_QUERYCTRL, &cap)) {
DEBUG_PRINT_ERROR("Query caps for id = %u failed", cap.id);
return false;
}
return true;
}
bool inline venc_dev::venc_validate_range(OMX_S32 id, OMX_S32 val) {
struct v4l2_queryctrl cap;
memset(&cap, 0, sizeof(struct v4l2_queryctrl));
cap.id = id;
if (venc_query_cap(cap)) {
if (val >= cap.minimum && val <= cap.maximum) {
return true;
} else {
DEBUG_PRINT_ERROR("id = %u, value = %u, min = %u, max = %u",
cap.id, val, cap.minimum, cap.maximum);
}
}
return false;
}
void venc_dev::get_roi_for_timestamp(struct roidata &roi, OMX_TICKS timestamp)
{
std::list<roidata>::iterator iter;
bool found = false;
memset(&roi, 0, sizeof(struct roidata));
roi.dirty = false;
/*
* look for the roi data which has timestamp nearest and
* lower than the etb timestamp, we should not take the
* roi data which has the timestamp greater than etb timestamp.
*/
pthread_mutex_lock(&m_roilock);
iter = m_roilist.begin();
while (iter != m_roilist.end()) {
if (iter->timestamp <= timestamp) {
if (found) {
/* we found roidata in previous iteration already and got another
* roidata in this iteration, so we will use this iteration's
* roidata and free the previous roidata which is no longer used.
*/
DEBUG_PRINT_LOW("freeing unused roidata with timestamp %lld us", roi.timestamp);
free(roi.info.pRoiMBInfo);
}
found = true;
roi = *iter;
/* we got roidata so erase the elment in the roi list.
* after list erase iterator will point to next element
* so we don't need to increment iter after erase.
*/
iter = m_roilist.erase(iter);
} else {
iter++;
}
}
if (found) {
DEBUG_PRINT_LOW("found roidata with timestamp %lld us", roi.timestamp);
}
pthread_mutex_unlock(&m_roilock);
}
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);
}
inline int get_yuv_size(unsigned long fmt, int width, int height) {
unsigned int y_stride, uv_stride, y_sclines,
uv_sclines, y_plane, uv_plane;
unsigned int y_ubwc_plane = 0, uv_ubwc_plane = 0;
unsigned size = 0;
y_stride = VENUS_Y_STRIDE(fmt, width);
uv_stride = VENUS_UV_STRIDE(fmt, width);
y_sclines = VENUS_Y_SCANLINES(fmt, height);
uv_sclines = VENUS_UV_SCANLINES(fmt, height);
switch (fmt) {
case COLOR_FMT_NV12:
y_plane = y_stride * y_sclines;
uv_plane = uv_stride * uv_sclines;
size = MSM_MEDIA_ALIGN(y_plane + uv_plane, 4096);
break;
default:
break;
}
return size;
}
void venc_dev::append_extradata_mbidata(OMX_OTHER_EXTRADATATYPE *p_extra,
struct msm_vidc_extradata_header *p_extradata)
{
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;
}
void venc_dev::append_extradata_ltrinfo(OMX_OTHER_EXTRADATATYPE *p_extra,
struct msm_vidc_extradata_header *p_extradata)
{
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;
memcpy(p_extra->data, p_extradata->data, p_extradata->data_size);
}
void venc_dev::append_extradata_none(OMX_OTHER_EXTRADATATYPE *p_extra)
{
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;
}
bool venc_dev::handle_input_extradata(struct v4l2_buffer buf)
{
OMX_OTHER_EXTRADATATYPE *p_extra = NULL;
unsigned int consumed_len = 0, filled_len = 0;
unsigned int yuv_size = 0, index = 0;
int enable = 0, i = 0, size = 0;
unsigned char *pVirt = NULL;
int height = m_sVenc_cfg.input_height;
int width = m_sVenc_cfg.input_width;
OMX_TICKS nTimeStamp = buf.timestamp.tv_sec * 1000000 + buf.timestamp.tv_usec;
int fd = buf.m.planes[0].reserved[0];
bool vqzip_sei_found = 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 true;
}
DEBUG_PRINT_HIGH("Processing Extradata for Buffer = %lld", nTimeStamp); // Useful for debugging
if (m_sVenc_cfg.inputformat == V4L2_PIX_FMT_NV12 || m_sVenc_cfg.inputformat == V4L2_PIX_FMT_NV21) {
size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
yuv_size = get_yuv_size(COLOR_FMT_NV12, width, height);
pVirt = (unsigned char *)mmap(NULL, size, PROT_READ|PROT_WRITE,MAP_SHARED, fd, 0);
if (pVirt == MAP_FAILED) {
DEBUG_PRINT_ERROR("%s Failed to mmap",__func__);
return false;
}
p_extra = (OMX_OTHER_EXTRADATATYPE *) ((unsigned long)(pVirt + yuv_size + 3)&(~3));
}
index = venc_get_index_from_fd(input_extradata_info.m_ion_dev,fd);
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
while (p_extra && (consumed_len + sizeof(OMX_OTHER_EXTRADATATYPE)) <= (size - yuv_size)
&& (consumed_len + p_extra->nSize) <= (size - yuv_size)
&& (filled_len + sizeof(OMX_OTHER_EXTRADATATYPE) <= input_extradata_info.buffer_size)
&& (filled_len + p_extra->nSize <= input_extradata_info.buffer_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);
filled_len += data->nSize;
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);
filled_len += data->nSize;
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;
case OMX_ExtraDataFrameInfo:
{
OMX_QCOM_EXTRADATA_FRAMEINFO *frame_info = NULL;
frame_info = (OMX_QCOM_EXTRADATA_FRAMEINFO *)(p_extra->data);
if (frame_info->ePicType == OMX_VIDEO_PictureTypeI) {
if (venc_set_intra_vop_refresh((OMX_BOOL)true) == false)
DEBUG_PRINT_ERROR("%s Error in requesting I Frame ", __func__);
}
break;
}
default:
DEBUG_PRINT_HIGH("Unknown Extradata 0x%x", (OMX_QCOM_EXTRADATATYPE)p_extra->eType);
break;
}
consumed_len += p_extra->nSize;
p_extra = (OMX_OTHER_EXTRADATATYPE *)((char *)p_extra + p_extra->nSize);
}
/*
* Below code is based on these points.
* 1) As _PQ_ not defined in Napali :
* 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) Normal ROI handling.
* By this time if client sets next ROI, then we shouldn't process new ROI here.
*/
struct roidata roi;
memset(&roi, 0, sizeof(struct roidata));
roi.dirty = false;
if (m_roi_enabled) {
get_roi_for_timestamp(roi, nTimeStamp);
}
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);
if (data->nSize > input_extradata_info.buffer_size - consumed_len) {
DEBUG_PRINT_ERROR("Buffer size (%lu) is less than ROI extradata size (%u)",
(input_extradata_info.buffer_size - consumed_len) ,data->nSize);
return false;
}
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);
data = (OMX_OTHER_EXTRADATATYPE *)((char *)data + data->nSize);
consumed_len += data->nSize;
}
if (m_roi_enabled) {
if (roi.dirty) {
DEBUG_PRINT_LOW("free roidata with timestamp %lld us", roi.timestamp);
free(roi.info.pRoiMBInfo);
roi.dirty = false;
}
}
#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");
if (pVirt)
munmap(pVirt, size);
return false; //This should be treated as fatal error
}
if (vqzip_sei_info.enabled && pVirt) {
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;
if (pVirt)
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;
OMX_OTHER_EXTRADATATYPE *p_clientextra = NULL;
if(venc_handle->m_client_output_extradata_mem_ptr && venc_handle->m_sExtraData
&& venc_handle->m_client_out_extradata_info.getSize() >=
output_extradata_info.buffer_size) {
p_clientextra = (OMX_OTHER_EXTRADATATYPE * )
((venc_handle->m_client_output_extradata_mem_ptr + index) ->pBuffer);
}
if (p_clientextra == NULL) {
DEBUG_PRINT_ERROR("Client Extradata buffers not allocated\n");
}
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:
{
append_extradata_mbidata(p_extra, p_extradata);
if(p_clientextra) {
append_extradata_mbidata(p_clientextra, p_extradata);
}
DEBUG_PRINT_LOW("MBI Extradata = 0x%x", *((OMX_U32 *)p_extra->data));
break;
}
case MSM_VIDC_EXTRADATA_METADATA_LTR:
{
append_extradata_ltrinfo(p_extra, p_extradata);
if(p_clientextra) {
append_extradata_ltrinfo(p_clientextra, p_extradata);
}
DEBUG_PRINT_LOW("LTRInfo Extradata = 0x%x", *((OMX_U32 *)p_extra->data));
break;
}
case MSM_VIDC_EXTRADATA_NONE:
append_extradata_none(p_extra);
if(p_clientextra) {
append_extradata_none(p_clientextra);
}
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);
if(p_clientextra) {
p_clientextra = (OMX_OTHER_EXTRADATATYPE *)(((char *)p_clientextra) + p_clientextra->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);
case NV12_UBWC:
return venc_set_color_format((OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed);
default:
return false;
}
} else {
color_format = 0;
rc = false;
}
return rc;
}
OMX_ERRORTYPE venc_dev::venc_get_supported_profile_level(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
struct v4l2_queryctrl profile_cap, level_cap;
int v4l2_profile;
int avc_profiles[5] = { QOMX_VIDEO_AVCProfileConstrainedBaseline,
QOMX_VIDEO_AVCProfileBaseline,
QOMX_VIDEO_AVCProfileMain,
QOMX_VIDEO_AVCProfileConstrainedHigh,
QOMX_VIDEO_AVCProfileHigh };
int hevc_profiles[3] = { OMX_VIDEO_HEVCProfileMain,
OMX_VIDEO_HEVCProfileMain10HDR10,
OMX_VIDEO_HEVCProfileMainStill };
if (!profileLevelType)
return OMX_ErrorBadParameter;
memset(&level_cap, 0, sizeof(struct v4l2_queryctrl));
memset(&profile_cap, 0, sizeof(struct v4l2_queryctrl));
if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) {
level_cap.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
profile_cap.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
} else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) {
level_cap.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL;
} else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) {
level_cap.id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL;
profile_cap.id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE;
} else {
DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported Invalid codec");
return OMX_ErrorInvalidComponent;
}
if (profile_cap.id) {
if(!venc_query_cap(profile_cap)) {
DEBUG_PRINT_ERROR("Getting capabilities for profile failed");
return OMX_ErrorHardware;
}
}
if (level_cap.id) {
if(!venc_query_cap(level_cap)) {
DEBUG_PRINT_ERROR("Getting capabilities for level failed");
return OMX_ErrorHardware;
}
}
/* Get the corresponding omx level from v4l2 level */
if (!profile_level_converter::convert_v4l2_level_to_omx(m_sVenc_cfg.codectype, level_cap.maximum, (int *)&profileLevelType->eLevel)) {
DEBUG_PRINT_ERROR("Invalid level, cannot find corresponding v4l2 level : %d ", level_cap.maximum);
return OMX_ErrorHardware;
}
/* For given profile index get corresponding profile that needs to be supported */
if (profileLevelType->nPortIndex != 1) {
DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported should be queried on output port only %u",
(unsigned int)profileLevelType->nPortIndex);
return OMX_ErrorBadPortIndex;
}
if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_H264) {
if (profileLevelType->nProfileIndex < (sizeof(avc_profiles)/sizeof(int))) {
profileLevelType->eProfile = avc_profiles[profileLevelType->nProfileIndex];
} else {
DEBUG_PRINT_LOW("AVC: get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u",
(unsigned int)profileLevelType->nProfileIndex);
return OMX_ErrorNoMore;
}
} else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) {
if (profileLevelType->nProfileIndex == 0) {
profileLevelType->eProfile = OMX_VIDEO_VP8ProfileMain;
} else {
DEBUG_PRINT_LOW("VP8: get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u",
(unsigned int)profileLevelType->nProfileIndex);
return OMX_ErrorNoMore;
}
/* Driver has no notion of VP8 profile and there is only one profile supported. Hence return here */
return OMX_ErrorNone;
} else if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_HEVC) {
if (profileLevelType->nProfileIndex < (sizeof(hevc_profiles)/sizeof(int))) {
profileLevelType->eProfile = hevc_profiles[profileLevelType->nProfileIndex];
} else {
DEBUG_PRINT_LOW("HEVC: get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %u",
(unsigned int)profileLevelType->nProfileIndex);
return OMX_ErrorNoMore;
}
}
/* Check if the profile is supported by driver or not */
/* During query caps of profile driver sends a mask of */
/* of all v4l2 profiles supported(in the flags field) */
if (!profile_level_converter::convert_omx_profile_to_v4l2(m_sVenc_cfg.codectype, profileLevelType->eProfile, &v4l2_profile)) {
DEBUG_PRINT_ERROR("Invalid profile, cannot find corresponding omx profile");
return OMX_ErrorHardware;
}
DEBUG_PRINT_INFO("v4l2 profile : %d flags : %d ", v4l2_profile, profile_cap.flags);
if(!((profile_cap.flags >> v4l2_profile) & 0x1)) {
DEBUG_PRINT_ERROR("%s: Invalid index corresponding profile not supported : %d ",__FUNCTION__, profileLevelType->eProfile);
eRet = OMX_ErrorNoMore;
}
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported for Input port returned Profile:%u, Level:%u",
(unsigned int)profileLevelType->eProfile, (unsigned int)profileLevelType->eLevel);
return eRet;
}
bool venc_dev::venc_get_supported_color_format(unsigned index, OMX_U32 *colorFormat) {
#ifdef _UBWC_
//we support following formats
//index 0 - Compressed (UBWC) Venus flavour of YUV420SP
//index 1 - Venus flavour of YUV420SP
//index 2 - Compressed (UBWC) TP10 (10bit packed)
//index 3 - Compressed (UBWC) Venus flavour of RGBA8888
//index 4 - Venus flavour of RGBA8888
//index 5 - opaque which internally maps to YUV420SP.
//index 6 - vannilla YUV420SP
//this can be extended in the future
int supportedFormats[] = {
[0] = QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mCompressed,
[1] = QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m,
[2] = QOMX_COLOR_FormatYVU420SemiPlanar,
[3] = QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m10bitCompressed,
[4] = QOMX_COLOR_Format32bitRGBA8888Compressed,
[5] = QOMX_COLOR_Format32bitRGBA8888,
[6] = QOMX_COLOR_FormatAndroidOpaque,
[7] = OMX_COLOR_FormatYUV420SemiPlanar,
};
#else
//we support two formats
//index 0 - Venus flavour of YUV420SP
//index 1 - opaque which internally maps to YUV420SP.
//index 2 - vannilla YUV420SP
//this can be extended in the future
int supportedFormats[] = {
[0] = QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m,
[1] = QOMX_COLOR_FormatYVU420SemiPlanar,
[2] = QOMX_COLOR_FormatAndroidOpaque,
[3] = OMX_COLOR_FormatYUV420SemiPlanar,
};
#endif
if (index > (sizeof(supportedFormats)/sizeof(*supportedFormats) - 1))
return false;
*colorFormat = supportedFormats[index];
return true;
}
OMX_ERRORTYPE venc_dev::allocate_extradata(struct extradata_buffer_info *extradata_info, int flags)
{
if (extradata_info->allocated) {
DEBUG_PRINT_HIGH("2nd allocation return for port = %d",extradata_info->port_index);
return OMX_ErrorNone;
}
#ifdef USE_ION
if (extradata_info->buffer_size) {
if (extradata_info->ion.ion_alloc_data.handle) {
munmap((void *)extradata_info->uaddr, extradata_info->size);
close(extradata_info->ion.fd_ion_data.fd);
venc_handle->free_ion_memory(&extradata_info->ion);
}
extradata_info->size = (extradata_info->size + 4095) & (~4095);
extradata_info->ion.ion_device_fd = venc_handle->alloc_map_ion_memory(
extradata_info->size,
&extradata_info->ion.ion_alloc_data,
&extradata_info->ion.fd_ion_data, flags);
if (extradata_info->ion.ion_device_fd < 0) {
DEBUG_PRINT_ERROR("Failed to alloc extradata memory\n");
return OMX_ErrorInsufficientResources;
}
extradata_info->uaddr = (char *)mmap(NULL,
extradata_info->size,
PROT_READ|PROT_WRITE, MAP_SHARED,
extradata_info->ion.fd_ion_data.fd , 0);
if (extradata_info->uaddr == MAP_FAILED) {
DEBUG_PRINT_ERROR("Failed to map extradata memory\n");
close(extradata_info->ion.fd_ion_data.fd);
venc_handle->free_ion_memory(&extradata_info->ion);
return OMX_ErrorInsufficientResources;
}
extradata_info->m_ion_dev = open("/dev/ion", O_RDONLY);
}
#endif
extradata_info->allocated = OMX_TRUE;
return OMX_ErrorNone;
}
void venc_dev::free_extradata(struct extradata_buffer_info *extradata_info)
{
#ifdef USE_ION
if (extradata_info == NULL) {
return;
}
if (extradata_info->uaddr) {
munmap((void *)extradata_info->uaddr, extradata_info->size);
extradata_info->uaddr = NULL;
close(extradata_info->ion.fd_ion_data.fd);
venc_handle->free_ion_memory(&extradata_info->ion);
}
if (extradata_info->m_ion_dev)
close(extradata_info->m_ion_dev);
memset(extradata_info, 0, sizeof(*extradata_info));
extradata_info->ion.fd_ion_data.fd = -1;
extradata_info->allocated = OMX_FALSE;
#endif // USE_ION
}
void venc_dev::free_extradata_all()
{
free_extradata(&output_extradata_info);
free_extradata(&input_extradata_info);
}
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, uint64_t timestamp)
{
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_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_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_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) {
int fps = m_sVenc_cfg.fps_num / m_sVenc_cfg.fps_den;
IvfFileHeader ivfFileHeader(false, m_sVenc_cfg.input_width,
m_sVenc_cfg.input_height, fps, 1, 0);
fwrite(&ivfFileHeader, sizeof(ivfFileHeader), 1, m_debug.outfile);
}
}
if (m_debug.outfile && buffer_len) {
if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_VP8) {
IvfFrameHeader ivfFrameHeader(buffer_len, timestamp);
fwrite(&ivfFrameHeader, sizeof(ivfFrameHeader), 1, m_debug.outfile);
}
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_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_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, minqp = 0, maxqp = 127;
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");
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_rotation.rotation = 0;
m_codec = codec;
downscalar_enabled = OMX_FALSE;
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;
idrperiod.idrperiod = 1;
minqp = 0;
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;
minqp = 0;
maxqp = 127;
} else if (codec == OMX_VIDEO_CodingHEVC || codec == OMX_VIDEO_CodingHEIC) {
m_sVenc_cfg.codectype = V4L2_PIX_FMT_HEVC;
idrperiod.idrperiod = 1;
minqp = 0;
maxqp = 51;
if (codec == OMX_VIDEO_CodingHEIC)
codec_profile.profile = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC;
else
codec_profile.profile = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN;
profile_level.level = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1;
} else if (codec == QOMX_VIDEO_CodingTME) {
m_sVenc_cfg.codectype = V4L2_PIX_FMT_TME;
}
session_ipb_qp_values.min_i_qp = minqp;
session_ipb_qp_values.max_i_qp = maxqp;
session_ipb_qp_values.min_p_qp = minqp;
session_ipb_qp_values.max_p_qp = maxqp;
session_ipb_qp_values.min_b_qp = minqp;
session_ipb_qp_values.max_b_qp = 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++;
}
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;
if (m_sVenc_cfg.codectype != V4L2_PIX_FMT_TME) {
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");
}
/* Enable Low power mode by default for better power */
input_extradata_info.port_index = OUTPUT_PORT;
output_extradata_info.port_index = CAPTURE_PORT;
if (m_sVenc_cfg.codectype == V4L2_PIX_FMT_TME) {
control.id = V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION;
ret = ioctl(m_nDriver_fd, VIDIOC_G_CTRL,&control);
if (ret) {
DEBUG_PRINT_ERROR("Failed to read TME version");
return false;
}
venc_handle->tme_payload_version = control.value;
DEBUG_PRINT_HIGH("TME version is 0x%x", control.value);
}
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 _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_dimensions(OMX_U32 portIndex, OMX_U32 *w, OMX_U32 *h) {
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = portIndex == PORT_INDEX_OUT ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
if (ioctl(m_nDriver_fd, VIDIOC_G_FMT, &fmt)) {
DEBUG_PRINT_ERROR("Failed to get format on %s port",
portIndex == PORT_INDEX_OUT ? "capture" : "output");
return false;
}
*w = fmt.fmt.pix_mp.width;
*h = fmt.fmt.pix_mp.height;
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;
unsigned int buf_size = 0, extra_data_size = 0, client_extra_data_size = 0;
int ret;
int extra_idx = 0;
struct v4l2_control control;
unsigned int minCount = 0;
memset(&control, 0, sizeof(control));
memset(&fmt, 0, sizeof(fmt));
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);
if (ret) {
DEBUG_PRINT_ERROR("set format failed, type %d, wxh %dx%d, format %#x, colorspace %d\n",
fmt.type, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
fmt.fmt.pix_mp.pixelformat, fmt.fmt.pix_mp.colorspace);
return false;
}
m_sInput_buff_property.datasize=fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
control.id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT;
ret = ioctl(m_nDriver_fd, VIDIOC_G_CTRL, &control);
if (ret || (unsigned int)control.value > MAX_V4L2_BUFS) {
DEBUG_PRINT_ERROR("Driver returned invalid data, port = %d ret = %d Count = %d",
port, ret, (unsigned int)control.value);
return false;
}
// Increase buffer-header count for metadata-mode on input port
// to improve buffering and reduce bottlenecks in clients
if (metadatamode) {
DEBUG_PRINT_LOW("FW returned buffer count = %d , overwriting with 9",
control.value);
minCount = 9;
}
if (m_sVenc_cfg.input_height * m_sVenc_cfg.input_width >= 3840*2160) {
DEBUG_PRINT_LOW("Increasing buffer count = %d to 11", minCount);
minCount = 11;
}
// Request MAX_V4L2_BUFS from V4L2 in batch mode.
// Keep the original count for the client
if (metadatamode && mBatchSize) {
minCount = MAX_V4L2_BUFS;
DEBUG_PRINT_LOW("Set buffer count = %d as metadata mode and batchmode enabled", minCount);
}
minCount = MAX((unsigned int)control.value, minCount);
m_sInput_buff_property.mincount = minCount;
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);
if (ret) {
DEBUG_PRINT_ERROR("get format failed, type %d, wxh %dx%d, format %#x\n",
fmt.type, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
fmt.fmt.pix_mp.pixelformat);
return false;
}
m_sInput_buff_property.datasize=fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
if (m_sInput_buff_property.actualcount < m_sInput_buff_property.mincount)
m_sInput_buff_property.actualcount = m_sInput_buff_property.mincount;
*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 false;
}
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);
if (ret) {
DEBUG_PRINT_ERROR("set format failed, type %d, wxh %dx%d, format %#x\n",
fmt.type, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
fmt.fmt.pix_mp.pixelformat);
return false;
}
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);
if (ret) {
DEBUG_PRINT_ERROR("get format failed, type %d, wxh %dx%d, format %#x\n",
fmt.type, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
fmt.fmt.pix_mp.pixelformat);
return false;
}
m_sOutput_buff_property.datasize=fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
control.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
ret = ioctl(m_nDriver_fd, VIDIOC_G_CTRL, &control);
if (ret || (unsigned int)control.value > MAX_V4L2_BUFS) {
DEBUG_PRINT_ERROR("Driver returned invalid data port = %d ret = %d Count = %d",
port, ret, (unsigned int)control.value);
return false;
}
minCount = control.value;
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
minCount = MAX((unsigned int)control.value, mBatchSize) + mBatchSize;
DEBUG_PRINT_LOW("set min count %d as mBatchSize %d", minCount, mBatchSize);
}
m_sOutput_buff_property.mincount = minCount;
if (m_sOutput_buff_property.actualcount < m_sOutput_buff_property.mincount)
m_sOutput_buff_property.actualcount = m_sOutput_buff_property.mincount;
*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 false;
}
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;
venc_handle->m_client_out_extradata_info.set_extradata_info(extra_data_size,m_sOutput_buff_property.actualcount);
}
DEBUG_PRINT_HIGH("venc_get_buf_req: port %d, wxh %dx%d, format %#x, driver min count %d, "
"updated min count %d, act count %d, size %d, num planes %d",
port, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height, fmt.fmt.pix_mp.pixelformat,
control.value, *min_buff_count, *actual_buff_count, *buff_size, fmt.fmt.pix_mp.num_planes);
return true;
}
bool venc_dev::venc_set_param(void *paramData, OMX_INDEXTYPE index)
{
DEBUG_PRINT_LOW("venc_set_param index 0x%x", index);
struct v4l2_format fmt;
struct v4l2_requestbuffers bufreq;
int ret;
bool isCBR;
switch ((int)index) {
case OMX_IndexParamPortDefinition:
{
OMX_PARAM_PORTDEFINITIONTYPE *portDefn;
portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData;
if (portDefn->nPortIndex == PORT_INDEX_IN) {
if (!venc_set_encode_framerate(portDefn->format.video.xFramerate)) {
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");
}
}
unsigned long inputformat = venc_get_color_format(portDefn->format.video.eColorFormat);
if (m_sVenc_cfg.input_height != portDefn->format.video.nFrameHeight ||
m_sVenc_cfg.input_width != portDefn->format.video.nFrameWidth ||
m_sInput_buff_property.actualcount != portDefn->nBufferCountActual ||
m_sVenc_cfg.inputformat != inputformat) {
DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamPortDefinition: port: %u, WxH %lux%lu --> %ux%u, count %lu --> %u, format %#lx --> %#lx",
portDefn->nPortIndex, m_sVenc_cfg.input_width, m_sVenc_cfg.input_height,
portDefn->format.video.nFrameWidth, portDefn->format.video.nFrameHeight,
m_sInput_buff_property.actualcount, portDefn->nBufferCountActual,
m_sVenc_cfg.inputformat, inputformat);
if (portDefn->nBufferCountActual < m_sInput_buff_property.mincount) {
DEBUG_PRINT_LOW("Actual count %u is less than driver mincount %lu on port %u",
portDefn->nBufferCountActual, m_sInput_buff_property.mincount, portDefn->nPortIndex);
return false;
}
m_sVenc_cfg.input_height = portDefn->format.video.nFrameHeight;
m_sVenc_cfg.input_width = portDefn->format.video.nFrameWidth;
m_sVenc_cfg.inputformat = inputformat;
m_sInput_buff_property.actualcount = portDefn->nBufferCountActual;
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("set format failed, type %d, wxh %dx%d, pixelformat %#x, colorspace %#x",
fmt.type, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
fmt.fmt.pix_mp.pixelformat, fmt.fmt.pix_mp.colorspace);
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("reqbufs failed, type %d, count %d", bufreq.type, bufreq.count);
return false;
}
if (num_input_planes > 1)
input_extradata_info.count = m_sInput_buff_property.actualcount + 1;
if (!downscalar_enabled) {
if (m_rotation.rotation == 90 || m_rotation.rotation == 270) {
m_sVenc_cfg.dvs_height = portDefn->format.video.nFrameWidth;
m_sVenc_cfg.dvs_width = portDefn->format.video.nFrameHeight;
} else {
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;
} else {
DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamPortDefinition: parameters not changed on port %d",
portDefn->nPortIndex);
}
} else if (portDefn->nPortIndex == PORT_INDEX_OUT) {
unsigned long codectype = venc_get_codectype(portDefn->format.video.eCompressionFormat);
if (portDefn->format.video.eCompressionFormat == OMX_VIDEO_CodingHEIC) {
portDefn->format.video.nFrameWidth = DEFAULT_TILE_DIMENSION;
portDefn->format.video.nFrameHeight = DEFAULT_TILE_DIMENSION;
DEBUG_PRINT_HIGH("set_parameter: OMX_IndexParamPortDefinition: port %d, wxh (for HEIC coding type) %dx%d",
portDefn->nPortIndex, portDefn->format.video.nFrameWidth,
portDefn->format.video.nFrameHeight);
}
//Don't worry about width/height if downscalar is enabled.
if (((m_sVenc_cfg.dvs_height != portDefn->format.video.nFrameHeight ||
m_sVenc_cfg.dvs_width != portDefn->format.video.nFrameWidth) && !downscalar_enabled) ||
m_sOutput_buff_property.actualcount != portDefn->nBufferCountActual ||
m_sVenc_cfg.codectype != codectype) {
if (portDefn->nBufferCountActual < m_sOutput_buff_property.mincount) {
DEBUG_PRINT_LOW("Actual count %u is less than driver mincount %lu on port %u",
portDefn->nBufferCountActual, m_sOutput_buff_property.mincount, portDefn->nPortIndex);
return false;
}
//If downscalar is enabled. Correct width/height is populated no need to replace with port def width/height
if (!downscalar_enabled) {
DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamPortDefinition: port: %u, WxH %lux%lu --> %ux%u, count %lu --> %u, format %#lx --> %#lx",
portDefn->nPortIndex, m_sVenc_cfg.dvs_width, m_sVenc_cfg.dvs_height,
portDefn->format.video.nFrameWidth, portDefn->format.video.nFrameHeight,
m_sOutput_buff_property.actualcount, portDefn->nBufferCountActual,
m_sVenc_cfg.codectype, codectype);
m_sVenc_cfg.dvs_height = portDefn->format.video.nFrameHeight;
m_sVenc_cfg.dvs_width = portDefn->format.video.nFrameWidth;
}
m_sVenc_cfg.codectype = codectype;
m_sOutput_buff_property.actualcount = portDefn->nBufferCountActual;
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("set format failed, type %d, wxh %dx%d, pixelformat %#x",
fmt.type, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
fmt.fmt.pix_mp.pixelformat);
hw_overload = errno == EBUSY;
return false;
}
m_sOutput_buff_property.datasize = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
if (m_sVenc_cfg.codectype != V4L2_PIX_FMT_TME) {
if (!venc_set_target_bitrate(portDefn->format.video.nBitrate)) {
return false;
}
}
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("reqbufs failed, type %d, count %d", bufreq.type, bufreq.count);
return false;
}
if (num_output_planes > 1)
output_extradata_info.count = m_sOutput_buff_property.actualcount;
//reset rotation as output port dimension is changed
m_rotation.rotation = 0;
venc_handle->m_sConfigFrameRotation.nRotation = 0;
} else {
DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamPortDefinition: parameters not changed on port %d",
portDefn->nPortIndex);
}
} else {
DEBUG_PRINT_ERROR("ERROR: Invalid Port Index (%d) for OMX_IndexParamPortDefinition", portDefn->nPortIndex);
}
}
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)) {
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)) {
DEBUG_PRINT_ERROR("ERROR: Setting Target Bit Rate / Quality Factor 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_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);
if (!venc_set_profile (pParam->eProfile)) {
DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating Profile %d",
pParam->eProfile);
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_level(OMX_VIDEO_LEVEL_UNKNOWN)) {
DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating level to unknown");
return false;
}
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(V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB, 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;
//TODO: Set VP8 level/profile currently based on driver change
if (!venc_set_profile (pParam->eProfile)) {
DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating Profile %d",
pParam->eProfile);
return false;
}
if (!venc_set_level (OMX_VIDEO_LEVEL_UNKNOWN)) {
DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating level to unknown");
return false;
}
if(venc_set_vpx_error_resilience(pParam->bErrorResilientMode) == false) {
DEBUG_PRINT_ERROR("ERROR: Failed to set vpx error resilience");
return false;
}
break;
}
case (OMX_INDEXTYPE)OMX_IndexParamVideoHevc:
{
DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoHevc");
OMX_VIDEO_PARAM_HEVCTYPE* pParam = (OMX_VIDEO_PARAM_HEVCTYPE*)paramData;
if (!venc_set_profile (pParam->eProfile)) {
DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating Profile %d",
pParam->eProfile);
return false;
}
if (!venc_set_level (OMX_VIDEO_LEVEL_UNKNOWN)) {
DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating level to unknown");
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_den ? 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_INDEXTYPE)OMX_IndexParamVideoTme:
{
DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoTme");
QOMX_VIDEO_PARAM_TMETYPE * pParam = (QOMX_VIDEO_PARAM_TMETYPE*)paramData;
if (!venc_set_profile(pParam->eProfile)) {
DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating Profile %d",
pParam->eProfile);
return false;
}
if (!venc_set_level(pParam->eLevel)) {
DEBUG_PRINT_ERROR("ERROR: Unsuccessful in updating level %d",
pParam->eLevel);
return false;
}
break;
}
case (OMX_INDEXTYPE)OMX_IndexParamVideoAndroidImageGrid:
{
DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoAndroidImageGrid");
OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE* pParam =
(OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE*)paramData;
if (m_codec != OMX_VIDEO_CodingHEIC) {
DEBUG_PRINT_ERROR("OMX_IndexParamVideoAndroidImageGrid is only supported for HEIC");
return false;
}
if (!venc_set_tile_dimension(pParam->nTileWidth)) {
DEBUG_PRINT_ERROR("ERROR: Failed to set tile dimension %d",
pParam->nTileWidth);
return false;
}
break;
}
case OMX_IndexParamVideoIntraRefresh:
{
DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoIntraRefresh");
OMX_VIDEO_PARAM_INTRAREFRESHTYPE *intra_refresh_param =
(OMX_VIDEO_PARAM_INTRAREFRESHTYPE *)paramData;
if (intra_refresh_param->nPortIndex == (OMX_U32) PORT_INDEX_OUT) {
intra_refresh.irmode = intra_refresh_param->eRefreshMode;
intra_refresh.mbcount = intra_refresh_param->nCirMBs;
intra_refresh.framecount = 0;
} 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 Error Correction failed");
return false;
}
} else {
DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_IndexParamVideoErrorCorrection");
}
break;
}
case OMX_QcomIndexParamVideoSliceSpacing:
{
DEBUG_PRINT_LOW("venc_set_param:OMX_QcomIndexParamVideoSliceSpacing");
QOMX_VIDEO_PARAM_SLICE_SPACING_TYPE *slice_spacing =
(QOMX_VIDEO_PARAM_SLICE_SPACING_TYPE*)paramData;
if (slice_spacing->nPortIndex == (OMX_U32) PORT_INDEX_OUT) {
if (!venc_set_multislice_cfg(slice_spacing->eSliceMode, slice_spacing->nSliceSize)) {
DEBUG_PRINT_ERROR("ERROR: Setting Slice Spacing failed");
return false;
}
} else {
DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for OMX_QcomIndexParamVideoSliceSpacing");
}
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) {
if (!venc_set_profile(profile_level->eProfile)) {
DEBUG_PRINT_ERROR("WARNING: Unsuccessful in updating Profile");
return false;
}
if (!venc_set_level(profile_level->eLevel)) {
DEBUG_PRINT_ERROR("WARNING: Unsuccessful in updating 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_qp(session_qp->nQpI,
session_qp->nQpP,
session_qp->nQpB,
ENABLE_I_QP | ENABLE_P_QP | ENABLE_B_QP) == 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:
{
DEBUG_PRINT_LOW("venc_set_param:QOMX_IndexParamVideoInitialQp");
QOMX_EXTNINDEX_VIDEO_INITIALQP *initial_qp =
(QOMX_EXTNINDEX_VIDEO_INITIALQP *)paramData;
if (initial_qp->nPortIndex == (OMX_U32) PORT_INDEX_OUT) {
if (venc_set_qp(initial_qp->nQpI,
initial_qp->nQpP,
initial_qp->nQpB,
initial_qp->bEnableInitQp) == false) {
DEBUG_PRINT_ERROR("ERROR: Setting Initial QP failed");
return false;
}
} else {
DEBUG_PRINT_ERROR("ERROR: Invalid Port Index for QOMX_IndexParamVideoInitialQp");
}
break;
}
case OMX_QcomIndexParamVideoIPBQPRange:
{
DEBUG_PRINT_LOW("venc_set_param:OMX_QcomIndexParamVideoIPBQPRange");
OMX_QCOM_VIDEO_PARAM_IPB_QPRANGETYPE *session_qp_range =
(OMX_QCOM_VIDEO_PARAM_IPB_QPRANGETYPE *)paramData;
if(session_qp_range->nPortIndex == (OMX_U32)PORT_INDEX_OUT) {
if ( venc_set_session_qp_range (session_qp_range) == false) {
DEBUG_PRINT_ERROR("ERROR: Setting QP range failed");
return false;
}
}
break;
}
case OMX_QcomIndexEnableSliceDeliveryMode:
{
QOMX_EXTNINDEX_PARAMTYPE* pParam =
(QOMX_EXTNINDEX_PARAMTYPE*)paramData;
if (pParam->nPortIndex == PORT_INDEX_OUT) {
if (venc_set_slice_delivery_mode(pParam->bEnable) == false) {
DEBUG_PRINT_ERROR("Setting slice delivery mode failed");
return false;
}
} else {
DEBUG_PRINT_ERROR("OMX_QcomIndexEnableSliceDeliveryMode "
"called on wrong port(%u)", (unsigned int)pParam->nPortIndex);
return false;
}
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_ExtraDataVideoLTRInfo:
{
DEBUG_PRINT_LOW("venc_set_param: OMX_ExtraDataVideoLTRInfo");
OMX_BOOL extra_data = *(OMX_BOOL *)(paramData);
if (venc_set_extradata(OMX_ExtraDataVideoLTRInfo, extra_data) == false) {
DEBUG_PRINT_ERROR("ERROR: Setting OMX_ExtraDataVideoLTRInfo failed");
return false;
}
extradata = true;
break;
}
case OMX_QcomIndexParamSequenceHeaderWithIDR:
{
PrependSPSPPSToIDRFramesParams * pParam =
(PrependSPSPPSToIDRFramesParams *)paramData;