blob: ff82ad0d5ffd8f5d9b81ce245e31bc3491469243 [file] [log] [blame]
/*--------------------------------------------------------------------------
Copyright (c) 2010, Code Aurora Forum. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Code Aurora nor
the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------*/
/*============================================================================
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 <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include "omx_vdec.h"
#include <fcntl.h>
#define BITSTREAM_LOG 0
#if BITSTREAM_LOG
FILE *outputBufferFile1;
char filename [] = "/data/input-bitstream.m4v";
#endif
#define H264_SUPPORTED_WIDTH (480)
#define H264_SUPPORTED_HEIGHT (368)
#define MPEG4_SUPPORTED_WIDTH (480)
#define MPEG4_SUPPORTED_HEIGHT (368)
#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
#ifdef _ANDROID_
extern "C"{
#include<utils/Log.h>
}
#endif//_ANDROID_
void* async_message_thread (void *input)
{
struct vdec_ioctl_msg ioctl_msg;
struct vdec_msginfo vdec_msg;
omx_vdec *omx = reinterpret_cast<omx_vdec*>(input);
DEBUG_PRINT_HIGH("omx_vdec: Async thread start\n");
while (1)
{
ioctl_msg.inputparam = NULL;
ioctl_msg.outputparam = (void*)&vdec_msg;
/*Wait for a message from the video decoder driver*/
if (ioctl ( omx->driver_context.video_driver_fd,VDEC_IOCTL_GET_NEXT_MSG,
(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Error in ioctl read next msg");
break;
}
else
{
/*Call Instance specific process function*/
if (omx->async_message_process(input,&vdec_msg) < 0)
{
DEBUG_PRINT_ERROR("\nERROR:Wrong ioctl message");
}
}
}
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");
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_ERROR("\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;
}
// factory function executed by the core to create instances
void *get_omx_component_factory_fn(void)
{
return (new omx_vdec);
}
#ifdef _ANDROID_
VideoHeap::VideoHeap(int fd, size_t size, void* base)
{
// dup file descriptor, map once, use pmem
init(dup(fd), base, size, 0 , "/dev/pmem_adsp");
}
#endif // _ANDROID_
/* ======================================================================
FUNCTION
omx_vdec::omx_vdec
DESCRIPTION
Constructor
PARAMETERS
None
RETURN VALUE
None.
========================================================================== */
omx_vdec::omx_vdec(): m_state(OMX_StateInvalid),
m_app_data(NULL),
m_color_format(OMX_COLOR_FormatYUV420Planar),
m_inp_mem_ptr(NULL),
m_out_mem_ptr(NULL),
pending_input_buffers(0),
pending_output_buffers(0),
m_out_bm_count(0),
m_out_buf_count(0),
m_inp_buf_count(OMX_VIDEO_DEC_NUM_INPUT_BUFFERS),
m_inp_buf_size(OMX_VIDEO_DEC_INPUT_BUFFER_SIZE),
m_inp_bm_count(0),
m_inp_bPopulated(OMX_FALSE),
m_out_bPopulated(OMX_FALSE),
m_height(0),
m_width(0),
m_port_height(0),
m_port_width(0),
m_crop_x(0),
m_crop_y(0),
m_crop_dx(0),
m_crop_dy(0),
m_flags(0),
m_inp_bEnabled(OMX_TRUE),
m_out_bEnabled(OMX_TRUE),
m_event_port_settings_sent(false),
input_flush_progress (false),
output_flush_progress (false),
m_platform_list(NULL),
m_platform_entry(NULL),
m_pmem_info(NULL),
input_use_buffer (false),
output_use_buffer (false),
m_ineos_reached (0),
m_outeos_pending (0),
m_outeos_reached (0),
arbitrary_bytes (true),
psource_frame (NULL),
pdest_frame (NULL),
m_inp_heap_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),
set_seq_header_done(false),
gate_output_buffers(true),
gate_input_buffers(false),
stride(0),
sent_first_frame(false),
m_error_propogated(false),
scan_lines(0),
m_device_file_ptr(NULL),
m_vc1_profile((vc1_profile_type)0)
{
/* Assumption is that , to begin with , we have all the frames with decoder */
DEBUG_PRINT_HIGH("\n In OMX vdec Constuctor");
memset(&m_cmp,0,sizeof(m_cmp));
memset(&m_cb,0,sizeof(m_cb));
memset (&driver_context,0,sizeof(driver_context));
memset (&h264_scratch,0,sizeof (OMX_BUFFERHEADERTYPE));
memset (m_hwdevice_name,0,sizeof(m_hwdevice_name));
driver_context.video_driver_fd = -1;
m_vendor_config.pData = NULL;
pthread_mutex_init(&m_lock, NULL);
sem_init(&m_cmd_lock,0,0);
}
/* ======================================================================
FUNCTION
omx_vdec::~omx_vdec
DESCRIPTION
Destructor
PARAMETERS
None
RETURN VALUE
None.
========================================================================== */
omx_vdec::~omx_vdec()
{
m_pmem_info = NULL;
m_port_width = m_port_height = 0;
DEBUG_PRINT_HIGH("\n 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("\n Waiting on OMX Msg Thread exit");
pthread_join(msg_thread_id,NULL);
DEBUG_PRINT_HIGH("\n Waiting on OMX Async Thread exit");
pthread_join(async_thread_id,NULL);
pthread_mutex_destroy(&m_lock);
sem_destroy(&m_cmd_lock);
DEBUG_PRINT_HIGH("\n Exit OMX vdec Destructor");
}
/* ======================================================================
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)
{
unsigned p1; // Parameter - 1
unsigned 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(&p1,&p2,&ident);
}
if (qsize == 0 && !pThis->gate_output_buffers)
{
qsize = pThis->m_ftb_q.m_size;
if (qsize)
{
pThis->m_ftb_q.pop_entry(&p1,&p2,&ident);
}
}
if (qsize == 0)
{
qsize = pThis->m_etb_q.m_size;
if (qsize)
{
pThis->m_etb_q.pop_entry(&p1,&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 == (unsigned)OMX_ErrorHardware)
{
pThis->omx_report_error();
}
else
{
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventError, p2, NULL, NULL );
}
break;
case OMX_CommandPortDisable:
DEBUG_PRINT_HIGH("\n OMX_CommandPortDisable complete for port [%d]", p2);
pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data,
OMX_EventCmdComplete, p1, p2, NULL );
//TODO: Check if output port is one that got disabled
pThis->gate_output_buffers = false;
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)
{
DEBUG_PRINT_ERROR("\n OMX_COMPONENT_GENERATE_EBD failure");
pThis->omx_report_error ();
}
else
{
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 ();
}
}
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 Flush i/p Port complete");
pThis->input_flush_progress = false;
DEBUG_PRINT_LOW("\n Input flush done pending input %d",
pThis->pending_input_buffers);
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->output_flush_progress)
{
DEBUG_PRINT_LOW("\n Output flush done hence issue stop");
if (ioctl (pThis->driver_context.video_driver_fd,
VDEC_IOCTL_CMD_STOP,NULL ) < 0)
{
DEBUG_PRINT_ERROR("\n VDEC_IOCTL_CMD_STOP failed");
pThis->omx_report_error ();
}
}
}
}
}
break;
case OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH:
DEBUG_PRINT_HIGH("\n Flush o/p Port complete");
pThis->output_flush_progress = false;
DEBUG_PRINT_LOW("\n Output flush done pending buf %d",pThis->pending_output_buffers);
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_IDLE_PENDING))
{
if (!pThis->input_flush_progress)
{
DEBUG_PRINT_LOW("\n Input flush done hence issue stop");
if (ioctl (pThis->driver_context.video_driver_fd,
VDEC_IOCTL_CMD_STOP,NULL ) < 0)
{
DEBUG_PRINT_ERROR("\n VDEC_IOCTL_CMD_STOP failed");
pThis->omx_report_error ();
}
}
}
}
}
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->driver_context.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
{
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);
}
}
}
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);
}
}
}
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
{
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);
}
}
}
break;
case OMX_COMPONENT_GENERATE_HARDWARE_ERROR:
DEBUG_PRINT_ERROR("\n OMX_COMPONENT_GENERATE_HARDWARE_ERROR");
pThis->omx_report_error ();
break;
default:
break;
}
}
pthread_mutex_lock(&pThis->m_lock);
if(!pThis->gate_output_buffers)
{
qsize = pThis->m_cmd_q.m_size + pThis->m_ftb_q.m_size +\
pThis->m_etb_q.m_size;
}
else
{
qsize = pThis->m_cmd_q.m_size + pThis->m_etb_q.m_size;
}
pthread_mutex_unlock(&pThis->m_lock);
}
while(qsize>0);
}
/* ======================================================================
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 vdec_ioctl_msg ioctl_msg = {NULL,NULL};
unsigned int alignment = 0,buffer_size = 0;
int fds[2];
int r;
bool is_fluid = false;
if (!m_device_file_ptr) {
int bytes_read = 0,count = 0;
unsigned min_size;
m_device_file_ptr = fopen("/sys/devices/system/soc/soc0/hw_platform","rb");
if (m_device_file_ptr) {
(void)fgets((char *)m_hwdevice_name,sizeof(m_hwdevice_name),m_device_file_ptr);
DEBUG_PRINT_HIGH ("\n Name of the device is %s",m_hwdevice_name);
min_size = strnlen((const char *)m_hwdevice_name,sizeof(m_hwdevice_name));
if (strlen("Fluid") < min_size) {
min_size = strnlen("Fluid",sizeof("Fluid"));
}
if (!strncmp("Fluid",(const char *)m_hwdevice_name,min_size)) {
is_fluid = true;
}
fclose (m_device_file_ptr);
} else {
DEBUG_PRINT_HIGH("\n Could not open hw_platform file");
}
}
DEBUG_PRINT_HIGH("\n omx_vdec::component_init(): Start of New Playback");
driver_context.video_driver_fd = open ("/dev/msm_vidc_dec",\
O_RDWR|O_NONBLOCK);
DEBUG_PRINT_HIGH("\n omx_vdec::component_init(): Open returned fd %d",
driver_context.video_driver_fd);
if(driver_context.video_driver_fd == 0){
driver_context.video_driver_fd = open ("/dev/msm_vidc_dec",\
O_RDWR|O_NONBLOCK);
}
if(driver_context.video_driver_fd < 0)
{
DEBUG_PRINT_ERROR("Omx_vdec::Comp Init Returning failure\n");
return OMX_ErrorInsufficientResources;
}
#ifndef MULTI_DEC_INST
unsigned int instance_count = 0;
if (!is_fluid) {
ioctl_msg.outputparam = &instance_count;
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_GET_NUMBER_INSTANCES,
(void*)&ioctl_msg) < 0){
DEBUG_PRINT_ERROR("\n Instance Query Failed");
return OMX_ErrorInsufficientResources;
}
if (instance_count > 1) {
close(driver_context.video_driver_fd);
DEBUG_PRINT_ERROR("\n Reject Second instance of Decoder");
driver_context.video_driver_fd = -1;
return OMX_ErrorInsufficientResources;
}
}
#endif
#if BITSTREAM_LOG
outputBufferFile1 = fopen (filename, "ab");
#endif
// Copy the role information which provides the decoder kind
strncpy(driver_context.kind,role,128);
if(!strncmp(driver_context.kind,"OMX.qcom.video.decoder.mpeg4",\
OMX_MAX_STRINGNAME_SIZE))
{
strncpy((char *)m_cRole, "video_decoder.mpeg4",\
OMX_MAX_STRINGNAME_SIZE);
driver_context.decoder_format = VDEC_CODECTYPE_MPEG4;
eCompressionFormat = OMX_VIDEO_CodingMPEG4;
/*Initialize Start Code for MPEG4*/
codec_type_parse = CODEC_TYPE_MPEG4;
m_frame_parser.init_start_codes (codec_type_parse);
}
else if(!strncmp(driver_context.kind, "OMX.qcom.video.decoder.h263",\
OMX_MAX_STRINGNAME_SIZE))
{
strncpy((char *)m_cRole, "video_decoder.h263",OMX_MAX_STRINGNAME_SIZE);
DEBUG_PRINT_LOW("\n H263 Decoder selected");
driver_context.decoder_format = VDEC_CODECTYPE_H263;
eCompressionFormat = OMX_VIDEO_CodingH263;
codec_type_parse = CODEC_TYPE_H263;
m_frame_parser.init_start_codes (codec_type_parse);
}
else if(!strncmp(driver_context.kind, "OMX.qcom.video.decoder.avc",\
OMX_MAX_STRINGNAME_SIZE))
{
strncpy((char *)m_cRole, "video_decoder.avc",OMX_MAX_STRINGNAME_SIZE);
driver_context.decoder_format = VDEC_CODECTYPE_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);
}
else if(!strncmp(driver_context.kind, "OMX.qcom.video.decoder.vc1",\
OMX_MAX_STRINGNAME_SIZE))
{
strncpy((char *)m_cRole, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE);
driver_context.decoder_format = VDEC_CODECTYPE_VC1;
eCompressionFormat = OMX_VIDEO_CodingWMV;
codec_type_parse = CODEC_TYPE_VC1;
m_frame_parser.init_start_codes (codec_type_parse);
}
else
{
DEBUG_PRINT_ERROR("\nERROR:Unknown Component\n");
eRet = OMX_ErrorInvalidComponentName;
}
if (eRet == OMX_ErrorNone)
{
driver_context.output_format = VDEC_YUV_FORMAT_NV12;
if (is_fluid) {
FILE * pFile;
char disable_overlay = '0';
pFile = fopen
("/data/data/com.arcsoft.videowall/files/disableoverlay.txt", "rb" );
if (pFile == NULL) {
DEBUG_PRINT_HIGH(" fopen FAiLED for disableoverlay.txt\n");
} else {
int count = fread(&disable_overlay, 1, 1, pFile);
fclose(pFile);
}
if(disable_overlay == '1') {
DEBUG_PRINT_HIGH(" vdec : TILE format \n");
driver_context.output_format = VDEC_YUV_FORMAT_TILE_4x2;
} else {
DEBUG_PRINT_HIGH(" vdec : NV 12 format \n");
driver_context.output_format = VDEC_YUV_FORMAT_NV12;
}
}
/*Initialize Decoder with codec type and resolution*/
ioctl_msg.inputparam = &driver_context.decoder_format;
ioctl_msg.outputparam = NULL;
if ( (eRet == OMX_ErrorNone) &&
ioctl (driver_context.video_driver_fd,VDEC_IOCTL_SET_CODEC,
(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Set codec type failed");
eRet = OMX_ErrorInsufficientResources;
}
/*Set the output format*/
ioctl_msg.inputparam = &driver_context.output_format;
ioctl_msg.outputparam = NULL;
if ( (eRet == OMX_ErrorNone) &&
ioctl (driver_context.video_driver_fd,VDEC_IOCTL_SET_OUTPUT_FORMAT,
(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Set output format failed");
eRet = OMX_ErrorInsufficientResources;
}
#ifdef MAX_RES_720P
driver_context.video_resoultion.frame_height = 720;
driver_context.video_resoultion.frame_width = 1280;
driver_context.video_resoultion.stride = 1280;
driver_context.video_resoultion.scan_lines = 720;
#endif
#ifdef MAX_RES_1080P
driver_context.video_resoultion.frame_height = 1088;
driver_context.video_resoultion.frame_width = 1920;
driver_context.video_resoultion.stride = 1920;
driver_context.video_resoultion.scan_lines = 1088;
#endif
ioctl_msg.inputparam = &driver_context.video_resoultion;
ioctl_msg.outputparam = NULL;
if ( (eRet == OMX_ErrorNone) &&
ioctl (driver_context.video_driver_fd,VDEC_IOCTL_SET_PICRES,
(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Set Resolution failed");
eRet = OMX_ErrorInsufficientResources;
}
/*Get the Buffer requirements for input and output ports*/
driver_context.input_buffer.buffer_type = VDEC_BUFFER_TYPE_INPUT;
ioctl_msg.inputparam = NULL;
ioctl_msg.outputparam = &driver_context.input_buffer;
if ( (eRet == OMX_ErrorNone) &&
ioctl (driver_context.video_driver_fd,VDEC_IOCTL_GET_BUFFER_REQ,
(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Requesting for input buffer requirements failed");
eRet = OMX_ErrorInsufficientResources;
}
m_inp_buf_count = driver_context.input_buffer.actualcount;
buffer_size = driver_context.input_buffer.buffer_size;
alignment = driver_context.input_buffer.alignment;
m_inp_buf_size = ((buffer_size + alignment -1 ) & (~(alignment -1)));
m_inp_buf_count_min = driver_context.input_buffer.mincount;
/*Get the Buffer requirements for input and output ports*/
driver_context.input_buffer.buffer_type = VDEC_BUFFER_TYPE_INPUT;
ioctl_msg.inputparam = &driver_context.input_buffer;
ioctl_msg.outputparam = NULL;
m_inp_buf_count_min = m_inp_buf_count = driver_context.input_buffer.actualcount =
driver_context.input_buffer.mincount + 3;
if ( (eRet == OMX_ErrorNone) &&
ioctl (driver_context.video_driver_fd,VDEC_IOCTL_SET_BUFFER_REQ,
(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Set input buffer requirements failed");
eRet = OMX_ErrorInsufficientResources;
}
driver_context.output_buffer.buffer_type = VDEC_BUFFER_TYPE_OUTPUT;
ioctl_msg.inputparam = NULL;
ioctl_msg.outputparam = &driver_context.output_buffer;
if ((eRet == OMX_ErrorNone) &&
ioctl (driver_context.video_driver_fd,VDEC_IOCTL_GET_BUFFER_REQ,
(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Requesting for output buffer requirements failed");
eRet = OMX_ErrorInsufficientResources;
}
m_out_buf_count_recon = m_out_buf_count = driver_context.output_buffer.actualcount;
m_out_buf_count_min_recon = m_out_buf_count_min = driver_context.output_buffer.mincount;
alignment = driver_context.output_buffer.alignment;
buffer_size = driver_context.output_buffer.buffer_size;
m_out_buf_size_recon = m_out_buf_size =
((buffer_size + alignment - 1) & (~(alignment -1)));
#ifdef MAX_RES_720P
scan_lines = m_crop_dy = m_height = 720;
stride = m_crop_dx = m_width = 1280;
#endif
#ifdef MAX_RES_1080P
scan_lines = m_crop_dy = m_height = 1088;
stride = m_crop_dx = m_width = 1920;
#endif
m_port_height = m_height;
m_port_width = m_width;
m_state = OMX_StateLoaded;
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];
r = pthread_create(&msg_thread_id,0,message_thread,this);
if(r < 0)
{
DEBUG_PRINT_ERROR("\n component_init(): message_thread creation failed");
eRet = OMX_ErrorInsufficientResources;
}
else
{
r = pthread_create(&async_thread_id,0,async_message_thread,this);
if(r < 0)
{
DEBUG_PRINT_ERROR("\n component_init(): async_message_thread creation failed");
eRet = OMX_ErrorInsufficientResources;
}
}
}
}
if (eRet != OMX_ErrorNone)
{
DEBUG_PRINT_ERROR("\n Component Init Failed");
DEBUG_PRINT_HIGH("\n Calling VDEC_IOCTL_STOP_NEXT_MSG");
(void)ioctl(driver_context.video_driver_fd, VDEC_IOCTL_STOP_NEXT_MSG,
NULL);
DEBUG_PRINT_HIGH("\n Calling close() on Video Driver");
close (driver_context.video_driver_fd);
driver_context.video_driver_fd = -1;
}
else
{
DEBUG_PRINT_HIGH("\n omx_vdec::component_init() success");
}
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 */
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;
}
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;;
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)
{
BITMASK_SET(&m_flags,OMX_COMPONENT_EXECUTE_PENDING);
DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing\n");
post_event (NULL,VDEC_S_SUCCESS,OMX_COMPONENT_GENERATE_START_DONE);
bFlag = 0;
}
/* 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 (driver_context.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");
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_CMD_PAUSE,
NULL) < 0)
{
DEBUG_PRINT_ERROR("\n Error In Pause State");
post_event(OMX_EventError,OMX_ErrorHardware,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorHardware;
}
else
{
BITMASK_SET(&m_flags,OMX_COMPONENT_PAUSE_PENDING);
DEBUG_PRINT_LOW("send_command_proxy(): Pause-->Executing\n");
bFlag = 0;
}
}
/* 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");
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_CMD_RESUME,
NULL) < 0)
{
DEBUG_PRINT_ERROR("\n VDEC_IOCTL_CMD_RESUME failed");
post_event(OMX_EventError,OMX_ErrorHardware,\
OMX_COMPONENT_GENERATE_EVENT);
eRet = OMX_ErrorHardware;
}
else
{
BITMASK_SET(&m_flags,OMX_COMPONENT_EXECUTE_PENDING);
DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing\n");
post_event (NULL,VDEC_S_SUCCESS,\
OMX_COMPONENT_GENERATE_RESUME_DONE);
bFlag = 0;
}
}
/* 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: %d", param1);
if(0 == param1 || OMX_ALL == param1)
{
BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_FLUSH_PENDING);
}
if(1 == param1 || OMX_ALL == param1)
{
//generate output flush event only.
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: %d", 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: %d", 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);
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)
{
struct vdec_ioctl_msg ioctl_msg = {NULL,NULL};
enum vdec_bufferflush flush_dir = VDEC_FLUSH_TYPE_ALL;
bool bRet = false;
if(flushType == 0 || flushType == OMX_ALL)
{
input_flush_progress = true;
//flush input only
bRet = execute_input_flush(flushType);
}
if(flushType == 1 || flushType == OMX_ALL)
{
//flush output only
output_flush_progress = true;
bRet = execute_output_flush(flushType);
}
if(flushType == OMX_ALL)
{
/*Check if there are buffers with the Driver*/
DEBUG_PRINT_LOW("\n Flush ALL ioctl issued");
ioctl_msg.inputparam = &flush_dir;
ioctl_msg.outputparam = NULL;
if (ioctl(driver_context.video_driver_fd,VDEC_IOCTL_CMD_FLUSH,&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Flush ALL Failed ");
return 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(OMX_U32 flushType)
{
struct vdec_ioctl_msg ioctl_msg = {NULL,NULL};
enum vdec_bufferflush flush_dir = VDEC_FLUSH_TYPE_OUTPUT;
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);
if(ident == OMX_COMPONENT_GENERATE_FTB )
{
DEBUG_PRINT_LOW("\n Inside Flush Buffer OMX_COMPONENT_GENERATE_FTB");
pending_output_buffers++;
fill_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p2);
}
else if (ident == OMX_COMPONENT_GENERATE_FBD)
{
fill_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1);
}
}
pthread_mutex_unlock(&m_lock);
if(gate_output_buffers)
{
DEBUG_PRINT_LOW("\n Output Buffers gated Check flush response");
if(BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_FLUSH_PENDING))
{
DEBUG_PRINT_LOW("\n Notify Output Flush done");
BITMASK_CLEAR (&m_flags,OMX_COMPONENT_OUTPUT_FLUSH_PENDING);
m_cb.EventHandler(&m_cmp,m_app_data,OMX_EventCmdComplete,OMX_CommandFlush,
OMX_CORE_OUTPUT_PORT_INDEX,NULL );
}
output_flush_progress = false;
return bRet;
}
DEBUG_PRINT_LOW("\n output buffers count = %d",pending_output_buffers);
if(flushType == 1)
{
/*Check if there are buffers with the Driver*/
DEBUG_PRINT_LOW("\n ioctl command flush for output");
ioctl_msg.inputparam = &flush_dir;
ioctl_msg.outputparam = NULL;
if (ioctl(driver_context.video_driver_fd,VDEC_IOCTL_CMD_FLUSH,&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n output flush failed");
return false;
}
}
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(OMX_U32 flushType)
{
struct vdec_ioctl_msg ioctl_msg = {NULL,NULL};
enum vdec_bufferflush flush_dir = VDEC_FLUSH_TYPE_INPUT;
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++;
empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p2);
}
else if (ident == OMX_COMPONENT_GENERATE_EBD)
{
empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1);
}
}
/*Check if Heap Buffers are to be flushed*/
if (arbitrary_bytes)
{
DEBUG_PRINT_LOW("\n Reset all the variables before flusing");
h264_scratch.nFilledLen = 0;
nal_count = 0;
look_ahead_nal = false;
frame_count = 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,NULL,NULL);
pdest_frame = NULL;
}
m_frame_parser.flush();
}
pthread_mutex_unlock(&m_lock);
DEBUG_PRINT_LOW("\n Value of pending input buffers %d \n",pending_input_buffers);
if(flushType == 0)
{
/*Check if there are buffers with the Driver*/
DEBUG_PRINT_LOW("\n Input Flush ioctl issued");
ioctl_msg.inputparam = &flush_dir;
ioctl_msg.outputparam = NULL;
if (ioctl(driver_context.video_driver_fd,VDEC_IOCTL_CMD_FLUSH,&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Input Flush Failed ");
return false;
}
}
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 == OMX_COMPONENT_GENERATE_FTB || \
(id == OMX_COMPONENT_GENERATE_FBD)||
(id == OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH))
{
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)||
(id == OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH))
{
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;
}
/* ======================================================================
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;
unsigned int height=0,width = 0;
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(paramIndex)
{
case OMX_IndexParamPortDefinition:
{
OMX_PARAM_PORTDEFINITIONTYPE *portDefn;
portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData;
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamPortDefinition\n");
portDefn->nVersion.nVersion = OMX_SPEC_VERSION;
portDefn->nSize = sizeof(portDefn);
portDefn->eDomain = OMX_PortDomainVideo;
portDefn->format.video.nFrameHeight = m_crop_dy;
portDefn->format.video.nFrameWidth = m_crop_dx;
portDefn->format.video.nStride = m_width;
portDefn->format.video.nSliceHeight = m_height;
portDefn->format.video.xFramerate= 25;
if (0 == portDefn->nPortIndex)
{
portDefn->eDir = OMX_DirInput;
/*Actual count is based on input buffer count*/
portDefn->nBufferCountActual = m_inp_buf_count;
/*Set the Min count*/
portDefn->nBufferCountMin = m_inp_buf_count_min;
portDefn->nBufferSize = m_inp_buf_size;
portDefn->format.video.eColorFormat = OMX_COLOR_FormatUnused;
portDefn->format.video.eCompressionFormat = eCompressionFormat;
portDefn->bEnabled = m_inp_bEnabled;
portDefn->bPopulated = m_inp_bPopulated;
}
else if (1 == portDefn->nPortIndex)
{
m_out_buf_count = m_out_buf_count_recon;
m_out_buf_count_min = m_out_buf_count_min_recon;
m_out_buf_size = m_out_buf_size_recon;
portDefn->eDir = OMX_DirOutput;
portDefn->nBufferCountActual = m_out_buf_count;
portDefn->nBufferCountMin = m_out_buf_count_min;
portDefn->nBufferSize = m_out_buf_size;
portDefn->bEnabled = m_out_bEnabled;
portDefn->bPopulated = m_out_bPopulated;
height = driver_context.video_resoultion.frame_height;
width = driver_context.video_resoultion.frame_width;
portDefn->format.video.nFrameHeight = height;
portDefn->format.video.nFrameWidth = width;
portDefn->format.video.nStride = stride;
portDefn->format.video.nSliceHeight = scan_lines;
DEBUG_PRINT_LOW("\n Get Param Slice Height %d Slice Width %d",
scan_lines,stride);
//TODO: Need to add color format
portDefn->format.video.eColorFormat = m_color_format;
portDefn->format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
DEBUG_PRINT_LOW("\n Output Actual %d Output Min %d",
portDefn->nBufferCountActual,portDefn->nBufferCountMin);
}
else
{
portDefn->eDir = OMX_DirMax;
DEBUG_PRINT_LOW(" get_parameter: Bad Port idx %d",
(int)portDefn->nPortIndex);
eRet = OMX_ErrorBadPortIndex;
}
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);
if (0 == portFmt->nPortIndex)
{
if (0 == portFmt->nIndex)
{
portFmt->eColorFormat = OMX_COLOR_FormatUnused;
portFmt->eCompressionFormat = eCompressionFormat;
}
else
{
DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamVideoPortFormat:"\
" NoMore compression formats\n");
eRet = OMX_ErrorNoMore;
}
}
else if (1 == portFmt->nPortIndex)
{
if (0 == portFmt->nIndex)
{
if (driver_context.output_format == VDEC_YUV_FORMAT_NV12)
portFmt->eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
else
portFmt->eColorFormat = (OMX_COLOR_FORMATTYPE)0x7F000000;
portFmt->eCompressionFormat = OMX_VIDEO_CodingUnused;
}
else
{
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoPortFormat:"\
" NoMore Color formats\n");
eRet = OMX_ErrorNoMore;
}
}
else
{
DEBUG_PRINT_ERROR("get_parameter: Bad port index %d\n",
(int)portFmt->nPortIndex);
eRet = OMX_ErrorBadPortIndex;
}
break;
}
/*Component should support this port definition*/
case OMX_IndexParamAudioInit:
{
OMX_PORT_PARAM_TYPE *audioPortParamType =
(OMX_PORT_PARAM_TYPE *) paramData;
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamAudioInit\n");
audioPortParamType->nVersion.nVersion = OMX_SPEC_VERSION;
audioPortParamType->nSize = sizeof(audioPortParamType);
audioPortParamType->nPorts = 0;
audioPortParamType->nStartPortNumber = 0;
break;
}
/*Component should support this port definition*/
case OMX_IndexParamImageInit:
{
OMX_PORT_PARAM_TYPE *imagePortParamType =
(OMX_PORT_PARAM_TYPE *) paramData;
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamImageInit\n");
imagePortParamType->nVersion.nVersion = OMX_SPEC_VERSION;
imagePortParamType->nSize = sizeof(imagePortParamType);
imagePortParamType->nPorts = 0;
imagePortParamType->nStartPortNumber = 0;
break;
}
/*Component should support this port definition*/
case OMX_IndexParamOtherInit:
{
DEBUG_PRINT_ERROR("get_parameter: OMX_IndexParamOtherInit %08x\n",
paramIndex);
eRet =OMX_ErrorUnsupportedIndex;
break;
}
case OMX_IndexParamStandardComponentRole:
{
OMX_PARAM_COMPONENTROLETYPE *comp_role;
comp_role = (OMX_PARAM_COMPONENTROLETYPE *) paramData;
comp_role->nVersion.nVersion = OMX_SPEC_VERSION;
comp_role->nSize = sizeof(*comp_role);
DEBUG_PRINT_LOW("Getparameter: OMX_IndexParamStandardComponentRole %d\n",
paramIndex);
strncpy((char*)comp_role->cRole,(const char*)m_cRole,
OMX_MAX_STRINGNAME_SIZE);
break;
}
/* Added for parameter test */
case OMX_IndexParamPriorityMgmt:
{
OMX_PRIORITYMGMTTYPE *priorityMgmType =
(OMX_PRIORITYMGMTTYPE *) paramData;
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamPriorityMgmt\n");
priorityMgmType->nVersion.nVersion = OMX_SPEC_VERSION;
priorityMgmType->nSize = sizeof(priorityMgmType);
break;
}
/* Added for parameter test */
case OMX_IndexParamCompBufferSupplier:
{
OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType =
(OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData;
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamCompBufferSupplier\n");
bufferSupplierType->nSize = sizeof(bufferSupplierType);
bufferSupplierType->nVersion.nVersion = OMX_SPEC_VERSION;
if(0 == bufferSupplierType->nPortIndex)
bufferSupplierType->nPortIndex = OMX_BufferSupplyUnspecified;
else if (1 == bufferSupplierType->nPortIndex)
bufferSupplierType->nPortIndex = OMX_BufferSupplyUnspecified;
else
eRet = OMX_ErrorBadPortIndex;
break;
}
case OMX_IndexParamVideoAvc:
{
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoAvc %08x\n",
paramIndex);
break;
}
case OMX_IndexParamVideoH263:
{
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoH263 %08x\n",
paramIndex);
break;
}
case OMX_IndexParamVideoMpeg4:
{
DEBUG_PRINT_LOW("get_parameter: OMX_IndexParamVideoMpeg4 %08x\n",
paramIndex);
break;
}
default:
{
DEBUG_PRINT_ERROR("get_parameter: unknown param %08x\n", paramIndex);
eRet =OMX_ErrorUnsupportedIndex;
}
}
DEBUG_PRINT_LOW("\n get_parameter returning Height %d , Width %d \n",
m_height, m_width);
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::Setparameter
DESCRIPTION
OMX Set Parameter method implementation.
PARAMETERS
<TBD>.
RETURN VALUE
OMX Error None if successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::set_parameter(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_INDEXTYPE paramIndex,
OMX_IN OMX_PTR paramData)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
struct vdec_ioctl_msg ioctl_msg = {NULL,NULL};
unsigned int alignment = 0,buffer_size = 0;
int i;
if(m_state == OMX_StateInvalid)
{
DEBUG_PRINT_ERROR("Set Param in Invalid State\n");
return OMX_ErrorInvalidState;
}
if(paramData == NULL)
{
DEBUG_PRINT_ERROR("Get Param in Invalid paramData \n");
return OMX_ErrorBadParameter;
}
switch(paramIndex)
{
case OMX_IndexParamPortDefinition:
{
OMX_PARAM_PORTDEFINITIONTYPE *portDefn;
portDefn = (OMX_PARAM_PORTDEFINITIONTYPE *) paramData;
/*set_parameter can be called in loaded state
or disabled port */
/* When the component is in Loaded state and IDLE Pending*/
if(((m_state == OMX_StateLoaded)&&
!BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
/* Or while the I/P or the O/P port or disabled */
||((OMX_DirInput == portDefn->eDir && m_inp_bEnabled == OMX_FALSE)||
(OMX_DirOutput == portDefn->eDir && m_out_bEnabled == OMX_FALSE)))
{
DEBUG_PRINT_LOW("Set Parameter called in valid state");
}
else
{
DEBUG_PRINT_ERROR("Set Parameter called in Invalid State\n");
return OMX_ErrorIncorrectStateOperation;
}
DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPortDefinition H= %d, W = %d\n",
(int)portDefn->format.video.nFrameHeight,
(int)portDefn->format.video.nFrameWidth);
eRet = omx_vdec_validate_port_param(portDefn->format.video.nFrameHeight,
portDefn->format.video.nFrameWidth);
if(eRet != OMX_ErrorNone)
{
return OMX_ErrorUnsupportedSetting;
}
if(OMX_DirOutput == portDefn->eDir)
{
if ( portDefn->nBufferCountActual < m_out_buf_count_min ||
portDefn->nBufferSize != m_out_buf_size
)
{
return OMX_ErrorBadParameter;
}
driver_context.output_buffer.buffer_type = VDEC_BUFFER_TYPE_OUTPUT;
ioctl_msg.inputparam = NULL;
ioctl_msg.outputparam = &driver_context.output_buffer;
if (ioctl (driver_context.video_driver_fd,
VDEC_IOCTL_GET_BUFFER_REQ,(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Request output buffer requirements failed");
return OMX_ErrorUnsupportedSetting;
}
driver_context.output_buffer.buffer_type = VDEC_BUFFER_TYPE_OUTPUT;
driver_context.output_buffer.actualcount =
portDefn->nBufferCountActual;
ioctl_msg.inputparam = &driver_context.output_buffer;
ioctl_msg.outputparam = NULL;
if (ioctl (driver_context.video_driver_fd,
VDEC_IOCTL_SET_BUFFER_REQ,(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Request output buffer requirements failed");
return OMX_ErrorUnsupportedSetting;
}
m_out_buf_count = portDefn->nBufferCountActual;
m_out_buf_count_recon = m_out_buf_count;
DEBUG_PRINT_LOW("set_parameter:OMX_IndexParamPortDefinition output port\n");
}
else if(OMX_DirInput == portDefn->eDir)
{
if(m_height != portDefn->format.video.nFrameHeight ||
m_width != portDefn->format.video.nFrameWidth)
{
DEBUG_PRINT_LOW("set_parameter ip port: stride %d\n",
(int)portDefn->format.video.nStride);
// set the HxW only if non-zero
if((portDefn->format.video.nFrameHeight != 0x0)
&& (portDefn->format.video.nFrameWidth != 0x0))
{
m_crop_x = m_crop_y = 0;
m_crop_dy = m_port_height = m_height =
portDefn->format.video.nFrameHeight;
m_crop_dx = m_port_width = m_width =
portDefn->format.video.nFrameWidth;
scan_lines = portDefn->format.video.nSliceHeight;
stride = portDefn->format.video.nStride;
DEBUG_PRINT_LOW("\n SetParam with new H %d and W %d\n",
m_height, m_width );
driver_context.video_resoultion.frame_height = m_height;
driver_context.video_resoultion.frame_width = m_width;
driver_context.video_resoultion.stride = stride;
driver_context.video_resoultion.scan_lines = scan_lines;
ioctl_msg.inputparam = &driver_context.video_resoultion;
ioctl_msg.outputparam = NULL;
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_SET_PICRES,
(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Set Resolution failed");
return OMX_ErrorUnsupportedSetting;
}
driver_context.output_buffer.buffer_type =
VDEC_BUFFER_TYPE_OUTPUT;
ioctl_msg.inputparam = NULL;
ioctl_msg.outputparam = &driver_context.output_buffer;
if (ioctl (driver_context.video_driver_fd,
VDEC_IOCTL_GET_BUFFER_REQ,(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Request output buffer requirements failed");
return OMX_ErrorUnsupportedSetting;
}
m_out_buf_count_recon = m_out_buf_count = driver_context.output_buffer.actualcount;
m_out_buf_count_min_recon = m_out_buf_count_min = driver_context.output_buffer.mincount;
alignment = driver_context.output_buffer.alignment;
buffer_size = driver_context.output_buffer.buffer_size;
m_out_buf_size_recon = m_out_buf_size =
((buffer_size + alignment - 1) & (~(alignment - 1)));
}
}
else
{
/*
If actual buffer count is greater than the Min buffer
count,change the actual count.
m_inp_buf_count is initialized to OMX_CORE_NUM_INPUT_BUFFERS
in the constructor
*/
if ( portDefn->nBufferCountActual < m_inp_buf_count_min ||
portDefn->nBufferSize != m_inp_buf_size
)
{
return OMX_ErrorBadParameter;
}
/*Get the Buffer requirements for input and output ports*/
driver_context.input_buffer.buffer_type = VDEC_BUFFER_TYPE_INPUT;
ioctl_msg.inputparam = NULL;
ioctl_msg.outputparam = &driver_context.input_buffer;
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_GET_BUFFER_REQ,
(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Request input buffer requirements failed");
return OMX_ErrorUnsupportedSetting;
}
driver_context.input_buffer.buffer_type = VDEC_BUFFER_TYPE_INPUT;
driver_context.input_buffer.actualcount =
portDefn->nBufferCountActual;
ioctl_msg.inputparam = &driver_context.input_buffer;
ioctl_msg.outputparam = NULL;
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_SET_BUFFER_REQ,
(void*)&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Request input buffer requirements failed");
return OMX_ErrorUnsupportedSetting;
}
m_inp_buf_count = portDefn->nBufferCountActual;
DEBUG_PRINT_LOW("\n set_parameter: Image Dimensions same \n");
}
}
else if (portDefn->eDir == OMX_DirMax)
{
DEBUG_PRINT_ERROR(" Set_parameter: Bad Port idx %d",
(int)portDefn->nPortIndex);
eRet = OMX_ErrorBadPortIndex;
}
}
break;
case OMX_IndexParamVideoPortFormat:
{
OMX_VIDEO_PARAM_PORTFORMATTYPE *portFmt =
(OMX_VIDEO_PARAM_PORTFORMATTYPE *)paramData;
DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoPortFormat %d\n",
portFmt->eColorFormat);
DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoPortFormat %d\n",
portFmt->eColorFormat);
if(1 == portFmt->nPortIndex)
{
m_color_format = portFmt->eColorFormat;
}
}
break;
case OMX_QcomIndexPortDefn:
{
OMX_QCOM_PARAM_PORTDEFINITIONTYPE *portFmt =
(OMX_QCOM_PARAM_PORTDEFINITIONTYPE *) paramData;
DEBUG_PRINT_LOW("set_parameter: OMX_IndexQcomParamPortDefinitionType %d\n",
portFmt->nFramePackingFormat);
/* Input port */
if (portFmt->nPortIndex == 0)
{
if (portFmt->nFramePackingFormat == OMX_QCOM_FramePacking_Arbitrary)
{
arbitrary_bytes = true;
}
else if (portFmt->nFramePackingFormat ==
OMX_QCOM_FramePacking_OnlyOneCompleteFrame)
{
arbitrary_bytes = false;
}
else
{
DEBUG_PRINT_ERROR("Setparameter: unknown FramePacking format %d\n",
portFmt->nFramePackingFormat);
eRet = OMX_ErrorUnsupportedSetting;
}
}
}
break;
case OMX_IndexParamStandardComponentRole:
{
OMX_PARAM_COMPONENTROLETYPE *comp_role;
comp_role = (OMX_PARAM_COMPONENTROLETYPE *) paramData;
DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamStandardComponentRole %s\n",
comp_role->cRole);
if((m_state == OMX_StateLoaded)&&
!BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
{
DEBUG_PRINT_LOW("Set Parameter called in valid state");
}
else
{
DEBUG_PRINT_ERROR("Set Parameter called in Invalid State\n");
return OMX_ErrorIncorrectStateOperation;
}
if(!strncmp(driver_context.kind, "OMX.qcom.video.decoder.avc",OMX_MAX_STRINGNAME_SIZE))
{
if(!strncmp((char*)comp_role->cRole,"video_decoder.avc",OMX_MAX_STRINGNAME_SIZE))
{
strncpy((char*)m_cRole,"video_decoder.avc",OMX_MAX_STRINGNAME_SIZE);
}
else
{
DEBUG_PRINT_ERROR("Setparameter: unknown Index %s\n", comp_role->cRole);
eRet =OMX_ErrorUnsupportedSetting;
}
}
else if(!strncmp(driver_context.kind, "OMX.qcom.video.decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE))
{
if(!strncmp((const char*)comp_role->cRole,"video_decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE))
{
strncpy((char*)m_cRole,"video_decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE);
}
else
{
DEBUG_PRINT_ERROR("Setparameter: unknown Index %s\n", comp_role->cRole);
eRet = OMX_ErrorUnsupportedSetting;
}
}
else if(!strncmp(driver_context.kind, "OMX.qcom.video.decoder.h263",OMX_MAX_STRINGNAME_SIZE))
{
if(!strncmp((const char*)comp_role->cRole,"video_decoder.h263",OMX_MAX_STRINGNAME_SIZE))
{
strncpy((char*)m_cRole,"video_decoder.h263",OMX_MAX_STRINGNAME_SIZE);
}
else
{
DEBUG_PRINT_ERROR("Setparameter: unknown Index %s\n", comp_role->cRole);
eRet =OMX_ErrorUnsupportedSetting;
}
}
else if(!strncmp(driver_context.kind, "OMX.qcom.video.decoder.vc1",OMX_MAX_STRINGNAME_SIZE))
{
if(!strncmp((const char*)comp_role->cRole,"video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE))
{
strncpy((char*)m_cRole,"video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE);
}
else
{
DEBUG_PRINT_ERROR("Setparameter: unknown Index %s\n", comp_role->cRole);
eRet =OMX_ErrorUnsupportedSetting;
}
}
else
{
DEBUG_PRINT_ERROR("Setparameter: unknown param %s\n", driver_context.kind);
eRet = OMX_ErrorInvalidComponentName;
}
break;
}
case OMX_IndexParamPriorityMgmt:
{
if(m_state != OMX_StateLoaded)
{
DEBUG_PRINT_ERROR("Set Parameter called in Invalid State\n");
return OMX_ErrorIncorrectStateOperation;
}
OMX_PRIORITYMGMTTYPE *priorityMgmtype = (OMX_PRIORITYMGMTTYPE*) paramData;
DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamPriorityMgmt %d\n",
priorityMgmtype->nGroupID);
DEBUG_PRINT_LOW("set_parameter: priorityMgmtype %d\n",
priorityMgmtype->nGroupPriority);
m_priority_mgm.nGroupID = priorityMgmtype->nGroupID;
m_priority_mgm.nGroupPriority = priorityMgmtype->nGroupPriority;
break;
}
case OMX_IndexParamCompBufferSupplier:
{
OMX_PARAM_BUFFERSUPPLIERTYPE *bufferSupplierType = (OMX_PARAM_BUFFERSUPPLIERTYPE*) paramData;
DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamCompBufferSupplier %d\n",
bufferSupplierType->eBufferSupplier);
if(bufferSupplierType->nPortIndex == 0 || bufferSupplierType->nPortIndex ==1)
m_buffer_supplier.eBufferSupplier = bufferSupplierType->eBufferSupplier;
else
eRet = OMX_ErrorBadPortIndex;
break;
}
case OMX_IndexParamVideoAvc:
{
DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoAvc %d\n",
paramIndex);
break;
}
case OMX_IndexParamVideoH263:
{
DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoH263 %d\n",
paramIndex);
break;
}
case OMX_IndexParamVideoMpeg4:
{
DEBUG_PRINT_LOW("set_parameter: OMX_IndexParamVideoMpeg4 %d\n",
paramIndex);
break;
}
default:
{
DEBUG_PRINT_ERROR("Setparameter: unknown param %d\n", paramIndex);
eRet = OMX_ErrorUnsupportedIndex;
}
}
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::GetConfig
DESCRIPTION
OMX Get Config Method implementation.
PARAMETERS
<TBD>.
RETURN VALUE
OMX Error None if successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::get_config(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_INDEXTYPE configIndex,
OMX_INOUT OMX_PTR configData)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
if (m_state == OMX_StateInvalid)
{
DEBUG_PRINT_ERROR("Get Config in Invalid State\n");
return OMX_ErrorInvalidState;
}
switch (configIndex)
{
case OMX_QcomIndexConfigInterlaced:
{
OMX_QCOM_CONFIG_INTERLACETYPE *configFmt =
(OMX_QCOM_CONFIG_INTERLACETYPE *) configData;
if (configFmt->nPortIndex == 1)
{
if (configFmt->nIndex == 0)
{
configFmt->eInterlaceType = OMX_QCOM_InterlaceFrameProgressive;
}
else if (configFmt->nIndex == 1)
{
configFmt->eInterlaceType =
OMX_QCOM_InterlaceInterleaveFrameTopFieldFirst;
}
else if (configFmt->nIndex == 2)
{
configFmt->eInterlaceType =
OMX_QCOM_InterlaceInterleaveFrameBottomFieldFirst;
}
else
{
DEBUG_PRINT_ERROR("get_config: OMX_QcomIndexConfigInterlaced:"
" NoMore Interlaced formats\n");
eRet = OMX_ErrorNoMore;
}
}
else
{
DEBUG_PRINT_ERROR("get_config: Bad port index %d queried on only o/p port\n",
(int)configFmt->nPortIndex);
eRet = OMX_ErrorBadPortIndex;
}
break;
}
case OMX_QcomIndexQueryNumberOfVideoDecInstance:
{
struct vdec_ioctl_msg ioctl_msg = {NULL,NULL};
QOMX_VIDEO_QUERY_DECODER_INSTANCES *decoderinstances =
(QOMX_VIDEO_QUERY_DECODER_INSTANCES*)configData;
ioctl_msg.outputparam = (void*)&decoderinstances->nNumOfInstances;
(void)(ioctl(driver_context.video_driver_fd,
VDEC_IOCTL_GET_NUMBER_INSTANCES,&ioctl_msg));
break;
}
default:
{
DEBUG_PRINT_ERROR("get_config: unknown param %d\n",configIndex);
eRet = OMX_ErrorBadParameter;
}
}
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::SetConfig
DESCRIPTION
OMX Set Config method implementation
PARAMETERS
<TBD>.
RETURN VALUE
OMX Error None if successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::set_config(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_INDEXTYPE configIndex,
OMX_IN OMX_PTR configData)
{
if(m_state == OMX_StateInvalid)
{
DEBUG_PRINT_ERROR("Get Config in Invalid State\n");
return OMX_ErrorInvalidState;
}
OMX_ERRORTYPE ret = OMX_ErrorNone;
OMX_VIDEO_CONFIG_NALSIZE *pNal;
DEBUG_PRINT_LOW("\n Set Config Called");
if (m_state == OMX_StateExecuting)
{
DEBUG_PRINT_ERROR("set_config:Ignore in Exe state\n");
return ret;
}
if (configIndex == OMX_IndexVendorVideoExtraData)
{
OMX_VENDOR_EXTRADATATYPE *config = (OMX_VENDOR_EXTRADATATYPE *) configData;
DEBUG_PRINT_LOW("\n Index OMX_IndexVendorVideoExtraData called");
if (!strcmp(driver_context.kind, "OMX.qcom.video.decoder.avc"))
{
DEBUG_PRINT_LOW("\n Index OMX_IndexVendorVideoExtraData AVC");
OMX_U32 extra_size;
// Parsing done here for the AVC atom is definitely not generic
// Currently this piece of code is working, but certainly
// not tested with all .mp4 files.
// Incase of failure, we might need to revisit this
// for a generic piece of code.
// Retrieve size of NAL length field
// byte #4 contains the size of NAL lenght field
nal_length = (config->pData[4] & 0x03) + 1;
extra_size = 0;
if (nal_length > 2)
{
/* Presently we assume that only one SPS and one PPS in AvC1 Atom */
extra_size = (nal_length - 2) * 2;
}
// SPS starts from byte #6
OMX_U8 *pSrcBuf = (OMX_U8 *) (&config->pData[6]);
OMX_U8 *pDestBuf;
m_vendor_config.nPortIndex = config->nPortIndex;
// minus 6 --> SPS starts from byte #6
// minus 1 --> picture param set byte to be ignored from avcatom
m_vendor_config.nDataSize = config->nDataSize - 6 - 1 + extra_size;
m_vendor_config.pData = (OMX_U8 *) malloc(m_vendor_config.nDataSize);
OMX_U32 len;
OMX_U8 index = 0;
// case where SPS+PPS is sent as part of set_config
pDestBuf = m_vendor_config.pData;
DEBUG_PRINT_LOW("Rxd SPS+PPS nPortIndex[%d] len[%d] data[0x%x]\n",
m_vendor_config.nPortIndex,
m_vendor_config.nDataSize,
m_vendor_config.pData);
while (index < 2)
{
uint8 *psize;
len = *pSrcBuf;
len = len << 8;
len |= *(pSrcBuf + 1);
psize = (uint8 *) & len;
memcpy(pDestBuf + nal_length, pSrcBuf + 2,len);
for (int i = 0; i < nal_length; i++)
{
pDestBuf[i] = psize[nal_length - 1 - i];
}
//memcpy(pDestBuf,pSrcBuf,(len+2));
pDestBuf += len + nal_length;
pSrcBuf += len + 2;
index++;
pSrcBuf++; // skip picture param set
len = 0;
}
}
else if (!strcmp(driver_context.kind, "OMX.qcom.video.decoder.mpeg4"))
{
m_vendor_config.nPortIndex = config->nPortIndex;
m_vendor_config.nDataSize = config->nDataSize;
m_vendor_config.pData = (OMX_U8 *) malloc((config->nDataSize));
memcpy(m_vendor_config.pData, config->pData,config->nDataSize);
}
else if (!strcmp(driver_context.kind, "OMX.qcom.video.decoder.vc1"))
{
if(m_vendor_config.pData)
{
free(m_vendor_config.pData);
m_vendor_config.pData = NULL;
m_vendor_config.nDataSize = 0;
}
if (((*((OMX_U32 *) config->pData)) &
VC1_SP_MP_START_CODE_MASK) ==
VC1_SP_MP_START_CODE)
{
DEBUG_PRINT_LOW("set_config - VC1 simple/main profile\n");
m_vendor_config.nPortIndex = config->nPortIndex;
m_vendor_config.nDataSize = config->nDataSize;
m_vendor_config.pData =
(OMX_U8 *) malloc(config->nDataSize);
memcpy(m_vendor_config.pData, config->pData,
config->nDataSize);
m_vc1_profile = VC1_SP_MP_RCV;
}
else if (*((OMX_U32 *) config->pData) == VC1_AP_SEQ_START_CODE)
{
DEBUG_PRINT_LOW("set_config - VC1 Advance profile\n");
m_vendor_config.nPortIndex = config->nPortIndex;
m_vendor_config.nDataSize = config->nDataSize;
m_vendor_config.pData =
(OMX_U8 *) malloc((config->nDataSize));
memcpy(m_vendor_config.pData, config->pData,
config->nDataSize);
m_vc1_profile = VC1_AP;
}
else if ((config->nDataSize == VC1_STRUCT_C_LEN))
{
DEBUG_PRINT_LOW("set_config - VC1 Simple/Main profile struct C only\n");
m_vendor_config.nPortIndex = config->nPortIndex;
m_vendor_config.nDataSize = config->nDataSize;
m_vendor_config.pData = (OMX_U8*)malloc(config->nDataSize);
memcpy(m_vendor_config.pData,config->pData,config->nDataSize);
m_vc1_profile = VC1_SP_MP_RCV;
}
else
{
DEBUG_PRINT_LOW("set_config - Error: Unknown VC1 profile\n");
}
}
return ret;
}
else if (configIndex == OMX_IndexConfigVideoNalSize)
{
pNal = reinterpret_cast < OMX_VIDEO_CONFIG_NALSIZE * >(configData);
nal_length = pNal->nNaluBytes;
m_frame_parser.init_nal_length(nal_length);
DEBUG_PRINT_LOW("\n Nal Length option called with Size %d",nal_length);
return ret;
}
return OMX_ErrorNotImplemented;
}
/* ======================================================================
FUNCTION
omx_vdec::GetExtensionIndex
DESCRIPTION
OMX GetExtensionIndex method implementaion. <TBD>
PARAMETERS
<TBD>.
RETURN VALUE
OMX Error None if everything successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::get_extension_index(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_STRING paramName,
OMX_OUT OMX_INDEXTYPE* indexType)
{
DEBUG_PRINT_ERROR("get_extension_index: Error, Not implemented\n");
if(m_state == OMX_StateInvalid)
{
DEBUG_PRINT_ERROR("Get Extension Index in Invalid State\n");
return OMX_ErrorInvalidState;
}
return OMX_ErrorNotImplemented;
}
/* ======================================================================
FUNCTION
omx_vdec::GetState
DESCRIPTION
Returns the state information back to the caller.<TBD>
PARAMETERS
<TBD>.
RETURN VALUE
Error None if everything is successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::get_state(OMX_IN OMX_HANDLETYPE hComp,
OMX_OUT OMX_STATETYPE* state)
{
*state = m_state;
DEBUG_PRINT_LOW("get_state: Returning the state %d\n",*state);
return OMX_ErrorNone;
}
/* ======================================================================
FUNCTION
omx_vdec::ComponentTunnelRequest
DESCRIPTION
OMX Component Tunnel Request method implementation. <TBD>
PARAMETERS
None.
RETURN VALUE
OMX Error None if everything successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::component_tunnel_request(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_U32 port,
OMX_IN OMX_HANDLETYPE peerComponent,
OMX_IN OMX_U32 peerPort,
OMX_INOUT OMX_TUNNELSETUPTYPE* tunnelSetup)
{
DEBUG_PRINT_ERROR("Error: component_tunnel_request Not Implemented\n");
return OMX_ErrorNotImplemented;
}
/* ======================================================================
FUNCTION
omx_vdec::UseInputBuffer
DESCRIPTION
Helper function for Use buffer in the input pin
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
OMX_ERRORTYPE omx_vdec::use_input_buffer(
OMX_IN OMX_HANDLETYPE hComp,
OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
OMX_IN OMX_U32 port,
OMX_IN OMX_PTR appData,
OMX_IN OMX_U32 bytes,
OMX_IN OMX_U8* buffer)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
struct vdec_setbuffer_cmd setbuffers;
OMX_BUFFERHEADERTYPE *input = NULL;
struct vdec_ioctl_msg ioctl_msg = {NULL,NULL};
unsigned i = 0;
unsigned char *buf_addr = NULL;
int pmem_fd = -1;
if(bytes != m_inp_buf_size)
{
return OMX_ErrorBadParameter;
}
if(!m_inp_mem_ptr)
{
DEBUG_PRINT_HIGH("\n Use i/p buffer case - Header List allocation");
input_use_buffer = true;
m_inp_mem_ptr = (OMX_BUFFERHEADERTYPE*) \
calloc( (sizeof(OMX_BUFFERHEADERTYPE)), m_inp_buf_count);
if (m_inp_mem_ptr == NULL)
{
return OMX_ErrorInsufficientResources;
}
driver_context.ptr_inputbuffer = (struct vdec_bufferpayload *) \
calloc ((sizeof (struct vdec_bufferpayload)),m_inp_buf_count);
if (driver_context.ptr_inputbuffer == NULL)
{
return OMX_ErrorInsufficientResources;
}
for (i=0; i < m_inp_buf_count; i++)
{
driver_context.ptr_inputbuffer [i].pmem_fd = -1;
}
}
for(i=0; i< m_inp_buf_count; i++)
{
if(BITMASK_ABSENT(&m_inp_bm_count,i))
{
break;
}
}
if(i < m_inp_buf_count)
{
pmem_fd = open ("/dev/pmem_adsp",O_RDWR);
if (pmem_fd < 0)
{
return OMX_ErrorInsufficientResources;
}
if(pmem_fd == 0)
{
pmem_fd = open ("/dev/pmem_adsp",O_RDWR);
if (pmem_fd < 0)
{
return OMX_ErrorInsufficientResources;
}
}
if(!align_pmem_buffers(pmem_fd, m_inp_buf_size,
driver_context.input_buffer.alignment))
{
DEBUG_PRINT_ERROR("\n align_pmem_buffers() failed");
close(pmem_fd);
return OMX_ErrorInsufficientResources;
}
buf_addr = (unsigned char *)mmap(NULL,m_inp_buf_size,PROT_READ|PROT_WRITE,
MAP_SHARED,pmem_fd,0);
if (buf_addr == MAP_FAILED)
{
return OMX_ErrorInsufficientResources;
}
driver_context.ptr_inputbuffer [i].bufferaddr = buf_addr;
driver_context.ptr_inputbuffer [i].pmem_fd = pmem_fd;
driver_context.ptr_inputbuffer [i].mmaped_size = m_inp_buf_size;
driver_context.ptr_inputbuffer [i].offset = 0;
setbuffers.buffer_type = VDEC_BUFFER_TYPE_INPUT;
memcpy (&setbuffers.buffer,&driver_context.ptr_inputbuffer [i],
sizeof (vdec_bufferpayload));
ioctl_msg.inputparam = &setbuffers;
ioctl_msg.outputparam = NULL;
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_SET_BUFFER,
&ioctl_msg) < 0)
{
return OMX_ErrorInsufficientResources;
}
*bufferHdr = (m_inp_mem_ptr + i);
input = *bufferHdr;
BITMASK_SET(&m_inp_bm_count,i);
input->pBuffer = (OMX_U8 *)buffer;
input->nSize = sizeof(OMX_BUFFERHEADERTYPE);
input->nVersion.nVersion = OMX_SPEC_VERSION;
input->nAllocLen = m_inp_buf_size;
input->pAppPrivate = appData;
input->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX;
input->pInputPortPrivate = (void *)&driver_context.ptr_inputbuffer [i];
}
else
{
eRet = OMX_ErrorInsufficientResources;
}
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::UseOutputBuffer
DESCRIPTION
Helper function for Use buffer in the input pin
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
OMX_ERRORTYPE omx_vdec::use_output_buffer(
OMX_IN OMX_HANDLETYPE hComp,
OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
OMX_IN OMX_U32 port,
OMX_IN OMX_PTR appData,
OMX_IN OMX_U32 bytes,
OMX_IN OMX_U8* buffer)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
OMX_BUFFERHEADERTYPE *bufHdr= NULL; // buffer header
unsigned i= 0; // Temporary counter
if(!m_out_mem_ptr)
{
DEBUG_PRINT_HIGH("\n Use o/p buffer case - Header List allocation");
output_use_buffer = true;
int nBufHdrSize = 0;
int nPlatformEntrySize = 0;
int nPlatformListSize = 0;
int nPMEMInfoSize = 0;
OMX_QCOM_PLATFORM_PRIVATE_LIST *pPlatformList;
OMX_QCOM_PLATFORM_PRIVATE_ENTRY *pPlatformEntry;
OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo;
DEBUG_PRINT_LOW("Allocating First Output Buffer(%d)\n",m_out_buf_count);
nBufHdrSize = m_out_buf_count * sizeof(OMX_BUFFERHEADERTYPE);
nPMEMInfoSize = m_out_buf_count *
sizeof(OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO);
nPlatformListSize = m_out_buf_count *
sizeof(OMX_QCOM_PLATFORM_PRIVATE_LIST);
nPlatformEntrySize = m_out_buf_count *
sizeof(OMX_QCOM_PLATFORM_PRIVATE_ENTRY);
DEBUG_PRINT_LOW("TotalBufHdr %d BufHdrSize %d PMEM %d PL %d\n",nBufHdrSize,
sizeof(OMX_BUFFERHEADERTYPE),
nPMEMInfoSize,
nPlatformListSize);
DEBUG_PRINT_LOW("PE %d bmSize %d \n",nPlatformEntrySize,
m_out_bm_count);
/*
* Memory for output side involves the following:
* 1. Array of Buffer Headers
* 2. Platform specific information List
* 3. Platform specific Entry List
* 4. PMem Information entries
* 5. Bitmask array to hold the buffer allocation details
* In order to minimize the memory management entire allocation
* is done in one step.
*/
m_out_mem_ptr = (OMX_BUFFERHEADERTYPE *)calloc(nBufHdrSize,1);
// Alloc mem for platform specific info
char *pPtr=NULL;
pPtr = (char*) calloc(nPlatformListSize + nPlatformEntrySize +
nPMEMInfoSize,1);
driver_context.ptr_outputbuffer = (struct vdec_bufferpayload *) \
calloc (sizeof(struct vdec_bufferpayload),m_out_buf_count);
driver_context.ptr_respbuffer = (struct vdec_output_frameinfo *)\
calloc (sizeof (struct vdec_output_frameinfo),m_out_buf_count);
if(m_out_mem_ptr && pPtr && driver_context.ptr_outputbuffer
&& driver_context.ptr_respbuffer)
{
bufHdr = m_out_mem_ptr;
m_platform_list = (OMX_QCOM_PLATFORM_PRIVATE_LIST *)(pPtr);
m_platform_entry= (OMX_QCOM_PLATFORM_PRIVATE_ENTRY *)
(((char *) m_platform_list) + nPlatformListSize);
m_pmem_info = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *)
(((char *) m_platform_entry) + nPlatformEntrySize);
pPlatformList = m_platform_list;
pPlatformEntry = m_platform_entry;
pPMEMInfo = m_pmem_info;
DEBUG_PRINT_LOW("Memory Allocation Succeeded for OUT port%p\n",m_out_mem_ptr);
// Settting the entire storage nicely
DEBUG_PRINT_LOW("bHdr %p OutMem %p PE %p\n",bufHdr, m_out_mem_ptr,pPlatformEntry);
DEBUG_PRINT_LOW(" Pmem Info = %p \n",pPMEMInfo);
for(i=0; i < m_out_buf_count ; i++)
{
bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
// Set the values when we determine the right HxW param
bufHdr->nAllocLen = bytes;
bufHdr->nFilledLen = 0;
bufHdr->pAppPrivate = appData;
bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX;
// Platform specific PMEM Information
// Initialize the Platform Entry
//DEBUG_PRINT_LOW("Initializing the Platform Entry for %d\n",i);
pPlatformEntry->type = OMX_QCOM_PLATFORM_PRIVATE_PMEM;
pPlatformEntry->entry = pPMEMInfo;
// Initialize the Platform List
pPlatformList->nEntries = 1;
pPlatformList->entryList = pPlatformEntry;
// Keep pBuffer NULL till vdec is opened
bufHdr->pBuffer = NULL;
pPMEMInfo->offset = 0;
pPMEMInfo->pmem_fd = 0;
bufHdr->pPlatformPrivate = pPlatformList;
driver_context.ptr_outputbuffer[i].pmem_fd = -1;
/*Create a mapping between buffers*/
bufHdr->pOutputPortPrivate = &driver_context.ptr_respbuffer[i];
driver_context.ptr_respbuffer[i].client_data = (void *) \
&driver_context.ptr_outputbuffer[i];
// Move the buffer and buffer header pointers
bufHdr++;
pPMEMInfo++;
pPlatformEntry++;
pPlatformList++;
}
}
else
{
DEBUG_PRINT_ERROR("Output buf mem alloc failed[0x%x][0x%x]\n",\
m_out_mem_ptr, pPtr);
if(m_out_mem_ptr)
{
free(m_out_mem_ptr);
m_out_mem_ptr = NULL;
}
if(pPtr)
{
free(pPtr);
pPtr = NULL;
}
if(driver_context.ptr_outputbuffer)
{
free(driver_context.ptr_outputbuffer);
driver_context.ptr_outputbuffer = NULL;
}
if(driver_context.ptr_respbuffer)
{
free(driver_context.ptr_respbuffer);
driver_context.ptr_respbuffer = NULL;
}
eRet = OMX_ErrorInsufficientResources;
}
}
for(i=0; i< m_out_buf_count; i++)
{
if(BITMASK_ABSENT(&m_out_bm_count,i))
{
break;
}
}
if (eRet == OMX_ErrorNone)
{
if(i < m_out_buf_count)
{
driver_context.ptr_outputbuffer[i].pmem_fd = \
open ("/dev/pmem_adsp",O_RDWR);
if (driver_context.ptr_outputbuffer[i].pmem_fd < 0)
{
return OMX_ErrorInsufficientResources;
}
if(driver_context.ptr_outputbuffer[i].pmem_fd == 0)
{
driver_context.ptr_outputbuffer[i].pmem_fd = \
open ("/dev/pmem_adsp",O_RDWR);
if (driver_context.ptr_outputbuffer[i].pmem_fd < 0)
{
return OMX_ErrorInsufficientResources;
}
}
if(!align_pmem_buffers(driver_context.ptr_outputbuffer[i].pmem_fd,
m_out_buf_size, driver_context.output_buffer.alignment))
{
DEBUG_PRINT_ERROR("\n align_pmem_buffers() failed");
close(driver_context.ptr_outputbuffer[i].pmem_fd);
return OMX_ErrorInsufficientResources;
}
driver_context.ptr_outputbuffer[i].bufferaddr =
(unsigned char *)mmap(NULL,m_out_buf_size,PROT_READ|PROT_WRITE,
MAP_SHARED,driver_context.ptr_outputbuffer[i].pmem_fd,0);
if (driver_context.ptr_outputbuffer[i].bufferaddr == MAP_FAILED)
{
return OMX_ErrorInsufficientResources;
}
driver_context.ptr_outputbuffer[i].offset = 0;
m_pmem_info[i].offset = driver_context.ptr_outputbuffer[i].offset;
m_pmem_info[i].pmem_fd = driver_context.ptr_outputbuffer[i].pmem_fd;
// found an empty buffer at i
*bufferHdr = (m_out_mem_ptr + i );
(*bufferHdr)->pBuffer = buffer;
(*bufferHdr)->pAppPrivate = appData;
BITMASK_SET(&m_out_bm_count,i);
}
else
{
DEBUG_PRINT_ERROR("All the Output Buffers have been Allocated ; Returning Insufficient \n");
eRet = OMX_ErrorInsufficientResources;
}
}
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::UseBuffer
DESCRIPTION
OMX Use Buffer method implementation.
PARAMETERS
<TBD>.
RETURN VALUE
OMX Error None , if everything successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::use_buffer(
OMX_IN OMX_HANDLETYPE hComp,
OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
OMX_IN OMX_U32 port,
OMX_IN OMX_PTR appData,
OMX_IN OMX_U32 bytes,
OMX_IN OMX_U8* buffer)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
if(m_state == OMX_StateInvalid)
{
DEBUG_PRINT_ERROR("Use Buffer in Invalid State\n");
return OMX_ErrorInvalidState;
}
if(port == OMX_CORE_INPUT_PORT_INDEX)
{
eRet = use_input_buffer(hComp,bufferHdr,port,appData,bytes,buffer);
}
else if(port == OMX_CORE_OUTPUT_PORT_INDEX)
{
eRet = use_output_buffer(hComp,bufferHdr,port,appData,bytes,buffer);
}
else
{
DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",(int)port);
eRet = OMX_ErrorBadPortIndex;
}
DEBUG_PRINT_LOW("Use Buffer: port %u, buffer %p, eRet %d", port, *bufferHdr, eRet);
if(eRet == OMX_ErrorNone)
{
if(allocate_done())
{
if(BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
{
// Send the callback now
BITMASK_CLEAR((&m_flags),OMX_COMPONENT_IDLE_PENDING);
post_event(OMX_CommandStateSet,OMX_StateIdle,
OMX_COMPONENT_GENERATE_EVENT);
}
}
if(port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated)
{
if(BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING))
{
BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING);
post_event(OMX_CommandPortEnable,
OMX_CORE_INPUT_PORT_INDEX,
OMX_COMPONENT_GENERATE_EVENT);
}
}
else if(port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated)
{
if(BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING))
{
BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
post_event(OMX_CommandPortEnable,
OMX_CORE_OUTPUT_PORT_INDEX,
OMX_COMPONENT_GENERATE_EVENT);
m_event_port_settings_sent = false;
}
}
}
return eRet;
}
OMX_ERRORTYPE omx_vdec::free_input_buffer(OMX_BUFFERHEADERTYPE *bufferHdr)
{
unsigned int index = 0;
if (bufferHdr == NULL || m_inp_mem_ptr == NULL)
{
return OMX_ErrorBadParameter;
}
index = bufferHdr - m_inp_mem_ptr;
DEBUG_PRINT_LOW("\n Free Input Buffer index = %d",index);
if (index < m_inp_buf_count && driver_context.ptr_inputbuffer)
{
DEBUG_PRINT_LOW("\n Free Input Buffer index = %d",index);
if (driver_context.ptr_inputbuffer[index].pmem_fd > 0)
{
struct vdec_ioctl_msg ioctl_msg = {NULL,NULL};
struct vdec_setbuffer_cmd setbuffers;
setbuffers.buffer_type = VDEC_BUFFER_TYPE_INPUT;
memcpy (&setbuffers.buffer,&driver_context.ptr_inputbuffer[index],
sizeof (vdec_bufferpayload));
ioctl_msg.inputparam = &setbuffers;
ioctl_msg.outputparam = NULL;
int ioctl_r = ioctl (driver_context.video_driver_fd,
VDEC_IOCTL_FREE_BUFFER, &ioctl_msg);
if (ioctl_r < 0)
{
DEBUG_PRINT_ERROR("\nVDEC_IOCTL_FREE_BUFFER returned error %d", ioctl_r);
}
DEBUG_PRINT_LOW("\n unmap the input buffer fd=%d",
driver_context.ptr_inputbuffer[index].pmem_fd);
DEBUG_PRINT_LOW("\n unmap the input buffer size=%d address = %d",
driver_context.ptr_inputbuffer[index].mmaped_size,
driver_context.ptr_inputbuffer[index].bufferaddr);
munmap (driver_context.ptr_inputbuffer[index].bufferaddr,
driver_context.ptr_inputbuffer[index].mmaped_size);
close (driver_context.ptr_inputbuffer[index].pmem_fd);
driver_context.ptr_inputbuffer[index].pmem_fd = -1;
}
}
return OMX_ErrorNone;
}
OMX_ERRORTYPE omx_vdec::free_output_buffer(OMX_BUFFERHEADERTYPE *bufferHdr)
{
unsigned int index = 0;
if (bufferHdr == NULL || m_out_mem_ptr == NULL)
{
return OMX_ErrorBadParameter;
}
index = bufferHdr - m_out_mem_ptr;
DEBUG_PRINT_LOW("\n Free ouput Buffer index = %d",index);
if (index < m_out_buf_count && driver_context.ptr_outputbuffer)
{
DEBUG_PRINT_LOW("\n Free ouput Buffer index = %d addr = %x", index,
driver_context.ptr_outputbuffer[index].bufferaddr);
if (!gate_output_buffers)
{
struct vdec_ioctl_msg ioctl_msg = {NULL,NULL};
struct vdec_setbuffer_cmd setbuffers;
setbuffers.buffer_type = VDEC_BUFFER_TYPE_OUTPUT;
memcpy (&setbuffers.buffer,&driver_context.ptr_outputbuffer[index],
sizeof (vdec_bufferpayload));
ioctl_msg.inputparam = &setbuffers;
ioctl_msg.outputparam = NULL;
DEBUG_PRINT_LOW("\nRelease the Output Buffer");
if (ioctl (driver_context.video_driver_fd, VDEC_IOCTL_FREE_BUFFER,
&ioctl_msg) < 0)
DEBUG_PRINT_ERROR("\nRelease output buffer failed in VCD");
}
if (driver_context.ptr_outputbuffer[0].pmem_fd > 0)
{
DEBUG_PRINT_LOW("\n unmap the output buffer fd = %d",
driver_context.ptr_outputbuffer[0].pmem_fd);
DEBUG_PRINT_LOW("\n unmap the ouput buffer size=%d address = %d",
driver_context.ptr_outputbuffer[0].mmaped_size,
driver_context.ptr_outputbuffer[0].bufferaddr);
munmap (driver_context.ptr_outputbuffer[0].bufferaddr,
driver_context.ptr_outputbuffer[0].mmaped_size);
close (driver_context.ptr_outputbuffer[0].pmem_fd);
driver_context.ptr_outputbuffer[0].pmem_fd = -1;
}
}
return OMX_ErrorNone;
}
OMX_ERRORTYPE omx_vdec::allocate_input_heap_buffer(OMX_HANDLETYPE hComp,
OMX_BUFFERHEADERTYPE **bufferHdr,
OMX_U32 port,
OMX_PTR appData,
OMX_U32 bytes)
{
OMX_BUFFERHEADERTYPE *input = NULL;
unsigned char *buf_addr = NULL;
OMX_ERRORTYPE eRet = OMX_ErrorNone;
unsigned i = 0;
/* Sanity Check*/
if (bufferHdr == NULL)
{
return OMX_ErrorBadParameter;
}
if (m_inp_heap_ptr == NULL)
{
m_inp_heap_ptr = (OMX_BUFFERHEADERTYPE*) \
calloc( (sizeof(OMX_BUFFERHEADERTYPE)), m_inp_buf_count);
m_phdr_pmem_ptr = (OMX_BUFFERHEADERTYPE**) \
calloc( (sizeof(OMX_BUFFERHEADERTYPE*)), m_inp_buf_count);
if (m_inp_heap_ptr == NULL)
{
DEBUG_PRINT_ERROR("\n m_inp_heap_ptr Allocation failed ");
return OMX_ErrorInsufficientResources;
}
h264_scratch.nAllocLen = m_inp_buf_size;
h264_scratch.pBuffer = (OMX_U8 *)malloc (m_inp_buf_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;
}
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 ");
return OMX_ErrorInsufficientResources;
}
m_frame_parser.mutils->initialize_frame_checking_environment();
m_frame_parser.mutils->allocate_rbsp_buffer (m_inp_buf_size);
}
}
/*Find a Free index*/
for(i=0; i< m_inp_buf_count; i++)
{
if(BITMASK_ABSENT(&m_heap_inp_bm_count,i))
{
DEBUG_PRINT_LOW("\n Free Input Buffer Index %d",i);
break;
}
}
if (i < m_inp_buf_count)
{
buf_addr = (unsigned char *)malloc (m_inp_buf_size);
if (buf_addr == NULL)
{
return OMX_ErrorInsufficientResources;
}
*bufferHdr = (m_inp_heap_ptr + i);
input = *bufferHdr;
BITMASK_SET(&m_heap_inp_bm_count,i);
input->pBuffer = (OMX_U8 *)buf_addr;
input->nSize = sizeof(OMX_BUFFERHEADERTYPE);
input->nVersion.nVersion = OMX_SPEC_VERSION;
input->nAllocLen = m_inp_buf_size;
input->pAppPrivate = appData;
input->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX;
DEBUG_PRINT_LOW("\n Address of Heap Buffer %p",*bufferHdr );
eRet = allocate_input_buffer(hComp,&m_phdr_pmem_ptr [i],port,appData,bytes);
DEBUG_PRINT_LOW("\n Address of Pmem Buffer %p",m_phdr_pmem_ptr [i] );
/*Add the Buffers to freeq*/
if (!m_input_free_q.insert_entry((unsigned)m_phdr_pmem_ptr [i],NULL,NULL))
{
DEBUG_PRINT_ERROR("\nERROR:Free_q is full");
return OMX_ErrorInsufficientResources;
}
}
else
{
return OMX_ErrorBadParameter;
}
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::AllocateInputBuffer
DESCRIPTION
Helper function for allocate buffer in the input pin
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
OMX_ERRORTYPE omx_vdec::allocate_input_buffer(
OMX_IN OMX_HANDLETYPE hComp,
OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
OMX_IN OMX_U32 port,
OMX_IN OMX_PTR appData,
OMX_IN OMX_U32 bytes)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
struct vdec_setbuffer_cmd setbuffers;
OMX_BUFFERHEADERTYPE *input = NULL;
struct vdec_ioctl_msg ioctl_msg = {NULL,NULL};
unsigned i = 0;
unsigned char *buf_addr = NULL;
int pmem_fd = -1;
if(bytes != m_inp_buf_size)
{
DEBUG_PRINT_LOW("\n Requested Size is wrong %d epected is %d",bytes,m_inp_buf_size);
//return OMX_ErrorBadParameter;
}
if(!m_inp_mem_ptr)
{
DEBUG_PRINT_HIGH("\n Allocate i/p buffer case - Header List allocation");
DEBUG_PRINT_LOW("\n Allocating input buffer count %d ",m_inp_buf_count);
DEBUG_PRINT_LOW("\n Size of input buffer is %d",m_inp_buf_size);
m_inp_mem_ptr = (OMX_BUFFERHEADERTYPE*) \
calloc( (sizeof(OMX_BUFFERHEADERTYPE)), m_inp_buf_count);
if (m_inp_mem_ptr == NULL)
{
return OMX_ErrorInsufficientResources;
}
driver_context.ptr_inputbuffer = (struct vdec_bufferpayload *) \
calloc ((sizeof (struct vdec_bufferpayload)),m_inp_buf_count);
if (driver_context.ptr_inputbuffer == NULL)
{
return OMX_ErrorInsufficientResources;
}
for (i=0; i < m_inp_buf_count; i++)
{
driver_context.ptr_inputbuffer [i].pmem_fd = -1;
}
}
for(i=0; i< m_inp_buf_count; i++)
{
if(BITMASK_ABSENT(&m_inp_bm_count,i))
{
DEBUG_PRINT_LOW("\n Free Input Buffer Index %d",i);
break;
}
}
if(i < m_inp_buf_count)
{
DEBUG_PRINT_LOW("\n Allocate input Buffer");
pmem_fd = open ("/dev/pmem_adsp",O_RDWR);
if (pmem_fd < 0)
{
DEBUG_PRINT_ERROR("\n open failed for pmem/adsp for input buffer");
return OMX_ErrorInsufficientResources;
}
if (pmem_fd == 0)
{
pmem_fd = open ("/dev/pmem_adsp",O_RDWR);
if (pmem_fd < 0)
{
DEBUG_PRINT_ERROR("\n open failed for pmem/adsp for input buffer");
return OMX_ErrorInsufficientResources;
}
}
if(!align_pmem_buffers(pmem_fd, m_inp_buf_size,
driver_context.input_buffer.alignment))
{
DEBUG_PRINT_ERROR("\n align_pmem_buffers() failed");
close(pmem_fd);
return OMX_ErrorInsufficientResources;
}
buf_addr = (unsigned char *)mmap(NULL,m_inp_buf_size,PROT_READ|PROT_WRITE,
MAP_SHARED,pmem_fd,0);
if (buf_addr == MAP_FAILED)
{
DEBUG_PRINT_ERROR("\n Map Failed to allocate input buffer");
return OMX_ErrorInsufficientResources;
}
driver_context.ptr_inputbuffer [i].bufferaddr = buf_addr;
driver_context.ptr_inputbuffer [i].pmem_fd = pmem_fd;
driver_context.ptr_inputbuffer [i].buffer_len = m_inp_buf_size;
driver_context.ptr_inputbuffer [i].mmaped_size = m_inp_buf_size;
driver_context.ptr_inputbuffer [i].offset = 0;
setbuffers.buffer_type = VDEC_BUFFER_TYPE_INPUT;
memcpy (&setbuffers.buffer,&driver_context.ptr_inputbuffer [i],
sizeof (vdec_bufferpayload));
ioctl_msg.inputparam = &setbuffers;
ioctl_msg.outputparam = NULL;
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_SET_BUFFER,
&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Set Buffers Failed");
return OMX_ErrorInsufficientResources;
}
*bufferHdr = (m_inp_mem_ptr + i);
input = *bufferHdr;
BITMASK_SET(&m_inp_bm_count,i);
DEBUG_PRINT_LOW("\n Buffer address %p of pmem",*bufferHdr);
input->pBuffer = (OMX_U8 *)buf_addr;
input->nSize = sizeof(OMX_BUFFERHEADERTYPE);
input->nVersion.nVersion = OMX_SPEC_VERSION;
input->nAllocLen = m_inp_buf_size;
input->pAppPrivate = appData;
input->nInputPortIndex = OMX_CORE_INPUT_PORT_INDEX;
input->pInputPortPrivate = (void *)&driver_context.ptr_inputbuffer [i];
}
else
{
DEBUG_PRINT_ERROR("\nERROR:Input Buffer Index not found");
eRet = OMX_ErrorInsufficientResources;
}
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::AllocateOutputBuffer
DESCRIPTION
Helper fn for AllocateBuffer in the output pin
PARAMETERS
<TBD>.
RETURN VALUE
OMX Error None if everything went well.
========================================================================== */
OMX_ERRORTYPE omx_vdec::allocate_output_buffer(
OMX_IN OMX_HANDLETYPE hComp,
OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
OMX_IN OMX_U32 port,
OMX_IN OMX_PTR appData,
OMX_IN OMX_U32 bytes)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
OMX_BUFFERHEADERTYPE *bufHdr= NULL; // buffer header
unsigned i= 0; // Temporary counter
struct vdec_ioctl_msg ioctl_msg = {NULL,NULL};
struct vdec_setbuffer_cmd setbuffers;
if(!m_out_mem_ptr)
{
DEBUG_PRINT_HIGH("\n Allocate o/p buffer case - Header List allocation");
int nBufHdrSize = 0;
int nPlatformEntrySize = 0;
int nPlatformListSize = 0;
int nPMEMInfoSize = 0;
int pmem_fd = -1;
unsigned char *pmem_baseaddress = NULL;
OMX_QCOM_PLATFORM_PRIVATE_LIST *pPlatformList;
OMX_QCOM_PLATFORM_PRIVATE_ENTRY *pPlatformEntry;
OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo;
DEBUG_PRINT_LOW("Allocating First Output Buffer(%d)\n",m_out_buf_count);
nBufHdrSize = m_out_buf_count * sizeof(OMX_BUFFERHEADERTYPE);
nPMEMInfoSize = m_out_buf_count *
sizeof(OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO);
nPlatformListSize = m_out_buf_count *
sizeof(OMX_QCOM_PLATFORM_PRIVATE_LIST);
nPlatformEntrySize = m_out_buf_count *
sizeof(OMX_QCOM_PLATFORM_PRIVATE_ENTRY);
DEBUG_PRINT_LOW("TotalBufHdr %d BufHdrSize %d PMEM %d PL %d\n",nBufHdrSize,
sizeof(OMX_BUFFERHEADERTYPE),
nPMEMInfoSize,
nPlatformListSize);
DEBUG_PRINT_LOW("PE %d OutputBuffer Count %d \n",nPlatformEntrySize,
m_out_buf_count);
pmem_fd = open ("/dev/pmem_adsp",O_RDWR);
if (pmem_fd < 0)
{
DEBUG_PRINT_ERROR("\nERROR:pmem fd for output buffer %d",m_out_buf_size);
return OMX_ErrorInsufficientResources;
}
if(pmem_fd == 0)
{
pmem_fd = open ("/dev/pmem_adsp",O_RDWR);
if (pmem_fd < 0)
{
DEBUG_PRINT_ERROR("\nERROR:pmem fd for output buffer %d",m_out_buf_size);
return OMX_ErrorInsufficientResources;
}
}
if(!align_pmem_buffers(pmem_fd, m_out_buf_size * m_out_buf_count,
driver_context.output_buffer.alignment))
{
DEBUG_PRINT_ERROR("\n align_pmem_buffers() failed");
close(pmem_fd);
return OMX_ErrorInsufficientResources;
}
pmem_baseaddress = (unsigned char *)mmap(NULL,(m_out_buf_size * m_out_buf_count),
PROT_READ|PROT_WRITE,MAP_SHARED,pmem_fd,0);
m_heap_ptr = new VideoHeap (pmem_fd,
m_out_buf_size*m_out_buf_count,
pmem_baseaddress);
if (pmem_baseaddress == MAP_FAILED)
{
DEBUG_PRINT_ERROR("\n MMAP failed for Size %d",m_out_buf_size);
return OMX_ErrorInsufficientResources;
}
m_out_mem_ptr = (OMX_BUFFERHEADERTYPE *)calloc(nBufHdrSize,1);
// Alloc mem for platform specific info
char *pPtr=NULL;
pPtr = (char*) calloc(nPlatformListSize + nPlatformEntrySize +
nPMEMInfoSize,1);
driver_context.ptr_outputbuffer = (struct vdec_bufferpayload *) \
calloc (sizeof(struct vdec_bufferpayload),m_out_buf_count);
driver_context.ptr_respbuffer = (struct vdec_output_frameinfo *)\
calloc (sizeof (struct vdec_output_frameinfo),m_out_buf_count);
if(m_out_mem_ptr && pPtr && driver_context.ptr_outputbuffer
&& driver_context.ptr_respbuffer)
{
driver_context.ptr_outputbuffer[0].mmaped_size =
(m_out_buf_size * m_out_buf_count);
bufHdr = m_out_mem_ptr;
m_platform_list = (OMX_QCOM_PLATFORM_PRIVATE_LIST *)(pPtr);
m_platform_entry= (OMX_QCOM_PLATFORM_PRIVATE_ENTRY *)
(((char *) m_platform_list) + nPlatformListSize);
m_pmem_info = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *)
(((char *) m_platform_entry) + nPlatformEntrySize);
pPlatformList = m_platform_list;
pPlatformEntry = m_platform_entry;
pPMEMInfo = m_pmem_info;
DEBUG_PRINT_LOW("Memory Allocation Succeeded for OUT port%p\n",m_out_mem_ptr);
// Settting the entire storage nicely
DEBUG_PRINT_LOW("bHdr %p OutMem %p PE %p\n",bufHdr, m_out_mem_ptr,pPlatformEntry);
DEBUG_PRINT_LOW(" Pmem Info = %p \n",pPMEMInfo);
for(i=0; i < m_out_buf_count ; i++)
{
bufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE);
bufHdr->nVersion.nVersion = OMX_SPEC_VERSION;
// Set the values when we determine the right HxW param
bufHdr->nAllocLen = bytes;
bufHdr->nFilledLen = 0;
bufHdr->pAppPrivate = appData;
bufHdr->nOutputPortIndex = OMX_CORE_OUTPUT_PORT_INDEX;
// Platform specific PMEM Information
// Initialize the Platform Entry
//DEBUG_PRINT_LOW("Initializing the Platform Entry for %d\n",i);
pPlatformEntry->type = OMX_QCOM_PLATFORM_PRIVATE_PMEM;
pPlatformEntry->entry = pPMEMInfo;
// Initialize the Platform List
pPlatformList->nEntries = 1;
pPlatformList->entryList = pPlatformEntry;
// Keep pBuffer NULL till vdec is opened
bufHdr->pBuffer = NULL;
bufHdr->nOffset = 0;
pPMEMInfo->offset = m_out_buf_size*i;
pPMEMInfo->pmem_fd = 0;
bufHdr->pPlatformPrivate = pPlatformList;
driver_context.ptr_outputbuffer[i].pmem_fd = pmem_fd;
/*Create a mapping between buffers*/
bufHdr->pOutputPortPrivate = &driver_context.ptr_respbuffer[i];
driver_context.ptr_respbuffer[i].client_data = (void *) \
&driver_context.ptr_outputbuffer[i];
driver_context.ptr_outputbuffer[i].offset = m_out_buf_size*i;
driver_context.ptr_outputbuffer[i].bufferaddr = \
pmem_baseaddress + (m_out_buf_size*i);
DEBUG_PRINT_LOW("\n pmem_fd = %d offset = %d address = %p",\
pmem_fd,driver_context.ptr_outputbuffer[i].offset,driver_context.ptr_outputbuffer[i].bufferaddr);
// Move the buffer and buffer header pointers
bufHdr++;
pPMEMInfo++;
pPlatformEntry++;
pPlatformList++;
}
}
else
{
DEBUG_PRINT_ERROR("Output buf mem alloc failed[0x%x][0x%x]\n",\
m_out_mem_ptr, pPtr);
if(m_out_mem_ptr)
{
free(m_out_mem_ptr);
m_out_mem_ptr = NULL;
}
if(pPtr)
{
free(pPtr);
pPtr = NULL;
}
if(driver_context.ptr_outputbuffer)
{
free(driver_context.ptr_outputbuffer);
driver_context.ptr_outputbuffer = NULL;
}
if(driver_context.ptr_respbuffer)
{
free(driver_context.ptr_respbuffer);
driver_context.ptr_respbuffer = NULL;
}
eRet = OMX_ErrorInsufficientResources;
}
}
for(i=0; i< m_out_buf_count; i++)
{
if(BITMASK_ABSENT(&m_out_bm_count,i))
{
DEBUG_PRINT_LOW("\n Found a Free Output Buffer %d",i);
break;
}
}
if (eRet == OMX_ErrorNone)
{
if(i < m_out_buf_count)
{
m_pmem_info[i].offset = driver_context.ptr_outputbuffer[i].offset;
m_pmem_info[i].pmem_fd = (OMX_U32) m_heap_ptr.get ();
driver_context.ptr_outputbuffer[i].buffer_len = m_out_buf_size;
//driver_context.ptr_outputbuffer[i].mmaped_size = m_out_buf_size;
if(!gate_output_buffers)
{
setbuffers.buffer_type = VDEC_BUFFER_TYPE_OUTPUT;
memcpy (&setbuffers.buffer,&driver_context.ptr_outputbuffer [i],
sizeof (vdec_bufferpayload));
ioctl_msg.inputparam = &setbuffers;
ioctl_msg.outputparam = NULL;
DEBUG_PRINT_LOW("\n Set the Output Buffer");
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_SET_BUFFER,
&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Set output buffer failed");
return OMX_ErrorInsufficientResources;
}
}
// found an empty buffer at i
*bufferHdr = (m_out_mem_ptr + i );
(*bufferHdr)->pBuffer = driver_context.ptr_outputbuffer[i].bufferaddr;
(*bufferHdr)->pAppPrivate = appData;
BITMASK_SET(&m_out_bm_count,i);
}
else
{
DEBUG_PRINT_ERROR("All the Output Buffers have been Allocated ; Returning Insufficient \n");
eRet = OMX_ErrorInsufficientResources;
}
}
return eRet;
}
// AllocateBuffer -- API Call
/* ======================================================================
FUNCTION
omx_vdec::AllocateBuffer
DESCRIPTION
Returns zero if all the buffers released..
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
OMX_ERRORTYPE omx_vdec::allocate_buffer(OMX_IN OMX_HANDLETYPE hComp,
OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
OMX_IN OMX_U32 port,
OMX_IN OMX_PTR appData,
OMX_IN OMX_U32 bytes)
{
unsigned i = 0;
OMX_ERRORTYPE eRet = OMX_ErrorNone; // OMX return type
DEBUG_PRINT_LOW("\n Allocate buffer on port %d \n", (int)port);
if(m_state == OMX_StateInvalid)
{
DEBUG_PRINT_ERROR("Allocate Buf in Invalid State\n");
return OMX_ErrorInvalidState;
}
if(port == OMX_CORE_INPUT_PORT_INDEX)
{
if (arbitrary_bytes)
{
eRet = allocate_input_heap_buffer (hComp,bufferHdr,port,appData,bytes);
}
else
{
eRet = allocate_input_buffer(hComp,bufferHdr,port,appData,bytes);
}
}
else if(port == OMX_CORE_OUTPUT_PORT_INDEX)
{
eRet = allocate_output_buffer(hComp,bufferHdr,port,appData,bytes);
}
else
{
DEBUG_PRINT_ERROR("Error: Invalid Port Index received %d\n",(int)port);
eRet = OMX_ErrorBadPortIndex;
}
DEBUG_PRINT_LOW("Checking for Output Allocate buffer Done");
if(eRet == OMX_ErrorNone)
{
if(allocate_done()){
if(BITMASK_PRESENT(&m_flags,OMX_COMPONENT_IDLE_PENDING))
{
// Send the callback now
BITMASK_CLEAR((&m_flags),OMX_COMPONENT_IDLE_PENDING);
post_event(OMX_CommandStateSet,OMX_StateIdle,
OMX_COMPONENT_GENERATE_EVENT);
}
}
if(port == OMX_CORE_INPUT_PORT_INDEX && m_inp_bPopulated)
{
if(BITMASK_PRESENT(&m_flags,OMX_COMPONENT_INPUT_ENABLE_PENDING))
{
BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_ENABLE_PENDING);
post_event(OMX_CommandPortEnable,
OMX_CORE_INPUT_PORT_INDEX,
OMX_COMPONENT_GENERATE_EVENT);
}
}
if(port == OMX_CORE_OUTPUT_PORT_INDEX && m_out_bPopulated)
{
if(BITMASK_PRESENT(&m_flags,OMX_COMPONENT_OUTPUT_ENABLE_PENDING))
{
BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_ENABLE_PENDING);
post_event(OMX_CommandPortEnable,
OMX_CORE_OUTPUT_PORT_INDEX,
OMX_COMPONENT_GENERATE_EVENT);
m_event_port_settings_sent = false;
}
}
}
DEBUG_PRINT_LOW("Allocate Buffer exit with ret Code %d\n",eRet);
return eRet;
}
// Free Buffer - API call
/* ======================================================================
FUNCTION
omx_vdec::FreeBuffer
DESCRIPTION
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
OMX_ERRORTYPE omx_vdec::free_buffer(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_U32 port,
OMX_IN OMX_BUFFERHEADERTYPE* buffer)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
unsigned int nPortIndex;
DEBUG_PRINT_LOW("In for decoder free_buffer \n");
if(m_state == OMX_StateIdle &&
(BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING)))
{
DEBUG_PRINT_LOW(" free buffer while Component in Loading pending\n");
}
else if((m_inp_bEnabled == OMX_FALSE && port == OMX_CORE_INPUT_PORT_INDEX)||
(m_out_bEnabled == OMX_FALSE && port == OMX_CORE_OUTPUT_PORT_INDEX))
{
DEBUG_PRINT_LOW("Free Buffer while port %d disabled\n", port);
}
else if(m_state == OMX_StateExecuting || m_state == OMX_StatePause)
{
DEBUG_PRINT_ERROR("Invalid state to free buffer,ports need to be disabled\n");
post_event(OMX_EventError,
OMX_ErrorPortUnpopulated,
OMX_COMPONENT_GENERATE_EVENT);
return eRet;
}
else if (m_state != OMX_StateInvalid)
{
DEBUG_PRINT_ERROR("Invalid state to free buffer,port lost Buffers\n");
post_event(OMX_EventError,
OMX_ErrorPortUnpopulated,
OMX_COMPONENT_GENERATE_EVENT);
}
if(port == OMX_CORE_INPUT_PORT_INDEX)
{
/*Check if arbitrary bytes*/
if (!arbitrary_bytes)
{
// check if the buffer is valid
nPortIndex = buffer - m_inp_mem_ptr;
}
else
{
nPortIndex = buffer - m_inp_heap_ptr;
}
DEBUG_PRINT_LOW("free_buffer on i/p port - Port idx %d \n", nPortIndex);
if(nPortIndex < m_inp_buf_count)
{
// Clear the bit associated with it.
BITMASK_CLEAR(&m_inp_bm_count,nPortIndex);
if (arbitrary_bytes)
{
if (m_inp_heap_ptr[nPortIndex].pBuffer)
{
BITMASK_CLEAR(&m_heap_inp_bm_count,nPortIndex);
DEBUG_PRINT_LOW("\n Free Heap Buffer index %d",nPortIndex);
free (m_inp_heap_ptr[nPortIndex].pBuffer);
m_inp_heap_ptr[nPortIndex].pBuffer = NULL;
}
if (m_phdr_pmem_ptr[nPortIndex])
{
DEBUG_PRINT_LOW("\n Free pmem Buffer index %d",nPortIndex);
free_input_buffer(m_phdr_pmem_ptr[nPortIndex]);
}
}
else
{
free_input_buffer(buffer);
}
m_inp_bPopulated = OMX_FALSE;
/*Free the Buffer Header*/
if (release_input_done())
{
DEBUG_PRINT_HIGH("\n ALL input buffers are freed/released");
input_use_buffer = false;
if (arbitrary_bytes)
{
if (m_frame_parser.mutils)
{
DEBUG_PRINT_LOW("\n Free utils parser");
delete (m_frame_parser.mutils);
m_frame_parser.mutils = NULL;
}
if (m_inp_heap_ptr)
{
DEBUG_PRINT_LOW("\n Free input Heap Pointer");
free (m_inp_heap_ptr);
m_inp_heap_ptr = NULL;
}
if (m_phdr_pmem_ptr)
{
DEBUG_PRINT_LOW("\n Free input pmem header Pointer");
free (m_phdr_pmem_ptr);
m_phdr_pmem_ptr = NULL;
}
}
if (m_inp_mem_ptr)
{
DEBUG_PRINT_LOW("\n Free input pmem Pointer area");
free (m_inp_mem_ptr);
m_inp_mem_ptr = NULL;
}
if (driver_context.ptr_inputbuffer)
{
DEBUG_PRINT_LOW("\n Free Driver Context pointer");
free (driver_context.ptr_inputbuffer);
driver_context.ptr_inputbuffer = NULL;
}
}
}
else
{
DEBUG_PRINT_ERROR("Error: free_buffer ,Port Index Invalid\n");
eRet = OMX_ErrorBadPortIndex;
}
if(BITMASK_PRESENT((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING)
&& release_input_done())
{
DEBUG_PRINT_LOW("MOVING TO DISABLED STATE \n");
BITMASK_CLEAR((&m_flags),OMX_COMPONENT_INPUT_DISABLE_PENDING);
post_event(OMX_CommandPortDisable,
OMX_CORE_INPUT_PORT_INDEX,
OMX_COMPONENT_GENERATE_EVENT);
}
}
else if(port == OMX_CORE_OUTPUT_PORT_INDEX)
{
// check if the buffer is valid
nPortIndex = buffer - (OMX_BUFFERHEADERTYPE*)m_out_mem_ptr;
if(nPortIndex < m_out_buf_count)
{
DEBUG_PRINT_LOW("free_buffer on o/p port - Port idx %d \n", nPortIndex);
// Clear the bit associated with it.
BITMASK_CLEAR(&m_out_bm_count,nPortIndex);
m_out_bPopulated = OMX_FALSE;
free_output_buffer (buffer);
if (release_output_done())
{
DEBUG_PRINT_HIGH("\n ALL output buffers are freed/released");
output_use_buffer = false;
if (m_out_mem_ptr)
{
free (m_out_mem_ptr);
m_out_mem_ptr = NULL;
}
if (driver_context.ptr_respbuffer)
{
free (driver_context.ptr_respbuffer);
driver_context.ptr_respbuffer = NULL;
}
if (driver_context.ptr_outputbuffer)
{
free (driver_context.ptr_outputbuffer);
driver_context.ptr_outputbuffer = NULL;
}
}
}
else
{
DEBUG_PRINT_ERROR("Error: free_buffer , Port Index Invalid\n");
eRet = OMX_ErrorBadPortIndex;
}
if(BITMASK_PRESENT((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING)
&& release_output_done() )
{
DEBUG_PRINT_LOW("FreeBuffer : If any Disable event pending,post it\n");
DEBUG_PRINT_LOW("MOVING TO DISABLED STATE \n");
BITMASK_CLEAR((&m_flags),OMX_COMPONENT_OUTPUT_DISABLE_PENDING);
post_event(OMX_CommandPortDisable,
OMX_CORE_OUTPUT_PORT_INDEX,
OMX_COMPONENT_GENERATE_EVENT);
}
}
else
{
eRet = OMX_ErrorBadPortIndex;
}
if((eRet == OMX_ErrorNone) &&
(BITMASK_PRESENT(&m_flags ,OMX_COMPONENT_LOADING_PENDING)))
{
if(release_done())
{
// Send the callback now
BITMASK_CLEAR((&m_flags),OMX_COMPONENT_LOADING_PENDING);
post_event(OMX_CommandStateSet, OMX_StateLoaded,
OMX_COMPONENT_GENERATE_EVENT);
}
}
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::EmptyThisBuffer
DESCRIPTION
This routine is used to push the encoded video frames to
the video decoder.
PARAMETERS
None.
RETURN VALUE
OMX Error None if everything went successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::empty_this_buffer(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_BUFFERHEADERTYPE* buffer)
{
OMX_ERRORTYPE ret1 = OMX_ErrorNone;
unsigned int nBufferIndex = m_inp_buf_count;
if(m_state == OMX_StateInvalid)
{
DEBUG_PRINT_ERROR("Empty this buffer in Invalid State\n");
return OMX_ErrorInvalidState;
}
if (buffer == NULL)
{
DEBUG_PRINT_ERROR("\nERROR:ETB Buffer is NULL");
return OMX_ErrorBadParameter;
}
if (arbitrary_bytes)
{
nBufferIndex = buffer - m_inp_heap_ptr;
}
else
{
nBufferIndex = buffer - m_inp_mem_ptr;
}
if (nBufferIndex > m_inp_buf_count )
{
DEBUG_PRINT_ERROR("\nERROR:ETB nBufferIndex is invalid");
return OMX_ErrorBadParameter;
}
DEBUG_PRINT_LOW("\n ETB: bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer);
if (arbitrary_bytes)
{
post_event ((unsigned)hComp,(unsigned)buffer,
OMX_COMPONENT_GENERATE_ETB_ARBITRARY);
}
else
{
post_event ((unsigned)hComp,(unsigned)buffer,OMX_COMPONENT_GENERATE_ETB);
}
return OMX_ErrorNone;
}
/* ======================================================================
FUNCTION
omx_vdec::empty_this_buffer_proxy
DESCRIPTION
This routine is used to push the encoded video frames to
the video decoder.
PARAMETERS
None.
RETURN VALUE
OMX Error None if everything went successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::empty_this_buffer_proxy(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_BUFFERHEADERTYPE* buffer)
{
int push_cnt = 0,i=0;
unsigned nPortIndex = 0;
OMX_ERRORTYPE ret = OMX_ErrorNone;
struct vdec_input_frameinfo frameinfo;
struct vdec_bufferpayload *temp_buffer;
struct vdec_ioctl_msg ioctl_msg;
struct vdec_seqheader seq_header;
bool port_setting_changed = true;
/*Should we generate a Aync error event*/
if (buffer == NULL || buffer->pInputPortPrivate == NULL)
{
DEBUG_PRINT_ERROR("\nERROR:empty_this_buffer_proxy is invalid");
return OMX_ErrorBadParameter;
}
nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)m_inp_mem_ptr);
if (nPortIndex > m_inp_buf_count)
{
DEBUG_PRINT_ERROR("\nERROR:empty_this_buffer_proxy invalid nPortIndex[%u]",
nPortIndex);
return OMX_ErrorBadParameter;
}
pending_input_buffers++;
if( input_flush_progress == true || m_ineos_reached == 1)
{
DEBUG_PRINT_LOW("\n Flush in progress return buffer ");
post_event ((unsigned int)buffer,VDEC_S_SUCCESS,
OMX_COMPONENT_GENERATE_EBD);
return OMX_ErrorNone;
}
if(m_event_port_settings_sent && !arbitrary_bytes)
{
post_event((unsigned)hComp,(unsigned)buffer,OMX_COMPONENT_GENERATE_ETB);
return OMX_ErrorNone;
}
temp_buffer = (struct vdec_bufferpayload *)buffer->pInputPortPrivate;
if ((temp_buffer - driver_context.ptr_inputbuffer) > m_inp_buf_count)
{
return OMX_ErrorBadParameter;
}
DEBUG_PRINT_LOW("\n ETBProxy: bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer);
/*for use buffer we need to memcpy the data*/
temp_buffer->buffer_len = buffer->nFilledLen;
if (input_use_buffer)
{
if (buffer->nFilledLen <= temp_buffer->buffer_len)
{
memcpy (temp_buffer->bufferaddr,(buffer->pBuffer + buffer->nOffset),
buffer->nFilledLen);
}
else
{
return OMX_ErrorBadParameter;
}
}
if (!arbitrary_bytes && first_frame < 2 && codec_type_parse == CODEC_TYPE_MPEG4)
{
if (first_frame == 0)
{
first_buffer = (unsigned char *)malloc (m_inp_buf_size);
DEBUG_PRINT_LOW("\n Copied the first buffer data size %d ",
temp_buffer->buffer_len);
first_frame = 1;
memcpy (first_buffer,temp_buffer->bufferaddr,temp_buffer->buffer_len);
first_frame_size = buffer->nFilledLen;
buffer->nFilledLen = 0;
post_event ((unsigned int)buffer,VDEC_S_SUCCESS,
OMX_COMPONENT_GENERATE_EBD);
return OMX_ErrorNone;
}
else if (first_frame == 1)
{
first_frame = 2;
DEBUG_PRINT_LOW("\n Second buffer copy the header size %d frame size %d",
first_frame_size,temp_buffer->buffer_len);
memcpy (&first_buffer [first_frame_size],temp_buffer->bufferaddr,
temp_buffer->buffer_len);
first_frame_size += temp_buffer->buffer_len;
memcpy (temp_buffer->bufferaddr,first_buffer,first_frame_size);
temp_buffer->buffer_len = first_frame_size;
free (first_buffer);
}
}
frameinfo.bufferaddr = temp_buffer->bufferaddr;
frameinfo.client_data = (void *) buffer;
frameinfo.datalen = temp_buffer->buffer_len;
frameinfo.flags = 0;
frameinfo.offset = buffer->nOffset;
frameinfo.pmem_fd = temp_buffer->pmem_fd;
frameinfo.pmem_offset = temp_buffer->offset;
frameinfo.timestamp = buffer->nTimeStamp;
#if BITSTREAM_LOG
int bytes_written;
bytes_written = fwrite((const char *)temp_buffer->bufferaddr,
temp_buffer->buffer_len,1,outputBufferFile1);
#endif
if(!set_seq_header_done)
{
set_seq_header_done = true;
DEBUG_PRINT_HIGH("\n Set Sequence Header");
seq_header.ptr_seqheader = frameinfo.bufferaddr;
seq_header.seq_header_len = frameinfo.datalen;
seq_header.pmem_fd = frameinfo.pmem_fd;
seq_header.pmem_offset = frameinfo.pmem_offset;
ioctl_msg.inputparam = &seq_header;
ioctl_msg.outputparam = NULL;
if (ioctl(driver_context.video_driver_fd,VDEC_IOCTL_SET_SEQUENCE_HEADER,
&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Set Sequence Header Failed");
/*Generate an async error and move to invalid state*/
return OMX_ErrorBadParameter;
}
if(omx_vdec_check_port_settings (&port_setting_changed) != OMX_ErrorNone)
{
DEBUG_PRINT_ERROR("\n Check port setting failed");
return OMX_ErrorBadParameter;
}
if(port_setting_changed)
{
DEBUG_PRINT_HIGH("\n Port settings changed");
m_event_port_settings_sent = true;
m_cb.EventHandler(&m_cmp, m_app_data,OMX_EventPortSettingsChanged,
OMX_CORE_OUTPUT_PORT_INDEX, 0, NULL );
DEBUG_PRINT_HIGH("\n EventHandler for Port Setting changed done");
return OMX_ErrorNone;
}
else
{
if(!register_output_buffers())
{
DEBUG_PRINT_ERROR("\n register output failed");
return OMX_ErrorBadParameter;
}
DEBUG_PRINT_HIGH("\n Port settings Not changed");
}
}
if (temp_buffer->buffer_len == 0 || (buffer->nFlags & 0x01))
{
DEBUG_PRINT_HIGH("\n Rxd i/p EOS, Notify Driver that EOS has been reached");
frameinfo.flags |= VDEC_BUFFERFLAG_EOS;
m_ineos_reached = 1;
}
sent_first_frame = true;
DEBUG_PRINT_LOW("\n Decode Input Frame Size %d",frameinfo.datalen);
ioctl_msg.inputparam = &frameinfo;
ioctl_msg.outputparam = NULL;
if (ioctl(driver_context.video_driver_fd,VDEC_IOCTL_DECODE_FRAME,
&ioctl_msg) < 0)
{
/*Generate an async error and move to invalid state*/
return OMX_ErrorBadParameter;
}
return ret;
}
/* ======================================================================
FUNCTION
omx_vdec::FillThisBuffer
DESCRIPTION
IL client uses this method to release the frame buffer
after displaying them.
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
OMX_ERRORTYPE omx_vdec::fill_this_buffer(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_BUFFERHEADERTYPE* buffer)
{
if(m_state == OMX_StateInvalid)
{
DEBUG_PRINT_ERROR("FTB in Invalid State\n");
return OMX_ErrorInvalidState;
}
if (buffer == NULL || ((buffer - m_out_mem_ptr) > m_out_buf_size))
{
return OMX_ErrorBadParameter;
}
DEBUG_PRINT_LOW("\n FTB: bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer);
post_event((unsigned) hComp, (unsigned)buffer,OMX_COMPONENT_GENERATE_FTB);
return OMX_ErrorNone;
}
/* ======================================================================
FUNCTION
omx_vdec::fill_this_buffer_proxy
DESCRIPTION
IL client uses this method to release the frame buffer
after displaying them.
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
OMX_ERRORTYPE omx_vdec::fill_this_buffer_proxy(
OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_BUFFERHEADERTYPE* bufferAdd)
{
OMX_ERRORTYPE nRet = OMX_ErrorNone;
struct vdec_ioctl_msg ioctl_msg = {NULL,NULL};
OMX_BUFFERHEADERTYPE *buffer = bufferAdd;
struct vdec_fillbuffer_cmd fillbuffer;
struct vdec_bufferpayload *ptr_outputbuffer = NULL;
struct vdec_output_frameinfo *ptr_respbuffer = NULL;
if (bufferAdd == NULL || ((buffer - m_out_mem_ptr) > m_out_buf_count) )
{
return OMX_ErrorBadParameter;
}
DEBUG_PRINT_LOW("\n FTBProxy: bufhdr = %p, bufhdr->pBuffer = %p",
bufferAdd, bufferAdd->pBuffer);
/*Return back the output buffer to client*/
if( (m_event_port_settings_sent == true) || (m_out_bEnabled != OMX_TRUE)
|| output_flush_progress == true || m_outeos_reached == 1)
{
DEBUG_PRINT_LOW("\n Output Buffers return in EOS condition");
buffer->nFlags |= m_outeos_reached;
m_cb.FillBufferDone (hComp,m_app_data,buffer);
return OMX_ErrorNone;
}
pending_output_buffers++;
ptr_respbuffer = (struct vdec_output_frameinfo*)buffer->pOutputPortPrivate;
if (ptr_respbuffer)
{
ptr_outputbuffer = (struct vdec_bufferpayload*)ptr_respbuffer->client_data;
}
if (ptr_respbuffer == NULL || ptr_outputbuffer == NULL)
{
return OMX_ErrorBadParameter;
}
memcpy (&fillbuffer.buffer,ptr_outputbuffer,\
sizeof(struct vdec_bufferpayload));
fillbuffer.client_data = bufferAdd;
ioctl_msg.inputparam = &fillbuffer;
ioctl_msg.outputparam = NULL;
if (ioctl (driver_context.video_driver_fd,
VDEC_IOCTL_FILL_OUTPUT_BUFFER,&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Decoder frame failed");
m_cb.FillBufferDone (hComp,m_app_data,buffer);
return OMX_ErrorBadParameter;
}
if(gate_input_buffers)
{
gate_input_buffers = false;
if(pdest_frame)
{
/*Push the frame to the Decoder*/
if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone)
{
return OMX_ErrorBadParameter;
}
frame_count++;
pdest_frame = NULL;
}
}
return OMX_ErrorNone;
}
/* ======================================================================
FUNCTION
omx_vdec::SetCallbacks
DESCRIPTION
Set the callbacks.
PARAMETERS
None.
RETURN VALUE
OMX Error None if everything successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::set_callbacks(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_CALLBACKTYPE* callbacks,
OMX_IN OMX_PTR appData)
{
m_cb = *callbacks;
DEBUG_PRINT_LOW("\n Callbacks Set %p %p %p",m_cb.EmptyBufferDone,\
m_cb.EventHandler,m_cb.FillBufferDone);
m_app_data = appData;
return OMX_ErrorNotImplemented;
}
/* ======================================================================
FUNCTION
omx_vdec::ComponentDeInit
DESCRIPTION
Destroys the component and release memory allocated to the heap.
PARAMETERS
<TBD>.
RETURN VALUE
OMX Error None if everything successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::component_deinit(OMX_IN OMX_HANDLETYPE hComp)
{
int i = 0;
if (OMX_StateLoaded != m_state)
{
DEBUG_PRINT_ERROR("WARNING:Rxd DeInit,OMX not in LOADED state %d\n",\
m_state);
DEBUG_PRINT_ERROR("\nPlayback Ended - FAILED");
}
else
{
DEBUG_PRINT_HIGH("\n Playback Ended - PASSED");
}
/*Check if the output buffers have to be cleaned up*/
if(m_out_mem_ptr)
{
DEBUG_PRINT_LOW("Freeing the Output Memory\n");
for (i=0; i<m_out_buf_count; i++ )
{
free_output_buffer (&m_out_mem_ptr[i]);
}
if (driver_context.ptr_outputbuffer)
{
free (driver_context.ptr_outputbuffer);
driver_context.ptr_outputbuffer = NULL;
}
if (driver_context.ptr_respbuffer)
{
free (driver_context.ptr_respbuffer);
driver_context.ptr_respbuffer = NULL;
}
free(m_out_mem_ptr);
m_out_mem_ptr = NULL;
}
/*Check if the input buffers have to be cleaned up*/
if(m_inp_mem_ptr)
{
DEBUG_PRINT_LOW("Freeing the Input Memory\n");
for (i=0; i<m_inp_buf_count; i++ )
{
free_input_buffer (&m_inp_mem_ptr[i]);
}
if (driver_context.ptr_inputbuffer)
{
free (driver_context.ptr_inputbuffer);
driver_context.ptr_inputbuffer = NULL;
}
free(m_inp_mem_ptr);
m_inp_mem_ptr = NULL;
}
if(h264_scratch.pBuffer)
{
free(h264_scratch.pBuffer);
h264_scratch.pBuffer = NULL;
}
if(m_platform_list)
{
free(m_platform_list);
m_platform_list = NULL;
}
if(m_vendor_config.pData)
{
free(m_vendor_config.pData);
m_vendor_config.pData = NULL;
}
// Reset counters in mesg queues
m_ftb_q.m_size=0;
m_cmd_q.m_size=0;
m_etb_q.m_size=0;
m_ftb_q.m_read = m_ftb_q.m_write =0;
m_cmd_q.m_read = m_cmd_q.m_write =0;
m_etb_q.m_read = m_etb_q.m_write =0;
DEBUG_PRINT_LOW("\n Calling VDEC_IOCTL_STOP_NEXT_MSG");
(void)ioctl(driver_context.video_driver_fd, VDEC_IOCTL_STOP_NEXT_MSG,
NULL);
DEBUG_PRINT_HIGH("\n Close the driver instance");
close(driver_context.video_driver_fd);
#if BITSTREAM_LOG
fclose (outputBufferFile1);
#endif
#ifdef _ANDROID_
//for (i=0; i<m_out_buf_count; i++ )
{
// Clear the strong reference
m_heap_ptr.clear();
}
#endif // _ANDROID_
DEBUG_PRINT_HIGH("\n omx_vdec::component_deinit() complete");
return OMX_ErrorNone;
}
/* ======================================================================
FUNCTION
omx_vdec::UseEGLImage
DESCRIPTION
OMX Use EGL Image method implementation <TBD>.
PARAMETERS
<TBD>.
RETURN VALUE
Not Implemented error.
========================================================================== */
OMX_ERRORTYPE omx_vdec::use_EGL_image(OMX_IN OMX_HANDLETYPE hComp,
OMX_INOUT OMX_BUFFERHEADERTYPE** bufferHdr,
OMX_IN OMX_U32 port,
OMX_IN OMX_PTR appData,
OMX_IN void* eglImage)
{
DEBUG_PRINT_ERROR("Error : use_EGL_image: Not Implemented \n");
return OMX_ErrorNotImplemented;
}
/* ======================================================================
FUNCTION
omx_vdec::ComponentRoleEnum
DESCRIPTION
OMX Component Role Enum method implementation.
PARAMETERS
<TBD>.
RETURN VALUE
OMX Error None if everything is successful.
========================================================================== */
OMX_ERRORTYPE omx_vdec::component_role_enum(OMX_IN OMX_HANDLETYPE hComp,
OMX_OUT OMX_U8* role,
OMX_IN OMX_U32 index)
{
OMX_ERRORTYPE eRet = OMX_ErrorNone;
if(!strncmp(driver_context.kind, "OMX.qcom.video.decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE))
{
if((0 == index) && role)
{
strncpy((char *)role, "video_decoder.mpeg4",OMX_MAX_STRINGNAME_SIZE);
DEBUG_PRINT_LOW("component_role_enum: role %s\n",role);
}
else
{
eRet = OMX_ErrorNoMore;
}
}
else if(!strncmp(driver_context.kind, "OMX.qcom.video.decoder.h263",OMX_MAX_STRINGNAME_SIZE))
{
if((0 == index) && role)
{
strncpy((char *)role, "video_decoder.h263",OMX_MAX_STRINGNAME_SIZE);
DEBUG_PRINT_LOW("component_role_enum: role %s\n",role);
}
else
{
DEBUG_PRINT_LOW("\n No more roles \n");
eRet = OMX_ErrorNoMore;
}
}
else if(!strncmp(driver_context.kind, "OMX.qcom.video.decoder.avc",OMX_MAX_STRINGNAME_SIZE))
{
if((0 == index) && role)
{
strncpy((char *)role, "video_decoder.avc",OMX_MAX_STRINGNAME_SIZE);
DEBUG_PRINT_LOW("component_role_enum: role %s\n",role);
}
else
{
DEBUG_PRINT_LOW("\n No more roles \n");
eRet = OMX_ErrorNoMore;
}
}
else if(!strncmp(driver_context.kind, "OMX.qcom.video.decoder.vc1",OMX_MAX_STRINGNAME_SIZE))
{
if((0 == index) && role)
{
strncpy((char *)role, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE);
DEBUG_PRINT_LOW("component_role_enum: role %s\n",role);
}
else
{
DEBUG_PRINT_LOW("\n No more roles \n");
eRet = OMX_ErrorNoMore;
}
}
else
{
DEBUG_PRINT_ERROR("\nERROR:Querying Role on Unknown Component\n");
eRet = OMX_ErrorInvalidComponentName;
}
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::AllocateDone
DESCRIPTION
Checks if entire buffer pool is allocated by IL Client or not.
Need this to move to IDLE state.
PARAMETERS
None.
RETURN VALUE
true/false.
========================================================================== */
bool omx_vdec::allocate_done(void)
{
bool bRet = false;
bool bRet_In = false;
bool bRet_Out = false;
bRet_In = allocate_input_done();
bRet_Out = allocate_output_done();
if(bRet_In && bRet_Out)
{
bRet = true;
}
return bRet;
}
/* ======================================================================
FUNCTION
omx_vdec::AllocateInputDone
DESCRIPTION
Checks if I/P buffer pool is allocated by IL Client or not.
PARAMETERS
None.
RETURN VALUE
true/false.
========================================================================== */
bool omx_vdec::allocate_input_done(void)
{
bool bRet = false;
unsigned i=0;
if (m_inp_mem_ptr == NULL)
{
return bRet;
}
if(m_inp_mem_ptr )
{
for(;i<m_inp_buf_count;i++)
{
if(BITMASK_ABSENT(&m_inp_bm_count,i))
{
break;
}
}
}
if(i==m_inp_buf_count)
{
bRet = true;
DEBUG_PRINT_HIGH("\n Allocate done for all i/p buffers");
}
if(i==m_inp_buf_count && m_inp_bEnabled)
{
m_inp_bPopulated = OMX_TRUE;
}
return bRet;
}
/* ======================================================================
FUNCTION
omx_vdec::AllocateOutputDone
DESCRIPTION
Checks if entire O/P buffer pool is allocated by IL Client or not.
PARAMETERS
None.
RETURN VALUE
true/false.
========================================================================== */
bool omx_vdec::allocate_output_done(void)
{
bool bRet = false;
unsigned j=0;
if (m_out_mem_ptr == NULL)
{
return bRet;
}
if(m_out_mem_ptr )
{
for(;j<m_out_buf_count;j++)
{
if(BITMASK_ABSENT(&m_out_bm_count,j))
{
break;
}
}
}
if(j==m_out_buf_count)
{
bRet = true;
DEBUG_PRINT_HIGH("\n Allocate done for all o/p buffers");
}
if(j==m_out_buf_count && m_out_bEnabled)
{
m_out_bPopulated = OMX_TRUE;
}
return bRet;
}
/* ======================================================================
FUNCTION
omx_vdec::ReleaseDone
DESCRIPTION
Checks if IL client has released all the buffers.
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
bool omx_vdec::release_done(void)
{
bool bRet = false;
if(release_input_done())
{
if(release_output_done())
{
bRet = true;
}
}
return bRet;
}
/* ======================================================================
FUNCTION
omx_vdec::ReleaseOutputDone
DESCRIPTION
Checks if IL client has released all the buffers.
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
bool omx_vdec::release_output_done(void)
{
bool bRet = false;
unsigned i=0,j=0;
DEBUG_PRINT_LOW("\n Value of m_out_mem_ptr %p",m_inp_mem_ptr);
if(m_out_mem_ptr)
{
for(;j<m_out_buf_count;j++)
{
if(BITMASK_PRESENT(&m_out_bm_count,j))
{
break;
}
}
if(j==m_out_buf_count)
{
m_out_bm_count = 0;
bRet = true;
}
}
else
{
m_out_bm_count = 0;
bRet = true;
}
return bRet;
}
/* ======================================================================
FUNCTION
omx_vdec::ReleaseInputDone
DESCRIPTION
Checks if IL client has released all the buffers.
PARAMETERS
None.
RETURN VALUE
true/false
========================================================================== */
bool omx_vdec::release_input_done(void)
{
bool bRet = false;
unsigned i=0,j=0;
DEBUG_PRINT_LOW("\n Value of m_inp_mem_ptr %p",m_inp_mem_ptr);
if(m_inp_mem_ptr)
{
for(;j<m_inp_buf_count;j++)
{
if( BITMASK_PRESENT(&m_inp_bm_count,j))
{
break;
}
}
if(j==m_inp_buf_count)
{
bRet = true;
}
}
else
{
bRet = true;
}
return bRet;
}
/* ======================================================================
FUNCTION
omx_vdec::omx_vdec_check_port_settings
DESCRIPTION
Parse meta data to check the height and width param
Check the level and profile
PARAMETERS
None.
RETURN VALUE
OMX_ErrorNone, if profile and level are supported
OMX_ErrorUnsupportedSetting, if profile and level are not supported
========================================================================== */
OMX_ERRORTYPE omx_vdec::omx_vdec_check_port_settings(bool *port_setting_changed)
{
struct vdec_ioctl_msg ioctl_msg;
unsigned int alignment = 0,buffer_size = 0;
OMX_ERRORTYPE eRet = OMX_ErrorNone;
*port_setting_changed = false;
ioctl_msg.inputparam = NULL;
ioctl_msg.outputparam = &driver_context.video_resoultion;
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_GET_PICRES,&ioctl_msg))
{
DEBUG_PRINT_ERROR("\n Error in VDEC_IOCTL_GET_PICRES in port_setting");
return OMX_ErrorHardware;
}
ioctl_msg.inputparam = NULL;
ioctl_msg.outputparam = &driver_context.output_buffer;
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_GET_BUFFER_REQ,
&ioctl_msg))
{
DEBUG_PRINT_ERROR("\n Error in VDEC_IOCTL_GET_BUFFER_REQ in port_setting");
return OMX_ErrorHardware;
}
DEBUG_PRINT_HIGH("\n Queried Dimensions H=%d W=%d Act H=%d W=%d",
driver_context.video_resoultion.frame_height,
driver_context.video_resoultion.frame_width,
m_height,m_width);
DEBUG_PRINT_HIGH("\n Queried Buffer ACnt=%d BSiz=%d Act Acnt=%d Bsiz=%d",
driver_context.output_buffer.actualcount,
driver_context.output_buffer.buffer_size,
m_out_buf_count,m_out_buf_size);
DEBUG_PRINT_HIGH("\n Queried stride cuur Str=%d cur scan=%d Act str=%d act scan =%d",
driver_context.video_resoultion.stride,driver_context.video_resoultion.scan_lines,
stride,scan_lines);
if(driver_context.video_resoultion.frame_height != m_height ||
driver_context.video_resoultion.frame_width != m_width ||
driver_context.video_resoultion.scan_lines != scan_lines ||
driver_context.video_resoultion.stride != stride ||
driver_context.output_buffer.actualcount != m_out_buf_count ||
driver_context.output_buffer.buffer_size > m_out_buf_size)
{
*port_setting_changed = true;
ioctl_msg.inputparam = &driver_context.output_buffer;
ioctl_msg.outputparam = NULL;
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_SET_BUFFER_REQ,
&ioctl_msg))
{
DEBUG_PRINT_ERROR("\n Error in VDEC_IOCTL_GET_BUFFER_REQ in port_setting");
return OMX_ErrorHardware;
}
m_out_buf_size_recon = driver_context.output_buffer.buffer_size;
m_out_buf_count_recon = driver_context.output_buffer.actualcount;
m_out_buf_count_min_recon = driver_context.output_buffer.mincount;
alignment = driver_context.output_buffer.alignment;
buffer_size = driver_context.output_buffer.buffer_size;
m_out_buf_size_recon =
((buffer_size + alignment - 1) & (~(alignment - 1)));
m_crop_dy = m_height = driver_context.video_resoultion.frame_height;
m_crop_dx = m_width = driver_context.video_resoultion.frame_width;
scan_lines = driver_context.video_resoultion.scan_lines;
stride = driver_context.video_resoultion.stride;
m_port_height = m_height;
m_port_width = m_width;
}
return eRet;
}
/* ======================================================================
FUNCTION
omx_vdec::omx_vdec_validate_port_param
DESCRIPTION
Get the PMEM area from video decoder
PARAMETERS
None.
RETURN VALUE
None
========================================================================== */
OMX_ERRORTYPE omx_vdec::omx_vdec_validate_port_param(int height, int width)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
long hxw = height*width;
long lmt_hxw = 0;
return ret;
}
static FILE * outputBufferFile = NULL;
OMX_ERRORTYPE omx_vdec::fill_buffer_done(OMX_HANDLETYPE hComp,
OMX_BUFFERHEADERTYPE * buffer)
{
OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo = NULL;
if (buffer == NULL || ((buffer - m_out_mem_ptr) > m_out_buf_count))
{
return OMX_ErrorBadParameter;
}
DEBUG_PRINT_LOW("\n fill_buffer_done: bufhdr = %p, bufhdr->pBuffer = %p",
buffer, buffer->pBuffer);
pending_output_buffers --;
if (buffer->nFlags & 0x01)
{
DEBUG_PRINT_LOW("\n Output EOS has been reached");
m_outeos_reached = 0;
m_ineos_reached = 0;
h264_scratch.nFilledLen = 0;
nal_count = 0;
look_ahead_nal = false;
frame_count = 0;
if (m_frame_parser.mutils)
{
m_frame_parser.mutils->initialize_frame_checking_environment();
}
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,NULL,NULL);
pdest_frame = NULL;
}
m_frame_parser.flush();
}
DEBUG_PRINT_LOW("\n In fill Buffer done call address %p ",buffer);
if (outputBufferFile == NULL)
{
outputBufferFile = fopen ("/data/output.yuv","wb");
}
if (outputBufferFile)
{
/*fwrite (buffer->pBuffer,1,buffer->nFilledLen,
outputBufferFile); */
}
/* For use buffer we need to copy the data */
if (m_cb.FillBufferDone)
{
pPMEMInfo = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *)
((OMX_QCOM_PLATFORM_PRIVATE_LIST *)
buffer->pPlatformPrivate)->entryList->entry;
DEBUG_PRINT_LOW("\n Before FBD callback Accessed Pmeminfo %d",pPMEMInfo->pmem_fd);
m_cb.FillBufferDone (hComp,m_app_data,buffer);
DEBUG_PRINT_LOW("\n After Fill Buffer Done callback %d",pPMEMInfo->pmem_fd);
}
else
{
return OMX_ErrorBadParameter;
}
return OMX_ErrorNone;
}
OMX_ERRORTYPE omx_vdec::empty_buffer_done(OMX_HANDLETYPE hComp,
OMX_BUFFERHEADERTYPE* buffer)
{
if (buffer == NULL || ((buffer - m_inp_mem_ptr) > m_inp_buf_count))
{
return OMX_ErrorBadParameter;
}
DEBUG_PRINT_LOW("\n empty_buffer_done: bufhdr = %p, bufhdr->pBuffer = %p",
buffer, buffer->pBuffer);
pending_input_buffers--;
if (arbitrary_bytes)
{
if (pdest_frame == NULL && input_flush_progress == false)
{
DEBUG_PRINT_LOW("\n Push input from buffer done address of Buffer %p",buffer);
pdest_frame = buffer;
buffer->nFilledLen = 0;
push_input_buffer (hComp);
}
else
{
DEBUG_PRINT_LOW("\n Push buffer into freeq address of Buffer %p",buffer);
buffer->nFilledLen = 0;
if (!m_input_free_q.insert_entry((unsigned)buffer,NULL,NULL))
{
DEBUG_PRINT_ERROR("\nERROR:i/p free Queue is FULL Error");
}
}
}
else if(m_cb.EmptyBufferDone)
{
buffer->nFilledLen = 0;
m_cb.EmptyBufferDone(hComp ,m_app_data, buffer);
}
return OMX_ErrorNone;
}
int omx_vdec::async_message_process (void *context, void* message)
{
omx_vdec* omx = NULL;
struct vdec_msginfo *vdec_msg = NULL;
OMX_BUFFERHEADERTYPE* omxhdr = NULL;
struct vdec_output_frameinfo *output_respbuf = NULL;
if (context == NULL || message == NULL)
{
DEBUG_PRINT_ERROR("\n FATAL ERROR in omx_vdec::async_message_process NULL Check");
return -1;
}
vdec_msg = (struct vdec_msginfo *)message;
omx = reinterpret_cast<omx_vdec*>(context);
switch (vdec_msg->msgcode)
{
case VDEC_MSG_EVT_HW_ERROR:
omx->post_event (NULL,vdec_msg->status_code,\
OMX_COMPONENT_GENERATE_HARDWARE_ERROR);
break;
case VDEC_MSG_RESP_START_DONE:
omx->post_event (NULL,vdec_msg->status_code,\
OMX_COMPONENT_GENERATE_START_DONE);
break;
case VDEC_MSG_RESP_STOP_DONE:
omx->post_event (NULL,vdec_msg->status_code,\
OMX_COMPONENT_GENERATE_STOP_DONE);
break;
case VDEC_MSG_RESP_RESUME_DONE:
omx->post_event (NULL,vdec_msg->status_code,\
OMX_COMPONENT_GENERATE_RESUME_DONE);
break;
case VDEC_MSG_RESP_PAUSE_DONE:
omx->post_event (NULL,vdec_msg->status_code,\
OMX_COMPONENT_GENERATE_PAUSE_DONE);
break;
case VDEC_MSG_RESP_FLUSH_INPUT_DONE:
omx->post_event (NULL,vdec_msg->status_code,\
OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH);
break;
case VDEC_MSG_RESP_FLUSH_OUTPUT_DONE:
omx->post_event (NULL,vdec_msg->status_code,\
OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH);
break;
case VDEC_MSG_RESP_INPUT_FLUSHED:
case VDEC_MSG_RESP_INPUT_BUFFER_DONE:
omxhdr = (OMX_BUFFERHEADERTYPE* )\
vdec_msg->msgdata.input_frame_clientdata;
if (omxhdr == NULL ||
((omxhdr - omx->m_inp_mem_ptr) > omx->m_inp_buf_count) )
{
omxhdr = NULL;
vdec_msg->status_code = VDEC_S_EFATAL;
}
omx->post_event ((unsigned int)omxhdr,vdec_msg->status_code,
OMX_COMPONENT_GENERATE_EBD);
break;
case VDEC_MSG_RESP_OUTPUT_FLUSHED:
case VDEC_MSG_RESP_OUTPUT_BUFFER_DONE:
omxhdr = (OMX_BUFFERHEADERTYPE*)vdec_msg->msgdata.output_frame.client_data;
DEBUG_PRINT_LOW("\n Got Buffer back from Driver %p omxhdr time stamp = %d " ,omxhdr,vdec_msg->msgdata.output_frame.time_stamp);
if ( (omxhdr != NULL) &&
((omxhdr - omx->m_out_mem_ptr) < omx->m_out_buf_count) &&
(omxhdr->pOutputPortPrivate != NULL) &&
( ((struct vdec_output_frameinfo *)omxhdr->pOutputPortPrivate
- omx->driver_context.ptr_respbuffer) < omx->m_out_buf_count)
)
{
if (vdec_msg->msgdata.output_frame.len <= omxhdr->nAllocLen)
{
omxhdr->nFilledLen = vdec_msg->msgdata.output_frame.len;
omxhdr->nOffset = vdec_msg->msgdata.output_frame.offset;
omxhdr->nTimeStamp = vdec_msg->msgdata.output_frame.time_stamp;
omxhdr->nFlags = (vdec_msg->msgdata.output_frame.flags & 0x01);
output_respbuf = (struct vdec_output_frameinfo *)\
omxhdr->pOutputPortPrivate;
output_respbuf->framesize.bottom = \
vdec_msg->msgdata.output_frame.framesize.bottom;
output_respbuf->framesize.left = \
vdec_msg->msgdata.output_frame.framesize.left;
output_respbuf->framesize.right = \
vdec_msg->msgdata.output_frame.framesize.right;
output_respbuf->framesize.top = \
vdec_msg->msgdata.output_frame.framesize.top;
output_respbuf->len = vdec_msg->msgdata.output_frame.len;
output_respbuf->offset = vdec_msg->msgdata.output_frame.offset;
output_respbuf->time_stamp = vdec_msg->msgdata.output_frame.time_stamp;
output_respbuf->flags = vdec_msg->msgdata.output_frame.flags;
/*Use buffer case*/
if (omx->output_use_buffer)
{
if (vdec_msg->msgdata.output_frame.len <= omxhdr->nAllocLen)
{
memcpy ( omxhdr->pBuffer,
(vdec_msg->msgdata.output_frame.bufferaddr +
vdec_msg->msgdata.output_frame.offset),
vdec_msg->msgdata.output_frame.len );
}
else
{
omxhdr->nFilledLen = 0;
}
}
}
else
{
omxhdr->nFilledLen = 0;
}
}
else
{
omxhdr = NULL;
vdec_msg->status_code = VDEC_S_EFATAL;
}
DEBUG_PRINT_LOW("\n Driver returned a output Buffer status %d",
vdec_msg->status_code);
omx->post_event ((unsigned int)omxhdr,vdec_msg->status_code,
OMX_COMPONENT_GENERATE_FBD);
break;
default:
break;
}
return 1;
}
OMX_ERRORTYPE omx_vdec::empty_this_buffer_proxy_arbitrary (
OMX_HANDLETYPE hComp,
OMX_BUFFERHEADERTYPE *buffer
)
{
unsigned address,p2,id;
DEBUG_PRINT_LOW("\n Empty this arbitrary");
if (buffer == NULL)
{
return OMX_ErrorBadParameter;
}
DEBUG_PRINT_LOW("\n ETBProxyArb: bufhdr = %p, bufhdr->pBuffer = %p", buffer, buffer->pBuffer);
DEBUG_PRINT_LOW("\n ETBProxyArb: nFilledLen %u, flags %d, timestamp %u",
buffer->nFilledLen, buffer->nFlags, (unsigned)buffer->nTimeStamp);
if( input_flush_progress == true || m_ineos_reached == 1)
{
DEBUG_PRINT_LOW("\n Flush in progress return buffer ");
m_cb.EmptyBufferDone (hComp,m_app_data,buffer);
return OMX_ErrorNone;
}
if (psource_frame == NULL)
{
DEBUG_PRINT_LOW("\n Set Buffer as source Buffer %p time stamp %d",buffer,buffer->nTimeStamp);
psource_frame = buffer;
DEBUG_PRINT_LOW("\n Try to Push One Input Buffer ");
push_input_buffer (hComp);
}
else
{
DEBUG_PRINT_LOW("\n Push the source buffer into pendingq %p",buffer);
if (!m_input_pending_q.insert_entry((unsigned)buffer,NULL,NULL))
{
return OMX_ErrorBadParameter;
}
}
return OMX_ErrorNone;
}
OMX_ERRORTYPE omx_vdec::push_input_buffer (OMX_HANDLETYPE hComp)
{
unsigned address,p2,id;
OMX_ERRORTYPE ret = OMX_ErrorNone;
if (pdest_frame == NULL || psource_frame == NULL)
{
/*Check if we have a destination buffer*/
if (pdest_frame == NULL)
{
DEBUG_PRINT_LOW("\n Get a Destination buffer from the queue");
if (m_input_free_q.m_size && !gate_input_buffers)
{
m_input_free_q.pop_entry(&address,&p2,&id);
pdest_frame = (OMX_BUFFERHEADERTYPE *)address;
pdest_frame->nFilledLen = 0;
DEBUG_PRINT_LOW("\n Address of Pmem Buffer %p",pdest_frame);
}
}
/*Check if we have a destination buffer*/
if (psource_frame == NULL)
{
DEBUG_PRINT_LOW("\n Get a source buffer from the queue");
if (m_input_pending_q.m_size && !gate_input_buffers)
{
m_input_pending_q.pop_entry(&address,&p2,&id);
psource_frame = (OMX_BUFFERHEADERTYPE *)address;
DEBUG_PRINT_LOW("\n Next source Buffer %p time stamp %d",psource_frame,
psource_frame->nTimeStamp);
DEBUG_PRINT_LOW("\n Next source Buffer flag %d length %d",
psource_frame->nFlags,psource_frame->nFilledLen);
}
}
}
while ((pdest_frame != NULL) && (psource_frame != NULL)&& !gate_input_buffers)
{
switch (codec_type_parse)
{
case CODEC_TYPE_MPEG4:
case CODEC_TYPE_H263:
ret = push_input_sc_codec(hComp);
break;
case CODEC_TYPE_H264:
ret = push_input_h264(hComp);
break;
case CODEC_TYPE_VC1:
ret = push_input_vc1(hComp);
break;
}
if (ret != OMX_ErrorNone)
{
DEBUG_PRINT_ERROR("\n Pushing input Buffer Failed");
omx_report_error ();
break;
}
}
return ret;
}
OMX_ERRORTYPE omx_vdec::push_input_sc_codec(OMX_HANDLETYPE hComp)
{
OMX_U32 partial_frame = 1;
OMX_BOOL genarte_edb = OMX_TRUE,generate_eos = OMX_TRUE;
unsigned address,p2,id;
DEBUG_PRINT_LOW("\n Start Parsing the bit stream address %p TimeStamp %d",
psource_frame,psource_frame->nTimeStamp);
if (m_frame_parser.parse_mpeg4_frame(psource_frame,
pdest_frame,&partial_frame) == -1)
{
DEBUG_PRINT_ERROR("\n Error In Parsing Return Error");
return OMX_ErrorBadParameter;
}
if (partial_frame == 0)
{
DEBUG_PRINT_LOW("\n Frame size %d source %p frame count %d",
pdest_frame->nFilledLen,psource_frame,frame_count);
DEBUG_PRINT_LOW("\n TimeStamp updated %d",pdest_frame->nTimeStamp);
/*First Parsed buffer will have only header Hence skip*/
if (frame_count == 0)
{
DEBUG_PRINT_LOW("\n H263/MPEG4 Codec First Frame ");
mp4h263_flags = psource_frame->nFlags;
mp4h263_timestamp = psource_frame->nTimeStamp;
frame_count++;
}
else
{
pdest_frame->nTimeStamp = mp4h263_timestamp;
mp4h263_timestamp = psource_frame->nTimeStamp;
pdest_frame->nFlags = mp4h263_flags;
mp4h263_flags = psource_frame->nFlags;
if(psource_frame->nFilledLen == 0)
{
pdest_frame->nFlags = mp4h263_flags;
generate_eos = OMX_FALSE;
}
/*Push the frame to the Decoder*/
if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone)
{
return OMX_ErrorBadParameter;
}
if(m_event_port_settings_sent)
{
gate_input_buffers = true;
return OMX_ErrorNone;
}
frame_count++;
pdest_frame = NULL;
if (m_input_free_q.m_size && !gate_input_buffers)
{
m_input_free_q.pop_entry(&address,&p2,&id);
pdest_frame = (OMX_BUFFERHEADERTYPE *) address;
pdest_frame->nFilledLen = 0;
}
}
}
else
{
DEBUG_PRINT_LOW("\n Not a Complete Frame %d",pdest_frame->nFilledLen);
/*Check if Destination Buffer is full*/
if (pdest_frame->nAllocLen ==
pdest_frame->nFilledLen + pdest_frame->nOffset)
{
DEBUG_PRINT_ERROR("\nERROR:Frame Not found though Destination Filled");
return OMX_ErrorStreamCorrupt;
}
}
if (psource_frame->nFilledLen == 0)
{
if ((psource_frame->nFlags & 0x01) && generate_eos)
{
if (pdest_frame)
{
pdest_frame->nTimeStamp = psource_frame->nTimeStamp;
pdest_frame->nFlags = psource_frame->nFlags;
DEBUG_PRINT_LOW("\n Frame Found start Decoding Size =%d TimeStamp = %x",
pdest_frame->nFilledLen,pdest_frame->nTimeStamp);
DEBUG_PRINT_LOW("\n Found a frame size = %d number = %d",
pdest_frame->nFilledLen,frame_count++);
/*Push the frame to the Decoder*/
if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone)
{
return OMX_ErrorBadParameter;
}
frame_count++;
pdest_frame = NULL;
}
else
{
DEBUG_PRINT_LOW("\n Last frame in else dest addr") ;
genarte_edb = OMX_FALSE;
}
}
if(genarte_edb)
{
DEBUG_PRINT_LOW("\n Buffer Consumed return back to client %p",psource_frame);
m_cb.EmptyBufferDone (hComp,m_app_data,psource_frame);
psource_frame = NULL;
if (m_input_pending_q.m_size)
{
DEBUG_PRINT_LOW("\n Pull Next source Buffer %p",psource_frame);
m_input_pending_q.pop_entry(&address,&p2,&id);
psource_frame = (OMX_BUFFERHEADERTYPE *) address;
DEBUG_PRINT_LOW("\n Next source Buffer %p time stamp %d",psource_frame,
psource_frame->nTimeStamp);
DEBUG_PRINT_LOW("\n Next source Buffer flag %d length %d",
psource_frame->nFlags,psource_frame->nFilledLen);
}
}
}
return OMX_ErrorNone;
}
OMX_ERRORTYPE omx_vdec::push_input_h264 (OMX_HANDLETYPE hComp)
{
OMX_U32 partial_frame = 1;
unsigned address,p2,id;
OMX_BOOL isNewFrame = OMX_FALSE;
OMX_BOOL genarte_edb = OMX_TRUE;
OMX_BOOL skip_parsing = OMX_FALSE;
if (h264_scratch.pBuffer == NULL)
{
DEBUG_PRINT_ERROR("\nERROR:H.264 Scratch Buffer not allocated");
return OMX_ErrorBadParameter;
}
DEBUG_PRINT_LOW("\n Values of h264_scratch.nFilledLen %d look_ahead_nal %d",
h264_scratch.nFilledLen,look_ahead_nal);
DEBUG_PRINT_LOW("\n pdest_frame->nFilledLen %d",pdest_frame->nFilledLen);
if (h264_scratch.nFilledLen && look_ahead_nal)
{
look_ahead_nal = false;
DEBUG_PRINT_LOW("\n Copy the previous NAL into Buffer %d ",
h264_scratch.nFilledLen);
if ((pdest_frame->nAllocLen - pdest_frame->nFilledLen) >=
h264_scratch.nFilledLen)
{
memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen),
h264_scratch.pBuffer,h264_scratch.nFilledLen);
pdest_frame->nFilledLen += h264_scratch.nFilledLen;
DEBUG_PRINT_LOW("\n Total filled length %d",pdest_frame->nFilledLen);
h264_scratch.nFilledLen = 0;
}
else
{
DEBUG_PRINT_ERROR("\nERROR:Destination buffer overflow for H264");
return OMX_ErrorBadParameter;
}
}
if(psource_frame->nFlags & 0x01)
{
DEBUG_PRINT_LOW("\n EOS has been reached no parsing required");
skip_parsing = OMX_TRUE;
if ((pdest_frame->nAllocLen - pdest_frame->nFilledLen) >=
psource_frame->nFilledLen)
{
memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen),
(psource_frame->pBuffer+psource_frame->nOffset),
psource_frame->nFilledLen);
pdest_frame->nFilledLen += psource_frame->nFilledLen;
DEBUG_PRINT_LOW("\n Total filled length %d",pdest_frame->nFilledLen);
psource_frame->nFilledLen = 0;
}
else
{
DEBUG_PRINT_ERROR("\nERROR:Destination buffer overflow for H264");
return OMX_ErrorBadParameter;
}
}
if(!skip_parsing)
{
if (nal_length == 0)
{
DEBUG_PRINT_LOW("\n NAL length Zero hence parse using start code");
if (m_frame_parser.parse_mpeg4_frame(psource_frame,
&h264_scratch,&partial_frame) == -1)
{
DEBUG_PRINT_ERROR("\n Error In Parsing Return Error");
return OMX_ErrorBadParameter;
}
}
else
{
DEBUG_PRINT_LOW("\n NAL length %d hence parse with NAL length %d",nal_length);
if (m_frame_parser.parse_h264_nallength(psource_frame,
&h264_scratch,&partial_frame) == -1)
{
DEBUG_PRINT_ERROR("\n Error In Parsing NAL Return Error");
return OMX_ErrorBadParameter;
}
}
if (partial_frame == 0)
{
if (nal_count == 0 && h264_scratch.nFilledLen == 0)
{
DEBUG_PRINT_LOW("\n First NAL with Zero Length Hence Skip");
nal_count++;
h264_scratch.nTimeStamp = psource_frame->nTimeStamp;
h264_scratch.nFlags = psource_frame->nFlags;
}
else
{
DEBUG_PRINT_LOW("\n Length of New NAL is %d",h264_scratch.nFilledLen);
m_frame_parser.mutils->isNewFrame(h264_scratch.pBuffer,
h264_scratch.nFilledLen,0,isNewFrame);
nal_count++;
if (!isNewFrame)
{
if ( (pdest_frame->nAllocLen - pdest_frame->nFilledLen) >=
h264_scratch.nFilledLen)
{
DEBUG_PRINT_LOW("\n Not a NewFrame Copy into Dest len %d",
h264_scratch.nFilledLen);
memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen),
h264_scratch.pBuffer,h264_scratch.nFilledLen);
pdest_frame->nFilledLen += h264_scratch.nFilledLen;
h264_scratch.nFilledLen = 0;
}
else
{
DEBUG_PRINT_LOW("\n Destination buffer overflow for H264");
return OMX_ErrorBadParameter;
}
}
else
{
look_ahead_nal = true;
pdest_frame->nTimeStamp = h264_scratch.nTimeStamp;
pdest_frame->nFlags = h264_scratch.nFlags;
h264_scratch.nTimeStamp = psource_frame->nTimeStamp;
h264_scratch.nFlags = psource_frame->nFlags;
DEBUG_PRINT_LOW("\n Frame Found start Decoding Size =%d TimeStamp = %x",
pdest_frame->nFilledLen,pdest_frame->nTimeStamp);
DEBUG_PRINT_LOW("\n Found a frame size = %d number = %d",
pdest_frame->nFilledLen,frame_count++);
if (pdest_frame->nFilledLen == 0)
{
DEBUG_PRINT_LOW("\n Copy the Current Frame since and push it");
look_ahead_nal = false;
if ( (pdest_frame->nAllocLen - pdest_frame->nFilledLen) >=
h264_scratch.nFilledLen)
{
memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen),
h264_scratch.pBuffer,h264_scratch.nFilledLen);
pdest_frame->nFilledLen += h264_scratch.nFilledLen;
h264_scratch.nFilledLen = 0;
}
else
{
DEBUG_PRINT_ERROR("\nERROR:Destination buffer overflow for H264");
return OMX_ErrorBadParameter;
}
}
else
{
/*Push the frame to the Decoder*/
if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone)
{
return OMX_ErrorBadParameter;
}
if(m_event_port_settings_sent)
{
gate_input_buffers = true;
return OMX_ErrorNone;
}
//frame_count++;
pdest_frame = NULL;
if (m_input_free_q.m_size && !gate_input_buffers)
{
m_input_free_q.pop_entry(&address,&p2,&id);
pdest_frame = (OMX_BUFFERHEADERTYPE *) address;
DEBUG_PRINT_LOW("\n Pop the next pdest_buffer %p",pdest_frame);
pdest_frame->nFilledLen = 0;
}
}
}
}
}
else
{
DEBUG_PRINT_LOW("\n Not a Complete Frame %d",pdest_frame->nFilledLen);
/*Check if Destination Buffer is full*/
if (h264_scratch.nAllocLen ==
h264_scratch.nFilledLen + h264_scratch.nOffset)
{
DEBUG_PRINT_ERROR("\nERROR: Frame Not found though Destination Filled");
return OMX_ErrorStreamCorrupt;
}
}
}
if (psource_frame->nFilledLen == 0)
{
DEBUG_PRINT_LOW("\n Buffer Consumed return back to client %p",psource_frame);
if (psource_frame->nFlags & 0x01)
{
if (pdest_frame)
{
DEBUG_PRINT_LOW("\n EOS Reached Pass Last Buffer");
if ( (pdest_frame->nAllocLen - pdest_frame->nFilledLen) >=
h264_scratch.nFilledLen)
{
memcpy ((pdest_frame->pBuffer + pdest_frame->nFilledLen),
h264_scratch.pBuffer,h264_scratch.nFilledLen);
pdest_frame->nFilledLen += h264_scratch.nFilledLen;
h264_scratch.nFilledLen = 0;
}
else
{
DEBUG_PRINT_ERROR("\nERROR:Destination buffer overflow for H264");
return OMX_ErrorBadParameter;
}
pdest_frame->nTimeStamp = psource_frame->nTimeStamp;
pdest_frame->nFlags = psource_frame->nFlags;
DEBUG_PRINT_LOW("\n Frame Found start Decoding Size =%d TimeStamp = %x",
pdest_frame->nFilledLen,pdest_frame->nTimeStamp);
DEBUG_PRINT_LOW("\n Found a frame size = %d number = %d",
pdest_frame->nFilledLen,frame_count++);
/*Push the frame to the Decoder*/
if (empty_this_buffer_proxy(hComp,pdest_frame) != OMX_ErrorNone)
{
return OMX_ErrorBadParameter;
}
if(m_event_port_settings_sent)
{
gate_input_buffers = true;
return OMX_ErrorNone;
}
frame_count++;
pdest_frame = NULL;
}
else
{
DEBUG_PRINT_LOW("\n Last frame in else dest addr %p size %d",
pdest_frame,h264_scratch.nFilledLen);
genarte_edb = OMX_FALSE;
}
}
if(genarte_edb)
{
m_cb.EmptyBufferDone (hComp,m_app_data,psource_frame);
psource_frame = NULL;
if (m_input_pending_q.m_size && !gate_input_buffers)
{
DEBUG_PRINT_LOW("\n Pull Next source Buffer %p",psource_frame);
m_input_pending_q.pop_entry(&address,&p2,&id);
psource_frame = (OMX_BUFFERHEADERTYPE *) address;
DEBUG_PRINT_LOW("\nNext source Buffer flag %d length %d",
psource_frame->nFlags,psource_frame->nFilledLen);
}
}
}
return OMX_ErrorNone;
}
OMX_ERRORTYPE omx_vdec::push_input_vc1 (OMX_HANDLETYPE hComp)
{
OMX_U8 *buf, *pdest;
OMX_U32 partial_frame = 1;
OMX_U32 buf_len, dest_len;
if(frame_count == 0)
{
DEBUG_PRINT_LOW("\nFirst i/p buffer for VC1 arbitrary bytes\n");
if(!m_vendor_config.pData)
{
DEBUG_PRINT_LOW("\nCheck profile type in 1st source buffer\n");
buf = psource_frame->pBuffer;
buf_len = psource_frame->nFilledLen;
if ((*((OMX_U32 *) buf) & VC1_SP_MP_START_CODE_MASK) ==
VC1_SP_MP_START_CODE)
{
m_vc1_profile = VC1_SP_MP_RCV;
}
else if(*((OMX_U32 *) buf) & VC1_AP_SEQ_START_CODE)
{
m_vc1_profile = VC1_AP;
}
else
{
DEBUG_PRINT_ERROR("\nInvalid sequence layer in first buffer\n");
return OMX_ErrorStreamCorrupt;
}
}
else
{
pdest = pdest_frame->pBuffer + pdest_frame->nFilledLen +
pdest_frame->nOffset;
dest_len = pdest_frame->nAllocLen - (pdest_frame->nFilledLen +
pdest_frame->nOffset);
if(dest_len < m_vendor_config.nDataSize)
{
DEBUG_PRINT_ERROR("\nDestination buffer full\n");
return OMX_ErrorBadParameter;
}
else
{
memcpy(pdest, m_vendor_config.pData, m_vendor_config.nDataSize);
pdest_frame->nFilledLen += m_vendor_config.nDataSize;
}
}
}
switch(m_vc1_profile)
{
case VC1_AP:
DEBUG_PRINT_LOW("\n VC1 AP, hence parse using frame start code");
if (push_input_sc_codec(hComp) != OMX_ErrorNone)
{
DEBUG_PRINT_ERROR("\n Error In Parsing VC1 AP start code");
return OMX_ErrorBadParameter;
}
break;
case VC1_SP_MP_RCV:
default:
DEBUG_PRINT_ERROR("\n Unsupported VC1 profile in ArbitraryBytes Mode\n");
return OMX_ErrorBadParameter;
}
return OMX_ErrorNone;
}
bool omx_vdec::register_output_buffers()
{
struct vdec_ioctl_msg ioctl_msg;
struct vdec_setbuffer_cmd setbuffers;
int i = 0;
unsigned p1 =0,p2 = 0,ident = 0;
for(i=0;i<m_out_buf_count;i++)
{
setbuffers.buffer_type = VDEC_BUFFER_TYPE_OUTPUT;
memcpy (&setbuffers.buffer,&driver_context.ptr_outputbuffer [i],
sizeof (vdec_bufferpayload));
ioctl_msg.inputparam = &setbuffers;
ioctl_msg.outputparam = NULL;
DEBUG_PRINT_LOW("\n Set the Output Buffer");
if (ioctl (driver_context.video_driver_fd,VDEC_IOCTL_SET_BUFFER,
&ioctl_msg) < 0)
{
DEBUG_PRINT_ERROR("\n Set output buffer failed");
return false;
}
}
if(gate_output_buffers)
{
/*Generate FBD for all Buffers in the FTBq*/
pthread_mutex_lock(&m_lock);
DEBUG_PRINT_LOW("\n Initiate Pushing Output Buffers");
while (m_ftb_q.m_size)
{
m_ftb_q.pop_entry(&p1,&p2,&ident);
if(ident == OMX_COMPONENT_GENERATE_FTB )
{
if (fill_this_buffer_proxy ((OMX_HANDLETYPE)p1,
(OMX_BUFFERHEADERTYPE *)p2) != OMX_ErrorNone)
{
DEBUG_PRINT_ERROR("\n fill_this_buffer_proxy failure");
omx_report_error ();
return false;
}
}
else if (ident == OMX_COMPONENT_GENERATE_FBD)
{
fill_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1);
}
}
gate_output_buffers = false;
pthread_mutex_unlock(&m_lock);
}
return true;
}
bool omx_vdec::align_pmem_buffers(int pmem_fd, OMX_U32 buffer_size,
OMX_U32 alignment)
{
//TODO: figure out if this is really necessary (PMEM_ALLOCATE_ALIGNED is a
// QCOM extension to pmem
return true;
#if 0
struct pmem_allocation allocation;
allocation.size = buffer_size;
allocation.align = clip2(alignment);
if (allocation.align < 4096)
{
allocation.align = 4096;
}
if (ioctl(pmem_fd, PMEM_ALLOCATE_ALIGNED, &allocation) < 0)
{
DEBUG_PRINT_ERROR("\n Aligment failed with pmem driver");
return false;
}
return true;
#endif
}