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