blob: 179b2a0a9a03f325eb047f49c8a425def2bf83bb [file] [log] [blame]
Andreas Huber4b3913a2011-05-11 14:13:42 -07001/*
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