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                    || 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    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::onPortEnable(OMX_U32 portIndex, bool enable) {
454    CHECK_LT(portIndex, mPorts.size());
455
456    PortInfo *port = &mPorts.editItemAt(portIndex);
457    CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
458    CHECK(port->mDef.bEnabled == !enable);
459
460    if (!enable) {
461        port->mDef.bEnabled = OMX_FALSE;
462        port->mTransition = PortInfo::DISABLING;
463
464        for (size_t i = 0; i < port->mBuffers.size(); ++i) {
465            BufferInfo *buffer = &port->mBuffers.editItemAt(i);
466
467            if (buffer->mOwnedByUs) {
468                buffer->mOwnedByUs = false;
469
470                if (port->mDef.eDir == OMX_DirInput) {
471                    notifyEmptyBufferDone(buffer->mHeader);
472                } else {
473                    CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
474                    notifyFillBufferDone(buffer->mHeader);
475                }
476            }
477        }
478
479        port->mQueue.clear();
480    } else {
481        port->mTransition = PortInfo::ENABLING;
482    }
483
484    checkTransitions();
485}
486
487void SimpleSoftOMXComponent::onPortFlush(
488        OMX_U32 portIndex, bool sendFlushComplete) {
489    if (portIndex == OMX_ALL) {
490        for (size_t i = 0; i < mPorts.size(); ++i) {
491            onPortFlush(i, sendFlushComplete);
492        }
493
494        if (sendFlushComplete) {
495            notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL);
496        }
497
498        return;
499    }
500
501    CHECK_LT(portIndex, mPorts.size());
502
503    PortInfo *port = &mPorts.editItemAt(portIndex);
504    CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
505
506    for (size_t i = 0; i < port->mBuffers.size(); ++i) {
507        BufferInfo *buffer = &port->mBuffers.editItemAt(i);
508
509        if (!buffer->mOwnedByUs) {
510            continue;
511        }
512
513        buffer->mHeader->nFilledLen = 0;
514        buffer->mHeader->nOffset = 0;
515        buffer->mHeader->nFlags = 0;
516
517        buffer->mOwnedByUs = false;
518
519        if (port->mDef.eDir == OMX_DirInput) {
520            notifyEmptyBufferDone(buffer->mHeader);
521        } else {
522            CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
523
524            notifyFillBufferDone(buffer->mHeader);
525        }
526    }
527
528    port->mQueue.clear();
529
530    if (sendFlushComplete) {
531        notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL);
532
533        onPortFlushCompleted(portIndex);
534    }
535}
536
537void SimpleSoftOMXComponent::checkTransitions() {
538    if (mState != mTargetState) {
539        bool transitionComplete = true;
540
541        if (mState == OMX_StateLoaded) {
542            CHECK_EQ((int)mTargetState, (int)OMX_StateIdle);
543
544            for (size_t i = 0; i < mPorts.size(); ++i) {
545                const PortInfo &port = mPorts.itemAt(i);
546                if (port.mDef.bEnabled == OMX_FALSE) {
547                    continue;
548                }
549
550                if (port.mDef.bPopulated == OMX_FALSE) {
551                    transitionComplete = false;
552                    break;
553                }
554            }
555        } else if (mTargetState == OMX_StateLoaded) {
556            CHECK_EQ((int)mState, (int)OMX_StateIdle);
557
558            for (size_t i = 0; i < mPorts.size(); ++i) {
559                const PortInfo &port = mPorts.itemAt(i);
560                if (port.mDef.bEnabled == OMX_FALSE) {
561                    continue;
562                }
563
564                size_t n = port.mBuffers.size();
565
566                if (n > 0) {
567                    CHECK_LE(n, port.mDef.nBufferCountActual);
568
569                    if (n == port.mDef.nBufferCountActual) {
570                        CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE);
571                    } else {
572                        CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE);
573                    }
574
575                    transitionComplete = false;
576                    break;
577                }
578            }
579        }
580
581        if (transitionComplete) {
582            mState = mTargetState;
583
584            notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL);
585        }
586    }
587
588    for (size_t i = 0; i < mPorts.size(); ++i) {
589        PortInfo *port = &mPorts.editItemAt(i);
590
591        if (port->mTransition == PortInfo::DISABLING) {
592            if (port->mBuffers.empty()) {
593                ALOGV("Port %d now disabled.", i);
594
595                port->mTransition = PortInfo::NONE;
596                notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL);
597
598                onPortEnableCompleted(i, false /* enabled */);
599            }
600        } else if (port->mTransition == PortInfo::ENABLING) {
601            if (port->mDef.bPopulated == OMX_TRUE) {
602                ALOGV("Port %d now enabled.", i);
603
604                port->mTransition = PortInfo::NONE;
605                port->mDef.bEnabled = OMX_TRUE;
606                notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL);
607
608                onPortEnableCompleted(i, true /* enabled */);
609            }
610        }
611    }
612}
613
614void SimpleSoftOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) {
615    CHECK_EQ(def.nPortIndex, mPorts.size());
616
617    mPorts.push();
618    PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1);
619    info->mDef = def;
620    info->mTransition = PortInfo::NONE;
621}
622
623void SimpleSoftOMXComponent::onQueueFilled(OMX_U32 portIndex) {
624}
625
626void SimpleSoftOMXComponent::onPortFlushCompleted(OMX_U32 portIndex) {
627}
628
629void SimpleSoftOMXComponent::onPortEnableCompleted(
630        OMX_U32 portIndex, bool enabled) {
631}
632
633List<SimpleSoftOMXComponent::BufferInfo *> &
634SimpleSoftOMXComponent::getPortQueue(OMX_U32 portIndex) {
635    CHECK_LT(portIndex, mPorts.size());
636    return mPorts.editItemAt(portIndex).mQueue;
637}
638
639SimpleSoftOMXComponent::PortInfo *SimpleSoftOMXComponent::editPortInfo(
640        OMX_U32 portIndex) {
641    CHECK_LT(portIndex, mPorts.size());
642    return &mPorts.editItemAt(portIndex);
643}
644
645}  // namespace android
646