1 /**
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "omxUtils.h"
17
18 sp<IMediaPlayerService> mediaPlayerService = NULL;
19 sp<IOMXNode> mOMXNode = 0;
20 sp<IOMX> mOMX;
21 omx_message msg;
22 Mutex mLock;
23 Condition mMessageAddedCondition;
24 int32_t mLastMsgGeneration;
25 int32_t mCurGeneration;
26 List<omx_message> mMessageQueue;
27 int numCallbackEmptyBufferDone;
28
29 struct CodecObserver : public BnOMXObserver {
30 public:
CodecObserverCodecObserver31 CodecObserver(int32_t gen)
32 : mGeneration(gen) {
33 }
34
35 void onMessages(const std::list<omx_message> &messages) override;
36 int32_t mGeneration;
37
38 protected:
~CodecObserverCodecObserver39 virtual ~CodecObserver() {
40 }
41 };
handleMessages(int32_t gen,const std::list<omx_message> & messages)42 void handleMessages(int32_t gen, const std::list<omx_message> &messages) {
43 Mutex::Autolock autoLock(mLock);
44 for (std::list<omx_message>::const_iterator it = messages.cbegin();
45 it != messages.cend();) {
46 mMessageQueue.push_back(*it);
47 const omx_message &msg = *it++;
48 if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
49 numCallbackEmptyBufferDone++;
50 }
51 mLastMsgGeneration = gen;
52 }
53 mMessageAddedCondition.signal();
54 }
onMessages(const std::list<omx_message> & messages)55 void CodecObserver::onMessages(const std::list<omx_message> &messages) {
56 handleMessages(mGeneration, messages);
57 }
58
59 struct DeathNotifier : public IBinder::DeathRecipient,
60 public ::android::hardware::hidl_death_recipient {
DeathNotifierDeathNotifier61 explicit DeathNotifier() {
62 }
binderDiedDeathNotifier63 virtual void binderDied(const wp<IBinder> &) {
64 ALOGE("Binder Died");
65 exit (EXIT_FAILURE);
66 }
serviceDiedDeathNotifier67 virtual void serviceDied(
68 uint64_t /* cookie */,
69 const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
70 ALOGE("Service Died");
71 exit (EXIT_FAILURE);
72 }
73 };
74 sp<DeathNotifier> mDeathNotifier;
dequeueMessageForNode(omx_message * msg,int64_t timeoutUs)75 status_t dequeueMessageForNode(omx_message *msg, int64_t timeoutUs) {
76 int64_t finishBy = ALooper::GetNowUs() + timeoutUs;
77 status_t err = OK;
78
79 while (err != TIMED_OUT) {
80 Mutex::Autolock autoLock(mLock);
81 if (mLastMsgGeneration < mCurGeneration) {
82 mMessageQueue.clear();
83 }
84 // Messages are queued in batches, if the last batch queued is
85 // from a node that already expired, discard those messages.
86 List<omx_message>::iterator it = mMessageQueue.begin();
87 while (it != mMessageQueue.end()) {
88 *msg = *it;
89 mMessageQueue.erase(it);
90 return OK;
91 }
92 if (timeoutUs < 0) {
93 err = mMessageAddedCondition.wait(mLock);
94 } else {
95 err = mMessageAddedCondition.waitRelative(
96 mLock, (finishBy - ALooper::GetNowUs()) * 1000);
97 }
98 }
99 return err;
100 }
omxUtilsCheckCmdExecution(char * name)101 void omxUtilsCheckCmdExecution(char *name) {
102 status_t err = dequeueMessageForNode(&msg, DEFAULT_TIMEOUT);
103 if (err == TIMED_OUT) {
104 ALOGE("[omxUtils] OMX command timed out for %s, exiting the app", name);
105 exit (EXIT_FAILURE);
106 }
107 }
omxExitOnError(status_t ret)108 void omxExitOnError(status_t ret) {
109 if (ret != OK) {
110 exit (EXIT_FAILURE);
111 }
112 }
omxUtilsInit(char * codecName)113 status_t omxUtilsInit(char *codecName) {
114 android::ProcessState::self()->startThreadPool();
115 OMXClient client;
116 if (client.connect() != OK) {
117 ALOGE("Failed to connect to OMX to create persistent input surface.");
118 return NO_INIT;
119 }
120 mOMX = client.interface();
121 sp<CodecObserver> observer = new CodecObserver(++mCurGeneration);
122 status_t ret = mOMX->allocateNode(codecName, observer, &mOMXNode);
123 if (ret == OK) {
124 mDeathNotifier = new DeathNotifier();
125 auto tOmxNode = mOMXNode->getHalInterface<IOmxNode>();
126 if (tOmxNode != NULL) {
127 tOmxNode->linkToDeath(mDeathNotifier, 0);
128 } else {
129 ALOGE("No HAL Interface");
130 exit (EXIT_FAILURE);
131 }
132 }
133 numCallbackEmptyBufferDone = 0;
134 return ret;
135 }
omxUtilsGetParameter(int portIndex,OMX_PARAM_PORTDEFINITIONTYPE * params)136 status_t omxUtilsGetParameter(int portIndex,
137 OMX_PARAM_PORTDEFINITIONTYPE *params) {
138 InitOMXParams(params);
139 params->nPortIndex = portIndex;
140 return mOMXNode->getParameter(OMX_IndexParamPortDefinition, params,
141 sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
142 }
omxUtilsSetParameter(int portIndex,OMX_PARAM_PORTDEFINITIONTYPE * params)143 status_t omxUtilsSetParameter(int portIndex,
144 OMX_PARAM_PORTDEFINITIONTYPE *params) {
145 InitOMXParams(params);
146 params->nPortIndex = portIndex;
147 return mOMXNode->setParameter(OMX_IndexParamPortDefinition, params,
148 sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
149 }
omxUtilsSetPortMode(OMX_U32 portIndex,IOMX::PortMode mode)150 status_t omxUtilsSetPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
151 return mOMXNode->setPortMode(portIndex, mode);
152 }
omxUtilsUseBuffer(OMX_U32 portIndex,const OMXBuffer & omxBuf,android::IOMX::buffer_id * buffer)153 status_t omxUtilsUseBuffer(OMX_U32 portIndex, const OMXBuffer &omxBuf,
154 android::IOMX::buffer_id *buffer) {
155 return mOMXNode->useBuffer(portIndex, omxBuf, buffer);
156 }
omxUtilsSendCommand(OMX_COMMANDTYPE cmd,OMX_S32 param)157 status_t omxUtilsSendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {
158 int ret = mOMXNode->sendCommand(cmd, param);
159 omxUtilsCheckCmdExecution((char *) __FUNCTION__);
160 return ret;
161 }
omxUtilsEmptyBuffer(android::IOMX::buffer_id buffer,const OMXBuffer & omxBuf,OMX_U32 flags,OMX_TICKS timestamp,int fenceFd)162 status_t omxUtilsEmptyBuffer(android::IOMX::buffer_id buffer,
163 const OMXBuffer &omxBuf, OMX_U32 flags,
164 OMX_TICKS timestamp, int fenceFd) {
165 return mOMXNode->emptyBuffer(buffer, omxBuf, flags, timestamp, fenceFd);
166 }
omxUtilsFillBuffer(android::IOMX::buffer_id buffer,const OMXBuffer & omxBuf,int fenceFd)167 status_t omxUtilsFillBuffer(android::IOMX::buffer_id buffer,
168 const OMXBuffer &omxBuf, int fenceFd) {
169 return mOMXNode->fillBuffer(buffer, omxBuf, fenceFd);
170 }
omxUtilsFreeBuffer(OMX_U32 portIndex,android::IOMX::buffer_id buffer)171 status_t omxUtilsFreeBuffer(OMX_U32 portIndex,
172 android::IOMX::buffer_id buffer) {
173 return mOMXNode->freeBuffer(portIndex, buffer);
174 }
omxUtilsFreeNode()175 status_t omxUtilsFreeNode() {
176 return mOMXNode->freeNode();
177 }
178