/*
* Copyright (c) 2009-2012 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "OMXVideoDecoder"
#include <wrs_omxil_core/log.h>
#include "OMXVideoDecoderAVCSecure.h"
#include <time.h>
#include <signal.h>
#include <pthread.h>
#include "VideoFrameInfo.h"
// Be sure to have an equal string in VideoDecoderHost.cpp (libmix)
static const char* AVC_MIME_TYPE = "video/avc";
static const char* AVC_SECURE_MIME_TYPE = "video/avc-secure";
#define DATA_BUFFER_INITIAL_OFFSET 0 //1024
#define DATA_BUFFER_SIZE (8 * 1024 * 1024)
#define KEEP_ALIVE_INTERVAL 5 // seconds
#define DRM_KEEP_ALIVE_TIMER 1000000
#define WV_SESSION_ID 0x00000011
#define NALU_BUFFER_SIZE 8192
#define NALU_HEADER_LENGTH 1024 // THis should be changed to 4K
#define FLUSH_WAIT_INTERVAL (30 * 1000) //30 ms
#define DRM_SCHEME_NONE 0
#define DRM_SCHEME_WVC 1
#define DRM_SCHEME_CENC 2
#define DRM_SCHEME_PRASF 3
//#pragma pack(push, 1)
struct DataBuffer {
uint32_t size;
uint8_t *data;
uint8_t clear;
uint32_t drmScheme;
uint32_t session_id; //used by PR only
uint32_t flags; //used by PR only
};
//#pragma pack(pop)
bool OMXVideoDecoderAVCSecure::EnableIEDSession(bool enable)
{
if (mDrmDevFd <= 0) {
ALOGE("invalid mDrmDevFd");
return false;
}
int request = enable ? DRM_PSB_ENABLE_IED_SESSION : DRM_PSB_DISABLE_IED_SESSION;
int ret = drmCommandNone(mDrmDevFd, request);
return ret == 0;
}
OMXVideoDecoderAVCSecure::OMXVideoDecoderAVCSecure()
: mKeepAliveTimer(0),
mSessionPaused(false){
ALOGV("OMXVideoDecoderAVCSecure is constructed.");
if (drm_vendor_api_init(&drm_vendor_api)) {
ALOGE("drm_vendor_api_init failed");
}
mVideoDecoder = createVideoDecoder(AVC_SECURE_MIME_TYPE);
if (!mVideoDecoder) {
ALOGE("createVideoDecoder failed for \"%s\"", AVC_SECURE_MIME_TYPE);
}
// Override default native buffer count defined in the base class
mNativeBufferCount = OUTPORT_NATIVE_BUFFER_COUNT;
BuildHandlerList();
mDrmDevFd = open("/dev/card0", O_RDWR, 0);
if (mDrmDevFd <= 0) {
ALOGE("Failed to open drm device.");
}
}
OMXVideoDecoderAVCSecure::~OMXVideoDecoderAVCSecure() {
ALOGI("OMXVideoDecoderAVCSecure is destructed.");
if (drm_vendor_api_deinit(&drm_vendor_api)) {
ALOGE("drm_vendor_api_deinit failed");
}
if (mDrmDevFd > 0) {
close(mDrmDevFd);
mDrmDevFd = 0;
}
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::InitInputPortFormatSpecific(OMX_PARAM_PORTDEFINITIONTYPE *paramPortDefinitionInput) {
// OMX_PARAM_PORTDEFINITIONTYPE
paramPortDefinitionInput->nBufferCountActual = INPORT_ACTUAL_BUFFER_COUNT;
paramPortDefinitionInput->nBufferCountMin = INPORT_MIN_BUFFER_COUNT;
paramPortDefinitionInput->nBufferSize = INPORT_BUFFER_SIZE;
paramPortDefinitionInput->format.video.cMIMEType = (OMX_STRING)AVC_MIME_TYPE;
paramPortDefinitionInput->format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
// OMX_VIDEO_PARAM_AVCTYPE
memset(&mParamAvc, 0, sizeof(mParamAvc));
SetTypeHeader(&mParamAvc, sizeof(mParamAvc));
mParamAvc.nPortIndex = INPORT_INDEX;
// TODO: check eProfile/eLevel
mParamAvc.eProfile = OMX_VIDEO_AVCProfileHigh; //OMX_VIDEO_AVCProfileBaseline;
mParamAvc.eLevel = OMX_VIDEO_AVCLevel41; //OMX_VIDEO_AVCLevel1;
this->ports[INPORT_INDEX]->SetMemAllocator(MemAllocDataBuffer, MemFreeDataBuffer, this);
for (int i = 0; i < INPORT_ACTUAL_BUFFER_COUNT; i++) {
mDataBufferSlot[i].offset = DATA_BUFFER_INITIAL_OFFSET + i * INPORT_BUFFER_SIZE;
mDataBufferSlot[i].owner = NULL;
}
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::ProcessorInit(void) {
mSessionPaused = false;
if (drm_vendor_api.handle == NULL) {
return OMX_ErrorUndefined;
}
return OMXVideoDecoderBase::ProcessorInit();
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::ProcessorDeinit(void) {
WaitForFrameDisplayed();
// Session should be torn down in ProcessorStop, delayed to ProcessorDeinit
// to allow remaining frames completely rendered.
ALOGI("Calling Drm_DestroySession.");
uint32_t ret = drm_vendor_api.drm_stop_playback();
if (ret != DRM_WV_MOD_SUCCESS) {
ALOGE("drm_stop_playback failed: (0x%x)", ret);
}
EnableIEDSession(false);
return OMXVideoDecoderBase::ProcessorDeinit();
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::ProcessorStart(void) {
uint32_t imrOffset = 0;
uint32_t dataBufferSize = DATA_BUFFER_SIZE;
EnableIEDSession(true);
uint32_t ret = drm_vendor_api.drm_start_playback();
if (ret != DRM_WV_MOD_SUCCESS) {
ALOGE("drm_start_playback failed: (0x%x)", ret);
}
mSessionPaused = false;
return OMXVideoDecoderBase::ProcessorStart();
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::ProcessorStop(void) {
if (mKeepAliveTimer != 0) {
timer_delete(mKeepAliveTimer);
mKeepAliveTimer = 0;
}
return OMXVideoDecoderBase::ProcessorStop();
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::ProcessorFlush(OMX_U32 portIndex) {
return OMXVideoDecoderBase::ProcessorFlush(portIndex);
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::ProcessorProcess(
OMX_BUFFERHEADERTYPE ***pBuffers,
buffer_retain_t *retains,
OMX_U32 numberBuffers) {
int ret_value;
OMX_BUFFERHEADERTYPE *pInput = *pBuffers[INPORT_INDEX];
DataBuffer *dataBuffer = (DataBuffer *)pInput->pBuffer;
if((dataBuffer->drmScheme == DRM_SCHEME_WVC) && (!mKeepAliveTimer)){
struct sigevent sev;
memset(&sev, 0, sizeof(sev));
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_value.sival_ptr = this;
sev.sigev_notify_function = KeepAliveTimerCallback;
ret_value = timer_create(CLOCK_REALTIME, &sev, &mKeepAliveTimer);
if (ret_value != 0) {
ALOGE("Failed to create timer.");
} else {
struct itimerspec its;
its.it_value.tv_sec = -1; // never expire
its.it_value.tv_nsec = 0;
its.it_interval.tv_sec = KEEP_ALIVE_INTERVAL;
its.it_interval.tv_nsec = 0;
ret_value = timer_settime(mKeepAliveTimer, TIMER_ABSTIME, &its, NULL);
if (ret_value != 0) {
ALOGE("Failed to set timer.");
}
}
}
if (dataBuffer->size == 0) {
// error occurs during decryption.
ALOGW("size of returned data buffer is 0, decryption fails.");
mVideoDecoder->flush();
usleep(FLUSH_WAIT_INTERVAL);
OMX_BUFFERHEADERTYPE *pOutput = *pBuffers[OUTPORT_INDEX];
pOutput->nFilledLen = 0;
// reset Data buffer size
dataBuffer->size = INPORT_BUFFER_SIZE;
this->ports[INPORT_INDEX]->FlushPort();
this->ports[OUTPORT_INDEX]->FlushPort();
return OMX_ErrorNone;
}
OMX_ERRORTYPE ret;
ret = OMXVideoDecoderBase::ProcessorProcess(pBuffers, retains, numberBuffers);
if (ret != OMX_ErrorNone) {
ALOGE("OMXVideoDecoderBase::ProcessorProcess failed. Result: %#x", ret);
return ret;
}
if (mSessionPaused && (retains[OUTPORT_INDEX] == BUFFER_RETAIN_GETAGAIN)) {
retains[OUTPORT_INDEX] = BUFFER_RETAIN_NOT_RETAIN;
OMX_BUFFERHEADERTYPE *pOutput = *pBuffers[OUTPORT_INDEX];
pOutput->nFilledLen = 0;
this->ports[INPORT_INDEX]->FlushPort();
this->ports[OUTPORT_INDEX]->FlushPort();
}
return ret;
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::ProcessorPause(void) {
return OMXVideoDecoderBase::ProcessorPause();
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::ProcessorResume(void) {
return OMXVideoDecoderBase::ProcessorResume();
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::PrepareConfigBuffer(VideoConfigBuffer *p) {
OMX_ERRORTYPE ret;
ret = OMXVideoDecoderBase::PrepareConfigBuffer(p);
CHECK_RETURN_VALUE("OMXVideoDecoderBase::PrepareConfigBuffer");
p->flag |= WANT_SURFACE_PROTECTION;
return ret;
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::PrepareWVCDecodeBuffer(OMX_BUFFERHEADERTYPE *buffer, buffer_retain_t *retain, VideoDecodeBuffer *p)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
(void) retain; // unused parameter
p->flag |= HAS_COMPLETE_FRAME;
if (buffer->nOffset != 0) {
ALOGW("buffer offset %u is not zero!!!", buffer->nOffset);
}
DataBuffer *dataBuffer = (DataBuffer *)buffer->pBuffer;
if (dataBuffer->clear) {
p->data = dataBuffer->data + buffer->nOffset;
p->size = buffer->nFilledLen;
} else {
dataBuffer->size = NALU_BUFFER_SIZE;
struct drm_wv_nalu_headers nalu_headers;
nalu_headers.p_enc_ciphertext = dataBuffer->data;
// TODO: NALU Buffer is supposed to be 4k but using 1k, fix it once chaabi fix is there
nalu_headers.hdrs_buf_len = NALU_HEADER_LENGTH;
nalu_headers.frame_size = buffer->nFilledLen;
// Make sure that NALU header frame size is 16 bytes aligned
nalu_headers.frame_size = (nalu_headers.frame_size + 0xF) & (~0xF);
// Use same video buffer to fill NALU headers returned by chaabi,
// Adding 4 because the first 4 bytes after databuffer will be used to store length of NALU headers
if((nalu_headers.frame_size + NALU_HEADER_LENGTH) > INPORT_BUFFER_SIZE){
ALOGE("Not enough buffer for NALU headers");
return OMX_ErrorOverflow;
}
nalu_headers.p_hdrs_buf = (uint8_t *)(dataBuffer->data + nalu_headers.frame_size + 4);
nalu_headers.parse_size = buffer->nFilledLen;
uint32_t res = drm_vendor_api.drm_wv_return_naluheaders(WV_SESSION_ID, &nalu_headers);
if (res == DRM_FAIL_FW_SESSION) {
ALOGW("Drm_WV_ReturnNALUHeaders failed. Session is disabled.");
mSessionPaused = true;
ret = OMX_ErrorNotReady;
} else if (res != 0) {
mSessionPaused = false;
ALOGE("Drm_WV_ReturnNALUHeaders failed. Error = %#x, frame_size: %d, len = %u", res, nalu_headers.frame_size, buffer->nFilledLen);
ret = OMX_ErrorHardware;
} else {
mSessionPaused = false;
// If chaabi returns 0 NALU headers fill the frame size to zero.
if (!nalu_headers.hdrs_buf_len) {
p->size = 0;
return ret;
}
else{
// NALU headers are appended to encrypted video bitstream
// |...encrypted video bitstream (16 bytes aligned)...| 4 bytes of header size |...NALU headers..|
uint32_t *ptr = (uint32_t*)(dataBuffer->data + nalu_headers.frame_size);
*ptr = nalu_headers.hdrs_buf_len;
p->data = dataBuffer->data;
p->size = nalu_headers.frame_size;
p->flag |= IS_SECURE_DATA;
}
}
}
// reset Data size
dataBuffer->size = NALU_BUFFER_SIZE;
return ret;
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::PrepareCENCDecodeBuffer(OMX_BUFFERHEADERTYPE *buffer, buffer_retain_t *retain, VideoDecodeBuffer *p)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
(void) retain; // unused parameter
// OMX_BUFFERFLAG_CODECCONFIG is an optional flag
// if flag is set, buffer will only contain codec data.
if (buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
ALOGI("Received AVC codec data.");
// return ret;
}
p->flag |= HAS_COMPLETE_FRAME | IS_SUBSAMPLE_ENCRYPTION;
if (buffer->nOffset != 0) {
ALOGW("buffer offset %u is not zero!!!", buffer->nOffset);
}
DataBuffer *dataBuffer = (DataBuffer *)buffer->pBuffer;
p->data = dataBuffer->data;
p->size = sizeof(frame_info_t);
p->flag |= IS_SECURE_DATA;
return ret;
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::PreparePRASFDecodeBuffer(OMX_BUFFERHEADERTYPE *buffer, buffer_retain_t *retain, VideoDecodeBuffer *p)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
(void) retain; // unused parameter
// OMX_BUFFERFLAG_CODECCONFIG is an optional flag
// if flag is set, buffer will only contain codec data.
if (buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
ALOGV("PR: Received codec data.");
return ret;
}
p->flag |= HAS_COMPLETE_FRAME;
if (buffer->nOffset != 0) {
ALOGW("PR:buffer offset %u is not zero!!!", buffer->nOffset);
}
DataBuffer *dataBuffer = (DataBuffer *)buffer->pBuffer;
if (dataBuffer->clear) {
p->data = dataBuffer->data + buffer->nOffset;
p->size = buffer->nFilledLen;
} else {
dataBuffer->size = NALU_BUFFER_SIZE;
struct drm_nalu_headers nalu_headers;
nalu_headers.p_enc_ciphertext = dataBuffer->data;
// TODO: NALU Buffer is supposed to be 4k but using 1k, fix it once chaabi fix is there
nalu_headers.hdrs_buf_len = NALU_HEADER_LENGTH;
nalu_headers.frame_size = buffer->nFilledLen;
// Make sure that NALU header frame size is 16 bytes aligned
nalu_headers.frame_size = (nalu_headers.frame_size + 0xF) & (~0xF);
// Use same video buffer to fill NALU headers returned by chaabi,
// Adding 4 because the first 4 bytes after databuffer will be used to store length of NALU headers
if((nalu_headers.frame_size + NALU_HEADER_LENGTH) > INPORT_BUFFER_SIZE){
ALOGE("Not enough buffer for NALU headers");
return OMX_ErrorOverflow;
}
nalu_headers.p_hdrs_buf = (uint8_t *)(dataBuffer->data + nalu_headers.frame_size + 4);
nalu_headers.parse_size = buffer->nFilledLen;
uint32_t res = drm_vendor_api.drm_pr_return_naluheaders(dataBuffer->session_id, &nalu_headers);
if (res == DRM_FAIL_FW_SESSION || !nalu_headers.hdrs_buf_len) {
ALOGW("drm_ReturnNALUHeaders failed. Session is disabled.");
mSessionPaused = true;
ret = OMX_ErrorNotReady;
} else if (res != 0) {
mSessionPaused = false;
ALOGE("drm_pr_return_naluheaders failed. Error = %#x, frame_size: %d, len = %u", res, nalu_headers.frame_size, buffer->nFilledLen);
ret = OMX_ErrorHardware;
} else {
mSessionPaused = false;
// If chaabi returns 0 NALU headers fill the frame size to zero.
if (!nalu_headers.hdrs_buf_len) {
p->size = 0;
return ret;
}
else{
// NALU headers are appended to encrypted video bitstream
// |...encrypted video bitstream (16 bytes aligned)...| 4 bytes of header size |...NALU headers..|
uint32_t *ptr = (uint32_t*)(dataBuffer->data + nalu_headers.frame_size);
*ptr = nalu_headers.hdrs_buf_len;
p->data = dataBuffer->data;
p->size = nalu_headers.frame_size;
p->flag |= IS_SECURE_DATA;
}
}
}
// reset Data size
dataBuffer->size = NALU_BUFFER_SIZE;
return ret;
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::PrepareDecodeBuffer(OMX_BUFFERHEADERTYPE *buffer, buffer_retain_t *retain, VideoDecodeBuffer *p) {
OMX_ERRORTYPE ret;
ret = OMXVideoDecoderBase::PrepareDecodeBuffer(buffer, retain, p);
CHECK_RETURN_VALUE("OMXVideoDecoderBase::PrepareDecodeBuffer");
if (buffer->nFilledLen == 0) {
return OMX_ErrorNone;
}
DataBuffer *dataBuffer = (DataBuffer *)buffer->pBuffer;
if(dataBuffer->drmScheme == DRM_SCHEME_WVC){
// OMX_BUFFERFLAG_CODECCONFIG is an optional flag
// if flag is set, buffer will only contain codec data.
mDrmScheme = DRM_SCHEME_WVC;
if (buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
ALOGV("Received AVC codec data.");
return ret;
}
return PrepareWVCDecodeBuffer(buffer, retain, p);
}
else if(dataBuffer->drmScheme == DRM_SCHEME_CENC) {
mDrmScheme = DRM_SCHEME_CENC;
return PrepareCENCDecodeBuffer(buffer, retain, p);
}
else if(dataBuffer->drmScheme == DRM_SCHEME_PRASF)
{
mDrmScheme = DRM_SCHEME_PRASF;
return PreparePRASFDecodeBuffer(buffer, retain, p);
}
return ret;
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::BuildHandlerList(void) {
OMXVideoDecoderBase::BuildHandlerList();
AddHandler(OMX_IndexParamVideoAvc, GetParamVideoAvc, SetParamVideoAvc);
AddHandler(OMX_IndexParamVideoProfileLevelQuerySupported, GetParamVideoAVCProfileLevel, SetParamVideoAVCProfileLevel);
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::GetParamVideoAvc(OMX_PTR pStructure) {
OMX_ERRORTYPE ret;
OMX_VIDEO_PARAM_AVCTYPE *p = (OMX_VIDEO_PARAM_AVCTYPE *)pStructure;
CHECK_TYPE_HEADER(p);
CHECK_PORT_INDEX(p, INPORT_INDEX);
memcpy(p, &mParamAvc, sizeof(*p));
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::SetParamVideoAvc(OMX_PTR pStructure) {
OMX_ERRORTYPE ret;
OMX_VIDEO_PARAM_AVCTYPE *p = (OMX_VIDEO_PARAM_AVCTYPE *)pStructure;
CHECK_TYPE_HEADER(p);
CHECK_PORT_INDEX(p, INPORT_INDEX);
CHECK_SET_PARAM_STATE();
// TODO: do we need to check if port is enabled?
// TODO: see SetPortAvcParam implementation - Can we make simple copy????
memcpy(&mParamAvc, p, sizeof(mParamAvc));
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::GetParamVideoAVCProfileLevel(OMX_PTR pStructure) {
OMX_ERRORTYPE ret;
OMX_VIDEO_PARAM_PROFILELEVELTYPE *p = (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)pStructure;
CHECK_TYPE_HEADER(p);
CHECK_PORT_INDEX(p, INPORT_INDEX);
struct ProfileLevelTable {
OMX_U32 profile;
OMX_U32 level;
} plTable[] = {
{OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel42},
{OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel42},
{OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel42}
};
OMX_U32 count = sizeof(plTable)/sizeof(ProfileLevelTable);
CHECK_ENUMERATION_RANGE(p->nProfileIndex,count);
p->eProfile = plTable[p->nProfileIndex].profile;
p->eLevel = plTable[p->nProfileIndex].level;
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::SetParamVideoAVCProfileLevel(OMX_PTR pStructure) {
ALOGW("SetParamVideoAVCProfileLevel is not supported.");
(void) pStructure; // unused parameter
return OMX_ErrorUnsupportedSetting;
}
OMX_U8* OMXVideoDecoderAVCSecure::MemAllocDataBuffer(OMX_U32 nSizeBytes, OMX_PTR pUserData) {
OMXVideoDecoderAVCSecure* p = (OMXVideoDecoderAVCSecure *)pUserData;
if (p) {
return p->MemAllocDataBuffer(nSizeBytes);
}
ALOGE("NULL pUserData.");
return NULL;
}
void OMXVideoDecoderAVCSecure::MemFreeDataBuffer(OMX_U8 *pBuffer, OMX_PTR pUserData) {
OMXVideoDecoderAVCSecure* p = (OMXVideoDecoderAVCSecure *)pUserData;
if (p) {
p->MemFreeDataBuffer(pBuffer);
return;
}
ALOGE("NULL pUserData.");
}
OMX_U8* OMXVideoDecoderAVCSecure::MemAllocDataBuffer(OMX_U32 nSizeBytes) {
if (nSizeBytes > INPORT_BUFFER_SIZE) {
ALOGE("Invalid size (%u) of memory to allocate.", nSizeBytes);
return NULL;
}
ALOGW_IF(nSizeBytes != INPORT_BUFFER_SIZE, "Size of memory to allocate is %u", nSizeBytes);
for (int i = 0; i < INPORT_ACTUAL_BUFFER_COUNT; i++) {
if (mDataBufferSlot[i].owner == NULL) {
DataBuffer *pBuffer = new DataBuffer;
if (pBuffer == NULL) {
ALOGE("Failed to allocate memory.");
return NULL;
}
pBuffer->data = new uint8_t [INPORT_BUFFER_SIZE];
if (pBuffer->data == NULL) {
delete pBuffer;
ALOGE("Failed to allocate memory, size to allocate %d.", INPORT_BUFFER_SIZE);
return NULL;
}
// Is this required for classic or not?
// pBuffer->offset = mDataBufferSlot[i].offset;
pBuffer->size = INPORT_BUFFER_SIZE;
mDataBufferSlot[i].owner = (OMX_U8 *)pBuffer;
ALOGV("Allocating buffer = %#x, Data offset = %#x, data = %#x", (uint32_t)pBuffer, mDataBufferSlot[i].offset, (uint32_t)pBuffer->data);
return (OMX_U8 *) pBuffer;
}
}
ALOGE("Data buffer slot is not available.");
return NULL;
}
void OMXVideoDecoderAVCSecure::MemFreeDataBuffer(OMX_U8 *pBuffer) {
DataBuffer *p = (DataBuffer*) pBuffer;
if (p == NULL) {
return;
}
for (int i = 0; i < INPORT_ACTUAL_BUFFER_COUNT; i++) {
if (pBuffer == mDataBufferSlot[i].owner) {
ALOGV("Freeing Data buffer offset = %d, data = %#x", mDataBufferSlot[i].offset, (uint32_t)p->data);
delete [] p->data;
delete p;
mDataBufferSlot[i].owner = NULL;
return;
}
}
ALOGE("Invalid buffer %#x to de-allocate", (uint32_t)pBuffer);
}
void OMXVideoDecoderAVCSecure::KeepAliveTimerCallback(sigval v) {
OMXVideoDecoderAVCSecure *p = (OMXVideoDecoderAVCSecure *)v.sival_ptr;
if (p) {
p->KeepAliveTimerCallback();
}
}
void OMXVideoDecoderAVCSecure::KeepAliveTimerCallback() {
uint32_t timeout = DRM_KEEP_ALIVE_TIMER;
uint32_t sepres = drm_vendor_api.drm_keep_alive(WV_SESSION_ID, &timeout);
if (sepres != 0) {
ALOGE("Drm_KeepAlive failed. Result = %#x", sepres);
}
}
void OMXVideoDecoderAVCSecure::WaitForFrameDisplayed() {
if (mDrmDevFd <= 0) {
ALOGE("Invalid mDrmDevFd");
return;
}
// Wait up to 200ms until both overlay planes are disabled
int status = 3;
int retry = 20;
while (retry--) {
for (int i = 0; i < 2; i++) {
if (status & (1 << i)) {
struct drm_psb_register_rw_arg arg;
memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
arg.get_plane_state_mask = 1;
arg.plane.type = DC_OVERLAY_PLANE;
arg.plane.index = i;
int ret = drmCommandWriteRead(mDrmDevFd, DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
if (ret != 0) {
ALOGE("Failed to query status of overlay plane %d, ret = %d", i, ret);
status &= ~(1 << i);
} else if (arg.plane.ctx == PSB_DC_PLANE_DISABLED) {
status &= ~(1 << i);
}
}
}
if (status == 0) {
break;
}
// Sleep 10ms then query again
usleep(10000);
}
if (status != 0) {
ALOGE("Overlay planes not disabled, status %d", status);
}
}
OMX_ERRORTYPE OMXVideoDecoderAVCSecure::SetMaxOutputBufferCount(OMX_PARAM_PORTDEFINITIONTYPE *p) {
OMX_ERRORTYPE ret;
CHECK_TYPE_HEADER(p);
CHECK_PORT_INDEX(p, OUTPORT_INDEX);
p->nBufferCountActual = OUTPORT_NATIVE_BUFFER_COUNT;
return OMXVideoDecoderBase::SetMaxOutputBufferCount(p);
}
DECLARE_OMX_COMPONENT("OMX.Intel.VideoDecoder.AVC.secure", "video_decoder.avc", OMXVideoDecoderAVCSecure);