android_mt6572_jiabo/hardware/ti/omap4/camera/OmxFrameDecoder.cpp
2025-09-05 16:56:03 +08:00

1077 lines
36 KiB
C++

/*
* Copyright (C) Texas Instruments - http://www.ti.com/
*
* 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.
*/
#include "ErrorUtils.h"
#include "OmxFrameDecoder.h"
#include "OMX_TI_IVCommon.h"
#include "OMX_TI_Index.h"
#include "Decoder_libjpeg.h"
namespace Ti {
namespace Camera {
const static uint32_t kMaxColorFormatSupported = 1000;
const static int kMaxStateSwitchTimeOut = 1 * 1000 * 1000 * 1000; // 1 sec
static const char* gDecoderRole[2] = {"video_decoder.mjpeg", "video_decoder.avc"};
static const OMX_VIDEO_CODINGTYPE gCompressionFormat[2] = {OMX_VIDEO_CodingMJPEG, OMX_VIDEO_CodingAVC};
template<class T>
static void InitOMXParams(T *params) {
params->nSize = sizeof(T);
params->nVersion.s.nVersionMajor = 1;
params->nVersion.s.nVersionMinor = 0;
params->nVersion.s.nRevision = 0;
params->nVersion.s.nStep = 0;
}
CallbackDispatcher::CallbackDispatcher()
: mDone(false) {
mThread = new CallbackDispatcherThread(this);
mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_FOREGROUND);
}
CallbackDispatcher::~CallbackDispatcher() {
{
android::Mutex::Autolock autoLock(mLock);
mDone = true;
mQueueChanged.signal();
}
status_t status = mThread->join();
if (status != WOULD_BLOCK) {
//CAMHAL_ASSERT(status, (status_t)NO_ERROR);
}
}
void CallbackDispatcher::post(const OmxMessage &msg) {
android::Mutex::Autolock autoLock(mLock);
mQueue.push_back(msg);
mQueueChanged.signal();
}
void CallbackDispatcher::dispatch(const OmxMessage &msg) {
switch(msg.type)
{
case OmxMessage::EVENT :
{
static_cast<OmxFrameDecoder*>(msg.u.eventData.appData)->eventHandler(msg.u.eventData.event, msg.u.eventData.data1, msg.u.eventData.data2, msg.u.eventData.pEventData);
break;
}
case OmxMessage::EMPTY_BUFFER_DONE:
{
static_cast<OmxFrameDecoder*>(msg.u.bufferData.appData)->emptyBufferDoneHandler(msg.u.bufferData.pBuffHead);
break;
}
case OmxMessage::FILL_BUFFER_DONE:
{
static_cast<OmxFrameDecoder*>(msg.u.bufferData.appData)->fillBufferDoneHandler(msg.u.bufferData.pBuffHead);
break;
}
};
}
bool CallbackDispatcher::loop() {
for (;;) {
OmxMessage msg;
{
android::Mutex::Autolock autoLock(mLock);
while (!mDone && mQueue.empty()) {
mQueueChanged.wait(mLock);
}
if (mDone) {
break;
}
msg = *mQueue.begin();
mQueue.erase(mQueue.begin());
}
dispatch(msg);
}
return false;
}
bool CallbackDispatcherThread::threadLoop() {
return mDispatcher->loop();
}
//Static
OMX_ERRORTYPE OmxFrameDecoder::eventCallback(__unused const OMX_HANDLETYPE component,
const OMX_PTR appData, const OMX_EVENTTYPE event, const OMX_U32 data1, const OMX_U32 data2,
__unused const OMX_PTR pEventData) {
OmxMessage msg;
msg.type = OmxMessage::EVENT;
msg.u.eventData.appData = appData;
msg.u.eventData.event = event;
msg.u.eventData.data1 = data1;
msg.u.eventData.data2 = data2;
((OmxFrameDecoder *)appData)->mDispatcher.post(msg);
return OMX_ErrorNone;
}
//Static
OMX_ERRORTYPE OmxFrameDecoder::emptyBufferDoneCallback(__unused OMX_HANDLETYPE hComponent,
OMX_PTR appData, OMX_BUFFERHEADERTYPE* pBuffHead) {
OmxMessage msg;
msg.type = OmxMessage::EMPTY_BUFFER_DONE;
msg.u.bufferData.appData = appData;
msg.u.bufferData.pBuffHead = pBuffHead;
((OmxFrameDecoder *)appData)->mDispatcher.post(msg);
return OMX_ErrorNone;
}
//Static
OMX_ERRORTYPE OmxFrameDecoder::fillBufferDoneCallback(__unused OMX_HANDLETYPE hComponent,
OMX_PTR appData, OMX_BUFFERHEADERTYPE* pBuffHead) {
OmxMessage msg;
msg.type = OmxMessage::FILL_BUFFER_DONE;
msg.u.bufferData.appData = appData;
msg.u.bufferData.pBuffHead = pBuffHead;
((OmxFrameDecoder *)appData)->mDispatcher.post(msg);
return OMX_ErrorNone;
}
OmxFrameDecoder::OmxFrameDecoder(DecoderType type)
: mOmxInialized(false), mCurrentState(OmxDecoderState_Unloaded), mPreviousState(OmxDecoderState_Unloaded),
mStopping(false), mDecoderType(type), mIsNeedCheckDHT(true), mAlwaysAppendDHT(false) {
}
OmxFrameDecoder::~OmxFrameDecoder() {
}
OMX_ERRORTYPE OmxFrameDecoder::emptyBufferDoneHandler(OMX_BUFFERHEADERTYPE* pBuffHead) {
LOG_FUNCTION_NAME;
android::AutoMutex lock(mHwLock);
int bufferIndex = reinterpret_cast<int>(pBuffHead->pAppPrivate);
CAMHAL_LOGD("Got header %p id = %d", pBuffHead, bufferIndex);
android::sp<MediaBuffer>& in = mInBuffers->editItemAt(bufferIndex);
android::AutoMutex itemLock(in->getLock());
in->setStatus((getOmxState() == OmxDecoderState_Executing) ? BufferStatus_InDecoded : BufferStatus_InQueued);
return OMX_ErrorNone;
}
OMX_ERRORTYPE OmxFrameDecoder::fillBufferDoneHandler(OMX_BUFFERHEADERTYPE* pBuffHead) {
LOG_FUNCTION_NAME;
android::AutoMutex lock(mHwLock);
int index = (int)pBuffHead->pAppPrivate;
android::sp<MediaBuffer>& out = mOutBuffers->editItemAt(index);
android::AutoMutex itemLock(out->getLock());
CameraBuffer* frame = static_cast<CameraBuffer*>(out->buffer);
out->setOffset(pBuffHead->nOffset);
out->setTimestamp(pBuffHead->nTimeStamp);
out->setStatus((getOmxState() == OmxDecoderState_Executing) ? BufferStatus_OutFilled : BufferStatus_OutQueued);
return OMX_ErrorNone;
}
OMX_ERRORTYPE OmxFrameDecoder::eventHandler(const OMX_EVENTTYPE event, const OMX_U32 data1, const OMX_U32 data2,
__unused const OMX_PTR pEventData) {
LOG_FUNCTION_NAME;
OMX_ERRORTYPE ret = OMX_ErrorNone;
android::AutoMutex lock(mHwLock);
switch(event) {
case OMX_EventCmdComplete:
{
if ((data1 == OMX_CommandStateSet) && (data2 == OMX_StateIdle)) {
CAMHAL_LOGD("Component State Changed To OMX_StateIdle\n");
commitState(OmxDecoderState_Idle);
mStateCondition.signal();
}
else if ((data1 == OMX_CommandStateSet) && (data2 == OMX_StateExecuting)) {
CAMHAL_LOGD("Component State Changed To OMX_StateExecuting\n");
commitState(OmxDecoderState_Executing);
mStateCondition.signal();
}
else if ((data1 == OMX_CommandStateSet) && (data2 == OMX_StateLoaded)) {
CAMHAL_LOGD("Component State Changed To OMX_StateLoaded\n");
if(getOmxState() == OmxDecoderState_Executing)
commitState(OmxDecoderState_Loaded);
mStateCondition.signal();
}
else if (data1 == OMX_CommandFlush) {
CAMHAL_LOGD("OMX_CommandFlush done on %d port\n", data2);
mStateCondition.signal();
}
else if (data1 == OMX_CommandPortDisable) {
CAMHAL_LOGD("OMX_CommandPortDisable done on %d port\n", data2);
mStateCondition.signal();
}
else if (data1 == OMX_CommandPortEnable) {
CAMHAL_LOGD("OMX_CommandPortEnable done on %d port\n", data2);
mStateCondition.signal();
} else {
CAMHAL_LOGD("Event %d done on %d port\n", data1, data2);
}
break;
}
case OMX_EventError:
{
CAMHAL_LOGD("\n\n\nOMX Component reported an Error!!!! 0x%x 0x%x\n\n\n", data1, data2);
commitState(OmxDecoderState_Error);
omxSendCommand(OMX_CommandStateSet, OMX_StateInvalid);
mStateCondition.signal();
break;
}
case OMX_EventPortSettingsChanged:
{
CAMHAL_LOGD("\n\n\nOMX_EventPortSettingsChanged(port=%ld, data2=0x%08lx)\n\n\n",
data1, data2);
if (data2 == 0) {
// This means that some serious change to port happens
commitState(OmxDecoderState_Reconfigure);
} else if (data2 == OMX_IndexConfigCommonOutputCrop) {
#if 0
OMX_CONFIG_RECTTYPE rect;
InitOMXParams(&rect);
rect.nPortIndex = PortIndexOutput;
status_t ret = omxGetConfig(OMX_IndexConfigCommonOutputCrop, &rect);
if (ret != NO_ERROR) {
CAMHAL_LOGE("Can't get new crop parameters 0x%x", ret);
break;
}
CAMHAL_LOGV("Crop should change to %d %d %d %d", rect.nLeft, rect.nTop, rect.nLeft + rect.nWidth, rect.nTop + rect.nHeight);
#endif
}
break;
}
default:
{
CAMHAL_LOGD("\n\n\nOMX Unhandelled event ID=0x%x!!!!\n\n\n", event);
}
}
LOG_FUNCTION_NAME_EXIT;
return ret;
}
void OmxFrameDecoder::doConfigure(__unused const DecoderParameters& config) {
LOG_FUNCTION_NAME;
LOG_FUNCTION_NAME_EXIT;
}
status_t OmxFrameDecoder::enableGrallockHandles() {
OMX_TI_PARAMUSENATIVEBUFFER domxUseGrallocHandles;
InitOMXParams(&domxUseGrallocHandles);
domxUseGrallocHandles.nPortIndex = PortIndexOutput;
domxUseGrallocHandles.bEnable = OMX_TRUE;
return omxSetParameter((OMX_INDEXTYPE)OMX_TI_IndexUseNativeBuffers, &domxUseGrallocHandles);
}
status_t OmxFrameDecoder::omxSwitchToExecutingSync() {
CAMHAL_LOGV("Try set OMX_StateExecuting");
android::AutoMutex lock(mHwLock);
omxSendCommand(OMX_CommandStateSet, OMX_StateExecuting);
status_t ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut);
if (ret != NO_ERROR) {
CAMHAL_LOGE("State transition to EXECUTING ERROR 0x%x", ret);
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
void OmxFrameDecoder::dumpPortSettings(PortType port) {
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = port;
omxGetParameter(OMX_IndexParamPortDefinition, &def);
omxDumpPortSettings(def);
}
status_t OmxFrameDecoder::disablePortSync(int port) {
OMX_ERRORTYPE eError;
android::AutoMutex lock(mHwLock);
eError = OMX_SendCommand(mHandleComp, OMX_CommandPortDisable, port, NULL);
if (eError != OMX_ErrorNone) {
CAMHAL_LOGE("OMX_CommandPortDisable OMX_ALL returned error 0x%x", eError);
return Utils::ErrorUtils::omxToAndroidError(eError);
}
status_t ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut);
if (ret != NO_ERROR) {
CAMHAL_LOGE("State transition to OMX_StateLoaded ERROR 0x%x", ret);
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
status_t OmxFrameDecoder::enablePortSync(int port) {
android::AutoMutex lock(mHwLock);
OMX_ERRORTYPE eError = OMX_SendCommand(mHandleComp, OMX_CommandPortEnable, port, NULL);
status_t ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut);
if (eError != OMX_ErrorNone) {
CAMHAL_LOGE("OMX_SendCommand OMX_CommandPortEnable OUT returned error 0x%x", eError);
return Utils::ErrorUtils::omxToAndroidError(eError);
}
return NO_ERROR;
}
status_t OmxFrameDecoder::doPortReconfigure() {
OMX_ERRORTYPE eError;
status_t ret = NO_ERROR;
CAMHAL_LOGD("Starting port reconfiguration !");
dumpPortSettings(PortIndexInput);
dumpPortSettings(PortIndexOutput);
android::AutoMutex lock(mHwLock);
omxSendCommand(OMX_CommandFlush, PortIndexOutput);
ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut);
if (ret != NO_ERROR) {
CAMHAL_LOGE("State transition to OMX_CommandFlush ERROR 0x%x", ret);
return UNKNOWN_ERROR;
}
omxSendCommand(OMX_CommandFlush, PortIndexInput);
ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut);
if (ret != NO_ERROR) {
CAMHAL_LOGE("State transition to OMX_CommandFlush ERROR 0x%x", ret);
return UNKNOWN_ERROR;
}
ret = omxSendCommand(OMX_CommandPortDisable, PortIndexOutput);
if (ret != NO_ERROR) {
CAMHAL_LOGE("OMX_CommandPortDisable PortIndexOutput returned error 0x%x", ret);
return ret;
}
freeBuffersOnOutput();
ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut);
if (ret != NO_ERROR) {
CAMHAL_LOGE("State transition to OMX_StateLoaded ERROR 0x%x", ret);
return UNKNOWN_ERROR;
}
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = PortIndexOutput;
omxGetParameter(OMX_IndexParamPortDefinition, &def);
def.nBufferCountActual = mParams.outputBufferCount;
CAMHAL_LOGD("Will set def.nBufferSize=%d stride=%d height=%d", def.nBufferSize , def.format.video.nStride, def.format.video.nFrameHeight);
omxSetParameter(OMX_IndexParamPortDefinition, &def);
ret = omxSendCommand(OMX_CommandPortEnable, PortIndexOutput);
if (ret != NO_ERROR) {
CAMHAL_LOGE("omxSendCommand OMX_CommandPortEnable returned error 0x%x", ret);
return ret;
}
allocateBuffersOutput();
ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut);
if (ret != NO_ERROR) {
CAMHAL_LOGE("omxSendCommand OMX_CommandPortEnable timeout 0x%x", ret);
return UNKNOWN_ERROR;
}
CAMHAL_LOGD("Port reconfiguration DONE!");
//dumpPortSettings(PortIndexOutput);
return NO_ERROR;
}
void OmxFrameDecoder::queueOutputBuffers() {
LOG_FUNCTION_NAME;
android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
for (size_t i = 0; i < mOutQueue.size(); i++) {
int index = mOutQueue[i];
android::sp<MediaBuffer> &outBuffer = mOutBuffers->editItemAt(index);
android::AutoMutex bufferLock(outBuffer->getLock());
if (outBuffer->getStatus() == BufferStatus_OutQueued) {
outBuffer->setStatus(BufferStatus_OutWaitForFill);
CameraBuffer* frame = static_cast<CameraBuffer*>(outBuffer->buffer);
OMX_BUFFERHEADERTYPE *pOutBufHdr = mOutBufferHeaders[outBuffer->bufferId];
CAMHAL_LOGV("Fill this buffer cf=%p bh=%p id=%d", frame, pOutBufHdr, outBuffer->bufferId);
status_t status = omxFillThisBuffer(pOutBufHdr);
CAMHAL_ASSERT(status == NO_ERROR);
}
}
LOG_FUNCTION_NAME_EXIT;
}
void OmxFrameDecoder::doProcessInputBuffer() {
LOG_FUNCTION_NAME;
if (getOmxState() == OmxDecoderState_Reconfigure) {
if (doPortReconfigure() == NO_ERROR) {
commitState(OmxDecoderState_Executing);
queueOutputBuffers();
} else {
commitState(OmxDecoderState_Error);
return;
}
}
if (getOmxState() == OmxDecoderState_Idle) {
CAMHAL_ASSERT(omxSwitchToExecutingSync() == NO_ERROR);
queueOutputBuffers();
}
if (getOmxState() == OmxDecoderState_Executing) {
for (size_t i = 0; i < mInQueue.size(); i++) {
int index = mInQueue[i];
CAMHAL_LOGD("Got in inqueue[%d] buffer id=%d", i, index);
android::sp<MediaBuffer> &inBuffer = mInBuffers->editItemAt(index);
android::AutoMutex bufferLock(inBuffer->getLock());
if (inBuffer->getStatus() == BufferStatus_InQueued) {
OMX_BUFFERHEADERTYPE *pInBufHdr = mInBufferHeaders[index];
inBuffer->setStatus(BufferStatus_InWaitForEmpty);
omxEmptyThisBuffer(inBuffer, pInBufHdr);
}
}
queueOutputBuffers();
}
LOG_FUNCTION_NAME_EXIT;
}
status_t OmxFrameDecoder::omxInit() {
LOG_FUNCTION_NAME;
OMX_ERRORTYPE eError = OMX_Init();
if (eError != OMX_ErrorNone) {
CAMHAL_LOGEB("OMX_Init() failed, error: 0x%x", eError);
}
else mOmxInialized = true;
LOG_FUNCTION_NAME_EXIT;
return Utils::ErrorUtils::omxToAndroidError(eError);
}
status_t OmxFrameDecoder::omxFillThisBuffer(OMX_BUFFERHEADERTYPE *pOutBufHdr) {
OMX_ERRORTYPE eError = OMX_ErrorUndefined;
pOutBufHdr->nFilledLen = 0;
pOutBufHdr->nOffset = 0;
pOutBufHdr->nFlags = 0;
eError = OMX_FillThisBuffer(mHandleComp, pOutBufHdr);
if (eError != OMX_ErrorNone) {
CAMHAL_LOGE("OMX_FillThisBuffer ERROR 0x%x", eError);
}
return Utils::ErrorUtils::omxToAndroidError(eError);
}
status_t OmxFrameDecoder::omxGetHandle(OMX_HANDLETYPE *handle, OMX_PTR pAppData,
OMX_CALLBACKTYPE & callbacks) {
LOG_FUNCTION_NAME;
OMX_ERRORTYPE eError = OMX_ErrorUndefined;
eError = OMX_GetHandle(handle, (OMX_STRING)"OMX.TI.DUCATI1.VIDEO.DECODER", pAppData, &callbacks);
if((eError != OMX_ErrorNone) || (handle == NULL)) {
handle = NULL;
return Utils::ErrorUtils::omxToAndroidError(eError);
}
commitState(OmxDecoderState_Loaded);
LOG_FUNCTION_NAME_EXIT;
return Utils::ErrorUtils::omxToAndroidError(eError);
}
status_t OmxFrameDecoder::omxEmptyThisBuffer(android::sp<MediaBuffer>& inBuffer, OMX_BUFFERHEADERTYPE *pInBufHdr) {
LOG_FUNCTION_NAME;
OMX_PARAM_PORTDEFINITIONTYPE def;
OMX_ERRORTYPE eError = OMX_ErrorNone;
InitOMXParams(&def);
def.nPortIndex = PortIndexInput;
omxGetParameter(OMX_IndexParamPortDefinition, &def);
CAMHAL_LOGD("Founded id for empty is %d ", inBuffer->bufferId);
if (inBuffer->filledLen > (int)def.nBufferSize) {
CAMHAL_LOGE("Can't copy IN buffer due to it too small %d than needed %d", def.nBufferSize, inBuffer->filledLen);
return UNKNOWN_ERROR;
}
int filledLen = inBuffer->filledLen;
unsigned char* dataBuffer = reinterpret_cast<unsigned char*>(inBuffer->buffer);
//If decoder type MJPEG we check if append DHT forced and if true append it
//in other case we check mIsNeedCheckDHT and if true search for DHT in buffer
//if we don't found it - will do append
//once we find that buffer not contain DHT we will append it each time
if ((mDecoderType == DecoderType_MJPEG) && ((mAlwaysAppendDHT) || ((mIsNeedCheckDHT) &&
(mIsNeedCheckDHT = !Decoder_libjpeg::isDhtExist(dataBuffer, filledLen))))) {
CAMHAL_LOGV("Will append DHT to buffer");
Decoder_libjpeg::appendDHT(dataBuffer, filledLen, pInBufHdr->pBuffer, filledLen + Decoder_libjpeg::readDHTSize());
filledLen += Decoder_libjpeg::readDHTSize();
mIsNeedCheckDHT = false;
mAlwaysAppendDHT = true;
} else {
memcpy(pInBufHdr->pBuffer, dataBuffer, filledLen);
}
CAMHAL_LOGV("Copied %d bytes into In buffer with bh=%p", filledLen, pInBufHdr);
CAMHAL_LOGV("Empty this buffer id=%d timestamp %lld offset=%d", inBuffer->bufferId, pInBufHdr->nTimeStamp, pInBufHdr->nOffset);
pInBufHdr->nFilledLen = filledLen;
pInBufHdr->nTimeStamp = inBuffer->getTimestamp();
pInBufHdr->nFlags = 16;
pInBufHdr->nOffset = 0;
eError = OMX_EmptyThisBuffer(mHandleComp, pInBufHdr);
if (eError != OMX_ErrorNone) {
CAMHAL_LOGE("OMX_EmptyThisBuffer ERROR 0x%x", eError);
Utils::ErrorUtils::omxToAndroidError(eError);
}
LOG_FUNCTION_NAME_EXIT;
return NO_ERROR;
}
status_t OmxFrameDecoder::allocateBuffersOutput() {
LOG_FUNCTION_NAME;
OMX_ERRORTYPE eError = OMX_ErrorNone;
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = PortIndexOutput;
omxGetParameter(OMX_IndexParamPortDefinition, &def);
def.nBufferCountActual = mParams.outputBufferCount;
CAMHAL_LOGD("Will set def.nBufferSize=%d stride=%d height=%d", def.nBufferSize , def.format.video.nStride, def.format.video.nFrameHeight);
OMX_BUFFERHEADERTYPE *pOutBufHdr;
mOutBufferHeaders.clear();
for (size_t i = 0; i < mOutBuffers->size(); i++) {
android::sp<MediaBuffer>& outBuffer = mOutBuffers->editItemAt(i);
android::AutoMutex lock(outBuffer->getLock());
CameraBuffer* cb = static_cast<CameraBuffer*>(outBuffer->buffer);
OMX_U8 * outPtr = static_cast<OMX_U8*>(camera_buffer_get_omx_ptr(cb));
CAMHAL_LOGV("Try to set OMX_UseBuffer [0x%x] for output port with length %d ", outPtr, def.nBufferSize);
eError = OMX_UseBuffer(mHandleComp, &pOutBufHdr, PortIndexOutput, (void*)i, def.nBufferSize, outPtr);
if (eError != OMX_ErrorNone) {
ALOGE("OMX_UseBuffer failed with error %d (0x%08x)", eError, eError);
commitState(OmxDecoderState_Error);
return UNKNOWN_ERROR;
}
CAMHAL_LOGD("Got buffer header %p", pOutBufHdr);
mOutBufferHeaders.add(pOutBufHdr);
}
omxDumpPortSettings(def);
LOG_FUNCTION_NAME_EXIT;
return NO_ERROR;
}
status_t OmxFrameDecoder::allocateBuffersInput() {
LOG_FUNCTION_NAME;
OMX_PARAM_PORTDEFINITIONTYPE def;
OMX_BUFFERHEADERTYPE *pInBufHdr;
OMX_ERRORTYPE eError = OMX_ErrorNone;
InitOMXParams(&def);
def.nPortIndex = PortIndexInput;
omxGetParameter(OMX_IndexParamPortDefinition, &def);
// TODO: Will be changed since port reconfiguration will be handled
def.nBufferCountActual = mInBuffers->size();
def.bEnabled = OMX_TRUE;
omxSetParameter(OMX_IndexParamPortDefinition, &def);
mInBufferHeaders.clear();
for (size_t i = 0; i < mInBuffers->size(); i++) {
CAMHAL_LOGD("Will do OMX_AllocateBuffer for input port with size %d id=%d", def.nBufferSize, i);
eError = OMX_AllocateBuffer(mHandleComp, &pInBufHdr, PortIndexInput, (void*)i, def.nBufferSize);
if (eError != OMX_ErrorNone) {
ALOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", eError, eError);
commitState(OmxDecoderState_Error);
return UNKNOWN_ERROR;
}
CAMHAL_LOGD("Got new buffer header [%p] for IN port", pInBufHdr);
mInBufferHeaders.push_back(pInBufHdr);
}
LOG_FUNCTION_NAME_EXIT;
return NO_ERROR;
}
status_t OmxFrameDecoder::getAndConfigureDecoder() {
status_t ret = NO_ERROR;
OMX_ERRORTYPE eError;
ret = omxInit();
if (ret != NO_ERROR) {
CAMHAL_LOGE("OMX_Init returned error 0x%x", ret);
return ret;
}
OMX_CALLBACKTYPE callbacks;
callbacks.EventHandler = OmxFrameDecoder::eventCallback;
callbacks.EmptyBufferDone = OmxFrameDecoder::emptyBufferDoneCallback;
callbacks.FillBufferDone = OmxFrameDecoder::fillBufferDoneCallback;
ret = omxGetHandle(&mHandleComp, this, callbacks);
if (ret != NO_ERROR) {
CAMHAL_LOGE("OMX_GetHandle returned error 0x%x", ret);
OMX_Deinit();
mOmxInialized = false;
return ret;
}
ret = setComponentRole();
if (ret != NO_ERROR) {
CAMHAL_LOGE("setComponentRole returned error 0x%x", ret);
OMX_Deinit();
mOmxInialized = false;
return ret;
}
disablePortSync(PortIndexOutput);
ret = setVideoOutputFormat(mParams.width, mParams.height);
enablePortSync(PortIndexOutput);
if (ret != NO_ERROR) {
CAMHAL_LOGE("Can't set output format error 0x%x", ret);
OMX_Deinit();
mOmxInialized = false;
return ret;
}
enableGrallockHandles();
return NO_ERROR;
}
status_t OmxFrameDecoder::switchToIdle() {
CAMHAL_ASSERT(getOmxState() == OmxDecoderState_Loaded);
CAMHAL_LOGD("Try set OMX_StateIdle");
android::AutoMutex lock(mHwLock);
status_t ret = omxSendCommand(OMX_CommandStateSet, OMX_StateIdle);
if (ret != NO_ERROR) {
CAMHAL_LOGE("Can't omxSendCommandt error 0x%x", ret);
OMX_Deinit();
mOmxInialized = false;
return ret;
}
allocateBuffersInput();
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = PortIndexOutput;
omxGetParameter(OMX_IndexParamPortDefinition, &def);
def.nBufferCountActual = mParams.outputBufferCount;
omxSetParameter(OMX_IndexParamPortDefinition, &def);
allocateBuffersOutput();
ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut);
if (ret != NO_ERROR) {
CAMHAL_LOGE("State transition to IDLE ERROR 0x%x", ret);
return ret;
}
commitState(OmxDecoderState_Idle);
return NO_ERROR;
}
status_t OmxFrameDecoder::doStart() {
LOG_FUNCTION_NAME;
status_t ret = NO_ERROR;
mStopping = false;
OMX_ERRORTYPE eError;
ret = getAndConfigureDecoder();
#if 0
OMX_TI_PARAM_ENHANCEDPORTRECONFIG tParamStruct;
tParamStruct.nSize = sizeof(OMX_TI_PARAM_ENHANCEDPORTRECONFIG);
tParamStruct.nVersion.s.nVersionMajor = 0x1;
tParamStruct.nVersion.s.nVersionMinor = 0x1;
tParamStruct.nVersion.s.nRevision = 0x0;
tParamStruct.nVersion.s.nStep = 0x0;
tParamStruct.nPortIndex = PortIndexOutput;
tParamStruct.bUsePortReconfigForCrop = OMX_TRUE;
tParamStruct.bUsePortReconfigForPadding = OMX_FALSE;
omxSetParameter((OMX_INDEXTYPE)OMX_TI_IndexParamUseEnhancedPortReconfig, &tParamStruct);
#endif
// Transition to IDLE
ret = switchToIdle();
dumpPortSettings(PortIndexInput);
dumpPortSettings(PortIndexOutput);
LOG_FUNCTION_NAME_EXIT;
return ret;
}
status_t OmxFrameDecoder::omxGetParameter(OMX_INDEXTYPE index, OMX_PTR ptr) {
OMX_ERRORTYPE eError = OMX_GetParameter(mHandleComp, index, ptr);
if(eError != OMX_ErrorNone) {
CAMHAL_LOGE("OMX_GetParameter - error 0x%x", eError);
}
return Utils::ErrorUtils::omxToAndroidError(eError);
}
status_t OmxFrameDecoder::omxGetConfig(OMX_INDEXTYPE index, OMX_PTR ptr) {
OMX_ERRORTYPE eError = OMX_GetConfig(mHandleComp, index, ptr);
if(eError != OMX_ErrorNone) {
CAMHAL_LOGE("OMX_GetConfig - error 0x%x", eError);
}
return Utils::ErrorUtils::omxToAndroidError(eError);
}
status_t OmxFrameDecoder::omxSetParameter(OMX_INDEXTYPE index, OMX_PTR ptr) {
OMX_ERRORTYPE eError = OMX_SetParameter(mHandleComp, index, ptr);
if(eError != OMX_ErrorNone) {
CAMHAL_LOGE("OMX_SetParameter - error 0x%x", eError);
}
return Utils::ErrorUtils::omxToAndroidError(eError);
}
status_t OmxFrameDecoder::omxSetConfig(OMX_INDEXTYPE index, OMX_PTR ptr) {
OMX_ERRORTYPE eError = OMX_SetConfig(mHandleComp, index, ptr);
if(eError != OMX_ErrorNone) {
CAMHAL_LOGE("OMX_SetConfig - error 0x%x", eError);
}
return Utils::ErrorUtils::omxToAndroidError(eError);
}
status_t OmxFrameDecoder::omxSendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {
OMX_ERRORTYPE eError = OMX_SendCommand(mHandleComp, cmd, param, NULL);
if(eError != OMX_ErrorNone) {
CAMHAL_LOGE("OMX_SendCommand - error 0x%x", eError);
}
return Utils::ErrorUtils::omxToAndroidError(eError);
}
status_t OmxFrameDecoder::setVideoOutputFormat(OMX_U32 width, OMX_U32 height) {
LOG_FUNCTION_NAME;
CAMHAL_LOGV("setVideoOutputFormat width=%ld, height=%ld", width, height);
OMX_VIDEO_CODINGTYPE compressionFormat = gCompressionFormat[mDecoderType];
status_t err = setVideoPortFormatType(
PortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
if (err != NO_ERROR) {
CAMHAL_LOGE("Error during setVideoPortFormatType 0x%x", err);
return err;
}
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = PortIndexInput;
OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
err = omxGetParameter(OMX_IndexParamPortDefinition, &def);
if (err != NO_ERROR) {
return err;
}
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
video_def->eCompressionFormat = compressionFormat;
video_def->eColorFormat = OMX_COLOR_FormatUnused;
err = omxSetParameter(OMX_IndexParamPortDefinition, &def);
if (err != OK) {
return err;
}
OMX_PARAM_PORTDEFINITIONTYPE odef;
OMX_VIDEO_PORTDEFINITIONTYPE *out_video_def = &odef.format.video;
InitOMXParams(&odef);
odef.nPortIndex = PortIndexOutput;
err = omxGetParameter(OMX_IndexParamPortDefinition, &odef);
if (err != NO_ERROR) {
return err;
}
out_video_def->nFrameWidth = width;
out_video_def->nFrameHeight = height;
out_video_def->xFramerate = 30<< 16;//((width >= 720) ? 60 : 30) << 16;
out_video_def->nStride = 4096;
err = omxSetParameter(OMX_IndexParamPortDefinition, &odef);
CAMHAL_LOGD("OUT port is configured");
dumpPortSettings(PortIndexOutput);
LOG_FUNCTION_NAME_EXIT;
return err;
}
status_t OmxFrameDecoder::setVideoPortFormatType(
OMX_U32 portIndex,
OMX_VIDEO_CODINGTYPE compressionFormat,
OMX_COLOR_FORMATTYPE colorFormat) {
LOG_FUNCTION_NAME;
OMX_VIDEO_PARAM_PORTFORMATTYPE format;
InitOMXParams(&format);
format.nPortIndex = portIndex;
format.nIndex = 0;
bool found = false;
OMX_U32 index = 0;
for (;;) {
CAMHAL_LOGV("Will check index = %d", index);
format.nIndex = index;
OMX_ERRORTYPE eError = OMX_GetParameter(
mHandleComp, OMX_IndexParamVideoPortFormat,
&format);
CAMHAL_LOGV("format.eCompressionFormat=0x%x format.eColorFormat=0x%x", format.eCompressionFormat, format.eColorFormat);
if (format.eCompressionFormat == compressionFormat
&& format.eColorFormat == colorFormat) {
found = true;
break;
}
++index;
if (index >= kMaxColorFormatSupported) {
CAMHAL_LOGE("color format %d or compression format %d is not supported",
colorFormat, compressionFormat);
return UNKNOWN_ERROR;
}
}
if (!found) {
return UNKNOWN_ERROR;
}
CAMHAL_LOGV("found a match.");
OMX_ERRORTYPE eError = OMX_SetParameter(
mHandleComp, OMX_IndexParamVideoPortFormat,
&format);
LOG_FUNCTION_NAME_EXIT;
return Utils::ErrorUtils::omxToAndroidError(eError);
}
status_t OmxFrameDecoder::setComponentRole() {
OMX_PARAM_COMPONENTROLETYPE roleParams;
const char *role = gDecoderRole[mDecoderType];
InitOMXParams(&roleParams);
strncpy((char *)roleParams.cRole,
role, OMX_MAX_STRINGNAME_SIZE - 1);
roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
return omxSetParameter(OMX_IndexParamStandardComponentRole, &roleParams);
}
void OmxFrameDecoder::freeBuffersOnOutput() {
LOG_FUNCTION_NAME;
for (size_t i = 0; i < mOutBufferHeaders.size(); i++) {
OMX_BUFFERHEADERTYPE* header = mOutBufferHeaders[i];
CAMHAL_LOGD("Freeing OUT buffer header %p", header);
OMX_FreeBuffer(mHandleComp, PortIndexOutput, header);
}
mOutBufferHeaders.clear();
LOG_FUNCTION_NAME_EXIT;
}
void OmxFrameDecoder::freeBuffersOnInput() {
LOG_FUNCTION_NAME;
for (size_t i = 0; i < mInBufferHeaders.size(); i++) {
OMX_BUFFERHEADERTYPE* header = mInBufferHeaders[i];
CAMHAL_LOGD("Freeing IN buffer header %p", header);
OMX_FreeBuffer(mHandleComp, PortIndexInput, header);
}
mInBufferHeaders.clear();
LOG_FUNCTION_NAME_EXIT;
}
void OmxFrameDecoder::doStop() {
LOG_FUNCTION_NAME;
mStopping = true;
android::AutoMutex lock(mHwLock);
CAMHAL_LOGD("HwFrameDecoder::doStop state id=%d", getOmxState());
if ((getOmxState() == OmxDecoderState_Executing) || (getOmxState() == OmxDecoderState_Reconfigure)) {
CAMHAL_LOGD("Try set OMX_StateIdle");
status_t ret = omxSendCommand(OMX_CommandStateSet, OMX_StateIdle);
if (ret != NO_ERROR) {
CAMHAL_LOGE("Can't omxSendCommandt error 0x%x", ret);
}
ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut);
if (ret != NO_ERROR) {
CAMHAL_LOGE("State transition to IDLE ERROR 0x%x", ret);
}
commitState(OmxDecoderState_Idle);
}
if (getOmxState() == OmxDecoderState_Idle) {
CAMHAL_LOGD("Try set OMX_StateLoaded");
status_t ret = omxSendCommand(OMX_CommandStateSet, OMX_StateLoaded);
if (ret != NO_ERROR) {
CAMHAL_LOGE("Can't omxSendCommandt error 0x%x", ret);
return;
}
freeBuffersOnOutput();
freeBuffersOnInput();
ret = mStateCondition.waitRelative(mHwLock, kMaxStateSwitchTimeOut);
if (ret != NO_ERROR) {
CAMHAL_LOGE("State transition to OMX_StateLoaded ERROR 0x%x", ret);
}
commitState(OmxDecoderState_Loaded);
}
if (getOmxState() == OmxDecoderState_Error) {
CAMHAL_LOGD("In state ERROR will try to free buffers!");
freeBuffersOnOutput();
freeBuffersOnInput();
}
CAMHAL_LOGD("Before OMX_FreeHandle ....");
OMX_FreeHandle(mHandleComp);
CAMHAL_LOGD("After OMX_FreeHandle ....");
LOG_FUNCTION_NAME_EXIT;
}
void OmxFrameDecoder::doFlush() {
LOG_FUNCTION_NAME;
mIsNeedCheckDHT = true;
LOG_FUNCTION_NAME_EXIT;
}
void OmxFrameDecoder::doRelease() {
LOG_FUNCTION_NAME;
LOG_FUNCTION_NAME_EXIT;
}
void OmxFrameDecoder::omxDumpPortSettings(OMX_PARAM_PORTDEFINITIONTYPE& def) {
CAMHAL_LOGD("----------Port settings start--------------------");
CAMHAL_LOGD("nSize=%d nPortIndex=%d eDir=%d nBufferCountActual=%d", def.nSize, def.nPortIndex, def.eDir, def.nBufferCountActual);
CAMHAL_LOGD("nBufferCountMin=%d nBufferSize=%d bEnabled=%d bPopulated=%d bBuffersContiguous=%d nBufferAlignment=%d", def.nBufferCountMin, def.nBufferSize, def.bEnabled, def.bPopulated, def.bBuffersContiguous, def.nBufferAlignment);
CAMHAL_LOGD("eDomain = %d",def.eDomain);
if (def.eDomain == OMX_PortDomainVideo) {
CAMHAL_LOGD("===============Video Port===================");
CAMHAL_LOGD("cMIMEType=%s",def.format.video.cMIMEType);
CAMHAL_LOGD("nFrameWidth=%d nFrameHeight=%d", def.format.video.nFrameWidth, def.format.video.nFrameHeight);
CAMHAL_LOGD("nStride=%d nSliceHeight=%d", def.format.video.nStride, def.format.video.nSliceHeight);
CAMHAL_LOGD("nBitrate=%d xFramerate=%d", def.format.video.nBitrate, def.format.video.xFramerate>>16);
CAMHAL_LOGD("bFlagErrorConcealment=%d eCompressionFormat=%d", def.format.video.bFlagErrorConcealment, def.format.video.eCompressionFormat);
CAMHAL_LOGD("eColorFormat=0x%x pNativeWindow=%p", def.format.video.eColorFormat, def.format.video.pNativeWindow);
CAMHAL_LOGD("===============END Video Part===================");
}
else if (def.eDomain == OMX_PortDomainImage) {
CAMHAL_LOGD("===============Image Port===================");
CAMHAL_LOGD("cMIMEType=%s",def.format.image.cMIMEType);
CAMHAL_LOGD("nFrameWidth=%d nFrameHeight=%d", def.format.image.nFrameWidth, def.format.image.nFrameHeight);
CAMHAL_LOGD("nStride=%d nSliceHeight=%d", def.format.image.nStride, def.format.image.nSliceHeight);
CAMHAL_LOGD("bFlagErrorConcealment=%d eCompressionFormat=%d", def.format.image.bFlagErrorConcealment, def.format.image.eCompressionFormat);
CAMHAL_LOGD("eColorFormat=0x%x pNativeWindow=%p", def.format.image.eColorFormat, def.format.image.pNativeWindow);
CAMHAL_LOGD("===============END Image Part===================");
}
CAMHAL_LOGD("----------Port settings end--------------------");
}
void OmxFrameDecoder::omxDumpBufferHeader(__unused OMX_BUFFERHEADERTYPE* bh) {
CAMHAL_LOGD("==============OMX_BUFFERHEADERTYPE start==============");
CAMHAL_LOGD("nAllocLen=%d nFilledLen=%d nOffset=%d nFlags=0x%x", bh->nAllocLen, bh->nFilledLen, bh->nOffset, bh->nFlags);
CAMHAL_LOGD("pBuffer=%p nOutputPortIndex=%d nInputPortIndex=%d nSize=0x%x", bh->pBuffer, bh->nOutputPortIndex, bh->nInputPortIndex, bh->nSize);
CAMHAL_LOGD("nVersion=0x%x", bh->nVersion);
CAMHAL_LOGD("==============OMX_BUFFERHEADERTYPE end==============");
}
bool OmxFrameDecoder::getPaddedDimensions(size_t &width, size_t &height) {
switch (height) {
case 480: {
height = 576;
if (width == 640) {
width = 768;
}
break;
}
case 720: {
height = 832;
if (width == 1280) {
width = 1408;
}
break;
}
case 1080: {
height = 1184;
if (width == 1920) {
width = 2048;
}
break;
}
}
CAMHAL_LOGD("WxH updated to padded values : %d x %d", width, height);
return true;
}
} // namespace Camera
} // namespace Ti