/*-------------------------------------------------------------------------- Copyright (c) 2010-2012, 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 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 #include #include #include #include #include "video_encoder_device.h" #include "omx_video_encoder.h" #include #ifdef USE_ION #include #endif #define MPEG4_SP_START 0 #define MPEG4_ASP_START (MPEG4_SP_START + 8) #define MPEG4_720P_LEVEL 6 #define H263_BP_START 0 #define H264_BP_START 0 #define H264_HP_START (H264_BP_START + 13) #define H264_MP_START (H264_BP_START + 26) /* MPEG4 profile and level table*/ static const unsigned int mpeg4_profile_level_table[][5]= { /*max mb per frame, max mb per sec, max bitrate, level, profile*/ {99,1485,64000,OMX_VIDEO_MPEG4Level0,OMX_VIDEO_MPEG4ProfileSimple}, {99,1485,64000,OMX_VIDEO_MPEG4Level1,OMX_VIDEO_MPEG4ProfileSimple}, {396,5940,128000,OMX_VIDEO_MPEG4Level2,OMX_VIDEO_MPEG4ProfileSimple}, {396,11880,384000,OMX_VIDEO_MPEG4Level3,OMX_VIDEO_MPEG4ProfileSimple}, {1200,36000,4000000,OMX_VIDEO_MPEG4Level4a,OMX_VIDEO_MPEG4ProfileSimple}, {1620,40500,8000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileSimple}, {3600,108000,12000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileSimple}, {0,0,0,0,0}, {99,1485,128000,OMX_VIDEO_MPEG4Level0,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, {99,1485,128000,OMX_VIDEO_MPEG4Level1,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, {396,5940,384000,OMX_VIDEO_MPEG4Level2,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, {396,11880,768000,OMX_VIDEO_MPEG4Level3,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, {792,23760,3000000,OMX_VIDEO_MPEG4Level4,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, {1620,48600,8000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, {0,0,0,0,0}, }; /* H264 profile and level table*/ static const unsigned int h264_profile_level_table[][5]= { /*max mb per frame, max mb per sec, max bitrate, level, profile*/ {99,1485,64000,OMX_VIDEO_AVCLevel1,OMX_VIDEO_AVCProfileBaseline}, {99,1485,128000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileBaseline}, {396,3000,192000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileBaseline}, {396,6000,384000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileBaseline}, {396,11880,768000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileBaseline}, {396,11880,2000000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileBaseline}, {792,19800,4000000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileBaseline}, {1620,20250,4000000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileBaseline}, {1620,40500,10000000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileBaseline}, {3600,108000,14000000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileBaseline}, {5120,216000,20000000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileBaseline}, {8192,245760,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileBaseline}, {0,0,0,0,0}, {99,1485,64000,OMX_VIDEO_AVCLevel1,OMX_VIDEO_AVCProfileHigh}, {99,1485,160000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileHigh}, {396,3000,240000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileHigh}, {396,6000,480000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileHigh}, {396,11880,960000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileHigh}, {396,11880,2500000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileHigh}, {792,19800,5000000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileHigh}, {1620,20250,5000000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileHigh}, {1620,40500,12500000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileHigh}, {3600,108000,17500000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileHigh}, {5120,216000,25000000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileHigh}, {8192,245760,25000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileHigh}, {0,0,0,0,0}, {99,1485,64000,OMX_VIDEO_AVCLevel1,OMX_VIDEO_AVCProfileMain}, {99,1485,128000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileMain}, {396,3000,192000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileMain}, {396,6000,384000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileMain}, {396,11880,768000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileMain}, {396,11880,2000000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileMain}, {792,19800,4000000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileMain}, {1620,20250,4000000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileMain}, {1620,40500,10000000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileMain}, {3600,108000,14000000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileMain}, {5120,216000,20000000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileMain}, {8192,245760,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileMain}, {0,0,0,0,0} }; /* H263 profile and level table*/ static const unsigned int h263_profile_level_table[][5]= { /*max mb per frame, max mb per sec, max bitrate, level, profile*/ {99,1485,64000,OMX_VIDEO_H263Level10,OMX_VIDEO_H263ProfileBaseline}, {396,5940,128000,OMX_VIDEO_H263Level20,OMX_VIDEO_H263ProfileBaseline}, {396,11880,384000,OMX_VIDEO_H263Level30,OMX_VIDEO_H263ProfileBaseline}, {396,11880,2048000,OMX_VIDEO_H263Level40,OMX_VIDEO_H263ProfileBaseline}, {99,1485,128000,OMX_VIDEO_H263Level45,OMX_VIDEO_H263ProfileBaseline}, {396,19800,4096000,OMX_VIDEO_H263Level50,OMX_VIDEO_H263ProfileBaseline}, {810,40500,8192000,OMX_VIDEO_H263Level60,OMX_VIDEO_H263ProfileBaseline}, {1620,81000,16384000,OMX_VIDEO_H263Level70,OMX_VIDEO_H263ProfileBaseline}, {0,0,0,0,0} }; #define Log2(number, power) { OMX_U32 temp = number; power = 0; while( (0 == (temp & 0x1)) && power < 16) { temp >>=0x1; power++; } } #define Q16ToFraction(q,num,den) { OMX_U32 power; Log2(q,power); num = q >> power; den = 0x1 << (16 - power); } #ifdef INPUT_BUFFER_LOG FILE *inputBufferFile1; char inputfilename [] = "/data/input.yuv"; #endif #ifdef OUTPUT_BUFFER_LOG FILE *outputBufferFile1; char outputfilename [] = "/data/output-bitstream.\0\0\0\0"; #endif //constructor venc_dev::venc_dev(class omx_venc *venc_class) { m_max_allowed_bitrate_check = false; m_eLevel = 0; m_eProfile = 0; pthread_mutex_init(&loaded_start_stop_mlock, NULL); pthread_cond_init (&loaded_start_stop_cond, NULL); venc_encoder = reinterpret_cast(venc_class); DEBUG_PRINT_LOW("venc_dev constructor"); } venc_dev::~venc_dev() { pthread_cond_destroy(&loaded_start_stop_cond); pthread_mutex_destroy(&loaded_start_stop_mlock); DEBUG_PRINT_LOW("venc_dev distructor"); } void* async_venc_message_thread (void *input) { struct venc_ioctl_msg ioctl_msg ={NULL,NULL}; struct venc_timeout timeout; struct venc_msg venc_msg; int error_code = 0; omx_venc *omx = reinterpret_cast(input); prctl(PR_SET_NAME, (unsigned long)"VideoEncCallBackThread", 0, 0, 0); timeout.millisec = VEN_TIMEOUT_INFINITE; while(1) { ioctl_msg.in = NULL; ioctl_msg.out = (void*)&venc_msg; /*Wait for a message from the video decoder driver*/ error_code = ioctl(omx->handle->m_nDriver_fd,VEN_IOCTL_CMD_READ_NEXT_MSG,(void *)&ioctl_msg); if (error_code == -512) // ERESTARTSYS { DEBUG_PRINT_ERROR("\n ERESTARTSYS received in ioctl read next msg!"); } else if (error_code <0) { DEBUG_PRINT_ERROR("\nioctl VEN_IOCTL_CMD_READ_NEXT_MSG failed"); break; } else if(omx->async_message_process(input,&venc_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Wrong ioctl message"); break; } } DEBUG_PRINT_HIGH("omx_venc: Async Thread exit\n"); return NULL; } bool venc_dev::venc_open(OMX_U32 codec) { struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; int r; unsigned int alignment = 0,buffer_size = 0, temp =0; OMX_STRING device_name = "/dev/msm_vidc_enc"; DEBUG_PRINT_ERROR("\n Is component secure %d", venc_encoder->is_secure_session()); if(venc_encoder->is_secure_session()) device_name = "/dev/msm_vidc_enc_sec"; m_nDriver_fd = open (device_name,O_RDWR|O_NONBLOCK); if(m_nDriver_fd == 0) { DEBUG_PRINT_ERROR("ERROR: Got fd as 0 for msm_vidc_enc, Opening again\n"); m_nDriver_fd = open (device_name,O_RDWR|O_NONBLOCK); } if((int)m_nDriver_fd < 0) { DEBUG_PRINT_ERROR("ERROR: Omx_venc::Comp Init Returning failure\n"); return false; } DEBUG_PRINT_LOW("\nm_nDriver_fd = %d\n", m_nDriver_fd); #ifdef SINGLE_ENCODER_INSTANCE OMX_U32 num_instances = 0; ioctl_msg.in = NULL; ioctl_msg.out = &num_instances; if(ioctl (m_nDriver_fd, VEN_IOCTL_GET_NUMBER_INSTANCES, (void*)&ioctl_msg) < 0 ) { DEBUG_PRINT_ERROR("\nERROR: Request number of encoder instances failed"); } else if (num_instances > 1) { DEBUG_PRINT_ERROR("\nSecond encoder instance rejected!"); venc_close(); return false; } #endif // set the basic configuration of the video encoder driver m_sVenc_cfg.input_width = OMX_CORE_QCIF_WIDTH; m_sVenc_cfg.input_height= OMX_CORE_QCIF_HEIGHT; m_sVenc_cfg.dvs_width = OMX_CORE_QCIF_WIDTH; m_sVenc_cfg.dvs_height = OMX_CORE_QCIF_HEIGHT; m_sVenc_cfg.fps_num = 30; m_sVenc_cfg.fps_den = 1; m_sVenc_cfg.targetbitrate = 64000; #ifdef MAX_RES_1080P m_sVenc_cfg.inputformat= VEN_INPUTFMT_NV12_16M2KA; #else m_sVenc_cfg.inputformat= VEN_INPUTFMT_NV12; #endif if(codec == OMX_VIDEO_CodingMPEG4) { m_sVenc_cfg.codectype = VEN_CODEC_MPEG4; codec_profile.profile = VEN_PROFILE_MPEG4_SP; profile_level.level = VEN_LEVEL_MPEG4_2; #ifdef OUTPUT_BUFFER_LOG strcat(outputfilename, "m4v"); #endif } else if(codec == OMX_VIDEO_CodingH263) { m_sVenc_cfg.codectype = VEN_CODEC_H263; codec_profile.profile = VEN_PROFILE_H263_BASELINE; profile_level.level = VEN_LEVEL_H263_20; #ifdef OUTPUT_BUFFER_LOG strcat(outputfilename, "263"); #endif } if(codec == OMX_VIDEO_CodingAVC) { m_sVenc_cfg.codectype = VEN_CODEC_H264; codec_profile.profile = VEN_PROFILE_H264_BASELINE; profile_level.level = VEN_LEVEL_H264_1p1; #ifdef OUTPUT_BUFFER_LOG strcat(outputfilename, "264"); #endif } ioctl_msg.in = (void*)&m_sVenc_cfg; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_BASE_CFG,(void*)&ioctl_msg) < 0 ) { DEBUG_PRINT_ERROR("\nERROR: Request for setting base configuration failed"); return false; } #ifdef INPUT_BUFFER_LOG inputBufferFile1 = fopen (inputfilename, "ab"); #endif #ifdef OUTPUT_BUFFER_LOG outputBufferFile1 = fopen (outputfilename, "ab"); #endif // Get the I/P and O/P buffer requirements ioctl_msg.in = NULL; ioctl_msg.out = (void*)&m_sInput_buff_property; if(ioctl (m_nDriver_fd,VEN_IOCTL_GET_INPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for getting i/p buffer requirement failed"); return false; } ioctl_msg.in = NULL; ioctl_msg.out = (void*)&m_sOutput_buff_property; if(ioctl (m_nDriver_fd,VEN_IOCTL_GET_OUTPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for getting o/p buffer requirement failed"); return false; } m_profile_set = false; m_level_set = false; if(venc_set_profile_level(0, 0)) { DEBUG_PRINT_HIGH("\n %s(): Init Profile/Level setting success", __func__); } recon_buffers_count = MAX_RECON_BUFFERS; return true; } void venc_dev::venc_close() { DEBUG_PRINT_LOW("\nvenc_close: fd = %d", m_nDriver_fd); if((int)m_nDriver_fd >= 0) { DEBUG_PRINT_HIGH("\n venc_close(): Calling VEN_IOCTL_CMD_STOP_READ_MSG"); (void)ioctl(m_nDriver_fd, VEN_IOCTL_CMD_STOP_READ_MSG, NULL); DEBUG_PRINT_LOW("\nCalling close()\n"); close(m_nDriver_fd); m_nDriver_fd = -1; } #ifdef INPUT_BUFFER_LOG fclose (inputBufferFile1); #endif #ifdef OUTPUT_BUFFER_LOG fclose (outputBufferFile1); #endif } bool venc_dev::venc_set_buf_req(OMX_U32 *min_buff_count, OMX_U32 *actual_buff_count, OMX_U32 *buff_size, OMX_U32 port) { struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; unsigned long temp_count = 0; if(port == 0) { if(*actual_buff_count > m_sInput_buff_property.mincount) { temp_count = m_sInput_buff_property.actualcount; m_sInput_buff_property.actualcount = *actual_buff_count; ioctl_msg.in = (void*)&m_sInput_buff_property; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_INPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting i/p buffer requirement failed"); m_sInput_buff_property.actualcount = temp_count; return false; } DEBUG_PRINT_LOW("\n I/P Count set to %lu\n", *actual_buff_count); } } else { if(*actual_buff_count > m_sOutput_buff_property.mincount) { temp_count = m_sOutput_buff_property.actualcount; m_sOutput_buff_property.actualcount = *actual_buff_count; ioctl_msg.in = (void*)&m_sOutput_buff_property; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_OUTPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting o/p buffer requirement failed"); m_sOutput_buff_property.actualcount = temp_count; return false; } DEBUG_PRINT_LOW("\n O/P Count set to %lu\n", *actual_buff_count); } } return true; } bool venc_dev::venc_loaded_start() { struct timespec ts; int status = 0; if(ioctl (m_nDriver_fd,VEN_IOCTL_CMD_START, NULL) < 0) { DEBUG_PRINT_ERROR("ERROR: VEN_IOCTL_CMD_START failed"); return false; } if (clock_gettime(CLOCK_REALTIME, &ts) < 0) { DEBUG_PRINT_ERROR("%s: clock_gettime failed", __func__); return false; } ts.tv_sec += 1; pthread_mutex_lock(&loaded_start_stop_mlock); DEBUG_PRINT_LOW("%s: wait on start done", __func__); status = pthread_cond_timedwait(&loaded_start_stop_cond, &loaded_start_stop_mlock, &ts); if (status != 0) { DEBUG_PRINT_ERROR("%s: error status = %d, %s", __func__, status, strerror(status)); pthread_mutex_unlock(&loaded_start_stop_mlock); return false; } DEBUG_PRINT_LOW("%s: wait over on start done", __func__); pthread_mutex_unlock(&loaded_start_stop_mlock); DEBUG_PRINT_LOW("%s: venc_loaded_start success", __func__); return true; } bool venc_dev::venc_loaded_stop() { struct timespec ts; int status = 0; if(ioctl (m_nDriver_fd,VEN_IOCTL_CMD_STOP, NULL) < 0) { DEBUG_PRINT_ERROR("ERROR: VEN_IOCTL_CMD_STOP failed"); return false; } if (clock_gettime(CLOCK_REALTIME, &ts) < 0) { DEBUG_PRINT_ERROR("%s: clock_gettime failed", __func__); return false; } ts.tv_sec += 1; pthread_mutex_lock(&loaded_start_stop_mlock); DEBUG_PRINT_LOW("%s: wait on stop done", __func__); status = pthread_cond_timedwait(&loaded_start_stop_cond, &loaded_start_stop_mlock, &ts); if (status != 0) { DEBUG_PRINT_ERROR("%s: error status = %d, %s", __func__, status, strerror(status)); pthread_mutex_unlock(&loaded_start_stop_mlock); return false; } DEBUG_PRINT_LOW("%s: wait over on stop done", __func__); pthread_mutex_unlock(&loaded_start_stop_mlock); DEBUG_PRINT_LOW("%s: venc_loaded_stop success", __func__); return true; } bool venc_dev::venc_loaded_start_done() { pthread_mutex_lock(&loaded_start_stop_mlock); DEBUG_PRINT_LOW("%s: signal start done", __func__); pthread_cond_signal(&loaded_start_stop_cond); pthread_mutex_unlock(&loaded_start_stop_mlock); return true; } bool venc_dev::venc_loaded_stop_done() { pthread_mutex_lock(&loaded_start_stop_mlock); DEBUG_PRINT_LOW("%s: signal stop done", __func__); pthread_cond_signal(&loaded_start_stop_cond); pthread_mutex_unlock(&loaded_start_stop_mlock); return true; } bool venc_dev::venc_get_seq_hdr(void *buffer, unsigned buffer_size, unsigned *header_len) { struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; int i = 0; DEBUG_PRINT_HIGH("venc_dev::venc_get_seq_hdr"); venc_seqheader seq_in, seq_out; seq_in.hdrlen = 0; seq_in.bufsize = buffer_size; seq_in.hdrbufptr = (unsigned char*)buffer; if (seq_in.hdrbufptr == NULL) { DEBUG_PRINT_ERROR("ERROR: malloc for sequence header failed"); return false; } DEBUG_PRINT_LOW("seq_in: buf=%x, sz=%d, hdrlen=%d", seq_in.hdrbufptr, seq_in.bufsize, seq_in.hdrlen); ioctl_msg.in = (void*)&seq_in; ioctl_msg.out = (void*)&seq_out; if(ioctl (m_nDriver_fd,VEN_IOCTL_GET_SEQUENCE_HDR,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("ERROR: Request for getting sequence header failed"); return false; } if (seq_out.hdrlen == 0) { DEBUG_PRINT_ERROR("ERROR: Seq header returned zero length header"); DEBUG_PRINT_ERROR("seq_out: buf=%x, sz=%d, hdrlen=%d", seq_out.hdrbufptr, seq_out.bufsize, seq_out.hdrlen); return false; } *header_len = seq_out.hdrlen; DEBUG_PRINT_LOW("seq_out: buf=%x, sz=%d, hdrlen=%d", seq_out.hdrbufptr, seq_out.bufsize, seq_out.hdrlen); return true; } bool venc_dev::venc_get_buf_req(OMX_U32 *min_buff_count, OMX_U32 *actual_buff_count, OMX_U32 *buff_size, OMX_U32 port) { struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; if(port == 0) { ioctl_msg.in = NULL; ioctl_msg.out = (void*)&m_sInput_buff_property; if(ioctl (m_nDriver_fd,VEN_IOCTL_GET_INPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for getting i/p buffer requirement failed"); return false; } *min_buff_count = m_sInput_buff_property.mincount; *actual_buff_count = m_sInput_buff_property.actualcount; #ifdef USE_ION // For ION memory allocations of the allocated buffer size // must be 4k aligned, hence aligning the input buffer // size to 4k. m_sInput_buff_property.datasize = (m_sInput_buff_property.datasize + 4095) & (~4095); #endif *buff_size = m_sInput_buff_property.datasize; } else { ioctl_msg.in = NULL; ioctl_msg.out = (void*)&m_sOutput_buff_property; if(ioctl (m_nDriver_fd,VEN_IOCTL_GET_OUTPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for getting o/p buffer requirement failed"); return false; } *min_buff_count = m_sOutput_buff_property.mincount; *actual_buff_count = m_sOutput_buff_property.actualcount; *buff_size = m_sOutput_buff_property.datasize; } return true; } bool venc_dev::venc_set_param(void *paramData,OMX_INDEXTYPE index ) { venc_ioctl_msg ioctl_msg = {NULL,NULL}; DEBUG_PRINT_LOW("venc_set_param:: venc-720p\n"); switch(index) { case OMX_IndexParamPortDefinition: { OMX_PARAM_PORTDEFINITIONTYPE *portDefn; portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData; DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamPortDefinition\n"); if(portDefn->nPortIndex == PORT_INDEX_IN) { if(!venc_set_encode_framerate(portDefn->format.video.xFramerate, 0)) { return false; } if(!venc_set_color_format(portDefn->format.video.eColorFormat)) { return false; } DEBUG_PRINT_LOW("\n Basic parameter has changed"); m_sVenc_cfg.input_height = portDefn->format.video.nFrameHeight; m_sVenc_cfg.input_width = portDefn->format.video.nFrameWidth; ioctl_msg.in = (void*)&m_sVenc_cfg; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_BASE_CFG,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting base config failed"); return false; } DEBUG_PRINT_LOW("\n Updating the buffer count/size for the new resolution"); ioctl_msg.in = NULL; ioctl_msg.out = (void*)&m_sInput_buff_property; if(ioctl (m_nDriver_fd, VEN_IOCTL_GET_INPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for getting i/p bufreq failed"); return false; } DEBUG_PRINT_LOW("\n Got updated m_sInput_buff_property values: " "datasize = %u, maxcount = %u, actualcnt = %u, " "mincount = %u", m_sInput_buff_property.datasize, m_sInput_buff_property.maxcount, m_sInput_buff_property.actualcount, m_sInput_buff_property.mincount); ioctl_msg.in = NULL; ioctl_msg.out = (void*)&m_sOutput_buff_property; if(ioctl (m_nDriver_fd, VEN_IOCTL_GET_OUTPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for getting o/p bufreq failed"); return false; } DEBUG_PRINT_LOW("\n Got updated m_sOutput_buff_property values: " "datasize = %u, maxcount = %u, actualcnt = %u, " "mincount = %u", m_sOutput_buff_property.datasize, m_sOutput_buff_property.maxcount, m_sOutput_buff_property.actualcount, m_sOutput_buff_property.mincount); ioctl_msg.in = (void*)&m_sOutput_buff_property; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd, VEN_IOCTL_SET_OUTPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting o/p bufreq failed"); return false; } if((portDefn->nBufferCountActual >= m_sInput_buff_property.mincount) && (portDefn->nBufferCountActual <= m_sInput_buff_property.maxcount)) { m_sInput_buff_property.actualcount = portDefn->nBufferCountActual; ioctl_msg.in = (void*)&m_sInput_buff_property; ioctl_msg.out = NULL; if(ioctl(m_nDriver_fd,VEN_IOCTL_SET_INPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting i/p buffer requirements failed"); return false; } } if(m_sInput_buff_property.datasize != portDefn->nBufferSize) { DEBUG_PRINT_ERROR("\nWARNING: Requested i/p bufsize[%u]," "Driver's updated i/p bufsize = %u", portDefn->nBufferSize, m_sInput_buff_property.datasize); } m_level_set = false; if(venc_set_profile_level(0, 0)) { DEBUG_PRINT_HIGH("\n %s(): Profile/Level setting success", __func__); } } else if(portDefn->nPortIndex == PORT_INDEX_OUT) { if(!venc_set_target_bitrate(portDefn->format.video.nBitrate, 0)) { return false; } if( (portDefn->nBufferCountActual >= m_sOutput_buff_property.mincount) && (m_sOutput_buff_property.maxcount >= portDefn->nBufferCountActual) && (m_sOutput_buff_property.datasize == portDefn->nBufferSize) ) { m_sOutput_buff_property.actualcount = portDefn->nBufferCountActual; ioctl_msg.in = (void*)&m_sOutput_buff_property; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_OUTPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: ioctl VEN_IOCTL_SET_OUTPUT_BUFFER_REQ failed"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Setting Output buffer requirements failed"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Invalid Port Index for OMX_IndexParamPortDefinition"); } break; } case OMX_IndexParamVideoPortFormat: { OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt; portFmt =(OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData; DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoPortFormat\n"); if(portFmt->nPortIndex == (OMX_U32) PORT_INDEX_IN) { if(!venc_set_color_format(portFmt->eColorFormat)) { return false; } } else if(portFmt->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { if(!venc_set_encode_framerate(portFmt->xFramerate, 0)) { return false; } } else { DEBUG_PRINT_ERROR("\nERROR: 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\n"); if(pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { if(!venc_set_target_bitrate(pParam->nTargetBitrate, 0)) { DEBUG_PRINT_ERROR("\nERROR: Target Bit Rate setting failed"); return false; } if(!venc_set_ratectrl_cfg(pParam->eControlRate)) { DEBUG_PRINT_ERROR("\nERROR: Rate Control setting failed"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Invalid Port Index for OMX_IndexParamVideoBitrate"); } break; } case OMX_IndexParamVideoMpeg4: { OMX_VIDEO_PARAM_MPEG4TYPE* pParam; OMX_U32 bFrames = 0; pParam = (OMX_VIDEO_PARAM_MPEG4TYPE*)paramData; DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoMpeg4\n"); if(pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { if(!venc_set_voptiming_cfg(pParam->nTimeIncRes)) { DEBUG_PRINT_ERROR("\nERROR: Request for setting vop_timing failed"); return false; } m_profile_set = false; m_level_set = false; if(!venc_set_profile_level (pParam->eProfile, pParam->eLevel)) { DEBUG_PRINT_ERROR("\nERROR: Unsuccessful in updating Profile and level"); return false; } #ifdef MAX_RES_1080P else { if(pParam->eProfile == OMX_VIDEO_MPEG4ProfileAdvancedSimple) { if(pParam->nBFrames) { DEBUG_PRINT_HIGH("INFO: Only 1 Bframe is supported"); bFrames = 1; } } else { if(pParam->nBFrames) { DEBUG_PRINT_ERROR("Warning: B frames not supported\n"); bFrames = 0; } } } #endif if(!venc_set_intra_period (pParam->nPFrames,bFrames)) { DEBUG_PRINT_ERROR("\nERROR: Request for setting intra period failed"); return false; } if(!venc_set_multislice_cfg(OMX_IndexParamVideoMpeg4,pParam->nSliceHeaderSpacing)) { DEBUG_PRINT_ERROR("\nERROR: Unsuccessful in updating slice_config"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Invalid Port Index for OMX_IndexParamVideoMpeg4"); } break; } case OMX_IndexParamVideoH263: { OMX_VIDEO_PARAM_H263TYPE* pParam = (OMX_VIDEO_PARAM_H263TYPE*)paramData; DEBUG_PRINT_LOW("venc_set_param: OMX_IndexParamVideoH263\n"); OMX_U32 bFrames = 0; if(pParam->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { m_profile_set = false; m_level_set = false; if(!venc_set_profile_level (pParam->eProfile, pParam->eLevel)) { DEBUG_PRINT_ERROR("\nERROR: Unsuccessful in updating Profile and level"); return false; } if (pParam->nBFrames) DEBUG_PRINT_ERROR("\nWARNING: B frame not supported for H.263"); if(venc_set_intra_period (pParam->nPFrames, bFrames) == false) { DEBUG_PRINT_ERROR("\nERROR: Request for setting intra period failed"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Invalid Port Index for OMX_IndexParamVideoH263"); } break; } case OMX_IndexParamVideoAvc: { DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoAvc\n"); 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\n", pParam->eProfile,pParam->eLevel); m_profile_set = false; m_level_set = false; if(!venc_set_profile_level (pParam->eProfile,pParam->eLevel)) { DEBUG_PRINT_ERROR("\nERROR: Unsuccessful in updating Profile and level %d, %d", pParam->eProfile, pParam->eLevel); return false; } #ifdef MAX_RES_1080P else { if(pParam->eProfile != OMX_VIDEO_AVCProfileBaseline) { if(pParam->nBFrames) { DEBUG_PRINT_HIGH("INFO: Only 1 Bframe is supported"); bFrames = 1; } } else { if(pParam->nBFrames) { DEBUG_PRINT_ERROR("Warning: B frames not supported\n"); bFrames = 0; } } } #endif if(!venc_set_intra_period (pParam->nPFrames, bFrames)) { DEBUG_PRINT_ERROR("\nERROR: Request for setting intra period failed"); return false; } if(!venc_set_entropy_config (pParam->bEntropyCodingCABAC, pParam->nCabacInitIdc)) { DEBUG_PRINT_ERROR("\nERROR: Request for setting Entropy failed"); return false; } if(!venc_set_inloop_filter (pParam->eLoopFilterMode)) { DEBUG_PRINT_ERROR("\nERROR: Request for setting Inloop filter failed"); return false; } if(!venc_set_multislice_cfg(OMX_IndexParamVideoAvc, pParam->nSliceHeaderSpacing)) { DEBUG_PRINT_ERROR("\nWARNING: Unsuccessful in updating slice_config"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Invalid Port Index for OMX_IndexParamVideoAvc"); } //TBD, lot of other variables to be updated, yet to decide break; } case OMX_IndexParamVideoIntraRefresh: { DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoIntraRefresh\n"); OMX_VIDEO_PARAM_INTRAREFRESHTYPE *intra_refresh = (OMX_VIDEO_PARAM_INTRAREFRESHTYPE *)paramData; if(intra_refresh->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { if(venc_set_intra_refresh(intra_refresh->eRefreshMode, intra_refresh->nCirMBs) == false) { DEBUG_PRINT_ERROR("\nERROR: Setting Intra refresh failed"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Invalid Port Index for OMX_IndexParamVideoIntraRefresh"); } break; } case OMX_IndexParamVideoErrorCorrection: { DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoErrorCorrection\n"); 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("\nERROR: Setting Intra refresh failed"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Invalid Port Index for OMX_IndexParamVideoErrorCorrection"); } break; } case OMX_IndexParamVideoProfileLevelCurrent: { DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoProfileLevelCurrent\n"); OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)paramData; if(profile_level->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { m_profile_set = false; m_level_set = false; if(!venc_set_profile_level (profile_level->eProfile, profile_level->eLevel)) { DEBUG_PRINT_ERROR("\nWARNING: Unsuccessful in updating Profile and level"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Invalid Port Index for OMX_IndexParamVideoProfileLevelCurrent"); } break; } case OMX_IndexParamVideoQuantization: { DEBUG_PRINT_LOW("venc_set_param:OMX_IndexParamVideoQuantization\n"); OMX_VIDEO_PARAM_QUANTIZATIONTYPE *session_qp = (OMX_VIDEO_PARAM_QUANTIZATIONTYPE *)paramData; if(session_qp->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { if(venc_set_session_qp (session_qp->nQpI, session_qp->nQpP) == false) { DEBUG_PRINT_ERROR("\nERROR: Setting Session QP failed"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Invalid Port Index for OMX_IndexParamVideoQuantization"); } break; } case OMX_ExtraDataVideoEncoderSliceInfo: { DEBUG_PRINT_LOW("venc_set_param: OMX_ExtraDataVideoEncoderSliceInfo"); OMX_U32 extra_data = *(OMX_U32 *)paramData; if(venc_set_extradata(extra_data) == false) { DEBUG_PRINT_ERROR("ERROR: Setting " "OMX_QcomIndexParamIndexExtraDataType failed"); return false; } break; } case OMX_QcomIndexEnableSliceDeliveryMode: { QOMX_EXTNINDEX_PARAMTYPE* pParam = (QOMX_EXTNINDEX_PARAMTYPE*)paramData; if(pParam->nPortIndex == PORT_INDEX_OUT) { if(venc_set_slice_delivery_mode(pParam->bEnable) == false) { DEBUG_PRINT_ERROR("Setting slice delivery mode failed"); return OMX_ErrorUnsupportedSetting; } } else { DEBUG_PRINT_ERROR("OMX_QcomIndexEnableSliceDeliveryMode " "called on wrong port(%d)", pParam->nPortIndex); return OMX_ErrorBadPortIndex; } break; } case OMX_QcomIndexParamSequenceHeaderWithIDR: { PrependSPSPPSToIDRFramesParams * pParam = (PrependSPSPPSToIDRFramesParams *)paramData; if(venc_set_inband_video_header(pParam->bEnable) == false) { DEBUG_PRINT_ERROR("Setting inband sps/pps failed"); return false; } break; } case OMX_QcomIndexParamEnableVUIStreamRestrictFlag: { QOMX_VUI_BITSTREAM_RESTRICT *pParam = (QOMX_VUI_BITSTREAM_RESTRICT *)paramData; if(venc_set_bitstream_restrict_in_vui(pParam->bEnable) == false) { DEBUG_PRINT_ERROR("Setting bitstream_restrict flag in VUI failed"); return false; } break; } case OMX_IndexParamVideoSliceFMO: default: DEBUG_PRINT_ERROR("\nERROR: Unsupported parameter in venc_set_param: %u", index); break; //case } return true; } bool venc_dev::venc_set_config(void *configData, OMX_INDEXTYPE index) { venc_ioctl_msg ioctl_msg = {NULL,NULL}; DEBUG_PRINT_LOW("\n Inside venc_set_config"); switch(index) { case OMX_IndexConfigVideoBitrate: { OMX_VIDEO_CONFIG_BITRATETYPE *bit_rate = (OMX_VIDEO_CONFIG_BITRATETYPE *) configData; if(m_max_allowed_bitrate_check && !venc_max_allowed_bitrate_check(bit_rate->nEncodeBitrate)) { DEBUG_PRINT_ERROR("Max Allowed Bitrate Check failed"); return false; } DEBUG_PRINT_LOW("\n venc_set_config: OMX_IndexConfigVideoBitrate"); if(bit_rate->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { if(venc_set_target_bitrate(bit_rate->nEncodeBitrate, 1) == false) { DEBUG_PRINT_ERROR("\nERROR: Setting Target Bit rate failed"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Invalid Port Index for OMX_IndexConfigVideoBitrate"); } break; } case OMX_IndexConfigVideoFramerate: { OMX_CONFIG_FRAMERATETYPE *frame_rate = (OMX_CONFIG_FRAMERATETYPE *) configData; DEBUG_PRINT_LOW("\n venc_set_config: OMX_IndexConfigVideoFramerate"); if(frame_rate->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { if(venc_set_encode_framerate(frame_rate->xEncodeFramerate, 1) == false) { DEBUG_PRINT_ERROR("\nERROR: Setting Encode Framerate failed"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Invalid Port Index for OMX_IndexConfigVideoFramerate"); } break; } case QOMX_IndexConfigVideoIntraperiod: { DEBUG_PRINT_LOW("venc_set_param:QOMX_IndexConfigVideoIntraperiod\n"); QOMX_VIDEO_INTRAPERIODTYPE *intraperiod = (QOMX_VIDEO_INTRAPERIODTYPE *)configData; if(intraperiod->nPortIndex == (OMX_U32) PORT_INDEX_OUT) { if(venc_set_intra_period(intraperiod->nPFrames, intraperiod->nBFrames) == false) { DEBUG_PRINT_ERROR("\nERROR: Request for setting intra period failed"); return false; } } break; } case OMX_IndexConfigVideoIntraVOPRefresh: { OMX_CONFIG_INTRAREFRESHVOPTYPE *intra_vop_refresh = (OMX_CONFIG_INTRAREFRESHVOPTYPE *) configData; DEBUG_PRINT_LOW("\n venc_set_config: OMX_IndexConfigVideoIntraVOPRefresh"); if(intra_vop_refresh->nPortIndex == (OMX_U32)PORT_INDEX_OUT) { if(venc_set_intra_vop_refresh(intra_vop_refresh->IntraRefreshVOP) == false) { DEBUG_PRINT_ERROR("\nERROR: Setting Encode Framerate failed"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: Invalid Port Index for OMX_IndexConfigVideoFramerate"); } break; } case OMX_IndexConfigCommonRotate: { OMX_CONFIG_ROTATIONTYPE *config_rotation = reinterpret_cast(configData); venc_ioctl_msg ioctl_msg = {NULL,NULL}; OMX_U32 nFrameWidth; DEBUG_PRINT_HIGH("\nvenc_set_config: updating the new Dims"); nFrameWidth = m_sVenc_cfg.input_width; m_sVenc_cfg.input_width = m_sVenc_cfg.input_height; m_sVenc_cfg.input_height = nFrameWidth; ioctl_msg.in = (void*)&m_sVenc_cfg; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_BASE_CFG,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Dimension Change for Rotation failed"); return false; } break; } default: DEBUG_PRINT_ERROR("\n Unsupported config index = %u", index); break; } return true; } unsigned venc_dev::venc_stop( void) { #ifdef MAX_RES_1080P pmem_free(); #endif return ioctl(m_nDriver_fd,VEN_IOCTL_CMD_STOP,NULL); } unsigned venc_dev::venc_pause(void) { return ioctl(m_nDriver_fd,VEN_IOCTL_CMD_PAUSE,NULL); } unsigned venc_dev::venc_resume(void) { return ioctl(m_nDriver_fd,VEN_IOCTL_CMD_RESUME,NULL) ; } unsigned venc_dev::venc_start_done(void) { return 0; } unsigned venc_dev::venc_stop_done(void) { return 0; } unsigned venc_dev::venc_start(void) { DEBUG_PRINT_HIGH("\n %s(): Check Profile/Level set in driver before start", __func__); if (!venc_set_profile_level(0, 0)) { DEBUG_PRINT_ERROR("\n ERROR: %s(): Driver Profile/Level is NOT SET", __func__); } else { DEBUG_PRINT_HIGH("\n %s(): Driver Profile[%lu]/Level[%lu] successfully SET", __func__, codec_profile.profile, profile_level.level); } if(m_max_allowed_bitrate_check && !venc_max_allowed_bitrate_check(bitrate.target_bitrate)) { DEBUG_PRINT_ERROR("Maximum Allowed Bitrate Check failed"); return -1; } venc_config_print(); #ifdef MAX_RES_1080P if((codec_profile.profile == VEN_PROFILE_MPEG4_SP) || (codec_profile.profile == VEN_PROFILE_H264_BASELINE) || (codec_profile.profile == VEN_PROFILE_H263_BASELINE)) recon_buffers_count = MAX_RECON_BUFFERS - 2; else recon_buffers_count = MAX_RECON_BUFFERS; if (!venc_allocate_recon_buffers()) return ioctl(m_nDriver_fd, VEN_IOCTL_CMD_START, NULL); else { DEBUG_PRINT_ERROR("Failed in creating Recon buffers\n"); return -1; } #else return ioctl(m_nDriver_fd, VEN_IOCTL_CMD_START, NULL); #endif } #ifdef MAX_RES_1080P OMX_U32 venc_dev::venc_allocate_recon_buffers() { OMX_U32 yuv_size; struct venc_ioctl_msg ioctl_msg; struct venc_recon_buff_size recon_buff_size; recon_buff_size.width = ((m_sVenc_cfg.input_width + 15) / 16) * 16; recon_buff_size.height = ((m_sVenc_cfg.input_height + 15) / 16 ) * 16; DEBUG_PRINT_LOW("Width %d, Height %d, w_round %d, h_round %d\n", m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, recon_buff_size.width, recon_buff_size.height); ioctl_msg.in = NULL; ioctl_msg.out = (void*)&recon_buff_size; if (ioctl (m_nDriver_fd,VEN_IOCTL_GET_RECON_BUFFER_SIZE, (void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\n VEN_IOCTL_GET_RECON_BUFFER_SIZE Failed for width: %d, Height %d" , recon_buff_size.width, recon_buff_size.height); return OMX_ErrorInsufficientResources; } DEBUG_PRINT_HIGH("Width %d, Height %d, w_round %d, h_round %d, yuv_size %d alignment %d count %d\n", m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, recon_buff_size.width, recon_buff_size.height, recon_buff_size.size, recon_buff_size.alignment, recon_buffers_count); for(int i = 0; i < recon_buffers_count; i++) { if(pmem_allocate(recon_buff_size.size, recon_buff_size.alignment,i)) { DEBUG_PRINT_ERROR("Error returned in allocating recon buffers\n"); return -1; } } return 0; } OMX_U32 venc_dev::pmem_allocate(OMX_U32 size, OMX_U32 alignment, OMX_U32 count) { OMX_U32 pmem_fd = -1; OMX_U32 width, height; void *buf_addr = NULL; struct venc_ioctl_msg ioctl_msg; struct venc_recon_addr recon_addr; int rc = 0; #ifdef USE_ION recon_buff[count].ion_device_fd = open (MEM_DEVICE,O_RDONLY | O_DSYNC); if(recon_buff[count].ion_device_fd < 0) { DEBUG_PRINT_ERROR("\nERROR: ION Device open() Failed"); return -1; } recon_buff[count].alloc_data.flags = 0; recon_buff[count].alloc_data.len = size; recon_buff[count].alloc_data.heap_id_mask = (ION_HEAP(MEM_HEAP_ID) | (venc_encoder->is_secure_session() ? ION_SECURE : ION_HEAP(ION_IOMMU_HEAP_ID))); recon_buff[count].alloc_data.align = clip2(alignment); if (recon_buff[count].alloc_data.align != 8192) recon_buff[count].alloc_data.align = 8192; rc = ioctl(recon_buff[count].ion_device_fd,ION_IOC_ALLOC,&recon_buff[count].alloc_data); if(rc || !recon_buff[count].alloc_data.handle) { DEBUG_PRINT_ERROR("\n ION ALLOC memory failed "); recon_buff[count].alloc_data.handle=NULL; return -1; } recon_buff[count].ion_alloc_fd.handle = recon_buff[count].alloc_data.handle; rc = ioctl(recon_buff[count].ion_device_fd,ION_IOC_MAP,&recon_buff[count].ion_alloc_fd); if(rc) { DEBUG_PRINT_ERROR("\n ION MAP failed "); recon_buff[count].ion_alloc_fd.fd =-1; recon_buff[count].ion_alloc_fd.fd =-1; return -1; } pmem_fd = recon_buff[count].ion_alloc_fd.fd; #else struct pmem_allocation allocation; pmem_fd = open(MEM_DEVICE, O_RDWR); if ((int)(pmem_fd) < 0) { DEBUG_PRINT_ERROR("\n Failed to get an pmem handle"); return -1; } allocation.size = size; allocation.align = clip2(alignment); if (allocation.align != 8192) allocation.align = 8192; if (ioctl(pmem_fd, PMEM_ALLOCATE_ALIGNED, &allocation) < 0) { DEBUG_PRINT_ERROR("\n Aligment(%u) failed with pmem driver Sz(%lu)", allocation.align, allocation.size); return -1; } #endif if(!venc_encoder->is_secure_session()) { buf_addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, pmem_fd, 0); if (buf_addr == (void*) MAP_FAILED) { close(pmem_fd); pmem_fd = -1; DEBUG_PRINT_ERROR("Error returned in allocating recon buffers buf_addr: %p\n",buf_addr); #ifdef USE_ION if(ioctl(recon_buff[count].ion_device_fd,ION_IOC_FREE, &recon_buff[count].alloc_data.handle)) { DEBUG_PRINT_ERROR("ion recon buffer free failed"); } recon_buff[count].alloc_data.handle = NULL; recon_buff[count].ion_alloc_fd.fd =-1; close(recon_buff[count].ion_device_fd); recon_buff[count].ion_device_fd =-1; #endif return -1; } } DEBUG_PRINT_HIGH("\n Allocated virt:%p, FD: %d of size %d \n", buf_addr, pmem_fd, size); recon_addr.buffer_size = size; recon_addr.pmem_fd = pmem_fd; recon_addr.offset = 0; if(!venc_encoder->is_secure_session()) recon_addr.pbuffer = (unsigned char *)buf_addr; else recon_addr.pbuffer = (unsigned char *)(pmem_fd + 1); ioctl_msg.in = (void*)&recon_addr; ioctl_msg.out = NULL; if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_RECON_BUFFER, (void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("Failed to set the Recon_buffers\n"); return -1; } recon_buff[count].virtual_address = (unsigned char *) buf_addr; recon_buff[count].size = size; recon_buff[count].offset = 0; recon_buff[count].pmem_fd = pmem_fd; DEBUG_PRINT_ERROR("\n Allocated virt:%p, FD: %d of size %d at index: %d\n", recon_buff[count].virtual_address, recon_buff[count].pmem_fd, recon_buff[count].size, count); return 0; } OMX_U32 venc_dev::pmem_free() { int cnt = 0; struct venc_ioctl_msg ioctl_msg; struct venc_recon_addr recon_addr; for (cnt = 0; cnt < recon_buffers_count; cnt++) { if(recon_buff[cnt].pmem_fd) { recon_addr.pbuffer = recon_buff[cnt].virtual_address; recon_addr.offset = recon_buff[cnt].offset; recon_addr.pmem_fd = recon_buff[cnt].pmem_fd; recon_addr.buffer_size = recon_buff[cnt].size; ioctl_msg.in = (void*)&recon_addr; ioctl_msg.out = NULL; if(ioctl(m_nDriver_fd, VEN_IOCTL_FREE_RECON_BUFFER ,&ioctl_msg) < 0) DEBUG_PRINT_ERROR("VEN_IOCTL_FREE_RECON_BUFFER failed"); if(!venc_encoder->is_secure_session()) munmap(recon_buff[cnt].virtual_address, recon_buff[cnt].size); close(recon_buff[cnt].pmem_fd); #ifdef USE_ION if(ioctl(recon_buff[cnt].ion_device_fd,ION_IOC_FREE, &recon_buff[cnt].alloc_data.handle)) { DEBUG_PRINT_ERROR("ion recon buffer free failed"); } recon_buff[cnt].alloc_data.handle = NULL; recon_buff[cnt].ion_alloc_fd.fd =-1; close(recon_buff[cnt].ion_device_fd); recon_buff[cnt].ion_device_fd =-1; #endif DEBUG_PRINT_LOW("\n cleaning Index %d of size %d \n",cnt,recon_buff[cnt].size); recon_buff[cnt].pmem_fd = -1; recon_buff[cnt].virtual_address = NULL; recon_buff[cnt].offset = 0; recon_buff[cnt].alignment = 0; recon_buff[cnt].size = 0; } } return 0; } #endif void venc_dev::venc_config_print() { DEBUG_PRINT_HIGH("\nENC_CONFIG: Codec: %d, Profile %d, level : %d", m_sVenc_cfg.codectype, codec_profile.profile, profile_level.level); DEBUG_PRINT_HIGH("\n ENC_CONFIG: Width: %d, Height:%d, Fps: %d", m_sVenc_cfg.input_width, m_sVenc_cfg.input_height, m_sVenc_cfg.fps_num/m_sVenc_cfg.fps_den); DEBUG_PRINT_HIGH("\nENC_CONFIG: Bitrate: %d, RC: %d, I-Period: %d", bitrate.target_bitrate, rate_ctrl.rcmode, intra_period.num_pframes); DEBUG_PRINT_HIGH("\nENC_CONFIG: qpI: %d, qpP: %d, qpb: 0", session_qp.iframeqp, session_qp.pframqp); DEBUG_PRINT_HIGH("\nENC_CONFIG: VOP_Resolution: %d, Slice-Mode: %d, Slize_Size: %d", voptimecfg.voptime_resolution, multislice.mslice_mode, multislice.mslice_size); DEBUG_PRINT_HIGH("\nENC_CONFIG: EntropyMode: %d, CabacModel: %d", entropy.longentropysel, entropy.cabacmodel); DEBUG_PRINT_HIGH("\nENC_CONFIG: DB-Mode: %d, alpha: %d, Beta: %d\n", dbkfilter.db_mode, dbkfilter.slicealpha_offset, dbkfilter.slicebeta_offset); DEBUG_PRINT_HIGH("\nENC_CONFIG: IntraMB/Frame: %d, HEC: %d\n", intra_refresh.mbcount, hec.header_extension); } unsigned venc_dev::venc_flush( unsigned port) { struct venc_ioctl_msg ioctl_msg; struct venc_bufferflush buffer_index; if(port == PORT_INDEX_IN) { DEBUG_PRINT_HIGH("Calling Input Flush"); buffer_index.flush_mode = VEN_FLUSH_INPUT; ioctl_msg.in = (void*)&buffer_index; ioctl_msg.out = NULL; return ioctl (m_nDriver_fd,VEN_IOCTL_CMD_FLUSH,(void*)&ioctl_msg); } else if(port == PORT_INDEX_OUT) { DEBUG_PRINT_HIGH("Calling Output Flush"); buffer_index.flush_mode = VEN_FLUSH_OUTPUT; ioctl_msg.in = (void*)&buffer_index; ioctl_msg.out = NULL; return ioctl (m_nDriver_fd,VEN_IOCTL_CMD_FLUSH,(void*)&ioctl_msg); } else { return -1; } } //allocating I/P memory from pmem and register with the device bool venc_dev::venc_use_buf(void *buf_addr, unsigned port,unsigned) { struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; struct pmem *pmem_tmp; struct venc_bufferpayload dev_buffer = {0}; struct venc_allocatorproperty buff_alloc_property = {0}; pmem_tmp = (struct pmem *)buf_addr; DEBUG_PRINT_LOW("\n venc_use_buf:: pmem_tmp = %p", pmem_tmp); if(port == PORT_INDEX_IN) { dev_buffer.pbuffer = (OMX_U8 *)pmem_tmp->buffer; dev_buffer.fd = pmem_tmp->fd; dev_buffer.maped_size = pmem_tmp->size; dev_buffer.sz = pmem_tmp->size; dev_buffer.offset = pmem_tmp->offset; if((m_sVenc_cfg.input_height %16 !=0) || (m_sVenc_cfg.input_width%16 != 0)) { unsigned long ht = m_sVenc_cfg.input_height; unsigned long wd = m_sVenc_cfg.input_width; unsigned int luma_size, luma_size_2k; ht = (ht + 15) & ~15; wd = (wd + 15) & ~15; luma_size = ht * wd; luma_size_2k = (luma_size + 2047) & ~2047; dev_buffer.sz = luma_size_2k + ((luma_size/2 + 2047) & ~2047); #ifdef USE_ION ioctl_msg.in = NULL; ioctl_msg.out = (void*)&buff_alloc_property; if(ioctl (m_nDriver_fd,VEN_IOCTL_GET_INPUT_BUFFER_REQ,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: venc_use_buf:get input buffer failed "); return false; } if(buff_alloc_property.alignment < 4096) { dev_buffer.sz = ((dev_buffer.sz + 4095) & ~4095); } else { dev_buffer.sz = ((dev_buffer.sz + (buff_alloc_property.alignment - 1)) & ~(buff_alloc_property.alignment - 1)); } #endif dev_buffer.maped_size = dev_buffer.sz; } ioctl_msg.in = (void*)&dev_buffer; ioctl_msg.out = NULL; DEBUG_PRINT_LOW("\n venc_use_buf:pbuffer = %x,fd = %x, offset = %d, maped_size = %d", \ dev_buffer.pbuffer, \ dev_buffer.fd, \ dev_buffer.offset, \ dev_buffer.maped_size); if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_INPUT_BUFFER,&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: venc_use_buf:set input buffer failed "); return false; } } else if(port == PORT_INDEX_OUT) { dev_buffer.pbuffer = (OMX_U8 *)pmem_tmp->buffer; dev_buffer.fd = pmem_tmp->fd; dev_buffer.sz = pmem_tmp->size; dev_buffer.maped_size = pmem_tmp->size; dev_buffer.offset = pmem_tmp->offset; ioctl_msg.in = (void*)&dev_buffer; ioctl_msg.out = NULL; DEBUG_PRINT_LOW("\n venc_use_buf:pbuffer = %x,fd = %x, offset = %d, maped_size = %d", \ dev_buffer.pbuffer, \ dev_buffer.fd, \ dev_buffer.offset, \ dev_buffer.maped_size); if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_OUTPUT_BUFFER,&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: venc_use_buf:set output buffer failed "); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: venc_use_buf:Invalid Port Index "); return false; } return true; } bool venc_dev::venc_free_buf(void *buf_addr, unsigned port) { struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; struct pmem *pmem_tmp; struct venc_bufferpayload dev_buffer = {0}; pmem_tmp = (struct pmem *)buf_addr; DEBUG_PRINT_LOW("\n venc_use_buf:: pmem_tmp = %p", pmem_tmp); if(port == PORT_INDEX_IN) { dev_buffer.pbuffer = (OMX_U8 *)pmem_tmp->buffer; dev_buffer.fd = pmem_tmp->fd; dev_buffer.maped_size = pmem_tmp->size; dev_buffer.sz = pmem_tmp->size; dev_buffer.offset = pmem_tmp->offset; ioctl_msg.in = (void*)&dev_buffer; ioctl_msg.out = NULL; DEBUG_PRINT_LOW("\n venc_free_buf:pbuffer = %x,fd = %x, offset = %d, maped_size = %d", \ dev_buffer.pbuffer, \ dev_buffer.fd, \ dev_buffer.offset, \ dev_buffer.maped_size); if(ioctl (m_nDriver_fd,VEN_IOCTL_CMD_FREE_INPUT_BUFFER,&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: venc_free_buf: free input buffer failed "); return false; } } else if(port == PORT_INDEX_OUT) { dev_buffer.pbuffer = (OMX_U8 *)pmem_tmp->buffer; dev_buffer.fd = pmem_tmp->fd; dev_buffer.sz = pmem_tmp->size; dev_buffer.maped_size = pmem_tmp->size; dev_buffer.offset = pmem_tmp->offset; ioctl_msg.in = (void*)&dev_buffer; ioctl_msg.out = NULL; DEBUG_PRINT_LOW("\n venc_free_buf:pbuffer = %x,fd = %x, offset = %d, maped_size = %d", \ dev_buffer.pbuffer, \ dev_buffer.fd, \ dev_buffer.offset, \ dev_buffer.maped_size); if(ioctl (m_nDriver_fd,VEN_IOCTL_CMD_FREE_OUTPUT_BUFFER,&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: venc_free_buf: free output buffer failed "); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: venc_free_buf:Invalid Port Index "); return false; } return true; } bool venc_dev::venc_empty_buf(void *buffer, void *pmem_data_buf,unsigned,unsigned) { struct venc_buffer frameinfo; struct pmem *temp_buffer; struct venc_ioctl_msg ioctl_msg; struct OMX_BUFFERHEADERTYPE *bufhdr; if(buffer == NULL) { DEBUG_PRINT_ERROR("\nERROR: venc_etb: buffer is NULL"); return false; } bufhdr = (OMX_BUFFERHEADERTYPE *)buffer; DEBUG_PRINT_LOW("\n Input buffer length %d",bufhdr->nFilledLen); if(pmem_data_buf) { DEBUG_PRINT_LOW("\n Internal PMEM addr for i/p Heap UseBuf: %p", pmem_data_buf); frameinfo.ptrbuffer = (OMX_U8 *)pmem_data_buf; } else { DEBUG_PRINT_LOW("\n Shared PMEM addr for i/p PMEM UseBuf/AllocateBuf: %p", bufhdr->pBuffer); frameinfo.ptrbuffer = (OMX_U8 *)bufhdr->pBuffer; } frameinfo.clientdata = (void *) buffer; frameinfo.sz = bufhdr->nFilledLen; frameinfo.len = bufhdr->nFilledLen; frameinfo.flags = bufhdr->nFlags; frameinfo.offset = bufhdr->nOffset; frameinfo.timestamp = bufhdr->nTimeStamp; DEBUG_PRINT_LOW("\n i/p TS = %u", (OMX_U32)frameinfo.timestamp); ioctl_msg.in = &frameinfo; ioctl_msg.out = NULL; DEBUG_PRINT_LOW("DBG: i/p frameinfo: bufhdr->pBuffer = %p, ptrbuffer = %p, offset = %u, len = %u", bufhdr->pBuffer, frameinfo.ptrbuffer, frameinfo.offset, frameinfo.len); if(ioctl(m_nDriver_fd,VEN_IOCTL_CMD_ENCODE_FRAME,&ioctl_msg) < 0) { /*Generate an async error and move to invalid state*/ return false; } #ifdef INPUT_BUFFER_LOG #ifdef MAX_RES_1080P int y_size = 0; int c_offset = 0; unsigned char *buf_addr = NULL; y_size = m_sVenc_cfg.input_width * m_sVenc_cfg.input_height; //chroma offset is y_size aligned to the 2k boundary c_offset= (y_size + 2047) & (~(2047)); if(pmem_data_buf) { DEBUG_PRINT_LOW("\n Internal PMEM addr for i/p Heap UseBuf: %p", pmem_data_buf); buf_addr = (OMX_U8 *)pmem_data_buf; } else { DEBUG_PRINT_LOW("\n Shared PMEM addr for i/p PMEM UseBuf/AllocateBuf: %p", bufhdr->pBuffer); buf_addr = (unsigned char *)mmap(NULL, ((encoder_media_buffer_type *)bufhdr->pBuffer)->meta_handle->data[2], PROT_READ|PROT_WRITE, MAP_SHARED, ((encoder_media_buffer_type *)bufhdr->pBuffer)->meta_handle->data[0], 0); } if(inputBufferFile1) { fwrite((const char *)buf_addr, y_size, 1,inputBufferFile1); fwrite((const char *)(buf_addr + c_offset), (y_size>>1), 1,inputBufferFile1); } munmap (buf_addr, ((encoder_media_buffer_type *)bufhdr->pBuffer)->meta_handle->data[2]); #else if(inputBufferFile1) { fwrite((const char *)frameinfo.ptrbuffer, frameinfo.len, 1,inputBufferFile1); } #endif #endif return true; } bool venc_dev::venc_fill_buf(void *buffer, void *pmem_data_buf,unsigned,unsigned) { struct venc_ioctl_msg ioctl_msg = {NULL,NULL}; struct pmem *temp_buffer = NULL; struct venc_buffer frameinfo; struct OMX_BUFFERHEADERTYPE *bufhdr; if(buffer == NULL) { return false; } bufhdr = (OMX_BUFFERHEADERTYPE *)buffer; if(pmem_data_buf) { DEBUG_PRINT_LOW("\n Internal PMEM addr for o/p Heap UseBuf: %p", pmem_data_buf); frameinfo.ptrbuffer = (OMX_U8 *)pmem_data_buf; } else { DEBUG_PRINT_LOW("\n Shared PMEM addr for o/p PMEM UseBuf/AllocateBuf: %p", bufhdr->pBuffer); frameinfo.ptrbuffer = (OMX_U8 *)bufhdr->pBuffer; } frameinfo.clientdata = buffer; frameinfo.sz = bufhdr->nAllocLen; frameinfo.flags = bufhdr->nFlags; frameinfo.offset = bufhdr->nOffset; ioctl_msg.in = &frameinfo; ioctl_msg.out = NULL; DEBUG_PRINT_LOW("DBG: o/p frameinfo: bufhdr->pBuffer = %p, ptrbuffer = %p, offset = %u, len = %u", bufhdr->pBuffer, frameinfo.ptrbuffer, frameinfo.offset, frameinfo.len); if(ioctl (m_nDriver_fd,VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER,&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: ioctl VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER failed"); return false; } return true; } bool venc_dev::venc_set_slice_delivery_mode(OMX_BOOL enable) { venc_ioctl_msg ioctl_msg = {NULL,NULL}; DEBUG_PRINT_HIGH("Set slice_delivery_mode: %d", enable); if(multislice.mslice_mode == VEN_MSLICE_CNT_MB) { if(ioctl(m_nDriver_fd, VEN_IOCTL_SET_SLICE_DELIVERY_MODE) < 0) { DEBUG_PRINT_ERROR("Request for setting slice delivery mode failed"); return false; } } else { DEBUG_PRINT_ERROR("WARNING: slice_mode[%d] is not VEN_MSLICE_CNT_MB to set " "slice delivery mode to the driver.", multislice.mslice_mode); } return true; } bool venc_dev::venc_set_inband_video_header(OMX_BOOL enable) { venc_ioctl_msg ioctl_msg = {(void *)&enable, NULL}; DEBUG_PRINT_HIGH("Set inband sps/pps: %d", enable); if(ioctl(m_nDriver_fd, VEN_IOCTL_SET_SPS_PPS_FOR_IDR, (void *)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("Request for inband sps/pps failed"); return false; } return true; } bool venc_dev::venc_set_bitstream_restrict_in_vui(OMX_BOOL enable) { venc_ioctl_msg ioctl_msg = {NULL, NULL}; DEBUG_PRINT_HIGH("Set bistream_restrict in vui: %d", enable); if(ioctl(m_nDriver_fd, VEN_IOCTL_SET_VUI_BITSTREAM_RESTRICT_FLAG, (void *)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("Request for setting bitstream_restrict flag in VUI failed"); return false; } return true; } bool venc_dev::venc_set_extradata(OMX_U32 extra_data) { venc_ioctl_msg ioctl_msg = {NULL,NULL}; DEBUG_PRINT_HIGH("venc_set_extradata:: %x", extra_data); ioctl_msg.in = (void*)&extra_data; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd, VEN_IOCTL_SET_EXTRADATA, (void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("ERROR: Request for setting extradata failed"); return false; } return true; } bool venc_dev::venc_set_session_qp(OMX_U32 i_frame_qp, OMX_U32 p_frame_qp) { venc_ioctl_msg ioctl_msg = {NULL,NULL}; struct venc_sessionqp qp = {0, 0}; DEBUG_PRINT_LOW("venc_set_session_qp:: i_frame_qp = %d, p_frame_qp = %d", i_frame_qp, p_frame_qp); qp.iframeqp = i_frame_qp; qp.pframqp = p_frame_qp; ioctl_msg.in = (void*)&qp; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_SESSION_QP,(void*)&ioctl_msg)< 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting session qp failed"); return false; } session_qp.iframeqp = i_frame_qp; session_qp.pframqp = p_frame_qp; return true; } bool venc_dev::venc_set_profile_level(OMX_U32 eProfile,OMX_U32 eLevel) { venc_ioctl_msg ioctl_msg = {NULL,NULL}; struct venc_profile requested_profile; struct ven_profilelevel requested_level; unsigned const int *profile_tbl = NULL; unsigned long mb_per_frame = 0, mb_per_sec = 0; DEBUG_PRINT_LOW("venc_set_profile_level:: eProfile = %d, Level = %d", eProfile, eLevel); mb_per_frame = ((m_sVenc_cfg.input_height + 15) >> 4)* ((m_sVenc_cfg.input_width + 15) >> 4); if((eProfile == 0) && (eLevel == 0) && m_profile_set && m_level_set) { DEBUG_PRINT_LOW("\n Profile/Level setting complete before venc_start"); return true; } if(eProfile && eLevel) { /* non-zero values will be set by user, saving the same*/ m_eProfile = eProfile; m_eLevel = eLevel; DEBUG_PRINT_HIGH("Profile/Level set equal to %d/%d",m_eProfile, m_eLevel); } DEBUG_PRINT_LOW("\n Validating Profile/Level from table"); if(!venc_validate_profile_level(&eProfile, &eLevel)) { DEBUG_PRINT_LOW("\nERROR: Profile/Level validation failed"); return false; } if(m_sVenc_cfg.codectype == VEN_CODEC_MPEG4) { DEBUG_PRINT_LOW("eProfile = %d, OMX_VIDEO_MPEG4ProfileSimple = %d and " "OMX_VIDEO_MPEG4ProfileAdvancedSimple = %d", eProfile, OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4ProfileAdvancedSimple); if(eProfile == OMX_VIDEO_MPEG4ProfileSimple) { requested_profile.profile = VEN_PROFILE_MPEG4_SP; profile_tbl = (unsigned int const *) (&mpeg4_profile_level_table[MPEG4_SP_START]); profile_tbl += MPEG4_720P_LEVEL*5; } else if(eProfile == OMX_VIDEO_MPEG4ProfileAdvancedSimple) { requested_profile.profile = VEN_PROFILE_MPEG4_ASP; profile_tbl = (unsigned int const *) (&mpeg4_profile_level_table[MPEG4_ASP_START]); profile_tbl += MPEG4_720P_LEVEL*5; } else { DEBUG_PRINT_LOW("\nERROR: Unsupported MPEG4 profile = %u", eProfile); return false; } DEBUG_PRINT_LOW("eLevel = %d, OMX_VIDEO_MPEG4Level0 = %d, OMX_VIDEO_MPEG4Level1 = %d," "OMX_VIDEO_MPEG4Level2 = %d, OMX_VIDEO_MPEG4Level3 = %d, OMX_VIDEO_MPEG4Level4 = %d," "OMX_VIDEO_MPEG4Level5 = %d", eLevel, OMX_VIDEO_MPEG4Level0, OMX_VIDEO_MPEG4Level1, OMX_VIDEO_MPEG4Level2, OMX_VIDEO_MPEG4Level3, OMX_VIDEO_MPEG4Level4, OMX_VIDEO_MPEG4Level5); if(mb_per_frame >= 3600) { if(requested_profile.profile == VEN_PROFILE_MPEG4_ASP) requested_level.level = VEN_LEVEL_MPEG4_5; if(requested_profile.profile == VEN_PROFILE_MPEG4_SP) requested_level.level = VEN_LEVEL_MPEG4_6; } else { switch(eLevel) { case OMX_VIDEO_MPEG4Level0: requested_level.level = VEN_LEVEL_MPEG4_0; break; case OMX_VIDEO_MPEG4Level1: requested_level.level = VEN_LEVEL_MPEG4_1; break; case OMX_VIDEO_MPEG4Level2: requested_level.level = VEN_LEVEL_MPEG4_2; break; case OMX_VIDEO_MPEG4Level3: requested_level.level = VEN_LEVEL_MPEG4_3; break; case OMX_VIDEO_MPEG4Level4a: requested_level.level = VEN_LEVEL_MPEG4_4; break; case OMX_VIDEO_MPEG4Level5: mb_per_sec = mb_per_frame * (m_sVenc_cfg.fps_num / m_sVenc_cfg.fps_den); if((requested_profile.profile == VEN_PROFILE_MPEG4_SP) && (mb_per_frame >= profile_tbl[0]) && (mb_per_sec >= profile_tbl[1])) { DEBUG_PRINT_LOW("\nMPEG4 Level 6 is set for 720p resolution"); requested_level.level = VEN_LEVEL_MPEG4_6; } else { DEBUG_PRINT_LOW("\nMPEG4 Level 5 is set for non-720p resolution"); requested_level.level = VEN_LEVEL_MPEG4_5; } break; default: return false; // TODO update corresponding levels for MPEG4_LEVEL_3b,MPEG4_LEVEL_6 break; } } } else if(m_sVenc_cfg.codectype == VEN_CODEC_H263) { if(eProfile == OMX_VIDEO_H263ProfileBaseline) { requested_profile.profile = VEN_PROFILE_H263_BASELINE; } else { DEBUG_PRINT_LOW("\nERROR: Unsupported H.263 profile = %u", requested_profile.profile); return false; } //profile level switch(eLevel) { case OMX_VIDEO_H263Level10: requested_level.level = VEN_LEVEL_H263_10; break; case OMX_VIDEO_H263Level20: requested_level.level = VEN_LEVEL_H263_20; break; case OMX_VIDEO_H263Level30: requested_level.level = VEN_LEVEL_H263_30; break; case OMX_VIDEO_H263Level40: requested_level.level = VEN_LEVEL_H263_40; break; case OMX_VIDEO_H263Level45: requested_level.level = VEN_LEVEL_H263_45; break; case OMX_VIDEO_H263Level50: requested_level.level = VEN_LEVEL_H263_50; break; case OMX_VIDEO_H263Level60: requested_level.level = VEN_LEVEL_H263_60; break; case OMX_VIDEO_H263Level70: requested_level.level = VEN_LEVEL_H263_70; break; default: return false; break; } } else if(m_sVenc_cfg.codectype == VEN_CODEC_H264) { if(eProfile == OMX_VIDEO_AVCProfileBaseline) { requested_profile.profile = VEN_PROFILE_H264_BASELINE; } else if(eProfile == OMX_VIDEO_AVCProfileMain) { requested_profile.profile = VEN_PROFILE_H264_MAIN; } else if(eProfile == OMX_VIDEO_AVCProfileHigh) { requested_profile.profile = VEN_PROFILE_H264_HIGH; } else { DEBUG_PRINT_LOW("\nERROR: Unsupported H.264 profile = %u", requested_profile.profile); return false; } //profile level switch(eLevel) { case OMX_VIDEO_AVCLevel1: requested_level.level = VEN_LEVEL_H264_1; break; case OMX_VIDEO_AVCLevel1b: requested_level.level = VEN_LEVEL_H264_1b; break; case OMX_VIDEO_AVCLevel11: requested_level.level = VEN_LEVEL_H264_1p1; break; case OMX_VIDEO_AVCLevel12: requested_level.level = VEN_LEVEL_H264_1p2; break; case OMX_VIDEO_AVCLevel13: requested_level.level = VEN_LEVEL_H264_1p3; break; case OMX_VIDEO_AVCLevel2: requested_level.level = VEN_LEVEL_H264_2; break; case OMX_VIDEO_AVCLevel21: requested_level.level = VEN_LEVEL_H264_2p1; break; case OMX_VIDEO_AVCLevel22: requested_level.level = VEN_LEVEL_H264_2p2; break; case OMX_VIDEO_AVCLevel3: requested_level.level = VEN_LEVEL_H264_3; break; case OMX_VIDEO_AVCLevel31: requested_level.level = VEN_LEVEL_H264_3p1; break; case OMX_VIDEO_AVCLevel32: requested_level.level = VEN_LEVEL_H264_3p2; break; case OMX_VIDEO_AVCLevel4: requested_level.level = VEN_LEVEL_H264_4; break; default : DEBUG_PRINT_ERROR("\nERROR: Unsupported H.264 level= %u", requested_level.level); return false; break; } } if(!m_profile_set) { ioctl_msg.in = (void*)&requested_profile; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_CODEC_PROFILE,(void*)&ioctl_msg)< 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting profile failed"); return false; } codec_profile.profile = requested_profile.profile; m_profile_set = true; } if(!m_level_set) { ioctl_msg.in = (void*)&requested_level; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_PROFILE_LEVEL,(void*)&ioctl_msg)< 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting profile level failed"); return false; } profile_level.level = requested_level.level; m_level_set = true; } return true; } bool venc_dev::venc_set_voptiming_cfg( OMX_U32 TimeIncRes) { venc_ioctl_msg ioctl_msg = {NULL,NULL}; struct venc_voptimingcfg vop_timing_cfg; DEBUG_PRINT_LOW("\n venc_set_voptiming_cfg: TimeRes = %u", TimeIncRes); vop_timing_cfg.voptime_resolution = TimeIncRes; ioctl_msg.in = (void*)&vop_timing_cfg; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_VOP_TIMING_CFG,(void*)&ioctl_msg)< 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting Vop Timing failed"); return false; } voptimecfg.voptime_resolution = vop_timing_cfg.voptime_resolution; return true; } bool venc_dev::venc_set_intra_period(OMX_U32 nPFrames, OMX_U32 nBFrames) { venc_ioctl_msg ioctl_msg = {NULL,NULL}; struct venc_intraperiod intraperiod_cfg; DEBUG_PRINT_LOW("\n venc_set_intra_period: nPFrames = %u", nPFrames); intraperiod_cfg.num_pframes = nPFrames; if((codec_profile.profile == VEN_PROFILE_MPEG4_ASP) || (codec_profile.profile == VEN_PROFILE_H264_MAIN) || (codec_profile.profile == VEN_PROFILE_H264_HIGH)) { #ifdef MAX_RES_1080P if (nBFrames) { DEBUG_PRINT_HIGH("INFO: Only 1 Bframe is supported"); intraperiod_cfg.num_bframes = 1; } else intraperiod_cfg.num_bframes = 0; #else if(nBFrames) { DEBUG_PRINT_ERROR("B frames not supported"); intraperiod_cfg.num_bframes = 0; } else { DEBUG_PRINT_ERROR("B frames not supported"); intraperiod_cfg.num_bframes = 0; } #endif } else intraperiod_cfg.num_bframes = 0; DEBUG_PRINT_ERROR("\n venc_set_intra_period: nPFrames = %u nBFrames = %u", intraperiod_cfg.num_pframes, intraperiod_cfg.num_bframes); ioctl_msg.in = (void*)&intraperiod_cfg; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_INTRA_PERIOD,(void*)&ioctl_msg)< 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting intra period failed"); return false; } intra_period.num_pframes = intraperiod_cfg.num_pframes; intra_period.num_bframes = intraperiod_cfg.num_bframes; return true; } bool venc_dev::venc_set_entropy_config(OMX_BOOL enable, OMX_U32 i_cabac_level) { venc_ioctl_msg ioctl_msg = {NULL,NULL}; struct venc_entropycfg entropy_cfg; memset(&entropy_cfg,0,sizeof(entropy_cfg)); DEBUG_PRINT_LOW("\n venc_set_entropy_config: CABAC = %u level: %u", enable, i_cabac_level); if(enable &&(codec_profile.profile != VEN_PROFILE_H264_BASELINE)){ entropy_cfg.longentropysel = VEN_ENTROPY_MODEL_CABAC; if (i_cabac_level == 0) { entropy_cfg.cabacmodel = VEN_CABAC_MODEL_0; } #ifdef MAX_RES_1080P else { DEBUG_PRINT_HIGH("Invalid model set (%d) defaulting to model 0",i_cabac_level); entropy_cfg.cabacmodel = VEN_CABAC_MODEL_0; } #else else if (i_cabac_level == 1) { entropy_cfg.cabacmodel = VEN_CABAC_MODEL_1; } else if (i_cabac_level == 2) { entropy_cfg.cabacmodel = VEN_CABAC_MODEL_2; } #endif } else if(!enable){ entropy_cfg.longentropysel = VEN_ENTROPY_MODEL_CAVLC; } else{ DEBUG_PRINT_ERROR("\nInvalid Entropy mode for Baseline Profile"); return false; } ioctl_msg.in = (void*)&entropy_cfg; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_ENTROPY_CFG,(void*)&ioctl_msg)< 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting entropy config failed"); return false; } entropy.longentropysel = entropy_cfg.longentropysel; entropy.cabacmodel = entropy_cfg.cabacmodel; return true; } bool venc_dev::venc_set_multislice_cfg(OMX_INDEXTYPE Codec, OMX_U32 nSlicesize) // MB { venc_ioctl_msg ioctl_msg = {NULL, NULL}; bool status = true; struct venc_multiclicecfg multislice_cfg; if((Codec != OMX_IndexParamVideoH263) && (nSlicesize)){ multislice_cfg.mslice_mode = VEN_MSLICE_CNT_MB; multislice_cfg.mslice_size = nSlicesize; } else{ multislice_cfg.mslice_mode = VEN_MSLICE_OFF; multislice_cfg.mslice_size = 0; } DEBUG_PRINT_LOW("\n %s(): mode = %u, size = %u", __func__, multislice_cfg.mslice_mode, multislice_cfg.mslice_size); ioctl_msg.in = (void*)&multislice_cfg; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd, VEN_IOCTL_SET_MULTI_SLICE_CFG,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting multi-slice cfg failed"); status = false; } else { multislice.mslice_mode = multislice_cfg.mslice_mode; multislice.mslice_size = nSlicesize; } return status; } bool venc_dev::venc_set_intra_refresh(OMX_VIDEO_INTRAREFRESHTYPE ir_mode, OMX_U32 irMBs) { venc_ioctl_msg ioctl_msg = {NULL, NULL}; bool status = true; struct venc_intrarefresh intraRefresh_cfg; // There is no disabled mode. Disabled mode is indicated by a 0 count. if (irMBs == 0 || ir_mode == OMX_VIDEO_IntraRefreshMax) { intraRefresh_cfg.irmode = VEN_IR_OFF; intraRefresh_cfg.mbcount = 0; } else if ((ir_mode == OMX_VIDEO_IntraRefreshCyclic) && (irMBs < ((m_sVenc_cfg.input_width * m_sVenc_cfg.input_height)>>8))) { intraRefresh_cfg.irmode = VEN_IR_CYCLIC; intraRefresh_cfg.mbcount = irMBs; } else { DEBUG_PRINT_ERROR("\nERROR: Invalid IntraRefresh Parameters:" "mb count: %d, mb mode:%d", irMBs, ir_mode); return false; } ioctl_msg.in = (void*)&intraRefresh_cfg; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_INTRA_REFRESH,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting Intra Refresh failed"); status = false; } else { intra_refresh.irmode = intraRefresh_cfg.irmode; intra_refresh.mbcount = intraRefresh_cfg.mbcount; } return status; } bool venc_dev::venc_set_error_resilience(OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE* error_resilience) { venc_ioctl_msg ioctl_msg = {NULL, NULL}; bool status = true; struct venc_headerextension hec_cfg; struct venc_multiclicecfg multislice_cfg; if (m_sVenc_cfg.codectype == OMX_VIDEO_CodingMPEG4) { if (error_resilience->bEnableHEC) { hec_cfg.header_extension = 1; } else { hec_cfg.header_extension = 0; } ioctl_msg.in = (void*)&hec_cfg; ioctl_msg.out = NULL; if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_HEC,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting HEader Error correction failed"); return false; } hec.header_extension = error_resilience->bEnableHEC; } if (error_resilience->bEnableRVLC) { DEBUG_PRINT_ERROR("\n RVLC is not Supported"); return false; } if (( m_sVenc_cfg.codectype != OMX_VIDEO_CodingH263) && (error_resilience->bEnableDataPartitioning)) { DEBUG_PRINT_ERROR("\n DataPartioning are not Supported for MPEG4/H264"); return false; } if (( m_sVenc_cfg.codectype != OMX_VIDEO_CodingH263) && (error_resilience->nResynchMarkerSpacing)) { multislice_cfg.mslice_mode = VEN_MSLICE_CNT_BYTE; multislice_cfg.mslice_size = error_resilience->nResynchMarkerSpacing; } else if (m_sVenc_cfg.codectype == OMX_VIDEO_CodingH263 && error_resilience->bEnableDataPartitioning) { multislice_cfg.mslice_mode = VEN_MSLICE_GOB; multislice_cfg.mslice_size = 0; } else { multislice_cfg.mslice_mode = VEN_MSLICE_OFF; multislice_cfg.mslice_size = 0; } DEBUG_PRINT_LOW("\n %s(): mode = %u, size = %u", __func__, multislice_cfg.mslice_mode, multislice_cfg.mslice_size); ioctl_msg.in = (void*)&multislice_cfg; ioctl_msg.out = NULL; if (ioctl (m_nDriver_fd,VEN_IOCTL_SET_MULTI_SLICE_CFG,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting multi-slice cfg failed"); status = false; } else { multislice.mslice_mode = multislice_cfg.mslice_mode ; multislice.mslice_size = multislice_cfg.mslice_size; } return status; } bool venc_dev::venc_set_inloop_filter(OMX_VIDEO_AVCLOOPFILTERTYPE loopfilter) { venc_ioctl_msg ioctl_msg = {NULL,NULL}; struct venc_dbcfg filter_cfg; memset(&filter_cfg, 0, sizeof(filter_cfg)); DEBUG_PRINT_LOW("\n venc_set_inloop_filter: %u",loopfilter); if (loopfilter == OMX_VIDEO_AVCLoopFilterEnable){ filter_cfg.db_mode = VEN_DB_ALL_BLKG_BNDRY; } else if(loopfilter == OMX_VIDEO_AVCLoopFilterDisable){ filter_cfg.db_mode = VEN_DB_DISABLE; } else if(loopfilter == OMX_VIDEO_AVCLoopFilterDisableSliceBoundary){ filter_cfg.db_mode = VEN_DB_SKIP_SLICE_BNDRY; } filter_cfg.slicealpha_offset = filter_cfg.slicebeta_offset = 0; ioctl_msg.in = (void*)&filter_cfg; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_DEBLOCKING_CFG,(void*)&ioctl_msg)< 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting inloop filter failed"); return false; } dbkfilter.db_mode = filter_cfg.db_mode; dbkfilter.slicealpha_offset = dbkfilter.slicebeta_offset = 0; return true; } bool venc_dev::venc_set_target_bitrate(OMX_U32 nTargetBitrate, OMX_U32 config) { venc_ioctl_msg ioctl_msg = {NULL, NULL}; struct venc_targetbitrate bitrate_cfg; DEBUG_PRINT_LOW("\n venc_set_target_bitrate: bitrate = %u", nTargetBitrate); bitrate_cfg.target_bitrate = nTargetBitrate ; ioctl_msg.in = (void*)&bitrate_cfg; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_TARGET_BITRATE,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting bit rate failed"); return false; } m_sVenc_cfg.targetbitrate = nTargetBitrate; bitrate.target_bitrate = nTargetBitrate; if(!config) { m_level_set = false; if(venc_set_profile_level(0, 0)) { DEBUG_PRINT_LOW("Calling set level (Bitrate) with %d\n",profile_level.level); } } return true; } bool venc_dev::venc_set_encode_framerate(OMX_U32 encode_framerate, OMX_U32 config) { venc_ioctl_msg ioctl_msg = {NULL, NULL}; struct venc_framerate frame_rate_cfg; Q16ToFraction(encode_framerate,frame_rate_cfg.fps_numerator,frame_rate_cfg.fps_denominator); DEBUG_PRINT_LOW("\n venc_set_encode_framerate: framerate(Q16) = %u,NR: %d, DR: %d", encode_framerate,frame_rate_cfg.fps_numerator,frame_rate_cfg.fps_denominator); ioctl_msg.in = (void*)&frame_rate_cfg; ioctl_msg.out = NULL; if(ioctl(m_nDriver_fd, VEN_IOCTL_SET_FRAME_RATE, (void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting framerate failed"); return false; } m_sVenc_cfg.fps_den = frame_rate_cfg.fps_denominator; m_sVenc_cfg.fps_num = frame_rate_cfg.fps_numerator; if(!config) { m_level_set = false; if(venc_set_profile_level(0, 0)) { DEBUG_PRINT_LOW("Calling set level (Framerate) with %d\n",profile_level.level); } } return true; } bool venc_dev::venc_set_color_format(OMX_COLOR_FORMATTYPE color_format) { venc_ioctl_msg ioctl_msg = {NULL, NULL}; DEBUG_PRINT_LOW("\n venc_set_color_format: color_format = %u ", color_format); if(color_format == OMX_COLOR_FormatYUV420SemiPlanar) { #ifdef MAX_RES_1080P m_sVenc_cfg.inputformat= VEN_INPUTFMT_NV12_16M2KA; #else m_sVenc_cfg.inputformat = VEN_INPUTFMT_NV12; #endif } else { DEBUG_PRINT_ERROR("\nWARNING: Unsupported Color format [%d]", color_format); #ifdef MAX_RES_1080P m_sVenc_cfg.inputformat= VEN_INPUTFMT_NV12_16M2KA; #else m_sVenc_cfg.inputformat = VEN_INPUTFMT_NV12; #endif DEBUG_PRINT_HIGH("\n Default color format YUV420SemiPlanar is set"); } ioctl_msg.in = (void*)&m_sVenc_cfg; ioctl_msg.out = NULL; if (ioctl(m_nDriver_fd, VEN_IOCTL_SET_BASE_CFG, (void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting color format failed"); return false; } return true; } bool venc_dev::venc_set_intra_vop_refresh(OMX_BOOL intra_vop_refresh) { DEBUG_PRINT_LOW("\n venc_set_intra_vop_refresh: intra_vop = %uc", intra_vop_refresh); if(intra_vop_refresh == OMX_TRUE) { if(ioctl(m_nDriver_fd, VEN_IOCTL_CMD_REQUEST_IFRAME, NULL) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting Intra VOP Refresh failed"); return false; } } else { DEBUG_PRINT_ERROR("\nERROR: VOP Refresh is False, no effect"); } return true; } bool venc_dev::venc_set_ratectrl_cfg(OMX_VIDEO_CONTROLRATETYPE eControlRate) { venc_ioctl_msg ioctl_msg = {NULL,NULL}; bool status = true; struct venc_ratectrlcfg ratectrl_cfg; //rate control switch(eControlRate) { case OMX_Video_ControlRateDisable: ratectrl_cfg.rcmode = VEN_RC_OFF; break; case OMX_Video_ControlRateVariableSkipFrames: ratectrl_cfg.rcmode = VEN_RC_VBR_VFR; break; case OMX_Video_ControlRateVariable: ratectrl_cfg.rcmode = VEN_RC_VBR_CFR; break; case OMX_Video_ControlRateConstantSkipFrames: ratectrl_cfg.rcmode = VEN_RC_CBR_VFR; break; case OMX_Video_ControlRateConstant: ratectrl_cfg.rcmode = VEN_RC_CBR_CFR; break; default: status = false; break; } if(status) { ioctl_msg.in = (void*)&ratectrl_cfg; ioctl_msg.out = NULL; if(ioctl (m_nDriver_fd,VEN_IOCTL_SET_RATE_CTRL_CFG,(void*)&ioctl_msg) < 0) { DEBUG_PRINT_ERROR("\nERROR: Request for setting rate control failed"); status = false; } else rate_ctrl.rcmode = ratectrl_cfg.rcmode; } return status; } bool venc_dev::venc_get_profile_level(OMX_U32 *eProfile,OMX_U32 *eLevel) { bool status = true; if(eProfile == NULL || eLevel == NULL) { return false; } if(m_sVenc_cfg.codectype == VEN_CODEC_MPEG4) { switch(codec_profile.profile) { case VEN_PROFILE_MPEG4_SP: *eProfile = OMX_VIDEO_MPEG4ProfileSimple; break; case VEN_PROFILE_MPEG4_ASP: *eProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple; break; default: *eProfile = OMX_VIDEO_MPEG4ProfileMax; status = false; break; } if(!status) { return status; } //profile level switch(profile_level.level) { case VEN_LEVEL_MPEG4_0: *eLevel = OMX_VIDEO_MPEG4Level0; break; case VEN_LEVEL_MPEG4_1: *eLevel = OMX_VIDEO_MPEG4Level1; break; case VEN_LEVEL_MPEG4_2: *eLevel = OMX_VIDEO_MPEG4Level2; break; case VEN_LEVEL_MPEG4_3: *eLevel = OMX_VIDEO_MPEG4Level3; break; case VEN_LEVEL_MPEG4_4: *eLevel = OMX_VIDEO_MPEG4Level4a; break; case VEN_LEVEL_MPEG4_5: case VEN_LEVEL_MPEG4_6: *eLevel = OMX_VIDEO_MPEG4Level5; break; default: *eLevel = OMX_VIDEO_MPEG4LevelMax; status = false; break; } } else if(m_sVenc_cfg.codectype == VEN_CODEC_H263) { if(codec_profile.profile == VEN_PROFILE_H263_BASELINE) { *eProfile = OMX_VIDEO_H263ProfileBaseline; } else { *eProfile = OMX_VIDEO_H263ProfileMax; return false; } switch(profile_level.level) { case VEN_LEVEL_H263_10: *eLevel = OMX_VIDEO_H263Level10; break; case VEN_LEVEL_H263_20: *eLevel = OMX_VIDEO_H263Level20; break; case VEN_LEVEL_H263_30: *eLevel = OMX_VIDEO_H263Level30; break; case VEN_LEVEL_H263_40: *eLevel = OMX_VIDEO_H263Level40; break; case VEN_LEVEL_H263_45: *eLevel = OMX_VIDEO_H263Level45; break; case VEN_LEVEL_H263_50: *eLevel = OMX_VIDEO_H263Level50; break; case VEN_LEVEL_H263_60: *eLevel = OMX_VIDEO_H263Level60; break; case VEN_LEVEL_H263_70: *eLevel = OMX_VIDEO_H263Level70; break; default: *eLevel = OMX_VIDEO_H263LevelMax; status = false; break; } } else if(m_sVenc_cfg.codectype == VEN_CODEC_H264) { switch(codec_profile.profile) { case VEN_PROFILE_H264_BASELINE: *eProfile = OMX_VIDEO_AVCProfileBaseline; break; case VEN_PROFILE_H264_MAIN: *eProfile = OMX_VIDEO_AVCProfileMain; break; case VEN_PROFILE_H264_HIGH: *eProfile = OMX_VIDEO_AVCProfileHigh; break; default: *eProfile = OMX_VIDEO_AVCProfileMax; status = false; break; } if(!status) { return status; } switch(profile_level.level) { case VEN_LEVEL_H264_1: *eLevel = OMX_VIDEO_AVCLevel1; break; case VEN_LEVEL_H264_1b: *eLevel = OMX_VIDEO_AVCLevel1b; break; case VEN_LEVEL_H264_1p1: *eLevel = OMX_VIDEO_AVCLevel11; break; case VEN_LEVEL_H264_1p2: *eLevel = OMX_VIDEO_AVCLevel12; break; case VEN_LEVEL_H264_1p3: *eLevel = OMX_VIDEO_AVCLevel13; break; case VEN_LEVEL_H264_2: *eLevel = OMX_VIDEO_AVCLevel2; break; case VEN_LEVEL_H264_2p1: *eLevel = OMX_VIDEO_AVCLevel21; break; case VEN_LEVEL_H264_2p2: *eLevel = OMX_VIDEO_AVCLevel22; break; case VEN_LEVEL_H264_3: *eLevel = OMX_VIDEO_AVCLevel3; break; case VEN_LEVEL_H264_3p1: *eLevel = OMX_VIDEO_AVCLevel31; break; case VEN_LEVEL_H264_3p2: *eLevel = OMX_VIDEO_AVCLevel32; break; case VEN_LEVEL_H264_4: *eLevel = OMX_VIDEO_AVCLevel4; break; default : *eLevel = OMX_VIDEO_AVCLevelMax; status = false; break; } } return status; } bool venc_dev::venc_validate_profile_level(OMX_U32 *eProfile, OMX_U32 *eLevel) { OMX_U32 new_profile = 0, new_level = 0; unsigned const int *profile_tbl = NULL; OMX_U32 mb_per_frame, mb_per_sec; bool profile_level_found = false; DEBUG_PRINT_LOW("\n Init profile table for respective codec"); //validate the ht,width,fps,bitrate and set the appropriate profile and level if(m_sVenc_cfg.codectype == VEN_CODEC_MPEG4) { if(*eProfile == 0) { if(!m_profile_set) { *eProfile = OMX_VIDEO_MPEG4ProfileSimple; } else { switch(codec_profile.profile) { case VEN_PROFILE_MPEG4_ASP: *eProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple; break; case VEN_PROFILE_MPEG4_SP: *eProfile = OMX_VIDEO_MPEG4ProfileSimple; break; default: DEBUG_PRINT_LOW("\n %s(): Unknown Error", __func__); return false; } } } if(*eLevel == 0 && !m_level_set) { *eLevel = OMX_VIDEO_MPEG4LevelMax; } if(*eProfile == OMX_VIDEO_MPEG4ProfileSimple) { profile_tbl = (unsigned int const *)mpeg4_profile_level_table; } else if(*eProfile == OMX_VIDEO_MPEG4ProfileAdvancedSimple) { profile_tbl = (unsigned int const *) (&mpeg4_profile_level_table[MPEG4_ASP_START]); } else { DEBUG_PRINT_LOW("\n Unsupported MPEG4 profile type %lu", *eProfile); return false; } } else if(m_sVenc_cfg.codectype == VEN_CODEC_H264) { if(*eProfile == 0) { if(!m_profile_set) { *eProfile = OMX_VIDEO_AVCProfileBaseline; } else { switch(codec_profile.profile) { case VEN_PROFILE_H264_BASELINE: *eProfile = OMX_VIDEO_AVCProfileBaseline; break; case VEN_PROFILE_H264_MAIN: *eProfile = OMX_VIDEO_AVCProfileMain; break; case VEN_PROFILE_H264_HIGH: *eProfile = OMX_VIDEO_AVCProfileHigh; break; default: DEBUG_PRINT_LOW("\n %s(): Unknown Error", __func__); return false; } } } if(*eLevel == 0 && !m_level_set) { *eLevel = OMX_VIDEO_AVCLevelMax; } if(*eProfile == OMX_VIDEO_AVCProfileBaseline) { profile_tbl = (unsigned int const *)h264_profile_level_table; } else if(*eProfile == OMX_VIDEO_AVCProfileHigh) { profile_tbl = (unsigned int const *) (&h264_profile_level_table[H264_HP_START]); } else if(*eProfile == OMX_VIDEO_AVCProfileMain) { profile_tbl = (unsigned int const *) (&h264_profile_level_table[H264_MP_START]); } else { DEBUG_PRINT_LOW("\n Unsupported AVC profile type %lu", *eProfile); return false; } } else if(m_sVenc_cfg.codectype == VEN_CODEC_H263) { if(*eProfile == 0) { if(!m_profile_set) { *eProfile = OMX_VIDEO_H263ProfileBaseline; } else { switch(codec_profile.profile) { case VEN_PROFILE_H263_BASELINE: *eProfile = OMX_VIDEO_H263ProfileBaseline; break; default: DEBUG_PRINT_LOW("\n %s(): Unknown Error", __func__); return false; } } } if(*eLevel == 0 && !m_level_set) { *eLevel = OMX_VIDEO_H263LevelMax; } if(*eProfile == OMX_VIDEO_H263ProfileBaseline) { profile_tbl = (unsigned int const *)h263_profile_level_table; } else { DEBUG_PRINT_LOW("\n Unsupported H.263 profile type %lu", *eProfile); return false; } } else { DEBUG_PRINT_LOW("\n Invalid codec type"); return false; } mb_per_frame = ((m_sVenc_cfg.input_height + 15) >> 4)* ((m_sVenc_cfg.input_width + 15)>> 4); if((mb_per_frame >= 3600) && (m_sVenc_cfg.codectype == VEN_CODEC_MPEG4)) { if(codec_profile.profile == VEN_PROFILE_MPEG4_ASP) profile_level.level = VEN_LEVEL_MPEG4_5; if(codec_profile.profile == VEN_PROFILE_MPEG4_SP) profile_level.level = VEN_LEVEL_MPEG4_6; { new_level = profile_level.level; new_profile = codec_profile.profile; return true; } } mb_per_sec = mb_per_frame * m_sVenc_cfg.fps_num / m_sVenc_cfg.fps_den; do{ if(mb_per_frame <= (int)profile_tbl[0]) { if(mb_per_sec <= (int)profile_tbl[1]) { if(m_sVenc_cfg.targetbitrate <= (int)profile_tbl[2]) { new_level = (int)profile_tbl[3]; new_profile = (int)profile_tbl[4]; profile_level_found = true; DEBUG_PRINT_LOW("\n Appropriate profile/level found %d/%d\n", new_profile, new_level); break; } } } profile_tbl = profile_tbl + 5; }while(profile_tbl[0] != 0); if (profile_level_found != true) { DEBUG_PRINT_LOW("\n ERROR: Unsupported profile/level\n"); return false; } if((*eLevel == OMX_VIDEO_MPEG4LevelMax) || (*eLevel == OMX_VIDEO_AVCLevelMax) || (*eLevel == OMX_VIDEO_H263LevelMax)) { *eLevel = new_level; } DEBUG_PRINT_LOW("%s: Returning with eProfile = %lu" "Level = %lu", __func__, *eProfile, *eLevel); return true; } bool venc_dev::venc_max_allowed_bitrate_check(OMX_U32 nTargetBitrate) { unsigned const int *profile_tbl = NULL; switch(m_sVenc_cfg.codectype) { case VEN_CODEC_MPEG4: if(m_eProfile == OMX_VIDEO_MPEG4ProfileSimple) { profile_tbl = (unsigned int const *)mpeg4_profile_level_table; } else if(m_eProfile == OMX_VIDEO_MPEG4ProfileAdvancedSimple) { profile_tbl = (unsigned int const *) (&mpeg4_profile_level_table[MPEG4_ASP_START]); } else { DEBUG_PRINT_ERROR("Unsupported MPEG4 profile type %lu", m_eProfile); return false; } break; case VEN_CODEC_H264: if(m_eProfile == OMX_VIDEO_AVCProfileBaseline) { profile_tbl = (unsigned int const *)h264_profile_level_table; } else if(m_eProfile == OMX_VIDEO_AVCProfileHigh) { profile_tbl = (unsigned int const *) (&h264_profile_level_table[H264_HP_START]); } else if(m_eProfile == OMX_VIDEO_AVCProfileMain) { profile_tbl = (unsigned int const *) (&h264_profile_level_table[H264_MP_START]); } else { DEBUG_PRINT_ERROR("Unsupported AVC profile type %lu", m_eProfile); return false; } break; case VEN_CODEC_H263: if(m_eProfile == OMX_VIDEO_H263ProfileBaseline) { profile_tbl = (unsigned int const *)h263_profile_level_table; } else { DEBUG_PRINT_ERROR("Unsupported H.263 profile type %lu", m_eProfile); return false; } break; default: DEBUG_PRINT_ERROR("%s: unknown codec type", __func__); return false; } while(profile_tbl[0] != 0) { if(profile_tbl[3] == m_eLevel) { if(nTargetBitrate > profile_tbl[2]) { DEBUG_PRINT_ERROR("Max. supported bitrate for Profile[%d] & Level[%d]" " is %u", m_eProfile, m_eLevel, profile_tbl[2]); return false; } } profile_tbl += 5; } return true; } #ifdef _ANDROID_ICS_ bool venc_dev::venc_set_meta_mode(bool mode) { venc_ioctl_msg ioctl_msg = {NULL,NULL}; ioctl_msg.in = &mode; DEBUG_PRINT_HIGH("Set meta buffer mode: %d", mode); if(ioctl(m_nDriver_fd,VEN_IOCTL_SET_METABUFFER_MODE,&ioctl_msg) < 0) { DEBUG_PRINT_ERROR(" Set meta buffer mode failed"); return false; } return true; } #endif