SimpleSoftOMXComponent.cpp revision 5a65e30064dc8dffa4f3d868f1c46038972c40c5
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            PRIORITY_AUDIO);
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                    || defParams->nSize
157                            != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
158                return OMX_ErrorUndefined;
159            }
160
161            PortInfo *port =
162                &mPorts.editItemAt(defParams->nPortIndex);
163
164            if (defParams->nBufferSize != port->mDef.nBufferSize) {
165                CHECK_GE(defParams->nBufferSize, port->mDef.nBufferSize);
166                port->mDef.nBufferSize = defParams->nBufferSize;
167            }
168
169            if (defParams->nBufferCountActual
170                    != port->mDef.nBufferCountActual) {
171                CHECK_GE(defParams->nBufferCountActual,
172                         port->mDef.nBufferCountMin);
173
174                port->mDef.nBufferCountActual = defParams->nBufferCountActual;
175            }
176
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
337    switch (msg->what()) {
338        case kWhatSendCommand:
339        {
340            int32_t cmd, param;
341            CHECK(msg->findInt32("cmd", &cmd));
342            CHECK(msg->findInt32("param", &param));
343
344            onSendCommand((OMX_COMMANDTYPE)cmd, (OMX_U32)param);
345            break;
346        }
347
348        case kWhatEmptyThisBuffer:
349        case kWhatFillThisBuffer:
350        {
351            OMX_BUFFERHEADERTYPE *header;
352            CHECK(msg->findPointer("header", (void **)&header));
353
354            CHECK(mState == OMX_StateExecuting && mTargetState == mState);
355
356            bool found = false;
357            for (size_t i = 0; i < mPorts.size(); ++i) {
358                PortInfo *port = &mPorts.editItemAt(i);
359
360                for (size_t j = 0; j < port->mBuffers.size(); ++j) {
361                    BufferInfo *buffer = &port->mBuffers.editItemAt(j);
362
363                    if (buffer->mHeader == header) {
364                        CHECK(!buffer->mOwnedByUs);
365
366                        buffer->mOwnedByUs = true;
367
368                        CHECK((msg->what() == kWhatEmptyThisBuffer
369                                    && port->mDef.eDir == OMX_DirInput)
370                                || (port->mDef.eDir == OMX_DirOutput));
371
372                        port->mQueue.push_back(buffer);
373                        onQueueFilled(i);
374
375                        found = true;
376                        break;
377                    }
378                }
379            }
380
381            CHECK(found);
382            break;
383        }
384
385        default:
386            TRESPASS();
387            break;
388    }
389}
390
391void SimpleSoftOMXComponent::onSendCommand(
392        OMX_COMMANDTYPE cmd, OMX_U32 param) {
393    switch (cmd) {
394        case OMX_CommandStateSet:
395        {
396            onChangeState((OMX_STATETYPE)param);
397            break;
398        }
399
400        case OMX_CommandPortEnable:
401        case OMX_CommandPortDisable:
402        {
403            onPortEnable(param, cmd == OMX_CommandPortEnable);
404            break;
405        }
406
407        case OMX_CommandFlush:
408        {
409            onPortFlush(param, true /* sendFlushComplete */);
410            break;
411        }
412
413        default:
414            TRESPASS();
415            break;
416    }
417}
418
419void SimpleSoftOMXComponent::onChangeState(OMX_STATETYPE state) {
420    // We shouldn't be in a state transition already.
421    CHECK_EQ((int)mState, (int)mTargetState);
422
423    switch (mState) {
424        case OMX_StateLoaded:
425            CHECK_EQ((int)state, (int)OMX_StateIdle);
426            break;
427        case OMX_StateIdle:
428            CHECK(state == OMX_StateLoaded || state == OMX_StateExecuting);
429            break;
430        case OMX_StateExecuting:
431        {
432            CHECK_EQ((int)state, (int)OMX_StateIdle);
433
434            for (size_t i = 0; i < mPorts.size(); ++i) {
435                onPortFlush(i, false /* sendFlushComplete */);
436            }
437
438            mState = OMX_StateIdle;
439            notify(OMX_EventCmdComplete, OMX_CommandStateSet, state, NULL);
440            break;
441        }
442
443        default:
444            TRESPASS();
445    }
446
447    mTargetState = state;
448
449    checkTransitions();
450}
451
452void SimpleSoftOMXComponent::onPortEnable(OMX_U32 portIndex, bool enable) {
453    CHECK_LT(portIndex, mPorts.size());
454
455    PortInfo *port = &mPorts.editItemAt(portIndex);
456    CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
457    CHECK(port->mDef.bEnabled == !enable);
458
459    if (!enable) {
460        port->mDef.bEnabled = OMX_FALSE;
461        port->mTransition = PortInfo::DISABLING;
462
463        for (size_t i = 0; i < port->mBuffers.size(); ++i) {
464            BufferInfo *buffer = &port->mBuffers.editItemAt(i);
465
466            if (buffer->mOwnedByUs) {
467                buffer->mOwnedByUs = false;
468
469                if (port->mDef.eDir == OMX_DirInput) {
470                    notifyEmptyBufferDone(buffer->mHeader);
471                } else {
472                    CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
473                    notifyFillBufferDone(buffer->mHeader);
474                }
475            }
476        }
477
478        port->mQueue.clear();
479    } else {
480        port->mTransition = PortInfo::ENABLING;
481    }
482
483    checkTransitions();
484}
485
486void SimpleSoftOMXComponent::onPortFlush(
487        OMX_U32 portIndex, bool sendFlushComplete) {
488    if (portIndex == OMX_ALL) {
489        for (size_t i = 0; i < mPorts.size(); ++i) {
490            onPortFlush(i, sendFlushComplete);
491        }
492
493        if (sendFlushComplete) {
494            notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL);
495        }
496
497        return;
498    }
499
500    CHECK_LT(portIndex, mPorts.size());
501
502    PortInfo *port = &mPorts.editItemAt(portIndex);
503    CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
504
505    for (size_t i = 0; i < port->mBuffers.size(); ++i) {
506        BufferInfo *buffer = &port->mBuffers.editItemAt(i);
507
508        if (!buffer->mOwnedByUs) {
509            continue;
510        }
511
512        buffer->mHeader->nFilledLen = 0;
513        buffer->mHeader->nOffset = 0;
514        buffer->mHeader->nFlags = 0;
515
516        buffer->mOwnedByUs = false;
517
518        if (port->mDef.eDir == OMX_DirInput) {
519            notifyEmptyBufferDone(buffer->mHeader);
520        } else {
521            CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
522
523            notifyFillBufferDone(buffer->mHeader);
524        }
525    }
526
527    port->mQueue.clear();
528
529    if (sendFlushComplete) {
530        notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL);
531
532        onPortFlushCompleted(portIndex);
533    }
534}
535
536void SimpleSoftOMXComponent::checkTransitions() {
537    if (mState != mTargetState) {
538        bool transitionComplete = true;
539
540        if (mState == OMX_StateLoaded) {
541            CHECK_EQ((int)mTargetState, (int)OMX_StateIdle);
542
543            for (size_t i = 0; i < mPorts.size(); ++i) {
544                const PortInfo &port = mPorts.itemAt(i);
545                if (port.mDef.bEnabled == OMX_FALSE) {
546                    continue;
547                }
548
549                if (port.mDef.bPopulated == OMX_FALSE) {
550                    transitionComplete = false;
551                    break;
552                }
553            }
554        } else if (mTargetState == OMX_StateLoaded) {
555            CHECK_EQ((int)mState, (int)OMX_StateIdle);
556
557            for (size_t i = 0; i < mPorts.size(); ++i) {
558                const PortInfo &port = mPorts.itemAt(i);
559                if (port.mDef.bEnabled == OMX_FALSE) {
560                    continue;
561                }
562
563                size_t n = port.mBuffers.size();
564
565                if (n > 0) {
566                    CHECK_LE(n, port.mDef.nBufferCountActual);
567
568                    if (n == port.mDef.nBufferCountActual) {
569                        CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE);
570                    } else {
571                        CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE);
572                    }
573
574                    transitionComplete = false;
575                    break;
576                }
577            }
578        }
579
580        if (transitionComplete) {
581            mState = mTargetState;
582
583            notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL);
584        }
585    }
586
587    for (size_t i = 0; i < mPorts.size(); ++i) {
588        PortInfo *port = &mPorts.editItemAt(i);
589
590        if (port->mTransition == PortInfo::DISABLING) {
591            if (port->mBuffers.empty()) {
592                LOGV("Port %d now disabled.", i);
593
594                port->mTransition = PortInfo::NONE;
595                notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL);
596
597                onPortEnableCompleted(i, false /* enabled */);
598            }
599        } else if (port->mTransition == PortInfo::ENABLING) {
600            if (port->mDef.bPopulated == OMX_TRUE) {
601                LOGV("Port %d now enabled.", i);
602
603                port->mTransition = PortInfo::NONE;
604                port->mDef.bEnabled = OMX_TRUE;
605                notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL);
606
607                onPortEnableCompleted(i, true /* enabled */);
608            }
609        }
610    }
611}
612
613void SimpleSoftOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) {
614    CHECK_EQ(def.nPortIndex, mPorts.size());
615
616    mPorts.push();
617    PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1);
618    info->mDef = def;
619    info->mTransition = PortInfo::NONE;
620}
621
622void SimpleSoftOMXComponent::onQueueFilled(OMX_U32 portIndex) {
623}
624
625void SimpleSoftOMXComponent::onPortFlushCompleted(OMX_U32 portIndex) {
626}
627
628void SimpleSoftOMXComponent::onPortEnableCompleted(
629        OMX_U32 portIndex, bool enabled) {
630}
631
632List<SimpleSoftOMXComponent::BufferInfo *> &
633SimpleSoftOMXComponent::getPortQueue(OMX_U32 portIndex) {
634    CHECK_LT(portIndex, mPorts.size());
635    return mPorts.editItemAt(portIndex).mQueue;
636}
637
638SimpleSoftOMXComponent::PortInfo *SimpleSoftOMXComponent::editPortInfo(
639        OMX_U32 portIndex) {
640    CHECK_LT(portIndex, mPorts.size());
641    return &mPorts.editItemAt(portIndex);
642}
643
644}  // namespace android
645