OMXNodeInstance.cpp revision d6703ab22c85b43fdb2deb78a37e51465c902a5f
1/*
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            break;
153
154        default:
155            CHECK(!"should not be here, unknown state.");
156            break;
157    }
158
159    OMX_ERRORTYPE err = OMX_MasterFreeHandle(mHandle);
160    mHandle = NULL;
161
162    if (err != OMX_ErrorNone) {
163        LOGE("FreeHandle FAILED with error 0x%08x.", err);
164    }
165
166    mOwner->invalidateNodeID(mNodeID);
167    mNodeID = NULL;
168
169    LOGV("OMXNodeInstance going away.");
170    delete this;
171
172    return StatusFromOMXError(err);
173}
174
175status_t OMXNodeInstance::sendCommand(
176        OMX_COMMANDTYPE cmd, OMX_S32 param) {
177    Mutex::Autolock autoLock(mLock);
178
179    OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
180    return StatusFromOMXError(err);
181}
182
183status_t OMXNodeInstance::getParameter(
184        OMX_INDEXTYPE index, void *params, size_t size) {
185    Mutex::Autolock autoLock(mLock);
186
187    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
188    return StatusFromOMXError(err);
189}
190
191status_t OMXNodeInstance::setParameter(
192        OMX_INDEXTYPE index, const void *params, size_t size) {
193    Mutex::Autolock autoLock(mLock);
194
195    OMX_ERRORTYPE err = OMX_SetParameter(
196            mHandle, index, const_cast<void *>(params));
197
198    return StatusFromOMXError(err);
199}
200
201status_t OMXNodeInstance::getConfig(
202        OMX_INDEXTYPE index, void *params, size_t size) {
203    Mutex::Autolock autoLock(mLock);
204
205    OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
206    return StatusFromOMXError(err);
207}
208
209status_t OMXNodeInstance::setConfig(
210        OMX_INDEXTYPE index, const void *params, size_t size) {
211    Mutex::Autolock autoLock(mLock);
212
213    OMX_ERRORTYPE err = OMX_SetConfig(
214            mHandle, index, const_cast<void *>(params));
215
216    return StatusFromOMXError(err);
217}
218
219status_t OMXNodeInstance::useBuffer(
220        OMX_U32 portIndex, const sp<IMemory> &params,
221        OMX::buffer_id *buffer) {
222    Mutex::Autolock autoLock(mLock);
223
224    BufferMeta *buffer_meta = new BufferMeta(params);
225
226    OMX_BUFFERHEADERTYPE *header;
227
228    OMX_ERRORTYPE err = OMX_UseBuffer(
229            mHandle, &header, portIndex, buffer_meta,
230            params->size(), static_cast<OMX_U8 *>(params->pointer()));
231
232    if (err != OMX_ErrorNone) {
233        LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
234
235        delete buffer_meta;
236        buffer_meta = NULL;
237
238        *buffer = 0;
239
240        return UNKNOWN_ERROR;
241    }
242
243    *buffer = header;
244
245    addActiveBuffer(portIndex, *buffer);
246
247    return OK;
248}
249
250status_t OMXNodeInstance::allocateBuffer(
251        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer) {
252    Mutex::Autolock autoLock(mLock);
253
254    BufferMeta *buffer_meta = new BufferMeta(size);
255
256    OMX_BUFFERHEADERTYPE *header;
257
258    OMX_ERRORTYPE err = OMX_AllocateBuffer(
259            mHandle, &header, portIndex, buffer_meta, size);
260
261    if (err != OMX_ErrorNone) {
262        LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
263
264        delete buffer_meta;
265        buffer_meta = NULL;
266
267        *buffer = 0;
268
269        return UNKNOWN_ERROR;
270    }
271
272    *buffer = header;
273
274    addActiveBuffer(portIndex, *buffer);
275
276    return OK;
277}
278
279status_t OMXNodeInstance::allocateBufferWithBackup(
280        OMX_U32 portIndex, const sp<IMemory> &params,
281        OMX::buffer_id *buffer) {
282    Mutex::Autolock autoLock(mLock);
283
284    BufferMeta *buffer_meta = new BufferMeta(params, true);
285
286    OMX_BUFFERHEADERTYPE *header;
287
288    OMX_ERRORTYPE err = OMX_AllocateBuffer(
289            mHandle, &header, portIndex, buffer_meta, params->size());
290
291    if (err != OMX_ErrorNone) {
292        LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
293
294        delete buffer_meta;
295        buffer_meta = NULL;
296
297        *buffer = 0;
298
299        return UNKNOWN_ERROR;
300    }
301
302    *buffer = header;
303
304    addActiveBuffer(portIndex, *buffer);
305
306    return OK;
307}
308
309status_t OMXNodeInstance::freeBuffer(
310        OMX_U32 portIndex, OMX::buffer_id buffer) {
311    Mutex::Autolock autoLock(mLock);
312
313    removeActiveBuffer(portIndex, buffer);
314
315    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
316    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
317
318    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
319
320    delete buffer_meta;
321    buffer_meta = NULL;
322
323    return StatusFromOMXError(err);
324}
325
326status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
327    Mutex::Autolock autoLock(mLock);
328
329    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
330    header->nFilledLen = 0;
331    header->nOffset = 0;
332    header->nFlags = 0;
333
334    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
335
336    return StatusFromOMXError(err);
337}
338
339status_t OMXNodeInstance::emptyBuffer(
340        OMX::buffer_id buffer,
341        OMX_U32 rangeOffset, OMX_U32 rangeLength,
342        OMX_U32 flags, OMX_TICKS timestamp) {
343    Mutex::Autolock autoLock(mLock);
344
345    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
346    header->nFilledLen = rangeLength;
347    header->nOffset = rangeOffset;
348    header->nFlags = flags;
349    header->nTimeStamp = timestamp;
350
351    BufferMeta *buffer_meta =
352        static_cast<BufferMeta *>(header->pAppPrivate);
353    buffer_meta->CopyToOMX(header);
354
355    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
356
357    return StatusFromOMXError(err);
358}
359
360status_t OMXNodeInstance::getExtensionIndex(
361        const char *parameterName, OMX_INDEXTYPE *index) {
362    Mutex::Autolock autoLock(mLock);
363
364    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
365            mHandle, const_cast<char *>(parameterName), index);
366
367    return StatusFromOMXError(err);
368}
369
370void OMXNodeInstance::onMessage(const omx_message &msg) {
371    if (msg.type == omx_message::FILL_BUFFER_DONE) {
372        OMX_BUFFERHEADERTYPE *buffer =
373            static_cast<OMX_BUFFERHEADERTYPE *>(
374                    msg.u.extended_buffer_data.buffer);
375
376        BufferMeta *buffer_meta =
377            static_cast<BufferMeta *>(buffer->pAppPrivate);
378
379        buffer_meta->CopyFromOMX(buffer);
380    }
381
382    mObserver->onMessage(msg);
383}
384
385void OMXNodeInstance::onObserverDied() {
386    LOGE("!!! Observer died. Quickly, do something, ... anything...");
387
388    // Try to force shutdown of the node and hope for the best.
389    freeNode();
390}
391
392void OMXNodeInstance::onGetHandleFailed() {
393    delete this;
394}
395
396// static
397OMX_ERRORTYPE OMXNodeInstance::OnEvent(
398        OMX_IN OMX_HANDLETYPE hComponent,
399        OMX_IN OMX_PTR pAppData,
400        OMX_IN OMX_EVENTTYPE eEvent,
401        OMX_IN OMX_U32 nData1,
402        OMX_IN OMX_U32 nData2,
403        OMX_IN OMX_PTR pEventData) {
404    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
405    return instance->owner()->OnEvent(
406            instance->nodeID(), eEvent, nData1, nData2, pEventData);
407}
408
409// static
410OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
411        OMX_IN OMX_HANDLETYPE hComponent,
412        OMX_IN OMX_PTR pAppData,
413        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
414    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
415    return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
416}
417
418// static
419OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
420        OMX_IN OMX_HANDLETYPE hComponent,
421        OMX_IN OMX_PTR pAppData,
422        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
423    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
424    return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
425}
426
427void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
428    ActiveBuffer active;
429    active.mPortIndex = portIndex;
430    active.mID = id;
431    mActiveBuffers.push(active);
432}
433
434void OMXNodeInstance::removeActiveBuffer(
435        OMX_U32 portIndex, OMX::buffer_id id) {
436    bool found = false;
437    for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
438        if (mActiveBuffers[i].mPortIndex == portIndex
439            && mActiveBuffers[i].mID == id) {
440            found = true;
441            mActiveBuffers.removeItemsAt(i);
442            break;
443        }
444    }
445
446    if (!found) {
447        LOGW("Attempt to remove an active buffer we know nothing about...");
448    }
449}
450
451void OMXNodeInstance::freeActiveBuffers() {
452    // Make sure to count down here, as freeBuffer will in turn remove
453    // the active buffer from the vector...
454    for (size_t i = mActiveBuffers.size(); i--;) {
455        freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
456    }
457}
458
459}  // namespace android
460
461