SimpleSoftOMXComponent.cpp revision 643319f60e72a86c180ee839b25c086554e5bd47
1/*
2 * Copyright (C) 2011 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 "SimpleSoftOMXComponent"
19#include <utils/Log.h>
20
21#include "include/SimpleSoftOMXComponent.h"
22
23#include <media/stagefright/foundation/ADebug.h>
24#include <media/stagefright/foundation/ALooper.h>
25#include <media/stagefright/foundation/AMessage.h>
26
27namespace android {
28
29SimpleSoftOMXComponent::SimpleSoftOMXComponent(
30        const char *name,
31        const OMX_CALLBACKTYPE *callbacks,
32        OMX_PTR appData,
33        OMX_COMPONENTTYPE **component)
34    : SoftOMXComponent(name, callbacks, appData, component),
35      mLooper(new ALooper),
36      mHandler(new AHandlerReflector<SimpleSoftOMXComponent>(this)),
37      mState(OMX_StateLoaded),
38      mTargetState(OMX_StateLoaded) {
39    mLooper->setName(name);
40    mLooper->registerHandler(mHandler);
41
42    mLooper->start(
43            false, // runOnCallingThread
44            false, // canCallJava
45            ANDROID_PRIORITY_FOREGROUND);
46}
47
48void SimpleSoftOMXComponent::prepareForDestruction() {
49    // The looper's queue may still contain messages referencing this
50    // object. Make sure those are flushed before returning so that
51    // a subsequent dlunload() does not pull out the rug from under us.
52
53    mLooper->unregisterHandler(mHandler->id());
54    mLooper->stop();
55}
56
57OMX_ERRORTYPE SimpleSoftOMXComponent::sendCommand(
58        OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data) {
59    CHECK(data == NULL);
60
61    sp<AMessage> msg = new AMessage(kWhatSendCommand, mHandler->id());
62    msg->setInt32("cmd", cmd);
63    msg->setInt32("param", param);
64    msg->post();
65
66    return OMX_ErrorNone;
67}
68
69bool SimpleSoftOMXComponent::isSetParameterAllowed(
70        OMX_INDEXTYPE index, const OMX_PTR params) const {
71    if (mState == OMX_StateLoaded) {
72        return true;
73    }
74
75    OMX_U32 portIndex;
76
77    switch (index) {
78        case OMX_IndexParamPortDefinition:
79        {
80            portIndex = ((OMX_PARAM_PORTDEFINITIONTYPE *)params)->nPortIndex;
81            break;
82        }
83
84        case OMX_IndexParamAudioPcm:
85        {
86            portIndex = ((OMX_AUDIO_PARAM_PCMMODETYPE *)params)->nPortIndex;
87            break;
88        }
89
90        case OMX_IndexParamAudioAac:
91        {
92            portIndex = ((OMX_AUDIO_PARAM_AACPROFILETYPE *)params)->nPortIndex;
93            break;
94        }
95
96        default:
97            return false;
98    }
99
100    CHECK(portIndex < mPorts.size());
101
102    return !mPorts.itemAt(portIndex).mDef.bEnabled;
103}
104
105OMX_ERRORTYPE SimpleSoftOMXComponent::getParameter(
106        OMX_INDEXTYPE index, OMX_PTR params) {
107    Mutex::Autolock autoLock(mLock);
108    return internalGetParameter(index, params);
109}
110
111OMX_ERRORTYPE SimpleSoftOMXComponent::setParameter(
112        OMX_INDEXTYPE index, const OMX_PTR params) {
113    Mutex::Autolock autoLock(mLock);
114
115    CHECK(isSetParameterAllowed(index, params));
116
117    return internalSetParameter(index, params);
118}
119
120OMX_ERRORTYPE SimpleSoftOMXComponent::internalGetParameter(
121        OMX_INDEXTYPE index, OMX_PTR params) {
122    switch (index) {
123        case OMX_IndexParamPortDefinition:
124        {
125            OMX_PARAM_PORTDEFINITIONTYPE *defParams =
126                (OMX_PARAM_PORTDEFINITIONTYPE *)params;
127
128            if (defParams->nPortIndex >= mPorts.size()
129                    || defParams->nSize
130                            != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
131                return OMX_ErrorUndefined;
132            }
133
134            const PortInfo *port =
135                &mPorts.itemAt(defParams->nPortIndex);
136
137            memcpy(defParams, &port->mDef, sizeof(port->mDef));
138
139            return OMX_ErrorNone;
140        }
141
142        default:
143            return OMX_ErrorUnsupportedIndex;
144    }
145}
146
147OMX_ERRORTYPE SimpleSoftOMXComponent::internalSetParameter(
148        OMX_INDEXTYPE index, const OMX_PTR params) {
149    switch (index) {
150        case OMX_IndexParamPortDefinition:
151        {
152            OMX_PARAM_PORTDEFINITIONTYPE *defParams =
153                (OMX_PARAM_PORTDEFINITIONTYPE *)params;
154
155            if (defParams->nPortIndex >= mPorts.size()) {
156                return OMX_ErrorBadPortIndex;
157            }
158            if (defParams->nSize != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
159                return OMX_ErrorUnsupportedSetting;
160            }
161
162            PortInfo *port =
163                &mPorts.editItemAt(defParams->nPortIndex);
164
165            // default behavior is that we only allow buffer size to increase
166            if (defParams->nBufferSize > port->mDef.nBufferSize) {
167                port->mDef.nBufferSize = defParams->nBufferSize;
168            }
169
170            if (defParams->nBufferCountActual < port->mDef.nBufferCountMin) {
171                ALOGW("component requires at least %u buffers (%u requested)",
172                        port->mDef.nBufferCountMin, defParams->nBufferCountActual);
173                return OMX_ErrorUnsupportedSetting;
174            }
175
176            port->mDef.nBufferCountActual = defParams->nBufferCountActual;
177            return OMX_ErrorNone;
178        }
179
180        default:
181            return OMX_ErrorUnsupportedIndex;
182    }
183}
184
185OMX_ERRORTYPE SimpleSoftOMXComponent::useBuffer(
186        OMX_BUFFERHEADERTYPE **header,
187        OMX_U32 portIndex,
188        OMX_PTR appPrivate,
189        OMX_U32 size,
190        OMX_U8 *ptr) {
191    Mutex::Autolock autoLock(mLock);
192    CHECK_LT(portIndex, mPorts.size());
193
194    *header = new OMX_BUFFERHEADERTYPE;
195    (*header)->nSize = sizeof(OMX_BUFFERHEADERTYPE);
196    (*header)->nVersion.s.nVersionMajor = 1;
197    (*header)->nVersion.s.nVersionMinor = 0;
198    (*header)->nVersion.s.nRevision = 0;
199    (*header)->nVersion.s.nStep = 0;
200    (*header)->pBuffer = ptr;
201    (*header)->nAllocLen = size;
202    (*header)->nFilledLen = 0;
203    (*header)->nOffset = 0;
204    (*header)->pAppPrivate = appPrivate;
205    (*header)->pPlatformPrivate = NULL;
206    (*header)->pInputPortPrivate = NULL;
207    (*header)->pOutputPortPrivate = NULL;
208    (*header)->hMarkTargetComponent = NULL;
209    (*header)->pMarkData = NULL;
210    (*header)->nTickCount = 0;
211    (*header)->nTimeStamp = 0;
212    (*header)->nFlags = 0;
213    (*header)->nOutputPortIndex = portIndex;
214    (*header)->nInputPortIndex = portIndex;
215
216    PortInfo *port = &mPorts.editItemAt(portIndex);
217
218    CHECK(mState == OMX_StateLoaded || port->mDef.bEnabled == OMX_FALSE);
219
220    CHECK_LT(port->mBuffers.size(), port->mDef.nBufferCountActual);
221
222    port->mBuffers.push();
223
224    BufferInfo *buffer =
225        &port->mBuffers.editItemAt(port->mBuffers.size() - 1);
226
227    buffer->mHeader = *header;
228    buffer->mOwnedByUs = false;
229
230    if (port->mBuffers.size() == port->mDef.nBufferCountActual) {
231        port->mDef.bPopulated = OMX_TRUE;
232        checkTransitions();
233    }
234
235    return OMX_ErrorNone;
236}
237
238OMX_ERRORTYPE SimpleSoftOMXComponent::allocateBuffer(
239        OMX_BUFFERHEADERTYPE **header,
240        OMX_U32 portIndex,
241        OMX_PTR appPrivate,
242        OMX_U32 size) {
243    OMX_U8 *ptr = new OMX_U8[size];
244
245    OMX_ERRORTYPE err =
246        useBuffer(header, portIndex, appPrivate, size, ptr);
247
248    if (err != OMX_ErrorNone) {
249        delete[] ptr;
250        ptr = NULL;
251
252        return err;
253    }
254
255    CHECK((*header)->pPlatformPrivate == NULL);
256    (*header)->pPlatformPrivate = ptr;
257
258    return OMX_ErrorNone;
259}
260
261OMX_ERRORTYPE SimpleSoftOMXComponent::freeBuffer(
262        OMX_U32 portIndex,
263        OMX_BUFFERHEADERTYPE *header) {
264    Mutex::Autolock autoLock(mLock);
265
266    CHECK_LT(portIndex, mPorts.size());
267
268    PortInfo *port = &mPorts.editItemAt(portIndex);
269
270#if 0 // XXX
271    CHECK((mState == OMX_StateIdle && mTargetState == OMX_StateLoaded)
272            || port->mDef.bEnabled == OMX_FALSE);
273#endif
274
275    bool found = false;
276    for (size_t i = 0; i < port->mBuffers.size(); ++i) {
277        BufferInfo *buffer = &port->mBuffers.editItemAt(i);
278
279        if (buffer->mHeader == header) {
280            CHECK(!buffer->mOwnedByUs);
281
282            if (header->pPlatformPrivate != NULL) {
283                // This buffer's data was allocated by us.
284                CHECK(header->pPlatformPrivate == header->pBuffer);
285
286                delete[] header->pBuffer;
287                header->pBuffer = NULL;
288            }
289
290            delete header;
291            header = NULL;
292
293            port->mBuffers.removeAt(i);
294            port->mDef.bPopulated = OMX_FALSE;
295
296            checkTransitions();
297
298            found = true;
299            break;
300        }
301    }
302
303    CHECK(found);
304
305    return OMX_ErrorNone;
306}
307
308OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer(
309        OMX_BUFFERHEADERTYPE *buffer) {
310    sp<AMessage> msg = new AMessage(kWhatEmptyThisBuffer, mHandler->id());
311    msg->setPointer("header", buffer);
312    msg->post();
313
314    return OMX_ErrorNone;
315}
316
317OMX_ERRORTYPE SimpleSoftOMXComponent::fillThisBuffer(
318        OMX_BUFFERHEADERTYPE *buffer) {
319    sp<AMessage> msg = new AMessage(kWhatFillThisBuffer, mHandler->id());
320    msg->setPointer("header", buffer);
321    msg->post();
322
323    return OMX_ErrorNone;
324}
325
326OMX_ERRORTYPE SimpleSoftOMXComponent::getState(OMX_STATETYPE *state) {
327    Mutex::Autolock autoLock(mLock);
328
329    *state = mState;
330
331    return OMX_ErrorNone;
332}
333
334void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) {
335    Mutex::Autolock autoLock(mLock);
336    uint32_t msgType = msg->what();
337    ALOGV("msgType = %d", msgType);
338    switch (msgType) {
339        case kWhatSendCommand:
340        {
341            int32_t cmd, param;
342            CHECK(msg->findInt32("cmd", &cmd));
343            CHECK(msg->findInt32("param", &param));
344
345            onSendCommand((OMX_COMMANDTYPE)cmd, (OMX_U32)param);
346            break;
347        }
348
349        case kWhatEmptyThisBuffer:
350        case kWhatFillThisBuffer:
351        {
352            OMX_BUFFERHEADERTYPE *header;
353            CHECK(msg->findPointer("header", (void **)&header));
354
355            CHECK(mState == OMX_StateExecuting && mTargetState == mState);
356
357            bool found = false;
358            size_t portIndex = (kWhatEmptyThisBuffer == msgType)?
359                    header->nInputPortIndex: header->nOutputPortIndex;
360            PortInfo *port = &mPorts.editItemAt(portIndex);
361
362            for (size_t j = 0; j < port->mBuffers.size(); ++j) {
363                BufferInfo *buffer = &port->mBuffers.editItemAt(j);
364
365                if (buffer->mHeader == header) {
366                    CHECK(!buffer->mOwnedByUs);
367
368                    buffer->mOwnedByUs = true;
369
370                    CHECK((msgType == kWhatEmptyThisBuffer
371                            && port->mDef.eDir == OMX_DirInput)
372                            || (port->mDef.eDir == OMX_DirOutput));
373
374                    port->mQueue.push_back(buffer);
375                    onQueueFilled(portIndex);
376
377                    found = true;
378                    break;
379                }
380            }
381
382            CHECK(found);
383            break;
384        }
385
386        default:
387            TRESPASS();
388            break;
389    }
390}
391
392void SimpleSoftOMXComponent::onSendCommand(
393        OMX_COMMANDTYPE cmd, OMX_U32 param) {
394    switch (cmd) {
395        case OMX_CommandStateSet:
396        {
397            onChangeState((OMX_STATETYPE)param);
398            break;
399        }
400
401        case OMX_CommandPortEnable:
402        case OMX_CommandPortDisable:
403        {
404            onPortEnable(param, cmd == OMX_CommandPortEnable);
405            break;
406        }
407
408        case OMX_CommandFlush:
409        {
410            onPortFlush(param, true /* sendFlushComplete */);
411            break;
412        }
413
414        default:
415            TRESPASS();
416            break;
417    }
418}
419
420void SimpleSoftOMXComponent::onChangeState(OMX_STATETYPE state) {
421    // We shouldn't be in a state transition already.
422    CHECK_EQ((int)mState, (int)mTargetState);
423
424    switch (mState) {
425        case OMX_StateLoaded:
426            CHECK_EQ((int)state, (int)OMX_StateIdle);
427            break;
428        case OMX_StateIdle:
429            CHECK(state == OMX_StateLoaded || state == OMX_StateExecuting);
430            break;
431        case OMX_StateExecuting:
432        {
433            CHECK_EQ((int)state, (int)OMX_StateIdle);
434
435            for (size_t i = 0; i < mPorts.size(); ++i) {
436                onPortFlush(i, false /* sendFlushComplete */);
437            }
438
439            mState = OMX_StateIdle;
440            notify(OMX_EventCmdComplete, OMX_CommandStateSet, state, NULL);
441            break;
442        }
443
444        default:
445            TRESPASS();
446    }
447
448    mTargetState = state;
449
450    checkTransitions();
451}
452
453void SimpleSoftOMXComponent::onReset() {
454    // no-op
455}
456
457void SimpleSoftOMXComponent::onPortEnable(OMX_U32 portIndex, bool enable) {
458    CHECK_LT(portIndex, mPorts.size());
459
460    PortInfo *port = &mPorts.editItemAt(portIndex);
461    CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
462    CHECK(port->mDef.bEnabled == !enable);
463
464    if (!enable) {
465        port->mDef.bEnabled = OMX_FALSE;
466        port->mTransition = PortInfo::DISABLING;
467
468        for (size_t i = 0; i < port->mBuffers.size(); ++i) {
469            BufferInfo *buffer = &port->mBuffers.editItemAt(i);
470
471            if (buffer->mOwnedByUs) {
472                buffer->mOwnedByUs = false;
473
474                if (port->mDef.eDir == OMX_DirInput) {
475                    notifyEmptyBufferDone(buffer->mHeader);
476                } else {
477                    CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
478                    notifyFillBufferDone(buffer->mHeader);
479                }
480            }
481        }
482
483        port->mQueue.clear();
484    } else {
485        port->mTransition = PortInfo::ENABLING;
486    }
487
488    checkTransitions();
489}
490
491void SimpleSoftOMXComponent::onPortFlush(
492        OMX_U32 portIndex, bool sendFlushComplete) {
493    if (portIndex == OMX_ALL) {
494        for (size_t i = 0; i < mPorts.size(); ++i) {
495            onPortFlush(i, sendFlushComplete);
496        }
497
498        if (sendFlushComplete) {
499            notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL);
500        }
501
502        return;
503    }
504
505    CHECK_LT(portIndex, mPorts.size());
506
507    PortInfo *port = &mPorts.editItemAt(portIndex);
508    CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
509
510    for (size_t i = 0; i < port->mBuffers.size(); ++i) {
511        BufferInfo *buffer = &port->mBuffers.editItemAt(i);
512
513        if (!buffer->mOwnedByUs) {
514            continue;
515        }
516
517        buffer->mHeader->nFilledLen = 0;
518        buffer->mHeader->nOffset = 0;
519        buffer->mHeader->nFlags = 0;
520
521        buffer->mOwnedByUs = false;
522
523        if (port->mDef.eDir == OMX_DirInput) {
524            notifyEmptyBufferDone(buffer->mHeader);
525        } else {
526            CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
527
528            notifyFillBufferDone(buffer->mHeader);
529        }
530    }
531
532    port->mQueue.clear();
533
534    if (sendFlushComplete) {
535        notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL);
536
537        onPortFlushCompleted(portIndex);
538    }
539}
540
541void SimpleSoftOMXComponent::checkTransitions() {
542    if (mState != mTargetState) {
543        bool transitionComplete = true;
544
545        if (mState == OMX_StateLoaded) {
546            CHECK_EQ((int)mTargetState, (int)OMX_StateIdle);
547
548            for (size_t i = 0; i < mPorts.size(); ++i) {
549                const PortInfo &port = mPorts.itemAt(i);
550                if (port.mDef.bEnabled == OMX_FALSE) {
551                    continue;
552                }
553
554                if (port.mDef.bPopulated == OMX_FALSE) {
555                    transitionComplete = false;
556                    break;
557                }
558            }
559        } else if (mTargetState == OMX_StateLoaded) {
560            CHECK_EQ((int)mState, (int)OMX_StateIdle);
561
562            for (size_t i = 0; i < mPorts.size(); ++i) {
563                const PortInfo &port = mPorts.itemAt(i);
564                if (port.mDef.bEnabled == OMX_FALSE) {
565                    continue;
566                }
567
568                size_t n = port.mBuffers.size();
569
570                if (n > 0) {
571                    CHECK_LE(n, port.mDef.nBufferCountActual);
572
573                    if (n == port.mDef.nBufferCountActual) {
574                        CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE);
575                    } else {
576                        CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE);
577                    }
578
579                    transitionComplete = false;
580                    break;
581                }
582            }
583        }
584
585        if (transitionComplete) {
586            mState = mTargetState;
587
588            if (mState == OMX_StateLoaded) {
589                onReset();
590            }
591
592            notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL);
593        }
594    }
595
596    for (size_t i = 0; i < mPorts.size(); ++i) {
597        PortInfo *port = &mPorts.editItemAt(i);
598
599        if (port->mTransition == PortInfo::DISABLING) {
600            if (port->mBuffers.empty()) {
601                ALOGV("Port %d now disabled.", i);
602
603                port->mTransition = PortInfo::NONE;
604                notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL);
605
606                onPortEnableCompleted(i, false /* enabled */);
607            }
608        } else if (port->mTransition == PortInfo::ENABLING) {
609            if (port->mDef.bPopulated == OMX_TRUE) {
610                ALOGV("Port %d now enabled.", i);
611
612                port->mTransition = PortInfo::NONE;
613                port->mDef.bEnabled = OMX_TRUE;
614                notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL);
615
616                onPortEnableCompleted(i, true /* enabled */);
617            }
618        }
619    }
620}
621
622void SimpleSoftOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) {
623    CHECK_EQ(def.nPortIndex, mPorts.size());
624
625    mPorts.push();
626    PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1);
627    info->mDef = def;
628    info->mTransition = PortInfo::NONE;
629}
630
631void SimpleSoftOMXComponent::onQueueFilled(OMX_U32 portIndex) {
632}
633
634void SimpleSoftOMXComponent::onPortFlushCompleted(OMX_U32 portIndex) {
635}
636
637void SimpleSoftOMXComponent::onPortEnableCompleted(
638        OMX_U32 portIndex, bool enabled) {
639}
640
641List<SimpleSoftOMXComponent::BufferInfo *> &
642SimpleSoftOMXComponent::getPortQueue(OMX_U32 portIndex) {
643    CHECK_LT(portIndex, mPorts.size());
644    return mPorts.editItemAt(portIndex).mQueue;
645}
646
647SimpleSoftOMXComponent::PortInfo *SimpleSoftOMXComponent::editPortInfo(
648        OMX_U32 portIndex) {
649    CHECK_LT(portIndex, mPorts.size());
650    return &mPorts.editItemAt(portIndex);
651}
652
653}  // namespace android
654