| /*-------------------------------------------------------------------------- |
| Copyright (c) 2010 - 2014, The Linux Foundation. All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions are met: |
| * Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| * Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| * Neither the name of The Linux Foundation nor |
| the names of its contributors may be used to endorse or promote |
| products derived from this software without specific prior written |
| permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| --------------------------------------------------------------------------*/ |
| |
| /*============================================================================ |
| O p e n M A X w r a p p e r s |
| O p e n M A X C o r e |
| |
| *//** @file omx_vdec.cpp |
| This module contains the implementation of the OpenMAX core & component. |
| |
| *//*========================================================================*/ |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // Include Files |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| #define __STDC_FORMAT_MACROS |
| #include <inttypes.h> |
| |
| #include <string.h> |
| #include <pthread.h> |
| #include <sys/prctl.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include "omx_vdec.h" |
| #include <fcntl.h> |
| #include <limits.h> |
| #include <stdlib.h> |
| #include <media/hardware/HardwareAPI.h> |
| #include <media/msm_media_info.h> |
| |
| #ifndef _ANDROID_ |
| #include <sys/ioctl.h> |
| #include <sys/mman.h> |
| #endif //_ANDROID_ |
| |
| #ifdef _ANDROID_ |
| #include <cutils/properties.h> |
| #undef USE_EGL_IMAGE_GPU |
| #endif |
| |
| #include <qdMetaData.h> |
| |
| #ifdef _ANDROID_ |
| #include "DivXDrmDecrypt.h" |
| #endif //_ANDROID_ |
| |
| #ifdef ANDROID_JELLYBEAN_MR2 |
| #include "QComOMXMetadata.h" |
| #endif |
| |
| #ifdef USE_EGL_IMAGE_GPU |
| #include <EGL/egl.h> |
| #include <EGL/eglQCOM.h> |
| #define EGL_BUFFER_HANDLE 0x4F00 |
| #define EGL_BUFFER_OFFSET 0x4F01 |
| #endif |
| |
| #define BUFFER_LOG_LOC "/data/misc/media" |
| |
| #ifdef OUTPUT_EXTRADATA_LOG |
| FILE *outputExtradataFile; |
| char output_extradata_filename [] = "/data/misc/media/extradata"; |
| #endif |
| |
| #define DEFAULT_FPS 30 |
| #define MAX_SUPPORTED_FPS 120 |
| #define DEFAULT_WIDTH_ALIGNMENT 128 |
| #define DEFAULT_HEIGHT_ALIGNMENT 32 |
| |
| #define VC1_SP_MP_START_CODE 0xC5000000 |
| #define VC1_SP_MP_START_CODE_MASK 0xFF000000 |
| #define VC1_AP_SEQ_START_CODE 0x0F010000 |
| #define VC1_STRUCT_C_PROFILE_MASK 0xF0 |
| #define VC1_STRUCT_B_LEVEL_MASK 0xE0000000 |
| #define VC1_SIMPLE_PROFILE 0 |
| #define VC1_MAIN_PROFILE 1 |
| #define VC1_ADVANCE_PROFILE 3 |
| #define VC1_SIMPLE_PROFILE_LOW_LEVEL 0 |
| #define VC1_SIMPLE_PROFILE_MED_LEVEL 2 |
| #define VC1_STRUCT_C_LEN 4 |
| #define VC1_STRUCT_C_POS 8 |
| #define VC1_STRUCT_A_POS 12 |
| #define VC1_STRUCT_B_POS 24 |
| #define VC1_SEQ_LAYER_SIZE 36 |
| #define POLL_TIMEOUT 0x7fffffff |
| |
| #define MEM_DEVICE "/dev/ion" |
| #define MEM_HEAP_ID ION_CP_MM_HEAP_ID |
| |
| #ifdef _ANDROID_ |
| extern "C" { |
| #include<utils/Log.h> |
| } |
| #endif//_ANDROID_ |
| |
| #define SZ_4K 0x1000 |
| #define SZ_1M 0x100000 |
| |
| #define Log2(number, power) { OMX_U32 temp = number; power = 0; while( (0 == (temp & 0x1)) && power < 16) { temp >>=0x1; power++; } } |
| #define Q16ToFraction(q,num,den) { OMX_U32 power; Log2(q,power); num = q >> power; den = 0x1 << (16 - power); } |
| #define EXTRADATA_IDX(__num_planes) (__num_planes - 1) |
| #define ALIGN(x, to_align) ((((unsigned) x) + (to_align - 1)) & ~(to_align - 1)) |
| |
| #ifndef DISABLE_EXTRADATA |
| #define DEFAULT_EXTRADATA (OMX_INTERLACE_EXTRADATA | OMX_VUI_DISPLAY_INFO_EXTRADATA) |
| #endif |
| |
| #define DEFAULT_CONCEAL_COLOR "32784" //0x8010, black by default |
| |
| |
| static OMX_U32 maxSmoothStreamingWidth = 1920; |
| static OMX_U32 maxSmoothStreamingHeight = 1088; |
| |
| void* async_message_thread (void *input) |
| { |
| OMX_BUFFERHEADERTYPE *buffer; |
| struct v4l2_plane plane[VIDEO_MAX_PLANES]; |
| struct pollfd pfd; |
| struct v4l2_buffer v4l2_buf; |
| memset((void *)&v4l2_buf,0,sizeof(v4l2_buf)); |
| struct v4l2_event dqevent; |
| omx_vdec *omx = reinterpret_cast<omx_vdec*>(input); |
| pfd.events = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLRDBAND | POLLPRI; |
| pfd.fd = omx->drv_ctx.video_driver_fd; |
| int error_code = 0,rc=0,bytes_read = 0,bytes_written = 0; |
| DEBUG_PRINT_HIGH("omx_vdec: Async thread start"); |
| prctl(PR_SET_NAME, (unsigned long)"VideoDecCallBackThread", 0, 0, 0); |
| while (1) { |
| rc = poll(&pfd, 1, POLL_TIMEOUT); |
| if (!rc) { |
| DEBUG_PRINT_ERROR("Poll timedout"); |
| break; |
| } else if (rc < 0) { |
| DEBUG_PRINT_ERROR("Error while polling: %d", rc); |
| break; |
| } |
| if ((pfd.revents & POLLIN) || (pfd.revents & POLLRDNORM)) { |
| struct vdec_msginfo vdec_msg; |
| memset(&vdec_msg, 0, sizeof(vdec_msg)); |
| v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| v4l2_buf.memory = V4L2_MEMORY_USERPTR; |
| v4l2_buf.length = omx->drv_ctx.num_planes; |
| v4l2_buf.m.planes = plane; |
| while (!ioctl(pfd.fd, VIDIOC_DQBUF, &v4l2_buf)) { |
| vdec_msg.msgcode=VDEC_MSG_RESP_OUTPUT_BUFFER_DONE; |
| vdec_msg.status_code=VDEC_S_SUCCESS; |
| vdec_msg.msgdata.output_frame.client_data=(void*)&v4l2_buf; |
| vdec_msg.msgdata.output_frame.len=plane[0].bytesused; |
| vdec_msg.msgdata.output_frame.bufferaddr=(void*)plane[0].m.userptr; |
| vdec_msg.msgdata.output_frame.time_stamp= ((uint64_t)v4l2_buf.timestamp.tv_sec * (uint64_t)1000000) + |
| (uint64_t)v4l2_buf.timestamp.tv_usec; |
| if (vdec_msg.msgdata.output_frame.len) { |
| vdec_msg.msgdata.output_frame.framesize.left = plane[0].reserved[2]; |
| vdec_msg.msgdata.output_frame.framesize.top = plane[0].reserved[3]; |
| vdec_msg.msgdata.output_frame.framesize.right = plane[0].reserved[4]; |
| vdec_msg.msgdata.output_frame.framesize.bottom = plane[0].reserved[5]; |
| vdec_msg.msgdata.output_frame.picsize.frame_width = plane[0].reserved[6]; |
| vdec_msg.msgdata.output_frame.picsize.frame_height = plane[0].reserved[7]; |
| } |
| if (omx->async_message_process(input,&vdec_msg) < 0) { |
| DEBUG_PRINT_HIGH("async_message_thread Exited"); |
| break; |
| } |
| } |
| } |
| if ((pfd.revents & POLLOUT) || (pfd.revents & POLLWRNORM)) { |
| struct vdec_msginfo vdec_msg; |
| v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| v4l2_buf.memory = V4L2_MEMORY_USERPTR; |
| v4l2_buf.length = 1; |
| v4l2_buf.m.planes = plane; |
| while (!ioctl(pfd.fd, VIDIOC_DQBUF, &v4l2_buf)) { |
| vdec_msg.msgcode=VDEC_MSG_RESP_INPUT_BUFFER_DONE; |
| vdec_msg.status_code=VDEC_S_SUCCESS; |
| vdec_msg.msgdata.input_frame_clientdata=(void*)&v4l2_buf; |
| if (omx->async_message_process(input,&vdec_msg) < 0) { |
| DEBUG_PRINT_HIGH("async_message_thread Exited"); |
| break; |
| } |
| } |
| } |
| if (pfd.revents & POLLPRI) { |
| rc = ioctl(pfd.fd, VIDIOC_DQEVENT, &dqevent); |
| if (dqevent.type == V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT ) { |
| struct vdec_msginfo vdec_msg; |
| vdec_msg.msgcode=VDEC_MSG_EVT_CONFIG_CHANGED; |
| vdec_msg.status_code=VDEC_S_SUCCESS; |
| DEBUG_PRINT_HIGH("VIDC Port Reconfig recieved insufficient"); |
| if (omx->async_message_process(input,&vdec_msg) < 0) { |
| DEBUG_PRINT_HIGH("async_message_thread Exited"); |
| break; |
| } |
| } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_FLUSH_DONE) { |
| struct vdec_msginfo vdec_msg; |
| vdec_msg.msgcode=VDEC_MSG_RESP_FLUSH_INPUT_DONE; |
| vdec_msg.status_code=VDEC_S_SUCCESS; |
| DEBUG_PRINT_HIGH("VIDC Input Flush Done Recieved"); |
| if (omx->async_message_process(input,&vdec_msg) < 0) { |
| DEBUG_PRINT_HIGH("async_message_thread Exited"); |
| break; |
| } |
| vdec_msg.msgcode=VDEC_MSG_RESP_FLUSH_OUTPUT_DONE; |
| vdec_msg.status_code=VDEC_S_SUCCESS; |
| DEBUG_PRINT_HIGH("VIDC Output Flush Done Recieved"); |
| if (omx->async_message_process(input,&vdec_msg) < 0) { |
| DEBUG_PRINT_HIGH("async_message_thread Exited"); |
| break; |
| } |
| } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_CLOSE_DONE) { |
| DEBUG_PRINT_HIGH("VIDC Close Done Recieved and async_message_thread Exited"); |
| break; |
| } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_HW_OVERLOAD) { |
| struct vdec_msginfo vdec_msg; |
| vdec_msg.msgcode=VDEC_MSG_EVT_HW_OVERLOAD; |
| vdec_msg.status_code=VDEC_S_SUCCESS; |
| DEBUG_PRINT_ERROR("HW Overload received"); |
| if (omx->async_message_process(input,&vdec_msg) < 0) { |
| DEBUG_PRINT_HIGH("async_message_thread Exited"); |
| break; |
| } |
| } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED) { |
| struct vdec_msginfo vdec_msg; |
| vdec_msg.msgcode=VDEC_MSG_EVT_HW_UNSUPPORTED; |
| vdec_msg.status_code=VDEC_S_SUCCESS; |
| DEBUG_PRINT_ERROR("HW Unsupported received"); |
| if (omx->async_message_process(input,&vdec_msg) < 0) { |
| DEBUG_PRINT_HIGH("async_message_thread Exited"); |
| break; |
| } |
| } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_SYS_ERROR) { |
| struct vdec_msginfo vdec_msg; |
| vdec_msg.msgcode=VDEC_MSG_EVT_HW_ERROR; |
| vdec_msg.status_code=VDEC_S_SUCCESS; |
| DEBUG_PRINT_HIGH("SYS Error Recieved"); |
| if (omx->async_message_process(input,&vdec_msg) < 0) { |
| DEBUG_PRINT_HIGH("async_message_thread Exited"); |
| break; |
| } |
| } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE) { |
| unsigned int *ptr = (unsigned int *)(void *)dqevent.u.data; |
| |
| DEBUG_PRINT_LOW("REFERENCE RELEASE EVENT RECVD fd = %d offset = %d", ptr[0], ptr[1]); |
| omx->buf_ref_remove(ptr[0], ptr[1]); |
| } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER) { |
| unsigned int *ptr = (unsigned int *)(void *)dqevent.u.data; |
| struct vdec_msginfo vdec_msg; |
| |
| DEBUG_PRINT_LOW("Release unqueued buffer event recvd fd = %d offset = %d", ptr[0], ptr[1]); |
| |
| v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| v4l2_buf.memory = V4L2_MEMORY_USERPTR; |
| v4l2_buf.length = omx->drv_ctx.num_planes; |
| v4l2_buf.m.planes = plane; |
| v4l2_buf.index = ptr[5]; |
| v4l2_buf.flags = 0; |
| |
| vdec_msg.msgcode=VDEC_MSG_RESP_OUTPUT_BUFFER_DONE; |
| vdec_msg.status_code=VDEC_S_SUCCESS; |
| vdec_msg.msgdata.output_frame.client_data = (void*)&v4l2_buf; |
| vdec_msg.msgdata.output_frame.len = 0; |
| vdec_msg.msgdata.output_frame.bufferaddr = (void*)(intptr_t)ptr[2]; |
| vdec_msg.msgdata.output_frame.time_stamp = ((uint64_t)ptr[3] * (uint64_t)1000000) + |
| (uint64_t)ptr[4]; |
| if (omx->async_message_process(input,&vdec_msg) < 0) { |
| DEBUG_PRINT_HIGH("async_message_thread Exitedn"); |
| break; |
| } |
| } |
| else { |
| DEBUG_PRINT_HIGH("VIDC Some Event recieved"); |
| continue; |
| } |
| } |
| } |
| DEBUG_PRINT_HIGH("omx_vdec: Async thread stop"); |
| 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"); |
| prctl(PR_SET_NAME, (unsigned long)"VideoDecMsgThread", 0, 0, 0); |
| while (1) { |
| |
| n = read(omx->m_pipe_in, &id, 1); |
| |
| if (0 == n) { |
| break; |
| } |
| |
| if (1 == n) { |
| omx->process_event_cb(omx, id); |
| } |
| if ((n < 0) && (errno != EINTR)) { |
| DEBUG_PRINT_LOW("ERROR: read from pipe failed, ret %d errno %d", n, errno); |
| break; |
| } |
| } |
| DEBUG_PRINT_HIGH("omx_vdec: message thread stop"); |
| 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", id,omx->m_pipe_out); |
| ret_value = write(omx->m_pipe_out, &id, 1); |
| DEBUG_PRINT_LOW("post_message to pipe done %d",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 long p1, unsigned long p2, unsigned long 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", __func__); |
| } |
| return ret; |
| } |
| |
| // omx cmd queue pop |
| bool omx_vdec::omx_cmd_queue::pop_entry(unsigned long *p1, unsigned long *p2, unsigned long *id) |
| { |
| bool ret = true; |
| if (m_size > 0) { |
| *id = m_q[m_read].id; |
| *p1 = m_q[m_read].param1; |
| *p2 = m_q[m_read].param2; |
| // Move the read pointer ahead |
| ++m_read; |
| --m_size; |
| if (m_read >= OMX_CORE_CONTROL_CMDQ_SIZE) { |
| m_read = 0; |
| } |
| } else { |
| ret = false; |
| } |
| return ret; |
| } |
| |
| // Retrieve the first mesg type in the queue |
| unsigned omx_vdec::omx_cmd_queue::get_q_msg_type() |
| { |
| return m_q[m_read].id; |
| } |
| |
| #ifdef _ANDROID_ |
| omx_vdec::ts_arr_list::ts_arr_list() |
| { |
| //initialize timestamps array |
| memset(m_ts_arr_list, 0, ( sizeof(ts_entry) * MAX_NUM_INPUT_OUTPUT_BUFFERS) ); |
| } |
| omx_vdec::ts_arr_list::~ts_arr_list() |
| { |
| //free m_ts_arr_list? |
| } |
| |
| bool omx_vdec::ts_arr_list::insert_ts(OMX_TICKS ts) |
| { |
| bool ret = true; |
| bool duplicate_ts = false; |
| int idx = 0; |
| |
| //insert at the first available empty location |
| for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) { |
| if (!m_ts_arr_list[idx].valid) { |
| //found invalid or empty entry, save timestamp |
| m_ts_arr_list[idx].valid = true; |
| m_ts_arr_list[idx].timestamp = ts; |
| DEBUG_PRINT_LOW("Insert_ts(): Inserting TIMESTAMP (%lld) at idx (%d)", |
| ts, idx); |
| break; |
| } |
| } |
| |
| if (idx == MAX_NUM_INPUT_OUTPUT_BUFFERS) { |
| DEBUG_PRINT_LOW("Timestamp array list is FULL. Unsuccessful insert"); |
| ret = false; |
| } |
| return ret; |
| } |
| |
| bool omx_vdec::ts_arr_list::pop_min_ts(OMX_TICKS &ts) |
| { |
| bool ret = true; |
| int min_idx = -1; |
| OMX_TICKS min_ts = 0; |
| int idx = 0; |
| |
| for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) { |
| |
| if (m_ts_arr_list[idx].valid) { |
| //found valid entry, save index |
| if (min_idx < 0) { |
| //first valid entry |
| min_ts = m_ts_arr_list[idx].timestamp; |
| min_idx = idx; |
| } else if (m_ts_arr_list[idx].timestamp < min_ts) { |
| min_ts = m_ts_arr_list[idx].timestamp; |
| min_idx = idx; |
| } |
| } |
| |
| } |
| |
| if (min_idx < 0) { |
| //no valid entries found |
| DEBUG_PRINT_LOW("Timestamp array list is empty. Unsuccessful pop"); |
| ts = 0; |
| ret = false; |
| } else { |
| ts = m_ts_arr_list[min_idx].timestamp; |
| m_ts_arr_list[min_idx].valid = false; |
| DEBUG_PRINT_LOW("Pop_min_ts:Timestamp (%lld), index(%d)", |
| ts, min_idx); |
| } |
| |
| return ret; |
| |
| } |
| |
| |
| bool omx_vdec::ts_arr_list::reset_ts_list() |
| { |
| bool ret = true; |
| int idx = 0; |
| |
| DEBUG_PRINT_LOW("reset_ts_list(): Resetting timestamp array list"); |
| for ( ; idx < MAX_NUM_INPUT_OUTPUT_BUFFERS; idx++) { |
| m_ts_arr_list[idx].valid = false; |
| } |
| return ret; |
| } |
| #endif |
| |
| // factory function executed by the core to create instances |
| void *get_omx_component_factory_fn(void) |
| { |
| return (new omx_vdec); |
| } |
| |
| #ifdef _ANDROID_ |
| #ifdef USE_ION |
| VideoHeap::VideoHeap(int devicefd, size_t size, void* base, |
| ion_user_handle_t handle, int ionMapfd) |
| { |
| (void) devicefd; |
| (void) size; |
| (void) base; |
| (void) handle; |
| (void) ionMapfd; |
| // ionInit(devicefd, base, size, 0 , MEM_DEVICE,handle,ionMapfd); |
| } |
| #else |
| VideoHeap::VideoHeap(int fd, size_t size, void* base) |
| { |
| // dup file descriptor, map once, use pmem |
| init(dup(fd), base, size, 0 , MEM_DEVICE); |
| } |
| #endif |
| #endif // _ANDROID_ |
| /* ====================================================================== |
| FUNCTION |
| omx_vdec::omx_vdec |
| |
| DESCRIPTION |
| Constructor |
| |
| PARAMETERS |
| None |
| |
| RETURN VALUE |
| None. |
| ========================================================================== */ |
| omx_vdec::omx_vdec(): m_error_propogated(false), |
| m_state(OMX_StateInvalid), |
| m_app_data(NULL), |
| m_inp_mem_ptr(NULL), |
| m_out_mem_ptr(NULL), |
| input_flush_progress (false), |
| output_flush_progress (false), |
| input_use_buffer (false), |
| output_use_buffer (false), |
| ouput_egl_buffers(false), |
| m_use_output_pmem(OMX_FALSE), |
| m_out_mem_region_smi(OMX_FALSE), |
| m_out_pvt_entry_pmem(OMX_FALSE), |
| pending_input_buffers(0), |
| pending_output_buffers(0), |
| m_out_bm_count(0), |
| m_inp_bm_count(0), |
| m_inp_bPopulated(OMX_FALSE), |
| m_out_bPopulated(OMX_FALSE), |
| m_flags(0), |
| #ifdef _ANDROID_ |
| m_heap_ptr(NULL), |
| #endif |
| m_inp_bEnabled(OMX_TRUE), |
| m_out_bEnabled(OMX_TRUE), |
| m_in_alloc_cnt(0), |
| m_platform_list(NULL), |
| m_platform_entry(NULL), |
| m_pmem_info(NULL), |
| h264_parser(NULL), |
| arbitrary_bytes (true), |
| psource_frame (NULL), |
| pdest_frame (NULL), |
| m_inp_heap_ptr (NULL), |
| m_phdr_pmem_ptr(NULL), |
| m_heap_inp_bm_count (0), |
| codec_type_parse ((codec_type)0), |
| first_frame_meta (true), |
| frame_count (0), |
| nal_count (0), |
| nal_length(0), |
| look_ahead_nal (false), |
| first_frame(0), |
| first_buffer(NULL), |
| first_frame_size (0), |
| m_device_file_ptr(NULL), |
| m_vc1_profile((vc1_profile_type)0), |
| h264_last_au_ts(LLONG_MAX), |
| h264_last_au_flags(0), |
| m_disp_hor_size(0), |
| m_disp_vert_size(0), |
| prev_ts(LLONG_MAX), |
| rst_prev_ts(true), |
| frm_int(0), |
| in_reconfig(false), |
| m_display_id(NULL), |
| client_extradata(0), |
| m_reject_avc_1080p_mp (0), |
| #ifdef _ANDROID_ |
| m_enable_android_native_buffers(OMX_FALSE), |
| m_use_android_native_buffers(OMX_FALSE), |
| iDivXDrmDecrypt(NULL), |
| #endif |
| m_desc_buffer_ptr(NULL), |
| secure_mode(false), |
| m_other_extradata(NULL), |
| m_profile(0), |
| client_set_fps(false), |
| m_last_rendered_TS(-1), |
| m_queued_codec_config_count(0), |
| secure_scaling_to_non_secure_opb(false) |
| { |
| /* Assumption is that , to begin with , we have all the frames with decoder */ |
| DEBUG_PRINT_HIGH("In %u bit OMX vdec Constructor", (unsigned int)sizeof(long) * 8); |
| memset(&m_debug,0,sizeof(m_debug)); |
| #ifdef _ANDROID_ |
| char property_value[PROPERTY_VALUE_MAX] = {0}; |
| property_get("vidc.debug.level", property_value, "1"); |
| debug_level = atoi(property_value); |
| property_value[0] = '\0'; |
| |
| DEBUG_PRINT_HIGH("In OMX vdec Constructor"); |
| |
| property_get("vidc.dec.debug.perf", property_value, "0"); |
| perf_flag = atoi(property_value); |
| if (perf_flag) { |
| DEBUG_PRINT_HIGH("vidc.dec.debug.perf is %d", perf_flag); |
| dec_time.start(); |
| proc_frms = latency = 0; |
| } |
| prev_n_filled_len = 0; |
| property_value[0] = '\0'; |
| property_get("vidc.dec.debug.ts", property_value, "0"); |
| m_debug_timestamp = atoi(property_value); |
| DEBUG_PRINT_HIGH("vidc.dec.debug.ts value is %d",m_debug_timestamp); |
| if (m_debug_timestamp) { |
| time_stamp_dts.set_timestamp_reorder_mode(true); |
| time_stamp_dts.enable_debug_print(true); |
| } |
| |
| property_value[0] = '\0'; |
| property_get("vidc.dec.debug.concealedmb", property_value, "0"); |
| m_debug_concealedmb = atoi(property_value); |
| DEBUG_PRINT_HIGH("vidc.dec.debug.concealedmb value is %d",m_debug_concealedmb); |
| |
| property_value[0] = '\0'; |
| property_get("vidc.dec.profile.check", property_value, "0"); |
| m_reject_avc_1080p_mp = atoi(property_value); |
| DEBUG_PRINT_HIGH("vidc.dec.profile.check value is %d",m_reject_avc_1080p_mp); |
| |
| property_value[0] = '\0'; |
| property_get("vidc.dec.log.in", property_value, "0"); |
| m_debug.in_buffer_log = atoi(property_value); |
| |
| property_value[0] = '\0'; |
| property_get("vidc.dec.log.out", property_value, "0"); |
| m_debug.out_buffer_log = atoi(property_value); |
| sprintf(m_debug.log_loc, "%s", BUFFER_LOG_LOC); |
| |
| property_value[0] = '\0'; |
| property_get("vidc.log.loc", property_value, ""); |
| if (*property_value) |
| strlcpy(m_debug.log_loc, property_value, PROPERTY_VALUE_MAX); |
| |
| property_value[0] = '\0'; |
| property_get("vidc.dec.120fps.enabled", property_value, "0"); |
| |
| //if this feature is not enabled then reset this value -ve |
| if(atoi(property_value)) { |
| DEBUG_PRINT_LOW("feature 120 FPS decode enabled"); |
| m_last_rendered_TS = 0; |
| } |
| |
| property_value[0] = '\0'; |
| property_get("vidc.dec.debug.dyn.disabled", property_value, "0"); |
| m_disable_dynamic_buf_mode = atoi(property_value); |
| DEBUG_PRINT_HIGH("vidc.dec.debug.dyn.disabled value is %d",m_disable_dynamic_buf_mode); |
| |
| #endif |
| memset(&m_cmp,0,sizeof(m_cmp)); |
| memset(&m_cb,0,sizeof(m_cb)); |
| memset (&drv_ctx,0,sizeof(drv_ctx)); |
| memset (&h264_scratch,0,sizeof (OMX_BUFFERHEADERTYPE)); |
| memset (m_hwdevice_name,0,sizeof(m_hwdevice_name)); |
| memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) ); |
| memset(&m_custom_buffersize, 0, sizeof(m_custom_buffersize)); |
| m_demux_entries = 0; |
| msg_thread_id = 0; |
| async_thread_id = 0; |
| msg_thread_created = false; |
| async_thread_created = false; |
| #ifdef _ANDROID_ICS_ |
| memset(&native_buffer, 0 ,(sizeof(struct nativebuffer) * MAX_NUM_INPUT_OUTPUT_BUFFERS)); |
| #endif |
| memset(&drv_ctx.extradata_info, 0, sizeof(drv_ctx.extradata_info)); |
| |
| /* invalidate m_frame_pack_arrangement */ |
| memset(&m_frame_pack_arrangement, 0, sizeof(OMX_QCOM_FRAME_PACK_ARRANGEMENT)); |
| m_frame_pack_arrangement.cancel_flag = 1; |
| |
| drv_ctx.timestamp_adjust = false; |
| drv_ctx.video_driver_fd = -1; |
| m_vendor_config.pData = NULL; |
| pthread_mutex_init(&m_lock, NULL); |
| pthread_mutex_init(&c_lock, NULL); |
| sem_init(&m_cmd_lock,0,0); |
| sem_init(&m_safe_flush, 0, 0); |
| streaming[CAPTURE_PORT] = |
| streaming[OUTPUT_PORT] = false; |
| #ifdef _ANDROID_ |
| char extradata_value[PROPERTY_VALUE_MAX] = {0}; |
| property_get("vidc.dec.debug.extradata", extradata_value, "0"); |
| m_debug_extradata = atoi(extradata_value); |
| DEBUG_PRINT_HIGH("vidc.dec.debug.extradata value is %d",m_debug_extradata); |
| #endif |
| m_fill_output_msg = OMX_COMPONENT_GENERATE_FTB; |
| client_buffers.set_vdec_client(this); |
| dynamic_buf_mode = false; |
| out_dynamic_list = NULL; |
| is_down_scalar_enabled = false; |
| m_smoothstreaming_mode = false; |
| m_smoothstreaming_width = 0; |
| m_smoothstreaming_height = 0; |
| is_q6_platform = false; |
| } |
| |
| static const int event_type[] = { |
| V4L2_EVENT_MSM_VIDC_FLUSH_DONE, |
| V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT, |
| V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT, |
| V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE, |
| V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER, |
| V4L2_EVENT_MSM_VIDC_CLOSE_DONE, |
| V4L2_EVENT_MSM_VIDC_SYS_ERROR, |
| V4L2_EVENT_MSM_VIDC_HW_OVERLOAD, |
| V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED |
| }; |
| |
| static OMX_ERRORTYPE subscribe_to_events(int fd) |
| { |
| OMX_ERRORTYPE eRet = OMX_ErrorNone; |
| struct v4l2_event_subscription sub; |
| int array_sz = sizeof(event_type)/sizeof(int); |
| int i,rc; |
| if (fd < 0) { |
| DEBUG_PRINT_ERROR("Invalid input: %d", fd); |
| return OMX_ErrorBadParameter; |
| } |
| |
| for (i = 0; i < array_sz; ++i) { |
| memset(&sub, 0, sizeof(sub)); |
| sub.type = event_type[i]; |
| rc = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub); |
| if (rc) { |
| DEBUG_PRINT_ERROR("Failed to subscribe event: 0x%x", sub.type); |
| break; |
| } |
| } |
| if (i < array_sz) { |
| for (--i; i >=0 ; i--) { |
| memset(&sub, 0, sizeof(sub)); |
| sub.type = event_type[i]; |
| rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub); |
| if (rc) |
| DEBUG_PRINT_ERROR("Failed to unsubscribe event: 0x%x", sub.type); |
| } |
| eRet = OMX_ErrorNotImplemented; |
| } |
| return eRet; |
| } |
| |
| |
| static OMX_ERRORTYPE unsubscribe_to_events(int fd) |
| { |
| OMX_ERRORTYPE eRet = OMX_ErrorNone; |
| struct v4l2_event_subscription sub; |
| int array_sz = sizeof(event_type)/sizeof(int); |
| int i,rc; |
| if (fd < 0) { |
| DEBUG_PRINT_ERROR("Invalid input: %d", fd); |
| return OMX_ErrorBadParameter; |
| } |
| |
| for (i = 0; i < array_sz; ++i) { |
| memset(&sub, 0, sizeof(sub)); |
| sub.type = event_type[i]; |
| rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub); |
| if (rc) { |
| DEBUG_PRINT_ERROR("Failed to unsubscribe event: 0x%x", sub.type); |
| break; |
| } |
| } |
| return eRet; |
| } |
| |
| /* ====================================================================== |
| FUNCTION |
| omx_vdec::~omx_vdec |
| |
| DESCRIPTION |
| Destructor |
| |
| PARAMETERS |
| None |
| |
| RETURN VALUE |
| None. |
| ========================================================================== */ |
| omx_vdec::~omx_vdec() |
| { |
| m_pmem_info = NULL; |
| struct v4l2_decoder_cmd dec; |
| DEBUG_PRINT_HIGH("In OMX vdec Destructor"); |
| if (m_pipe_in) close(m_pipe_in); |
| if (m_pipe_out) close(m_pipe_out); |
| m_pipe_in = -1; |
| m_pipe_out = -1; |
| DEBUG_PRINT_HIGH("Waiting on OMX Msg Thread exit"); |
| if (msg_thread_created) |
| pthread_join(msg_thread_id,NULL); |
| DEBUG_PRINT_HIGH("Waiting on OMX Async Thread exit"); |
| dec.cmd = V4L2_DEC_CMD_STOP; |
| if (drv_ctx.video_driver_fd >=0 ) { |
| if (ioctl(drv_ctx.video_driver_fd, VIDIOC_DECODER_CMD, &dec)) |
| DEBUG_PRINT_ERROR("STOP Command failed"); |
| } |
| if (async_thread_created) |
| pthread_join(async_thread_id,NULL); |
| unsubscribe_to_events(drv_ctx.video_driver_fd); |
| close(drv_ctx.video_driver_fd); |
| pthread_mutex_destroy(&m_lock); |
| pthread_mutex_destroy(&c_lock); |
| sem_destroy(&m_cmd_lock); |
| if (perf_flag) { |
| DEBUG_PRINT_HIGH("--> TOTAL PROCESSING TIME"); |
| dec_time.end(); |
| } |
| DEBUG_PRINT_INFO("Exit OMX vdec Destructor: fd=%d",drv_ctx.video_driver_fd); |
| } |
| |
| int release_buffers(omx_vdec* obj, enum vdec_buffer buffer_type) |
| { |
| struct v4l2_requestbuffers bufreq; |
| int rc = 0; |
| if (buffer_type == VDEC_BUFFER_TYPE_OUTPUT) { |
| bufreq.memory = V4L2_MEMORY_USERPTR; |
| bufreq.count = 0; |
| bufreq.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| rc = ioctl(obj->drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); |
| } else if(buffer_type == VDEC_BUFFER_TYPE_INPUT) { |
| bufreq.memory = V4L2_MEMORY_USERPTR; |
| bufreq.count = 0; |
| bufreq.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| rc = ioctl(obj->drv_ctx.video_driver_fd,VIDIOC_REQBUFS, &bufreq); |
| } |
| return rc; |
| } |
| |
| /* ====================================================================== |
| FUNCTION |
| omx_vdec::OMXCntrlProcessMsgCb |
| |
| DESCRIPTION |
| IL Client callbacks are generated through this routine. The decoder |
| provides the thread context for this routine. |
| |
| PARAMETERS |
| ctxt -- Context information related to the self. |
| id -- Event identifier. This could be any of the following: |
| 1. Command completion event |
| 2. Buffer done callback event |
| 3. Frame done callback event |
| |
| RETURN VALUE |
| None. |
| |
| ========================================================================== */ |
| void omx_vdec::process_event_cb(void *ctxt, unsigned char id) |
| { |
| unsigned long p1; // Parameter - 1 |
| unsigned long p2; // Parameter - 2 |
| unsigned long ident; |
| unsigned qsize=0; // qsize |
| omx_vdec *pThis = (omx_vdec *) ctxt; |
| |
| if (!pThis) { |
| DEBUG_PRINT_ERROR("ERROR: %s()::Context is incorrect, bailing out", |
| __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->m_state != OMX_StatePause) { |
| qsize = pThis->m_ftb_q.m_size; |
| if (qsize) { |
| pThis->m_ftb_q.pop_entry(&p1, &p2, &ident); |
| } |
| } |
| |
| if (qsize == 0 && pThis->m_state != OMX_StatePause) { |
| qsize = pThis->m_etb_q.m_size; |
| if (qsize) { |
| pThis->m_etb_q.pop_entry(&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("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("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 long)OMX_ErrorHardware) { |
| pThis->omx_report_error(); |
| } else { |
| pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, |
| OMX_EventError, p2, (OMX_U32)NULL, NULL ); |
| } |
| break; |
| |
| case OMX_CommandPortDisable: |
| DEBUG_PRINT_HIGH("OMX_CommandPortDisable complete for port [%lu]", p2); |
| if (BITMASK_PRESENT(&pThis->m_flags, |
| OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING)) { |
| BITMASK_SET(&pThis->m_flags, OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED); |
| break; |
| } |
| if (p2 == OMX_CORE_OUTPUT_PORT_INDEX) { |
| OMX_ERRORTYPE eRet = OMX_ErrorNone; |
| pThis->stream_off(OMX_CORE_OUTPUT_PORT_INDEX); |
| if (release_buffers(pThis, VDEC_BUFFER_TYPE_OUTPUT)) |
| DEBUG_PRINT_HIGH("Failed to release output buffers"); |
| OMX_ERRORTYPE eRet1 = pThis->get_buffer_req(&pThis->drv_ctx.op_buf); |
| pThis->in_reconfig = false; |
| if (eRet != OMX_ErrorNone) { |
| DEBUG_PRINT_ERROR("set_buffer_req failed eRet = %d",eRet); |
| pThis->omx_report_error(); |
| break; |
| } |
| } |
| pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, |
| OMX_EventCmdComplete, p1, p2, NULL ); |
| break; |
| case OMX_CommandPortEnable: |
| DEBUG_PRINT_HIGH("OMX_CommandPortEnable complete for port [%lu]", 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", __func__); |
| } |
| break; |
| case OMX_COMPONENT_GENERATE_ETB_ARBITRARY: |
| if (pThis->empty_this_buffer_proxy_arbitrary((OMX_HANDLETYPE)p1,\ |
| (OMX_BUFFERHEADERTYPE *)(intptr_t)p2) != OMX_ErrorNone) { |
| DEBUG_PRINT_ERROR("empty_this_buffer_proxy_arbitrary failure"); |
| pThis->omx_report_error (); |
| } |
| break; |
| case OMX_COMPONENT_GENERATE_ETB: { |
| OMX_ERRORTYPE iret; |
| iret = pThis->empty_this_buffer_proxy((OMX_HANDLETYPE)p1, (OMX_BUFFERHEADERTYPE *)p2); |
| if (iret == OMX_ErrorInsufficientResources) { |
| DEBUG_PRINT_ERROR("empty_this_buffer_proxy failure due to HW overload"); |
| pThis->omx_report_hw_overload (); |
| } else if (iret != OMX_ErrorNone) { |
| DEBUG_PRINT_ERROR("empty_this_buffer_proxy failure"); |
| pThis->omx_report_error (); |
| } |
| } |
| break; |
| |
| case OMX_COMPONENT_GENERATE_FTB: |
| if ( pThis->fill_this_buffer_proxy((OMX_HANDLETYPE)(intptr_t)p1,\ |
| (OMX_BUFFERHEADERTYPE *)(intptr_t)p2) != OMX_ErrorNone) { |
| DEBUG_PRINT_ERROR("fill_this_buffer_proxy failure"); |
| pThis->omx_report_error (); |
| } |
| break; |
| |
| case OMX_COMPONENT_GENERATE_COMMAND: |
| pThis->send_command_proxy(&pThis->m_cmp,(OMX_COMMANDTYPE)p1,\ |
| (OMX_U32)p2,(OMX_PTR)NULL); |
| break; |
| |
| case OMX_COMPONENT_GENERATE_EBD: |
| |
| if (p2 != VDEC_S_SUCCESS && p2 != VDEC_S_INPUT_BITSTREAM_ERR) { |
| DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_EBD failure"); |
| pThis->omx_report_error (); |
| } else { |
| if (p2 == VDEC_S_INPUT_BITSTREAM_ERR && p1) { |
| pThis->time_stamp_dts.remove_time_stamp( |
| ((OMX_BUFFERHEADERTYPE *)(intptr_t)p1)->nTimeStamp, |
| (pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) |
| ?true:false); |
| } |
| if ( pThis->empty_buffer_done(&pThis->m_cmp, |
| (OMX_BUFFERHEADERTYPE *)(intptr_t)p1) != OMX_ErrorNone) { |
| DEBUG_PRINT_ERROR("empty_buffer_done failure"); |
| pThis->omx_report_error (); |
| } |
| } |
| break; |
| case OMX_COMPONENT_GENERATE_INFO_FIELD_DROPPED: { |
| int64_t *timestamp = (int64_t *)(intptr_t)p1; |
| if (p1) { |
| pThis->time_stamp_dts.remove_time_stamp(*timestamp, |
| (pThis->drv_ctx.interlace != VDEC_InterlaceFrameProgressive) |
| ?true:false); |
| free(timestamp); |
| } |
| } |
| break; |
| case OMX_COMPONENT_GENERATE_FBD: |
| if (p2 != VDEC_S_SUCCESS) { |
| DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_FBD failure"); |
| pThis->omx_report_error (); |
| } else if ( pThis->fill_buffer_done(&pThis->m_cmp, |
| (OMX_BUFFERHEADERTYPE *)(intptr_t)p1) != OMX_ErrorNone ) { |
| DEBUG_PRINT_ERROR("fill_buffer_done failure"); |
| pThis->omx_report_error (); |
| } |
| break; |
| |
| case OMX_COMPONENT_GENERATE_EVENT_INPUT_FLUSH: |
| DEBUG_PRINT_HIGH("Driver flush i/p Port complete"); |
| if (!pThis->input_flush_progress) { |
| DEBUG_PRINT_HIGH("WARNING: Unexpected flush from driver"); |
| } else { |
| pThis->execute_input_flush(); |
| if (pThis->m_cb.EventHandler) { |
| if (p2 != VDEC_S_SUCCESS) { |
| DEBUG_PRINT_ERROR("OMX_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("Input Flush completed - Notify Client"); |
| pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, |
| OMX_EventCmdComplete,OMX_CommandFlush, |
| OMX_CORE_INPUT_PORT_INDEX,NULL ); |
| } |
| if (BITMASK_PRESENT(&pThis->m_flags, |
| OMX_COMPONENT_IDLE_PENDING)) { |
| if (pThis->stream_off(OMX_CORE_INPUT_PORT_INDEX)) { |
| DEBUG_PRINT_ERROR("Failed to call streamoff on OUTPUT Port"); |
| pThis->omx_report_error (); |
| } else { |
| pThis->streaming[OUTPUT_PORT] = false; |
| } |
| if (!pThis->output_flush_progress) { |
| DEBUG_PRINT_LOW("Input flush done hence issue stop"); |
| pThis->post_event ((unsigned int)NULL, VDEC_S_SUCCESS,\ |
| OMX_COMPONENT_GENERATE_STOP_DONE); |
| } |
| } |
| } |
| } else { |
| DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); |
| } |
| } |
| break; |
| |
| case OMX_COMPONENT_GENERATE_EVENT_OUTPUT_FLUSH: |
| DEBUG_PRINT_HIGH("Driver flush o/p Port complete"); |
| if (!pThis->output_flush_progress) { |
| DEBUG_PRINT_HIGH("WARNING: Unexpected flush from driver"); |
| } else { |
| pThis->execute_output_flush(); |
| if (pThis->m_cb.EventHandler) { |
| if (p2 != VDEC_S_SUCCESS) { |
| DEBUG_PRINT_ERROR("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("Notify Output Flush done"); |
| BITMASK_CLEAR (&pThis->m_flags,OMX_COMPONENT_OUTPUT_FLUSH_PENDING); |
| pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, |
| OMX_EventCmdComplete,OMX_CommandFlush, |
| OMX_CORE_OUTPUT_PORT_INDEX,NULL ); |
| } |
| if (BITMASK_PRESENT(&pThis->m_flags, |
| OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING)) { |
| DEBUG_PRINT_LOW("Internal flush complete"); |
| BITMASK_CLEAR (&pThis->m_flags, |
| OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING); |
| if (BITMASK_PRESENT(&pThis->m_flags, |
| OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED)) { |
| pThis->post_event(OMX_CommandPortDisable, |
| OMX_CORE_OUTPUT_PORT_INDEX, |
| OMX_COMPONENT_GENERATE_EVENT); |
| BITMASK_CLEAR (&pThis->m_flags, |
| OMX_COMPONENT_DISABLE_OUTPUT_DEFERRED); |
| BITMASK_CLEAR (&pThis->m_flags, |
| OMX_COMPONENT_OUTPUT_DISABLE_PENDING); |
| |
| } |
| } |
| |
| if (BITMASK_PRESENT(&pThis->m_flags ,OMX_COMPONENT_IDLE_PENDING)) { |
| if (pThis->stream_off(OMX_CORE_OUTPUT_PORT_INDEX)) { |
| DEBUG_PRINT_ERROR("Failed to call streamoff on CAPTURE Port"); |
| pThis->omx_report_error (); |
| break; |
| } |
| pThis->streaming[CAPTURE_PORT] = false; |
| if (!pThis->input_flush_progress) { |
| DEBUG_PRINT_LOW("Output flush done hence issue stop"); |
| pThis->post_event ((unsigned int)NULL, VDEC_S_SUCCESS,\ |
| OMX_COMPONENT_GENERATE_STOP_DONE); |
| } |
| } |
| } |
| } else { |
| DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); |
| } |
| } |
| break; |
| |
| case OMX_COMPONENT_GENERATE_START_DONE: |
| DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_START_DONE"); |
| |
| if (pThis->m_cb.EventHandler) { |
| if (p2 != VDEC_S_SUCCESS) { |
| DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_START_DONE Failure"); |
| pThis->omx_report_error (); |
| } else { |
| DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_START_DONE Success"); |
| if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_EXECUTE_PENDING)) { |
| DEBUG_PRINT_LOW("Move to executing"); |
| // Send the callback now |
| BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_EXECUTE_PENDING); |
| pThis->m_state = OMX_StateExecuting; |
| pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, |
| OMX_EventCmdComplete,OMX_CommandStateSet, |
| OMX_StateExecuting, NULL); |
| } else if (BITMASK_PRESENT(&pThis->m_flags, |
| OMX_COMPONENT_PAUSE_PENDING)) { |
| if (/*ioctl (pThis->drv_ctx.video_driver_fd, |
| VDEC_IOCTL_CMD_PAUSE,NULL ) < */0) { |
| DEBUG_PRINT_ERROR("VDEC_IOCTL_CMD_PAUSE failed"); |
| pThis->omx_report_error (); |
| } |
| } |
| } |
| } else { |
| DEBUG_PRINT_LOW("Event Handler callback is NULL"); |
| } |
| break; |
| |
| case OMX_COMPONENT_GENERATE_PAUSE_DONE: |
| DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_PAUSE_DONE"); |
| if (pThis->m_cb.EventHandler) { |
| if (p2 != VDEC_S_SUCCESS) { |
| DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_PAUSE_DONE ret failed"); |
| pThis->omx_report_error (); |
| } else { |
| pThis->complete_pending_buffer_done_cbs(); |
| if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_PAUSE_PENDING)) { |
| DEBUG_PRINT_LOW("OMX_COMPONENT_GENERATE_PAUSE_DONE nofity"); |
| //Send the callback now |
| BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_PAUSE_PENDING); |
| pThis->m_state = OMX_StatePause; |
| pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, |
| OMX_EventCmdComplete,OMX_CommandStateSet, |
| OMX_StatePause, NULL); |
| } |
| } |
| } else { |
| DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); |
| } |
| |
| break; |
| |
| case OMX_COMPONENT_GENERATE_RESUME_DONE: |
| DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_RESUME_DONE"); |
| if (pThis->m_cb.EventHandler) { |
| if (p2 != VDEC_S_SUCCESS) { |
| DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_RESUME_DONE failed"); |
| pThis->omx_report_error (); |
| } else { |
| if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_EXECUTE_PENDING)) { |
| DEBUG_PRINT_LOW("Moving the decoder to execute state"); |
| // Send the callback now |
| BITMASK_CLEAR((&pThis->m_flags),OMX_COMPONENT_EXECUTE_PENDING); |
| pThis->m_state = OMX_StateExecuting; |
| pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, |
| OMX_EventCmdComplete,OMX_CommandStateSet, |
| OMX_StateExecuting,NULL); |
| } |
| } |
| } else { |
| DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); |
| } |
| |
| break; |
| |
| case OMX_COMPONENT_GENERATE_STOP_DONE: |
| DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_STOP_DONE"); |
| if (pThis->m_cb.EventHandler) { |
| if (p2 != VDEC_S_SUCCESS) { |
| DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_STOP_DONE ret failed"); |
| pThis->omx_report_error (); |
| } else { |
| pThis->complete_pending_buffer_done_cbs(); |
| if (BITMASK_PRESENT(&pThis->m_flags,OMX_COMPONENT_IDLE_PENDING)) { |
| DEBUG_PRINT_LOW("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("Move to Idle State"); |
| pThis->m_cb.EventHandler(&pThis->m_cmp,pThis->m_app_data, |
| OMX_EventCmdComplete,OMX_CommandStateSet, |
| OMX_StateIdle,NULL); |
| } |
| } |
| } else { |
| DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); |
| } |
| |
| break; |
| |
| case OMX_COMPONENT_GENERATE_PORT_RECONFIG: |
| if (p2 == OMX_IndexParamPortDefinition) { |
| DEBUG_PRINT_HIGH("Rxd PORT_RECONFIG: OMX_IndexParamPortDefinition"); |
| pThis->in_reconfig = true; |
| |
| } else if (p2 == OMX_IndexConfigCommonOutputCrop) { |
| DEBUG_PRINT_HIGH("Rxd PORT_RECONFIG: OMX_IndexConfigCommonOutputCrop"); |
| |
| /* Check if resolution is changed in smooth streaming mode */ |
| if (pThis->m_smoothstreaming_mode && |
| (pThis->framesize.nWidth != |
| pThis->drv_ctx.video_resolution.frame_width) || |
| (pThis->framesize.nHeight != |
| pThis->drv_ctx.video_resolution.frame_height)) { |
| |
| DEBUG_PRINT_HIGH("Resolution changed from: wxh = %dx%d to: wxh = %dx%d", |
| pThis->framesize.nWidth, |
| pThis->framesize.nHeight, |
| pThis->drv_ctx.video_resolution.frame_width, |
| pThis->drv_ctx.video_resolution.frame_height); |
| |
| /* Update new resolution */ |
| pThis->framesize.nWidth = |
| pThis->drv_ctx.video_resolution.frame_width; |
| pThis->framesize.nHeight = |
| pThis->drv_ctx.video_resolution.frame_height; |
| |
| /* Update C2D with new resolution */ |
| if (!pThis->client_buffers.update_buffer_req()) { |
| DEBUG_PRINT_ERROR("Setting C2D buffer requirements failed"); |
| } |
| } |
| |
| /* Update new crop information */ |
| pThis->rectangle.nLeft = pThis->drv_ctx.frame_size.left; |
| pThis->rectangle.nTop = pThis->drv_ctx.frame_size.top; |
| pThis->rectangle.nWidth = pThis->drv_ctx.frame_size.right; |
| pThis->rectangle.nHeight = pThis->drv_ctx.frame_size.bottom; |
| |
| /* Validate the new crop information */ |
| if (pThis->rectangle.nLeft + pThis->rectangle.nWidth > |
| pThis->drv_ctx.video_resolution.frame_width) { |
| |
| DEBUG_PRINT_HIGH("Crop L[%u] + R[%u] > W[%u]", |
| pThis->rectangle.nLeft, pThis->rectangle.nWidth, |
| pThis->drv_ctx.video_resolution.frame_width); |
| pThis->rectangle.nLeft = 0; |
| |
| if (pThis->rectangle.nWidth > |
| pThis->drv_ctx.video_resolution.frame_width) { |
| |
| DEBUG_PRINT_HIGH("Crop R[%u] > W[%u]", |
| pThis->rectangle.nWidth, |
| pThis->drv_ctx.video_resolution.frame_width); |
| pThis->rectangle.nWidth = |
| pThis->drv_ctx.video_resolution.frame_width; |
| } |
| } |
| if (pThis->rectangle.nTop + pThis->rectangle.nHeight > |
| pThis->drv_ctx.video_resolution.frame_height) { |
| |
| DEBUG_PRINT_HIGH("Crop T[%u] + B[%u] > H[%u]", |
| pThis->rectangle.nTop, pThis->rectangle.nHeight, |
| pThis->drv_ctx.video_resolution.frame_height); |
| pThis->rectangle.nTop = 0; |
| |
| if (pThis->rectangle.nHeight > |
| pThis->drv_ctx.video_resolution.frame_height) { |
| |
| DEBUG_PRINT_HIGH("Crop B[%u] > H[%u]", |
| pThis->rectangle.nHeight, |
| pThis->drv_ctx.video_resolution.frame_height); |
| pThis->rectangle.nHeight = |
| pThis->drv_ctx.video_resolution.frame_height; |
| } |
| } |
| DEBUG_PRINT_HIGH("Updated Crop Info: L: %u, T: %u, R: %u, B: %u", |
| pThis->rectangle.nLeft, pThis->rectangle.nTop, |
| pThis->rectangle.nWidth, pThis->rectangle.nHeight); |
| } else { |
| DEBUG_PRINT_ERROR("Rxd Invalid PORT_RECONFIG event (%lu)", p2); |
| break; |
| } |
| if (pThis->m_cb.EventHandler) { |
| pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, |
| OMX_EventPortSettingsChanged, p1, p2, NULL ); |
| } else { |
| DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); |
| } |
| |
| break; |
| |
| case OMX_COMPONENT_GENERATE_EOS_DONE: |
| DEBUG_PRINT_HIGH("Rxd OMX_COMPONENT_GENERATE_EOS_DONE"); |
| if (pThis->m_cb.EventHandler) { |
| pThis->m_cb.EventHandler(&pThis->m_cmp, pThis->m_app_data, OMX_EventBufferFlag, |
| OMX_CORE_OUTPUT_PORT_INDEX, OMX_BUFFERFLAG_EOS, NULL ); |
| } else { |
| DEBUG_PRINT_ERROR("ERROR: %s()::EventHandler is NULL", __func__); |
| } |
| pThis->prev_ts = LLONG_MAX; |
| pThis->rst_prev_ts = true; |
| break; |
| |
| case OMX_COMPONENT_GENERATE_HARDWARE_ERROR: |
| DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_HARDWARE_ERROR"); |
| pThis->omx_report_error (); |
| break; |
| |
| case OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING: |
| DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_UNSUPPORTED_SETTING"); |
| pThis->omx_report_unsupported_setting(); |
| break; |
| |
| case OMX_COMPONENT_GENERATE_HARDWARE_OVERLOAD: |
| DEBUG_PRINT_ERROR("OMX_COMPONENT_GENERATE_HARDWARE_OVERLOAD"); |
| pThis->omx_report_hw_overload(); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| pthread_mutex_lock(&pThis->m_lock); |
| qsize = pThis->m_cmd_q.m_size; |
| if (pThis->m_state != OMX_StatePause) |
| qsize += (pThis->m_ftb_q.m_size + pThis->m_etb_q.m_size); |
| pthread_mutex_unlock(&pThis->m_lock); |
| } while (qsize>0); |
| |
| } |
| |
| int omx_vdec::update_resolution(int width, int height, int stride, int scan_lines) |
| { |
| int format_changed = 0; |
| if ((height != (int)drv_ctx.video_resolution.frame_height) || |
| (width != (int)drv_ctx.video_resolution.frame_width)) { |
| DEBUG_PRINT_HIGH("NOTE_CIF: W/H %d (%d), %d (%d)", |
| width, drv_ctx.video_resolution.frame_width, |
| height,drv_ctx.video_resolution.frame_height); |
| format_changed = 1; |
| } |
| drv_ctx.video_resolution.frame_height = height; |
| drv_ctx.video_resolution.frame_width = width; |
| drv_ctx.video_resolution.scan_lines = scan_lines; |
| drv_ctx.video_resolution.stride = stride; |
| if(!is_down_scalar_enabled) { |
| rectangle.nLeft = 0; |
| rectangle.nTop = 0; |
| rectangle.nWidth = drv_ctx.video_resolution.frame_width; |
| rectangle.nHeight = drv_ctx.video_resolution.frame_height; |
| } |
| return format_changed; |
| } |
| |
| OMX_ERRORTYPE omx_vdec::is_video_session_supported() |
| { |
| if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc", |
| OMX_MAX_STRINGNAME_SIZE) && |
| (m_profile == HIGH_PROFILE || m_profile == MAIN_PROFILE)) { |
| m_decoder_capability.max_width = 1280; |
| m_decoder_capability.max_height = 720; |
| DEBUG_PRINT_HIGH("Set max_width=1280 & max_height=720 for H264 HP/MP"); |
| } |
| |
| if ((drv_ctx.video_resolution.frame_width * |
| drv_ctx.video_resolution.frame_height > |
| m_decoder_capability.max_width * |
| m_decoder_capability.max_height) || |
| (drv_ctx.video_resolution.frame_width* |
| drv_ctx.video_resolution.frame_height < |
| m_decoder_capability.min_width * |
| m_decoder_capability.min_height)) { |
| DEBUG_PRINT_ERROR( |
| "Unsupported WxH = (%u)x(%u) supported range is min(%u)x(%u) - max(%u)x(%u)", |
| drv_ctx.video_resolution.frame_width, |
| drv_ctx.video_resolution.frame_height, |
| m_decoder_capability.min_width, |
| m_decoder_capability.min_height, |
| m_decoder_capability.max_width, |
| m_decoder_capability.max_height); |
| return OMX_ErrorUnsupportedSetting; |
| } |
| DEBUG_PRINT_HIGH("video session supported"); |
| return OMX_ErrorNone; |
| } |
| |
| int omx_vdec::log_input_buffers(const char *buffer_addr, int buffer_len) |
| { |
| if (m_debug.in_buffer_log && !m_debug.infile) { |
| if(!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.mpeg4", OMX_MAX_STRINGNAME_SIZE)) { |
| sprintf(m_debug.infile_name, "%s/input_dec_%d_%d_%p.m4v", |
| m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); |
| } |
| else if(!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.mpeg2", OMX_MAX_STRINGNAME_SIZE)) { |
| sprintf(m_debug.infile_name, "%s/input_dec_%d_%d_%p.mpg", m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); } |
| else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263", OMX_MAX_STRINGNAME_SIZE)) { |
| sprintf(m_debug.infile_name, "%s/input_dec_%d_%d_%p.263", |
| m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); |
| } |
| else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc", OMX_MAX_STRINGNAME_SIZE) || |
| !strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mvc", OMX_MAX_STRINGNAME_SIZE)) { |
| sprintf(m_debug.infile_name, "%s/input_dec_%d_%d_%p.264", |
| m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); |
| } |
| else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.hevc", OMX_MAX_STRINGNAME_SIZE)) { |
| sprintf(m_debug.infile_name, "%s/input_dec_%d_%d_%p.265", |
| m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); |
| } |
| else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vc1", OMX_MAX_STRINGNAME_SIZE)) { |
| sprintf(m_debug.infile_name, "%s/input_dec_%d_%d_%p.vc1", |
| m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); |
| } |
| else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.wmv", OMX_MAX_STRINGNAME_SIZE)) { |
| sprintf(m_debug.infile_name, "%s/input_dec_%d_%d_%p.vc1", |
| m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); |
| } |
| else if(!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8", OMX_MAX_STRINGNAME_SIZE)) { |
| sprintf(m_debug.infile_name, "%s/input_dec_%d_%d_%p.ivf", |
| m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); |
| } |
| else { |
| sprintf(m_debug.infile_name, "%s/input_dec_%d_%d_%p.divx", |
| m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); |
| } |
| m_debug.infile = fopen (m_debug.infile_name, "ab"); |
| if (!m_debug.infile) { |
| DEBUG_PRINT_HIGH("Failed to open input file: %s for logging", m_debug.infile_name); |
| m_debug.infile_name[0] = '\0'; |
| return -1; |
| } |
| if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8", OMX_MAX_STRINGNAME_SIZE)) { |
| struct ivf_file_header { |
| OMX_U8 signature[4]; //='DKIF'; |
| OMX_U8 version ; //= 0; |
| OMX_U8 headersize ; //= 32; |
| OMX_U32 FourCC; |
| OMX_U8 width; |
| OMX_U8 height; |
| OMX_U32 rate; |
| OMX_U32 scale; |
| OMX_U32 length; |
| OMX_U8 unused[4]; |
| } file_header; |
| |
| memset((void *)&file_header,0,sizeof(file_header)); |
| file_header.signature[0] = 'D'; |
| file_header.signature[1] = 'K'; |
| file_header.signature[2] = 'I'; |
| file_header.signature[3] = 'F'; |
| file_header.version = 0; |
| file_header.headersize = 32; |
| file_header.FourCC = 0x30385056; |
| fwrite((const char *)&file_header, |
| sizeof(file_header),1,m_debug.infile); |
| } |
| } |
| if (m_debug.infile && buffer_addr && buffer_len) { |
| if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8", OMX_MAX_STRINGNAME_SIZE)) { |
| struct vp8_ivf_frame_header { |
| OMX_U32 framesize; |
| OMX_U32 timestamp_lo; |
| OMX_U32 timestamp_hi; |
| } vp8_frame_header; |
| vp8_frame_header.framesize = buffer_len; |
| /* Currently FW doesn't use timestamp values */ |
| vp8_frame_header.timestamp_lo = 0; |
| vp8_frame_header.timestamp_hi = 0; |
| fwrite((const char *)&vp8_frame_header, |
| sizeof(vp8_frame_header),1,m_debug.infile); |
| } |
| fwrite(buffer_addr, buffer_len, 1, m_debug.infile); |
| } |
| return 0; |
| } |
| |
| int omx_vdec::log_output_buffers(OMX_BUFFERHEADERTYPE *buffer) { |
| if (m_debug.out_buffer_log && !m_debug.outfile && buffer->nFilledLen) { |
| sprintf(m_debug.outfile_name, "%s/output_%d_%d_%p.yuv", |
| m_debug.log_loc, drv_ctx.video_resolution.frame_width, drv_ctx.video_resolution.frame_height, this); |
| m_debug.outfile = fopen (m_debug.outfile_name, "ab"); |
| if (!m_debug.outfile) { |
| DEBUG_PRINT_HIGH("Failed to open output file: %s for logging", m_debug.log_loc); |
| m_debug.outfile_name[0] = '\0'; |
| return -1; |
| } |
| } |
| if (m_debug.outfile && buffer && buffer->nFilledLen) { |
| int buf_index = buffer - m_out_mem_ptr; |
| int stride = drv_ctx.video_resolution.stride; |
| int scanlines = drv_ctx.video_resolution.scan_lines; |
| if (m_smoothstreaming_mode) { |
| stride = drv_ctx.video_resolution.frame_width; |
| scanlines = drv_ctx.video_resolution.frame_height; |
| stride = (stride + DEFAULT_WIDTH_ALIGNMENT - 1) & (~(DEFAULT_WIDTH_ALIGNMENT - 1)); |
| scanlines = (scanlines + DEFAULT_HEIGHT_ALIGNMENT - 1) & (~(DEFAULT_HEIGHT_ALIGNMENT - 1)); |
| } |
| char *temp = (char *)drv_ctx.ptr_outputbuffer[buf_index].bufferaddr; |
| unsigned i; |
| DEBUG_PRINT_HIGH("Logging width/height(%u/%u) stride/scanlines(%u/%u)", |
| drv_ctx.video_resolution.frame_width, |
| drv_ctx.video_resolution.frame_height, stride, scanlines); |
| int bytes_written = 0; |
| for (i = 0; i < drv_ctx.video_resolution.frame_height; i++) { |
| bytes_written = fwrite(temp, drv_ctx.video_resolution.frame_width, 1, m_debug.outfile); |
| temp += stride; |
| } |
| temp = (char *)drv_ctx.ptr_outputbuffer[buf_index].bufferaddr + stride * scanlines; |
| int stride_c = stride; |
| for(i = 0; i < drv_ctx.video_resolution.frame_height/2; i++) { |
| bytes_written += fwrite(temp, drv_ctx.video_resolution.frame_width, 1, m_debug.outfile); |
| temp += stride_c; |
| } |
| } |
| return 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 v4l2_fmtdesc fdesc; |
| struct v4l2_format fmt; |
| struct v4l2_requestbuffers bufreq; |
| struct v4l2_control control; |
| struct v4l2_frmsizeenum frmsize; |
| unsigned int alignment = 0,buffer_size = 0; |
| int fds[2]; |
| int r,ret=0; |
| bool codec_ambiguous = false; |
| OMX_STRING device_name = (OMX_STRING)"/dev/video32"; |
| char property_value[PROPERTY_VALUE_MAX] = {0}; |
| |
| #ifdef _ANDROID_ |
| char platform_name[PROPERTY_VALUE_MAX]; |
| property_get("ro.board.platform", platform_name, "0"); |
| if (!strncmp(platform_name, "msm8610", 7)) { |
| device_name = (OMX_STRING)"/dev/video/q6_dec"; |
| is_q6_platform = true; |
| maxSmoothStreamingWidth = 1280; |
| maxSmoothStreamingHeight = 720; |
| } |
| #endif |
| |
| #ifdef _ANDROID_ |
| /* |
| * turn off frame parsing for Android by default. |
| * Clients may configure OMX_QCOM_FramePacking_Arbitrary to enable this mode |
| */ |
| arbitrary_bytes = false; |
| property_get("vidc.dec.debug.arbitrarybytes.mode", property_value, "0"); |
| if (atoi(property_value)) { |
| DEBUG_PRINT_HIGH("arbitrary_bytes mode enabled via property command"); |
| arbitrary_bytes = true; |
| } |
| #endif |
| |
| if (!strncmp(role, "OMX.qcom.video.decoder.avc.secure", |
| OMX_MAX_STRINGNAME_SIZE)) { |
| secure_mode = true; |
| arbitrary_bytes = false; |
| role = (OMX_STRING)"OMX.qcom.video.decoder.avc"; |
| } else if (!strncmp(role, "OMX.qcom.video.decoder.mpeg2.secure", |
| OMX_MAX_STRINGNAME_SIZE)) { |
| secure_mode = true; |
| arbitrary_bytes = false; |
| role = (OMX_STRING)"OMX.qcom.video.decoder.mpeg2"; |
| } else if (!strncmp(role, "OMX.qcom.video.decoder.hevc.secure", |
| OMX_MAX_STRINGNAME_SIZE)) { |
| secure_mode = true; |
| arbitrary_bytes = false; |
| role = (OMX_STRING)"OMX.qcom.video.decoder.hevc"; |
| } else if (!strncmp(role, "OMX.qcom.video.decoder.vc1.secure", |
| OMX_MAX_STRINGNAME_SIZE)) { |
| secure_mode = true; |
| arbitrary_bytes = false; |
| role = (OMX_STRING)"OMX.qcom.video.decoder.vc1"; |
| } else if (!strncmp(role, "OMX.qcom.video.decoder.wmv.secure", |
| OMX_MAX_STRINGNAME_SIZE)) { |
| secure_mode = true; |
| arbitrary_bytes = false; |
| role = (OMX_STRING)"OMX.qcom.video.decoder.wmv"; |
| } else if (!strncmp(role, "OMX.qcom.video.decoder.mpeg4.secure", |
| OMX_MAX_STRINGNAME_SIZE)) { |
| secure_mode = true; |
| arbitrary_bytes = false; |
| role = (OMX_STRING)"OMX.qcom.video.decoder.mpeg4"; |
| } |
| |
| drv_ctx.video_driver_fd = open(device_name, O_RDWR); |
| |
| DEBUG_PRINT_INFO("component_init: %s : fd=%d", role, drv_ctx.video_driver_fd); |
| |
| if (drv_ctx.video_driver_fd == 0) { |
| DEBUG_PRINT_ERROR("omx_vdec_msm8974 :: Got fd as 0 for msm_vidc_dec, Opening again"); |
| drv_ctx.video_driver_fd = open(device_name, O_RDWR); |
| close(0); |
| } |
| |
| if (drv_ctx.video_driver_fd < 0) { |
| DEBUG_PRINT_ERROR("Omx_vdec::Comp Init Returning failure, errno %d", errno); |
| return OMX_ErrorInsufficientResources; |
| } |
| drv_ctx.frame_rate.fps_numerator = DEFAULT_FPS; |
| drv_ctx.frame_rate.fps_denominator = 1; |
| |
| ret = subscribe_to_events(drv_ctx.video_driver_fd); |
| if (!ret) { |
| async_thread_created = true; |
| ret = pthread_create(&async_thread_id,0,async_message_thread,this); |
| } |
| if (ret) { |
| DEBUG_PRINT_ERROR("Failed to create async_message_thread"); |
| async_thread_created = false; |
| return OMX_ErrorInsufficientResources; |
| } |
| |
| #ifdef OUTPUT_EXTRADATA_LOG |
| outputExtradataFile = fopen (output_extradata_filename, "ab"); |
| #endif |
| |
| // Copy the role information which provides the decoder kind |
| strlcpy(drv_ctx.kind,role,128); |
| |
| if (!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.mpeg4",\ |
| OMX_MAX_STRINGNAME_SIZE)) { |
| strlcpy((char *)m_cRole, "video_decoder.mpeg4",\ |
| OMX_MAX_STRINGNAME_SIZE); |
| drv_ctx.timestamp_adjust = true; |
| drv_ctx.decoder_format = VDEC_CODECTYPE_MPEG4; |
| eCompressionFormat = OMX_VIDEO_CodingMPEG4; |
| output_capability=V4L2_PIX_FMT_MPEG4; |
| /*Initialize Start Code for MPEG4*/ |
| codec_type_parse = CODEC_TYPE_MPEG4; |
| m_frame_parser.init_start_codes (codec_type_parse); |
| } else if (!strncmp(drv_ctx.kind,"OMX.qcom.video.decoder.mpeg2",\ |
| OMX_MAX_STRINGNAME_SIZE)) { |
| strlcpy((char *)m_cRole, "video_decoder.mpeg2",\ |
| OMX_MAX_STRINGNAME_SIZE); |
| drv_ctx.decoder_format = VDEC_CODECTYPE_MPEG2; |
| output_capability = V4L2_PIX_FMT_MPEG2; |
| eCompressionFormat = OMX_VIDEO_CodingMPEG2; |
| /*Initialize Start Code for MPEG2*/ |
| codec_type_parse = CODEC_TYPE_MPEG2; |
| m_frame_parser.init_start_codes (codec_type_parse); |
| } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.h263",\ |
| OMX_MAX_STRINGNAME_SIZE)) { |
| strlcpy((char *)m_cRole, "video_decoder.h263",OMX_MAX_STRINGNAME_SIZE); |
| DEBUG_PRINT_LOW("H263 Decoder selected"); |
| drv_ctx.decoder_format = VDEC_CODECTYPE_H263; |
| eCompressionFormat = OMX_VIDEO_CodingH263; |
| output_capability = V4L2_PIX_FMT_H263; |
| codec_type_parse = CODEC_TYPE_H263; |
| m_frame_parser.init_start_codes (codec_type_parse); |
| } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx311",\ |
| OMX_MAX_STRINGNAME_SIZE)) { |
| strlcpy((char *)m_cRole, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE); |
| DEBUG_PRINT_LOW ("DIVX 311 Decoder selected"); |
| drv_ctx.decoder_format = VDEC_CODECTYPE_DIVX_3; |
| output_capability = V4L2_PIX_FMT_DIVX_311; |
| eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; |
| codec_type_parse = CODEC_TYPE_DIVX; |
| m_frame_parser.init_start_codes (codec_type_parse); |
| |
| eRet = createDivxDrmContext(); |
| if (eRet != OMX_ErrorNone) { |
| DEBUG_PRINT_ERROR("createDivxDrmContext Failed"); |
| return eRet; |
| } |
| } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx4",\ |
| OMX_MAX_STRINGNAME_SIZE)) { |
| strlcpy((char *)m_cRole, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE); |
| DEBUG_PRINT_ERROR ("DIVX 4 Decoder selected"); |
| drv_ctx.decoder_format = VDEC_CODECTYPE_DIVX_4; |
| output_capability = V4L2_PIX_FMT_DIVX; |
| eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; |
| codec_type_parse = CODEC_TYPE_DIVX; |
| codec_ambiguous = true; |
| m_frame_parser.init_start_codes (codec_type_parse); |
| |
| eRet = createDivxDrmContext(); |
| if (eRet != OMX_ErrorNone) { |
| DEBUG_PRINT_ERROR("createDivxDrmContext Failed"); |
| return eRet; |
| } |
| } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.divx",\ |
| OMX_MAX_STRINGNAME_SIZE)) { |
| strlcpy((char *)m_cRole, "video_decoder.divx",OMX_MAX_STRINGNAME_SIZE); |
| DEBUG_PRINT_ERROR ("DIVX 5/6 Decoder selected"); |
| drv_ctx.decoder_format = VDEC_CODECTYPE_DIVX_6; |
| output_capability = V4L2_PIX_FMT_DIVX; |
| eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; |
| codec_type_parse = CODEC_TYPE_DIVX; |
| codec_ambiguous = true; |
| m_frame_parser.init_start_codes (codec_type_parse); |
| |
| eRet = createDivxDrmContext(); |
| if (eRet != OMX_ErrorNone) { |
| DEBUG_PRINT_ERROR("createDivxDrmContext Failed"); |
| return eRet; |
| } |
| |
| } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc",\ |
| OMX_MAX_STRINGNAME_SIZE)) { |
| strlcpy((char *)m_cRole, "video_decoder.avc",OMX_MAX_STRINGNAME_SIZE); |
| drv_ctx.decoder_format = VDEC_CODECTYPE_H264; |
| output_capability=V4L2_PIX_FMT_H264; |
| eCompressionFormat = OMX_VIDEO_CodingAVC; |
| codec_type_parse = CODEC_TYPE_H264; |
| m_frame_parser.init_start_codes (codec_type_parse); |
| m_frame_parser.init_nal_length(nal_length); |
| } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.mvc",\ |
| OMX_MAX_STRINGNAME_SIZE)) { |
| strlcpy((char *)m_cRole, "video_decoder.mvc", OMX_MAX_STRINGNAME_SIZE); |
| drv_ctx.decoder_format = VDEC_CODECTYPE_MVC; |
| output_capability = V4L2_PIX_FMT_H264_MVC; |
| eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingMVC; |
| 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(drv_ctx.kind, "OMX.qcom.video.decoder.hevc",\ |
| OMX_MAX_STRINGNAME_SIZE)) { |
| strlcpy((char *)m_cRole, "video_decoder.hevc",OMX_MAX_STRINGNAME_SIZE); |
| drv_ctx.decoder_format = VDEC_CODECTYPE_HEVC; |
| output_capability = V4L2_PIX_FMT_HEVC; |
| eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc; |
| codec_type_parse = CODEC_TYPE_HEVC; |
| m_frame_parser.init_start_codes(codec_type_parse); |
| m_frame_parser.init_nal_length(nal_length); |
| } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vc1",\ |
| OMX_MAX_STRINGNAME_SIZE)) { |
| strlcpy((char *)m_cRole, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE); |
| drv_ctx.decoder_format = VDEC_CODECTYPE_VC1; |
| eCompressionFormat = OMX_VIDEO_CodingWMV; |
| codec_type_parse = CODEC_TYPE_VC1; |
| output_capability = V4L2_PIX_FMT_VC1_ANNEX_G; |
| m_frame_parser.init_start_codes (codec_type_parse); |
| } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.wmv",\ |
| OMX_MAX_STRINGNAME_SIZE)) { |
| strlcpy((char *)m_cRole, "video_decoder.vc1",OMX_MAX_STRINGNAME_SIZE); |
| drv_ctx.decoder_format = VDEC_CODECTYPE_VC1_RCV; |
| eCompressionFormat = OMX_VIDEO_CodingWMV; |
| codec_type_parse = CODEC_TYPE_VC1; |
| output_capability = V4L2_PIX_FMT_VC1_ANNEX_L; |
| m_frame_parser.init_start_codes (codec_type_parse); |
| } else if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.vp8", \ |
| OMX_MAX_STRINGNAME_SIZE)) { |
| strlcpy((char *)m_cRole, "video_decoder.vp8",OMX_MAX_STRINGNAME_SIZE); |
| output_capability=V4L2_PIX_FMT_VP8; |
| eCompressionFormat = OMX_VIDEO_CodingVP8; |
| codec_type_parse = CODEC_TYPE_VP8; |
| arbitrary_bytes = false; |
| |
| } else { |
| DEBUG_PRINT_ERROR("ERROR:Unknown Component"); |
| eRet = OMX_ErrorInvalidComponentName; |
| } |
| if (eRet == OMX_ErrorNone) { |
| OMX_COLOR_FORMATTYPE dest_color_format; |
| drv_ctx.output_format = VDEC_YUV_FORMAT_NV12; |
| if (eCompressionFormat == (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingMVC) |
| dest_color_format = (OMX_COLOR_FORMATTYPE) |
| QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView; |
| else |
| dest_color_format = (OMX_COLOR_FORMATTYPE) |
| QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; |
| if (!client_buffers.set_color_format(dest_color_format)) { |
| DEBUG_PRINT_ERROR("Setting color format failed"); |
| eRet = OMX_ErrorInsufficientResources; |
| } |
| |
| capture_capability= V4L2_PIX_FMT_NV12; |
| |
| struct v4l2_capability cap; |
| ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_QUERYCAP, &cap); |
| if (ret) { |
| DEBUG_PRINT_ERROR("Failed to query capabilities"); |
| /*TODO: How to handle this case */ |
| } else { |
| DEBUG_PRINT_INFO("Capabilities: driver_name = %s, card = %s, bus_info = %s," |
| " version = %d, capabilities = %x", cap.driver, cap.card, |
| cap.bus_info, cap.version, cap.capabilities); |
| } |
| ret=0; |
| fdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| fdesc.index=0; |
| while (ioctl(drv_ctx.video_driver_fd, VIDIOC_ENUM_FMT, &fdesc) == 0) { |
| DEBUG_PRINT_HIGH("fmt: description: %s, fmt: %x, flags = %x", fdesc.description, |
| fdesc.pixelformat, fdesc.flags); |
| fdesc.index++; |
| } |
| fdesc.type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| fdesc.index=0; |
| while (ioctl(drv_ctx.video_driver_fd, VIDIOC_ENUM_FMT, &fdesc) == 0) { |
| |
| DEBUG_PRINT_HIGH("fmt: description: %s, fmt: %x, flags = %x", fdesc.description, |
| fdesc.pixelformat, fdesc.flags); |
| fdesc.index++; |
| } |
| update_resolution(320, 240, 320, 240); |
| fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; |
| fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; |
| fmt.fmt.pix_mp.pixelformat = output_capability; |
| ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); |
| if (ret) { |
| /*TODO: How to handle this case */ |
| DEBUG_PRINT_ERROR("Failed to set format on output port"); |
| return OMX_ErrorInsufficientResources; |
| } |
| DEBUG_PRINT_HIGH("Set Format was successful"); |
| if (codec_ambiguous) { |
| if (output_capability == V4L2_PIX_FMT_DIVX) { |
| struct v4l2_control divx_ctrl; |
| |
| if (drv_ctx.decoder_format == VDEC_CODECTYPE_DIVX_4) { |
| divx_ctrl.value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4; |
| } else if (drv_ctx.decoder_format == VDEC_CODECTYPE_DIVX_5) { |
| divx_ctrl.value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5; |
| } else { |
| divx_ctrl.value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6; |
| } |
| |
| divx_ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT; |
| ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &divx_ctrl); |
| if (ret) { |
| DEBUG_PRINT_ERROR("Failed to set divx version"); |
| } |
| } else { |
| DEBUG_PRINT_ERROR("Codec should not be ambiguous"); |
| } |
| } |
| |
| property_get("persist.vidc.dec.conceal_color", property_value, DEFAULT_CONCEAL_COLOR); |
| m_conceal_color= atoi(property_value); |
| DEBUG_PRINT_HIGH("trying to set 0x%u as conceal color\n", (unsigned int)m_conceal_color); |
| control.id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR; |
| control.value = m_conceal_color; |
| ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); |
| if (ret) { |
| DEBUG_PRINT_ERROR("Failed to set conceal color %d\n", ret); |
| } |
| |
| //Get the hardware capabilities |
| memset((void *)&frmsize,0,sizeof(frmsize)); |
| frmsize.index = 0; |
| frmsize.pixel_format = output_capability; |
| ret = ioctl(drv_ctx.video_driver_fd, |
| VIDIOC_ENUM_FRAMESIZES, &frmsize); |
| if (ret || frmsize.type != V4L2_FRMSIZE_TYPE_STEPWISE) { |
| DEBUG_PRINT_ERROR("Failed to get framesizes"); |
| return OMX_ErrorHardware; |
| } |
| |
| if (frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) { |
| m_decoder_capability.min_width = frmsize.stepwise.min_width; |
| m_decoder_capability.max_width = frmsize.stepwise.max_width; |
| m_decoder_capability.min_height = frmsize.stepwise.min_height; |
| m_decoder_capability.max_height = frmsize.stepwise.max_height; |
| } |
| |
| memset(&fmt, 0x0, sizeof(struct v4l2_format)); |
| fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| fmt.fmt.pix_mp.height = drv_ctx.video_resolution.frame_height; |
| fmt.fmt.pix_mp.width = drv_ctx.video_resolution.frame_width; |
| fmt.fmt.pix_mp.pixelformat = capture_capability; |
| ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_FMT, &fmt); |
| if (ret) { |
| /*TODO: How to handle this case */ |
| DEBUG_PRINT_ERROR("Failed to set format on capture port"); |
| } |
| memset(&framesize, 0, sizeof(OMX_FRAMESIZETYPE)); |
| framesize.nWidth = drv_ctx.video_resolution.frame_width; |
| framesize.nHeight = drv_ctx.video_resolution.frame_height; |
| |
| memset(&rectangle, 0, sizeof(OMX_CONFIG_RECTTYPE)); |
| rectangle.nWidth = drv_ctx.video_resolution.frame_width; |
| rectangle.nHeight = drv_ctx.video_resolution.frame_height; |
| |
| DEBUG_PRINT_HIGH("Set Format was successful"); |
| if (secure_mode) { |
| control.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE; |
| control.value = 1; |
| DEBUG_PRINT_LOW("Omx_vdec:: calling to open secure device %d", ret); |
| ret=ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL,&control); |
| if (ret) { |
| DEBUG_PRINT_ERROR("Omx_vdec:: Unable to open secure device %d", ret); |
| return OMX_ErrorInsufficientResources; |
| } |
| } |
| if (output_capability == V4L2_PIX_FMT_H264_MVC) { |
| control.id = V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT; |
| control.value = V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM; |
| ret=ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL,&control); |
| if (ret) { |
| DEBUG_PRINT_ERROR("Failed to set MVC buffer layout"); |
| return OMX_ErrorInsufficientResources; |
| } |
| } |
| |
| /*Get the Buffer requirements for input and output ports*/ |
| drv_ctx.ip_buf.buffer_type = VDEC_BUFFER_TYPE_INPUT; |
| drv_ctx.op_buf.buffer_type = VDEC_BUFFER_TYPE_OUTPUT; |
| if (secure_mode) { |
| drv_ctx.op_buf.alignment=SZ_1M; |
| drv_ctx.ip_buf.alignment=SZ_1M; |
| } else { |
| drv_ctx.op_buf.alignment=SZ_4K; |
| drv_ctx.ip_buf.alignment=SZ_4K; |
| } |
| drv_ctx.interlace = VDEC_InterlaceFrameProgressive; |
| drv_ctx.extradata = 0; |
| drv_ctx.picture_order = VDEC_ORDER_DISPLAY; |
| control.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER; |
| control.value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY; |
| ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control); |
| drv_ctx.idr_only_decoding = 0; |
| |
| property_get("vidc.debug.turbo", property_value, "0"); |
| if (atoi(property_value)) { |
| DEBUG_PRINT_HIGH("Turbo mode debug property enabled"); |
| control.id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL; |
| control.value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO; |
| if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { |
| DEBUG_PRINT_ERROR("Failed to set turbo mode"); |
| } |
| } |
| |
| m_state = OMX_StateLoaded; |
| #ifdef DEFAULT_EXTRADATA |
| if (!strncmp(drv_ctx.kind, "OMX.qcom.video.decoder.avc", OMX_MAX_STRINGNAME_SIZE) && |
| (eRet == OMX_ErrorNone)) { |
| DEBUG_PRINT_INFO("Enabling default extradata for %s", drv_ctx.kind); |
| enable_extradata(DEFAULT_EXTRADATA, true, true); |
| } |
| #endif |
| eRet=get_buffer_req(&drv_ctx.ip_buf); |
| DEBUG_PRINT_HIGH("Input Buffer Size =%u",(unsigned int)drv_ctx.ip_buf.buffer_size); |
| get_buffer_req(&drv_ctx.op_buf); |
| if (drv_ctx.decoder_format == VDEC_CODECTYPE_H264 || |
| drv_ctx.decoder_format == VDEC_CODECTYPE_HEVC || |
| drv_ctx.decoder_format == VDEC_CODECTYPE_MVC) { |
| h264_scratch.nAllocLen = drv_ctx.ip_buf.buffer_size; |
| h264_scratch.pBuffer = (OMX_U8 *)malloc (drv_ctx.ip_buf.buffer_size); |
| h264_scratch.nFilledLen = 0; |
| h264_scratch.nOffset = 0; |
| |
| if (h264_scratch.pBuffer == NULL) { |
| DEBUG_PRINT_ERROR("h264_scratch.pBuffer Allocation failed "); |
| return OMX_ErrorInsufficientResources; |
| } |
| } |
| if (drv_ctx.decoder_format == VDEC_CODECTYPE_H264 || |
| drv_ctx.decoder_format == VDEC_CODECTYPE_MVC) { |
| if (m_frame_parser.mutils == NULL) { |
| m_frame_parser.mutils = new H264_Utils(); |
| if (m_frame_parser.mutils == NULL) { |
| DEBUG_PRINT_ERROR("parser utils Allocation failed "); |
| eRet = OMX_ErrorInsufficientResources; |
| } else { |
| m_frame_parser.mutils->initialize_frame_checking_environment(); |
| m_frame_parser.mutils->allocate_rbsp_buffer (drv_ctx.ip_buf.buffer_size); |
| } |
| } |
| |
| h264_parser = new h264_stream_parser(); |
| if (!h264_parser) { |
| DEBUG_PRINT_ERROR("ERROR: H264 parser allocation failed!"); |
| eRet = OMX_ErrorInsufficientResources; |
| } |
| } |
| |
| if (pipe(fds)) { |
| DEBUG_PRINT_ERROR("pipe creation failed"); |
| eRet = OMX_ErrorInsufficientResources; |
| } else { |
| int temp1[2]; |
| if (fds[0] == 0 || fds[1] == 0) { |
| if (pipe (temp1)) { |
| DEBUG_PRINT_ERROR("pipe creation failed"); |
| return OMX_ErrorInsufficientResources; |
| } |
| //close (fds[0]); |
| //close (fds[1]); |
| fds[0] = temp1 [0]; |
| fds[1] = temp1 [1]; |
| } |
| m_pipe_in = fds[0]; |
| m_pipe_out = fds[1]; |
| msg_thread_created = true; |
| r = pthread_create(&msg_thread_id,0,message_thread,this); |
| |
| if (r < 0) { |
| DEBUG_PRINT_ERROR("component_init(): message_thread creation failed"); |
| msg_thread_created = false; |
| eRet = OMX_ErrorInsufficientResources; |
| } |
| } |
| } |
| |
| if (eRet != OMX_ErrorNone) { |
| DEBUG_PRINT_ERROR("Component Init Failed"); |
| } else { |
| DEBUG_PRINT_INFO("omx_vdec::component_init() success : fd=%d", |
| drv_ctx.video_driver_fd); |
| } |
| //memset(&h264_mv_buff,0,sizeof(struct h264_mv_buffer)); |
| control.id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY; |
| control.value = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE; |
| |
| if (ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL, &control)) { |
| DEBUG_PRINT_ERROR("Failed to set Default Priority"); |
| eRet = OMX_ErrorUnsupportedSetting; |
| } |
| 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 |
| ) |
| { |
| (void) hComp; |
| (void) componentName; |
| (void) componentVersion; |
| (void) componentUUID; |
| if (m_state == OMX_StateInvalid) { |
| DEBUG_PRINT_ERROR("Get Comp Version in Invalid State"); |
| return OMX_ErrorInvalidState; |
| } |
| /* TBD -- Return the proper version */ |
| if (specVersion) { |
| specVersion->nVersion = OMX_SPEC_VERSION; |
| } |
| return OMX_ErrorNone; |
| } |
| /* ====================================================================== |
| FUNCTION |
| omx_vdec::SendCommand |
| |
| DESCRIPTION |
| Returns zero if all the buffers released.. |
| |
| PARAMETERS |
| None. |
| |
| RETURN VALUE |
| true/false |
| |
| ========================================================================== */ |
| OMX_ERRORTYPE omx_vdec::send_command(OMX_IN OMX_HANDLETYPE hComp, |
| OMX_IN OMX_COMMANDTYPE cmd, |
| OMX_IN OMX_U32 param1, |
| OMX_IN OMX_PTR cmdData |
| ) |
| { |
| (void) hComp; |
| (void) cmdData; |
| DEBUG_PRINT_LOW("send_command: Recieved a Command from Client"); |
| if (m_state == OMX_StateInvalid) { |
| DEBUG_PRINT_ERROR("ERROR: Send Command in Invalid State"); |
| return OMX_ErrorInvalidState; |
| } |
| if (cmd == OMX_CommandFlush && param1 != OMX_CORE_INPUT_PORT_INDEX |
| && param1 != OMX_CORE_OUTPUT_PORT_INDEX && param1 != OMX_ALL) { |
| DEBUG_PRINT_ERROR("send_command(): ERROR OMX_CommandFlush " |
| "to invalid port: %u", (unsigned int)param1); |
| return OMX_ErrorBadPortIndex; |
| } |
| |
| post_event((unsigned)cmd,(unsigned)param1,OMX_COMPONENT_GENERATE_COMMAND); |
| sem_wait(&m_cmd_lock); |
| DEBUG_PRINT_LOW("send_command: Command Processed"); |
| 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 |
| ) |
| { |
| (void) hComp; |
| (void) cmdData; |
| OMX_ERRORTYPE eRet = OMX_ErrorNone; |
| OMX_STATETYPE eState = (OMX_STATETYPE) param1; |
| int bFlag = 1,sem_posted = 0,ret=0; |
| |
| DEBUG_PRINT_LOW("send_command_proxy(): cmd = %d", cmd); |
| DEBUG_PRINT_HIGH("send_command_proxy(): Current State %d, Expected State %d", |
| m_state, eState); |
| |
| if (cmd == OMX_CommandStateSet) { |
| DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandStateSet issued"); |
| DEBUG_PRINT_HIGH("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"); |
| } else { |
| DEBUG_PRINT_LOW("send_command_proxy(): Loaded-->Idle-Pending"); |
| 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"); |
| 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"); |
| } |
| /* Requesting transition from Loaded to Executing */ |
| else if (eState == OMX_StateExecuting) { |
| DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Loaded-->Executing"); |
| 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"); |
| 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"); |
| 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)",\ |
| 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"); |
| } else { |
| DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Loaded-Pending"); |
| BITMASK_SET(&m_flags, OMX_COMPONENT_LOADING_PENDING); |
| // Skip the event notification |
| bFlag = 0; |
| } |
| } |
| /* Requesting transition from Idle to Executing */ |
| else if (eState == OMX_StateExecuting) { |
| DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing"); |
| //BITMASK_SET(&m_flags, OMX_COMPONENT_EXECUTE_PENDING); |
| bFlag = 1; |
| DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing"); |
| m_state=OMX_StateExecuting; |
| DEBUG_PRINT_HIGH("Stream On CAPTURE Was successful"); |
| } |
| /* Requesting transition from Idle to Idle */ |
| else if (eState == OMX_StateIdle) { |
| DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->Idle"); |
| 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"); |
| post_event(OMX_EventError,OMX_ErrorIncorrectStateTransition,\ |
| OMX_COMPONENT_GENERATE_EVENT); |
| eRet = OMX_ErrorIncorrectStateTransition; |
| } |
| /* Requesting transition from Idle to Pause */ |
| else if (eState == OMX_StatePause) { |
| /*To pause the Video core we need to start the driver*/ |
| if (/*ioctl (drv_ctx.video_driver_fd,VDEC_IOCTL_CMD_START, |
| NULL) < */0) { |
| DEBUG_PRINT_ERROR("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"); |
| bFlag = 0; |
| } |
| } |
| /* Requesting transition from Idle to Invalid */ |
| else if (eState == OMX_StateInvalid) { |
| DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle-->Invalid"); |
| post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); |
| eRet = OMX_ErrorInvalidState; |
| } else { |
| DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Idle --> %d Not Handled",eState); |
| eRet = OMX_ErrorBadParameter; |
| } |
| } |
| |
| /******************************/ |
| /* Current State is Executing */ |
| /******************************/ |
| else if (m_state == OMX_StateExecuting) { |
| DEBUG_PRINT_LOW("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("send_command_proxy(): Executing --> Idle"); |
| 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("PAUSE Command Issued"); |
| m_state = OMX_StatePause; |
| bFlag = 1; |
| } |
| /* Requesting transition from Executing to Loaded */ |
| else if (eState == OMX_StateLoaded) { |
| DEBUG_PRINT_ERROR("send_command_proxy(): Executing --> Loaded"); |
| 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("send_command_proxy(): Executing --> WaitForResources"); |
| 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("send_command_proxy(): Executing --> Executing"); |
| 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("send_command_proxy(): Executing --> Invalid"); |
| post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); |
| eRet = OMX_ErrorInvalidState; |
| } else { |
| DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Executing --> %d Not Handled",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("Pause --> Executing"); |
| m_state = OMX_StateExecuting; |
| bFlag = 1; |
| } |
| /* Requesting transition from Pause to Idle */ |
| else if (eState == OMX_StateIdle) { |
| /* Since error is None , we will post an event |
| at the end of this function definition */ |
| DEBUG_PRINT_LOW("Pause --> Idle"); |
| 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("Pause --> loaded"); |
| 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("Pause --> WaitForResources"); |
| 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("Pause --> Pause"); |
| 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("Pause --> Invalid"); |
| post_event(OMX_EventError,eState,OMX_COMPONENT_GENERATE_EVENT); |
| eRet = OMX_ErrorInvalidState; |
| } else { |
| DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): Paused --> %d Not Handled",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"); |
| } |
| /* Requesting transition from WaitForResources to WaitForResources */ |
| else if (eState == OMX_StateWaitForResources) { |
| DEBUG_PRINT_ERROR("ERROR::send_command_proxy(): WaitForResources-->WaitForResources"); |
| 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"); |
| 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"); |
| 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"); |
| 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)",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"); |
| post_event(OMX_EventError,OMX_ErrorInvalidState,\ |
| OMX_COMPONENT_GENERATE_EVENT); |
| eRet = OMX_ErrorInvalidState; |
| } |
| } else if (cmd == OMX_CommandFlush) { |
| DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandFlush issued" |
| "with param1: %u", (unsigned int)param1); |
| #ifdef _MSM8974_ |
| send_codec_config(); |
| #endif |
| if (cmd == OMX_CommandFlush && (param1 == OMX_CORE_INPUT_PORT_INDEX || |
| param1 == OMX_ALL)) { |
| if (android_atomic_add(0, &m_queued_codec_config_count) > 0) { |
| struct timespec ts; |
| |
| clock_gettime(CLOCK_REALTIME, &ts); |
| ts.tv_sec += 2; |
| DEBUG_PRINT_LOW("waiting for %d EBDs of CODEC CONFIG buffers ", |
| m_queued_codec_config_count); |
| BITMASK_SET(&m_flags, OMX_COMPONENT_FLUSH_DEFERRED); |
| if (sem_timedwait(&m_safe_flush, &ts)) { |
| DEBUG_PRINT_ERROR("Failed to wait for EBDs of CODEC CONFIG buffers"); |
| } |
| BITMASK_CLEAR (&m_flags,OMX_COMPONENT_FLUSH_DEFERRED); |
| } |
| } |
| |
| if (OMX_CORE_INPUT_PORT_INDEX == param1 || OMX_ALL == param1) { |
| BITMASK_SET(&m_flags, OMX_COMPONENT_INPUT_FLUSH_PENDING); |
| } |
| if (OMX_CORE_OUTPUT_PORT_INDEX == param1 || OMX_ALL == param1) { |
| BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_FLUSH_PENDING); |
| } |
| if (!sem_posted) { |
| sem_posted = 1; |
| DEBUG_PRINT_LOW("Set the Semaphore"); |
| sem_post (&m_cmd_lock); |
| execute_omx_flush(param1); |
| } |
| bFlag = 0; |
| } else if ( cmd == OMX_CommandPortEnable) { |
| DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandPortEnable issued" |
| "with param1: %u", (unsigned int)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"); |
| 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("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"); |
| BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_ENABLE_PENDING); |
| // Skip the event notification |
| bFlag = 0; |
| } |
| } |
| } else if (cmd == OMX_CommandPortDisable) { |
| DEBUG_PRINT_HIGH("send_command_proxy(): OMX_CommandPortDisable issued" |
| "with param1: %u", (unsigned int)param1); |
| if (param1 == OMX_CORE_INPUT_PORT_INDEX || param1 == OMX_ALL) { |
| codec_config_flag = false; |
| 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("Disable output Port command recieved"); |
| if ((m_state == OMX_StateLoaded || m_state == OMX_StateIdle) |
| && release_output_done()) { |
| post_event(OMX_CommandPortDisable,OMX_CORE_OUTPUT_PORT_INDEX,\ |
| OMX_COMPONENT_GENERATE_EVENT); |
| } else { |
| BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_DISABLE_PENDING); |
| if (m_state == OMX_StatePause ||m_state == OMX_StateExecuting) { |
| if (!sem_posted) { |
| sem_posted = 1; |
| sem_post (&m_cmd_lock); |
| } |
| BITMASK_SET(&m_flags, OMX_COMPONENT_OUTPUT_FLUSH_IN_DISABLE_PENDING); |
| execute_omx_flush(OMX_CORE_OUTPUT_PORT_INDEX); |
| } |
| // Skip the event notification |
| bFlag = 0; |
| |
| } |
| } |
| } else { |
| DEBUG_PRINT_ERROR("Error: Invalid Command other than StateSet (%d)",cmd); |
| eRet = OMX_ErrorNotImplemented; |
| } |
| if (eRet == OMX_ErrorNone && bFlag) { |
| post_event(cmd,eState,OMX_COMPONENT_GENERATE_EVENT); |
| } |
| if (!sem_posted) { |
| sem_post(&m_cmd_lock); |
| } |
| |
| return eRet; |
| } |
| |
| /* ====================================================================== |
| FUNCTION |
| omx_vdec::ExecuteOmxFlush |
| |
| DESCRIPTION |
| Executes the OMX flush. |
| |
| PARAMETERS |
| flushtype - input flush(1)/output flush(0)/ both. |
| |
| RETURN VALUE |
| true/false |
| |
| ========================================================================== */ |
| bool omx_vdec::execute_omx_flush(OMX_U32 flushType) |
| { |
| bool bRet = false; |
| struct v4l2_plane plane; |
| struct v4l2_buffer v4l2_buf; |
| struct v4l2_decoder_cmd dec; |
| DEBUG_PRINT_LOW("in %s, flushing %u", __func__, (unsigned int)flushType); |
| memset((void *)&v4l2_buf,0,sizeof(v4l2_buf)); |
| dec.cmd = V4L2_DEC_QCOM_CMD_FLUSH; |
| |
| DEBUG_PRINT_HIGH("in %s: reconfig? %d", __func__, in_reconfig); |
| |
| if (in_reconfig && flushType == OMX_CORE_OUTPUT_PORT_INDEX) { |
| output_flush_progress = true; |
| dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE; |
| } else { |
| /* XXX: The driver/hardware does not support flushing of individual ports |
| * in all states. So we pretty much need to flush both ports internally, |
| * but client should only get the FLUSH_(INPUT|OUTPUT)_DONE for the one it |
| * requested. Since OMX_COMPONENT_(OUTPUT|INPUT)_FLUSH_PENDING isn't set, |
| * we automatically omit sending the FLUSH done for the "opposite" port. */ |
| input_flush_progress = true; |
| output_flush_progress = true; |
| dec.flags = V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT | V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE; |
| } |
| |
| if (ioctl(drv_ctx.video_driver_fd, VIDIOC_DECODER_CMD, &dec)) { |
| DEBUG_PRINT_ERROR("Flush Port (%u) Failed ", (unsigned int)flushType); |
| bRet = false; |
| } |
| |
| return bRet; |
| } |
| /*========================================================================= |
| FUNCTION : execute_output_flush |
| |
| DESCRIPTION |
| Executes the OMX flush at OUTPUT PORT. |
| |
| PARAMETERS |
| None. |
| |
| RETURN VALUE |
| true/false |
| ==========================================================================*/ |
| bool omx_vdec::execute_output_flush() |
| { |
| unsigned long p1 = 0; // Parameter - 1 |
| unsigned long p2 = 0; // Parameter - 2 |
| unsigned long ident = 0; |
| bool bRet = true; |
| |
| /*Generate FBD for all Buffers in the FTBq*/ |
| pthread_mutex_lock(&m_lock); |
| DEBUG_PRINT_LOW("Initiate Output Flush"); |
| |
| //reset last render TS |
| if(m_last_rendered_TS > 0) { |
| m_last_rendered_TS = 0; |
| } |
| |
| while (m_ftb_q.m_size) { |
| DEBUG_PRINT_LOW("Buffer queue size %lu pending buf cnt %d", |
| m_ftb_q.m_size,pending_output_buffers); |
| m_ftb_q.pop_entry(&p1,&p2,&ident); |
| DEBUG_PRINT_LOW("ID(%lx) P1(%lx) P2(%lx)", ident, p1, p2); |
| if (ident == m_fill_output_msg ) { |
| m_cb.FillBufferDone(&m_cmp, m_app_data, (OMX_BUFFERHEADERTYPE *)(intptr_t)p2); |
| } else if (ident == OMX_COMPONENT_GENERATE_FBD) { |
| fill_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)(intptr_t)p1); |
| } |
| } |
| pthread_mutex_unlock(&m_lock); |
| output_flush_progress = false; |
| |
| if (arbitrary_bytes) { |
| prev_ts = LLONG_MAX; |
| rst_prev_ts = true; |
| } |
| DEBUG_PRINT_HIGH("OMX flush o/p Port complete PenBuf(%d)", pending_output_buffers); |
| return bRet; |
| } |
| /*========================================================================= |
| FUNCTION : execute_input_flush |
| |
| DESCRIPTION |
| Executes the OMX flush at INPUT PORT. |
| |
| PARAMETERS |
| None. |
| |
| RETURN VALUE |
| true/false |
| ==========================================================================*/ |
| bool omx_vdec::execute_input_flush() |
| { |
| unsigned i =0; |
| unsigned long p1 = 0; // Parameter - 1 |
| unsigned long p2 = 0; // Parameter - 2 |
| unsigned long ident = 0; |
| bool bRet = true; |
| |
| /*Generate EBD for all Buffers in the ETBq*/ |
| DEBUG_PRINT_LOW("Initiate Input Flush"); |
| |
| pthread_mutex_lock(&m_lock); |
| DEBUG_PRINT_LOW("Check if the Queue is empty"); |
| while (m_etb_q.m_size) { |
| m_etb_q.pop_entry(&p1,&p2,&ident); |
| |
| if (ident == OMX_COMPONENT_GENERATE_ETB_ARBITRARY) { |
| DEBUG_PRINT_LOW("Flush Input Heap Buffer %p",(OMX_BUFFERHEADERTYPE *)p2); |
| m_cb.EmptyBufferDone(&m_cmp ,m_app_data, (OMX_BUFFERHEADERTYPE *)p2); |
| } else if (ident == OMX_COMPONENT_GENERATE_ETB) { |
| pending_input_buffers++; |
| DEBUG_PRINT_LOW("Flush Input OMX_COMPONENT_GENERATE_ETB %p, pending_input_buffers %d", |
| (OMX_BUFFERHEADERTYPE *)p2, pending_input_buffers); |
| empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p2); |
| } else if (ident == OMX_COMPONENT_GENERATE_EBD) { |
| DEBUG_PRINT_LOW("Flush Input OMX_COMPONENT_GENERATE_EBD %p", |
| (OMX_BUFFERHEADERTYPE *)p1); |
| empty_buffer_done(&m_cmp,(OMX_BUFFERHEADERTYPE *)p1); |
| } |
| } |
| time_stamp_dts.flush_timestamp(); |
| /*Check if Heap Buffers are to be flushed*/ |
| if (arbitrary_bytes && !(codec_config_flag)) { |
| DEBUG_PRINT_LOW("Reset all the variables before flusing"); |
| h264_scratch.nFilledLen = 0; |
| nal_count = 0; |
| look_ahead_nal = false; |
| frame_count = 0; |
| h264_last_au_ts = LLONG_MAX; |
| h264_last_au_flags = 0; |
| memset(m_demux_offsets, 0, ( sizeof(OMX_U32) * 8192) ); |
| m_demux_entries = 0; |
| DEBUG_PRINT_LOW("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 long) pdest_frame, (unsigned int)NULL, |
| (unsigned int)NULL); |
| pdest_frame = NULL; |
| } |
| m_frame_parser.flush(); |
| } else if (codec_config_flag) { |
| DEBUG_PRINT_HIGH("frame_parser flushing skipped due to codec config buffer " |
| "is not sent to the driver yet"); |
| } |
| pthread_mutex_unlock(&m_lock); |
| input_flush_progress = false; |
| if (!arbitrary_bytes) { |
| prev_ts = LLONG_MAX; |
| rst_prev_ts = true; |
| } |
| #ifdef _ANDROID_ |
| if (m_debug_timestamp) { |
| m_timestamp_list.reset_ts_list(); |
| } |
| #endif |
| DEBUG_PRINT_HIGH("OMX flush i/p Port complete PenBuf(%d)", pending_input_buffers); |
| return bRet; |
| } |
| |
| |
| /* ====================================================================== |
| FUNCTION |
| omx_vdec::SendCommandEvent |
| |
| DESCRIPTION |
| Send the event to decoder pipe. This is needed to generate the callbacks |
| in decoder thread context. |
| |
| PARAMETERS |
| None. |
| |
| RETURN VALUE |
| true/false |
| |
| ========================================================================== */ |
| bool omx_vdec::post_event(unsigned long p1, |
| unsigned long p2, |
| unsigned long id) |
| { |
| bool bRet = false; |
| |
| /* Just drop messages typically generated by hardware (w/o client request), |
| * if we've reported an error to client. */ |
| if (m_error_propogated) { |
| switch (id) { |
| case OMX_COMPONENT_GENERATE_PORT_RECONFIG: |
| case OMX_COMPONENT_GENERATE_HARDWARE_ERROR: |
| DEBUG_PRINT_ERROR("Dropping message %lx " |
| "since client expected to be in error state", id); |
| return false; |
| default: |
| /* whatever */ |
|