OMXNodeInstance.cpp revision 83750eaf5a3f38c243a9e7eb81d4b2421e3a0d88
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#include "OMXMaster.h"
23
24#include <OMX_Component.h>
25
26#include <binder/IMemory.h>
27#include <media/stagefright/HardwareAPI.h>
28#include <media/stagefright/MediaDebug.h>
29#include <media/stagefright/MediaErrors.h>
30
31namespace android {
32
33struct BufferMeta {
34    BufferMeta(const sp<IMemory> &mem, bool is_backup = false)
35        : mMem(mem),
36          mIsBackup(is_backup) {
37    }
38
39    BufferMeta(size_t size)
40        : mSize(size),
41          mIsBackup(false) {
42    }
43
44    BufferMeta(const sp<GraphicBuffer> &graphicBuffer)
45        : mGraphicBuffer(graphicBuffer),
46          mIsBackup(false) {
47    }
48
49    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
50        if (!mIsBackup) {
51            return;
52        }
53
54        memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
55               header->pBuffer + header->nOffset,
56               header->nFilledLen);
57    }
58
59    void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
60        if (!mIsBackup) {
61            return;
62        }
63
64        memcpy(header->pBuffer + header->nOffset,
65               (const OMX_U8 *)mMem->pointer() + header->nOffset,
66               header->nFilledLen);
67    }
68
69private:
70    sp<GraphicBuffer> mGraphicBuffer;
71    sp<IMemory> mMem;
72    size_t mSize;
73    bool mIsBackup;
74
75    BufferMeta(const BufferMeta &);
76    BufferMeta &operator=(const BufferMeta &);
77};
78
79// static
80OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
81    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
82};
83
84OMXNodeInstance::OMXNodeInstance(
85        OMX *owner, const sp<IOMXObserver> &observer)
86    : mOwner(owner),
87      mNodeID(NULL),
88      mHandle(NULL),
89      mObserver(observer),
90      mDying(false) {
91}
92
93OMXNodeInstance::~OMXNodeInstance() {
94    CHECK_EQ(mHandle, NULL);
95}
96
97void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
98    CHECK_EQ(mHandle, NULL);
99    mNodeID = node_id;
100    mHandle = handle;
101}
102
103OMX *OMXNodeInstance::owner() {
104    return mOwner;
105}
106
107sp<IOMXObserver> OMXNodeInstance::observer() {
108    return mObserver;
109}
110
111OMX::node_id OMXNodeInstance::nodeID() {
112    return mNodeID;
113}
114
115static status_t StatusFromOMXError(OMX_ERRORTYPE err) {
116    switch (err) {
117        case OMX_ErrorNone:
118            return OK;
119        case OMX_ErrorUnsupportedSetting:
120            return ERROR_UNSUPPORTED;
121        default:
122            return UNKNOWN_ERROR;
123    }
124}
125
126status_t OMXNodeInstance::freeNode(OMXMaster *master) {
127    // Transition the node from its current state all the way down
128    // to "Loaded".
129    // This ensures that all active buffers are properly freed even
130    // for components that don't do this themselves on a call to
131    // "FreeHandle".
132
133    // The code below may trigger some more events to be dispatched
134    // by the OMX component - we want to ignore them as our client
135    // does not expect them.
136    mDying = true;
137
138    OMX_STATETYPE state;
139    CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone);
140    switch (state) {
141        case OMX_StateExecuting:
142        {
143            LOGV("forcing Executing->Idle");
144            sendCommand(OMX_CommandStateSet, OMX_StateIdle);
145            OMX_ERRORTYPE err;
146            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
147                   && state != OMX_StateIdle
148                   && state != OMX_StateInvalid) {
149                usleep(100000);
150            }
151            CHECK_EQ(err, OMX_ErrorNone);
152
153            if (state == OMX_StateInvalid) {
154                break;
155            }
156
157            // fall through
158        }
159
160        case OMX_StateIdle:
161        {
162            LOGV("forcing Idle->Loaded");
163            sendCommand(OMX_CommandStateSet, OMX_StateLoaded);
164
165            freeActiveBuffers();
166
167            OMX_ERRORTYPE err;
168            while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
169                   && state != OMX_StateLoaded
170                   && state != OMX_StateInvalid) {
171                LOGV("waiting for Loaded state...");
172                usleep(100000);
173            }
174            CHECK_EQ(err, OMX_ErrorNone);
175
176            // fall through
177        }
178
179        case OMX_StateLoaded:
180        case OMX_StateInvalid:
181            break;
182
183        default:
184            CHECK(!"should not be here, unknown state.");
185            break;
186    }
187
188    OMX_ERRORTYPE err = master->destroyComponentInstance(
189            static_cast<OMX_COMPONENTTYPE *>(mHandle));
190
191    mHandle = NULL;
192
193    if (err != OMX_ErrorNone) {
194        LOGE("FreeHandle FAILED with error 0x%08x.", err);
195    }
196
197    mOwner->invalidateNodeID(mNodeID);
198    mNodeID = NULL;
199
200    LOGV("OMXNodeInstance going away.");
201    delete this;
202
203    return StatusFromOMXError(err);
204}
205
206status_t OMXNodeInstance::sendCommand(
207        OMX_COMMANDTYPE cmd, OMX_S32 param) {
208    Mutex::Autolock autoLock(mLock);
209
210    OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
211    return StatusFromOMXError(err);
212}
213
214status_t OMXNodeInstance::getParameter(
215        OMX_INDEXTYPE index, void *params, size_t size) {
216    Mutex::Autolock autoLock(mLock);
217
218    OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
219    return StatusFromOMXError(err);
220}
221
222status_t OMXNodeInstance::setParameter(
223        OMX_INDEXTYPE index, const void *params, size_t size) {
224    Mutex::Autolock autoLock(mLock);
225
226    OMX_ERRORTYPE err = OMX_SetParameter(
227            mHandle, index, const_cast<void *>(params));
228
229    return StatusFromOMXError(err);
230}
231
232status_t OMXNodeInstance::getConfig(
233        OMX_INDEXTYPE index, void *params, size_t size) {
234    Mutex::Autolock autoLock(mLock);
235
236    OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
237    return StatusFromOMXError(err);
238}
239
240status_t OMXNodeInstance::setConfig(
241        OMX_INDEXTYPE index, const void *params, size_t size) {
242    Mutex::Autolock autoLock(mLock);
243
244    OMX_ERRORTYPE err = OMX_SetConfig(
245            mHandle, index, const_cast<void *>(params));
246
247    return StatusFromOMXError(err);
248}
249
250status_t OMXNodeInstance::enableGraphicBuffers(
251        OMX_U32 portIndex, OMX_BOOL enable) {
252    Mutex::Autolock autoLock(mLock);
253
254    OMX_INDEXTYPE index;
255    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
256            mHandle,
257            const_cast<OMX_STRING>("OMX.google.android.index.enableAndroidNativeBuffers"),
258            &index);
259
260    if (err != OMX_ErrorNone) {
261        LOGE("OMX_GetExtensionIndex failed");
262
263        return StatusFromOMXError(err);
264    }
265
266    OMX_VERSIONTYPE ver;
267    ver.s.nVersionMajor = 1;
268    ver.s.nVersionMinor = 0;
269    ver.s.nRevision = 0;
270    ver.s.nStep = 0;
271    EnableAndroidNativeBuffersParams params = {
272        sizeof(EnableAndroidNativeBuffersParams), ver, portIndex, enable,
273    };
274
275    err = OMX_SetParameter(mHandle, index, &params);
276
277    if (err != OMX_ErrorNone) {
278        LOGE("OMX_EnableAndroidNativeBuffers failed with error %d (0x%08x)",
279                err, err);
280
281        return UNKNOWN_ERROR;
282    }
283
284    return OK;
285}
286
287status_t OMXNodeInstance::useBuffer(
288        OMX_U32 portIndex, const sp<IMemory> &params,
289        OMX::buffer_id *buffer) {
290    Mutex::Autolock autoLock(mLock);
291
292    BufferMeta *buffer_meta = new BufferMeta(params);
293
294    OMX_BUFFERHEADERTYPE *header;
295
296    OMX_ERRORTYPE err = OMX_UseBuffer(
297            mHandle, &header, portIndex, buffer_meta,
298            params->size(), static_cast<OMX_U8 *>(params->pointer()));
299
300    if (err != OMX_ErrorNone) {
301        LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
302
303        delete buffer_meta;
304        buffer_meta = NULL;
305
306        *buffer = 0;
307
308        return UNKNOWN_ERROR;
309    }
310
311    CHECK_EQ(header->pAppPrivate, buffer_meta);
312
313    *buffer = header;
314
315    addActiveBuffer(portIndex, *buffer);
316
317    return OK;
318}
319
320status_t OMXNodeInstance::useGraphicBuffer(
321        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
322        OMX::buffer_id *buffer) {
323    Mutex::Autolock autoLock(mLock);
324
325    OMX_INDEXTYPE index;
326    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
327            mHandle,
328            const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer"),
329            &index);
330
331    if (err != OMX_ErrorNone) {
332        LOGE("OMX_GetExtensionIndex failed");
333
334        return StatusFromOMXError(err);
335    }
336
337    BufferMeta *bufferMeta = new BufferMeta(graphicBuffer);
338
339    OMX_BUFFERHEADERTYPE *header;
340
341    OMX_VERSIONTYPE ver;
342    ver.s.nVersionMajor = 1;
343    ver.s.nVersionMinor = 0;
344    ver.s.nRevision = 0;
345    ver.s.nStep = 0;
346    UseAndroidNativeBufferParams params = {
347        sizeof(UseAndroidNativeBufferParams), ver, portIndex, bufferMeta,
348        &header, graphicBuffer,
349    };
350
351    err = OMX_SetParameter(mHandle, index, &params);
352
353    if (err != OMX_ErrorNone) {
354        LOGE("OMX_UseAndroidNativeBuffer failed with error %d (0x%08x)", err,
355                err);
356
357        delete bufferMeta;
358        bufferMeta = NULL;
359
360        *buffer = 0;
361
362        return UNKNOWN_ERROR;
363    }
364
365    CHECK_EQ(header->pAppPrivate, bufferMeta);
366
367    *buffer = header;
368
369    addActiveBuffer(portIndex, *buffer);
370
371    return OK;
372}
373
374status_t OMXNodeInstance::allocateBuffer(
375        OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
376        void **buffer_data) {
377    Mutex::Autolock autoLock(mLock);
378
379    BufferMeta *buffer_meta = new BufferMeta(size);
380
381    OMX_BUFFERHEADERTYPE *header;
382
383    OMX_ERRORTYPE err = OMX_AllocateBuffer(
384            mHandle, &header, portIndex, buffer_meta, size);
385
386    if (err != OMX_ErrorNone) {
387        LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
388
389        delete buffer_meta;
390        buffer_meta = NULL;
391
392        *buffer = 0;
393
394        return UNKNOWN_ERROR;
395    }
396
397    CHECK_EQ(header->pAppPrivate, buffer_meta);
398
399    *buffer = header;
400    *buffer_data = header->pBuffer;
401
402    addActiveBuffer(portIndex, *buffer);
403
404    return OK;
405}
406
407status_t OMXNodeInstance::allocateBufferWithBackup(
408        OMX_U32 portIndex, const sp<IMemory> &params,
409        OMX::buffer_id *buffer) {
410    Mutex::Autolock autoLock(mLock);
411
412    BufferMeta *buffer_meta = new BufferMeta(params, true);
413
414    OMX_BUFFERHEADERTYPE *header;
415
416    OMX_ERRORTYPE err = OMX_AllocateBuffer(
417            mHandle, &header, portIndex, buffer_meta, params->size());
418
419    if (err != OMX_ErrorNone) {
420        LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
421
422        delete buffer_meta;
423        buffer_meta = NULL;
424
425        *buffer = 0;
426
427        return UNKNOWN_ERROR;
428    }
429
430    CHECK_EQ(header->pAppPrivate, buffer_meta);
431
432    *buffer = header;
433
434    addActiveBuffer(portIndex, *buffer);
435
436    return OK;
437}
438
439status_t OMXNodeInstance::freeBuffer(
440        OMX_U32 portIndex, OMX::buffer_id buffer) {
441    Mutex::Autolock autoLock(mLock);
442
443    removeActiveBuffer(portIndex, buffer);
444
445    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
446    BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
447
448    OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
449
450    delete buffer_meta;
451    buffer_meta = NULL;
452
453    return StatusFromOMXError(err);
454}
455
456status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
457    Mutex::Autolock autoLock(mLock);
458
459    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
460    header->nFilledLen = 0;
461    header->nOffset = 0;
462    header->nFlags = 0;
463
464    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
465
466    return StatusFromOMXError(err);
467}
468
469status_t OMXNodeInstance::emptyBuffer(
470        OMX::buffer_id buffer,
471        OMX_U32 rangeOffset, OMX_U32 rangeLength,
472        OMX_U32 flags, OMX_TICKS timestamp) {
473    Mutex::Autolock autoLock(mLock);
474
475    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
476    header->nFilledLen = rangeLength;
477    header->nOffset = rangeOffset;
478    header->nFlags = flags;
479    header->nTimeStamp = timestamp;
480
481    BufferMeta *buffer_meta =
482        static_cast<BufferMeta *>(header->pAppPrivate);
483    buffer_meta->CopyToOMX(header);
484
485    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
486
487    return StatusFromOMXError(err);
488}
489
490status_t OMXNodeInstance::getExtensionIndex(
491        const char *parameterName, OMX_INDEXTYPE *index) {
492    Mutex::Autolock autoLock(mLock);
493
494    OMX_ERRORTYPE err = OMX_GetExtensionIndex(
495            mHandle, const_cast<char *>(parameterName), index);
496
497    return StatusFromOMXError(err);
498}
499
500void OMXNodeInstance::onMessage(const omx_message &msg) {
501    if (msg.type == omx_message::FILL_BUFFER_DONE) {
502        OMX_BUFFERHEADERTYPE *buffer =
503            static_cast<OMX_BUFFERHEADERTYPE *>(
504                    msg.u.extended_buffer_data.buffer);
505
506        BufferMeta *buffer_meta =
507            static_cast<BufferMeta *>(buffer->pAppPrivate);
508
509        buffer_meta->CopyFromOMX(buffer);
510    }
511
512    mObserver->onMessage(msg);
513}
514
515void OMXNodeInstance::onObserverDied(OMXMaster *master) {
516    LOGE("!!! Observer died. Quickly, do something, ... anything...");
517
518    // Try to force shutdown of the node and hope for the best.
519    freeNode(master);
520}
521
522void OMXNodeInstance::onGetHandleFailed() {
523    delete this;
524}
525
526// static
527OMX_ERRORTYPE OMXNodeInstance::OnEvent(
528        OMX_IN OMX_HANDLETYPE hComponent,
529        OMX_IN OMX_PTR pAppData,
530        OMX_IN OMX_EVENTTYPE eEvent,
531        OMX_IN OMX_U32 nData1,
532        OMX_IN OMX_U32 nData2,
533        OMX_IN OMX_PTR pEventData) {
534    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
535    if (instance->mDying) {
536        return OMX_ErrorNone;
537    }
538    return instance->owner()->OnEvent(
539            instance->nodeID(), eEvent, nData1, nData2, pEventData);
540}
541
542// static
543OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
544        OMX_IN OMX_HANDLETYPE hComponent,
545        OMX_IN OMX_PTR pAppData,
546        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
547    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
548    if (instance->mDying) {
549        return OMX_ErrorNone;
550    }
551    return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
552}
553
554// static
555OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
556        OMX_IN OMX_HANDLETYPE hComponent,
557        OMX_IN OMX_PTR pAppData,
558        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
559    OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
560    if (instance->mDying) {
561        return OMX_ErrorNone;
562    }
563    return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
564}
565
566void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
567    ActiveBuffer active;
568    active.mPortIndex = portIndex;
569    active.mID = id;
570    mActiveBuffers.push(active);
571}
572
573void OMXNodeInstance::removeActiveBuffer(
574        OMX_U32 portIndex, OMX::buffer_id id) {
575    bool found = false;
576    for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
577        if (mActiveBuffers[i].mPortIndex == portIndex
578            && mActiveBuffers[i].mID == id) {
579            found = true;
580            mActiveBuffers.removeItemsAt(i);
581            break;
582        }
583    }
584
585    if (!found) {
586        LOGW("Attempt to remove an active buffer we know nothing about...");
587    }
588}
589
590void OMXNodeInstance::freeActiveBuffers() {
591    // Make sure to count down here, as freeBuffer will in turn remove
592    // the active buffer from the vector...
593    for (size_t i = mActiveBuffers.size(); i--;) {
594        freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
595    }
596}
597
598}  // namespace android
599