OMXNodeInstance.cpp revision fa70cad40b01627ac1c22e04cdd548ece9c2654f
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        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
462