blob: e702c627b564490ed5460217058a2d1f600ec334 [file] [log] [blame]
/*--------------------------------------------------------------------------
Copyright (c) 2010 - 2013, The Linux Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of The Linux Foundation nor
the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------*/
/*============================================================================
O p e n M A X w r a p p e r s
O p e n M A X C o r e
*//** @file omx_vdec.cpp
This module contains the implementation of the OpenMAX core & component.
*//*========================================================================*/
//////////////////////////////////////////////////////////////////////////////
// Include Files
//////////////////////////////////////////////////////////////////////////////
#include <string.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <errno.h>
#include "omx_vdec.h"
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <media/hardware/HardwareAPI.h>
#include <media/msm_media_info.h>
#ifndef _ANDROID_
#include <sys/ioctl.h>
#include <sys/mman.h>
#endif //_ANDROID_
#ifdef _ANDROID_
#include <cutils/properties.h>
#include <gralloc_priv.h>
#undef USE_EGL_IMAGE_GPU
#endif
#include <qdMetaData.h>
#ifdef _ANDROID_
#include "DivXDrmDecrypt.h"
#endif //_ANDROID_
#ifdef USE_EGL_IMAGE_GPU
#include <EGL/egl.h>
#include <EGL/eglQCOM.h>
#define EGL_BUFFER_HANDLE_QCOM 0x4F00
#define EGL_BUFFER_OFFSET_QCOM 0x4F01
#endif
#ifdef INPUT_BUFFER_LOG
#define INPUT_BUFFER_FILE_NAME "/data/input-bitstream.\0\0\0\0"
#define INPUT_BUFFER_FILE_NAME_LEN 30
FILE *inputBufferFile1;
char inputfilename [INPUT_BUFFER_FILE_NAME_LEN] = "\0";
#endif
#ifdef OUTPUT_BUFFER_LOG
FILE *outputBufferFile1;
char outputfilename [] = "/data/output.yuv";
#endif
#ifdef OUTPUT_EXTRADATA_LOG
FILE *outputExtradataFile;
char ouputextradatafilename [] = "/data/extradata";
#endif
#define DEFAULT_FPS 30
#define MAX_INPUT_ERROR DEFAULT_FPS
#define MAX_SUPPORTED_FPS 120
#define VC1_SP_MP_START_CODE 0xC5000000
#define VC1_SP_MP_START_CODE_MASK 0xFF000000
#define VC1_AP_SEQ_START_CODE 0x0F010000
#define VC1_STRUCT_C_PROFILE_MASK 0xF0
#define VC1_STRUCT_B_LEVEL_MASK 0xE0000000
#define VC1_SIMPLE_PROFILE 0
#define VC1_MAIN_PROFILE 1
#define VC1_ADVANCE_PROFILE 3
#define VC1_SIMPLE_PROFILE_LOW_LEVEL 0
#define VC1_SIMPLE_PROFILE_MED_LEVEL 2
#define VC1_STRUCT_C_LEN 4
#define VC1_STRUCT_C_POS 8
#define VC1_STRUCT_A_POS 12
#define VC1_STRUCT_B_POS 24
#define VC1_SEQ_LAYER_SIZE 36
#define POLL_TIMEOUT 0x7fffffff
#define MEM_DEVICE "/dev/ion"
#define MEM_HEAP_ID ION_CP_MM_HEAP_ID
#ifdef _ANDROID_
extern "C" {
#include<utils/Log.h>
}
#endif//_ANDROID_
#define SZ_4K 0x1000
#define SZ_1M 0x100000
#define Log2(number, power) { OMX_U32 temp = number; power = 0; while( (0 == (temp & 0x1)) && power < 16) { temp >>=0x1; power++; } }
#define Q16ToFraction(q,num,den) { OMX_U32 power; Log2(q,power); num = q >> power; den = 0x1 << (16 - power); }
#define EXTRADATA_IDX(__num_planes) (__num_planes - 1)
#define DEFAULT_EXTRADATA (OMX_INTERLACE_EXTRADATA)
void* async_message_thread (void *input)
{
OMX_BUFFERHEADERTYPE *buffer;
struct v4l2_plane plane[VIDEO_MAX_PLANES];
struct pollfd pfd;
struct v4l2_buffer v4l2_buf;
memset((void *)&v4l2_buf,0,sizeof(v4l2_buf));
struct v4l2_event dqevent;
omx_vdec *omx = reinterpret_cast<omx_vdec*>(input);
pfd.events = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLRDBAND | POLLPRI;
pfd.fd = omx->drv_ctx.video_driver_fd;
int error_code = 0,rc=0,bytes_read = 0,bytes_written = 0;
DEBUG_PRINT_HIGH("omx_vdec: Async thread start\n");
prctl(PR_SET_NAME, (unsigned long)"VideoDecCallBackThread", 0, 0, 0);
while (1) {
rc = poll(&pfd, 1, POLL_TIMEOUT);
if (!rc) {
DEBUG_PRINT_ERROR("Poll timedout\n");
break;
} else if (rc < 0) {
DEBUG_PRINT_ERROR("Error while polling: %d\n", rc);
break;
}
if ((pfd.revents & POLLIN) || (pfd.revents & POLLRDNORM)) {
struct vdec_msginfo vdec_msg;
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
v4l2_buf.memory = V4L2_MEMORY_USERPTR;
v4l2_buf.length = omx->drv_ctx.num_planes;
v4l2_buf.m.planes = plane;
while (!ioctl(pfd.fd, VIDIOC_DQBUF, &v4l2_buf)) {
vdec_msg.msgcode=VDEC_MSG_RESP_OUTPUT_BUFFER_DONE;
vdec_msg.status_code=VDEC_S_SUCCESS;
vdec_msg.msgdata.output_frame.client_data=(void*)&v4l2_buf;
vdec_msg.msgdata.output_frame.len=plane[0].bytesused;
vdec_msg.msgdata.output_frame.bufferaddr=(void*)plane[0].m.userptr;
vdec_msg.msgdata.output_frame.time_stamp= ((uint64_t)v4l2_buf.timestamp.tv_sec * (uint64_t)1000000) +
(uint64_t)v4l2_buf.timestamp.tv_usec;
if (vdec_msg.msgdata.output_frame.len) {
vdec_msg.msgdata.output_frame.framesize.left = plane[0].reserved[2];
vdec_msg.msgdata.output_frame.framesize.top = plane[0].reserved[3];
vdec_msg.msgdata.output_frame.framesize.right = plane[0].reserved[4];
vdec_msg.msgdata.output_frame.framesize.bottom = plane[0].reserved[5];
}
if (omx->async_message_process(input,&vdec_msg) < 0) {
DEBUG_PRINT_HIGH("\n async_message_thread Exited \n");
break;
}
}
}
if ((pfd.revents & POLLOUT) || (pfd.revents & POLLWRNORM)) {
struct vdec_msginfo vdec_msg;
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
v4l2_buf.memory = V4L2_MEMORY_USERPTR;
v4l2_buf.length = 1;
v4l2_buf.m.planes = plane;
while (!ioctl(pfd.fd, VIDIOC_DQBUF, &v4l2_buf)) {
vdec_msg.msgcode=VDEC_MSG_RESP_INPUT_BUFFER_DONE;
vdec_msg.status_code=VDEC_S_SUCCESS;
vdec_msg.msgdata.input_frame_clientdata=(void*)&v4l2_buf;
if (omx->async_message_process(input,&vdec_msg) < 0) {
DEBUG_PRINT_HIGH("\n async_message_thread Exited \n");
break;
}
}
}
if (pfd.revents & POLLPRI) {
rc = ioctl(pfd.fd, VIDIOC_DQEVENT, &dqevent);
if (dqevent.type == V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT ) {
struct vdec_msginfo vdec_msg;
vdec_msg.msgcode=VDEC_MSG_EVT_CONFIG_CHANGED;
vdec_msg.status_code=VDEC_S_SUCCESS;
DEBUG_PRINT_HIGH("\n VIDC Port Reconfig recieved insufficient\n");
if (omx->async_message_process(input,&vdec_msg) < 0) {
DEBUG_PRINT_HIGH("\n async_message_thread Exited \n");
break;
}
} else if (dqevent.type == V4L2_EVENT_MSM_VIDC_FLUSH_DONE) {
struct vdec_msginfo vdec_msg;
vdec_msg.msgcode=VDEC_MSG_RESP_FLUSH_INPUT_DONE;
vdec_msg.status_code=VDEC_S_SUCCESS;
DEBUG_PRINT_HIGH("VIDC Input Flush Done Recieved \n");
if (omx->async_message_process(input,&vdec_msg) < 0) {
DEBUG_PRINT_HIGH("\n async_message_thread Exited \n");
break;
}
vdec_msg.msgcode=VDEC_MSG_RESP_FLUSH_OUTPUT_DONE;
vdec_msg.status_code=VDEC_S_SUCCESS;
DEBUG_PRINT_HIGH("VIDC Output Flush Done Recieved \n");
if (omx->async_message_process(input,&vdec_msg) < 0) {
DEBUG_PRINT_HIGH("\n async_message_thread Exited \n");
break;
}
} else if (dqevent.type == V4L2_EVENT_MSM_VIDC_CLOSE_DONE) {
DEBUG_PRINT_HIGH("\n VIDC Close Done Recieved and async_message_thread Exited \n");
break;
} else if (dqevent.type == V4L2_EVENT_MSM_VIDC_SYS_ERROR) {
struct vdec_msginfo vdec_msg;
vdec_msg.msgcode=VDEC_MSG_EVT_HW_ERROR;
vdec_msg.status_code=VDEC_S_SUCCESS;
DEBUG_PRINT_HIGH("\n SYS Error Recieved \n");
if (omx->async_message_process(input,&vdec_msg) < 0) {
DEBUG_PRINT_HIGH("\n async_message_thread Exited \n");
break;
}
} else if (dqevent.type == V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE) {
unsigned int *ptr = (unsigned int *)dqevent.u.data;
DEBUG_PRINT_LOW("REFERENCE RELEASE EVENT RECVD fd = %d offset = %d\n", ptr[0], ptr[1]);
omx->buf_ref_remove(ptr[0], ptr[1]);
} else if (dqevent.type == V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER) {
unsigned int *ptr = (unsigned int *)dqevent.u.data;
struct vdec_msginfo vdec_msg;
DEBUG_PRINT_HIGH("Release unqueued buffer event recvd fd = %d offset = %d\n", ptr[0], ptr[1]);
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
v4l2_buf.memory = V4L2_MEMORY_USERPTR;
v4l2_buf.length = omx->drv_ctx.num_planes;
v4l2_buf.m.planes = plane;
v4l2_buf.index = ptr[5];
v4l2_buf.flags = 0;
vdec_msg.msgcode=VDEC_MSG_RESP_OUTPUT_BUFFER_DONE;
vdec_msg.status_code=VDEC_S_SUCCESS;
vdec_msg.msgdata.output_frame.client_data = (void*)&v4l2_buf;
vdec_msg.msgdata.output_frame.len = 0;
vdec_msg.msgdata.output_frame.bufferaddr = (void*)ptr[2];
vdec_msg.msgdata.output_frame.time_stamp= ((uint64_t)ptr[3] * (uint64_t)1000000) +
(uint64_t)ptr[4];
if (omx->async_message_process(input,&vdec_msg) < 0) {
DEBUG_PRINT_HIGH("\n async_message_thread Exited \n");
break;
}
}
else {
DEBUG_PRINT_HIGH("\n VIDC Some Event recieved \n");
continue;
}
}
}
DEBUG_PRINT_HIGH("omx_vdec: Async thread stop\n");
return NULL;
}
void* message_thread(void *input)
{
omx_vdec* omx = reinterpret_cast<omx_vdec*>(input);
unsigned char id;
int n;
DEBUG_PRINT_HIGH("omx_vdec: message thread start\n");
prctl(PR_SET_NAME, (unsigned long)"VideoDecMsgThread", 0, 0, 0);
while (1) {
n = read(omx->m_pipe_in, &id, 1);
if (0 == n) {
break;
}
if (1 == n) {
omx->process_event_cb(omx, id);
}
if ((n < 0) && (errno != EINTR)) {
DEBUG_PRINT_LOW("\nERROR: read from pipe failed, ret %d errno %d", n, errno);
break;
}
}
DEBUG_PRINT_HIGH("omx_vdec: message thread stop\n");
return 0;
}
void post_message(omx_vdec *omx, unsigned char id)
{
int ret_value;
DEBUG_PRINT_LOW("omx_vdec: post_message %d pipe out%d\n", id,omx->m_pipe_out);
ret_value = write(omx->m_pipe_out, &id, 1);
DEBUG_PRINT_LOW("post_message to pipe done %d\n",ret_value);
}
// omx_cmd_queue destructor
omx_vdec::omx_cmd_queue::~omx_cmd_queue()
{
// Nothing to do
}
// omx cmd queue constructor
omx_vdec::omx_cmd_queue::omx_cmd_queue(): m_read(0),m_write(0),m_size(0)
{
memset(m_q,0,sizeof(omx_event)*OMX_CORE_CONTROL_CMDQ_SIZE);
}
// omx cmd queue insert
bool omx_vdec::omx_cmd_queue::insert_entry(unsigned p1, unsigned p2, unsigned id)
{
bool ret = true;
if (m_size < OMX_CORE_CONTROL_CMDQ_SIZE) {
m_q[m_write].id = id;
m_q[m_write].param1 = p1;
m_q[m_write].param2 = p2;
m_write++;
m_size ++;
if (m_write >= OMX_CORE_CONTROL_CMDQ_SIZE) {
m_write = 0;
}
} else {
ret = false;
DEBUG_PRINT_ERROR("ERROR: %s()::Command Queue Full\n", __func__);
}
return ret;
}
// omx cmd queue pop
bool omx_vdec::omx_cmd_queue::pop_entry(unsigned *p1, unsigned *p2, unsigned *id)
{
bool ret = true;
if (m_size > 0) {
*id = m_q[m_read].id;
*p1 = m_q[m_read].param1;
*p2 = m_q[m_read].param2;
// Move the read pointer ahead
++m_read;
--m_size;
if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE) {
m_read = 0;
}
} else {
ret = false;
}
return ret;
}
// Retrieve the first mesg type in the queue
unsigned omx_vdec::omx_cmd_queue::get_q_msg_type()
{
return m_q[m_read].id;
}
#ifdef _ANDROID_
omx_vdec::ts_arr_list::ts_arr_list()
{
//initialize timestamps array
memset(m_ts_arr_list, 0, ( sizeof(ts_entry) * MAX_NUM_INPUT_OUTPUT_BUFFERS) );
}
omx_vdec::ts_arr_list::~ts_arr_list()
{
//free m_ts_arr_list?
}
bool omx_vdec::ts_arr_list::insert_ts(OMX_TICKS ts)
{
bool ret = true;
bool duplicate_ts = false;
int idx = 0;
//insert at the first available empty location
for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) {
if (!m_ts_arr_list[idx].valid) {
//found invalid or empty entry, save timestamp
m_ts_arr_list[idx].valid = true;
m_ts_arr_list[idx].timestamp = ts;
DEBUG_PRINT_LOW("Insert_ts(): Inserting TIMESTAMP (%lld) at idx (%d)",
ts, idx);
break;
}
}
if (idx == MAX_NUM_INPUT_OUTPUT_BUFFERS) {
DEBUG_PRINT_LOW("Timestamp array list is FULL. Unsuccessful insert");
ret = false;
}
return ret;
}
bool omx_vdec::ts_arr_list::pop_min_ts(OMX_TICKS &ts)
{
bool ret = true;
int min_idx = -1;
OMX_TICKS min_ts = 0;
int idx = 0;
for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) {
if (m_ts_arr_list[idx].valid) {
//found valid entry, save index
if (min_idx < 0) {
//first valid entry
min_ts = m_ts_arr_list[idx].timestamp;
min_idx = idx;
} else if (m_ts_arr_list[idx].timestamp < min_ts) {
min_ts = m_ts_arr_list[idx].timestamp;
min_idx = idx;
}
}
}
if (min_idx < 0) {
//no valid entries found
DEBUG_PRINT_LOW("Timestamp array list is empty. Unsuccessful pop");
ts = 0;
ret = false;
} else {
ts = m_ts_arr_list[min_idx].timestamp;
m_ts_arr_list[min_idx].valid = false;
DEBUG_PRINT_LOW("Pop_min_ts:Timestamp (%lld), index(%d)",
ts, min_idx);
}
return ret;
}
bool omx_vdec::ts_arr_list::reset_ts_list()
{
bool ret = true;
int idx = 0;
DEBUG_PRINT_LOW("reset_ts_list(): Resetting timestamp array list");
for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) {
m_ts_arr_list[idx].valid = false;
}
return ret;
}
#endif
// factory function executed by the core to create instances
void *get_omx_component_factory_fn(void)
{
return (new omx_vdec);
}
#ifdef _ANDROID_
#ifdef USE_ION
VideoHeap::VideoHeap(int devicefd, size_t size, void* base,
struct ion_handle *handle, int ionMapfd)
{
// ionInit(devicefd, base, size, 0 , MEM_DEVICE,handle,ionMapfd);
}
#else
VideoHeap::VideoHeap(int fd, size_t size, void* base)
{
// dup file descriptor, map once, use pmem
init(dup(fd), base, size, 0 , MEM_DEVICE);
}
#endif
#endif // _ANDROID_
/* ======================================================================
FUNCTION
omx_vdec::omx_vdec
DESCRIPTION
Constructor
PARAMETERS
None
RETURN VALUE
None.
========================================================================== */
omx_vdec::omx_vdec(): m_error_propogated(false),
m_state(OMX_StateInvalid),
m_app_data(NULL),
m_inp_mem_ptr(NULL),
m_out_mem_ptr(NULL),
m_inp_err_count(0),
input_flush_progress (false),
output_flush_progress (false),
input_use_buffer (false),
output_use_buffer (false),
ouput_egl_buffers(false),
m_use_output_pmem(OMX_FALSE),
m_out_mem_region_smi(OMX_FALSE),
m_out_pvt_entry_pmem(OMX_FALSE),
pending_input_buffers(0),
pending_output_buffers(0),
m_out_bm_count(0),
m_inp_bm_count(0),
m_inp_bPopulated(OMX_FALSE),
m_out_bPopulated(OMX_FALSE),
m_flags(0),
#ifdef _ANDROID_
m_heap_ptr(NULL),
#endif
m_inp_bEnabled(OMX_TRUE),
m_out_bEnabled(OMX_TRUE),
m_in_alloc_cnt(0),
m_platform_list(NULL),
m_platform_entry(NULL),
m_pmem_info(NULL),
arbitrary_bytes (true),
psource_frame (NULL),
pdest_frame (NULL),
m_inp_heap_ptr (NULL),
m_phdr_pmem_ptr(NULL),
m_heap_inp_bm_count (0),
codec_type_parse ((codec_type)0),
first_frame_meta (true),
frame_count (0),
nal_count (0),
nal_length(0),
look_ahead_nal (false),
first_frame(0),
first_buffer(NULL),
first_frame_size (0),
m_device_file_ptr(NULL),
m_vc1_profile((vc1_profile_type)0),
m_profile(0),
mInSmoothstreamingMode(false),
h264_last_au_ts(LLONG_MAX),
h264_last_au_flags(0),
prev_ts(LLONG_MAX),
rst_prev_ts(true),
frm_int(0),
m_disp_hor_size(0),
m_disp_vert_size(0),
in_reconfig(false),
m_display_id(NULL),
h264_parser(NULL),
client_extradata(0),
m_reject_avc_1080p_mp (0),
#ifdef _ANDROID_
m_enable_android_native_buffers(OMX_FALSE),
m_use_android_native_buffers(OMX_FALSE),
iDivXDrmDecrypt(NULL),
#endif
m_desc_buffer_ptr(NULL),
secure_mode(false),
client_set_fps(false),
out_dynamic_list(NULL)
{
/* Assumption is that , to begin with , we have all the frames with decoder */
DEBUG_PRINT_HIGH("In OMX vdec Constructor");
#ifdef _ANDROID_
char property_value[PROPERTY_VALUE_MAX] = {0};
property_get("vidc.dec.debug.perf", property_value, "0");
perf_flag = atoi(property_value);
if (perf_flag) {
DEBUG_PRINT_HIGH("vidc.dec.debug.perf is %d", perf_flag);
dec_time.start();
proc_frms = latency = 0;
}
prev_n_filled_len = 0;
property_value[0] = '\0';
property_get("vidc.dec.debug.ts", property_value, "0");
m_debug_timestamp = atoi(property_value);
DEBUG_PRINT_HIGH("vidc.dec.debug.ts value is %d",m_debug_timestamp);
if (m_debug_timestamp) {
time_stamp_dts.set_timestamp_reorder_mode(true);
time_stamp_dts.enable_debug_print(true);
}
property_value[0] = '\0';
property_get("vidc.dec.debug.concealedmb", property_value, "0");
m_debug_concealedmb = atoi(property_value);
DEBUG_PRINT_HIGH("vidc.dec.debug.concealedmb value is %d",m_debug_concealedmb);
property_value[0] = '\0';
property_get("vidc.dec.profile.check", property_value, "0");
m_reject_avc_1080p_mp = atoi(property_value);
DEBUG_PRINT_HIGH("vidc.dec.profile.check value is %d",m_reject_avc_1080p_mp);
#endif
memset(&m_cmp,0,sizeof(m_cmp));
memset(&m_cb,0,sizeof(m_cb));
memset (&drv_ctx,0,sizeof(drv_ctx));
memset (&h264_scratch,0,sizeof (OMX_BUFFERHEADERTYPE));
memset (m_hwdevice_name,0,sizeof(m_hwdevice_name));
memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) );
m_demux_entries = 0;
msg_thread_id = 0;
async_thread_id = 0;
msg_thread_created = false;
async_thread_created = false;
#ifdef _ANDROID_ICS_
memset(&native_buffer, 0 ,(sizeof(struct nativebuffer) * MAX_NUM_INPUT_OUTPUT_BUFFERS));
#endif
memset(&drv_ctx.extradata_info, 0, sizeof(drv_ctx.extradata_info));
drv_ctx.timestamp_adjust = false;
drv_ctx.video_driver_fd = -1;
m_vendor_config.pData = NULL;
pthread_mutex_init(&m_lock, NULL);
pthread_mutex_init(&c_lock, NULL);
sem_init(&m_cmd_lock,0,0);
streaming[CAPTURE_PORT] =
streaming[OUTPUT_PORT] = false;
#ifdef _ANDROID_
char extradata_value[PROPERTY_VALUE_MAX] = {0};
property_get("vidc.dec.debug.extradata", extradata_value, "0");
m_debug_extradata = atoi(extradata_value);
DEBUG_PRINT_HIGH("vidc.dec.debug.extradata value is %d",m_debug_extradata);
#endif
m_fill_output_msg = OMX_COMPONENT_GENERATE_FTB;
client_buffers.set_vdec_client(this);
dynamic_buf_mode = false;
}
static const int event_type[] = {
V4L2_EVENT_MSM_VIDC_FLUSH_DONE,
V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT,
V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT,
V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE,
V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER,
V4L2_EVENT_MSM_VIDC_CLOSE_DONE,
V4L2_EVENT_MSM_VIDC_SYS_ERROR
};
static OMX_ERRORTYPE subscribe_to_events(int fd)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
struct v4l2_event_subscription sub;
int array_sz = sizeof(event_type)/sizeof(int);
int i,rc;
if (fd < 0) {
printf("Invalid input: %d\n", fd);
return OMX_ErrorBadParameter;
}
for (i = 0; i < array_sz; ++i) {
memset(&sub, 0, sizeof(sub));
sub.type = event_type[i];
rc = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
if (rc) {
printf("Failed to subscribe event: 0x%x\n", sub.type);
break;
}
}
if (i < array_sz) {
for (--i; i >=0 ; i--) {
memset(&sub, 0, sizeof(sub));
sub.type = event_type[i];
rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub);
if (rc)
printf("Failed to unsubscribe event: 0x%x\n", sub.type);
}
eRet = OMX_ErrorNotImplemented;
}
return eRet;
}
static OMX_ERRORTYPE unsubscribe_to_events(int fd)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
struct v4l2_event_subscription sub;
int array_sz = sizeof(event_type)/sizeof(int);
int i,rc;
if (fd < 0) {
printf("Invalid input: %d\n", fd);
return OMX_ErrorBadParameter;
}
for (i = 0; i < array_sz; ++i) {
memset(&sub, 0, sizeof(sub));
sub.type = event_type[i];
rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub);
if (rc) {
printf("Failed to unsubscribe event: 0x%x\n", sub.type);
break;
}
}
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::~omx_vdec
DESCRIPTION
Destructor
PARAMETERS
None
RETURN VALUE
None.
========================================================================== */
omx_vdec::~omx_vdec()
{
m_pmem_info = NULL;
struct v4l2_decoder_cmd dec;
DEBUG_PRINT_HIGH("In OMX vdec Destructor");
if (m_pipe_in) close(m_pipe_in);
if (m_pipe_out) close(m_pipe_out);
m_pipe_in = -1;
m_pipe_out = -1;
DEBUG_PRINT_HIGH("Waiting on OMX Msg Thread exit");
if (msg_thread_created)
pthread_join(msg_thread_id,NULL);
DEBUG_PRINT_HIGH("Waiting on OMX Async Thread exit");
dec.cmd = V4L2_DEC_CMD_STOP;
if (drv_ctx.video_driver_fd >=0 ) {
if (ioctl(drv_ctx.video_driver_fd, VIDIOC_DECODER_CMD, &dec))
DEBUG_PRINT_ERROR("\n STOP Command failed\n");
}
if (async_thread_created)
pthread_join(async_thread_id,NULL);
unsubscribe_to_events(drv_ctx.video_driver_fd);
close(drv_ctx.video_driver_fd);
pthread_mutex_destroy(&m_lock);
pthread_mutex_destroy(&c_lock);
sem_destroy(&m_cmd_lock);
if (perf_flag) {
DEBUG_PRINT_HIGH("--> TOTAL PROCESSING TIME");
dec_time.end();
}
DEBUG_PRINT_HIGH("Exit OMX vdec Destructor");
}
int release_buffers(omx_vdec* obj, enum vdec_buffer buffer_type)
{
struct v4l2_requestbuffers bufreq;
int rc = 0;
if (buffer_type == VDEC_BUFFER_TYPE_OUTPUT) {
bufreq.memory = V4L2_MEMORY_USERPTR;
bufreq.count = 0;
bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
rc = ioctl(obj->drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq);
} else if(buffer_type == VDEC_BUFFER_TYPE_INPUT) {
bufreq.memory = V4L2_MEMORY_USERPTR;
bufreq.count = 0;
bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
rc = ioctl(obj->drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq);
}
return rc;
}
/* ======================================================================
FUNCTION
omx_vdec::OMXCntrlProcessMsgCb
DESCRIPTION
IL Client callbacks are generated through this routine. The decoder
provides the thread context for this routine.
PARAMETERS
ctxt -- Context information related to the self.
id -- Event identifier. This could be any of the following:
1. Command completion event
2. Buffer done callback event
3. Frame done callback event
RETURN VALUE
None.
========================================================================== */
void omx_vdec::process_event_cb(void *ctxt, unsigned char id)
{
signed p1; // Parameter - 1
signed p2; // Parameter - 2
unsigned ident;
unsigned qsize=0; // qsize
omx_vdec *pThis = (omx_vdec *) ctxt;
if (!pThis) {
DEBUG_PRINT_ERROR("ERROR: %s()::Context is incorrect, bailing out\n",
__func__);
return;
}
// Protect the shared queue data structure
do {
/*Read the message id's from the queue*/
pthread_mutex_lock(&pThis->m_lock);
qsize = pThis->m_cmd_q.m_size;
if (qsize) {
pThis->m_cmd_q.pop_entry((unsigned *)&p1, (unsigned *)&p2, &ident);
}
if (qsize == 0 && pThis->m_state != OMX_StatePause) {
qsize = pThis->m_ftb_q.m_size;
if (qsize) {
pThis->m_ftb_q.pop_entry((unsigned *)&p1, (unsigned *)&p2, &ident);
}
}
if (qsize == 0 && pThis->m_state != OMX_StatePause) {
qsize = pThis->m_etb_q.m_size;
if (qsize) {
pThis->m_etb_q.pop_entry((unsigned *)&p1, (unsigned *)&p2, &ident);
}
}
pthread_mutex_unlock(&pThis->m_lock);
/*process message if we have one*/
if (qsize > 0) {
id = ident;
switch (id) {
case OMX_COMPONENT_GENERATE_EVENT:
if (pThis->m_cb.EventHandler) {
switch (p1) {
case OMX_CommandStateSet:
pThis->m_state = (OMX_STATETYPE) p2;
DEBUG_PRINT_HIGH("\n OMX_CommandStateSet complete, m_state = %d",
pThis->m_state);
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventCmdComplete, p1, p2, NULL);
break;
case OMX_EventError:
if (p2 == OMX_StateInvalid) {
DEBUG_PRINT_ERROR("\n OMX_EventError: p2 is OMX_StateInvalid");
pThis->m_state = (OMX_STATETYPE) p2;
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventError, OMX_ErrorInvalidState, p2, NULL);
} else if (p2 == OMX_ErrorHardware) {
pThis->omx_report_error();
} else {
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventError, p2, (OMX_U32)NULL, NULL );
}
break;
case OMX_CommandPortDisable:
DEBUG_PRINT_HIGH("\n OMX_CommandPortDisable complete for port [%d]", p2);
if (BITMASK_PRESENT(&pThis->m_flags,
OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING)) {
BITMASK_SET(&pThis->m_flags, OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED);
break;
}
if (p2 == OMX_CORE_OUTPUT_PORT_INDEX) {
OMX_ERRORTYPE eRet = OMX_ErrorNone;
pThis->stream_off(OMX_CORE_OUTPUT_PORT_INDEX);
if (release_buffers(pThis, VDEC_BUFFER_TYPE_OUTPUT))
DEBUG_PRINT_HIGH("Failed to release output buffers\n");
OMX_ERRORTYPE eRet1 = pThis->get_buffer_req(&pThis->drv_ctx.op_buf);
pThis->in_reconfig = false;
if (eRet != OMX_ErrorNone) {
DEBUG_PRINT_ERROR("set_buffer_req failed eRet = %d",eRet);
pThis->omx_report_error();
break;
}
}
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventCmdComplete, p1, p2, NULL );
break;
case OMX_CommandPortEnable:
DEBUG_PRINT_HIGH("\n OMX_CommandPortEnable complete for port [%d]", p2);
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,\
OMX_EventCmdComplete, p1, p2, NULL );
break;
default:
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventCmdComplete, p1, p2, NULL );
break;
}
} else {
DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL\n", __func__);
}
break;
case OMX_COMPONENT_GENERATE_ETB_ARBITRARY:
if (pThis->empty_this_buffer_proxy_arbitrary((OMX_HANDLETYPE)p1,\
(OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) {
DEBUG_PRINT_ERROR("\n empty_this_buffer_proxy_arbitrary failure");
pThis->omx_report_error ();
}
break;
case OMX_COMPONENT_GENERATE_ETB:
if (pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1,\
(OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) {
DEBUG_PRINT_ERROR("\n empty_this_buffer_proxy failure");
pThis->omx_report_error ();
}
break;
case OMX_COMPONENT_GENERATE_FTB:
if ( pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)p1,\
(OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone) {
DEBUG_PRINT_ERROR("\n fill_this_buffer_proxy failure");
pThis->omx_report_error ();
}
break;
case OMX_COMPONENT_GENERATE_COMMAND:
pThis->send_command_proxy(&pThis->m_cmp,(OMX_COMMANDTYPE)p1,\
(OMX_U32)p2,(OMX_PTR)NULL);
break;
case OMX_COMPONENT_GENERATE_EBD:
if (p2 != VDEC_S_SUCCESS && p2 != VDEC_S_INPUT_BITSTREAM_ERR) {
DEBUG_PRINT_ERROR("\n OMX_COMPONENT_GENERATE_EBD failure");
pThis->omx_report_error ();
} else {
if (p2 == VDEC_S_INPUT_BITSTREAM_ERR && p1) {
pThis->m_inp_err_count++;
pThis->time_stamp_dts.remove_time_stamp(
((OMX_BUFFERHEADERTYPE *)p1)->nTimeStamp,
(pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive)
?true:false);
} else {
pThis->m_inp_err_count = 0;
}
if ( pThis->empty_buffer_done(&pThis->m_cmp,
(OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone) {
DEBUG_PRINT_ERROR("\n empty_buffer_done failure");
pThis->omx_report_error ();
}
if (pThis->m_inp_err_count >= MAX_INPUT_ERROR) {
DEBUG_PRINT_ERROR("\n Input bitstream error for consecutive %d frames.", MAX_INPUT_ERROR);
pThis->omx_report_error ();
}
}
break;
case OMX_COMPONENT_GENERATE_INFO_FIELD_DROPPED: {
int64_t *timestamp = (int64_t *)p1;
if (p1) {
pThis->time_stamp_dts.remove_time_stamp(*timestamp,
(pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive)
?true:false);
free(timestamp);
}
}
break;
case OMX_COMPONENT_GENERATE_FBD:
if (p2 != VDEC_S_SUCCESS) {
DEBUG_PRINT_ERROR("\n OMX_COMPONENT_GENERATE_FBD failure");
pThis->omx_report_error ();
} else if ( pThis->fill_buffer_done(&pThis->m_cmp,
(OMX_BUFFERHEADERTYPE *)p1) != OMX_ErrorNone ) {
DEBUG_PRINT_ERROR("\n fill_buffer_done failure");
pThis->omx_report_error ();
}
break;
case OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH:
DEBUG_PRINT_HIGH("\n Driver flush i/p Port complete");
if (!pThis->input_flush_progress) {
DEBUG_PRINT_HIGH("\n WARNING: Unexpected flush from driver");
} else {
pThis->execute_input_flush();
if (pThis->m_cb.EventHandler) {
if (p2 != VDEC_S_SUCCESS) {
DEBUG_PRINT_ERROR("\nOMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH failure");
pThis->omx_report_error ();
} else {
/*Check if we need generate event for Flush done*/
if (BITMASK_PRESENT(&pThis->m_flags,
OMX_COMPONENT_INPUT_FLUSH_PENDING)) {
BITMASK_CLEAR (&pThis->m_flags,OMX_COMPONENT_INPUT_FLUSH_PENDING);
DEBUG_PRINT_LOW("\n Input Flush completed - Notify Client");
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventCmdComplete,OMX_CommandFlush,
OMX_CORE_INPUT_PORT_INDEX,NULL );
}
if (BITMASK_PRESENT(&pThis->m_flags,
OMX_COMPONENT_IDLE_PENDING)) {
if (pThis->stream_off(OMX_CORE_INPUT_PORT_INDEX)) {
DEBUG_PRINT_ERROR("\n Failed to call streamoff on OUTPUT Port \n");
pThis->omx_report_error ();
} else {
pThis->streaming[OUTPUT_PORT] = false;
}
if (!pThis->output_flush_progress) {
DEBUG_PRINT_LOW("\n Input flush done hence issue stop");
pThis->post_event ((unsigned int)NULL, VDEC_S_SUCCESS,\
OMX_COMPONENT_GENERATE_STOP_DONE);
}
}
}
} else {
DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__);
}
}
break;
case OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH:
DEBUG_PRINT_HIGH("\n Driver flush o/p Port complete");
if (!pThis->output_flush_progress) {
DEBUG_PRINT_HIGH("\n WARNING: Unexpected flush from driver");
} else {
pThis->execute_output_flush();
if (pThis->m_cb.EventHandler) {
if (p2 != VDEC_S_SUCCESS) {
DEBUG_PRINT_ERROR("\n OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH failed");
pThis->omx_report_error ();
} else {
/*Check if we need generate event for Flush done*/
if (BITMASK_PRESENT(&pThis->m_flags,
OMX_COMPONENT_OUTPUT_FLUSH_PENDING)) {
DEBUG_PRINT_LOW("\n Notify Output Flush done");
BITMASK_CLEAR (&pThis->m_flags,OMX_COMPONENT_OUTPUT_FLUSH_PENDING);
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventCmdComplete,OMX_CommandFlush,
OMX_CORE_OUTPUT_PORT_INDEX,NULL );
}
if (BITMASK_PRESENT(&pThis->m_flags,
OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING)) {
DEBUG_PRINT_LOW("\n Internal flush complete");
BITMASK_CLEAR (&pThis->m_flags,
OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING);
if (BITMASK_PRESENT(&pThis->m_flags,
OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED)) {
pThis->post_event(OMX_CommandPortDisable,
OMX_CORE_OUTPUT_PORT_INDEX,
OMX_COMPONENT_GENERATE_EVENT);
BITMASK_CLEAR (&pThis->m_flags,
OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED);
}
}
if (BITMASK_PRESENT(&pThis->m_flags ,OMX_COMPONENT_IDLE_PENDING)) {
if (pThis->stream_off(OMX_CORE_OUTPUT_PORT_INDEX)) {
DEBUG_PRINT_ERROR("\n Failed to call streamoff on CAPTURE Port \n");
pThis->omx_report_error ();
break;
}
pThis->streaming[CAPTURE_PORT] = false;
if (!pThis->input_flush_progress) {
DEBUG_PRINT_LOW("\n Output flush done hence issue stop");
pThis->post_event ((unsigned int)NULL, VDEC_S_SUCCESS,\
OMX_COMPONENT_GENERATE_STOP_DONE);
}
}
}
} else {
DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__);
}
}
break;
case OMX_COMPONENT_GENERATE_START_DONE:
DEBUG_PRINT_HIGH("\n Rxd OMX_COMPONENT_GENERATE_START_DONE");
if (pThis->m_cb.EventHandler) {
if (p2 != VDEC_S_SUCCESS) {
DEBUG_PRINT_ERROR("\n OMX_COMPONENT_GENERATE_START_DONE Failure");
pThis->omx_report_error ();
} else {
DEBUG_PRINT_LOW("\n OMX_COMPONENT_GENERATE_START_DONE Success");
if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_EXECUTE_PENDING)) {
DEBUG_PRINT_LOW("\n Move to executing");
// Send the callback now
BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_EXECUTE_PENDING);
pThis->m_state = OMX_StateExecuting;
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventCmdComplete,OMX_CommandStateSet,
OMX_StateExecuting, NULL);
} else if (BITMASK_PRESENT(&pThis->m_flags,
OMX_COMPONENT_PAUSE_PENDING)) {
if (/*ioctl (pThis->drv_ctx.video_driver_fd,
VDEC_IOCTL_CMD_PAUSE,NULL ) < */0) {
DEBUG_PRINT_ERROR("\n VDEC_IOCTL_CMD_PAUSE failed");
pThis->omx_report_error ();
}
}
}
} else {
DEBUG_PRINT_LOW("\n Event Handler callback is NULL");
}
break;
case OMX_COMPONENT_GENERATE_PAUSE_DONE:
DEBUG_PRINT_HIGH("\n Rxd OMX_COMPONENT_GENERATE_PAUSE_DONE");
if (pThis->m_cb.EventHandler) {
if (p2 != VDEC_S_SUCCESS) {
DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_PAUSE_DONE ret failed");
pThis->omx_report_error ();
} else {
pThis->complete_pending_buffer_done_cbs();
if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_PAUSE_PENDING)) {
DEBUG_PRINT_LOW("\n OMX_COMPONENT_GENERATE_PAUSE_DONE nofity");
//Send the callback now
BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_PAUSE_PENDING);
pThis->m_state = OMX_StatePause;
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventCmdComplete,OMX_CommandStateSet,
OMX_StatePause, NULL);
}
}
} else {
DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__);
}
break;
case OMX_COMPONENT_GENERATE_RESUME_DONE:
DEBUG_PRINT_HIGH("\n Rxd OMX_COMPONENT_GENERATE_RESUME_DONE");
if (pThis->m_cb.EventHandler) {
if (p2 != VDEC_S_SUCCESS) {
DEBUG_PRINT_ERROR("\n OMX_COMPONENT_GENERATE_RESUME_DONE failed");
pThis->omx_report_error ();
} else {
if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_EXECUTE_PENDING)) {
DEBUG_PRINT_LOW("\n Moving the decoder to execute state");
// Send the callback now
BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_EXECUTE_PENDING);
pThis->m_state = OMX_StateExecuting;
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventCmdComplete,OMX_CommandStateSet,
OMX_StateExecuting,NULL);
}
}
} else {
DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__);
}
break;
case OMX_COMPONENT_GENERATE_STOP_DONE:
DEBUG_PRINT_HIGH("\n Rxd OMX_COMPONENT_GENERATE_STOP_DONE");
if (pThis->m_cb.EventHandler) {
if (p2 != VDEC_S_SUCCESS) {
DEBUG_PRINT_ERROR("\n OMX_COMPONENT_GENERATE_STOP_DONE ret failed");
pThis->omx_report_error ();
} else {
pThis->complete_pending_buffer_done_cbs();
if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_IDLE_PENDING)) {
DEBUG_PRINT_LOW("\n OMX_COMPONENT_GENERATE_STOP_DONE Success");
// Send the callback now
BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_IDLE_PENDING);
pThis->m_state = OMX_StateIdle;
DEBUG_PRINT_LOW("\n Move to Idle State");
pThis->m_cb.EventHandler(&pThis->m_cmp,pThis->m_app_data,
OMX_EventCmdComplete,OMX_CommandStateSet,
OMX_StateIdle,NULL);
}
}
} else {
DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__);
}
break;
case OMX_COMPONENT_GENERATE_PORT_RECONFIG:
DEBUG_PRINT_HIGH("\n Rxd OMX_COMPONENT_GENERATE_PORT_RECONFIG");
if (p2 == OMX_IndexParamPortDefinition) {
pThis->in_reconfig = true;
}
if (pThis->m_cb.EventHandler) {
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventPortSettingsChanged, p1, p2, NULL );
} else {
DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__);
}
if (pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) {
OMX_INTERLACETYPE format = (OMX_INTERLACETYPE)-1;
OMX_EVENTTYPE event = (OMX_EVENTTYPE)OMX_EventIndexsettingChanged;
if (pThis->drv_ctx.interlace == VDEC_InterlaceInterleaveFrameTopFieldFirst)
format = OMX_InterlaceInterleaveFrameTopFieldFirst;
else if (pThis->drv_ctx.interlace == VDEC_InterlaceInterleaveFrameBottomFieldFirst)
format = OMX_InterlaceInterleaveFrameBottomFieldFirst;
else //unsupported interlace format; raise a error
event = OMX_EventError;
if (pThis->m_cb.EventHandler) {
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
event, format, 0, NULL );
} else {
DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__);
}
}
break;
case OMX_COMPONENT_GENERATE_EOS_DONE:
DEBUG_PRINT_HIGH("\n Rxd OMX_COMPONENT_GENERATE_EOS_DONE");
if (pThis->m_cb.EventHandler) {
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, OMX_EventBufferFlag,
OMX_CORE_OUTPUT_PORT_INDEX, OMX_BUFFERFLAG_EOS, NULL );
} else {
DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__);
}
pThis->prev_ts = LLONG_MAX;
pThis->rst_prev_ts = true;
break;
case OMX_COMPONENT_GENERATE_HARDWARE_ERROR:
DEBUG_PRINT_ERROR("\n OMX_COMPONENT_GENERATE_HARDWARE_ERROR");
pThis->omx_report_error ();
break;
case OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING:
DEBUG_PRINT_ERROR("\n OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING\n");
pThis->omx_report_unsupported_setting();
break;
case OMX_COMPONENT_GENERATE_INFO_PORT_RECONFIG: {
DEBUG_PRINT_HIGH("\n Rxd OMX_COMPONENT_GENERATE_INFO_PORT_RECONFIG");
if (pThis->m_cb.EventHandler) {
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
(OMX_EVENTTYPE)OMX_EventIndexsettingChanged, OMX_CORE_OUTPUT_PORT_INDEX, 0, NULL );
} else {
DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__);
}
}
default:
break;
}
}
pthread_mutex_lock(&pThis->m_lock);
qsize = pThis->m_cmd_q.m_size;
if (pThis->m_state != OMX_StatePause)
qsize += (pThis->m_ftb_q.m_size + pThis->m_etb_q.m_size);
pthread_mutex_unlock(&pThis->m_lock);
} while (qsize>0);
}
int omx_vdec::update_resolution(int width, int height, int stride, int scan_lines)
{
int format_changed = 0;
if ((height != drv_ctx.video_resolution.frame_height) ||
(width != drv_ctx.video_resolution.frame_width)) {
DEBUG_PRINT_HIGH("NOTE_CIF: W/H %d (%d), %d (%d)\n",
width, drv_ctx.video_resolution.frame_width,
height,drv_ctx.video_resolution.frame_height);
format_changed = 1;
}
drv_ctx.video_resolution.frame_height = height;
drv_ctx.video_resolution.frame_width = width;
drv_ctx.video_resolution.scan_lines = scan_lines;
drv_ctx.video_resolution.stride = stride;
rectangle.nLeft = 0;
rectangle.nTop = 0;
rectangle.nWidth = drv_ctx.video_resolution.frame_width;
rectangle.nHeight = drv_ctx.video_resolution.frame_height;
return format_changed;
}
OMX_ERRORTYPE omx_vdec::is_video_session_supported()
{
if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc",
OMX_MAX_STRINGNAME_SIZE) &&
(m_profile == HIGH_PROFILE || m_profile == MAIN_PROFILE)) {
m_decoder_capability.max_width = 1280;
m_decoder_capability.max_height = 720;
DEBUG_PRINT_HIGH("Set max_width=1280 & max_height=720 for H264 HP/MP");
}
if ((drv_ctx.video_resolution.frame_width *
drv_ctx.video_resolution.frame_height >
m_decoder_capability.max_width *
m_decoder_capability.max_height) ||
(drv_ctx.video_resolution.frame_width*
drv_ctx.video_resolution.frame_height <
m_decoder_capability.min_width *
m_decoder_capability.min_height)) {
DEBUG_PRINT_ERROR(
"Unsupported WxH = (%u)x(%u) supported range is min(%u)x(%u) - max(%u)x(%u)",
drv_ctx.video_resolution.frame_width,
drv_ctx.video_resolution.frame_height,
m_decoder_capability.min_width,
m_decoder_capability.min_height,
m_decoder_capability.max_width,
m_decoder_capability.max_height);
return OMX_ErrorUnsupportedSetting;
}
DEBUG_PRINT_HIGH("\n video session supported\n");
return OMX_ErrorNone;
}
/* ======================================================================
FUNCTION
omx_vdec::ComponentInit
DESCRIPTION
Initialize the component.
PARAMETERS
ctxt -- Context information related to the self.
id -- Event identifier. This could be any of the following:
1. Command completion event
2. Buffer done callback event
3. Frame done callback event
RETURN VALUE
None.
========================================================================== */
OMX_ERRORTYPE omx_vdec::component_init(OMX_STRING role)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
struct v4l2_fmtdesc fdesc;
struct v4l2_format fmt;
struct v4l2_requestbuffers bufreq;
struct v4l2_control control;
struct v4l2_frmsizeenum frmsize;
unsigned int alignment = 0,buffer_size = 0;
int fds[2];
int r,ret=0;
bool codec_ambiguous = false;
OMX_STRING device_name = (OMX_STRING)"/dev/video/venus_dec";
if (!strncmp(role, "OMX.qcom.video.decoder.avc.smoothstreaming",OMX_MAX_STRINGNAME_SIZE)) {
ALOGI("smooth streaming role");
mInSmoothstreamingMode = true;
role = "OMX.qcom.video.decoder.avc";
}
if (!strncmp(role, "OMX.qcom.video.decoder.avc.smoothstreaming.secure",OMX_MAX_STRINGNAME_SIZE)) {
ALOGI("secure smooth streaming role");
mInSmoothstreamingMode = true;
role = "OMX.qcom.video.decoder.avc.secure";
}
#ifdef _ANDROID_
char platform_name[PROPERTY_VALUE_MAX];
property_get("ro.board.platform", platform_name, "0");
if (!strncmp(platform_name, "msm8610", 7)) {
device_name = (OMX_STRING)"/dev/video/q6_dec";
}
#endif
if (!strncmp(role, "OMX.qcom.video.decoder.avc.secure",OMX_MAX_STRINGNAME_SIZE)) {
struct v4l2_control control;
secure_mode = true;
arbitrary_bytes = false;
role = (OMX_STRING)"OMX.qcom.video.decoder.avc";
}
drv_ctx.video_driver_fd = open(device_name, O_RDWR);
DEBUG_PRINT_HIGH("\n omx_vdec::component_init(): Open returned fd %d, errno %d",
drv_ctx.video_driver_fd, errno);
if (drv_ctx.video_driver_fd == 0) {
DEBUG_PRINT_ERROR("omx_vdec_msm8974 :: Got fd as 0 for msm_vidc_dec, Opening again\n");
drv_ctx.video_driver_fd = open(device_name, O_RDWR);
close(0);
}
if (drv_ctx.video_driver_fd < 0) {
DEBUG_PRINT_ERROR("Omx_vdec::Comp Init Returning failure, errno %d\n", errno);
return OMX_ErrorInsufficientResources;
}
drv_ctx.frame_rate.fps_numerator = DEFAULT_FPS;
drv_ctx.frame_rate.fps_denominator = 1;
ret = subscribe_to_events(drv_ctx.video_driver_fd);
if (!ret) {
async_thread_created = true;
ret = pthread_create(&async_thread_id,0,async_message_thread,this);
}
if (ret) {
DEBUG_PRINT_ERROR("\n Failed to create async_message_thread \n");
async_thread_created = false;
return OMX_ErrorInsufficientResources;
}
#ifdef INPUT_BUFFER_LOG
strcpy(inputfilename, INPUT_BUFFER_FILE_NAME);
#endif
#ifdef OUTPUT_BUFFER_LOG
outputBufferFile1 = fopen (outputfilename, "ab");
#endif
#ifdef OUTPUT_EXTRADATA_LOG
outputExtradataFile = fopen (ouputextradatafilename, "ab");
#endif
// Copy the role information which provides the decoder kind
strlcpy(drv_ctx.kind,role,128);
if (!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.mpeg4",\
OMX_MAX_STRINGNAME_SIZE)) {
strlcpy((char *)m_cRole, "video_decoder.mpeg4",\
OMX_MAX_STRINGNAME_SIZE);
drv_ctx.timestamp_adjust = true;
drv_ctx.decoder_format = VDEC_CODECTYPE_MPEG4;
eCompressionFormat = OMX_VIDEO_CodingMPEG4;
output_capability=V4L2_PIX_FMT_MPEG4;
/*Initialize Start Code for MPEG4*/
codec_type_parse = CODEC_TYPE_MPEG4;
m_frame_parser.init_start_codes (codec_type_parse);
#ifdef INPUT_BUFFER_LOG
strcat(inputfilename, "m4v");
#endif
} else if (!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.mpeg2",\
OMX_MAX_STRINGNAME_SIZE)) {
strlcpy((char *)m_cRole, "video_decoder.mpeg2",\
OMX_MAX_STRINGNAME_SIZE);
drv_ctx.decoder_format = VDEC_CODECTYPE_MPEG2;
output_capability = V4L2_PIX_FMT_MPEG2;
eCompressionFormat = OMX_VIDEO_CodingMPEG2;
/*Initialize Start Code for MPEG2*/
codec_type_parse = CODEC_TYPE_MPEG2;
m_frame_parser.init_start_codes (codec_type_parse);
#ifdef INPUT_BUFFER_LOG
strcat(inputfilename, "mpg");
#endif
} else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263",\
OMX_MAX_STRINGNAME_SIZE)) {
strlcpy((char *)m_cRole, "video_decoder.h263",OMX_MAX_STRINGNAME_SIZE);
DEBUG_PRINT_LOW("\n H263 Decoder selected");
drv_ctx.decoder_format = VDEC_CODECTYPE_H263;
eCompressionFormat = OMX_VIDEO_CodingH263;
output_capability = V4L2_PIX_FMT_H263;
codec_type_parse = CODEC_TYPE_H263;
m_frame_parser.init_start_codes (codec_type_parse);
#ifdef INPUT_BUFFER_LOG
strcat(inputfilename, "263");
#endif
} else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx311",\
OMX_MAX_STRINGNAME_SIZE)) {
strlcpy((char *)m_cRole, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE);
DEBUG_PRINT_LOW ("\n DIVX 311 Decoder selected");
drv_ctx.decoder_format = VDEC_CODECTYPE_DIVX_3;
output_capability = V4L2_PIX_FMT_DIVX_311;
eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
codec_type_parse = CODEC_TYPE_DIVX;
m_frame_parser.init_start_codes (codec_type_parse);
eRet = createDivxDrmContext();
if (eRet != OMX_ErrorNone) {
DEBUG_PRINT_ERROR("createDivxDrmContext Failed");
return eRet;
}
} else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx4",\
OMX_MAX_STRINGNAME_SIZE)) {
strlcpy((char *)m_cRole, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE);
DEBUG_PRINT_ERROR ("\n DIVX 4 Decoder selected");
drv_ctx.decoder_format = VDEC_CODECTYPE_DIVX_4;
output_capability = V4L2_PIX_FMT_DIVX;
eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
codec_type_parse = CODEC_TYPE_DIVX;
codec_ambiguous = true;
m_frame_parser.init_start_codes (codec_type_parse);
eRet = createDivxDrmContext();
if (eRet != OMX_ErrorNone) {
DEBUG_PRINT_ERROR("createDivxDrmContext Failed");
return eRet;
}
} else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx",\
OMX_MAX_STRINGNAME_SIZE)) {
strlcpy((char *)m_cRole, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE);
DEBUG_PRINT_ERROR ("\n DIVX 5/6 Decoder selected");
drv_ctx.decoder_format = VDEC_CODECTYPE_DIVX_6;
output_capability = V4L2_PIX_FMT_DIVX;
eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
codec_type_parse = CODEC_TYPE_DIVX;
codec_ambiguous = true;
m_frame_parser.init_start_codes (codec_type_parse);
eRet = createDivxDrmContext();
if (eRet != OMX_ErrorNone) {
DEBUG_PRINT_ERROR("createDivxDrmContext Failed");
return eRet;
}
} else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc",\
OMX_MAX_STRINGNAME_SIZE)) {
strlcpy((char *)m_cRole, "video_decoder.avc",OMX_MAX_STRINGNAME_SIZE);
drv_ctx.decoder_format = VDEC_CODECTYPE_H264;
output_capability=V4L2_PIX_FMT_H264;
eCompressionFormat = OMX_VIDEO_CodingAVC;
codec_type_parse = CODEC_TYPE_H264;
m_frame_parser.init_start_codes (codec_type_parse);
m_frame_parser.init_nal_length(nal_length);
#ifdef INPUT_BUFFER_LOG
strcat(inputfilename, "264");
#endif
} else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vc1",\
OMX_MAX_STRINGNAME_SIZE)) {
strlcpy((char *)m_cRole, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE);
drv_ctx.decoder_format = VDEC_CODECTYPE_VC1;
eCompressionFormat = OMX_VIDEO_CodingWMV;
codec_type_parse = CODEC_TYPE_VC1;
output_capability = V4L2_PIX_FMT_VC1_ANNEX_G;
m_frame_parser.init_start_codes (codec_type_parse);
#ifdef INPUT_BUFFER_LOG
strcat(inputfilename, "vc1");
#endif
} else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.wmv",\
OMX_MAX_STRINGNAME_SIZE)) {
strlcpy((char *)m_cRole, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE);
drv_ctx.decoder_format = VDEC_CODECTYPE_VC1_RCV;
eCompressionFormat = OMX_VIDEO_CodingWMV;
codec_type_parse = CODEC_TYPE_VC1;
output_capability = V4L2_PIX_FMT_VC1_ANNEX_L;
m_frame_parser.init_start_codes (codec_type_parse);
#ifdef INPUT_BUFFER_LOG
strcat(inputfilename, "vc1");
#endif
} else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8", \
OMX_MAX_STRINGNAME_SIZE)) {
strlcpy((char *)m_cRole, "video_decoder.vp8",OMX_MAX_STRINGNAME_SIZE);
output_capability=V4L2_PIX_FMT_VP8;
eCompressionFormat = OMX_VIDEO_CodingVPX;
codec_type_parse = CODEC_TYPE_VP8;
arbitrary_bytes = false;
#ifdef INPUT_BUFFER_LOG
strcat(inputfilename, "ivf");
#endif
} else {
DEBUG_PRINT_ERROR("\nERROR:Unknown Component\n");
eRet = OMX_ErrorInvalidComponentName;
}
#ifdef INPUT_BUFFER_LOG
inputBufferFile1 = fopen (inputfilename, "ab");
if (output_capability == V4L2_PIX_FMT_VP8) {
struct ivf_file_header {
OMX_U8 signature[4]; //='DKIF';
OMX_U8 version ; //= 0;
OMX_U8 headersize ; //= 32;
OMX_U32 FourCC;
OMX_U8 width;
OMX_U8 height;
OMX_U32 rate;
OMX_U32 scale;
OMX_U32 length;
OMX_U8 unused[4];
} file_header;
memset((void *)&file_header,0,sizeof(file_header));
file_header.signature[0] = 'D';
file_header.signature[1] = 'K';
file_header.signature[2] = 'I';
file_header.signature[3] = 'F';
file_header.version = 0;
file_header.headersize = 32;
file_header.FourCC = 0x30385056;
if (inputBufferFile1) {
fwrite((const char *)&file_header,
sizeof(file_header),1,inputBufferFile1);
}
}
#endif
if (eRet == OMX_ErrorNone) {
drv_ctx.output_format = VDEC_YUV_FORMAT_NV12;
OMX_COLOR_FORMATTYPE dest_color_format = (OMX_COLOR_FORMATTYPE)
QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m;
if (!client_buffers.set_color_format(dest_color_format)) {
DEBUG_PRINT_ERROR("\n Setting color format failed");
eRet = OMX_ErrorInsufficientResources;
}
capture_capability= V4L2_PIX_FMT_NV12;
struct v4l2_capability cap;
ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_QUERYCAP, &cap);
if (ret) {
DEBUG_PRINT_ERROR("Failed to query capabilities\n");
/*TODO: How to handle this case */
} else {
DEBUG_PRINT_HIGH("Capabilities: driver_name = %s, card = %s, bus_info = %s,"
" version = %d, capabilities = %x\n", cap.driver, cap.card,
cap.bus_info, cap.version, cap.capabilities);
}
ret=0;
fdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fdesc.index=0;
while (ioctl(drv_ctx.video_driver_fd, VIDIOC_ENUM_FMT, &fdesc) == 0) {
DEBUG_PRINT_HIGH("fmt: description: %s, fmt: %x, flags = %x\n", fdesc.description,
fdesc.pixelformat, fdesc.flags);
fdesc.index++;
}
fdesc.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
fdesc.index=0;
while (ioctl(drv_ctx.video_driver_fd, VIDIOC_ENUM_FMT, &fdesc) == 0) {
DEBUG_PRINT_HIGH("fmt: description: %s, fmt: %x, flags = %x\n", fdesc.description,
fdesc.pixelformat, fdesc.flags);
fdesc.index++;
}
update_resolution(320, 240, 320, 240);
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height;
fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width;
fmt.fmt.pix_mp.pixelformat = output_capability;
ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt);
if (ret) {
/*TODO: How to handle this case */
DEBUG_PRINT_ERROR("Failed to set format on output port\n");
return OMX_ErrorInsufficientResources;
}
DEBUG_PRINT_HIGH("\n Set Format was successful \n ");
if (codec_ambiguous) {
if (output_capability == V4L2_PIX_FMT_DIVX) {
struct v4l2_control divx_ctrl;
if (drv_ctx.decoder_format == VDEC_CODECTYPE_DIVX_4) {
divx_ctrl.value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4;
} else if (drv_ctx.decoder_format == VDEC_CODECTYPE_DIVX_5) {
divx_ctrl.value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5;
} else {
divx_ctrl.value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6;
}
divx_ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT;
ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &divx_ctrl);
if (ret) {
DEBUG_PRINT_ERROR("Failed to set divx version\n");
}
} else {
DEBUG_PRINT_ERROR("Codec should not be ambiguous");
}
}
//Get the hardware capabilities
memset((void *)&frmsize,0,sizeof(frmsize));
frmsize.index = 0;
frmsize.pixel_format = output_capability;
ret = ioctl(drv_ctx.video_driver_fd,
VIDIOC_ENUM_FRAMESIZES, &frmsize);
if (ret || frmsize.type != V4L2_FRMSIZE_TYPE_STEPWISE) {
DEBUG_PRINT_ERROR("Failed to get framesizes\n");
return OMX_ErrorHardware;
}
if (frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
m_decoder_capability.min_width = frmsize.stepwise.min_width;
m_decoder_capability.max_width = frmsize.stepwise.max_width;
m_decoder_capability.min_height = frmsize.stepwise.min_height;
m_decoder_capability.max_height = frmsize.stepwise.max_height;
}
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height;
fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width;
fmt.fmt.pix_mp.pixelformat = capture_capability;
ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt);
if (ret) {
/*TODO: How to handle this case */
DEBUG_PRINT_ERROR("Failed to set format on capture port\n");
}
DEBUG_PRINT_HIGH("\n Set Format was successful \n ");
if (secure_mode) {
control.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE;
control.value = 1;
DEBUG_PRINT_LOW("Omx_vdec:: calling to open secure device %d\n", ret);
ret=ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL,&control);
if (ret) {
DEBUG_PRINT_ERROR("Omx_vdec:: Unable to open secure device %d\n", ret);
return OMX_ErrorInsufficientResources;
}
}
/*Get the Buffer requirements for input and output ports*/
drv_ctx.ip_buf.buffer_type = VDEC_BUFFER_TYPE_INPUT;
drv_ctx.op_buf.buffer_type = VDEC_BUFFER_TYPE_OUTPUT;
if (secure_mode) {
drv_ctx.op_buf.alignment=SZ_1M;
drv_ctx.ip_buf.alignment=SZ_1M;
} else {
drv_ctx.op_buf.alignment=SZ_4K;
drv_ctx.ip_buf.alignment=SZ_4K;
}
drv_ctx.interlace = VDEC_InterlaceFrameProgressive;
drv_ctx.extradata = 0;
drv_ctx.picture_order = VDEC_ORDER_DISPLAY;
control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER;
control.value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY;
ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control);
drv_ctx.idr_only_decoding = 0;
m_state = OMX_StateLoaded;
#ifdef DEFAULT_EXTRADATA
if (strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8", \
OMX_MAX_STRINGNAME_SIZE)) {
if (eRet == OMX_ErrorNone && !secure_mode)
enable_extradata(DEFAULT_EXTRADATA, true, true);
}
#endif
if (mInSmoothstreamingMode) {
control.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
control.value = 1;
DEBUG_PRINT_ERROR("Enabling smooth streaming!\n");
if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control) < 0) {
DEBUG_PRINT_ERROR("Failed to enable Smooth Streaming");
}
}
eRet=get_buffer_req(&drv_ctx.ip_buf);
DEBUG_PRINT_HIGH("Input Buffer Size =%d \n ",drv_ctx.ip_buf.buffer_size);
get_buffer_req(&drv_ctx.op_buf);
if (drv_ctx.decoder_format == VDEC_CODECTYPE_H264) {
if (m_frame_parser.mutils == NULL) {
m_frame_parser.mutils = new H264_Utils();
if (m_frame_parser.mutils == NULL) {
DEBUG_PRINT_ERROR("\n parser utils Allocation failed ");
eRet = OMX_ErrorInsufficientResources;
} else {
h264_scratch.nAllocLen = drv_ctx.ip_buf.buffer_size;
h264_scratch.pBuffer = (OMX_U8 *)malloc (drv_ctx.ip_buf.buffer_size);
h264_scratch.nFilledLen = 0;
h264_scratch.nOffset = 0;
if (h264_scratch.pBuffer == NULL) {
DEBUG_PRINT_ERROR("\n h264_scratch.pBuffer Allocation failed ");
return OMX_ErrorInsufficientResources;
}
m_frame_parser.mutils->initialize_frame_checking_environment();
m_frame_parser.mutils->allocate_rbsp_buffer (drv_ctx.ip_buf.buffer_size);
}
}
h264_parser = new h264_stream_parser();
if (!h264_parser) {
DEBUG_PRINT_ERROR("ERROR: H264 parser allocation failed!");
eRet = OMX_ErrorInsufficientResources;
}
}
if (pipe(fds)) {
DEBUG_PRINT_ERROR("pipe creation failed\n");
eRet = OMX_ErrorInsufficientResources;
} else {
int temp1[2];
if (fds[0] == 0 || fds[1] == 0) {
if (pipe (temp1)) {
DEBUG_PRINT_ERROR("pipe creation failed\n");
return OMX_ErrorInsufficientResources;
}
//close (fds[0]);
//close (fds[1]);
fds[0] = temp1 [0];
fds[1] = temp1 [1];
}
m_pipe_in = fds[0];
m_pipe_out = fds[1];
msg_thread_created = true;
r = pthread_create(&msg_thread_id,0,message_thread,this);
if (r < 0) {
DEBUG_PRINT_ERROR("\n component_init(): message_thread creation failed");
msg_thread_created = false;
eRet = OMX_ErrorInsufficientResources;
}
}
}
if (eRet != OMX_ErrorNone) {
DEBUG_PRINT_ERROR("\n Component Init Failed");
} else {
DEBUG_PRINT_HIGH("\n omx_vdec::component_init() success");
}
//memset(&h264_mv_buff,0,sizeof(struct h264_mv_buffer));
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::GetComponentVersion
DESCRIPTION
Returns the component version.
PARAMETERS
TBD.
RETURN VALUE
OMX_ErrorNone.
========================================================================== */
OMX_ERRORTYPE omx_vdec::get_component_version
(
OMX_IN OMX_HANDLETYPE hComp,
OMX_OUT OMX_STRING componentName,
OMX_OUT OMX_VERSIONTYPE* componentVersion,
OMX_OUT OMX_VERSIONTYPE* specVersion,
OMX_OUT OMX_UUIDTYPE* componentUUID
)
{
if (m_state == OMX_StateInvalid) {
DEBUG_PRINT_ERROR("Get Comp Version in Invalid State\n");
return OMX_ErrorInvalidState;
}
/* TBD -- Return the proper version */
if (specVersion) {
specVersion->nVersion = OMX_SPEC_VERSION;
}
return OMX_ErrorNone;
}
/* ======================================================================
FUNCTION
omx_vdec::SendCommand
DESCRIPTION
Returns zero if all the buffers released..
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
OMX_ERRORTYPE omx_vdec::send_command(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_COMMANDTYPE cmd,
OMX_IN OMX_U32 param1,
OMX_IN OMX_PTR cmdData
)
{
DEBUG_PRINT_LOW("\n send_command: Recieved a Command from Client");
if (m_state == OMX_StateInvalid) {
DEBUG_PRINT_ERROR("ERROR: Send Command in Invalid State\n");
return OMX_ErrorInvalidState;
}
if (cmd == OMX_CommandFlush && param1 != OMX_CORE_INPUT_PORT_INDEX
&& param1 != OMX_CORE_OUTPUT_PORT_INDEX && param1 != OMX_ALL) {
DEBUG_PRINT_ERROR("\n send_command(): ERROR OMX_CommandFlush "
"to invalid port: %lu", param1);
return OMX_ErrorBadPortIndex;
}
post_event((unsigned)cmd,(unsigned)param1,OMX_COMPONENT_GENERATE_COMMAND);
sem_wait(&m_cmd_lock);
DEBUG_PRINT_LOW("\n send_command: Command Processed\n");
return OMX_ErrorNone;
}
/* ======================================================================
FUNCTION
omx_vdec::SendCommand
DESCRIPTION
Returns zero if all the buffers released..
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
OMX_ERRORTYPE omx_vdec::send_command_proxy(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_COMMANDTYPE cmd,
OMX_IN OMX_U32 param1,
OMX_IN OMX_PTR cmdData
)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
OMX_STATETYPE eState = (OMX_STATETYPE) param1;
int bFlag = 1,sem_posted = 0,ret=0;
DEBUG_PRINT_LOW("\n send_command_proxy(): cmd = %d", cmd);
DEBUG_PRINT_HIGH("\n send_command_proxy(): Current State %d, Expected State %d",
m_state, eState);
if (cmd == OMX_CommandStateSet) {
DEBUG_PRINT_HIGH("\n send_command_proxy(): OMX_CommandStateSet issued");
DEBUG_PRINT_HIGH("\n Current State %d, Expected State %d", m_state, eState);
/***************************/
/* Current State is Loaded */
/***************************/
if (m_state == OMX_StateLoaded) {
if (eState == OMX_StateIdle) {
//if all buffers are allocated or all ports disabled
if (allocate_done() ||
(m_inp_bEnabled == OMX_FALSE && m_out_bEnabled == OMX_FALSE)) {
DEBUG_PRINT_LOW("send_command_proxy(): Loaded-->Idle\n");
} else {
DEBUG_PRINT_LOW("send_command_proxy(): Loaded-->Idle-Pending\n");
BITMASK_SET(&m_flags, OMX_COMPONENT_IDLE_PENDING);
// Skip the event notification
bFlag = 0;
}
}
/* Requesting transition from Loaded to Loaded */
else if (eState == OMX_StateLoaded) {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Loaded\n");
post_event(OMX_EventError,OMX_ErrorSameState,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorSameState;
}
/* Requesting transition from Loaded to WaitForResources */
else if (eState == OMX_StateWaitForResources) {
/* Since error is None , we will post an event
at the end of this function definition */
DEBUG_PRINT_LOW("send_command_proxy(): Loaded-->WaitForResources\n");
}
/* Requesting transition from Loaded to Executing */
else if (eState == OMX_StateExecuting) {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Executing\n");
post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorIncorrectStateTransition;
}
/* Requesting transition from Loaded to Pause */
else if (eState == OMX_StatePause) {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Pause\n");
post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorIncorrectStateTransition;
}
/* Requesting transition from Loaded to Invalid */
else if (eState == OMX_StateInvalid) {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Invalid\n");
post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorInvalidState;
} else {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Invalid(%d Not Handled)\n",\
eState);
eRet = OMX_ErrorBadParameter;
}
}
/***************************/
/* Current State is IDLE */
/***************************/
else if (m_state == OMX_StateIdle) {
if (eState == OMX_StateLoaded) {
if (release_done()) {
/*
Since error is None , we will post an event at the end
of this function definition
*/
DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Loaded\n");
} else {
DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Loaded-Pending\n");
BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING);
// Skip the event notification
bFlag = 0;
}
}
/* Requesting transition from Idle to Executing */
else if (eState == OMX_StateExecuting) {
DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing\n");
//BITMASK_SET(&m_flags, OMX_COMPONENT_EXECUTE_PENDING);
bFlag = 1;
DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing\n");
m_state=OMX_StateExecuting;
DEBUG_PRINT_HIGH("Stream On CAPTURE Was successful\n");
}
/* Requesting transition from Idle to Idle */
else if (eState == OMX_StateIdle) {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->Idle\n");
post_event(OMX_EventError,OMX_ErrorSameState,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorSameState;
}
/* Requesting transition from Idle to WaitForResources */
else if (eState == OMX_StateWaitForResources) {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->WaitForResources\n");
post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorIncorrectStateTransition;
}
/* Requesting transition from Idle to Pause */
else if (eState == OMX_StatePause) {
/*To pause the Video core we need to start the driver*/
if (/*ioctl (drv_ctx.video_driver_fd,VDEC_IOCTL_CMD_START,
NULL) < */0) {
DEBUG_PRINT_ERROR("\n VDEC_IOCTL_CMD_START FAILED");
omx_report_error ();
eRet = OMX_ErrorHardware;
} else {
BITMASK_SET(&m_flags,OMX_COMPONENT_PAUSE_PENDING);
DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Pause\n");
bFlag = 0;
}
}
/* Requesting transition from Idle to Invalid */
else if (eState == OMX_StateInvalid) {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->Invalid\n");
post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorInvalidState;
} else {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle --> %d Not Handled\n",eState);
eRet = OMX_ErrorBadParameter;
}
}
/******************************/
/* Current State is Executing */
/******************************/
else if (m_state == OMX_StateExecuting) {
DEBUG_PRINT_LOW("\n Command Recieved in OMX_StateExecuting");
/* Requesting transition from Executing to Idle */
if (eState == OMX_StateIdle) {
/* Since error is None , we will post an event
at the end of this function definition
*/
DEBUG_PRINT_LOW("\n send_command_proxy(): Executing --> Idle \n");
BITMASK_SET(&m_flags,OMX_COMPONENT_IDLE_PENDING);
if (!sem_posted) {
sem_posted = 1;
sem_post (&m_cmd_lock);
execute_omx_flush(OMX_ALL);
}
bFlag = 0;
}
/* Requesting transition from Executing to Paused */
else if (eState == OMX_StatePause) {
DEBUG_PRINT_LOW("\n PAUSE Command Issued");
m_state = OMX_StatePause;
bFlag = 1;
}
/* Requesting transition from Executing to Loaded */
else if (eState == OMX_StateLoaded) {
DEBUG_PRINT_ERROR("\n send_command_proxy(): Executing --> Loaded \n");
post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorIncorrectStateTransition;
}
/* Requesting transition from Executing to WaitForResources */
else if (eState == OMX_StateWaitForResources) {
DEBUG_PRINT_ERROR("\n send_command_proxy(): Executing --> WaitForResources \n");
post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorIncorrectStateTransition;
}
/* Requesting transition from Executing to Executing */
else if (eState == OMX_StateExecuting) {
DEBUG_PRINT_ERROR("\n send_command_proxy(): Executing --> Executing \n");
post_event(OMX_EventError,OMX_ErrorSameState,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorSameState;
}
/* Requesting transition from Executing to Invalid */
else if (eState == OMX_StateInvalid) {
DEBUG_PRINT_ERROR("\n send_command_proxy(): Executing --> Invalid \n");
post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorInvalidState;
} else {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Executing --> %d Not Handled\n",eState);
eRet = OMX_ErrorBadParameter;
}
}
/***************************/
/* Current State is Pause */
/***************************/
else if (m_state == OMX_StatePause) {
/* Requesting transition from Pause to Executing */
if (eState == OMX_StateExecuting) {
DEBUG_PRINT_LOW("\n Pause --> Executing \n");
m_state = OMX_StateExecuting;
bFlag = 1;
}
/* Requesting transition from Pause to Idle */
else if (eState == OMX_StateIdle) {
/* Since error is None , we will post an event
at the end of this function definition */
DEBUG_PRINT_LOW("\n Pause --> Idle \n");
BITMASK_SET(&m_flags,OMX_COMPONENT_IDLE_PENDING);
if (!sem_posted) {
sem_posted = 1;
sem_post (&m_cmd_lock);
execute_omx_flush(OMX_ALL);
}
bFlag = 0;
}
/* Requesting transition from Pause to loaded */
else if (eState == OMX_StateLoaded) {
DEBUG_PRINT_ERROR("\n Pause --> loaded \n");
post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorIncorrectStateTransition;
}
/* Requesting transition from Pause to WaitForResources */
else if (eState == OMX_StateWaitForResources) {
DEBUG_PRINT_ERROR("\n Pause --> WaitForResources \n");
post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorIncorrectStateTransition;
}
/* Requesting transition from Pause to Pause */
else if (eState == OMX_StatePause) {
DEBUG_PRINT_ERROR("\n Pause --> Pause \n");
post_event(OMX_EventError,OMX_ErrorSameState,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorSameState;
}
/* Requesting transition from Pause to Invalid */
else if (eState == OMX_StateInvalid) {
DEBUG_PRINT_ERROR("\n Pause --> Invalid \n");
post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorInvalidState;
} else {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Paused --> %d Not Handled\n",eState);
eRet = OMX_ErrorBadParameter;
}
}
/***************************/
/* Current State is WaitForResources */
/***************************/
else if (m_state == OMX_StateWaitForResources) {
/* Requesting transition from WaitForResources to Loaded */
if (eState == OMX_StateLoaded) {
/* Since error is None , we will post an event
at the end of this function definition */
DEBUG_PRINT_LOW("send_command_proxy(): WaitForResources-->Loaded\n");
}
/* Requesting transition from WaitForResources to WaitForResources */
else if (eState == OMX_StateWaitForResources) {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->WaitForResources\n");
post_event(OMX_EventError,OMX_ErrorSameState,
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorSameState;
}
/* Requesting transition from WaitForResources to Executing */
else if (eState == OMX_StateExecuting) {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->Executing\n");
post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorIncorrectStateTransition;
}
/* Requesting transition from WaitForResources to Pause */
else if (eState == OMX_StatePause) {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->Pause\n");
post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorIncorrectStateTransition;
}
/* Requesting transition from WaitForResources to Invalid */
else if (eState == OMX_StateInvalid) {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->Invalid\n");
post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorInvalidState;
}
/* Requesting transition from WaitForResources to Loaded -
is NOT tested by Khronos TS */
} else {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): %d --> %d(Not Handled)\n",m_state,eState);
eRet = OMX_ErrorBadParameter;
}
}
/********************************/
/* Current State is Invalid */
/*******************************/
else if (m_state == OMX_StateInvalid) {
/* State Transition from Inavlid to any state */
if (eState == (OMX_StateLoaded || OMX_StateWaitForResources
|| OMX_StateIdle || OMX_StateExecuting
|| OMX_StatePause || OMX_StateInvalid)) {
DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Invalid -->Loaded\n");
post_event(OMX_EventError,OMX_ErrorInvalidState,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorInvalidState;
}
} else if (cmd == OMX_CommandFlush) {
DEBUG_PRINT_HIGH("\n send_command_proxy(): OMX_CommandFlush issued"
"with param1: %lu", param1);
if (OMX_CORE_INPUT_PORT_INDEX == param1 || OMX_ALL == param1) {
BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_FLUSH_PENDING);
}
if (OMX_CORE_OUTPUT_PORT_INDEX == param1 || OMX_ALL == param1) {
BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_FLUSH_PENDING);
}
if (!sem_posted) {
sem_posted = 1;
DEBUG_PRINT_LOW("\n Set the Semaphore");
sem_post (&m_cmd_lock);
execute_omx_flush(param1);
}
bFlag = 0;
} else if ( cmd == OMX_CommandPortEnable) {
DEBUG_PRINT_HIGH("\n send_command_proxy(): OMX_CommandPortEnable issued"
"with param1: %lu", param1);
if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) {
m_inp_bEnabled = OMX_TRUE;
if ( (m_state == OMX_StateLoaded &&
!BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
|| allocate_input_done()) {
post_event(OMX_CommandPortEnable,OMX_CORE_INPUT_PORT_INDEX,
OMX_COMPONENT_GENERATE_EVENT);
} else {
DEBUG_PRINT_LOW("send_command_proxy(): Disabled-->Enabled Pending\n");
BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_ENABLE_PENDING);
// Skip the event notification
bFlag = 0;
}
}
if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) {
DEBUG_PRINT_LOW("\n Enable output Port command recieved");
m_out_bEnabled = OMX_TRUE;
if ( (m_state == OMX_StateLoaded &&
!BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
|| (allocate_output_done())) {
post_event(OMX_CommandPortEnable,OMX_CORE_OUTPUT_PORT_INDEX,
OMX_COMPONENT_GENERATE_EVENT);
} else {
DEBUG_PRINT_LOW("send_command_proxy(): Disabled-->Enabled Pending\n");
BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
// Skip the event notification
bFlag = 0;
}
}
} else if (cmd == OMX_CommandPortDisable) {
DEBUG_PRINT_HIGH("\n send_command_proxy(): OMX_CommandPortDisable issued"
"with param1: %lu", param1);
if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) {
m_inp_bEnabled = OMX_FALSE;
if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle)
&& release_input_done()) {
post_event(OMX_CommandPortDisable,OMX_CORE_INPUT_PORT_INDEX,
OMX_COMPONENT_GENERATE_EVENT);
} else {
BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_DISABLE_PENDING);
if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) {
if (!sem_posted) {
sem_posted = 1;
sem_post (&m_cmd_lock);
}
execute_omx_flush(OMX_CORE_INPUT_PORT_INDEX);
}
// Skip the event notification
bFlag = 0;
}
}
if (param1 == OMX_CORE_OUTPUT_PORT_INDEX || param1 == OMX_ALL) {
m_out_bEnabled = OMX_FALSE;
DEBUG_PRINT_LOW("\n Disable output Port command recieved");
if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle)
&& release_output_done()) {
post_event(OMX_CommandPortDisable,OMX_CORE_OUTPUT_PORT_INDEX,\
OMX_COMPONENT_GENERATE_EVENT);
} else {
BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING);
if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) {
if (!sem_posted) {
sem_posted = 1;
sem_post (&m_cmd_lock);
}
BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING);
execute_omx_flush(OMX_CORE_OUTPUT_PORT_INDEX);
}
// Skip the event notification
bFlag = 0;
}
}
} else {
DEBUG_PRINT_ERROR("Error: Invalid Command other than StateSet (%d)\n",cmd);
eRet = OMX_ErrorNotImplemented;
}
if (eRet == OMX_ErrorNone && bFlag) {
post_event(cmd,eState,OMX_COMPONENT_GENERATE_EVENT);
}
if (!sem_posted) {
sem_post(&m_cmd_lock);
}
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::ExecuteOmxFlush
DESCRIPTION
Executes the OMX flush.
PARAMETERS
flushtype - input flush(1)/output flush(0)/ both.
RETURN VALUE
true/false
========================================================================== */
bool omx_vdec::execute_omx_flush(OMX_U32 flushType)
{
bool bRet = false;
struct v4l2_plane plane;
struct v4l2_buffer v4l2_buf;
struct v4l2_decoder_cmd dec;
DEBUG_PRINT_LOW("in %s, flushing %d", __func__, flushType);
memset((void *)&v4l2_buf,0,sizeof(v4l2_buf));
dec.cmd = V4L2_DEC_QCOM_CMD_FLUSH;
DEBUG_PRINT_HIGH("in %s: reconfig? %d", __func__, in_reconfig);
if (in_reconfig && flushType == OMX_CORE_OUTPUT_PORT_INDEX) {
output_flush_progress = true;
dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
} else {
/* XXX: The driver/hardware does not support flushing of individual ports
* in all states. So we pretty much need to flush both ports internally,
* but client should only get the FLUSH_(INPUT|OUTPUT)_DONE for the one it
* requested. Since OMX_COMPONENT_(OUTPUT|INPUT)_FLUSH_PENDING isn't set,
* we automatically omit sending the FLUSH done for the "opposite" port. */
input_flush_progress = true;
output_flush_progress = true;
dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT | V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
}
if (ioctl(drv_ctx.video_driver_fd, VIDIOC_DECODER_CMD, &dec)) {
DEBUG_PRINT_ERROR("\n Flush Port (%lu) Failed ", flushType);
bRet = false;
}
return bRet;
}
/*=========================================================================
FUNCTION : execute_output_flush
DESCRIPTION
Executes the OMX flush at OUTPUT PORT.
PARAMETERS
None.
RETURN VALUE
true/false
==========================================================================*/
bool omx_vdec::execute_output_flush()
{
unsigned p1 = 0; // Parameter - 1
unsigned p2 = 0; // Parameter - 2
unsigned ident = 0;
bool bRet = true;
/*Generate FBD for all Buffers in the FTBq*/
pthread_mutex_lock(&m_lock);
DEBUG_PRINT_LOW("\n Initiate Output Flush");
while (m_ftb_q.m_size) {
DEBUG_PRINT_LOW("\n Buffer queue size %d pending buf cnt %d",
m_ftb_q.m_size,pending_output_buffers);
m_ftb_q.pop_entry(&p1,&p2,&ident);
DEBUG_PRINT_LOW("\n ID(%x) P1(%x) P2(%x)", ident, p1, p2);
if (ident == m_fill_output_msg ) {
m_cb.FillBufferDone(&m_cmp, m_app_data, (OMX_BUFFERHEADERTYPE *)p2);
} else if (ident == OMX_COMPONENT_GENERATE_FBD) {
fill_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1);
}
}
pthread_mutex_unlock(&m_lock);
output_flush_progress = false;
if (arbitrary_bytes) {
prev_ts = LLONG_MAX;
rst_prev_ts = true;
}
DEBUG_PRINT_HIGH("\n OMX flush o/p Port complete PenBuf(%d)", pending_output_buffers);
return bRet;
}
/*=========================================================================
FUNCTION : execute_input_flush
DESCRIPTION
Executes the OMX flush at INPUT PORT.
PARAMETERS
None.
RETURN VALUE
true/false
==========================================================================*/
bool omx_vdec::execute_input_flush()
{
unsigned i =0;
unsigned p1 = 0; // Parameter - 1
unsigned p2 = 0; // Parameter - 2
unsigned ident = 0;
bool bRet = true;
/*Generate EBD for all Buffers in the ETBq*/
DEBUG_PRINT_LOW("\n Initiate Input Flush \n");
pthread_mutex_lock(&m_lock);
DEBUG_PRINT_LOW("\n Check if the Queue is empty \n");
while (m_etb_q.m_size) {
m_etb_q.pop_entry(&p1,&p2,&ident);
if (ident == OMX_COMPONENT_GENERATE_ETB_ARBITRARY) {
DEBUG_PRINT_LOW("\n Flush Input Heap Buffer %p",(OMX_BUFFERHEADERTYPE *)p2);
m_cb.EmptyBufferDone(&m_cmp ,m_app_data, (OMX_BUFFERHEADERTYPE *)p2);
} else if (ident == OMX_COMPONENT_GENERATE_ETB) {
pending_input_buffers++;
DEBUG_PRINT_LOW("\n Flush Input OMX_COMPONENT_GENERATE_ETB %p, pending_input_buffers %d",
(OMX_BUFFERHEADERTYPE *)p2, pending_input_buffers);
empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p2);
} else if (ident == OMX_COMPONENT_GENERATE_EBD) {
DEBUG_PRINT_LOW("\n Flush Input OMX_COMPONENT_GENERATE_EBD %p",
(OMX_BUFFERHEADERTYPE *)p1);
empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1);
}
}
time_stamp_dts.flush_timestamp();
/*Check if Heap Buffers are to be flushed*/
if (arbitrary_bytes && !(codec_config_flag)) {
DEBUG_PRINT_LOW("\n Reset all the variables before flusing");
h264_scratch.nFilledLen = 0;
nal_count = 0;
look_ahead_nal = false;
frame_count = 0;
h264_last_au_ts = LLONG_MAX;
h264_last_au_flags = 0;
memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) );
m_demux_entries = 0;
DEBUG_PRINT_LOW("\n Initialize parser");
if (m_frame_parser.mutils) {
m_frame_parser.mutils->initialize_frame_checking_environment();
}
while (m_input_pending_q.m_size) {
m_input_pending_q.pop_entry(&p1,&p2,&ident);
m_cb.EmptyBufferDone(&m_cmp ,m_app_data, (OMX_BUFFERHEADERTYPE *)p1);
}
if (psource_frame) {
m_cb.EmptyBufferDone(&m_cmp ,m_app_data,psource_frame);
psource_frame = NULL;
}
if (pdest_frame) {
pdest_frame->nFilledLen = 0;
m_input_free_q.insert_entry((unsigned) pdest_frame, (unsigned int)NULL,
(unsigned int)NULL);
pdest_frame = NULL;
}
m_frame_parser.flush();
} else if (codec_config_flag) {
DEBUG_PRINT_HIGH("frame_parser flushing skipped due to codec config buffer "
"is not sent to the driver yet");
}
pthread_mutex_unlock(&m_lock);
input_flush_progress = false;
if (!arbitrary_bytes) {
prev_ts = LLONG_MAX;
rst_prev_ts = true;
}
#ifdef _ANDROID_
if (m_debug_timestamp) {
m_timestamp_list.reset_ts_list();
}
#endif
DEBUG_PRINT_HIGH("\n OMX flush i/p Port complete PenBuf(%d)", pending_input_buffers);
return bRet;
}
/* ======================================================================
FUNCTION
omx_vdec::SendCommandEvent
DESCRIPTION
Send the event to decoder pipe. This is needed to generate the callbacks
in decoder thread context.
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
bool omx_vdec::post_event(unsigned int p1,
unsigned int p2,
unsigned int id)
{
bool bRet = false;
pthread_mutex_lock(&m_lock);
if (id == m_fill_output_msg ||
id == OMX_COMPONENT_GENERATE_FBD) {
m_ftb_q.insert_entry(p1,p2,id);
} else if (id == OMX_COMPONENT_GENERATE_ETB ||
id == OMX_COMPONENT_GENERATE_EBD ||
id == OMX_COMPONENT_GENERATE_ETB_ARBITRARY) {
m_etb_q.insert_entry(p1,p2,id);
} else {
m_cmd_q.insert_entry(p1,p2,id);
}
bRet = true;
DEBUG_PRINT_LOW("\n Value of this pointer in post_event %p",this);
post_message(this, id);
pthread_mutex_unlock(&m_lock);
return bRet;
}
OMX_ERRORTYPE omx_vdec::get_supported_profile_level_for_1080p(OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevelType)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
if (!profileLevelType)
return OMX_ErrorBadParameter;
if (profileLevelType->nPortIndex == 0) {
if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc",OMX_MAX_STRINGNAME_SIZE)) {
if (profileLevelType->nProfileIndex == 0) {
profileLevelType->eProfile = OMX_VIDEO_AVCProfileBaseline;
profileLevelType->eLevel = OMX_VIDEO_AVCLevel4;
} else if (profileLevelType->nProfileIndex == 1) {
profileLevelType->eProfile = OMX_VIDEO_AVCProfileMain;
profileLevelType->eLevel = OMX_VIDEO_AVCLevel4;
} else if (profileLevelType->nProfileIndex == 2) {
profileLevelType->eProfile = OMX_VIDEO_AVCProfileHigh;
profileLevelType->eLevel = OMX_VIDEO_AVCLevel4;
} else {
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %lu\n",
profileLevelType->nProfileIndex);
eRet = OMX_ErrorNoMore;
}
} else if ((!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263",OMX_MAX_STRINGNAME_SIZE))) {
if (profileLevelType->nProfileIndex == 0) {
profileLevelType->eProfile = OMX_VIDEO_H263ProfileBaseline;
profileLevelType->eLevel = OMX_VIDEO_H263Level70;
} else {
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %lu\n", profileLevelType->nProfileIndex);
eRet = OMX_ErrorNoMore;
}
} else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE)) {
if (profileLevelType->nProfileIndex == 0) {
profileLevelType->eProfile = OMX_VIDEO_MPEG4ProfileSimple;
profileLevelType->eLevel = OMX_VIDEO_MPEG4Level5;
} else if (profileLevelType->nProfileIndex == 1) {
profileLevelType->eProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple;
profileLevelType->eLevel = OMX_VIDEO_MPEG4Level5;
} else {
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %lu\n", profileLevelType->nProfileIndex);
eRet = OMX_ErrorNoMore;
}
} else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8",OMX_MAX_STRINGNAME_SIZE)) {
eRet = OMX_ErrorNoMore;
} else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mpeg2",OMX_MAX_STRINGNAME_SIZE)) {
if (profileLevelType->nProfileIndex == 0) {
profileLevelType->eProfile = OMX_VIDEO_MPEG2ProfileSimple;
profileLevelType->eLevel = OMX_VIDEO_MPEG2LevelHL;
} else if (profileLevelType->nProfileIndex == 1) {
profileLevelType->eProfile = OMX_VIDEO_MPEG2ProfileMain;
profileLevelType->eLevel = OMX_VIDEO_MPEG2LevelHL;
} else {
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported nProfileIndex ret NoMore %lu\n", profileLevelType->nProfileIndex);
eRet = OMX_ErrorNoMore;
}
} else {
DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported ret NoMore for codec: %s\n", drv_ctx.kind);
eRet = OMX_ErrorNoMore;
}
} else {
DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoProfileLevelQuerySupported should be queries on Input port only %lu\n", profileLevelType->nPortIndex);
eRet = OMX_ErrorBadPortIndex;
}
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::GetParameter
DESCRIPTION
OMX Get Parameter method implementation
PARAMETERS
<TBD>.
RETURN VALUE
Error None if successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::get_parameter(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_INDEXTYPE paramIndex,
OMX_INOUT OMX_PTR paramData)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
DEBUG_PRINT_LOW("get_parameter: \n");
if (m_state == OMX_StateInvalid) {
DEBUG_PRINT_ERROR("Get Param in Invalid State\n");
return OMX_ErrorInvalidState;
}
if (paramData == NULL) {
DEBUG_PRINT_LOW("Get Param in Invalid paramData \n");
return OMX_ErrorBadParameter;
}
switch ((unsigned long)paramIndex) {
case OMX_IndexParamPortDefinition: {
OMX_PARAM_PORTDEFINITIONTYPE *portDefn =
(OMX_PARAM_PORTDEFINITIONTYPE *) paramData;
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamPortDefinition\n");
eRet = update_portdef(portDefn);
if (eRet == OMX_ErrorNone)
m_port_def = *portDefn;
break;
}
case OMX_IndexParamVideoInit: {
OMX_PORT_PARAM_TYPE *portParamType =
(OMX_PORT_PARAM_TYPE *) paramData;
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoInit\n");
portParamType->nVersion.nVersion = OMX_SPEC_VERSION;
portParamType->nSize = sizeof(portParamType);
portParamType->nPorts = 2;
portParamType->nStartPortNumber = 0;
break;
}
case OMX_IndexParamVideoPortFormat: {
OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt =
(OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData;
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoPortFormat\n");
portFmt->nVersion.nVersion = OMX_SPEC_VERSION;
portFmt->nSize = sizeof(portFmt);