blob: 425227d42d8884ecf99c5cee87db3b778c761009 [file] [log] [blame]
Shalaj Jain65506622013-01-29 18:27:08 -08001/*
2 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
3 * Not a Contribution, Apache license notifications and license are retained
4 * for attribution purposes only.
5 *
6 * Copyright (C) 2010 The Android Open Source Project
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21//#define LOG_NDEBUG 0
22#define LOG_TAG "DashCodec"
23
24#include "DashCodec.h"
25
26#include <binder/MemoryDealer.h>
27
28#include <media/stagefright/foundation/hexdump.h>
29#include <media/stagefright/foundation/ABuffer.h>
30#include <media/stagefright/foundation/ADebug.h>
31#include <media/stagefright/foundation/AMessage.h>
32
33#include <media/stagefright/MediaCodecList.h>
34#include <media/stagefright/MediaDefs.h>
35#include <media/stagefright/NativeWindowWrapper.h>
36#include <media/stagefright/OMXClient.h>
37#include <media/stagefright/OMXCodec.h>
38
39#include <media/hardware/HardwareAPI.h>
40#include <OMX_QCOMExtns.h>
41#include <OMX_Component.h>
42#include <cutils/properties.h>
43#include "avc_utils.h"
44
45//Smmoth streaming settings
46//Max resolution 1080p
47#define MAX_WIDTH 1920;
48#define MAX_HEIGHT 1080;
49
50//Min resolution QVGA
51#define MIN_WIDTH 480;
52#define MIN_HEIGHT 320;
53
54namespace android {
55
56template<class T>
57static void InitOMXParams(T *params) {
58 params->nSize = sizeof(T);
59 params->nVersion.s.nVersionMajor = 1;
60 params->nVersion.s.nVersionMinor = 0;
61 params->nVersion.s.nRevision = 0;
62 params->nVersion.s.nStep = 0;
63}
64
65struct CodecObserver : public BnOMXObserver {
66 CodecObserver() {}
67
68 void setNotificationMessage(const sp<AMessage> &msg) {
69 mNotify = msg;
70 }
71
72 // from IOMXObserver
73 virtual void onMessage(const omx_message &omx_msg) {
74 sp<AMessage> msg = mNotify->dup();
75
76 msg->setInt32("type", omx_msg.type);
77 msg->setPointer("node", omx_msg.node);
78
79 switch (omx_msg.type) {
80 case omx_message::EVENT:
81 {
82 msg->setInt32("event", omx_msg.u.event_data.event);
83 msg->setInt32("data1", omx_msg.u.event_data.data1);
84 msg->setInt32("data2", omx_msg.u.event_data.data2);
85 break;
86 }
87
88 case omx_message::EMPTY_BUFFER_DONE:
89 {
90 msg->setPointer("buffer", omx_msg.u.buffer_data.buffer);
91 break;
92 }
93
94 case omx_message::FILL_BUFFER_DONE:
95 {
96 msg->setPointer(
97 "buffer", omx_msg.u.extended_buffer_data.buffer);
98 msg->setInt32(
99 "range_offset",
100 omx_msg.u.extended_buffer_data.range_offset);
101 msg->setInt32(
102 "range_length",
103 omx_msg.u.extended_buffer_data.range_length);
104 msg->setInt32(
105 "flags",
106 omx_msg.u.extended_buffer_data.flags);
107 msg->setInt64(
108 "timestamp",
109 omx_msg.u.extended_buffer_data.timestamp);
110 msg->setPointer(
111 "platform_private",
112 omx_msg.u.extended_buffer_data.platform_private);
113 msg->setPointer(
114 "data_ptr",
115 omx_msg.u.extended_buffer_data.data_ptr);
116 break;
117 }
118
119 default:
120 TRESPASS();
121 break;
122 }
123
124 msg->post();
125 }
126
127protected:
128 virtual ~CodecObserver() {}
129
130private:
131 sp<AMessage> mNotify;
132
133 DISALLOW_EVIL_CONSTRUCTORS(CodecObserver);
134};
135
136////////////////////////////////////////////////////////////////////////////////
137
138struct DashCodec::BaseState : public AState {
139 BaseState(DashCodec *codec, const sp<AState> &parentState = NULL);
140
141protected:
142 enum PortMode {
143 KEEP_BUFFERS,
144 RESUBMIT_BUFFERS,
145 FREE_BUFFERS,
146 };
147
148 DashCodec *mCodec;
149
150 virtual PortMode getPortMode(OMX_U32 portIndex);
151
152 virtual bool onMessageReceived(const sp<AMessage> &msg);
153
154 virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
155
156 virtual void onOutputBufferDrained(const sp<AMessage> &msg);
157 virtual void onInputBufferFilled(const sp<AMessage> &msg);
158
159 void postFillThisBuffer(BufferInfo *info);
160
161private:
162 bool onOMXMessage(const sp<AMessage> &msg);
163
164 bool onOMXEmptyBufferDone(IOMX::buffer_id bufferID);
165
166 bool onOMXFillBufferDone(
167 IOMX::buffer_id bufferID,
168 size_t rangeOffset, size_t rangeLength,
169 OMX_U32 flags,
170 int64_t timeUs,
171 void *platformPrivate,
172 void *dataPtr);
173
174 void getMoreInputDataIfPossible();
175
176 DISALLOW_EVIL_CONSTRUCTORS(BaseState);
177};
178
179////////////////////////////////////////////////////////////////////////////////
180
181struct DashCodec::UninitializedState : public DashCodec::BaseState {
182 UninitializedState(DashCodec *codec);
183
184protected:
185 virtual bool onMessageReceived(const sp<AMessage> &msg);
186 virtual void stateEntered();
187
188private:
189 void onSetup(const sp<AMessage> &msg);
190 bool onAllocateComponent(const sp<AMessage> &msg);
191
192 DISALLOW_EVIL_CONSTRUCTORS(UninitializedState);
193};
194
195////////////////////////////////////////////////////////////////////////////////
196
197struct DashCodec::LoadedState : public DashCodec::BaseState {
198 LoadedState(DashCodec *codec);
199
200protected:
201 virtual bool onMessageReceived(const sp<AMessage> &msg);
202 virtual void stateEntered();
203
204private:
205 friend struct DashCodec::UninitializedState;
206
207 bool onConfigureComponent(const sp<AMessage> &msg);
208 void onStart();
209 void onShutdown(bool keepComponentAllocated);
210
211 DISALLOW_EVIL_CONSTRUCTORS(LoadedState);
212};
213
214////////////////////////////////////////////////////////////////////////////////
215
216struct DashCodec::LoadedToIdleState : public DashCodec::BaseState {
217 LoadedToIdleState(DashCodec *codec);
218
219protected:
220 virtual bool onMessageReceived(const sp<AMessage> &msg);
221 virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
222 virtual void stateEntered();
223
224private:
225 status_t allocateBuffers();
226
227 DISALLOW_EVIL_CONSTRUCTORS(LoadedToIdleState);
228};
229
230////////////////////////////////////////////////////////////////////////////////
231
232struct DashCodec::IdleToExecutingState : public DashCodec::BaseState {
233 IdleToExecutingState(DashCodec *codec);
234
235protected:
236 virtual bool onMessageReceived(const sp<AMessage> &msg);
237 virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
238 virtual void stateEntered();
239
240private:
241 DISALLOW_EVIL_CONSTRUCTORS(IdleToExecutingState);
242};
243
244////////////////////////////////////////////////////////////////////////////////
245
246struct DashCodec::ExecutingState : public DashCodec::BaseState {
247 ExecutingState(DashCodec *codec);
248
249 void submitOutputBuffers();
250
251 // Submit output buffers to the decoder, submit input buffers to client
252 // to fill with data.
253 void resume();
254
255 // Returns true iff input and output buffers are in play.
256 bool active() const { return mActive; }
257
258protected:
259 virtual PortMode getPortMode(OMX_U32 portIndex);
260 virtual bool onMessageReceived(const sp<AMessage> &msg);
261 virtual void stateEntered();
262
263 virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
264
265private:
266 bool mActive;
267
268 DISALLOW_EVIL_CONSTRUCTORS(ExecutingState);
269};
270
271////////////////////////////////////////////////////////////////////////////////
272
273struct DashCodec::OutputPortSettingsChangedState : public DashCodec::BaseState {
274 OutputPortSettingsChangedState(DashCodec *codec);
275
276protected:
277 virtual PortMode getPortMode(OMX_U32 portIndex);
278 virtual bool onMessageReceived(const sp<AMessage> &msg);
279 virtual void stateEntered();
280
281 virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
282
283private:
284 DISALLOW_EVIL_CONSTRUCTORS(OutputPortSettingsChangedState);
285};
286
287////////////////////////////////////////////////////////////////////////////////
288
289struct DashCodec::ExecutingToIdleState : public DashCodec::BaseState {
290 ExecutingToIdleState(DashCodec *codec);
291
292protected:
293 virtual bool onMessageReceived(const sp<AMessage> &msg);
294 virtual void stateEntered();
295
296 virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
297
298 virtual void onOutputBufferDrained(const sp<AMessage> &msg);
299 virtual void onInputBufferFilled(const sp<AMessage> &msg);
300
301private:
302 void changeStateIfWeOwnAllBuffers();
303
304 bool mComponentNowIdle;
305
306 DISALLOW_EVIL_CONSTRUCTORS(ExecutingToIdleState);
307};
308
309////////////////////////////////////////////////////////////////////////////////
310
311struct DashCodec::IdleToLoadedState : public DashCodec::BaseState {
312 IdleToLoadedState(DashCodec *codec);
313
314protected:
315 virtual bool onMessageReceived(const sp<AMessage> &msg);
316 virtual void stateEntered();
317
318 virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
319
320private:
321 DISALLOW_EVIL_CONSTRUCTORS(IdleToLoadedState);
322};
323
324////////////////////////////////////////////////////////////////////////////////
325
326struct DashCodec::FlushingState : public DashCodec::BaseState {
327 FlushingState(DashCodec *codec);
328
329protected:
330 virtual bool onMessageReceived(const sp<AMessage> &msg);
331 virtual void stateEntered();
332
333 virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
334
335 virtual void onOutputBufferDrained(const sp<AMessage> &msg);
336 virtual void onInputBufferFilled(const sp<AMessage> &msg);
337
338private:
339 bool mFlushComplete[2];
340
341 void changeStateIfWeOwnAllBuffers();
342
343 DISALLOW_EVIL_CONSTRUCTORS(FlushingState);
344};
345
346////////////////////////////////////////////////////////////////////////////////
347
348struct DashCodec::FlushingOutputState : public DashCodec::BaseState {
349 FlushingOutputState(DashCodec *codec);
350
351protected:
352 virtual PortMode getPortMode(OMX_U32 portIndex);
353 virtual bool onMessageReceived(const sp<AMessage> &msg);
354 virtual void stateEntered();
355
356 virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
357
358 virtual void onOutputBufferDrained(const sp<AMessage> &msg);
359 virtual void onInputBufferFilled(const sp<AMessage> &msg);
360
361private:
362 bool mFlushComplete;
363
364 void changeStateIfWeOwnAllBuffers();
365
366 DISALLOW_EVIL_CONSTRUCTORS(FlushingOutputState);
367};
368
369////////////////////////////////////////////////////////////////////////////////
370
371DashCodec::DashCodec()
372 : mQuirks(0),
373 mNode(NULL),
374 mSentFormat(false),
Eric (Quicb4042f02013-04-17 11:00:01 -0700375 mPostFormat(false),
Shalaj Jain65506622013-01-29 18:27:08 -0800376 mIsEncoder(false),
377 mShutdownInProgress(false),
378 mEncoderDelay(0),
379 mEncoderPadding(0),
380 mChannelMaskPresent(false),
381 mChannelMask(0),
382 mSmoothStreaming(false) {
383 mUninitializedState = new UninitializedState(this);
384 mLoadedState = new LoadedState(this);
385 mLoadedToIdleState = new LoadedToIdleState(this);
386 mIdleToExecutingState = new IdleToExecutingState(this);
387 mExecutingState = new ExecutingState(this);
388
389 mOutputPortSettingsChangedState =
390 new OutputPortSettingsChangedState(this);
391
392 mExecutingToIdleState = new ExecutingToIdleState(this);
393 mIdleToLoadedState = new IdleToLoadedState(this);
394 mFlushingState = new FlushingState(this);
395 mFlushingOutputState = new FlushingOutputState(this);
396
397 mPortEOS[kPortIndexInput] = mPortEOS[kPortIndexOutput] = false;
398 mInputEOSResult = OK;
399
400 changeState(mUninitializedState);
401}
402
403DashCodec::~DashCodec() {
Surajit Poddercd444a12013-08-05 15:43:22 +0530404 clearCachedFormats();
Shalaj Jain65506622013-01-29 18:27:08 -0800405}
406
407void DashCodec::setNotificationMessage(const sp<AMessage> &msg) {
408 mNotify = msg;
409}
410
411void DashCodec::initiateSetup(const sp<AMessage> &msg) {
412 msg->setWhat(kWhatSetup);
413 msg->setTarget(id());
414 msg->post();
415}
416
417void DashCodec::initiateAllocateComponent(const sp<AMessage> &msg) {
418 msg->setWhat(kWhatAllocateComponent);
419 msg->setTarget(id());
420 msg->post();
421}
422
423void DashCodec::initiateConfigureComponent(const sp<AMessage> &msg) {
424 msg->setWhat(kWhatConfigureComponent);
425 msg->setTarget(id());
426 msg->post();
427}
428
429void DashCodec::initiateStart() {
430 (new AMessage(kWhatStart, id()))->post();
431}
432
433void DashCodec::signalFlush() {
434 ALOGV("[%s] signalFlush", mComponentName.c_str());
435 (new AMessage(kWhatFlush, id()))->post();
436}
437
438void DashCodec::signalResume() {
439 (new AMessage(kWhatResume, id()))->post();
440}
441
442void DashCodec::initiateShutdown(bool keepComponentAllocated) {
443 sp<AMessage> msg = new AMessage(kWhatShutdown, id());
444 msg->setInt32("keepComponentAllocated", keepComponentAllocated);
445 msg->post();
446}
447
448void DashCodec::signalRequestIDRFrame() {
449 (new AMessage(kWhatRequestIDRFrame, id()))->post();
450}
451
452status_t DashCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
453 CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
454
455 CHECK(mDealer[portIndex] == NULL);
456 CHECK(mBuffers[portIndex].isEmpty());
457
458 status_t err;
459 if (mNativeWindow != NULL && portIndex == kPortIndexOutput) {
460 err = allocateOutputBuffersFromNativeWindow();
461 } else {
462 OMX_PARAM_PORTDEFINITIONTYPE def;
463 InitOMXParams(&def);
464 def.nPortIndex = portIndex;
465
466 err = mOMX->getParameter(
467 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
468
469 if (err == OK) {
470 ALOGV("[%s] Allocating %lu buffers of size %lu on %s port",
471 mComponentName.c_str(),
472 def.nBufferCountActual, def.nBufferSize,
473 portIndex == kPortIndexInput ? "input" : "output");
474
475 size_t totalSize = def.nBufferCountActual * def.nBufferSize;
476 mDealer[portIndex] = new MemoryDealer(totalSize, "DashCodec");
477
478 for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
479 sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
480 CHECK(mem.get() != NULL);
481
482 BufferInfo info;
483 info.mStatus = BufferInfo::OWNED_BY_US;
484
485 uint32_t requiresAllocateBufferBit =
486 (portIndex == kPortIndexInput)
487 ? OMXCodec::kRequiresAllocateBufferOnInputPorts
488 : OMXCodec::kRequiresAllocateBufferOnOutputPorts;
489
490 if (portIndex == kPortIndexInput && (mFlags & kFlagIsSecure)) {
491 mem.clear();
492
493 void *ptr;
494 err = mOMX->allocateBuffer(
495 mNode, portIndex, def.nBufferSize, &info.mBufferID,
496 &ptr);
497
498 info.mData = new ABuffer(ptr, def.nBufferSize);
499 } else if (mQuirks & requiresAllocateBufferBit) {
500 err = mOMX->allocateBufferWithBackup(
501 mNode, portIndex, mem, &info.mBufferID);
502 } else {
503 err = mOMX->useBuffer(mNode, portIndex, mem, &info.mBufferID);
504 }
505
506 if (mem != NULL) {
507 info.mData = new ABuffer(mem->pointer(), def.nBufferSize);
508 }
509
510 mBuffers[portIndex].push(info);
511 }
512 }
513 }
514
515 if (err != OK) {
516 return err;
517 }
518
519 sp<AMessage> notify = mNotify->dup();
520 notify->setInt32("what", DashCodec::kWhatBuffersAllocated);
521
522 notify->setInt32("portIndex", portIndex);
523
524 sp<PortDescription> desc = new PortDescription;
525
526 for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
527 const BufferInfo &info = mBuffers[portIndex][i];
528
529 desc->addBuffer(info.mBufferID, info.mData);
530 }
531
532 notify->setObject("portDesc", desc);
533 notify->post();
534
535 return OK;
536}
537
538status_t DashCodec::allocateOutputBuffersFromNativeWindow() {
539 OMX_PARAM_PORTDEFINITIONTYPE def;
540 InitOMXParams(&def);
541 def.nPortIndex = kPortIndexOutput;
542
543 status_t err = mOMX->getParameter(
544 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
545
546 if (err != OK) {
547 return err;
548 }
549
550 err = native_window_set_buffers_geometry(
551 mNativeWindow.get(),
552 def.format.video.nFrameWidth,
553 def.format.video.nFrameHeight,
554 def.format.video.eColorFormat);
555
556 if (err != 0) {
557 ALOGE("native_window_set_buffers_geometry failed: %s (%d)",
558 strerror(-err), -err);
559 return err;
560 }
561
562 // Set up the native window.
563 OMX_U32 usage = 0;
564 err = mOMX->getGraphicBufferUsage(mNode, kPortIndexOutput, &usage);
565 if (err != 0) {
566 ALOGW("querying usage flags from OMX IL component failed: %d", err);
567 // XXX: Currently this error is logged, but not fatal.
568 usage = 0;
569 }
570
Surajit Podder46ad8f12013-05-03 15:13:42 +0530571 if (mFlags & kFlagIsSecure || mFlags & kFlagIsSecureOPOnly) {
Shalaj Jain65506622013-01-29 18:27:08 -0800572 usage |= GRALLOC_USAGE_PROTECTED;
573 }
574
575 // Make sure to check whether either Stagefright or the video decoder
576 // requested protected buffers.
577 if (usage & GRALLOC_USAGE_PROTECTED) {
578 // Verify that the ANativeWindow sends images directly to
579 // SurfaceFlinger.
580 int queuesToNativeWindow = 0;
581 err = mNativeWindow->query(
582 mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
583 &queuesToNativeWindow);
584 if (err != 0) {
585 ALOGE("error authenticating native window: %d", err);
586 return err;
587 }
588 if (queuesToNativeWindow != 1) {
589 ALOGE("native window could not be authenticated");
590 return PERMISSION_DENIED;
591 }
592 }
593
594 err = native_window_set_usage(
595 mNativeWindow.get(),
596 usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
597
598 if (err != 0) {
599 ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
600 return err;
601 }
602
603 int minUndequeuedBufs = 0;
604 err = mNativeWindow->query(
605 mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
606 &minUndequeuedBufs);
607
608 if (err != 0) {
609 ALOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)",
610 strerror(-err), -err);
611 return err;
612 }
613
Surajit Podder68069b92013-04-29 10:43:03 +0530614 // XXX: Is this the right logic to use? It's not clear to me what the OMX
615 // buffer counts refer to - how do they account for the renderer holding on
616 // to buffers?
617 if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) {
618 OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs;
619 def.nBufferCountActual = newBufferCount;
620
621 //Keep an extra buffer for smooth streaming
622 if (mSmoothStreaming) {
623 def.nBufferCountActual += 1;
624 }
625
626 err = mOMX->setParameter(
627 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
628
629 if (err != OK) {
630 ALOGE("[%s] setting nBufferCountActual to %lu failed: %d",
631 mComponentName.c_str(), newBufferCount, err);
632 return err;
633 }
634 }
635
636
Shalaj Jain65506622013-01-29 18:27:08 -0800637 err = native_window_set_buffer_count(
638 mNativeWindow.get(), def.nBufferCountActual);
639
640 if (err != 0) {
641 ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),
642 -err);
643 return err;
644 }
645
646 ALOGV("[%s] Allocating %lu buffers from a native window of size %lu on "
647 "output port",
648 mComponentName.c_str(), def.nBufferCountActual, def.nBufferSize);
649
650 // Dequeue buffers and send them to OMX
651 for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
652 ANativeWindowBuffer *buf;
653 err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf);
654 if (err != 0) {
655 ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
656 break;
657 }
658
659 sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(buf, false));
660 BufferInfo info;
661 info.mStatus = BufferInfo::OWNED_BY_US;
662 info.mData = new ABuffer(0);
663 info.mGraphicBuffer = graphicBuffer;
664 mBuffers[kPortIndexOutput].push(info);
665
666 IOMX::buffer_id bufferId;
667 err = mOMX->useGraphicBuffer(mNode, kPortIndexOutput, graphicBuffer,
668 &bufferId);
669 if (err != 0) {
670 ALOGE("registering GraphicBuffer %lu with OMX IL component failed: "
671 "%d", i, err);
672 break;
673 }
674
675 mBuffers[kPortIndexOutput].editItemAt(i).mBufferID = bufferId;
676
677 ALOGV("[%s] Registered graphic buffer with ID %p (pointer = %p)",
678 mComponentName.c_str(),
679 bufferId, graphicBuffer.get());
680 }
681
682 OMX_U32 cancelStart;
683 OMX_U32 cancelEnd;
684
685 if (err != 0) {
686 // If an error occurred while dequeuing we need to cancel any buffers
687 // that were dequeued.
688 cancelStart = 0;
689 cancelEnd = mBuffers[kPortIndexOutput].size();
690 } else {
691 // Return the last two buffers to the native window.
692 cancelStart = def.nBufferCountActual - minUndequeuedBufs;
693 cancelEnd = def.nBufferCountActual;
694 }
695
696 for (OMX_U32 i = cancelStart; i < cancelEnd; i++) {
697 BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);
698 cancelBufferToNativeWindow(info);
699 }
700
701 return err;
702}
703
704status_t DashCodec::cancelBufferToNativeWindow(BufferInfo *info) {
705 CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
706
707 ALOGV("[%s] Calling cancelBuffer on buffer %p",
708 mComponentName.c_str(), info->mBufferID);
709
710 int err = mNativeWindow->cancelBuffer(
711 mNativeWindow.get(), info->mGraphicBuffer.get(), -1);
712
713 CHECK_EQ(err, 0);
714
715 info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
716
717 return OK;
718}
719
720DashCodec::BufferInfo *DashCodec::dequeueBufferFromNativeWindow() {
721 ANativeWindowBuffer *buf;
722 int fenceFd = -1;
723 if (native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf) != 0) {
724 ALOGE("dequeueBuffer failed.");
725 return NULL;
726 }
727
728 for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
729 BufferInfo *info =
730 &mBuffers[kPortIndexOutput].editItemAt(i);
731
732 if (info->mGraphicBuffer->handle == buf->handle) {
733 CHECK_EQ((int)info->mStatus,
734 (int)BufferInfo::OWNED_BY_NATIVE_WINDOW);
735
736 info->mStatus = BufferInfo::OWNED_BY_US;
737
738 return info;
739 }
740 }
741
742 TRESPASS();
743
744 return NULL;
745}
746
747status_t DashCodec::freeBuffersOnPort(OMX_U32 portIndex) {
748 for (size_t i = mBuffers[portIndex].size(); i-- > 0;) {
749 CHECK_EQ((status_t)OK, freeBuffer(portIndex, i));
750 }
751
752 mDealer[portIndex].clear();
753
754 return OK;
755}
756
757status_t DashCodec::freeOutputBuffersNotOwnedByComponent() {
758 for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
759 BufferInfo *info =
760 &mBuffers[kPortIndexOutput].editItemAt(i);
761
762 if (info->mStatus !=
763 BufferInfo::OWNED_BY_COMPONENT) {
764 // We shouldn't have sent out any buffers to the client at this
765 // point.
766 CHECK_NE((int)info->mStatus, (int)BufferInfo::OWNED_BY_DOWNSTREAM);
767
768 CHECK_EQ((status_t)OK, freeBuffer(kPortIndexOutput, i));
769 }
770 }
771
772 return OK;
773}
774
775status_t DashCodec::freeBuffer(OMX_U32 portIndex, size_t i) {
776 BufferInfo *info = &mBuffers[portIndex].editItemAt(i);
777
778 CHECK(info->mStatus == BufferInfo::OWNED_BY_US
779 || info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW);
780
781 if (portIndex == kPortIndexOutput && mNativeWindow != NULL
782 && info->mStatus == BufferInfo::OWNED_BY_US) {
783 CHECK_EQ((status_t)OK, cancelBufferToNativeWindow(info));
784 }
785
786 CHECK_EQ(mOMX->freeBuffer(
787 mNode, portIndex, info->mBufferID),
788 (status_t)OK);
789
790 mBuffers[portIndex].removeAt(i);
791
792 return OK;
793}
794
795DashCodec::BufferInfo *DashCodec::findBufferByID(
796 uint32_t portIndex, IOMX::buffer_id bufferID,
797 ssize_t *index) {
798 for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
799 BufferInfo *info = &mBuffers[portIndex].editItemAt(i);
800
801 if (info->mBufferID == bufferID) {
802 if (index != NULL) {
803 *index = i;
804 }
805 return info;
806 }
807 }
808
809 TRESPASS();
810
811 return NULL;
812}
813
814status_t DashCodec::setComponentRole(
815 bool isEncoder, const char *mime) {
816 struct MimeToRole {
817 const char *mime;
818 const char *decoderRole;
819 const char *encoderRole;
820 };
821
822 static const MimeToRole kMimeToRole[] = {
823 { MEDIA_MIMETYPE_AUDIO_MPEG,
824 "audio_decoder.mp3", "audio_encoder.mp3" },
825 { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
826 "audio_decoder.mp1", "audio_encoder.mp1" },
827 { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
828 "audio_decoder.mp2", "audio_encoder.mp2" },
829 { MEDIA_MIMETYPE_AUDIO_AMR_NB,
830 "audio_decoder.amrnb", "audio_encoder.amrnb" },
831 { MEDIA_MIMETYPE_AUDIO_AMR_WB,
832 "audio_decoder.amrwb", "audio_encoder.amrwb" },
Sudhir Sharma3cfecd62013-07-17 15:01:24 -0700833 // commenting out AMR_WM_PLUS for bringing up dash on MR2
834 /* { MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
835 "audio_decoder.amrwbplus", "audio_encoder.amrwbplus" }, */
Shalaj Jain65506622013-01-29 18:27:08 -0800836 { MEDIA_MIMETYPE_AUDIO_AAC,
837 "audio_decoder.aac", "audio_encoder.aac" },
838 { MEDIA_MIMETYPE_AUDIO_VORBIS,
839 "audio_decoder.vorbis", "audio_encoder.vorbis" },
840 { MEDIA_MIMETYPE_AUDIO_G711_MLAW,
841 "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" },
842 { MEDIA_MIMETYPE_AUDIO_G711_ALAW,
843 "audio_decoder.g711alaw", "audio_encoder.g711alaw" },
844 { MEDIA_MIMETYPE_VIDEO_AVC,
845 "video_decoder.avc", "video_encoder.avc" },
846 { MEDIA_MIMETYPE_VIDEO_MPEG4,
847 "video_decoder.mpeg4", "video_encoder.mpeg4" },
848 { MEDIA_MIMETYPE_VIDEO_H263,
849 "video_decoder.h263", "video_encoder.h263" },
850 { MEDIA_MIMETYPE_VIDEO_VPX,
851 "video_decoder.vpx", "video_encoder.vpx" },
852 { MEDIA_MIMETYPE_AUDIO_RAW,
853 "audio_decoder.raw", "audio_encoder.raw" },
854 { MEDIA_MIMETYPE_AUDIO_FLAC,
855 "audio_decoder.flac", "audio_encoder.flac" },
856 };
857
858 static const size_t kNumMimeToRole =
859 sizeof(kMimeToRole) / sizeof(kMimeToRole[0]);
860
861 size_t i;
862 for (i = 0; i < kNumMimeToRole; ++i) {
863 if (!strcasecmp(mime, kMimeToRole[i].mime)) {
864 break;
865 }
866 }
867
868 if (i == kNumMimeToRole) {
869 return ERROR_UNSUPPORTED;
870 }
871
872 const char *role =
873 isEncoder ? kMimeToRole[i].encoderRole
874 : kMimeToRole[i].decoderRole;
875
876 if (role != NULL) {
877 OMX_PARAM_COMPONENTROLETYPE roleParams;
878 InitOMXParams(&roleParams);
879
880 strncpy((char *)roleParams.cRole,
881 role, OMX_MAX_STRINGNAME_SIZE - 1);
882
883 roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
884
885 status_t err = mOMX->setParameter(
886 mNode, OMX_IndexParamStandardComponentRole,
887 &roleParams, sizeof(roleParams));
888
889 if (err != OK) {
890 ALOGW("[%s] Failed to set standard component role '%s'.",
891 mComponentName.c_str(), role);
892
893 return err;
894 }
895 }
896
897 return OK;
898}
899
900status_t DashCodec::configureCodec(
901 const char *mime, const sp<AMessage> &msg) {
902 int32_t encoder;
903 if (!msg->findInt32("encoder", &encoder)) {
904 encoder = false;
905 }
906
907 mIsEncoder = encoder;
908
909 status_t err = setComponentRole(encoder /* isEncoder */, mime);
910
911 if (err != OK) {
912 return err;
913 }
914
915 int32_t bitRate = 0;
916 // FLAC encoder doesn't need a bitrate, other encoders do
917 if (encoder && strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)
918 && !msg->findInt32("bitrate", &bitRate)) {
919 return INVALID_OPERATION;
920 }
921
922 int32_t storeMeta;
923 if (encoder
924 && msg->findInt32("store-metadata-in-buffers", &storeMeta)
925 && storeMeta != 0) {
926 err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE);
927
928 if (err != OK) {
929 ALOGE("[%s] storeMetaDataInBuffers failed w/ err %d",
930 mComponentName.c_str(), err);
931
932 return err;
933 }
934 }
935
936 int32_t prependSPSPPS;
937 if (encoder
938 && msg->findInt32("prepend-sps-pps-to-idr-frames", &prependSPSPPS)
939 && prependSPSPPS != 0) {
940 OMX_INDEXTYPE index;
941 err = mOMX->getExtensionIndex(
942 mNode,
943 "OMX.google.android.index.prependSPSPPSToIDRFrames",
944 &index);
945
946 if (err == OK) {
947 PrependSPSPPSToIDRFramesParams params;
948 InitOMXParams(&params);
949 params.bEnable = OMX_TRUE;
950
951 err = mOMX->setParameter(
952 mNode, index, &params, sizeof(params));
953 }
954
955 if (err != OK) {
956 ALOGE("Encoder could not be configured to emit SPS/PPS before "
957 "IDR frames. (err %d)", err);
958
959 return err;
960 }
961 }
962
963 if (!strncasecmp(mime, "video/", 6)) {
964 if (encoder) {
965 err = setupVideoEncoder(mime, msg);
966 } else {
967 int32_t width, height;
968 if (!msg->findInt32("width", &width)
969 || !msg->findInt32("height", &height)) {
970 err = INVALID_OPERATION;
971 } else {
972 //override height & width with max for smooth streaming
973 if (mSmoothStreaming) {
974 width = MAX_WIDTH;
975 height = MAX_HEIGHT;
976 }
977 err = setupVideoDecoder(mime, width, height);
978 }
979 }
980 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
981 int32_t numChannels, sampleRate;
982 if (!msg->findInt32("channel-count", &numChannels)
983 || !msg->findInt32("sample-rate", &sampleRate)) {
984 err = INVALID_OPERATION;
985 } else {
986 int32_t isADTS, aacProfile;
987 if (!msg->findInt32("is-adts", &isADTS)) {
988 isADTS = 0;
989 }
990 if (!msg->findInt32("aac-profile", &aacProfile)) {
991 aacProfile = OMX_AUDIO_AACObjectNull;
992 }
993
994 err = setupAACCodec(
995 encoder, numChannels, sampleRate, bitRate, aacProfile, isADTS != 0);
996 }
997 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
998 err = setupAMRCodec(encoder, false /* isWAMR */, bitRate);
999 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
1000 err = setupAMRCodec(encoder, true /* isWAMR */, bitRate);
1001 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_ALAW)
1002 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_MLAW)) {
1003 // These are PCM-like formats with a fixed sample rate but
1004 // a variable number of channels.
1005
1006 int32_t numChannels;
1007 if (!msg->findInt32("channel-count", &numChannels)) {
1008 err = INVALID_OPERATION;
1009 } else {
1010 err = setupG711Codec(encoder, numChannels);
1011 }
1012 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
1013 int32_t numChannels, sampleRate, compressionLevel = -1;
1014 if (encoder &&
1015 (!msg->findInt32("channel-count", &numChannels)
1016 || !msg->findInt32("sample-rate", &sampleRate))) {
1017 ALOGE("missing channel count or sample rate for FLAC encoder");
1018 err = INVALID_OPERATION;
1019 } else {
1020 if (encoder) {
1021 if (!msg->findInt32("flac-compression-level", &compressionLevel)) {
1022 compressionLevel = 5;// default FLAC compression level
1023 } else if (compressionLevel < 0) {
1024 ALOGW("compression level %d outside [0..8] range, using 0", compressionLevel);
1025 compressionLevel = 0;
1026 } else if (compressionLevel > 8) {
1027 ALOGW("compression level %d outside [0..8] range, using 8", compressionLevel);
1028 compressionLevel = 8;
1029 }
1030 }
1031 err = setupFlacCodec(encoder, numChannels, sampleRate, compressionLevel);
1032 }
1033 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
1034 int32_t numChannels, sampleRate;
1035 if (encoder
1036 || !msg->findInt32("channel-count", &numChannels)
1037 || !msg->findInt32("sample-rate", &sampleRate)) {
1038 err = INVALID_OPERATION;
1039 } else {
1040 err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1041 }
1042 }
1043
1044 if (!msg->findInt32("encoder-delay", &mEncoderDelay)) {
1045 mEncoderDelay = 0;
1046 }
1047
1048 if (!msg->findInt32("encoder-padding", &mEncoderPadding)) {
1049 mEncoderPadding = 0;
1050 }
1051
1052 if (msg->findInt32("channel-mask", &mChannelMask)) {
1053 mChannelMaskPresent = true;
1054 } else {
1055 mChannelMaskPresent = false;
1056 }
1057
1058 int32_t maxInputSize;
1059 if (msg->findInt32("max-input-size", &maxInputSize)) {
1060 err = setMinBufferSize(kPortIndexInput, (size_t)maxInputSize);
1061 } else if (!strcmp("OMX.Nvidia.aac.decoder", mComponentName.c_str())) {
1062 err = setMinBufferSize(kPortIndexInput, 8192); // XXX
1063 }
1064
1065 return err;
1066}
1067
1068status_t DashCodec::setMinBufferSize(OMX_U32 portIndex, size_t size) {
1069 OMX_PARAM_PORTDEFINITIONTYPE def;
1070 InitOMXParams(&def);
1071 def.nPortIndex = portIndex;
1072
1073 status_t err = mOMX->getParameter(
1074 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1075
1076 if (err != OK) {
1077 return err;
1078 }
1079
1080 if (def.nBufferSize >= size) {
1081 return OK;
1082 }
1083
1084 def.nBufferSize = size;
1085
1086 err = mOMX->setParameter(
1087 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1088
1089 if (err != OK) {
1090 return err;
1091 }
1092
1093 err = mOMX->getParameter(
1094 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1095
1096 if (err != OK) {
1097 return err;
1098 }
1099
1100 CHECK(def.nBufferSize >= size);
1101
1102 return OK;
1103}
1104
1105status_t DashCodec::selectAudioPortFormat(
1106 OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE desiredFormat) {
1107 OMX_AUDIO_PARAM_PORTFORMATTYPE format;
1108 InitOMXParams(&format);
1109
1110 format.nPortIndex = portIndex;
1111 for (OMX_U32 index = 0;; ++index) {
1112 format.nIndex = index;
1113
1114 status_t err = mOMX->getParameter(
1115 mNode, OMX_IndexParamAudioPortFormat,
1116 &format, sizeof(format));
1117
1118 if (err != OK) {
1119 return err;
1120 }
1121
1122 if (format.eEncoding == desiredFormat) {
1123 break;
1124 }
1125 }
1126
1127 return mOMX->setParameter(
1128 mNode, OMX_IndexParamAudioPortFormat, &format, sizeof(format));
1129}
1130
1131status_t DashCodec::setupAACCodec(
1132 bool encoder, int32_t numChannels, int32_t sampleRate,
1133 int32_t bitRate, int32_t aacProfile, bool isADTS) {
1134 if (encoder && isADTS) {
1135 return -EINVAL;
1136 }
1137
1138 status_t err = setupRawAudioFormat(
1139 encoder ? kPortIndexInput : kPortIndexOutput,
1140 sampleRate,
1141 numChannels);
1142
1143 if (err != OK) {
1144 return err;
1145 }
1146
1147 if (encoder) {
1148 err = selectAudioPortFormat(kPortIndexOutput, OMX_AUDIO_CodingAAC);
1149
1150 if (err != OK) {
1151 return err;
1152 }
1153
1154 OMX_PARAM_PORTDEFINITIONTYPE def;
1155 InitOMXParams(&def);
1156 def.nPortIndex = kPortIndexOutput;
1157
1158 err = mOMX->getParameter(
1159 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1160
1161 if (err != OK) {
1162 return err;
1163 }
1164
1165 def.format.audio.bFlagErrorConcealment = OMX_TRUE;
1166 def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
1167
1168 err = mOMX->setParameter(
1169 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1170
1171 if (err != OK) {
1172 return err;
1173 }
1174
1175 OMX_AUDIO_PARAM_AACPROFILETYPE profile;
1176 InitOMXParams(&profile);
1177 profile.nPortIndex = kPortIndexOutput;
1178
1179 err = mOMX->getParameter(
1180 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1181
1182 if (err != OK) {
1183 return err;
1184 }
1185
1186 profile.nChannels = numChannels;
1187
1188 profile.eChannelMode =
1189 (numChannels == 1)
1190 ? OMX_AUDIO_ChannelModeMono: OMX_AUDIO_ChannelModeStereo;
1191
1192 profile.nSampleRate = sampleRate;
1193 profile.nBitRate = bitRate;
1194 profile.nAudioBandWidth = 0;
1195 profile.nFrameLength = 0;
1196 profile.nAACtools = OMX_AUDIO_AACToolAll;
1197 profile.nAACERtools = OMX_AUDIO_AACERNone;
1198 profile.eAACProfile = (OMX_AUDIO_AACPROFILETYPE) aacProfile;
1199 profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
1200
1201 err = mOMX->setParameter(
1202 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1203
1204 if (err != OK) {
1205 return err;
1206 }
1207
1208 return err;
1209 }
1210
1211 OMX_AUDIO_PARAM_AACPROFILETYPE profile;
1212 InitOMXParams(&profile);
1213 profile.nPortIndex = kPortIndexInput;
1214
1215 err = mOMX->getParameter(
1216 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1217
1218 if (err != OK) {
1219 return err;
1220 }
1221
1222 profile.nChannels = numChannels;
1223 profile.nSampleRate = sampleRate;
1224
1225 profile.eAACStreamFormat =
1226 isADTS
1227 ? OMX_AUDIO_AACStreamFormatMP4ADTS
1228 : OMX_AUDIO_AACStreamFormatMP4FF;
1229
1230 return mOMX->setParameter(
1231 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1232}
1233
1234static OMX_AUDIO_AMRBANDMODETYPE pickModeFromBitRate(
1235 bool isAMRWB, int32_t bps) {
1236 if (isAMRWB) {
1237 if (bps <= 6600) {
1238 return OMX_AUDIO_AMRBandModeWB0;
1239 } else if (bps <= 8850) {
1240 return OMX_AUDIO_AMRBandModeWB1;
1241 } else if (bps <= 12650) {
1242 return OMX_AUDIO_AMRBandModeWB2;
1243 } else if (bps <= 14250) {
1244 return OMX_AUDIO_AMRBandModeWB3;
1245 } else if (bps <= 15850) {
1246 return OMX_AUDIO_AMRBandModeWB4;
1247 } else if (bps <= 18250) {
1248 return OMX_AUDIO_AMRBandModeWB5;
1249 } else if (bps <= 19850) {
1250 return OMX_AUDIO_AMRBandModeWB6;
1251 } else if (bps <= 23050) {
1252 return OMX_AUDIO_AMRBandModeWB7;
1253 }
1254
1255 // 23850 bps
1256 return OMX_AUDIO_AMRBandModeWB8;
1257 } else { // AMRNB
1258 if (bps <= 4750) {
1259 return OMX_AUDIO_AMRBandModeNB0;
1260 } else if (bps <= 5150) {
1261 return OMX_AUDIO_AMRBandModeNB1;
1262 } else if (bps <= 5900) {
1263 return OMX_AUDIO_AMRBandModeNB2;
1264 } else if (bps <= 6700) {
1265 return OMX_AUDIO_AMRBandModeNB3;
1266 } else if (bps <= 7400) {
1267 return OMX_AUDIO_AMRBandModeNB4;
1268 } else if (bps <= 7950) {
1269 return OMX_AUDIO_AMRBandModeNB5;
1270 } else if (bps <= 10200) {
1271 return OMX_AUDIO_AMRBandModeNB6;
1272 }
1273
1274 // 12200 bps
1275 return OMX_AUDIO_AMRBandModeNB7;
1276 }
1277}
1278
1279status_t DashCodec::setupAMRCodec(bool encoder, bool isWAMR, int32_t bitrate) {
1280 OMX_AUDIO_PARAM_AMRTYPE def;
1281 InitOMXParams(&def);
1282 def.nPortIndex = encoder ? kPortIndexOutput : kPortIndexInput;
1283
1284 status_t err =
1285 mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1286
1287 if (err != OK) {
1288 return err;
1289 }
1290
1291 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1292 def.eAMRBandMode = pickModeFromBitRate(isWAMR, bitrate);
1293
1294 err = mOMX->setParameter(
1295 mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1296
1297 if (err != OK) {
1298 return err;
1299 }
1300
1301 return setupRawAudioFormat(
1302 encoder ? kPortIndexInput : kPortIndexOutput,
1303 isWAMR ? 16000 : 8000 /* sampleRate */,
1304 1 /* numChannels */);
1305}
1306
1307status_t DashCodec::setupG711Codec(bool encoder, int32_t numChannels) {
1308 CHECK(!encoder); // XXX TODO
1309
1310 return setupRawAudioFormat(
1311 kPortIndexInput, 8000 /* sampleRate */, numChannels);
1312}
1313
1314status_t DashCodec::setupFlacCodec(
1315 bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel) {
1316
1317 if (encoder) {
1318 OMX_AUDIO_PARAM_FLACTYPE def;
1319 InitOMXParams(&def);
1320 def.nPortIndex = kPortIndexOutput;
1321
1322 // configure compression level
1323 status_t err = mOMX->getParameter(mNode, OMX_IndexParamAudioFlac, &def, sizeof(def));
1324 if (err != OK) {
1325 ALOGE("setupFlacCodec(): Error %d getting OMX_IndexParamAudioFlac parameter", err);
1326 return err;
1327 }
1328 def.nCompressionLevel = compressionLevel;
1329 err = mOMX->setParameter(mNode, OMX_IndexParamAudioFlac, &def, sizeof(def));
1330 if (err != OK) {
1331 ALOGE("setupFlacCodec(): Error %d setting OMX_IndexParamAudioFlac parameter", err);
1332 return err;
1333 }
1334 }
1335
1336 return setupRawAudioFormat(
1337 encoder ? kPortIndexInput : kPortIndexOutput,
1338 sampleRate,
1339 numChannels);
1340}
1341
1342status_t DashCodec::setupRawAudioFormat(
1343 OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
1344 OMX_PARAM_PORTDEFINITIONTYPE def;
1345 InitOMXParams(&def);
1346 def.nPortIndex = portIndex;
1347
1348 status_t err = mOMX->getParameter(
1349 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1350
1351 if (err != OK) {
1352 return err;
1353 }
1354
1355 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
1356
1357 err = mOMX->setParameter(
1358 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1359
1360 if (err != OK) {
1361 return err;
1362 }
1363
1364 OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
1365 InitOMXParams(&pcmParams);
1366 pcmParams.nPortIndex = portIndex;
1367
1368 err = mOMX->getParameter(
1369 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1370
1371 if (err != OK) {
1372 return err;
1373 }
1374
1375 pcmParams.nChannels = numChannels;
1376 pcmParams.eNumData = OMX_NumericalDataSigned;
1377 pcmParams.bInterleaved = OMX_TRUE;
1378 pcmParams.nBitPerSample = 16;
1379 pcmParams.nSamplingRate = sampleRate;
1380 pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
1381
1382 if (getOMXChannelMapping(numChannels, pcmParams.eChannelMapping) != OK) {
1383 return OMX_ErrorNone;
1384 }
1385
1386 return mOMX->setParameter(
1387 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1388}
1389
1390status_t DashCodec::setVideoPortFormatType(
1391 OMX_U32 portIndex,
1392 OMX_VIDEO_CODINGTYPE compressionFormat,
1393 OMX_COLOR_FORMATTYPE colorFormat) {
1394 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
1395 InitOMXParams(&format);
1396 format.nPortIndex = portIndex;
1397 format.nIndex = 0;
1398 bool found = false;
1399
1400 OMX_U32 index = 0;
1401 for (;;) {
1402 format.nIndex = index;
1403 status_t err = mOMX->getParameter(
1404 mNode, OMX_IndexParamVideoPortFormat,
1405 &format, sizeof(format));
1406
1407 if (err != OK) {
1408 return err;
1409 }
1410
1411 // The following assertion is violated by TI's video decoder.
1412 // CHECK_EQ(format.nIndex, index);
1413
1414 if (!strcmp("OMX.TI.Video.encoder", mComponentName.c_str())) {
1415 if (portIndex == kPortIndexInput
1416 && colorFormat == format.eColorFormat) {
1417 // eCompressionFormat does not seem right.
1418 found = true;
1419 break;
1420 }
1421 if (portIndex == kPortIndexOutput
1422 && compressionFormat == format.eCompressionFormat) {
1423 // eColorFormat does not seem right.
1424 found = true;
1425 break;
1426 }
1427 }
1428
1429 if (format.eCompressionFormat == compressionFormat
1430 && format.eColorFormat == colorFormat) {
1431 found = true;
1432 break;
1433 }
1434
1435 ++index;
1436 }
1437
1438 if (!found) {
1439 return UNKNOWN_ERROR;
1440 }
1441
1442 status_t err = mOMX->setParameter(
1443 mNode, OMX_IndexParamVideoPortFormat,
1444 &format, sizeof(format));
1445
1446 return err;
1447}
1448
1449status_t DashCodec::setSupportedOutputFormat() {
1450 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
1451 InitOMXParams(&format);
1452 format.nPortIndex = kPortIndexOutput;
1453 format.nIndex = 0;
1454
1455 status_t err = mOMX->getParameter(
1456 mNode, OMX_IndexParamVideoPortFormat,
1457 &format, sizeof(format));
1458 CHECK_EQ(err, (status_t)OK);
1459 CHECK_EQ((int)format.eCompressionFormat, (int)OMX_VIDEO_CodingUnused);
1460
1461 CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
1462 || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
1463 || format.eColorFormat == OMX_COLOR_FormatCbYCrY
1464 || format.eColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
1465 || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
1466 || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka
Sudhir Sharma3cfecd62013-07-17 15:01:24 -07001467 || format.eColorFormat == (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m
1468 );
Shalaj Jain65506622013-01-29 18:27:08 -08001469
1470 return mOMX->setParameter(
1471 mNode, OMX_IndexParamVideoPortFormat,
1472 &format, sizeof(format));
1473}
1474
1475static status_t GetVideoCodingTypeFromMime(
1476 const char *mime, OMX_VIDEO_CODINGTYPE *codingType) {
1477 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
1478 *codingType = OMX_VIDEO_CodingAVC;
1479 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
1480 *codingType = OMX_VIDEO_CodingMPEG4;
1481 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
1482 *codingType = OMX_VIDEO_CodingH263;
1483 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG2, mime)) {
1484 *codingType = OMX_VIDEO_CodingMPEG2;
1485 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_VPX, mime)) {
1486 *codingType = OMX_VIDEO_CodingVPX;
1487 } else {
1488 *codingType = OMX_VIDEO_CodingUnused;
1489 return ERROR_UNSUPPORTED;
1490 }
1491
1492 return OK;
1493}
1494
1495status_t DashCodec::setupVideoDecoder(
1496 const char *mime, int32_t width, int32_t height) {
1497 OMX_VIDEO_CODINGTYPE compressionFormat;
1498 status_t err = GetVideoCodingTypeFromMime(mime, &compressionFormat);
1499
1500 if (err != OK) {
1501 return err;
1502 }
1503
1504 err = setVideoPortFormatType(
1505 kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
1506
1507 if (err != OK) {
1508 return err;
1509 }
1510
1511 err = setSupportedOutputFormat();
1512
1513 if (err != OK) {
1514 return err;
1515 }
1516
1517 err = setVideoFormatOnPort(
1518 kPortIndexInput, width, height, compressionFormat);
1519
1520 if (err != OK) {
1521 return err;
1522 }
1523
1524 err = setVideoFormatOnPort(
1525 kPortIndexOutput, width, height, OMX_VIDEO_CodingUnused);
1526
1527 if (err != OK) {
1528 return err;
1529 }
1530
1531 return OK;
1532}
1533
1534status_t DashCodec::setupVideoEncoder(const char *mime, const sp<AMessage> &msg) {
1535 int32_t tmp;
1536 if (!msg->findInt32("color-format", &tmp)) {
1537 return INVALID_OPERATION;
1538 }
1539
1540 OMX_COLOR_FORMATTYPE colorFormat =
1541 static_cast<OMX_COLOR_FORMATTYPE>(tmp);
1542
1543 status_t err = setVideoPortFormatType(
1544 kPortIndexInput, OMX_VIDEO_CodingUnused, colorFormat);
1545
1546 if (err != OK) {
1547 ALOGE("[%s] does not support color format %d",
1548 mComponentName.c_str(), colorFormat);
1549
1550 return err;
1551 }
1552
1553 /* Input port configuration */
1554
1555 OMX_PARAM_PORTDEFINITIONTYPE def;
1556 InitOMXParams(&def);
1557
1558 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
1559
1560 def.nPortIndex = kPortIndexInput;
1561
1562 err = mOMX->getParameter(
1563 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1564
1565 if (err != OK) {
1566 return err;
1567 }
1568
1569 int32_t width, height, bitrate;
1570 if (!msg->findInt32("width", &width)
1571 || !msg->findInt32("height", &height)
1572 || !msg->findInt32("bitrate", &bitrate)) {
1573 return INVALID_OPERATION;
1574 }
1575
1576 video_def->nFrameWidth = width;
1577 video_def->nFrameHeight = height;
1578
1579 int32_t stride;
1580 if (!msg->findInt32("stride", &stride)) {
1581 stride = width;
1582 }
1583
1584 video_def->nStride = stride;
1585
1586 int32_t sliceHeight;
1587 if (!msg->findInt32("slice-height", &sliceHeight)) {
1588 sliceHeight = height;
1589 }
1590
1591 video_def->nSliceHeight = sliceHeight;
1592
1593 def.nBufferSize = (video_def->nStride * video_def->nSliceHeight * 3) / 2;
1594
1595 float frameRate;
1596 if (!msg->findFloat("frame-rate", &frameRate)) {
1597 int32_t tmp;
1598 if (!msg->findInt32("frame-rate", &tmp)) {
1599 return INVALID_OPERATION;
1600 }
1601 frameRate = (float)tmp;
1602 }
1603
1604 video_def->xFramerate = (OMX_U32)(frameRate * 65536.0f);
1605 video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
1606 video_def->eColorFormat = colorFormat;
1607
1608 err = mOMX->setParameter(
1609 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1610
1611 if (err != OK) {
1612 ALOGE("[%s] failed to set input port definition parameters.",
1613 mComponentName.c_str());
1614
1615 return err;
1616 }
1617
1618 /* Output port configuration */
1619
1620 OMX_VIDEO_CODINGTYPE compressionFormat;
1621 err = GetVideoCodingTypeFromMime(mime, &compressionFormat);
1622
1623 if (err != OK) {
1624 return err;
1625 }
1626
1627 err = setVideoPortFormatType(
1628 kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
1629
1630 if (err != OK) {
1631 ALOGE("[%s] does not support compression format %d",
1632 mComponentName.c_str(), compressionFormat);
1633
1634 return err;
1635 }
1636
1637 def.nPortIndex = kPortIndexOutput;
1638
1639 err = mOMX->getParameter(
1640 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1641
1642 if (err != OK) {
1643 return err;
1644 }
1645
1646 video_def->nFrameWidth = width;
1647 video_def->nFrameHeight = height;
1648 video_def->xFramerate = 0;
1649 video_def->nBitrate = bitrate;
1650 video_def->eCompressionFormat = compressionFormat;
1651 video_def->eColorFormat = OMX_COLOR_FormatUnused;
1652
1653 err = mOMX->setParameter(
1654 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1655
1656 if (err != OK) {
1657 ALOGE("[%s] failed to set output port definition parameters.",
1658 mComponentName.c_str());
1659
1660 return err;
1661 }
1662
1663 switch (compressionFormat) {
1664 case OMX_VIDEO_CodingMPEG4:
1665 err = setupMPEG4EncoderParameters(msg);
1666 break;
1667
1668 case OMX_VIDEO_CodingH263:
1669 err = setupH263EncoderParameters(msg);
1670 break;
1671
1672 case OMX_VIDEO_CodingAVC:
1673 err = setupAVCEncoderParameters(msg);
1674 break;
1675
1676 default:
1677 break;
1678 }
1679
1680 ALOGI("setupVideoEncoder succeeded");
1681
1682 return err;
1683}
1684
1685static OMX_U32 setPFramesSpacing(int32_t iFramesInterval, int32_t frameRate) {
1686 if (iFramesInterval < 0) {
1687 return 0xFFFFFFFF;
1688 } else if (iFramesInterval == 0) {
1689 return 0;
1690 }
1691 OMX_U32 ret = frameRate * iFramesInterval;
1692 CHECK(ret > 1);
1693 return ret;
1694}
1695
1696static OMX_VIDEO_CONTROLRATETYPE getBitrateMode(const sp<AMessage> &msg) {
1697 int32_t tmp;
1698 if (!msg->findInt32("bitrate-mode", &tmp)) {
1699 return OMX_Video_ControlRateVariable;
1700 }
1701
1702 return static_cast<OMX_VIDEO_CONTROLRATETYPE>(tmp);
1703}
1704
1705status_t DashCodec::setupMPEG4EncoderParameters(const sp<AMessage> &msg) {
1706 int32_t bitrate, iFrameInterval;
1707 if (!msg->findInt32("bitrate", &bitrate)
1708 || !msg->findInt32("i-frame-interval", &iFrameInterval)) {
1709 return INVALID_OPERATION;
1710 }
1711
1712 OMX_VIDEO_CONTROLRATETYPE bitrateMode = getBitrateMode(msg);
1713
1714 float frameRate;
1715 if (!msg->findFloat("frame-rate", &frameRate)) {
1716 int32_t tmp;
1717 if (!msg->findInt32("frame-rate", &tmp)) {
1718 return INVALID_OPERATION;
1719 }
1720 frameRate = (float)tmp;
1721 }
1722
1723 OMX_VIDEO_PARAM_MPEG4TYPE mpeg4type;
1724 InitOMXParams(&mpeg4type);
1725 mpeg4type.nPortIndex = kPortIndexOutput;
1726
1727 status_t err = mOMX->getParameter(
1728 mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
1729
1730 if (err != OK) {
1731 return err;
1732 }
1733
1734 mpeg4type.nSliceHeaderSpacing = 0;
1735 mpeg4type.bSVH = OMX_FALSE;
1736 mpeg4type.bGov = OMX_FALSE;
1737
1738 mpeg4type.nAllowedPictureTypes =
1739 OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
1740
1741 mpeg4type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate);
1742 if (mpeg4type.nPFrames == 0) {
1743 mpeg4type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
1744 }
1745 mpeg4type.nBFrames = 0;
1746 mpeg4type.nIDCVLCThreshold = 0;
1747 mpeg4type.bACPred = OMX_TRUE;
1748 mpeg4type.nMaxPacketSize = 256;
1749 mpeg4type.nTimeIncRes = 1000;
1750 mpeg4type.nHeaderExtension = 0;
1751 mpeg4type.bReversibleVLC = OMX_FALSE;
1752
1753 int32_t profile;
1754 if (msg->findInt32("profile", &profile)) {
1755 int32_t level;
1756 if (!msg->findInt32("level", &level)) {
1757 return INVALID_OPERATION;
1758 }
1759
1760 err = verifySupportForProfileAndLevel(profile, level);
1761
1762 if (err != OK) {
1763 return err;
1764 }
1765
1766 mpeg4type.eProfile = static_cast<OMX_VIDEO_MPEG4PROFILETYPE>(profile);
1767 mpeg4type.eLevel = static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(level);
1768 }
1769
1770 err = mOMX->setParameter(
1771 mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
1772
1773 if (err != OK) {
1774 return err;
1775 }
1776
1777 err = configureBitrate(bitrate, bitrateMode);
1778
1779 if (err != OK) {
1780 return err;
1781 }
1782
1783 return setupErrorCorrectionParameters();
1784}
1785
1786status_t DashCodec::setupH263EncoderParameters(const sp<AMessage> &msg) {
1787 int32_t bitrate, iFrameInterval;
1788 if (!msg->findInt32("bitrate", &bitrate)
1789 || !msg->findInt32("i-frame-interval", &iFrameInterval)) {
1790 return INVALID_OPERATION;
1791 }
1792
1793 OMX_VIDEO_CONTROLRATETYPE bitrateMode = getBitrateMode(msg);
1794
1795 float frameRate;
1796 if (!msg->findFloat("frame-rate", &frameRate)) {
1797 int32_t tmp;
1798 if (!msg->findInt32("frame-rate", &tmp)) {
1799 return INVALID_OPERATION;
1800 }
1801 frameRate = (float)tmp;
1802 }
1803
1804 OMX_VIDEO_PARAM_H263TYPE h263type;
1805 InitOMXParams(&h263type);
1806 h263type.nPortIndex = kPortIndexOutput;
1807
1808 status_t err = mOMX->getParameter(
1809 mNode, OMX_IndexParamVideoH263, &h263type, sizeof(h263type));
1810
1811 if (err != OK) {
1812 return err;
1813 }
1814
1815 h263type.nAllowedPictureTypes =
1816 OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
1817
1818 h263type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate);
1819 if (h263type.nPFrames == 0) {
1820 h263type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
1821 }
1822 h263type.nBFrames = 0;
1823
1824 int32_t profile;
1825 if (msg->findInt32("profile", &profile)) {
1826 int32_t level;
1827 if (!msg->findInt32("level", &level)) {
1828 return INVALID_OPERATION;
1829 }
1830
1831 err = verifySupportForProfileAndLevel(profile, level);
1832
1833 if (err != OK) {
1834 return err;
1835 }
1836
1837 h263type.eProfile = static_cast<OMX_VIDEO_H263PROFILETYPE>(profile);
1838 h263type.eLevel = static_cast<OMX_VIDEO_H263LEVELTYPE>(level);
1839 }
1840
1841 h263type.bPLUSPTYPEAllowed = OMX_FALSE;
1842 h263type.bForceRoundingTypeToZero = OMX_FALSE;
1843 h263type.nPictureHeaderRepetition = 0;
1844 h263type.nGOBHeaderInterval = 0;
1845
1846 err = mOMX->setParameter(
1847 mNode, OMX_IndexParamVideoH263, &h263type, sizeof(h263type));
1848
1849 if (err != OK) {
1850 return err;
1851 }
1852
1853 err = configureBitrate(bitrate, bitrateMode);
1854
1855 if (err != OK) {
1856 return err;
1857 }
1858
1859 return setupErrorCorrectionParameters();
1860}
1861
1862status_t DashCodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
1863 int32_t bitrate, iFrameInterval;
1864 if (!msg->findInt32("bitrate", &bitrate)
1865 || !msg->findInt32("i-frame-interval", &iFrameInterval)) {
1866 return INVALID_OPERATION;
1867 }
1868
1869 OMX_VIDEO_CONTROLRATETYPE bitrateMode = getBitrateMode(msg);
1870
1871 float frameRate;
1872 if (!msg->findFloat("frame-rate", &frameRate)) {
1873 int32_t tmp;
1874 if (!msg->findInt32("frame-rate", &tmp)) {
1875 return INVALID_OPERATION;
1876 }
1877 frameRate = (float)tmp;
1878 }
1879
1880 OMX_VIDEO_PARAM_AVCTYPE h264type;
1881 InitOMXParams(&h264type);
1882 h264type.nPortIndex = kPortIndexOutput;
1883
1884 status_t err = mOMX->getParameter(
1885 mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
1886
1887 if (err != OK) {
1888 return err;
1889 }
1890
1891 h264type.nAllowedPictureTypes =
1892 OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
1893
1894 int32_t profile;
1895 if (msg->findInt32("profile", &profile)) {
1896 int32_t level;
1897 if (!msg->findInt32("level", &level)) {
1898 return INVALID_OPERATION;
1899 }
1900
1901 err = verifySupportForProfileAndLevel(profile, level);
1902
1903 if (err != OK) {
1904 return err;
1905 }
1906
1907 h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile);
1908 h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(level);
1909 }
1910
1911 // XXX
1912 if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) {
1913 ALOGW("Use baseline profile instead of %d for AVC recording",
1914 h264type.eProfile);
1915 h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
1916 }
1917
1918 if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) {
1919 h264type.nSliceHeaderSpacing = 0;
1920 h264type.bUseHadamard = OMX_TRUE;
1921 h264type.nRefFrames = 1;
1922 h264type.nBFrames = 0;
1923 h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate);
1924 if (h264type.nPFrames == 0) {
1925 h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
1926 }
1927 h264type.nRefIdx10ActiveMinus1 = 0;
1928 h264type.nRefIdx11ActiveMinus1 = 0;
1929 h264type.bEntropyCodingCABAC = OMX_FALSE;
1930 h264type.bWeightedPPrediction = OMX_FALSE;
1931 h264type.bconstIpred = OMX_FALSE;
1932 h264type.bDirect8x8Inference = OMX_FALSE;
1933 h264type.bDirectSpatialTemporal = OMX_FALSE;
1934 h264type.nCabacInitIdc = 0;
1935 }
1936
1937 if (h264type.nBFrames != 0) {
1938 h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
1939 }
1940
1941 h264type.bEnableUEP = OMX_FALSE;
1942 h264type.bEnableFMO = OMX_FALSE;
1943 h264type.bEnableASO = OMX_FALSE;
1944 h264type.bEnableRS = OMX_FALSE;
1945 h264type.bFrameMBsOnly = OMX_TRUE;
1946 h264type.bMBAFF = OMX_FALSE;
1947 h264type.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable;
1948
1949 err = mOMX->setParameter(
1950 mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
1951
1952 if (err != OK) {
1953 return err;
1954 }
1955
1956 return configureBitrate(bitrate, bitrateMode);
1957}
1958
1959status_t DashCodec::verifySupportForProfileAndLevel(
1960 int32_t profile, int32_t level) {
1961 OMX_VIDEO_PARAM_PROFILELEVELTYPE params;
1962 InitOMXParams(&params);
1963 params.nPortIndex = kPortIndexOutput;
1964
1965 for (params.nProfileIndex = 0;; ++params.nProfileIndex) {
1966 status_t err = mOMX->getParameter(
1967 mNode,
1968 OMX_IndexParamVideoProfileLevelQuerySupported,
1969 &params,
1970 sizeof(params));
1971
1972 if (err != OK) {
1973 return err;
1974 }
1975
1976 int32_t supportedProfile = static_cast<int32_t>(params.eProfile);
1977 int32_t supportedLevel = static_cast<int32_t>(params.eLevel);
1978
1979 if (profile == supportedProfile && level <= supportedLevel) {
1980 return OK;
1981 }
1982 }
1983}
1984
1985status_t DashCodec::configureBitrate(
1986 int32_t bitrate, OMX_VIDEO_CONTROLRATETYPE bitrateMode) {
1987 OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
1988 InitOMXParams(&bitrateType);
1989 bitrateType.nPortIndex = kPortIndexOutput;
1990
1991 status_t err = mOMX->getParameter(
1992 mNode, OMX_IndexParamVideoBitrate,
1993 &bitrateType, sizeof(bitrateType));
1994
1995 if (err != OK) {
1996 return err;
1997 }
1998
1999 bitrateType.eControlRate = bitrateMode;
2000 bitrateType.nTargetBitrate = bitrate;
2001
2002 return mOMX->setParameter(
2003 mNode, OMX_IndexParamVideoBitrate,
2004 &bitrateType, sizeof(bitrateType));
2005}
2006
2007status_t DashCodec::setupErrorCorrectionParameters() {
2008 OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE errorCorrectionType;
2009 InitOMXParams(&errorCorrectionType);
2010 errorCorrectionType.nPortIndex = kPortIndexOutput;
2011
2012 status_t err = mOMX->getParameter(
2013 mNode, OMX_IndexParamVideoErrorCorrection,
2014 &errorCorrectionType, sizeof(errorCorrectionType));
2015
2016 if (err != OK) {
2017 return OK; // Optional feature. Ignore this failure
2018 }
2019
2020 errorCorrectionType.bEnableHEC = OMX_FALSE;
2021 errorCorrectionType.bEnableResync = OMX_TRUE;
2022 errorCorrectionType.nResynchMarkerSpacing = 256;
2023 errorCorrectionType.bEnableDataPartitioning = OMX_FALSE;
2024 errorCorrectionType.bEnableRVLC = OMX_FALSE;
2025
2026 return mOMX->setParameter(
2027 mNode, OMX_IndexParamVideoErrorCorrection,
2028 &errorCorrectionType, sizeof(errorCorrectionType));
2029}
2030
2031status_t DashCodec::setVideoFormatOnPort(
2032 OMX_U32 portIndex,
2033 int32_t width, int32_t height, OMX_VIDEO_CODINGTYPE compressionFormat) {
2034 OMX_PARAM_PORTDEFINITIONTYPE def;
2035 InitOMXParams(&def);
2036 def.nPortIndex = portIndex;
2037
2038 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
2039
2040 status_t err = mOMX->getParameter(
2041 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2042
2043 CHECK_EQ(err, (status_t)OK);
2044
2045 if (portIndex == kPortIndexInput) {
2046 // XXX Need a (much) better heuristic to compute input buffer sizes.
2047 const size_t X = 64 * 1024;
2048 if (def.nBufferSize < X) {
2049 def.nBufferSize = X;
2050 }
2051 }
2052
2053 CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainVideo);
2054
2055 video_def->nFrameWidth = width;
2056 video_def->nFrameHeight = height;
2057
2058 if (portIndex == kPortIndexInput) {
2059 video_def->eCompressionFormat = compressionFormat;
2060 video_def->eColorFormat = OMX_COLOR_FormatUnused;
2061 }
2062
2063 err = mOMX->setParameter(
2064 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2065
2066 return err;
2067}
2068
2069status_t DashCodec::initNativeWindow() {
2070 if (mNativeWindow != NULL) {
2071 return mOMX->enableGraphicBuffers(mNode, kPortIndexOutput, OMX_TRUE);
2072 }
2073
2074 mOMX->enableGraphicBuffers(mNode, kPortIndexOutput, OMX_FALSE);
2075 return OK;
2076}
2077
2078size_t DashCodec::countBuffersOwnedByComponent(OMX_U32 portIndex) const {
2079 size_t n = 0;
2080
2081 for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
2082 const BufferInfo &info = mBuffers[portIndex].itemAt(i);
2083
2084 if (info.mStatus == BufferInfo::OWNED_BY_COMPONENT) {
2085 ++n;
2086 }
2087 }
2088
2089 return n;
2090}
2091
2092bool DashCodec::allYourBuffersAreBelongToUs(
2093 OMX_U32 portIndex) {
2094 for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
2095 BufferInfo *info = &mBuffers[portIndex].editItemAt(i);
2096
2097 if (info->mStatus != BufferInfo::OWNED_BY_US
2098 && info->mStatus != BufferInfo::OWNED_BY_NATIVE_WINDOW) {
2099 ALOGV("[%s] Buffer %p on port %ld still has status %d",
2100 mComponentName.c_str(),
2101 info->mBufferID, portIndex, info->mStatus);
2102 return false;
2103 }
2104 }
2105
2106 return true;
2107}
2108
2109bool DashCodec::allYourBuffersAreBelongToUs() {
2110 return allYourBuffersAreBelongToUs(kPortIndexInput)
2111 && allYourBuffersAreBelongToUs(kPortIndexOutput);
2112}
2113
2114void DashCodec::deferMessage(const sp<AMessage> &msg) {
2115 bool wasEmptyBefore = mDeferredQueue.empty();
2116 mDeferredQueue.push_back(msg);
2117}
2118
2119void DashCodec::processDeferredMessages() {
2120 List<sp<AMessage> > queue = mDeferredQueue;
2121 mDeferredQueue.clear();
2122
2123 List<sp<AMessage> >::iterator it = queue.begin();
2124 while (it != queue.end()) {
2125 onMessageReceived(*it++);
2126 }
2127}
2128
Eric (Quicb4042f02013-04-17 11:00:01 -07002129void DashCodec::queueNextFormat() {
2130 OMX_PARAM_PORTDEFINITIONTYPE* def = new OMX_PARAM_PORTDEFINITIONTYPE();
2131 InitOMXParams(def);
2132 def->nPortIndex = kPortIndexOutput;
2133
2134 CHECK_EQ(mOMX->getParameter(
2135 mNode, OMX_IndexParamPortDefinition, def, sizeof(*def)),
2136 (status_t)OK);
2137
2138 CHECK_EQ((int)def->eDir, (int)OMX_DirOutput);
2139 mFormats.push_back(def);
2140
2141 OMX_CONFIG_RECTTYPE* rect = new OMX_CONFIG_RECTTYPE();
2142 InitOMXParams(rect);
2143 rect->nPortIndex = kPortIndexOutput;
2144 if (mOMX->getConfig(mNode, OMX_IndexConfigCommonOutputCrop, rect, sizeof(*rect)) != OK) {
2145 mOutputCrops.push_back(NULL);
2146 } else {
2147 mOutputCrops.push_back(rect);
2148 }
2149}
2150
2151void DashCodec::clearCachedFormats() {
2152 mOutputCrops.clear();
2153 mFormats.clear();
2154}
2155
Shalaj Jain65506622013-01-29 18:27:08 -08002156void DashCodec::sendFormatChange() {
2157 sp<AMessage> notify = mNotify->dup();
2158 notify->setInt32("what", kWhatOutputFormatChanged);
Eric (Quicb4042f02013-04-17 11:00:01 -07002159 bool useCachedConfig = false;
2160 OMX_PARAM_PORTDEFINITIONTYPE* def;
2161 if (mFormats.size() > 0) {
2162 useCachedConfig = true;
2163 def = mFormats[0];
Surajit Poddercd444a12013-08-05 15:43:22 +05302164 mFormats.removeAt(0);
Eric (Quicb4042f02013-04-17 11:00:01 -07002165 } else {
2166 def = new OMX_PARAM_PORTDEFINITIONTYPE();
2167 InitOMXParams(def);
2168 def->nPortIndex = kPortIndexOutput;
Shalaj Jain65506622013-01-29 18:27:08 -08002169
Eric (Quicb4042f02013-04-17 11:00:01 -07002170 CHECK_EQ(mOMX->getParameter(
2171 mNode, OMX_IndexParamPortDefinition, def, sizeof(*def)),
2172 (status_t)OK);
Shalaj Jain65506622013-01-29 18:27:08 -08002173
Eric (Quicb4042f02013-04-17 11:00:01 -07002174 CHECK_EQ((int)def->eDir, (int)OMX_DirOutput);
2175 }
2176 switch (def->eDomain) {
Shalaj Jain65506622013-01-29 18:27:08 -08002177 case OMX_PortDomainVideo:
2178 {
Eric (Quicb4042f02013-04-17 11:00:01 -07002179 OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def->format.video;
Shalaj Jain65506622013-01-29 18:27:08 -08002180
2181 notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RAW);
2182 notify->setInt32("width", videoDef->nFrameWidth);
2183 notify->setInt32("height", videoDef->nFrameHeight);
2184 notify->setInt32("stride", videoDef->nStride);
2185 notify->setInt32("slice-height", videoDef->nSliceHeight);
2186 notify->setInt32("color-format", videoDef->eColorFormat);
Eric (Quicb4042f02013-04-17 11:00:01 -07002187 ALOGE("sendformatchange: %d %d", videoDef->nFrameWidth, videoDef->nFrameHeight);
2188 OMX_CONFIG_RECTTYPE* rect;
2189 bool hasValidCrop = true;
2190 if (useCachedConfig) {
2191 rect = mOutputCrops[0];
Surajit Poddercd444a12013-08-05 15:43:22 +05302192 mOutputCrops.removeAt(0);
Eric (Quicb4042f02013-04-17 11:00:01 -07002193 if (rect == NULL) {
2194 rect = new OMX_CONFIG_RECTTYPE();
2195 hasValidCrop = false;
2196 }
2197 } else {
2198 rect = new OMX_CONFIG_RECTTYPE();
2199 InitOMXParams(rect);
2200 rect->nPortIndex = kPortIndexOutput;
2201 hasValidCrop = (mOMX->getConfig(
2202 mNode, OMX_IndexConfigCommonOutputCrop,
2203 rect, sizeof(*rect)) == OK);
Shalaj Jain65506622013-01-29 18:27:08 -08002204 }
2205
Eric (Quicb4042f02013-04-17 11:00:01 -07002206 if (!hasValidCrop) {
2207 rect->nLeft = 0;
2208 rect->nTop = 0;
2209 rect->nWidth = videoDef->nFrameWidth;
2210 rect->nHeight = videoDef->nFrameHeight;
2211 }
2212
2213 CHECK_GE(rect->nLeft, 0);
2214 CHECK_GE(rect->nTop, 0);
2215 CHECK_GE(rect->nWidth, 0u);
2216 CHECK_GE(rect->nHeight, 0u);
2217 CHECK_LE(rect->nLeft + rect->nWidth - 1, videoDef->nFrameWidth);
2218 CHECK_LE(rect->nTop + rect->nHeight - 1, videoDef->nFrameHeight);
Shalaj Jain65506622013-01-29 18:27:08 -08002219
2220 if( mSmoothStreaming ) {
2221 //call Update buffer geometry here
2222 ALOGE("Calling native window update buffer geometry");
2223 status_t err = mNativeWindow.get()->perform(mNativeWindow.get(),
2224 NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY,
Eric (Quicb4042f02013-04-17 11:00:01 -07002225 videoDef->nFrameWidth, videoDef->nFrameHeight, def->format.video.eColorFormat);
Shalaj Jain65506622013-01-29 18:27:08 -08002226 if( err != OK ) {
2227 ALOGE("native_window_update_buffers_geometry failed in SS mode %d", err);
2228 }
2229
2230 }
2231
2232 notify->setRect(
2233 "crop",
Eric (Quicb4042f02013-04-17 11:00:01 -07002234 rect->nLeft,
2235 rect->nTop,
2236 rect->nLeft + rect->nWidth - 1,
2237 rect->nTop + rect->nHeight - 1);
Shalaj Jain65506622013-01-29 18:27:08 -08002238
2239 if (mNativeWindow != NULL) {
2240 android_native_rect_t crop;
Eric (Quicb4042f02013-04-17 11:00:01 -07002241 crop.left = rect->nLeft;
2242 crop.top = rect->nTop;
2243 crop.right = rect->nLeft + rect->nWidth;
2244 crop.bottom = rect->nTop + rect->nHeight;
Shalaj Jain65506622013-01-29 18:27:08 -08002245
2246 CHECK_EQ(0, native_window_set_crop(
2247 mNativeWindow.get(), &crop));
2248 }
Eric (Quicb4042f02013-04-17 11:00:01 -07002249 delete rect;
Shalaj Jain65506622013-01-29 18:27:08 -08002250 break;
2251 }
2252
2253 case OMX_PortDomainAudio:
2254 {
Eric (Quicb4042f02013-04-17 11:00:01 -07002255 OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def->format.audio;
Shalaj Jain65506622013-01-29 18:27:08 -08002256 CHECK_EQ((int)audioDef->eEncoding, (int)OMX_AUDIO_CodingPCM);
2257
2258 OMX_AUDIO_PARAM_PCMMODETYPE params;
2259 InitOMXParams(&params);
2260 params.nPortIndex = kPortIndexOutput;
2261
2262 CHECK_EQ(mOMX->getParameter(
2263 mNode, OMX_IndexParamAudioPcm,
2264 &params, sizeof(params)),
2265 (status_t)OK);
2266
2267 CHECK(params.nChannels == 1 || params.bInterleaved);
2268 CHECK_EQ(params.nBitPerSample, 16u);
2269 CHECK_EQ((int)params.eNumData, (int)OMX_NumericalDataSigned);
2270 CHECK_EQ((int)params.ePCMMode, (int)OMX_AUDIO_PCMModeLinear);
2271
2272 notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RAW);
2273 notify->setInt32("channel-count", params.nChannels);
2274 notify->setInt32("sample-rate", params.nSamplingRate);
2275 if (mEncoderDelay + mEncoderPadding) {
2276 size_t frameSize = params.nChannels * sizeof(int16_t);
2277 if (mSkipCutBuffer != NULL) {
2278 size_t prevbufsize = mSkipCutBuffer->size();
2279 if (prevbufsize != 0) {
2280 ALOGW("Replacing SkipCutBuffer holding %d bytes", prevbufsize);
2281 }
2282 }
2283 mSkipCutBuffer = new SkipCutBuffer(mEncoderDelay * frameSize,
2284 mEncoderPadding * frameSize);
2285 }
2286
2287 if (mChannelMaskPresent) {
2288 notify->setInt32("channel-mask", mChannelMask);
2289 }
2290
2291 break;
2292 }
2293
2294 default:
2295 TRESPASS();
2296 }
2297
2298 notify->post();
Eric (Quicb4042f02013-04-17 11:00:01 -07002299 delete def;
Shalaj Jain65506622013-01-29 18:27:08 -08002300 mSentFormat = true;
2301}
2302
2303status_t DashCodec::InitSmoothStreaming() {
2304 status_t err = mOMX->setParameter(mNode, (OMX_INDEXTYPE)OMX_QcomIndexParamEnableSmoothStreaming,&err, sizeof(int32_t));
2305 if (err != OMX_ErrorNone) {
2306 ALOGE("InitSmoothStreaming setParam failed for extradata");
2307 return err;
2308 }
2309
2310 ALOGW("InitSmoothStreaming - Smooth streaming mode enabled");
2311
2312 return OK;
2313}
2314
2315void DashCodec::signalError(OMX_ERRORTYPE error, status_t internalError) {
2316 sp<AMessage> notify = mNotify->dup();
2317 notify->setInt32("what", DashCodec::kWhatError);
2318 notify->setInt32("omx-error", error);
2319 notify->setInt32("err", internalError);
2320 notify->post();
2321}
2322
2323status_t DashCodec::pushBlankBuffersToNativeWindow() {
2324 status_t err = NO_ERROR;
2325 ANativeWindowBuffer* anb = NULL;
2326 int numBufs = 0;
2327 int minUndequeuedBufs = 0;
2328
2329 // We need to reconnect to the ANativeWindow as a CPU client to ensure that
2330 // no frames get dropped by SurfaceFlinger assuming that these are video
2331 // frames.
2332 err = native_window_api_disconnect(mNativeWindow.get(),
2333 NATIVE_WINDOW_API_MEDIA);
2334 if (err != NO_ERROR) {
2335 ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
2336 strerror(-err), -err);
2337 return err;
2338 }
2339
2340 err = native_window_api_connect(mNativeWindow.get(),
2341 NATIVE_WINDOW_API_CPU);
2342 if (err != NO_ERROR) {
2343 ALOGE("error pushing blank frames: api_connect failed: %s (%d)",
2344 strerror(-err), -err);
2345 return err;
2346 }
2347
2348 err = native_window_set_buffers_geometry(mNativeWindow.get(), 1, 1,
2349 HAL_PIXEL_FORMAT_RGBX_8888);
2350 if (err != NO_ERROR) {
2351 ALOGE("error pushing blank frames: set_buffers_geometry failed: %s (%d)",
2352 strerror(-err), -err);
2353 goto error;
2354 }
2355
2356 err = native_window_set_usage(mNativeWindow.get(),
2357 GRALLOC_USAGE_SW_WRITE_OFTEN);
2358 if (err != NO_ERROR) {
2359 ALOGE("error pushing blank frames: set_usage failed: %s (%d)",
2360 strerror(-err), -err);
2361 goto error;
2362 }
2363
2364 err = mNativeWindow->query(mNativeWindow.get(),
2365 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
2366 if (err != NO_ERROR) {
2367 ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
2368 "failed: %s (%d)", strerror(-err), -err);
2369 goto error;
2370 }
2371
2372 numBufs = minUndequeuedBufs + 1;
2373 err = native_window_set_buffer_count(mNativeWindow.get(), numBufs);
2374 if (err != NO_ERROR) {
2375 ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)",
2376 strerror(-err), -err);
2377 goto error;
2378 }
2379
2380 // We push numBufs + 1 buffers to ensure that we've drawn into the same
2381 // buffer twice. This should guarantee that the buffer has been displayed
2382 // on the screen and then been replaced, so an previous video frames are
2383 // guaranteed NOT to be currently displayed.
2384 for (int i = 0; i < numBufs + 1; i++) {
2385 int fenceFd = -1;
2386 err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &anb);
2387 if (err != NO_ERROR) {
2388 ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
2389 strerror(-err), -err);
2390 goto error;
2391 }
2392
2393 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
2394
2395 // Fill the buffer with the a 1x1 checkerboard pattern ;)
2396 uint32_t* img = NULL;
2397 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
2398 if (err != NO_ERROR) {
2399 ALOGE("error pushing blank frames: lock failed: %s (%d)",
2400 strerror(-err), -err);
2401 goto error;
2402 }
2403
2404 *img = 0;
2405
2406 err = buf->unlock();
2407 if (err != NO_ERROR) {
2408 ALOGE("error pushing blank frames: unlock failed: %s (%d)",
2409 strerror(-err), -err);
2410 goto error;
2411 }
2412
2413 err = mNativeWindow->queueBuffer(mNativeWindow.get(),
2414 buf->getNativeBuffer(), -1);
2415 if (err != NO_ERROR) {
2416 ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)",
2417 strerror(-err), -err);
2418 goto error;
2419 }
2420
2421 anb = NULL;
2422 }
2423
2424error:
2425
2426 if (err != NO_ERROR) {
2427 // Clean up after an error.
2428 if (anb != NULL) {
2429 mNativeWindow->cancelBuffer(mNativeWindow.get(), anb, -1);
2430 }
2431
2432 native_window_api_disconnect(mNativeWindow.get(),
2433 NATIVE_WINDOW_API_CPU);
2434 native_window_api_connect(mNativeWindow.get(),
2435 NATIVE_WINDOW_API_MEDIA);
2436
2437 return err;
2438 } else {
2439 // Clean up after success.
2440 err = native_window_api_disconnect(mNativeWindow.get(),
2441 NATIVE_WINDOW_API_CPU);
2442 if (err != NO_ERROR) {
2443 ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
2444 strerror(-err), -err);
2445 return err;
2446 }
2447
2448 err = native_window_api_connect(mNativeWindow.get(),
2449 NATIVE_WINDOW_API_MEDIA);
2450 if (err != NO_ERROR) {
2451 ALOGE("error pushing blank frames: api_connect failed: %s (%d)",
2452 strerror(-err), -err);
2453 return err;
2454 }
2455
2456 return NO_ERROR;
2457 }
2458}
2459
2460////////////////////////////////////////////////////////////////////////////////
2461
2462DashCodec::PortDescription::PortDescription() {
2463}
2464
2465status_t DashCodec::requestIDRFrame() {
2466 if (!mIsEncoder) {
2467 return ERROR_UNSUPPORTED;
2468 }
2469
2470 OMX_CONFIG_INTRAREFRESHVOPTYPE params;
2471 InitOMXParams(&params);
2472
2473 params.nPortIndex = kPortIndexOutput;
2474 params.IntraRefreshVOP = OMX_TRUE;
2475
2476 return mOMX->setConfig(
2477 mNode,
2478 OMX_IndexConfigVideoIntraVOPRefresh,
2479 &params,
2480 sizeof(params));
2481}
2482
2483void DashCodec::PortDescription::addBuffer(
2484 IOMX::buffer_id id, const sp<ABuffer> &buffer) {
2485 mBufferIDs.push_back(id);
2486 mBuffers.push_back(buffer);
2487}
2488
2489size_t DashCodec::PortDescription::countBuffers() {
2490 return mBufferIDs.size();
2491}
2492
2493IOMX::buffer_id DashCodec::PortDescription::bufferIDAt(size_t index) const {
2494 return mBufferIDs.itemAt(index);
2495}
2496
2497sp<ABuffer> DashCodec::PortDescription::bufferAt(size_t index) const {
2498 return mBuffers.itemAt(index);
2499}
2500
2501////////////////////////////////////////////////////////////////////////////////
2502
2503DashCodec::BaseState::BaseState(DashCodec *codec, const sp<AState> &parentState)
2504 : AState(parentState),
2505 mCodec(codec) {
2506}
2507
2508DashCodec::BaseState::PortMode DashCodec::BaseState::getPortMode(OMX_U32 portIndex) {
2509 return KEEP_BUFFERS;
2510}
2511
2512bool DashCodec::BaseState::onMessageReceived(const sp<AMessage> &msg) {
2513 switch (msg->what()) {
2514 case kWhatInputBufferFilled:
2515 {
2516 onInputBufferFilled(msg);
2517 break;
2518 }
2519
2520 case kWhatOutputBufferDrained:
2521 {
2522 onOutputBufferDrained(msg);
2523 break;
2524 }
2525
2526 case DashCodec::kWhatOMXMessage:
2527 {
2528 return onOMXMessage(msg);
2529 }
2530
2531 case DashCodec::kWhatFlush:
2532 {
2533 sp<AMessage> notify = mCodec->mNotify->dup();
2534 notify->setInt32("what", DashCodec::kWhatFlushCompleted);
2535 notify->post();
2536 return true;
2537 }
2538
2539 default:
2540 return false;
2541 }
2542
2543 return true;
2544}
2545
2546bool DashCodec::BaseState::onOMXMessage(const sp<AMessage> &msg) {
2547 int32_t type;
2548 CHECK(msg->findInt32("type", &type));
2549
2550 IOMX::node_id nodeID;
2551 CHECK(msg->findPointer("node", &nodeID));
2552 CHECK_EQ(nodeID, mCodec->mNode);
2553
2554 switch (type) {
2555 case omx_message::EVENT:
2556 {
2557 int32_t event, data1, data2;
2558 CHECK(msg->findInt32("event", &event));
2559 CHECK(msg->findInt32("data1", &data1));
2560 CHECK(msg->findInt32("data2", &data2));
2561
2562 if (event == OMX_EventCmdComplete
2563 && data1 == OMX_CommandFlush
2564 && data2 == (int32_t)OMX_ALL) {
2565 // Use of this notification is not consistent across
2566 // implementations. We'll drop this notification and rely
2567 // on flush-complete notifications on the individual port
2568 // indices instead.
2569
2570 return true;
2571 }
2572
2573 return onOMXEvent(
2574 static_cast<OMX_EVENTTYPE>(event),
2575 static_cast<OMX_U32>(data1),
2576 static_cast<OMX_U32>(data2));
2577 }
2578
2579 case omx_message::EMPTY_BUFFER_DONE:
2580 {
2581 IOMX::buffer_id bufferID;
2582 CHECK(msg->findPointer("buffer", &bufferID));
2583
2584 return onOMXEmptyBufferDone(bufferID);
2585 }
2586
2587 case omx_message::FILL_BUFFER_DONE:
2588 {
2589 IOMX::buffer_id bufferID;
2590 CHECK(msg->findPointer("buffer", &bufferID));
2591
2592 int32_t rangeOffset, rangeLength, flags;
2593 int64_t timeUs;
2594 void *platformPrivate;
2595 void *dataPtr;
2596
2597 CHECK(msg->findInt32("range_offset", &rangeOffset));
2598 CHECK(msg->findInt32("range_length", &rangeLength));
2599 CHECK(msg->findInt32("flags", &flags));
2600 CHECK(msg->findInt64("timestamp", &timeUs));
2601 CHECK(msg->findPointer("platform_private", &platformPrivate));
2602 CHECK(msg->findPointer("data_ptr", &dataPtr));
2603
2604 return onOMXFillBufferDone(
2605 bufferID,
2606 (size_t)rangeOffset, (size_t)rangeLength,
2607 (OMX_U32)flags,
2608 timeUs,
2609 platformPrivate,
2610 dataPtr);
2611 }
2612
2613 default:
2614 TRESPASS();
2615 break;
2616 }
2617}
2618
2619bool DashCodec::BaseState::onOMXEvent(
2620 OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
2621 if (event != OMX_EventError) {
2622 ALOGV("[%s] EVENT(%d, 0x%08lx, 0x%08lx)",
2623 mCodec->mComponentName.c_str(), event, data1, data2);
2624
2625 return false;
2626 }
2627
2628 ALOGE("[%s] ERROR(0x%08lx)", mCodec->mComponentName.c_str(), data1);
2629
2630 mCodec->signalError((OMX_ERRORTYPE)data1);
2631
2632 return true;
2633}
2634
2635bool DashCodec::BaseState::onOMXEmptyBufferDone(IOMX::buffer_id bufferID) {
2636 ALOGV("[%s] onOMXEmptyBufferDone %p",
2637 mCodec->mComponentName.c_str(), bufferID);
2638
2639 BufferInfo *info =
2640 mCodec->findBufferByID(kPortIndexInput, bufferID);
2641
2642 CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_COMPONENT);
2643 info->mStatus = BufferInfo::OWNED_BY_US;
2644
2645 const sp<AMessage> &bufferMeta = info->mData->meta();
2646 void *mediaBuffer;
2647 if (bufferMeta->findPointer("mediaBuffer", &mediaBuffer)
2648 && mediaBuffer != NULL) {
2649 // We're in "store-metadata-in-buffers" mode, the underlying
2650 // OMX component had access to data that's implicitly refcounted
2651 // by this "mediaBuffer" object. Now that the OMX component has
2652 // told us that it's done with the input buffer, we can decrement
2653 // the mediaBuffer's reference count.
2654
2655 ALOGV("releasing mbuf %p", mediaBuffer);
2656
2657 ((MediaBuffer *)mediaBuffer)->release();
2658 mediaBuffer = NULL;
2659
2660 bufferMeta->setPointer("mediaBuffer", NULL);
2661 }
2662
2663 PortMode mode = getPortMode(kPortIndexInput);
2664
2665 switch (mode) {
2666 case KEEP_BUFFERS:
2667 break;
2668
2669 case RESUBMIT_BUFFERS:
2670 postFillThisBuffer(info);
2671 break;
2672
2673 default:
2674 {
2675 CHECK_EQ((int)mode, (int)FREE_BUFFERS);
2676 TRESPASS(); // Not currently used
2677 break;
2678 }
2679 }
2680
2681 return true;
2682}
2683
2684void DashCodec::BaseState::postFillThisBuffer(BufferInfo *info) {
2685 if (mCodec->mPortEOS[kPortIndexInput]) {
2686 return;
2687 }
2688
2689 CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
2690
2691 sp<AMessage> notify = mCodec->mNotify->dup();
2692 notify->setInt32("what", DashCodec::kWhatFillThisBuffer);
2693 notify->setPointer("buffer-id", info->mBufferID);
2694
2695 info->mData->meta()->clear();
2696 notify->setBuffer("buffer", info->mData);
2697
2698 sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, mCodec->id());
2699 reply->setPointer("buffer-id", info->mBufferID);
2700
2701 notify->setMessage("reply", reply);
2702
2703 notify->post();
2704
2705 info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
2706}
2707
2708void DashCodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
2709 IOMX::buffer_id bufferID;
2710 CHECK(msg->findPointer("buffer-id", &bufferID));
2711
2712 sp<ABuffer> buffer;
2713 int32_t err = OK;
2714 bool eos = false;
2715
2716 if (!msg->findBuffer("buffer", &buffer)) {
2717 CHECK(msg->findInt32("err", &err));
2718
2719 ALOGV("[%s] saw error %d instead of an input buffer",
2720 mCodec->mComponentName.c_str(), err);
2721
2722 buffer.clear();
2723
2724 eos = true;
2725 }
2726
2727 int32_t tmp;
2728 if (buffer != NULL && buffer->meta()->findInt32("eos", &tmp) && tmp) {
2729 eos = true;
2730 err = ERROR_END_OF_STREAM;
2731 }
2732
2733 BufferInfo *info = mCodec->findBufferByID(kPortIndexInput, bufferID);
2734 CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_UPSTREAM);
2735
2736 info->mStatus = BufferInfo::OWNED_BY_US;
2737
2738 PortMode mode = getPortMode(kPortIndexInput);
2739
2740 switch (mode) {
2741 case KEEP_BUFFERS:
2742 {
2743 if (eos) {
2744 if (!mCodec->mPortEOS[kPortIndexInput]) {
2745 mCodec->mPortEOS[kPortIndexInput] = true;
2746 mCodec->mInputEOSResult = err;
2747 }
2748 }
2749 break;
2750 }
2751
2752 case RESUBMIT_BUFFERS:
2753 {
2754 if (buffer != NULL && !mCodec->mPortEOS[kPortIndexInput]) {
2755 int64_t timeUs;
2756 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
2757
2758 OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
2759
2760 int32_t isCSD;
2761 if (buffer->meta()->findInt32("csd", &isCSD) && isCSD != 0) {
2762 flags |= OMX_BUFFERFLAG_CODECCONFIG;
2763 }
2764
2765 if (eos) {
2766 flags |= OMX_BUFFERFLAG_EOS;
2767 }
2768
2769 if (buffer != info->mData) {
2770 ALOGV("[%s] Needs to copy input data for buffer %p. (%p != %p)",
2771 mCodec->mComponentName.c_str(),
2772 bufferID,
2773 buffer.get(), info->mData.get());
2774
2775 CHECK_LE(buffer->size(), info->mData->capacity());
2776 memcpy(info->mData->data(), buffer->data(), buffer->size());
2777 }
2778
2779 if (flags & OMX_BUFFERFLAG_CODECCONFIG) {
2780 ALOGV("[%s] calling emptyBuffer %p w/ codec specific data",
2781 mCodec->mComponentName.c_str(), bufferID);
2782 } else if (flags & OMX_BUFFERFLAG_EOS) {
2783 ALOGV("[%s] calling emptyBuffer %p w/ EOS",
2784 mCodec->mComponentName.c_str(), bufferID);
2785 } else {
2786#if TRACK_BUFFER_TIMING
2787 ALOGI("[%s] calling emptyBuffer %p w/ time %lld us",
2788 mCodec->mComponentName.c_str(), bufferID, timeUs);
2789#else
2790 ALOGV("[%s] calling emptyBuffer %p w/ time %lld us",
2791 mCodec->mComponentName.c_str(), bufferID, timeUs);
2792#endif
2793 }
2794
2795#if TRACK_BUFFER_TIMING
2796 DashCodec::BufferStats stats;
2797 stats.mEmptyBufferTimeUs = ALooper::GetNowUs();
2798 stats.mFillBufferDoneTimeUs = -1ll;
2799 mCodec->mBufferStats.add(timeUs, stats);
2800#endif
2801
2802 CHECK_EQ(mCodec->mOMX->emptyBuffer(
2803 mCodec->mNode,
2804 bufferID,
2805 0,
2806 buffer->size(),
2807 flags,
2808 timeUs),
2809 (status_t)OK);
2810
2811 info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
2812
2813 if (!eos) {
2814 getMoreInputDataIfPossible();
2815 } else {
2816 ALOGV("[%s] Signalled EOS on the input port",
2817 mCodec->mComponentName.c_str());
2818
2819 mCodec->mPortEOS[kPortIndexInput] = true;
2820 mCodec->mInputEOSResult = err;
2821 }
2822 } else if (!mCodec->mPortEOS[kPortIndexInput]) {
2823 if (err != ERROR_END_OF_STREAM) {
2824 ALOGV("[%s] Signalling EOS on the input port "
2825 "due to error %d",
2826 mCodec->mComponentName.c_str(), err);
2827 } else {
2828 ALOGV("[%s] Signalling EOS on the input port",
2829 mCodec->mComponentName.c_str());
2830 }
2831
2832 ALOGV("[%s] calling emptyBuffer %p signalling EOS",
2833 mCodec->mComponentName.c_str(), bufferID);
2834
2835 CHECK_EQ(mCodec->mOMX->emptyBuffer(
2836 mCodec->mNode,
2837 bufferID,
2838 0,
2839 0,
2840 OMX_BUFFERFLAG_EOS,
2841 0),
2842 (status_t)OK);
2843
2844 info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
2845
2846 mCodec->mPortEOS[kPortIndexInput] = true;
2847 mCodec->mInputEOSResult = err;
2848 }
2849 break;
2850
2851 default:
2852 CHECK_EQ((int)mode, (int)FREE_BUFFERS);
2853 break;
2854 }
2855 }
2856}
2857
2858void DashCodec::BaseState::getMoreInputDataIfPossible() {
2859 if (mCodec->mPortEOS[kPortIndexInput]) {
2860 return;
2861 }
2862
2863 BufferInfo *eligible = NULL;
2864
2865 for (size_t i = 0; i < mCodec->mBuffers[kPortIndexInput].size(); ++i) {
2866 BufferInfo *info = &mCodec->mBuffers[kPortIndexInput].editItemAt(i);
2867
2868#if 0
2869 if (info->mStatus == BufferInfo::OWNED_BY_UPSTREAM) {
2870 // There's already a "read" pending.
2871 return;
2872 }
2873#endif
2874
2875 if (info->mStatus == BufferInfo::OWNED_BY_US) {
2876 eligible = info;
2877 }
2878 }
2879
2880 if (eligible == NULL) {
2881 return;
2882 }
2883
2884 postFillThisBuffer(eligible);
2885}
2886
2887bool DashCodec::BaseState::onOMXFillBufferDone(
2888 IOMX::buffer_id bufferID,
2889 size_t rangeOffset, size_t rangeLength,
2890 OMX_U32 flags,
2891 int64_t timeUs,
2892 void *platformPrivate,
2893 void *dataPtr) {
2894 ALOGV("[%s] onOMXFillBufferDone %p time %lld us, flags = 0x%08lx",
2895 mCodec->mComponentName.c_str(), bufferID, timeUs, flags);
2896
2897 ssize_t index;
2898
2899#if TRACK_BUFFER_TIMING
2900 index = mCodec->mBufferStats.indexOfKey(timeUs);
2901 if (index >= 0) {
2902 DashCodec::BufferStats *stats = &mCodec->mBufferStats.editValueAt(index);
2903 stats->mFillBufferDoneTimeUs = ALooper::GetNowUs();
2904
2905 ALOGI("frame PTS %lld: %lld",
2906 timeUs,
2907 stats->mFillBufferDoneTimeUs - stats->mEmptyBufferTimeUs);
2908
2909 mCodec->mBufferStats.removeItemsAt(index);
2910 stats = NULL;
2911 }
2912#endif
2913
2914 BufferInfo *info =
2915 mCodec->findBufferByID(kPortIndexOutput, bufferID, &index);
2916
2917 CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_COMPONENT);
2918
2919 info->mStatus = BufferInfo::OWNED_BY_US;
2920
2921 PortMode mode = getPortMode(kPortIndexOutput);
2922
2923 switch (mode) {
2924 case KEEP_BUFFERS:
2925 break;
2926
2927 case RESUBMIT_BUFFERS:
2928 {
2929 if (rangeLength == 0 && !(flags & OMX_BUFFERFLAG_EOS)) {
2930 ALOGV("[%s] calling fillBuffer %p",
2931 mCodec->mComponentName.c_str(), info->mBufferID);
2932
2933 CHECK_EQ(mCodec->mOMX->fillBuffer(
2934 mCodec->mNode, info->mBufferID),
2935 (status_t)OK);
2936
2937 info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
2938 break;
2939 }
2940
Surajit Podder57d85b62013-04-24 16:42:19 +05302941 if (flags & OMX_BUFFERFLAG_EOS) {
2942 ALOGE("[%s] saw output EOS", mCodec->mComponentName.c_str());
2943
2944 sp<AMessage> notify = mCodec->mNotify->dup();
2945 notify->setInt32("what", DashCodec::kWhatEOS);
2946 notify->setInt32("err", mCodec->mInputEOSResult);
2947 notify->post();
2948
2949 mCodec->mPortEOS[kPortIndexOutput] = true;
2950 break;
2951 }
2952
Shalaj Jain65506622013-01-29 18:27:08 -08002953 if (!mCodec->mIsEncoder && !mCodec->mSentFormat && !mCodec->mSmoothStreaming) {
2954 mCodec->sendFormatChange();
2955 }
2956
2957 if (mCodec->mNativeWindow == NULL) {
2958 info->mData->setRange(rangeOffset, rangeLength);
2959
2960#if 0
2961 if (IsIDR(info->mData)) {
2962 ALOGI("IDR frame");
2963 }
2964#endif
2965 }
2966
2967 if (mCodec->mSkipCutBuffer != NULL) {
2968 mCodec->mSkipCutBuffer->submit(info->mData);
2969 }
2970 info->mData->meta()->setInt64("timeUs", timeUs);
2971
2972 sp<AMessage> notify = mCodec->mNotify->dup();
2973 notify->setInt32("what", DashCodec::kWhatDrainThisBuffer);
2974 notify->setPointer("buffer-id", info->mBufferID);
2975 notify->setBuffer("buffer", info->mData);
2976 notify->setInt32("flags", flags);
2977 sp<AMessage> reply =
2978 new AMessage(kWhatOutputBufferDrained, mCodec->id());
2979
Eric (Quicb4042f02013-04-17 11:00:01 -07002980 if (!mCodec->mPostFormat && mCodec->mSmoothStreaming){
Shalaj Jain65506622013-01-29 18:27:08 -08002981 ALOGV("Resolution will change from this buffer, set a flag");
2982 reply->setInt32("resChange", 1);
Eric (Quicb4042f02013-04-17 11:00:01 -07002983 mCodec->mPostFormat = true;
Shalaj Jain65506622013-01-29 18:27:08 -08002984 }
2985
2986 reply->setPointer("buffer-id", info->mBufferID);
2987
2988 notify->setMessage("reply", reply);
2989
2990 notify->post();
2991
2992 info->mStatus = BufferInfo::OWNED_BY_DOWNSTREAM;
2993
Shalaj Jain65506622013-01-29 18:27:08 -08002994 break;
2995 }
2996
2997 default:
2998 {
2999 CHECK_EQ((int)mode, (int)FREE_BUFFERS);
3000
3001 CHECK_EQ((status_t)OK,
3002 mCodec->freeBuffer(kPortIndexOutput, index));
3003 break;
3004 }
3005 }
3006
3007 return true;
3008}
3009
3010void DashCodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) {
3011 IOMX::buffer_id bufferID;
3012 CHECK(msg->findPointer("buffer-id", &bufferID));
3013
3014 ssize_t index;
3015 BufferInfo *info =
3016 mCodec->findBufferByID(kPortIndexOutput, bufferID, &index);
3017 CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_DOWNSTREAM);
Eric (Quicb4042f02013-04-17 11:00:01 -07003018 if (mCodec->mSmoothStreaming) {
Shalaj Jain65506622013-01-29 18:27:08 -08003019 int32_t resChange = 0;
3020 if (msg->findInt32("resChange", &resChange) && resChange == 1) {
3021 ALOGV("Resolution change is sent to native window now ");
3022 mCodec->sendFormatChange();
3023 msg->setInt32("resChange", 0);
3024 }
3025 }
3026 int32_t render;
3027 if (mCodec->mNativeWindow != NULL
3028 && msg->findInt32("render", &render) && render != 0) {
3029 // The client wants this buffer to be rendered.
3030
3031 status_t err;
3032 if ((err = mCodec->mNativeWindow->queueBuffer(
3033 mCodec->mNativeWindow.get(),
3034 info->mGraphicBuffer.get(), -1)) == OK) {
3035 info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
3036 } else {
3037 mCodec->signalError(OMX_ErrorUndefined, err);
3038 info->mStatus = BufferInfo::OWNED_BY_US;
3039 }
3040 } else {
3041 info->mStatus = BufferInfo::OWNED_BY_US;
3042 }
3043
3044 PortMode mode = getPortMode(kPortIndexOutput);
3045
3046 switch (mode) {
3047 case KEEP_BUFFERS:
3048 {
3049 // XXX fishy, revisit!!! What about the FREE_BUFFERS case below?
3050
3051 if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) {
3052 // We cannot resubmit the buffer we just rendered, dequeue
3053 // the spare instead.
3054
3055 info = mCodec->dequeueBufferFromNativeWindow();
3056 }
3057 break;
3058 }
3059
3060 case RESUBMIT_BUFFERS:
3061 {
3062 if (!mCodec->mPortEOS[kPortIndexOutput]) {
3063 if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) {
3064 // We cannot resubmit the buffer we just rendered, dequeue
3065 // the spare instead.
3066
3067 info = mCodec->dequeueBufferFromNativeWindow();
3068 }
3069
3070 if (info != NULL) {
3071 ALOGV("[%s] calling fillBuffer %p",
3072 mCodec->mComponentName.c_str(), info->mBufferID);
3073
3074 CHECK_EQ(mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID),
3075 (status_t)OK);
3076
3077 info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
3078 }
3079 }
3080 break;
3081 }
3082
3083 default:
3084 {
3085 CHECK_EQ((int)mode, (int)FREE_BUFFERS);
3086
3087 CHECK_EQ((status_t)OK,
3088 mCodec->freeBuffer(kPortIndexOutput, index));
3089 break;
3090 }
3091 }
3092}
3093
3094////////////////////////////////////////////////////////////////////////////////
3095
3096DashCodec::UninitializedState::UninitializedState(DashCodec *codec)
3097 : BaseState(codec) {
3098}
3099
3100void DashCodec::UninitializedState::stateEntered() {
3101 ALOGV("Now uninitialized");
3102}
3103
3104bool DashCodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
3105 bool handled = false;
3106
3107 switch (msg->what()) {
3108 case DashCodec::kWhatSetup:
3109 {
3110 onSetup(msg);
3111
3112 handled = true;
3113 break;
3114 }
3115
3116 case DashCodec::kWhatAllocateComponent:
3117 {
3118 onAllocateComponent(msg);
3119 handled = true;
3120 break;
3121 }
3122
3123 case DashCodec::kWhatShutdown:
3124 {
3125 int32_t keepComponentAllocated;
3126 CHECK(msg->findInt32(
3127 "keepComponentAllocated", &keepComponentAllocated));
3128 CHECK(!keepComponentAllocated);
3129
3130 sp<AMessage> notify = mCodec->mNotify->dup();
3131 notify->setInt32("what", DashCodec::kWhatShutdownCompleted);
3132 notify->post();
3133
3134 handled = true;
3135 break;
3136 }
3137
3138 default:
3139 return BaseState::onMessageReceived(msg);
3140 }
3141
3142 return handled;
3143}
3144
3145void DashCodec::UninitializedState::onSetup(
3146 const sp<AMessage> &msg) {
3147 if (onAllocateComponent(msg)
3148 && mCodec->mLoadedState->onConfigureComponent(msg)) {
3149 mCodec->mLoadedState->onStart();
3150 }
3151}
3152
3153bool DashCodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
3154 ALOGV("onAllocateComponent");
3155
3156 CHECK(mCodec->mNode == NULL);
3157
3158 OMXClient client;
3159 CHECK_EQ(client.connect(), (status_t)OK);
3160
3161 sp<IOMX> omx = client.interface();
3162
3163 Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs;
3164
3165 AString mime;
3166
3167 AString componentName;
3168 uint32_t quirks = 0;
3169 if (msg->findString("componentName", &componentName)) {
3170 ssize_t index = matchingCodecs.add();
3171 OMXCodec::CodecNameAndQuirks *entry = &matchingCodecs.editItemAt(index);
3172 entry->mName = String8(componentName.c_str());
3173
3174 if (!OMXCodec::findCodecQuirks(
3175 componentName.c_str(), &entry->mQuirks)) {
3176 entry->mQuirks = 0;
3177 }
3178 } else {
3179 CHECK(msg->findString("mime", &mime));
3180
3181 int32_t encoder;
3182 if (!msg->findInt32("encoder", &encoder)) {
3183 encoder = false;
3184 }
3185
3186 OMXCodec::findMatchingCodecs(
3187 mime.c_str(),
3188 encoder, // createEncoder
3189 NULL, // matchComponentName
3190 0, // flags
3191 &matchingCodecs);
3192 }
3193
3194 sp<CodecObserver> observer = new CodecObserver;
3195 IOMX::node_id node = NULL;
3196
3197 for (size_t matchIndex = 0; matchIndex < matchingCodecs.size();
3198 ++matchIndex) {
3199 componentName = matchingCodecs.itemAt(matchIndex).mName.string();
3200 quirks = matchingCodecs.itemAt(matchIndex).mQuirks;
3201
3202 pid_t tid = androidGetTid();
3203 int prevPriority = androidGetThreadPriority(tid);
3204 androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
3205 status_t err = omx->allocateNode(componentName.c_str(), observer, &node);
3206 androidSetThreadPriority(tid, prevPriority);
3207
3208 if (err == OK) {
3209 break;
3210 }
3211
3212 node = NULL;
3213 }
3214
3215 if (node == NULL) {
3216 if (!mime.empty()) {
3217 ALOGE("Unable to instantiate a decoder for type '%s'.",
3218 mime.c_str());
3219 } else {
3220 ALOGE("Unable to instantiate decoder '%s'.", componentName.c_str());
3221 }
3222
3223 mCodec->signalError(OMX_ErrorComponentNotFound);
3224 return false;
3225 }
3226
3227 sp<AMessage> notify = new AMessage(kWhatOMXMessage, mCodec->id());
3228 observer->setNotificationMessage(notify);
3229
3230 mCodec->mComponentName = componentName;
3231 mCodec->mFlags = 0;
3232
3233 if (componentName.endsWith(".secure")) {
3234 mCodec->mFlags |= kFlagIsSecure;
3235 }
3236
3237 mCodec->mQuirks = quirks;
3238 mCodec->mOMX = omx;
3239 mCodec->mNode = node;
3240
3241 mCodec->mPortEOS[kPortIndexInput] =
3242 mCodec->mPortEOS[kPortIndexOutput] = false;
3243
3244 mCodec->mInputEOSResult = OK;
3245
3246 {
3247 sp<AMessage> notify = mCodec->mNotify->dup();
3248 notify->setInt32("what", DashCodec::kWhatComponentAllocated);
3249 notify->setString("componentName", mCodec->mComponentName.c_str());
3250 notify->post();
3251 }
3252
3253 mCodec->changeState(mCodec->mLoadedState);
3254
3255 return true;
3256}
3257
3258////////////////////////////////////////////////////////////////////////////////
3259
3260DashCodec::LoadedState::LoadedState(DashCodec *codec)
3261 : BaseState(codec) {
3262}
3263
3264void DashCodec::LoadedState::stateEntered() {
3265 ALOGV("[%s] Now Loaded", mCodec->mComponentName.c_str());
3266
3267 if (mCodec->mShutdownInProgress) {
3268 bool keepComponentAllocated = mCodec->mKeepComponentAllocated;
3269
3270 mCodec->mShutdownInProgress = false;
3271 mCodec->mKeepComponentAllocated = false;
3272
3273 onShutdown(keepComponentAllocated);
3274 }
3275}
3276
3277void DashCodec::LoadedState::onShutdown(bool keepComponentAllocated) {
3278 if (!keepComponentAllocated) {
3279 CHECK_EQ(mCodec->mOMX->freeNode(mCodec->mNode), (status_t)OK);
3280
3281 mCodec->mNativeWindow.clear();
3282 mCodec->mNode = NULL;
3283 mCodec->mOMX.clear();
3284 mCodec->mQuirks = 0;
3285 mCodec->mFlags = 0;
3286 mCodec->mComponentName.clear();
3287
3288 mCodec->changeState(mCodec->mUninitializedState);
3289 }
3290
3291 sp<AMessage> notify = mCodec->mNotify->dup();
3292 notify->setInt32("what", DashCodec::kWhatShutdownCompleted);
3293 notify->post();
3294}
3295
3296bool DashCodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) {
3297 bool handled = false;
3298
3299 switch (msg->what()) {
3300 case DashCodec::kWhatConfigureComponent:
3301 {
3302 onConfigureComponent(msg);
3303 handled = true;
3304 break;
3305 }
3306
3307 case DashCodec::kWhatStart:
3308 {
3309 onStart();
3310 handled = true;
3311 break;
3312 }
3313
3314 case DashCodec::kWhatShutdown:
3315 {
3316 int32_t keepComponentAllocated;
3317 CHECK(msg->findInt32(
3318 "keepComponentAllocated", &keepComponentAllocated));
3319
3320 onShutdown(keepComponentAllocated);
3321
3322 handled = true;
3323 break;
3324 }
3325
3326 default:
3327 return BaseState::onMessageReceived(msg);
3328 }
3329
3330 return handled;
3331}
3332
3333bool DashCodec::LoadedState::onConfigureComponent(
3334 const sp<AMessage> &msg) {
3335 ALOGV("onConfigureComponent");
3336
3337 CHECK(mCodec->mNode != NULL);
3338
3339 int32_t value;
3340 if (msg->findInt32("smooth-streaming", &value) && (value == 1) &&
3341 !strcmp("OMX.qcom.video.decoder.avc", mCodec->mComponentName.c_str())) {
3342
3343 char value_ss[PROPERTY_VALUE_MAX];
3344 if (property_get("hls.disable.smooth.streaming", value_ss, NULL) &&
3345 (!strcasecmp(value_ss, "true") || !strcmp(value_ss, "1"))) {
3346
3347 ALOGW("Dont enable Smooth streaming, disable property is set");
3348 } else {
3349 mCodec->mSmoothStreaming = true;
3350 status_t err = mCodec->InitSmoothStreaming();
3351 if (err != OK) {
3352 ALOGE("Error in enabling smooth streaming, ignore & disable ");
3353 mCodec->mSmoothStreaming = false;
3354 } else {
3355 ALOGI("Smooth streaming is enabled ");
3356 }
3357 }
3358 }
3359
Surajit Podder46ad8f12013-05-03 15:13:42 +05303360 if (msg->findInt32("secure-op", &value) && (value == 1)) {
3361 mCodec->mFlags |= kFlagIsSecureOPOnly;
3362 }
Shalaj Jain65506622013-01-29 18:27:08 -08003363
3364 AString mime;
3365 CHECK(msg->findString("mime", &mime));
3366
3367 status_t err = mCodec->configureCodec(mime.c_str(), msg);
3368
3369 if (err != OK) {
3370 ALOGE("[%s] configureCodec returning error %d",
3371 mCodec->mComponentName.c_str(), err);
3372
3373 mCodec->signalError(OMX_ErrorUndefined, err);
3374 return false;
3375 }
3376
3377 sp<RefBase> obj;
3378 if (msg->findObject("native-window", &obj)
3379 && strncmp("OMX.google.", mCodec->mComponentName.c_str(), 11)) {
3380 sp<NativeWindowWrapper> nativeWindow(
3381 static_cast<NativeWindowWrapper *>(obj.get()));
3382 CHECK(nativeWindow != NULL);
3383 mCodec->mNativeWindow = nativeWindow->getNativeWindow();
3384
3385 native_window_set_scaling_mode(
3386 mCodec->mNativeWindow.get(),
3387 NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
3388 }
3389 CHECK_EQ((status_t)OK, mCodec->initNativeWindow());
3390
3391 {
3392 sp<AMessage> notify = mCodec->mNotify->dup();
3393 notify->setInt32("what", DashCodec::kWhatComponentConfigured);
3394 notify->post();
3395 }
3396
3397 return true;
3398}
3399
3400void DashCodec::LoadedState::onStart() {
3401 ALOGV("onStart");
3402
3403 CHECK_EQ(mCodec->mOMX->sendCommand(
3404 mCodec->mNode, OMX_CommandStateSet, OMX_StateIdle),
3405 (status_t)OK);
3406
3407 mCodec->changeState(mCodec->mLoadedToIdleState);
3408}
3409
3410////////////////////////////////////////////////////////////////////////////////
3411
3412DashCodec::LoadedToIdleState::LoadedToIdleState(DashCodec *codec)
3413 : BaseState(codec) {
3414}
3415
3416void DashCodec::LoadedToIdleState::stateEntered() {
3417 ALOGV("[%s] Now Loaded->Idle", mCodec->mComponentName.c_str());
3418
3419 status_t err;
3420 if ((err = allocateBuffers()) != OK) {
3421 ALOGE("Failed to allocate buffers after transitioning to IDLE state "
3422 "(error 0x%08x)",
3423 err);
3424
3425 mCodec->signalError(OMX_ErrorUndefined, err);
3426
3427 mCodec->changeState(mCodec->mLoadedState);
3428 }
3429}
3430
3431status_t DashCodec::LoadedToIdleState::allocateBuffers() {
3432 status_t err = mCodec->allocateBuffersOnPort(kPortIndexInput);
3433
3434 if (err != OK) {
3435 return err;
3436 }
3437
3438 return mCodec->allocateBuffersOnPort(kPortIndexOutput);
3439}
3440
3441bool DashCodec::LoadedToIdleState::onMessageReceived(const sp<AMessage> &msg) {
3442 switch (msg->what()) {
3443 case kWhatShutdown:
3444 {
3445 mCodec->deferMessage(msg);
3446 return true;
3447 }
3448
3449 default:
3450 return BaseState::onMessageReceived(msg);
3451 }
3452}
3453
3454bool DashCodec::LoadedToIdleState::onOMXEvent(
3455 OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
3456 switch (event) {
3457 case OMX_EventCmdComplete:
3458 {
3459 CHECK_EQ(data1, (OMX_U32)OMX_CommandStateSet);
3460 CHECK_EQ(data2, (OMX_U32)OMX_StateIdle);
3461
3462 CHECK_EQ(mCodec->mOMX->sendCommand(
3463 mCodec->mNode, OMX_CommandStateSet, OMX_StateExecuting),
3464 (status_t)OK);
3465
3466 mCodec->changeState(mCodec->mIdleToExecutingState);
3467
3468 return true;
3469 }
3470
3471 default:
3472 return BaseState::onOMXEvent(event, data1, data2);
3473 }
3474}
3475
3476////////////////////////////////////////////////////////////////////////////////
3477
3478DashCodec::IdleToExecutingState::IdleToExecutingState(DashCodec *codec)
3479 : BaseState(codec) {
3480}
3481
3482void DashCodec::IdleToExecutingState::stateEntered() {
3483 ALOGV("[%s] Now Idle->Executing", mCodec->mComponentName.c_str());
3484}
3485
3486bool DashCodec::IdleToExecutingState::onMessageReceived(const sp<AMessage> &msg) {
3487 switch (msg->what()) {
3488 case kWhatShutdown:
3489 {
3490 mCodec->deferMessage(msg);
3491 return true;
3492 }
3493
3494 default:
3495 return BaseState::onMessageReceived(msg);
3496 }
3497}
3498
3499bool DashCodec::IdleToExecutingState::onOMXEvent(
3500 OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
3501 switch (event) {
3502 case OMX_EventCmdComplete:
3503 {
3504 CHECK_EQ(data1, (OMX_U32)OMX_CommandStateSet);
3505 CHECK_EQ(data2, (OMX_U32)OMX_StateExecuting);
3506
3507 mCodec->mExecutingState->resume();
3508 mCodec->changeState(mCodec->mExecutingState);
3509
3510 return true;
3511 }
3512
3513 default:
3514 return BaseState::onOMXEvent(event, data1, data2);
3515 }
3516}
3517
3518////////////////////////////////////////////////////////////////////////////////
3519
3520DashCodec::ExecutingState::ExecutingState(DashCodec *codec)
3521 : BaseState(codec),
3522 mActive(false) {
3523}
3524
3525DashCodec::BaseState::PortMode DashCodec::ExecutingState::getPortMode(
3526 OMX_U32 portIndex) {
3527 return RESUBMIT_BUFFERS;
3528}
3529
3530void DashCodec::ExecutingState::submitOutputBuffers() {
3531 for (size_t i = 0; i < mCodec->mBuffers[kPortIndexOutput].size(); ++i) {
3532 BufferInfo *info = &mCodec->mBuffers[kPortIndexOutput].editItemAt(i);
3533
3534 if (mCodec->mNativeWindow != NULL) {
3535 CHECK(info->mStatus == BufferInfo::OWNED_BY_US
3536 || info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW);
3537
3538 if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) {
3539 continue;
3540 }
3541 } else {
3542 CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
3543 }
3544
3545 ALOGV("[%s] calling fillBuffer %p",
3546 mCodec->mComponentName.c_str(), info->mBufferID);
3547
3548 CHECK_EQ(mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID),
3549 (status_t)OK);
3550
3551 info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
3552 }
3553}
3554
3555void DashCodec::ExecutingState::resume() {
3556 if (mActive) {
3557 ALOGV("[%s] We're already active, no need to resume.",
3558 mCodec->mComponentName.c_str());
3559
3560 return;
3561 }
3562
3563 submitOutputBuffers();
3564
3565 // Post the first input buffer.
3566 CHECK_GT(mCodec->mBuffers[kPortIndexInput].size(), 0u);
3567 BufferInfo *info = &mCodec->mBuffers[kPortIndexInput].editItemAt(0);
3568
3569 postFillThisBuffer(info);
3570
3571 mActive = true;
3572}
3573
3574void DashCodec::ExecutingState::stateEntered() {
3575 ALOGV("[%s] Now Executing", mCodec->mComponentName.c_str());
3576
3577 mCodec->processDeferredMessages();
3578}
3579
3580bool DashCodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) {
3581 bool handled = false;
3582
3583 switch (msg->what()) {
3584 case kWhatShutdown:
3585 {
3586 int32_t keepComponentAllocated;
3587 CHECK(msg->findInt32(
3588 "keepComponentAllocated", &keepComponentAllocated));
3589
3590 mCodec->mShutdownInProgress = true;
3591 mCodec->mKeepComponentAllocated = keepComponentAllocated;
3592
3593 mActive = false;
3594
3595 CHECK_EQ(mCodec->mOMX->sendCommand(
3596 mCodec->mNode, OMX_CommandStateSet, OMX_StateIdle),
3597 (status_t)OK);
3598
3599 mCodec->changeState(mCodec->mExecutingToIdleState);
3600
3601 handled = true;
3602 break;
3603 }
3604
3605 case kWhatFlush:
3606 {
3607 ALOGV("[%s] ExecutingState flushing now "
3608 "(codec owns %d/%d input, %d/%d output).",
3609 mCodec->mComponentName.c_str(),
3610 mCodec->countBuffersOwnedByComponent(kPortIndexInput),
3611 mCodec->mBuffers[kPortIndexInput].size(),
3612 mCodec->countBuffersOwnedByComponent(kPortIndexOutput),
3613 mCodec->mBuffers[kPortIndexOutput].size());
3614
3615 mActive = false;
3616
3617 CHECK_EQ(mCodec->mOMX->sendCommand(
3618 mCodec->mNode, OMX_CommandFlush, OMX_ALL),
3619 (status_t)OK);
3620
3621 mCodec->changeState(mCodec->mFlushingState);
Eric (Quicb4042f02013-04-17 11:00:01 -07003622 mCodec->clearCachedFormats();
Shalaj Jain65506622013-01-29 18:27:08 -08003623 handled = true;
3624 break;
3625 }
3626
3627 case kWhatResume:
3628 {
3629 resume();
3630
3631 handled = true;
3632 break;
3633 }
3634
3635 case kWhatRequestIDRFrame:
3636 {
3637 status_t err = mCodec->requestIDRFrame();
3638 if (err != OK) {
3639 ALOGW("Requesting an IDR frame failed.");
3640 }
3641
3642 handled = true;
3643 break;
3644 }
3645
3646 default:
3647 handled = BaseState::onMessageReceived(msg);
3648 break;
3649 }
3650
3651 return handled;
3652}
3653
3654bool DashCodec::ExecutingState::onOMXEvent(
3655 OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
3656 switch (event) {
3657 case OMX_EventPortSettingsChanged:
3658 {
3659 CHECK_EQ(data1, (OMX_U32)kPortIndexOutput);
3660
3661 if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
3662 ALOGV("Flush output port before disable");
3663 CHECK_EQ(mCodec->mOMX->sendCommand(
3664 mCodec->mNode, OMX_CommandFlush, kPortIndexOutput),
3665 (status_t)OK);
3666
3667 mCodec->changeState(mCodec->mFlushingOutputState);
3668
3669 } else if (data2 == OMX_IndexConfigCommonOutputCrop) {
3670 mCodec->mSentFormat = false;
Eric (Quicb4042f02013-04-17 11:00:01 -07003671 mCodec->mPostFormat = false;
3672 mCodec->queueNextFormat();
Shalaj Jain65506622013-01-29 18:27:08 -08003673 } else {
3674 ALOGV("[%s] OMX_EventPortSettingsChanged 0x%08lx",
3675 mCodec->mComponentName.c_str(), data2);
3676 }
3677
3678 return true;
3679 }
3680 case OMX_EventIndexsettingChanged:
3681 {
3682 ALOGW("[%s] Received OMX_EventIndexsettingChanged event ", mCodec->mComponentName.c_str());
3683 mCodec->mSentFormat = false;
3684 return true;
3685 }
3686 case OMX_EventBufferFlag:
3687 {
3688 return true;
3689 }
3690
3691 default:
3692 return BaseState::onOMXEvent(event, data1, data2);
3693 }
3694}
3695
3696////////////////////////////////////////////////////////////////////////////////
3697
3698DashCodec::OutputPortSettingsChangedState::OutputPortSettingsChangedState(
3699 DashCodec *codec)
3700 : BaseState(codec) {
3701}
3702
3703DashCodec::BaseState::PortMode DashCodec::OutputPortSettingsChangedState::getPortMode(
3704 OMX_U32 portIndex) {
3705 if (portIndex == kPortIndexOutput) {
3706 return FREE_BUFFERS;
3707 }
3708
3709 CHECK_EQ(portIndex, (OMX_U32)kPortIndexInput);
3710
3711 return RESUBMIT_BUFFERS;
3712}
3713
3714bool DashCodec::OutputPortSettingsChangedState::onMessageReceived(
3715 const sp<AMessage> &msg) {
3716 bool handled = false;
3717
3718 switch (msg->what()) {
3719 case kWhatFlush:
3720 case kWhatShutdown:
3721 case kWhatResume:
3722 {
3723 if (msg->what() == kWhatResume) {
3724 ALOGV("[%s] Deferring resume", mCodec->mComponentName.c_str());
3725 }
3726
3727 mCodec->deferMessage(msg);
3728 handled = true;
3729 break;
3730 }
3731
3732 default:
3733 handled = BaseState::onMessageReceived(msg);
3734 break;
3735 }
3736
3737 return handled;
3738}
3739
3740void DashCodec::OutputPortSettingsChangedState::stateEntered() {
3741 ALOGV("[%s] Now handling output port settings change",
3742 mCodec->mComponentName.c_str());
3743}
3744
3745bool DashCodec::OutputPortSettingsChangedState::onOMXEvent(
3746 OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
3747 switch (event) {
3748 case OMX_EventCmdComplete:
3749 {
3750 if (data1 == (OMX_U32)OMX_CommandPortDisable) {
3751 CHECK_EQ(data2, (OMX_U32)kPortIndexOutput);
3752
3753 ALOGV("[%s] Output port now disabled.",
3754 mCodec->mComponentName.c_str());
3755
3756 CHECK(mCodec->mBuffers[kPortIndexOutput].isEmpty());
3757 mCodec->mDealer[kPortIndexOutput].clear();
3758
3759 CHECK_EQ(mCodec->mOMX->sendCommand(
3760 mCodec->mNode, OMX_CommandPortEnable, kPortIndexOutput),
3761 (status_t)OK);
3762
3763 status_t err;
3764 if ((err = mCodec->allocateBuffersOnPort(
3765 kPortIndexOutput)) != OK) {
3766 ALOGE("Failed to allocate output port buffers after "
3767 "port reconfiguration (error 0x%08x)",
3768 err);
3769
3770 mCodec->signalError(OMX_ErrorUndefined, err);
3771
3772 // This is technically not correct, but appears to be
3773 // the only way to free the component instance.
3774 // Controlled transitioning from excecuting->idle
3775 // and idle->loaded seem impossible probably because
3776 // the output port never finishes re-enabling.
3777 mCodec->mShutdownInProgress = true;
3778 mCodec->mKeepComponentAllocated = false;
3779 mCodec->changeState(mCodec->mLoadedState);
3780 }
3781
3782 return true;
3783 } else if (data1 == (OMX_U32)OMX_CommandPortEnable) {
3784 CHECK_EQ(data2, (OMX_U32)kPortIndexOutput);
3785
3786 mCodec->mSentFormat = false;
3787
3788 ALOGV("[%s] Output port now reenabled.",
3789 mCodec->mComponentName.c_str());
3790
3791 if (mCodec->mExecutingState->active()) {
3792 mCodec->mExecutingState->submitOutputBuffers();
3793 }
3794
3795 mCodec->changeState(mCodec->mExecutingState);
3796
3797 return true;
3798 }
3799
3800 return false;
3801 }
3802
3803 default:
3804 return false;
3805 }
3806}
3807
3808////////////////////////////////////////////////////////////////////////////////
3809
3810DashCodec::ExecutingToIdleState::ExecutingToIdleState(DashCodec *codec)
3811 : BaseState(codec),
3812 mComponentNowIdle(false) {
3813}
3814
3815bool DashCodec::ExecutingToIdleState::onMessageReceived(const sp<AMessage> &msg) {
3816 bool handled = false;
3817
3818 switch (msg->what()) {
3819 case kWhatShutdown:
3820 {
3821 // We're already doing that...
3822
3823 handled = true;
3824 break;
3825 }
3826
3827 default:
3828 handled = BaseState::onMessageReceived(msg);
3829 break;
3830 }
3831
3832 return handled;
3833}
3834
3835void DashCodec::ExecutingToIdleState::stateEntered() {
3836 ALOGV("[%s] Now Executing->Idle", mCodec->mComponentName.c_str());
3837
3838 mComponentNowIdle = false;
3839 mCodec->mSentFormat = false;
3840}
3841
3842bool DashCodec::ExecutingToIdleState::onOMXEvent(
3843 OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
3844 switch (event) {
3845 case OMX_EventCmdComplete:
3846 {
3847 CHECK_EQ(data1, (OMX_U32)OMX_CommandStateSet);
3848 CHECK_EQ(data2, (OMX_U32)OMX_StateIdle);
3849
3850 mComponentNowIdle = true;
3851
3852 changeStateIfWeOwnAllBuffers();
3853
3854 return true;
3855 }
3856
3857 case OMX_EventPortSettingsChanged:
3858 case OMX_EventBufferFlag:
3859 {
3860 // We're shutting down and don't care about this anymore.
3861 return true;
3862 }
3863
3864 default:
3865 return BaseState::onOMXEvent(event, data1, data2);
3866 }
3867}
3868
3869void DashCodec::ExecutingToIdleState::changeStateIfWeOwnAllBuffers() {
3870 if (mComponentNowIdle && mCodec->allYourBuffersAreBelongToUs()) {
3871 CHECK_EQ(mCodec->mOMX->sendCommand(
3872 mCodec->mNode, OMX_CommandStateSet, OMX_StateLoaded),
3873 (status_t)OK);
3874
3875 CHECK_EQ(mCodec->freeBuffersOnPort(kPortIndexInput), (status_t)OK);
3876 CHECK_EQ(mCodec->freeBuffersOnPort(kPortIndexOutput), (status_t)OK);
3877
3878 if (mCodec->mFlags & kFlagIsSecure && mCodec->mNativeWindow != NULL) {
3879 // We push enough 1x1 blank buffers to ensure that one of
3880 // them has made it to the display. This allows the OMX
3881 // component teardown to zero out any protected buffers
3882 // without the risk of scanning out one of those buffers.
3883 mCodec->pushBlankBuffersToNativeWindow();
3884 }
3885
3886 mCodec->changeState(mCodec->mIdleToLoadedState);
3887 }
3888}
3889
3890void DashCodec::ExecutingToIdleState::onInputBufferFilled(
3891 const sp<AMessage> &msg) {
3892 BaseState::onInputBufferFilled(msg);
3893
3894 changeStateIfWeOwnAllBuffers();
3895}
3896
3897void DashCodec::ExecutingToIdleState::onOutputBufferDrained(
3898 const sp<AMessage> &msg) {
3899 BaseState::onOutputBufferDrained(msg);
3900
3901 changeStateIfWeOwnAllBuffers();
3902}
3903
3904////////////////////////////////////////////////////////////////////////////////
3905
3906DashCodec::IdleToLoadedState::IdleToLoadedState(DashCodec *codec)
3907 : BaseState(codec) {
3908}
3909
3910bool DashCodec::IdleToLoadedState::onMessageReceived(const sp<AMessage> &msg) {
3911 bool handled = false;
3912
3913 switch (msg->what()) {
3914 case kWhatShutdown:
3915 {
3916 // We're already doing that...
3917
3918 handled = true;
3919 break;
3920 }
3921
3922 default:
3923 handled = BaseState::onMessageReceived(msg);
3924 break;
3925 }
3926
3927 return handled;
3928}
3929
3930void DashCodec::IdleToLoadedState::stateEntered() {
3931 ALOGV("[%s] Now Idle->Loaded", mCodec->mComponentName.c_str());
3932}
3933
3934bool DashCodec::IdleToLoadedState::onOMXEvent(
3935 OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
3936 switch (event) {
3937 case OMX_EventCmdComplete:
3938 {
3939 CHECK_EQ(data1, (OMX_U32)OMX_CommandStateSet);
3940 CHECK_EQ(data2, (OMX_U32)OMX_StateLoaded);
3941
3942 mCodec->changeState(mCodec->mLoadedState);
3943
3944 return true;
3945 }
3946
3947 default:
3948 return BaseState::onOMXEvent(event, data1, data2);
3949 }
3950}
3951
3952////////////////////////////////////////////////////////////////////////////////
3953
3954DashCodec::FlushingState::FlushingState(DashCodec *codec)
3955 : BaseState(codec) {
3956}
3957
3958void DashCodec::FlushingState::stateEntered() {
3959 ALOGV("[%s] Now Flushing", mCodec->mComponentName.c_str());
3960
3961 mFlushComplete[kPortIndexInput] = mFlushComplete[kPortIndexOutput] = false;
3962}
3963
3964bool DashCodec::FlushingState::onMessageReceived(const sp<AMessage> &msg) {
3965 bool handled = false;
3966
3967 switch (msg->what()) {
3968 case kWhatShutdown:
3969 {
3970 mCodec->deferMessage(msg);
3971 break;
3972 }
3973
3974 case kWhatFlush:
3975 {
3976 // We're already doing this right now.
3977 handled = true;
3978 break;
3979 }
3980
3981 default:
3982 handled = BaseState::onMessageReceived(msg);
3983 break;
3984 }
3985
3986 return handled;
3987}
3988
3989bool DashCodec::FlushingState::onOMXEvent(
3990 OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
3991 ALOGV("[%s] FlushingState onOMXEvent(%d,%ld)",
3992 mCodec->mComponentName.c_str(), event, data1);
3993
3994 switch (event) {
3995 case OMX_EventCmdComplete:
3996 {
3997 CHECK_EQ(data1, (OMX_U32)OMX_CommandFlush);
3998
3999 if (data2 == kPortIndexInput || data2 == kPortIndexOutput) {
4000 CHECK(!mFlushComplete[data2]);
4001 mFlushComplete[data2] = true;
4002
4003 if (mFlushComplete[kPortIndexInput]
4004 && mFlushComplete[kPortIndexOutput]) {
4005 changeStateIfWeOwnAllBuffers();
4006 }
4007 } else {
4008 CHECK_EQ(data2, OMX_ALL);
4009 CHECK(mFlushComplete[kPortIndexInput]);
4010 CHECK(mFlushComplete[kPortIndexOutput]);
4011
4012 changeStateIfWeOwnAllBuffers();
4013 }
4014
4015 return true;
4016 }
4017
4018 case OMX_EventPortSettingsChanged:
4019 {
4020 sp<AMessage> msg = new AMessage(kWhatOMXMessage, mCodec->id());
4021 msg->setInt32("type", omx_message::EVENT);
4022 msg->setPointer("node", mCodec->mNode);
4023 msg->setInt32("event", event);
4024 msg->setInt32("data1", data1);
4025 msg->setInt32("data2", data2);
4026
4027 ALOGV("[%s] Deferring OMX_EventPortSettingsChanged",
4028 mCodec->mComponentName.c_str());
4029
4030 mCodec->deferMessage(msg);
4031
4032 return true;
4033 }
4034
4035 default:
4036 return BaseState::onOMXEvent(event, data1, data2);
4037 }
4038
4039 return true;
4040}
4041
4042void DashCodec::FlushingState::onOutputBufferDrained(const sp<AMessage> &msg) {
4043 BaseState::onOutputBufferDrained(msg);
4044
4045 changeStateIfWeOwnAllBuffers();
4046}
4047
4048void DashCodec::FlushingState::onInputBufferFilled(const sp<AMessage> &msg) {
4049 BaseState::onInputBufferFilled(msg);
4050
4051 changeStateIfWeOwnAllBuffers();
4052}
4053
4054void DashCodec::FlushingState::changeStateIfWeOwnAllBuffers() {
4055 if (mFlushComplete[kPortIndexInput]
4056 && mFlushComplete[kPortIndexOutput]
4057 && mCodec->allYourBuffersAreBelongToUs()) {
4058 sp<AMessage> notify = mCodec->mNotify->dup();
4059 notify->setInt32("what", DashCodec::kWhatFlushCompleted);
4060 notify->post();
4061
4062 mCodec->mPortEOS[kPortIndexInput] =
4063 mCodec->mPortEOS[kPortIndexOutput] = false;
4064
4065 mCodec->mInputEOSResult = OK;
4066
4067 mCodec->changeState(mCodec->mExecutingState);
4068 }
4069}
4070
4071////////////////////////////////////////////////////////////////////////////////
4072
4073DashCodec::FlushingOutputState::FlushingOutputState(DashCodec *codec)
4074 : BaseState(codec) {
4075}
4076
4077DashCodec::BaseState::PortMode DashCodec::FlushingOutputState::getPortMode(OMX_U32 portIndex) {
4078 if (portIndex == kPortIndexOutput)
4079 {
4080 return KEEP_BUFFERS;
4081 }
4082 return RESUBMIT_BUFFERS;
4083}
4084
4085void DashCodec::FlushingOutputState::stateEntered() {
4086 ALOGV("[%s] Now Flushing Output Port", mCodec->mComponentName.c_str());
4087
4088 mFlushComplete = false;
4089}
4090
4091bool DashCodec::FlushingOutputState::onMessageReceived(const sp<AMessage> &msg) {
4092 bool handled = false;
4093
4094 switch (msg->what()) {
4095 case kWhatShutdown:
4096 {
4097 mCodec->deferMessage(msg);
4098 handled = true;
4099 break;
4100 }
4101
4102 case kWhatFlush:
4103 {
4104 ALOGV("Flush received during port reconfig, deferring it");
4105 mCodec->deferMessage(msg);
4106 handled = true;
4107 break;
4108 }
4109
4110 case kWhatInputBufferFilled:
4111 {
4112 mCodec->deferMessage(msg);
4113 changeStateIfWeOwnAllBuffers();
4114 handled = true;
4115 break;
4116 }
4117
4118 default:
4119 handled = BaseState::onMessageReceived(msg);
4120 break;
4121 }
4122
4123 return handled;
4124}
4125
4126bool DashCodec::FlushingOutputState::onOMXEvent(
4127 OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
4128 switch (event) {
4129 case OMX_EventCmdComplete:
4130 {
4131 CHECK_EQ(data1, (OMX_U32)OMX_CommandFlush);
4132 CHECK_EQ(data2,(OMX_U32)kPortIndexOutput);
4133 ALOGV("FlushingOutputState::onOMXEvent Output port flush complete");
4134 mFlushComplete = true;
4135 changeStateIfWeOwnAllBuffers();
4136 return true;
4137 }
4138
4139 case OMX_EventPortSettingsChanged:
4140 {
4141 sp<AMessage> msg = new AMessage(kWhatOMXMessage, mCodec->id());
4142 msg->setInt32("type", omx_message::EVENT);
4143 msg->setPointer("node", mCodec->mNode);
4144 msg->setInt32("event", event);
4145 msg->setInt32("data1", data1);
4146 msg->setInt32("data2", data2);
4147
4148 ALOGV("[%s] Deferring OMX_EventPortSettingsChanged",
4149 mCodec->mComponentName.c_str());
4150
4151 mCodec->deferMessage(msg);
4152
4153 return true;
4154 }
4155
4156 default:
4157 return BaseState::onOMXEvent(event, data1, data2);
4158 }
4159
4160 return true;
4161}
4162
4163void DashCodec::FlushingOutputState::onOutputBufferDrained(const sp<AMessage> &msg) {
4164 BaseState::onOutputBufferDrained(msg);
4165
4166 changeStateIfWeOwnAllBuffers();
4167}
4168
4169void DashCodec::FlushingOutputState::onInputBufferFilled(const sp<AMessage> &msg) {
4170 BaseState::onInputBufferFilled(msg);
4171
4172 changeStateIfWeOwnAllBuffers();
4173}
4174
4175void DashCodec::FlushingOutputState::changeStateIfWeOwnAllBuffers() {
4176 ALOGV("FlushingOutputState::ChangeState %d",mFlushComplete);
4177
4178 if (mFlushComplete && mCodec->allYourBuffersAreBelongToUs( kPortIndexOutput )) {
4179 ALOGV("FlushingOutputState Sending port disable ");
4180 CHECK_EQ(mCodec->mOMX->sendCommand(
4181 mCodec->mNode,
4182 OMX_CommandPortDisable, kPortIndexOutput),
4183 (status_t)OK);
4184
4185 mCodec->mPortEOS[kPortIndexInput] = false;
4186 mCodec->mPortEOS[kPortIndexOutput] = false;
4187
4188 ALOGV("FlushingOutputState Calling freeOutputBuffersNotOwnedByComponent");
4189 mCodec->freeOutputBuffersNotOwnedByComponent();
4190
4191 ALOGV("FlushingOutputState Change state to port settings changed");
4192 mCodec->changeState(mCodec->mOutputPortSettingsChangedState);
4193 }
4194}
4195
4196} // namespace android