blob: 573cf6e5c1f45cfe63db61d0470c426aae6b3a4e [file] [log] [blame]
/*--------------------------------------------------------------------------
Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora 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 Files
==========================================================================*/
#include <stdio.h>
#include <linux/msm_q6venc.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/android_pmem.h>
#include <fcntl.h>
#include "venc_device.h"
#include "venc_debug.h"
/*----------------------------------------------------------------------------
* Type Declarations
* -------------------------------------------------------------------------*/
struct venc_pmem_buffer
{
unsigned int phys;
unsigned int virt;
struct file *file;
struct venc_pmem pmem_buf;
};
static int ven_ref;
/**************************************************************************
* @brief Set buffer properties based on current config
*************************************************************************/
static int ven_set_default_buf_properties(struct ven_device* dvenc)
{
int ret = 0;
struct ven_base_cfg* pcfg;
if (dvenc == NULL) {
QC_OMX_MSG_ERROR("%s: null driver", __func__);
ret = -1;
}
pcfg = &(dvenc->config.base_config);
QC_OMX_MSG_HIGH("Update input buffer requirements pcfg: %p\n", pcfg);
dvenc->input_attrs.min_count = 1;
dvenc->input_attrs.actual_count = 6;
dvenc->input_attrs.suffix_size = 0;
dvenc->input_attrs.data_size = pcfg->input_width * pcfg->input_height * 3 / 2;
dvenc->input_attrs.alignment = VEN_PMEM_ALIGN;
QC_OMX_MSG_HIGH("Update output buffer requirements pcfg:%p \n", pcfg);
dvenc->output_attrs.min_count = 1;
dvenc->output_attrs.actual_count = 4;
dvenc->output_attrs.suffix_size = 0;
dvenc->output_attrs.data_size = pcfg->input_width * pcfg->input_height * 3 / 2;
dvenc->output_attrs.alignment = VEN_PMEM_ALIGN;
return ret;
}
/**********************************************************************//**
* @brief Updates the output buffer size requirements
*************************************************************************/
void ven_update_output_size(struct ven_device* dvenc)
{
int width = dvenc->config.base_config.dvs_width;
int height = dvenc->config.base_config.dvs_height;
if (dvenc->config.base_config.codec_type == VEN_CODEC_MPEG4)
{
switch (dvenc->config.profile_level.level)
{
case VEN_LEVEL_MPEG4_0:
case VEN_LEVEL_MPEG4_1:
dvenc->output_attrs.data_size = 10 << 11;
break;
case VEN_LEVEL_MPEG4_0B:
dvenc->output_attrs.data_size = 20 << 11;
break;
case VEN_LEVEL_MPEG4_2:
case VEN_LEVEL_MPEG4_3:
dvenc->output_attrs.data_size = 40 << 11;
break;
case VEN_LEVEL_MPEG4_4A:
dvenc->output_attrs.data_size = 80 << 11;
break;
case VEN_LEVEL_MPEG4_5:
dvenc->output_attrs.data_size = 112 << 11;
break;
case VEN_LEVEL_MPEG4_6:
dvenc->output_attrs.data_size = 248 << 11;
break;
}
dvenc->output_attrs.data_size = dvenc->output_attrs.data_size;
}
else if (dvenc->config.base_config.codec_type == VEN_CODEC_H263)
{
if (VEN_FRAME_SIZE_IN_RANGE(width, height, VEN_QCIF_DX, VEN_QCIF_DY))
{
dvenc->output_attrs.data_size = 20 << 11;
}
else if (VEN_FRAME_SIZE_IN_RANGE(width, height, VEN_CIF_DX, VEN_CIF_DY))
{
dvenc->output_attrs.data_size = 40 << 11;
}
else if (VEN_FRAME_SIZE_IN_RANGE(width, height, VEN_VGA_DX, VEN_VGA_DY))
{
dvenc->output_attrs.data_size = 80 << 11;
}
else if (VEN_FRAME_SIZE_IN_RANGE(width, height, VEN_PAL_DX, VEN_PAL_DY))
{
dvenc->output_attrs.data_size = 112 << 11;
}
else
{
dvenc->output_attrs.data_size = 248 << 11;
}
}
else
{
// Compression of 50% of the YUV size
dvenc->output_attrs.data_size = (int) (width * height * 0.5) * 3 / 2;
}
QC_OMX_MSG_HIGH("new out buf size: %d", dvenc->output_attrs.data_size);
}
static int ven_update_buf_properties(struct ven_device *dvenc)
{
int result = VENC_S_SUCCESS;
struct ven_base_cfg* pcfg;
if (dvenc == NULL) {
QC_OMX_MSG_ERROR("null driver");
result = VENC_S_EBADPARAM;
}
pcfg = &dvenc->config.base_config;
dvenc->input_attrs.data_size = pcfg->input_height * pcfg->input_width * 3 / 2;
ven_update_output_size(dvenc);
return result;
}
/**************************************************************************
* @brief Set the default driver configuration.
*************************************************************************/
static int ven_set_default_config(struct ven_device *dvenc)
{
int ret = 0;
struct ven_config_type *pconfig;
pconfig = &(dvenc->config);
QC_OMX_MSG_HIGH("%s: pconfig: %p base_cfg %p \n", __func__, pconfig, &(pconfig->base_config) );
// base configuration MPEG4 720p @ 30fps / 8Mbps
pconfig->base_config.input_width = 1280;
pconfig->base_config.input_height = 720;
pconfig->base_config.dvs_width = 1280;
pconfig->base_config.dvs_height = 720;
pconfig->base_config.codec_type = VEN_CODEC_MPEG4;
pconfig->base_config.fps_num = 24;
pconfig->base_config.fps_den = 1;
pconfig->base_config.target_bitrate = 6000000;
pconfig->base_config.input_format = VEN_INPUTFMT_NV21;
// profile and level setting for 720p
pconfig->profile.profile = VEN_PROFILE_MPEG4_SP;
pconfig->profile_level.level = VEN_LEVEL_MPEG4_6;
// variable bitrate with frame skip
pconfig->rate_control.rc_mode = VEN_RC_VBR_CFR;
// disable slicing
pconfig->multi_slice.mslice_mode = VENC_SLICE_MODE_DEFAULT;
pconfig->multi_slice.mslice_size = 0;
// no rotation
pconfig->rotation.rotation = VEN_ROTATION_0;
// default bitrate
pconfig->bitrate.target_bitrate = pconfig->base_config.target_bitrate;
// default frame rate
pconfig->frame_rate.fps_numerator = pconfig->base_config.fps_num;
pconfig->frame_rate.fps_denominator = pconfig->base_config.fps_den;
// disable int ra refresh
pconfig->intra_refresh.mb_count = 0;
// two second int ra period
pconfig->intra_period.num_pframes = pconfig->base_config.fps_num * 2 - 1;
// conservative QP setting
pconfig->session_qp.iframe_qp = 14;
pconfig->session_qp.pframe_qp = 14;
// full QP range
pconfig->qp_range.min_qp = 2;
pconfig->qp_range.max_qp = 31;
// 2 ticks per frame
pconfig->vop_timing.vop_time_resolution = pconfig->base_config.fps_num * 2;
// enable AC prediction
pconfig->ac_prediction.status = 0;
// disable error resilience
pconfig->short_header.status = 0;
pconfig->hec_interval.header_extension = 0;
pconfig->data_partition.status = 0;
return ret;
}
static void ven_change_codec(struct ven_device * dvenc)
{
struct ven_config_type *pconfig =&(dvenc->config);
QC_OMX_MSG_HIGH("%s \n", __func__);
if (pconfig->base_config.codec_type == VEN_CODEC_MPEG4)
{
pconfig->qp_range.min_qp = 2;
pconfig->qp_range.max_qp = 31;
pconfig->multi_slice.mslice_mode = VENC_SLICE_MODE_DEFAULT;
pconfig->multi_slice.mslice_size = 0;
pconfig->profile.profile = VEN_PROFILE_MPEG4_SP;
pconfig->profile_level.level = VEN_LEVEL_MPEG4_6;
pconfig->session_qp.iframe_qp = 14;
pconfig->session_qp.pframe_qp = 14;
pconfig->short_header.status = 0;
pconfig->hec_interval.header_extension = 0;
pconfig->data_partition.status = 0;
}
else if (pconfig->base_config.codec_type == VEN_CODEC_H263)
{
pconfig->qp_range.min_qp = 2;
pconfig->qp_range.max_qp = 31;
pconfig->multi_slice.mslice_mode = VENC_SLICE_MODE_DEFAULT;
pconfig->multi_slice.mslice_size = 0;
pconfig->profile.profile = VEN_PROFILE_H263_BASELINE;
pconfig->profile_level.level = VEN_LEVEL_H263_70;
pconfig->session_qp.iframe_qp = 14;
pconfig->session_qp.pframe_qp = 14;
pconfig->short_header.status = 0;
pconfig->ac_prediction.status = 0;
pconfig->hec_interval.header_extension = 0;
pconfig->data_partition.status = 0;
}
else if (pconfig->base_config.codec_type == VEN_CODEC_H264)
{
pconfig->qp_range.min_qp = 2;
pconfig->qp_range.max_qp = 51;
pconfig->multi_slice.mslice_mode = VENC_SLICE_MODE_DEFAULT;
pconfig->multi_slice.mslice_size = 0;
pconfig->profile.profile = VEN_PROFILE_H264_BASELINE;
pconfig->profile_level.level = VEN_LEVEL_H264_3P1;
pconfig->session_qp.iframe_qp = 30;
pconfig->session_qp.pframe_qp = 30;
pconfig->short_header.status = 0;
pconfig->ac_prediction.status = 0;
pconfig->hec_interval.header_extension = 0;
pconfig->data_partition.status = 0;
}
else
{
QC_OMX_MSG_ERROR("invalid codec type");
}
}
/**************************************************************************
* @brief Validate the given encoder configuration
*************************************************************************/
static int ven_validate_config(struct ven_config_type* pconfig)
{
return 0;
}
/**************************************************************************
* @brief Print out configuration
*************************************************************************/
static void ven_print_config(struct venc_q6_config* pconfig)
{
QC_OMX_MSG_PROFILE("Config for video encoder \n");
QC_OMX_MSG_PROFILE("config standard=%d, input_frame_height=%d, input_frame_width=%d \n",
(int ) pconfig->config_params.standard,
(int ) pconfig->config_params.input_frame_height,
(int ) pconfig->config_params.input_frame_width);
QC_OMX_MSG_PROFILE("config output_frame_height=%d, output_frame_width=%d, rotation_angle=%d \n",
(int ) pconfig->config_params.output_frame_height,
(int ) pconfig->config_params.output_frame_width,
(int ) pconfig->config_params.rotation_angle);
QC_OMX_MSG_PROFILE("config intra_period=%d \n",
(int ) pconfig->config_params.intra_period);
QC_OMX_MSG_PROFILE("config rate_control=%d \n",
(int ) pconfig->config_params.rate_control);
////////////////////////////////////////
//////////////////////// slice
QC_OMX_MSG_PROFILE("config mslice_mode=%d, slice_size=%d \n",
(int ) pconfig->config_params.slice_config.slice_mode,
(int ) pconfig->config_params.slice_config.units_per_slice);
////////////////////////////////////////
//////////////////////// quality
QC_OMX_MSG_PROFILE("config frame_numerator=%d, fps_denominator=%d, bitrate=%d \n",
(int ) pconfig->config_params.frame_rate.frame_rate_num,
(int ) pconfig->config_params.frame_rate.frame_rate_den,
(int ) pconfig->config_params.bitrate);
QC_OMX_MSG_PROFILE("config iframe_qp=%d, pframe_qp=%d, min_qp=%d \n",
(int ) pconfig->config_params.iframe_qp,
(int ) pconfig->config_params.pframe_qp,
(int ) pconfig->config_params.qp_range.min_qp);
QC_OMX_MSG_PROFILE("config max_qp=%d",
(int ) pconfig->config_params.qp_range.max_qp);
////////////////////////////////////////
//////////////////////// mp4
if (pconfig->config_params.standard == VENC_CODEC_MPEG4)
{
QC_OMX_MSG_PROFILE("config mp4 profile=%d, level=%d, time_resolution=%d \n",
(int ) pconfig->codec_params.mpeg4_params.profile,
(int ) pconfig->codec_params.mpeg4_params.level,
(int ) pconfig->codec_params.mpeg4_params.time_resolution);
QC_OMX_MSG_PROFILE("config ac_prediction=%d, hec_interval=%d, data_partition=%d \n",
(int ) pconfig->codec_params.mpeg4_params.ac_prediction,
(int ) pconfig->codec_params.mpeg4_params.hec_interval,
(int ) pconfig->codec_params.mpeg4_params.data_partition);
QC_OMX_MSG_HIGH("config short_header=%d",
(int ) pconfig->codec_params.mpeg4_params.short_header);
}
////////////////////////////////////////
//////////////////////// h263
else if (pconfig->config_params.standard == VENC_CODEC_H263)
{
QC_OMX_MSG_PROFILE("config h263 profile=%d, level=%d \n",
(int ) pconfig->codec_params.h263_params.profile,
(int ) pconfig->codec_params.h263_params.level);
}
////////////////////////////////////////
//////////////////////// h264
else if (pconfig->config_params.standard == VENC_CODEC_H264)
{
QC_OMX_MSG_PROFILE("config h264 profile=%d, level=%d \n",
(int ) pconfig->codec_params.h264_params.profile,
(int ) pconfig->codec_params.h264_params.level);
}
}
/**************************************************************************
* @brief Translate driver to Q6 config
*************************************************************************/
static int ven_translate_config(struct ven_config_type* psrc,
union venc_codec_config* pcodec,
struct venc_common_config* pcommon)
{
int ret = 0;
if (psrc == NULL ||
pcommon == NULL ||
pcodec == NULL) {
QC_OMX_MSG_ERROR( "%s: failed with null parameter \n", __func__);
}
memset(pcommon, 0, sizeof(*pcommon));
memset(pcodec, 0, sizeof(*pcodec));
// codec specific
if (psrc->base_config.codec_type == VEN_CODEC_MPEG4)
{
struct venc_mpeg4_config* pmp4 = &(pcodec->mpeg4_params);
QC_OMX_MSG_HIGH("Configuring for mpeg4... psrc = %p\n",psrc);
pcommon->standard = VENC_CODEC_MPEG4;
if (psrc->profile.profile == VEN_PROFILE_MPEG4_SP) {
pmp4->profile = VENC_MPEG4_PROFILE_SIMPLE;
}
else
QC_OMX_MSG_ERROR("Invalid mp4 configuration \n");
switch (psrc->profile_level.level)
{
case VEN_LEVEL_MPEG4_0:
pmp4->level = VENC_MPEG4_LEVEL_0;
break;
case VEN_LEVEL_MPEG4_0B:
pmp4->level = VENC_MPEG4_LEVEL_0B;
break;
case VEN_LEVEL_MPEG4_1:
pmp4->level = VENC_MPEG4_LEVEL_1;
break;
case VEN_LEVEL_MPEG4_2:
pmp4->level = VENC_MPEG4_LEVEL_2;
break;
case VEN_LEVEL_MPEG4_3:
pmp4->level = VENC_MPEG4_LEVEL_3;
break;
case VEN_LEVEL_MPEG4_4A:
pmp4->level = VENC_MPEG4_LEVEL_4A;
break;
case VEN_LEVEL_MPEG4_5:
pmp4->level = VENC_MPEG4_LEVEL_5;
break;
case VEN_LEVEL_MPEG4_6:
pmp4->level = VENC_MPEG4_LEVEL_6;
break;
default:
QC_OMX_MSG_ERROR("invalid level specified %d",
(int) psrc->profile_level.level);
break;
}
pmp4->time_resolution = psrc->vop_timing.vop_time_resolution;
pmp4->ac_prediction = psrc->ac_prediction.status == 1 ? 1 : 0;
pmp4->hec_interval = psrc->hec_interval.header_extension; /// @int egrate need to have HEC int erval in driver api. also fix this hack in the OMX layer
pmp4->data_partition = psrc->data_partition.status == 1 ? 1 : 0;
pmp4->short_header = psrc->short_header.status == 1 ? 1 : 0;
}
else if (psrc->base_config.codec_type == VEN_CODEC_H263)
{
struct venc_h263_config* p263 = &(pcodec->h263_params);
QC_OMX_MSG_HIGH("Configuring for h263...");
pcommon->standard = VENC_CODEC_H263;
if (psrc->profile.profile == VEN_PROFILE_H263_BASELINE)
{
p263->profile = VENC_H263_PROFILE_P0;
}
else
{
QC_OMX_MSG_ERROR("invalid profile %d",
(int) psrc->profile.profile);
}
switch (psrc->profile_level.level)
{
case VEN_LEVEL_H263_10:
p263->level = VENC_H263_LEVEL_10;
break;
case VEN_LEVEL_H263_20:
p263->level = VENC_H263_LEVEL_20;
break;
case VEN_LEVEL_H263_30:
p263->level = VENC_H263_LEVEL_30;
break;
case VEN_LEVEL_H263_40:
p263->level = VENC_H263_LEVEL_40;
break;
case VEN_LEVEL_H263_45:
p263->level = VENC_H263_LEVEL_45;
break;
case VEN_LEVEL_H263_50:
p263->level = VENC_H263_LEVEL_50;
break;
case VEN_LEVEL_H263_60:
p263->level = VENC_H263_LEVEL_60;
break;
case VEN_LEVEL_H263_70:
p263->level = VENC_H263_LEVEL_70;
break;
default:
QC_OMX_MSG_ERROR("invalid level specified %d",
(int) psrc->profile_level.level);
break;
}
}
else if (psrc->base_config.codec_type == VEN_CODEC_H264)
{
struct venc_h264_config* p264 = &(pcodec->h264_params);
QC_OMX_MSG_HIGH("Configuring for h264...");
pcommon->standard = VENC_CODEC_H264;
if (psrc->profile.profile == VEN_PROFILE_H264_BASELINE)
{
p264->profile = VENC_H264_PROFILE_BASELINE;
}
else
{
QC_OMX_MSG_ERROR("invalid profile %d",
(int) psrc->profile.profile);
}
switch (psrc->profile_level.level)
{
case VEN_LEVEL_H264_1:
p264->level = VENC_H264_LEVEL_1;
break;
case VEN_LEVEL_H264_1B:
p264->level = VENC_H264_LEVEL_1B;
break;
case VEN_LEVEL_H264_1P1:
p264->level = VENC_H264_LEVEL_1P1;
break;
case VEN_LEVEL_H264_1P2:
p264->level = VENC_H264_LEVEL_1P2;
break;
case VEN_LEVEL_H264_1P3:
p264->level = VENC_H264_LEVEL_1P3;
break;
case VEN_LEVEL_H264_2:
p264->level = VENC_H264_LEVEL_2;
break;
case VEN_LEVEL_H264_2P1:
p264->level = VENC_H264_LEVEL_2P1;
break;
case VEN_LEVEL_H264_2P2:
p264->level = VENC_H264_LEVEL_2P2;
break;
case VEN_LEVEL_H264_3:
p264->level = VENC_H264_LEVEL_3;
break;
case VEN_LEVEL_H264_3P1:
p264->level = VENC_H264_LEVEL_3P1;
break;
default:
QC_OMX_MSG_ERROR("invalid level specified %d",
(int) psrc->profile_level.level);
break;
}
}
pcommon->input_frame_width = psrc->base_config.input_width;
pcommon->input_frame_height = psrc->base_config.input_height;
pcommon->output_frame_width = psrc->base_config.dvs_width;
pcommon->output_frame_height = psrc->base_config.dvs_height;
if (psrc->rotation.rotation == VEN_ROTATION_0)
{
pcommon->rotation_angle = VEN_ROTATION_0;
}
else if (psrc->rotation.rotation == VEN_ROTATION_90)
{
// swap width and height
pcommon->output_frame_width = psrc->base_config.dvs_height;
pcommon->output_frame_height = psrc->base_config.dvs_width;
pcommon->rotation_angle = VEN_ROTATION_90;
}
else if (psrc->rotation.rotation == VEN_ROTATION_180)
{
pcommon->rotation_angle = VEN_ROTATION_180;
}
else if (psrc->rotation.rotation == VEN_ROTATION_270)
{
// swap width and height
pcommon->output_frame_width = psrc->base_config.dvs_height;
pcommon->output_frame_height = psrc->base_config.dvs_width;
pcommon->rotation_angle = VEN_ROTATION_270;
}
else
{
QC_OMX_MSG_ERROR("invalid rotation %d", psrc->rotation.rotation);
}
pcommon->intra_period = psrc->intra_period.num_pframes;
// rate control config
if (psrc->rate_control.rc_mode == VEN_RC_OFF)
{
pcommon->rate_control = VEN_RC_OFF;
}
else if (psrc->rate_control.rc_mode == VEN_RC_VBR_CFR)
{
pcommon->rate_control = VEN_RC_VBR_CFR;
}
else if (psrc->rate_control.rc_mode == VEN_RC_VBR_VFR)
{
pcommon->rate_control = VEN_RC_VBR_VFR;
}
else if (psrc->rate_control.rc_mode == VEN_RC_CBR_VFR)
{
pcommon->rate_control = VEN_RC_CBR_VFR;
}
// quality config
pcommon->frame_rate.frame_rate_num = psrc->base_config.fps_num;
pcommon->frame_rate.frame_rate_den = psrc->base_config.fps_den;
pcommon->bitrate = psrc->bitrate.target_bitrate;
if (psrc->rate_control.rc_mode == VEN_RC_OFF)
{
// if rc is off, then use the client supplied qp
pcommon->iframe_qp = psrc->session_qp.iframe_qp;
pcommon->pframe_qp = psrc->session_qp.pframe_qp;
}
else
{
// if rc is on, then we have to supply the qp since driver
// interface qp ony applies when rc is off
if (psrc->base_config.codec_type == VEN_CODEC_H264)
{
pcommon->iframe_qp = 30;
pcommon->pframe_qp = 30;
}
else
{
pcommon->iframe_qp = 14;
pcommon->pframe_qp = 14;
}
if (pcommon->iframe_qp > psrc->qp_range.max_qp ||
pcommon->iframe_qp < psrc->qp_range.min_qp)
{
pcommon->iframe_qp = (psrc->qp_range.max_qp + psrc->qp_range.min_qp) / 2;
}
if (pcommon->pframe_qp > psrc->qp_range.max_qp ||
pcommon->pframe_qp < psrc->qp_range.min_qp)
{
pcommon->pframe_qp = (psrc->qp_range.max_qp + psrc->qp_range.min_qp) / 2;
}
}
pcommon->qp_range.min_qp = psrc->qp_range.min_qp;
pcommon->qp_range.max_qp = psrc->qp_range.max_qp;
return ret;
}
int ven_start(struct ven_device *dvenc,
struct venc_buffers *venc_bufs)
{
int ret = 0;
struct venc_init_config vcfg;
ven_translate_config(&(dvenc->config), &(vcfg.q6_config.codec_params),
&(vcfg.q6_config.config_params));
memcpy(&(vcfg.q6_bufs), venc_bufs, sizeof(struct venc_buffers));
ven_print_config(&(vcfg.q6_config));
ret = ioctl(dvenc->fd, VENC_IOCTL_CMD_START,&vcfg);
if (ret) {
QC_OMX_MSG_ERROR("%s failed (%d) \n", __func__, ret);
return ret;
}
return ret;
}
int ven_get_sequence_hdr(struct ven_device *dvenc,
struct venc_pmem *pbuf,
int *psize)
{
int ret = 0;
struct venc_seq_config vcfg;
ven_translate_config(&(dvenc->config), &(vcfg.q6_config.codec_params),
&(vcfg.q6_config.config_params));
memcpy(&(vcfg.buf), pbuf, sizeof(struct venc_pmem));
ret = ioctl(dvenc->fd, VENC_IOCTL_GET_SEQUENCE_HDR, &vcfg);
if (ret) {
QC_OMX_MSG_ERROR("%s failed (%d) \n", __func__, ret);
return ret;
}
else
*psize = vcfg.size;
return ret;
}
int ven_set_input_req(struct ven_device* dvenc,
struct ven_allocator_property* pprop)
{
int ret = 0;
QC_OMX_MSG_HIGH("Processing ven_set_input_req...\n");
if (pprop == NULL)
{ QC_OMX_MSG_ERROR( "null params(s)");
ret = -1;
return ret;
}
if (pprop->min_count == dvenc->input_attrs.min_count)
{
if (pprop->actual_count >= dvenc->input_attrs.min_count)
{
if (pprop->data_size >= dvenc->input_attrs.data_size)
{
if (pprop->alignment == dvenc->input_attrs.alignment)
{
dvenc->input_attrs = *pprop;
}
else
{
QC_OMX_MSG_ERROR( "alignment is read only");
ret = VENC_S_EBUFFREQ;
}
}
else
{
QC_OMX_MSG_ERROR( "buffer is too small");
ret = VENC_S_EBUFFREQ;
}
}
else
{
QC_OMX_MSG_ERROR( "not enough buffers");
ret = VENC_S_EBUFFREQ;
}
}
else
{
QC_OMX_MSG_ERROR( "min buffer count is read only");
ret = VENC_S_EBUFFREQ;
}
return ret;
}
int ven_get_input_req(struct ven_device* dvenc,
struct ven_allocator_property* pprop)
{
if(!pprop || !dvenc)
return -1;
memcpy(pprop, &dvenc->input_attrs, sizeof(struct ven_allocator_property));
return 0;
}
/**************************************************************************
* @brief
*************************************************************************/
int ven_set_output_req(struct ven_device* dvenc,
struct ven_allocator_property* pprop)
{
int ret = 0;
QC_OMX_MSG_HIGH("Processing ven_set_output_req...");
if (dvenc != NULL && pprop != NULL)
{
if (pprop->min_count == dvenc->output_attrs.min_count)
{
if (pprop->actual_count >= dvenc->output_attrs.min_count)
{
if (pprop->data_size >= dvenc->output_attrs.data_size)
{
if (pprop->alignment == dvenc->output_attrs.alignment)
{
dvenc->output_attrs = *pprop;
}
else
{
QC_OMX_MSG_ERROR( "alignment is read only");
ret = VENC_S_EBUFFREQ;
}
}
else
{
QC_OMX_MSG_ERROR( "buffer is too small");
ret = VENC_S_EBUFFREQ;
}
}
else
{
QC_OMX_MSG_ERROR( "not enough buffers");
ret = VENC_S_EBUFFREQ;
}
}
else
{
QC_OMX_MSG_ERROR( "min buffer count is read only");
ret = VENC_S_EBUFFREQ;
}
}
else
{
QC_OMX_MSG_ERROR( "null params(s)");
ret = -1;
}
return ret;
}
int ven_get_output_req(struct ven_device* dvenc,
struct ven_allocator_property* pprop)
{
if(!pprop || !dvenc)
return -1;
memcpy(pprop, &dvenc->output_attrs, sizeof(struct ven_allocator_property));
return 0;
}
/**************************************************************************
* @brief
*************************************************************************/
int ven_set_qp_range(struct ven_device* dvenc,
struct ven_qp_range *ptr)
{
int ret = 0;
struct venc_qp_range qp;
QC_OMX_MSG_HIGH("%s: SET_QP_RANGE \n", __func__);
memcpy(&(dvenc->config.qp_range), ptr, sizeof(struct ven_qp_range));
if (dvenc->state == VENC_STATE_START) {
qp.min_qp = (dvenc->config.qp_range).min_qp;
qp.max_qp = (dvenc->config.qp_range).max_qp;
ret = ioctl(dvenc->fd, VENC_IOCTL_SET_QP_RANGE,&qp);
if (ret) {
QC_OMX_MSG_ERROR("%s failed (%d) \n", __func__, ret);
return ret;
}
}
return ret;
}
int ven_get_qp_range(struct ven_device* dvenc,
struct ven_qp_range *ptr)
{
int ret = 0;
QC_OMX_MSG_HIGH("%s: SET_INTRA_PERIOD \n", __func__);
memcpy(ptr, &(dvenc->config.session_qp),
sizeof(struct ven_qp_range));
return ret;
}
/**************************************************************************
* @brief
*
* @todo document
*************************************************************************/
int ven_set_session_qp(struct ven_device* dvenc,
struct ven_session_qp *ptr)
{
int ret = 0;
QC_OMX_MSG_HIGH("%s: SET_SESSION_QP \n", __func__);
memcpy(&(dvenc->config.session_qp), ptr,
sizeof(struct ven_session_qp));
return ret;
}
int ven_get_session_qp(struct ven_device* dvenc,
struct ven_session_qp *ptr)
{
int ret = 0;
QC_OMX_MSG_HIGH("%s: GET_SESSION_QP \n", __func__);
memcpy(ptr, &(dvenc->config.session_qp),
sizeof(struct ven_session_qp));
return ret;
}
int ven_set_ac_prediction(struct ven_device* dvenc,
struct ven_switch *ptr)
{
int ret = 0;
QC_OMX_MSG_HIGH("%s: SET_AC_PREDICITON \n", __func__);
memcpy(&(dvenc->config.ac_prediction), ptr,
sizeof(struct ven_switch));
return ret;
}
int ven_get_ac_prediction(struct ven_device* dvenc,
struct ven_switch *ptr)
{
int ret = 0;
QC_OMX_MSG_HIGH("%s: GET_AC_PREDICTION \n", __func__);
memcpy(ptr, &(dvenc->config.ac_prediction),
sizeof(struct ven_switch));
return ret;
}
int ven_set_short_hdr(struct ven_device* dvenc,
struct ven_switch *ptr)
{
int ret = 0;
QC_OMX_MSG_HIGH("%s: SET_SHORT_HEADER \n", __func__);
memcpy(&(dvenc->config.short_header), ptr,
sizeof(struct ven_switch));
return ret;
}
int ven_get_short_hdr(struct ven_device* dvenc,
struct ven_switch *ptr)
{
int ret = 0;
QC_OMX_MSG_HIGH("%s: GET_SHORT_HEADER \n", __func__);
memcpy(ptr, &(dvenc->config.short_header),
sizeof(struct ven_switch));
return ret;
}
/**************************************************************************
* @brief
*
* @todo document
*************************************************************************/
int ven_set_intra_period(struct ven_device* dvenc,
struct ven_intra_period *ptr)
{
int ret = 0;
unsigned int pnum=0;
QC_OMX_MSG_HIGH("%s: SET_INTRA_PERIOD \n", __func__);
memcpy(&(dvenc->config.intra_period), ptr, sizeof(struct ven_intra_period));
if (dvenc->state == VENC_STATE_START) {
pnum = (dvenc->config.intra_period).num_pframes;
QC_OMX_MSG_HIGH("Process intra period with pnum:%d \n", pnum);
ret = ioctl(dvenc->fd, VENC_IOCTL_SET_INTRA_PERIOD, &pnum);
if (ret) {
QC_OMX_MSG_ERROR("%s failed (%d) \n", __func__, ret);
return ret;
}
}
return ret;
}
int ven_get_intra_period(struct ven_device* dvenc,
struct ven_intra_period* intra_period)
{
if(!intra_period || !dvenc)
return -1;
memcpy(intra_period, &dvenc->config.intra_period, sizeof(struct ven_intra_period));
return 0;
}
/**************************************************************************
* @brief
*
* @todo document
*************************************************************************/
int ven_set_frame_rate(struct ven_device* dvenc,
struct ven_frame_rate *ptr)
{
int ret = 0;
struct venc_frame_rate pdata;
QC_OMX_MSG_HIGH("%s: SET_FRAME_RATE \n", __func__);
memcpy(&(dvenc->config.frame_rate), ptr, sizeof(struct ven_frame_rate));
if (dvenc->state == VENC_STATE_START)
{
ptr = &(dvenc->config.frame_rate);
pdata.frame_rate_den = ptr->fps_denominator;
pdata.frame_rate_num = ptr->fps_numerator;
ret = ioctl(dvenc->fd, VENC_IOCTL_SET_FRAME_RATE, &pdata);
if (ret) {
QC_OMX_MSG_ERROR("%s failed (%d) \n", __func__, ret);
return ret;
}
}
return ret;
}
int ven_get_frame_rate(struct ven_device* dvenc,
struct ven_frame_rate* frame_rate)
{
if(!frame_rate || !dvenc)
return -1;
memcpy(frame_rate, &dvenc->config.frame_rate, sizeof(struct ven_frame_rate));
return 0;
}
/**************************************************************************
* @brief
*
* @todo document
*************************************************************************/
int ven_set_target_bitrate(struct ven_device* dvenc,
struct ven_target_bitrate *ptr)
{
int ret = 0;
unsigned int pdata = 0;
memcpy(&(dvenc->config.bitrate), ptr, sizeof(struct ven_target_bitrate));
if (dvenc->state == VENC_STATE_START)
{
pdata = (dvenc->config.bitrate).target_bitrate;
(dvenc->config.base_config).target_bitrate = pdata;
ret = ioctl(dvenc->fd, VENC_IOCTL_SET_TARGET_BITRATE, &pdata);
if (ret) {
QC_OMX_MSG_ERROR("%s: remote function failed (%d) \n", __func__, ret);
return ret;
}
}
return ret;
}
int ven_get_target_bitrate(struct ven_device* dvenc,
struct ven_target_bitrate *ptr)
{
if(!ptr || !dvenc)
return -1;
memcpy(ptr, &dvenc->config.bitrate, sizeof(struct ven_target_bitrate));
return 0;
}
int ven_request_iframe(struct ven_device* dvenc)
{
if(!dvenc)
return -1;
int rc = ioctl(dvenc->fd, VENC_IOCTL_CMD_REQUEST_IFRAME);
if(rc) {
QC_OMX_MSG_ERROR("%s: err: %d \n", __func__, rc);
}
return rc;
}
int ven_set_intra_refresh_rate(struct ven_device* dvenc,
struct ven_intra_refresh* intra_ref)
{
int ret = 0;
unsigned int pnum;
if(!intra_ref || !dvenc)
return -1;
memcpy(&dvenc->config.intra_refresh, intra_ref, sizeof(struct ven_intra_refresh));
pnum = dvenc->config.intra_refresh.mb_count;
ret = ioctl(dvenc->fd, VENC_IOCTL_SET_INTRA_REFRESH, &pnum);
if (ret) {
QC_OMX_MSG_ERROR("%s failed (%d) \n", __func__, ret);
return ret;
}
return 0;
}
int ven_get_intra_refresh_rate(struct ven_device* dvenc,
struct ven_intra_refresh* intra_ref)
{
if(!intra_ref || !dvenc)
return -1;
memcpy(intra_ref,&dvenc->config.intra_refresh, sizeof(struct ven_intra_refresh));
return 0;
}
int ven_set_multislice_cfg(struct ven_device* dvenc,
struct ven_multi_slice_cfg* multi_slice_cfg)
{
if(!multi_slice_cfg || !dvenc)
return -1;
memcpy(&dvenc->config.multi_slice, multi_slice_cfg, sizeof(struct ven_multi_slice_cfg));
return 0;
}
int ven_get_multislice_cfg(struct ven_device* dvenc,
struct ven_multi_slice_cfg* multi_slice_cfg)
{
if(!multi_slice_cfg || !dvenc)
return -1;
memcpy(multi_slice_cfg, &dvenc->config.multi_slice, sizeof(struct ven_multi_slice_cfg));
return 0;
}
int ven_set_rate_control(struct ven_device* dvenc,
struct ven_rate_ctrl_cfg* rate_ctrl)
{
if(!rate_ctrl || !dvenc)
return -1;
memcpy(&dvenc->config.rate_control, rate_ctrl, sizeof(struct ven_rate_ctrl_cfg));
return 0;
}
int ven_get_rate_control(struct ven_device* dvenc,
struct ven_rate_ctrl_cfg* rate_ctrl)
{
if(!rate_ctrl || !dvenc)
return -1;
memcpy(rate_ctrl, &dvenc->config.rate_control, sizeof(struct ven_rate_ctrl_cfg));
return 0;
}
int ven_set_vop_timing(struct ven_device* dvenc,
struct ven_vop_timing_cfg* vop_timing)
{
if(!vop_timing || !dvenc)
return -1;
memcpy(&dvenc->config.rate_control, vop_timing, sizeof(struct ven_vop_timing_cfg));
return 0;
}
int ven_get_vop_timing(struct ven_device* dvenc,
struct ven_vop_timing_cfg* vop_timing)
{
if(!vop_timing || !dvenc)
return -1;
memcpy(vop_timing, &dvenc->config.rate_control, sizeof(struct ven_vop_timing_cfg));
return 0;
}
int ven_set_rotation(struct ven_device* dvenc,
struct ven_rotation* rotation)
{
if(!rotation || !dvenc)
return -1;
memcpy(&dvenc->config.rotation, rotation, sizeof(struct ven_rotation));
return 0;
}
int ven_get_rotation(struct ven_device* dvenc,
struct ven_rotation* rotation)
{
if(!rotation || !dvenc)
return -1;
memcpy(rotation, &dvenc->config.rotation, sizeof(struct ven_rotation));
return 0;
}
int ven_set_hec(struct ven_device* dvenc,
struct ven_switch* hex)
{
if(!hex || !dvenc)
return -1;
memcpy(&dvenc->config.rotation, hex, sizeof(struct ven_header_extension));
return 0;
}
int ven_get_hec(struct ven_device* dvenc,
struct ven_switch* hex)
{
if(!hex || !dvenc)
return -1;
memcpy(hex, &dvenc->config.rotation, sizeof(struct ven_header_extension));
return 0;
}
int ven_set_data_partition(struct ven_device* dvenc,
struct ven_switch* dp)
{
if(!dp || !dvenc)
return -1;
memcpy(&dvenc->config.rotation, dp, sizeof(struct ven_switch));
return 0;
}
int ven_get_data_partition(struct ven_device* dvenc,
struct ven_switch* dp)
{
if(!dp || !dvenc)
return -1;
memcpy(dp, &dvenc->config.rotation, sizeof(struct ven_switch));
return 0;
}
int ven_get_base_cfg(struct ven_device * dvenc,
struct ven_base_cfg* bcfg)
{
if(!bcfg || !dvenc)
return -1;
memcpy(bcfg, &dvenc->config.base_config, sizeof(struct ven_base_cfg));
return 0;
}
int ven_set_base_cfg(struct ven_device * dvenc,
struct ven_base_cfg* pcfg)
{
struct ven_base_cfg *pconfig;
int new_codec;
int result = 0;
if (dvenc == NULL || pcfg == NULL) {
QC_OMX_MSG_ERROR( "null driver");
return -1;
}
new_codec = (pcfg->codec_type != dvenc->config.base_config.codec_type);
pconfig = &(dvenc->config.base_config);
memcpy(pconfig, pcfg, sizeof(struct ven_base_cfg));
dvenc->config.frame_rate.fps_numerator = pconfig->fps_num;
dvenc->config.frame_rate.fps_denominator = pconfig->fps_den;
dvenc->config.bitrate.target_bitrate = pconfig->target_bitrate;
dvenc->input_attrs.data_size = pconfig->input_width * pconfig->input_height * 3 / 2;
dvenc->output_attrs.data_size = pconfig->input_width * pconfig->input_height * 3 / 2;
dvenc->config.intra_period.num_pframes = pconfig->fps_num * 2 - 1;
dvenc->config.vop_timing.vop_time_resolution = pconfig->fps_num * 2;
if (new_codec)
{
ven_change_codec(dvenc);
}
result = ven_update_buf_properties(dvenc);
return 0;
}
int ven_set_codec_profile(struct ven_device* dvenc,
struct ven_profile* prof)
{
if(!prof || !dvenc)
return -1;
memcpy(&dvenc->config.profile, prof, sizeof(struct ven_profile));
return 0;
}
int ven_get_codec_profile(struct ven_device* dvenc,
struct ven_profile* prof)
{
if(!prof || !dvenc)
return -1;
memcpy(prof, &dvenc->config.profile, sizeof(struct ven_profile));
return 0;
}
int ven_set_profile_level(struct ven_device* dvenc,
struct ven_profile_level* prof_level)
{
int result = 0;
if(!prof_level || !dvenc)
return -1;
memcpy(&dvenc->config.profile_level, prof_level, sizeof(struct ven_profile_level));
result = ven_update_buf_properties(dvenc);
return result;
}
int ven_get_profile_level(struct ven_device* dvenc,
struct ven_profile_level* prof_level)
{
if(!prof_level || !dvenc)
return -1;
memcpy(prof_level, &dvenc->config.profile_level, sizeof(struct ven_profile_level));
return 0;
}
int ven_device_open(struct ven_device** handle)
{
int fd;
QC_OMX_MSG_HIGH("%s \n", __func__);
struct ven_device* dvenc = (struct ven_device *)malloc(sizeof(struct ven_device));
if (!dvenc) return -1;
*handle = dvenc;
QC_OMX_MSG_HIGH("%s: dvenc:%p pconfig: %p \n", __func__, dvenc, &(dvenc->config.base_config));
fd = open("/dev/q6venc", O_RDWR);
if (fd < 0)
{
QC_OMX_MSG_ERROR("Cannot open /dev/q6venc ");
close(fd);
return -1;
}
dvenc->fd = fd;
(void) ven_set_default_config(dvenc);
(void) ven_set_default_buf_properties(dvenc);
dvenc->config.callback_event = NULL;
dvenc->state = VENC_STATE_STOP;
// dvenc->is_active = 1;
QC_OMX_MSG_HIGH("%s = %d\n", __func__,fd);
return fd;
}
int ven_device_close(struct ven_device* handle)
{
int ret = 0;
struct ven_device *dvenc;
QC_OMX_MSG_HIGH("%s\n", __func__);
dvenc = (struct ven_device *)handle;
if (dvenc) {
close(dvenc->fd);
}
free(dvenc);
return ret;
}