blob: 821891862c4b2eae6189f9d91faca39129156851 [file] [log] [blame]
Andreas Huberdcaa2202009-11-05 12:04:22 -08001/*
2 * Copyright (C) 2009 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
17//#define LOG_NDEBUG 0
18#define LOG_TAG "OMXNodeInstance"
19#include <utils/Log.h>
20
21#include "../include/OMXNodeInstance.h"
22
23#include "pv_omxcore.h"
24
25#include <binder/IMemory.h>
26#include <media/stagefright/MediaDebug.h>
27
28namespace android {
29
30struct BufferMeta {
31 BufferMeta(const sp<IMemory> &mem, bool is_backup = false)
32 : mMem(mem),
33 mIsBackup(is_backup) {
34 }
35
36 BufferMeta(size_t size)
37 : mSize(size),
38 mIsBackup(false) {
39 }
40
41 void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
42 if (!mIsBackup) {
43 return;
44 }
45
46 memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
47 header->pBuffer + header->nOffset,
48 header->nFilledLen);
49 }
50
51 void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
52 if (!mIsBackup) {
53 return;
54 }
55
56 memcpy(header->pBuffer + header->nOffset,
57 (const OMX_U8 *)mMem->pointer() + header->nOffset,
58 header->nFilledLen);
59 }
60
61private:
62 sp<IMemory> mMem;
63 size_t mSize;
64 bool mIsBackup;
65
66 BufferMeta(const BufferMeta &);
67 BufferMeta &operator=(const BufferMeta &);
68};
69
70// static
71OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
72 &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
73};
74
75OMXNodeInstance::OMXNodeInstance(
76 OMX *owner, const sp<IOMXObserver> &observer)
77 : mOwner(owner),
78 mNodeID(NULL),
79 mHandle(NULL),
80 mObserver(observer) {
81}
82
83OMXNodeInstance::~OMXNodeInstance() {
84 CHECK_EQ(mHandle, NULL);
85}
86
87void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
88 CHECK_EQ(mHandle, NULL);
89 mNodeID = node_id;
90 mHandle = handle;
91}
92
93OMX *OMXNodeInstance::owner() {
94 return mOwner;
95}
96
97sp<IOMXObserver> OMXNodeInstance::observer() {
98 return mObserver;
99}
100
101OMX::node_id OMXNodeInstance::nodeID() {
102 return mNodeID;
103}
104
105static status_t StatusFromOMXError(OMX_ERRORTYPE err) {
106 return (err == OMX_ErrorNone) ? OK : UNKNOWN_ERROR;
107}
108
109status_t OMXNodeInstance::freeNode() {
110 // Transition the node from its current state all the way down
111 // to "Loaded".
112 // This ensures that all active buffers are properly freed even
113 // for components that don't do this themselves on a call to
114 // "FreeHandle".
115
116 OMX_STATETYPE state;
117 CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone);
118 switch (state) {
119 case OMX_StateExecuting:
120 {
121 LOGV("forcing Executing->Idle");
122 sendCommand(OMX_CommandStateSet, OMX_StateIdle);
123 OMX_ERRORTYPE err;
124 while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
125 && state != OMX_StateIdle) {
126 usleep(100000);
127 }
128 CHECK_EQ(err, OMX_ErrorNone);
129
130 // fall through
131 }
132
133 case OMX_StateIdle:
134 {
135 LOGV("forcing Idle->Loaded");
136 sendCommand(OMX_CommandStateSet, OMX_StateLoaded);
137
138 freeActiveBuffers();
139
140 OMX_ERRORTYPE err;
141 while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
142 && state != OMX_StateLoaded) {
143 LOGV("waiting for Loaded state...");
144 usleep(100000);
145 }
146 CHECK_EQ(err, OMX_ErrorNone);
147
148 // fall through
149 }
150
151 case OMX_StateLoaded:
152 case OMX_StateInvalid:
153 break;
154
155 default:
156 CHECK(!"should not be here, unknown state.");
157 break;
158 }
159
160 OMX_ERRORTYPE err = OMX_MasterFreeHandle(mHandle);
161 mHandle = NULL;
162
163 if (err != OMX_ErrorNone) {
164 LOGE("FreeHandle FAILED with error 0x%08x.", err);
165 }
166
167 mOwner->invalidateNodeID(mNodeID);
168 mNodeID = NULL;
169
170 LOGV("OMXNodeInstance going away.");
171 delete this;
172
173 return StatusFromOMXError(err);
174}
175
176status_t OMXNodeInstance::sendCommand(
177 OMX_COMMANDTYPE cmd, OMX_S32 param) {
178 Mutex::Autolock autoLock(mLock);
179
180 OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
181 return StatusFromOMXError(err);
182}
183
184status_t OMXNodeInstance::getParameter(
185 OMX_INDEXTYPE index, void *params, size_t size) {
186 Mutex::Autolock autoLock(mLock);
187
188 OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
189 return StatusFromOMXError(err);
190}
191
192status_t OMXNodeInstance::setParameter(
193 OMX_INDEXTYPE index, const void *params, size_t size) {
194 Mutex::Autolock autoLock(mLock);
195
196 OMX_ERRORTYPE err = OMX_SetParameter(
197 mHandle, index, const_cast<void *>(params));
198
199 return StatusFromOMXError(err);
200}
201
202status_t OMXNodeInstance::getConfig(
203 OMX_INDEXTYPE index, void *params, size_t size) {
204 Mutex::Autolock autoLock(mLock);
205
206 OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
207 return StatusFromOMXError(err);
208}
209
210status_t OMXNodeInstance::setConfig(
211 OMX_INDEXTYPE index, const void *params, size_t size) {
212 Mutex::Autolock autoLock(mLock);
213
214 OMX_ERRORTYPE err = OMX_SetConfig(
215 mHandle, index, const_cast<void *>(params));
216
217 return StatusFromOMXError(err);
218}
219
220status_t OMXNodeInstance::useBuffer(
221 OMX_U32 portIndex, const sp<IMemory> &params,
222 OMX::buffer_id *buffer) {
223 Mutex::Autolock autoLock(mLock);
224
225 BufferMeta *buffer_meta = new BufferMeta(params);
226
227 OMX_BUFFERHEADERTYPE *header;
228
229 OMX_ERRORTYPE err = OMX_UseBuffer(
230 mHandle, &header, portIndex, buffer_meta,
231 params->size(), static_cast<OMX_U8 *>(params->pointer()));
232
233 if (err != OMX_ErrorNone) {
234 LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
235
236 delete buffer_meta;
237 buffer_meta = NULL;
238
239 *buffer = 0;
240
241 return UNKNOWN_ERROR;
242 }
243
244 *buffer = header;
245
246 addActiveBuffer(portIndex, *buffer);
247
248 return OK;
249}
250
251status_t OMXNodeInstance::allocateBuffer(
252 OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer) {
253 Mutex::Autolock autoLock(mLock);
254
255 BufferMeta *buffer_meta = new BufferMeta(size);
256
257 OMX_BUFFERHEADERTYPE *header;
258
259 OMX_ERRORTYPE err = OMX_AllocateBuffer(
260 mHandle, &header, portIndex, buffer_meta, size);
261
262 if (err != OMX_ErrorNone) {
263 LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
264
265 delete buffer_meta;
266 buffer_meta = NULL;
267
268 *buffer = 0;
269
270 return UNKNOWN_ERROR;
271 }
272
273 *buffer = header;
274
275 addActiveBuffer(portIndex, *buffer);
276
277 return OK;
278}
279
280status_t OMXNodeInstance::allocateBufferWithBackup(
281 OMX_U32 portIndex, const sp<IMemory> &params,
282 OMX::buffer_id *buffer) {
283 Mutex::Autolock autoLock(mLock);
284
285 BufferMeta *buffer_meta = new BufferMeta(params, true);
286
287 OMX_BUFFERHEADERTYPE *header;
288
289 OMX_ERRORTYPE err = OMX_AllocateBuffer(
290 mHandle, &header, portIndex, buffer_meta, params->size());
291
292 if (err != OMX_ErrorNone) {
293 LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
294
295 delete buffer_meta;
296 buffer_meta = NULL;
297
298 *buffer = 0;
299
300 return UNKNOWN_ERROR;
301 }
302
303 *buffer = header;
304
305 addActiveBuffer(portIndex, *buffer);
306
307 return OK;
308}
309
310status_t OMXNodeInstance::freeBuffer(
311 OMX_U32 portIndex, OMX::buffer_id buffer) {
312 Mutex::Autolock autoLock(mLock);
313
314 removeActiveBuffer(portIndex, buffer);
315
316 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
317 BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
318
319 OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
320
321 delete buffer_meta;
322 buffer_meta = NULL;
323
324 return StatusFromOMXError(err);
325}
326
327status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
328 Mutex::Autolock autoLock(mLock);
329
330 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
331 header->nFilledLen = 0;
332 header->nOffset = 0;
333 header->nFlags = 0;
334
335 OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
336
337 return StatusFromOMXError(err);
338}
339
340status_t OMXNodeInstance::emptyBuffer(
341 OMX::buffer_id buffer,
342 OMX_U32 rangeOffset, OMX_U32 rangeLength,
343 OMX_U32 flags, OMX_TICKS timestamp) {
344 Mutex::Autolock autoLock(mLock);
345
346 OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
347 header->nFilledLen = rangeLength;
348 header->nOffset = rangeOffset;
349 header->nFlags = flags;
350 header->nTimeStamp = timestamp;
351
352 BufferMeta *buffer_meta =
353 static_cast<BufferMeta *>(header->pAppPrivate);
354 buffer_meta->CopyToOMX(header);
355
356 OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
357
358 return StatusFromOMXError(err);
359}
360
361status_t OMXNodeInstance::getExtensionIndex(
362 const char *parameterName, OMX_INDEXTYPE *index) {
363 Mutex::Autolock autoLock(mLock);
364
365 OMX_ERRORTYPE err = OMX_GetExtensionIndex(
366 mHandle, const_cast<char *>(parameterName), index);
367
368 return StatusFromOMXError(err);
369}
370
371void OMXNodeInstance::onMessage(const omx_message &msg) {
372 if (msg.type == omx_message::FILL_BUFFER_DONE) {
373 OMX_BUFFERHEADERTYPE *buffer =
374 static_cast<OMX_BUFFERHEADERTYPE *>(
375 msg.u.extended_buffer_data.buffer);
376
377 BufferMeta *buffer_meta =
378 static_cast<BufferMeta *>(buffer->pAppPrivate);
379
380 buffer_meta->CopyFromOMX(buffer);
381 }
382
383 mObserver->onMessage(msg);
384}
385
386void OMXNodeInstance::onObserverDied() {
387 LOGE("!!! Observer died. Quickly, do something, ... anything...");
388
389 // Try to force shutdown of the node and hope for the best.
390 freeNode();
391}
392
393void OMXNodeInstance::onGetHandleFailed() {
394 delete this;
395}
396
397// static
398OMX_ERRORTYPE OMXNodeInstance::OnEvent(
399 OMX_IN OMX_HANDLETYPE hComponent,
400 OMX_IN OMX_PTR pAppData,
401 OMX_IN OMX_EVENTTYPE eEvent,
402 OMX_IN OMX_U32 nData1,
403 OMX_IN OMX_U32 nData2,
404 OMX_IN OMX_PTR pEventData) {
405 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
406 return instance->owner()->OnEvent(
407 instance->nodeID(), eEvent, nData1, nData2, pEventData);
408}
409
410// static
411OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
412 OMX_IN OMX_HANDLETYPE hComponent,
413 OMX_IN OMX_PTR pAppData,
414 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
415 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
416 return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
417}
418
419// static
420OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
421 OMX_IN OMX_HANDLETYPE hComponent,
422 OMX_IN OMX_PTR pAppData,
423 OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
424 OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
425 return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
426}
427
428void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
429 ActiveBuffer active;
430 active.mPortIndex = portIndex;
431 active.mID = id;
432 mActiveBuffers.push(active);
433}
434
435void OMXNodeInstance::removeActiveBuffer(
436 OMX_U32 portIndex, OMX::buffer_id id) {
437 bool found = false;
438 for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
439 if (mActiveBuffers[i].mPortIndex == portIndex
440 && mActiveBuffers[i].mID == id) {
441 found = true;
442 mActiveBuffers.removeItemsAt(i);
443 break;
444 }
445 }
446
447 if (!found) {
448 LOGW("Attempt to remove an active buffer we know nothing about...");
449 }
450}
451
452void OMXNodeInstance::freeActiveBuffers() {
453 // Make sure to count down here, as freeBuffer will in turn remove
454 // the active buffer from the vector...
455 for (size_t i = mActiveBuffers.size(); i--;) {
456 freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
457 }
458}
459
460} // namespace android
461