blob: 0c613ad46d25c97547472cc67276c2c09418f04e [file] [log] [blame]
/**
* Copyright (C) 2019 The Android Open Source Project
*
* 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 "omxUtils.h"
sp<IMediaPlayerService> mediaPlayerService = NULL;
sp<IOMXNode> mOMXNode = 0;
sp<IOMX> mOMX;
omx_message msg;
Mutex mLock;
Condition mMessageAddedCondition;
int32_t mLastMsgGeneration;
int32_t mCurGeneration;
List<omx_message> mMessageQueue;
bool mUseTreble;
int numCallbackEmptyBufferDone;
struct CodecObserver : public BnOMXObserver {
public:
CodecObserver(int32_t gen)
: mGeneration(gen) {
}
void onMessages(const std::list<omx_message> &messages) override;
int32_t mGeneration;
protected:
virtual ~CodecObserver() {
}
};
struct DeathNotifier : public IBinder::DeathRecipient,
public ::android::hardware::hidl_death_recipient {
explicit DeathNotifier() {
}
virtual void binderDied(const wp<IBinder> &) {
ALOGE("Binder Died");
exit (EXIT_FAILURE);
}
virtual void serviceDied(
uint64_t /* cookie */,
const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
ALOGE("Service Died");
exit (EXIT_FAILURE);
}
};
sp<DeathNotifier> mDeathNotifier;
void handleMessages(int32_t gen, const std::list<omx_message> &messages) {
Mutex::Autolock autoLock(mLock);
for (std::list<omx_message>::const_iterator it = messages.cbegin();
it != messages.cend();) {
mMessageQueue.push_back(*it);
const omx_message &msg = *it++;
if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
numCallbackEmptyBufferDone++;
}
mLastMsgGeneration = gen;
}
mMessageAddedCondition.signal();
}
void CodecObserver::onMessages(const std::list<omx_message> &messages) {
handleMessages(mGeneration, messages);
}
status_t dequeueMessageForNode(omx_message *msg, int64_t timeoutUs) {
int64_t finishBy = ALooper::GetNowUs() + timeoutUs;
status_t err = OK;
while (err != TIMED_OUT) {
Mutex::Autolock autoLock(mLock);
if (mLastMsgGeneration < mCurGeneration) {
mMessageQueue.clear();
}
// Messages are queued in batches, if the last batch queued is
// from a node that already expired, discard those messages.
List<omx_message>::iterator it = mMessageQueue.begin();
while (it != mMessageQueue.end()) {
*msg = *it;
mMessageQueue.erase(it);
return OK;
}
if (timeoutUs < 0) {
err = mMessageAddedCondition.wait(mLock);
} else {
err = mMessageAddedCondition.waitRelative(
mLock, (finishBy - ALooper::GetNowUs()) * 1000);
}
}
return err;
}
void omxUtilsCheckCmdExecution(char *name) {
status_t err = dequeueMessageForNode(&msg, DEFAULT_TIMEOUT);
if (err == TIMED_OUT) {
ALOGE("[omxUtils] OMX command timed out for %s, exiting the app", name);
exit (EXIT_FAILURE);
}
}
void omxExitOnError(status_t ret) {
if (ret != OK) {
exit (EXIT_FAILURE);
}
}
status_t omxUtilsInit(char *codecName) {
android::ProcessState::self()->startThreadPool();
if (property_get_bool("persist.media.treble_omx", true)) {
using namespace ::android::hardware::media::omx::V1_0;
sp<IOmx> tOmx = IOmx::getService();
if (tOmx == nullptr) {
return NO_INIT;
}
mOMX = new utils::LWOmx(tOmx);
mUseTreble = true;
} else {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
sp<IMediaPlayerService> mediaPlayerService = interface_cast
<IMediaPlayerService> (binder);
if (mediaPlayerService == NULL) {
return NO_INIT;
}
mOMX = mediaPlayerService->getOMX();
if (mOMX == NULL) {
return NO_INIT;
}
mUseTreble = false;
}
sp<CodecObserver> observer = new CodecObserver(++mCurGeneration);
status_t ret = mOMX->allocateNode(codecName, observer, &mOMXNode);
if (ret == OK) {
mDeathNotifier = new DeathNotifier();
if (mUseTreble) {
auto tOmxNode = mOMXNode->getHalInterface();
if (tOmxNode != NULL) {
tOmxNode->linkToDeath(mDeathNotifier, 0);
} else {
ALOGE("No HAL Interface");
exit (EXIT_FAILURE);
}
} else {
IInterface::asBinder(mOMXNode)->linkToDeath(mDeathNotifier);
}
}
numCallbackEmptyBufferDone = 0;
return ret;
}
status_t omxUtilsGetParameter(int portIndex,
OMX_PARAM_PORTDEFINITIONTYPE *params) {
InitOMXParams(params);
params->nPortIndex = portIndex;
return mOMXNode->getParameter(OMX_IndexParamPortDefinition, params,
sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
}
status_t omxUtilsSetParameter(int portIndex,
OMX_PARAM_PORTDEFINITIONTYPE *params) {
InitOMXParams(params);
params->nPortIndex = portIndex;
return mOMXNode->setParameter(OMX_IndexParamPortDefinition, params,
sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
}
status_t omxUtilsSetPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
return mOMXNode->setPortMode(portIndex, mode);
}
status_t omxUtilsUseBuffer(OMX_U32 portIndex, const OMXBuffer &omxBuf,
android::BnOMX::buffer_id *buffer) {
return mOMXNode->useBuffer(portIndex, omxBuf, buffer);
}
status_t omxUtilsSendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {
int ret = mOMXNode->sendCommand(cmd, param);
omxUtilsCheckCmdExecution((char *) __FUNCTION__);
return ret;
}
status_t omxUtilsEmptyBuffer(android::BnOMX::buffer_id buffer,
const OMXBuffer &omxBuf, OMX_U32 flags,
OMX_TICKS timestamp, int fenceFd) {
return mOMXNode->emptyBuffer(buffer, omxBuf, flags, timestamp, fenceFd);
}
status_t omxUtilsFillBuffer(android::BnOMX::buffer_id buffer,
const OMXBuffer &omxBuf, int fenceFd) {
return mOMXNode->fillBuffer(buffer, omxBuf, fenceFd);
}
status_t omxUtilsFreeBuffer(OMX_U32 portIndex,
android::BnOMX::buffer_id buffer) {
return mOMXNode->freeBuffer(portIndex, buffer);
}
status_t omxUtilsFreeNode() {
return mOMXNode->freeNode();
}