1 /*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "MediaCodec"
19 #include <inttypes.h>
20
21 #include "include/avc_utils.h"
22 #include "include/SecureBuffer.h"
23 #include "include/SharedMemoryBuffer.h"
24 #include "include/SoftwareRenderer.h"
25
26 #include <android/hardware/cas/native/1.0/IDescrambler.h>
27
28 #include <binder/IMemory.h>
29 #include <binder/IPCThreadState.h>
30 #include <binder/IServiceManager.h>
31 #include <binder/MemoryDealer.h>
32 #include <gui/BufferQueue.h>
33 #include <gui/Surface.h>
34 #include <media/ICrypto.h>
35 #include <media/IOMX.h>
36 #include <media/IResourceManagerService.h>
37 #include <media/MediaCodecBuffer.h>
38 #include <media/MediaAnalyticsItem.h>
39 #include <media/stagefright/foundation/ABuffer.h>
40 #include <media/stagefright/foundation/ADebug.h>
41 #include <media/stagefright/foundation/AMessage.h>
42 #include <media/stagefright/foundation/AString.h>
43 #include <media/stagefright/foundation/AUtils.h>
44 #include <media/stagefright/foundation/hexdump.h>
45 #include <media/stagefright/ACodec.h>
46 #include <media/stagefright/BufferProducerWrapper.h>
47 #include <media/stagefright/MediaCodec.h>
48 #include <media/stagefright/MediaCodecList.h>
49 #include <media/stagefright/MediaDefs.h>
50 #include <media/stagefright/MediaErrors.h>
51 #include <media/stagefright/MediaFilter.h>
52 #include <media/stagefright/MetaData.h>
53 #include <media/stagefright/OMXClient.h>
54 #include <media/stagefright/PersistentSurface.h>
55 #include <media/stagefright/SurfaceUtils.h>
56 #include <mediautils/BatteryNotifier.h>
57 #include <private/android_filesystem_config.h>
58 #include <utils/Log.h>
59 #include <utils/Singleton.h>
60
61 namespace android {
62
63 // key for media statistics
64 static const char *kCodecKeyName = "codec";
65 // attrs for media statistics
66 static const char *kCodecCodec = "android.media.mediacodec.codec"; /* e.g. OMX.google.aac.decoder */
67 static const char *kCodecMime = "android.media.mediacodec.mime"; /* e.g. audio/mime */
68 static const char *kCodecMode = "android.media.mediacodec.mode"; /* audio, video */
69 static const char *kCodecSecure = "android.media.mediacodec.secure"; /* 0, 1 */
70 static const char *kCodecHeight = "android.media.mediacodec.height"; /* 0..n */
71 static const char *kCodecWidth = "android.media.mediacodec.width"; /* 0..n */
72 static const char *kCodecRotation = "android.media.mediacodec.rotation-degrees"; /* 0/90/180/270 */
73 static const char *kCodecCrypto = "android.media.mediacodec.crypto"; /* 0,1 */
74 static const char *kCodecEncoder = "android.media.mediacodec.encoder"; /* 0,1 */
75
76 static const char *kCodecBytesIn = "android.media.mediacodec.bytesin"; /* 0..n */
77 static const char *kCodecProfile = "android.media.mediacodec.profile"; /* 0..n */
78 static const char *kCodecLevel = "android.media.mediacodec.level"; /* 0..n */
79 static const char *kCodecMaxWidth = "android.media.mediacodec.maxwidth"; /* 0..n */
80 static const char *kCodecMaxHeight = "android.media.mediacodec.maxheight"; /* 0..n */
81 static const char *kCodecError = "android.media.mediacodec.errcode";
82 static const char *kCodecErrorState = "android.media.mediacodec.errstate";
83
84
getId(const sp<IResourceManagerClient> & client)85 static int64_t getId(const sp<IResourceManagerClient> &client) {
86 return (int64_t) client.get();
87 }
88
isResourceError(status_t err)89 static bool isResourceError(status_t err) {
90 return (err == NO_MEMORY);
91 }
92
93 static const int kMaxRetry = 2;
94 static const int kMaxReclaimWaitTimeInUs = 500000; // 0.5s
95 static const int kNumBuffersAlign = 16;
96
97 ////////////////////////////////////////////////////////////////////////////////
98
99 struct ResourceManagerClient : public BnResourceManagerClient {
ResourceManagerClientandroid::ResourceManagerClient100 explicit ResourceManagerClient(MediaCodec* codec) : mMediaCodec(codec) {}
101
reclaimResourceandroid::ResourceManagerClient102 virtual bool reclaimResource() {
103 sp<MediaCodec> codec = mMediaCodec.promote();
104 if (codec == NULL) {
105 // codec is already gone.
106 return true;
107 }
108 status_t err = codec->reclaim();
109 if (err == WOULD_BLOCK) {
110 ALOGD("Wait for the client to release codec.");
111 usleep(kMaxReclaimWaitTimeInUs);
112 ALOGD("Try to reclaim again.");
113 err = codec->reclaim(true /* force */);
114 }
115 if (err != OK) {
116 ALOGW("ResourceManagerClient failed to release codec with err %d", err);
117 }
118 return (err == OK);
119 }
120
getNameandroid::ResourceManagerClient121 virtual String8 getName() {
122 String8 ret;
123 sp<MediaCodec> codec = mMediaCodec.promote();
124 if (codec == NULL) {
125 // codec is already gone.
126 return ret;
127 }
128
129 AString name;
130 if (codec->getName(&name) == OK) {
131 ret.setTo(name.c_str());
132 }
133 return ret;
134 }
135
136 protected:
~ResourceManagerClientandroid::ResourceManagerClient137 virtual ~ResourceManagerClient() {}
138
139 private:
140 wp<MediaCodec> mMediaCodec;
141
142 DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient);
143 };
144
ResourceManagerServiceProxy(pid_t pid)145 MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(pid_t pid)
146 : mPid(pid) {
147 if (mPid == MediaCodec::kNoPid) {
148 mPid = IPCThreadState::self()->getCallingPid();
149 }
150 }
151
~ResourceManagerServiceProxy()152 MediaCodec::ResourceManagerServiceProxy::~ResourceManagerServiceProxy() {
153 if (mService != NULL) {
154 IInterface::asBinder(mService)->unlinkToDeath(this);
155 }
156 }
157
init()158 void MediaCodec::ResourceManagerServiceProxy::init() {
159 sp<IServiceManager> sm = defaultServiceManager();
160 sp<IBinder> binder = sm->getService(String16("media.resource_manager"));
161 mService = interface_cast<IResourceManagerService>(binder);
162 if (mService == NULL) {
163 ALOGE("Failed to get ResourceManagerService");
164 return;
165 }
166 IInterface::asBinder(mService)->linkToDeath(this);
167 }
168
binderDied(const wp<IBinder> &)169 void MediaCodec::ResourceManagerServiceProxy::binderDied(const wp<IBinder>& /*who*/) {
170 ALOGW("ResourceManagerService died.");
171 Mutex::Autolock _l(mLock);
172 mService.clear();
173 }
174
addResource(int64_t clientId,const sp<IResourceManagerClient> & client,const Vector<MediaResource> & resources)175 void MediaCodec::ResourceManagerServiceProxy::addResource(
176 int64_t clientId,
177 const sp<IResourceManagerClient> &client,
178 const Vector<MediaResource> &resources) {
179 Mutex::Autolock _l(mLock);
180 if (mService == NULL) {
181 return;
182 }
183 mService->addResource(mPid, clientId, client, resources);
184 }
185
removeResource(int64_t clientId)186 void MediaCodec::ResourceManagerServiceProxy::removeResource(int64_t clientId) {
187 Mutex::Autolock _l(mLock);
188 if (mService == NULL) {
189 return;
190 }
191 mService->removeResource(mPid, clientId);
192 }
193
reclaimResource(const Vector<MediaResource> & resources)194 bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
195 const Vector<MediaResource> &resources) {
196 Mutex::Autolock _l(mLock);
197 if (mService == NULL) {
198 return false;
199 }
200 return mService->reclaimResource(mPid, resources);
201 }
202
203 ////////////////////////////////////////////////////////////////////////////////
204
BufferInfo()205 MediaCodec::BufferInfo::BufferInfo() : mOwnedByClient(false) {}
206
207 ////////////////////////////////////////////////////////////////////////////////
208
209 namespace {
210
211 enum {
212 kWhatFillThisBuffer = 'fill',
213 kWhatDrainThisBuffer = 'drai',
214 kWhatEOS = 'eos ',
215 kWhatStartCompleted = 'Scom',
216 kWhatStopCompleted = 'scom',
217 kWhatReleaseCompleted = 'rcom',
218 kWhatFlushCompleted = 'fcom',
219 kWhatError = 'erro',
220 kWhatComponentAllocated = 'cAll',
221 kWhatComponentConfigured = 'cCon',
222 kWhatInputSurfaceCreated = 'isfc',
223 kWhatInputSurfaceAccepted = 'isfa',
224 kWhatSignaledInputEOS = 'seos',
225 kWhatOutputFramesRendered = 'outR',
226 kWhatOutputBuffersChanged = 'outC',
227 };
228
229 class BufferCallback : public CodecBase::BufferCallback {
230 public:
231 explicit BufferCallback(const sp<AMessage> ¬ify);
232 virtual ~BufferCallback() = default;
233
234 virtual void onInputBufferAvailable(
235 size_t index, const sp<MediaCodecBuffer> &buffer) override;
236 virtual void onOutputBufferAvailable(
237 size_t index, const sp<MediaCodecBuffer> &buffer) override;
238 private:
239 const sp<AMessage> mNotify;
240 };
241
BufferCallback(const sp<AMessage> & notify)242 BufferCallback::BufferCallback(const sp<AMessage> ¬ify)
243 : mNotify(notify) {}
244
onInputBufferAvailable(size_t index,const sp<MediaCodecBuffer> & buffer)245 void BufferCallback::onInputBufferAvailable(
246 size_t index, const sp<MediaCodecBuffer> &buffer) {
247 sp<AMessage> notify(mNotify->dup());
248 notify->setInt32("what", kWhatFillThisBuffer);
249 notify->setSize("index", index);
250 notify->setObject("buffer", buffer);
251 notify->post();
252 }
253
onOutputBufferAvailable(size_t index,const sp<MediaCodecBuffer> & buffer)254 void BufferCallback::onOutputBufferAvailable(
255 size_t index, const sp<MediaCodecBuffer> &buffer) {
256 sp<AMessage> notify(mNotify->dup());
257 notify->setInt32("what", kWhatDrainThisBuffer);
258 notify->setSize("index", index);
259 notify->setObject("buffer", buffer);
260 notify->post();
261 }
262
263 class CodecCallback : public CodecBase::CodecCallback {
264 public:
265 explicit CodecCallback(const sp<AMessage> ¬ify);
266 virtual ~CodecCallback() = default;
267
268 virtual void onEos(status_t err) override;
269 virtual void onStartCompleted() override;
270 virtual void onStopCompleted() override;
271 virtual void onReleaseCompleted() override;
272 virtual void onFlushCompleted() override;
273 virtual void onError(status_t err, enum ActionCode actionCode) override;
274 virtual void onComponentAllocated(const char *componentName) override;
275 virtual void onComponentConfigured(
276 const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) override;
277 virtual void onInputSurfaceCreated(
278 const sp<AMessage> &inputFormat,
279 const sp<AMessage> &outputFormat,
280 const sp<BufferProducerWrapper> &inputSurface) override;
281 virtual void onInputSurfaceCreationFailed(status_t err) override;
282 virtual void onInputSurfaceAccepted(
283 const sp<AMessage> &inputFormat,
284 const sp<AMessage> &outputFormat) override;
285 virtual void onInputSurfaceDeclined(status_t err) override;
286 virtual void onSignaledInputEOS(status_t err) override;
287 virtual void onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) override;
288 virtual void onOutputBuffersChanged() override;
289 private:
290 const sp<AMessage> mNotify;
291 };
292
CodecCallback(const sp<AMessage> & notify)293 CodecCallback::CodecCallback(const sp<AMessage> ¬ify) : mNotify(notify) {}
294
onEos(status_t err)295 void CodecCallback::onEos(status_t err) {
296 sp<AMessage> notify(mNotify->dup());
297 notify->setInt32("what", kWhatEOS);
298 notify->setInt32("err", err);
299 notify->post();
300 }
301
onStartCompleted()302 void CodecCallback::onStartCompleted() {
303 sp<AMessage> notify(mNotify->dup());
304 notify->setInt32("what", kWhatStartCompleted);
305 notify->post();
306 }
307
onStopCompleted()308 void CodecCallback::onStopCompleted() {
309 sp<AMessage> notify(mNotify->dup());
310 notify->setInt32("what", kWhatStopCompleted);
311 notify->post();
312 }
313
onReleaseCompleted()314 void CodecCallback::onReleaseCompleted() {
315 sp<AMessage> notify(mNotify->dup());
316 notify->setInt32("what", kWhatReleaseCompleted);
317 notify->post();
318 }
319
onFlushCompleted()320 void CodecCallback::onFlushCompleted() {
321 sp<AMessage> notify(mNotify->dup());
322 notify->setInt32("what", kWhatFlushCompleted);
323 notify->post();
324 }
325
onError(status_t err,enum ActionCode actionCode)326 void CodecCallback::onError(status_t err, enum ActionCode actionCode) {
327 sp<AMessage> notify(mNotify->dup());
328 notify->setInt32("what", kWhatError);
329 notify->setInt32("err", err);
330 notify->setInt32("actionCode", actionCode);
331 notify->post();
332 }
333
onComponentAllocated(const char * componentName)334 void CodecCallback::onComponentAllocated(const char *componentName) {
335 sp<AMessage> notify(mNotify->dup());
336 notify->setInt32("what", kWhatComponentAllocated);
337 notify->setString("componentName", componentName);
338 notify->post();
339 }
340
onComponentConfigured(const sp<AMessage> & inputFormat,const sp<AMessage> & outputFormat)341 void CodecCallback::onComponentConfigured(
342 const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) {
343 sp<AMessage> notify(mNotify->dup());
344 notify->setInt32("what", kWhatComponentConfigured);
345 notify->setMessage("input-format", inputFormat);
346 notify->setMessage("output-format", outputFormat);
347 notify->post();
348 }
349
onInputSurfaceCreated(const sp<AMessage> & inputFormat,const sp<AMessage> & outputFormat,const sp<BufferProducerWrapper> & inputSurface)350 void CodecCallback::onInputSurfaceCreated(
351 const sp<AMessage> &inputFormat,
352 const sp<AMessage> &outputFormat,
353 const sp<BufferProducerWrapper> &inputSurface) {
354 sp<AMessage> notify(mNotify->dup());
355 notify->setInt32("what", kWhatInputSurfaceCreated);
356 notify->setMessage("input-format", inputFormat);
357 notify->setMessage("output-format", outputFormat);
358 notify->setObject("input-surface", inputSurface);
359 notify->post();
360 }
361
onInputSurfaceCreationFailed(status_t err)362 void CodecCallback::onInputSurfaceCreationFailed(status_t err) {
363 sp<AMessage> notify(mNotify->dup());
364 notify->setInt32("what", kWhatInputSurfaceCreated);
365 notify->setInt32("err", err);
366 notify->post();
367 }
368
onInputSurfaceAccepted(const sp<AMessage> & inputFormat,const sp<AMessage> & outputFormat)369 void CodecCallback::onInputSurfaceAccepted(
370 const sp<AMessage> &inputFormat,
371 const sp<AMessage> &outputFormat) {
372 sp<AMessage> notify(mNotify->dup());
373 notify->setInt32("what", kWhatInputSurfaceAccepted);
374 notify->setMessage("input-format", inputFormat);
375 notify->setMessage("output-format", outputFormat);
376 notify->post();
377 }
378
onInputSurfaceDeclined(status_t err)379 void CodecCallback::onInputSurfaceDeclined(status_t err) {
380 sp<AMessage> notify(mNotify->dup());
381 notify->setInt32("what", kWhatInputSurfaceAccepted);
382 notify->setInt32("err", err);
383 notify->post();
384 }
385
onSignaledInputEOS(status_t err)386 void CodecCallback::onSignaledInputEOS(status_t err) {
387 sp<AMessage> notify(mNotify->dup());
388 notify->setInt32("what", kWhatSignaledInputEOS);
389 if (err != OK) {
390 notify->setInt32("err", err);
391 }
392 notify->post();
393 }
394
onOutputFramesRendered(const std::list<FrameRenderTracker::Info> & done)395 void CodecCallback::onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) {
396 sp<AMessage> notify(mNotify->dup());
397 notify->setInt32("what", kWhatOutputFramesRendered);
398 if (MediaCodec::CreateFramesRenderedMessage(done, notify)) {
399 notify->post();
400 }
401 }
402
onOutputBuffersChanged()403 void CodecCallback::onOutputBuffersChanged() {
404 sp<AMessage> notify(mNotify->dup());
405 notify->setInt32("what", kWhatOutputBuffersChanged);
406 notify->post();
407 }
408
409 } // namespace
410
411 ////////////////////////////////////////////////////////////////////////////////
412
413 // static
CreateByType(const sp<ALooper> & looper,const AString & mime,bool encoder,status_t * err,pid_t pid,uid_t uid)414 sp<MediaCodec> MediaCodec::CreateByType(
415 const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid,
416 uid_t uid) {
417 sp<MediaCodec> codec = new MediaCodec(looper, pid, uid);
418
419 const status_t ret = codec->init(mime, true /* nameIsType */, encoder);
420 if (err != NULL) {
421 *err = ret;
422 }
423 return ret == OK ? codec : NULL; // NULL deallocates codec.
424 }
425
426 // static
CreateByComponentName(const sp<ALooper> & looper,const AString & name,status_t * err,pid_t pid,uid_t uid)427 sp<MediaCodec> MediaCodec::CreateByComponentName(
428 const sp<ALooper> &looper, const AString &name, status_t *err, pid_t pid, uid_t uid) {
429 sp<MediaCodec> codec = new MediaCodec(looper, pid, uid);
430
431 const status_t ret = codec->init(name, false /* nameIsType */, false /* encoder */);
432 if (err != NULL) {
433 *err = ret;
434 }
435 return ret == OK ? codec : NULL; // NULL deallocates codec.
436 }
437
438 // static
CreatePersistentInputSurface()439 sp<PersistentSurface> MediaCodec::CreatePersistentInputSurface() {
440 OMXClient client;
441 if (client.connect() != OK) {
442 ALOGE("Failed to connect to OMX to create persistent input surface.");
443 return NULL;
444 }
445
446 sp<IOMX> omx = client.interface();
447
448 sp<IGraphicBufferProducer> bufferProducer;
449 sp<IGraphicBufferSource> bufferSource;
450
451 status_t err = omx->createInputSurface(&bufferProducer, &bufferSource);
452
453 if (err != OK) {
454 ALOGE("Failed to create persistent input surface.");
455 return NULL;
456 }
457
458 return new PersistentSurface(bufferProducer, bufferSource);
459 }
460
MediaCodec(const sp<ALooper> & looper,pid_t pid,uid_t uid)461 MediaCodec::MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid)
462 : mState(UNINITIALIZED),
463 mReleasedByResourceManager(false),
464 mLooper(looper),
465 mCodec(NULL),
466 mReplyID(0),
467 mFlags(0),
468 mStickyError(OK),
469 mSoftRenderer(NULL),
470 mAnalyticsItem(NULL),
471 mResourceManagerClient(new ResourceManagerClient(this)),
472 mResourceManagerService(new ResourceManagerServiceProxy(pid)),
473 mBatteryStatNotified(false),
474 mIsVideo(false),
475 mVideoWidth(0),
476 mVideoHeight(0),
477 mRotationDegrees(0),
478 mDequeueInputTimeoutGeneration(0),
479 mDequeueInputReplyID(0),
480 mDequeueOutputTimeoutGeneration(0),
481 mDequeueOutputReplyID(0),
482 mHaveInputSurface(false),
483 mHavePendingInputBuffers(false) {
484 if (uid == kNoUid) {
485 mUid = IPCThreadState::self()->getCallingUid();
486 } else {
487 mUid = uid;
488 }
489 initAnalyticsItem();
490 }
491
~MediaCodec()492 MediaCodec::~MediaCodec() {
493 CHECK_EQ(mState, UNINITIALIZED);
494 mResourceManagerService->removeResource(getId(mResourceManagerClient));
495
496 flushAnalyticsItem();
497 }
498
initAnalyticsItem()499 void MediaCodec::initAnalyticsItem() {
500 CHECK(mAnalyticsItem == NULL);
501 // set up our new record, get a sessionID, put it into the in-progress list
502 mAnalyticsItem = new MediaAnalyticsItem(kCodecKeyName);
503 if (mAnalyticsItem != NULL) {
504 (void) mAnalyticsItem->generateSessionID();
505 // don't record it yet; only at the end, when we have decided that we have
506 // data worth writing (e.g. .count() > 0)
507 }
508 }
509
flushAnalyticsItem()510 void MediaCodec::flushAnalyticsItem() {
511 if (mAnalyticsItem != NULL) {
512 // don't log empty records
513 if (mAnalyticsItem->count() > 0) {
514 mAnalyticsItem->setFinalized(true);
515 mAnalyticsItem->selfrecord();
516 }
517 delete mAnalyticsItem;
518 mAnalyticsItem = NULL;
519 }
520 }
521
522 // static
PostAndAwaitResponse(const sp<AMessage> & msg,sp<AMessage> * response)523 status_t MediaCodec::PostAndAwaitResponse(
524 const sp<AMessage> &msg, sp<AMessage> *response) {
525 status_t err = msg->postAndAwaitResponse(response);
526
527 if (err != OK) {
528 return err;
529 }
530
531 if (!(*response)->findInt32("err", &err)) {
532 err = OK;
533 }
534
535 return err;
536 }
537
PostReplyWithError(const sp<AReplyToken> & replyID,int32_t err)538 void MediaCodec::PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err) {
539 int32_t finalErr = err;
540 if (mReleasedByResourceManager) {
541 // override the err code if MediaCodec has been released by ResourceManager.
542 finalErr = DEAD_OBJECT;
543 }
544
545 sp<AMessage> response = new AMessage;
546 response->setInt32("err", finalErr);
547 response->postReply(replyID);
548 }
549
550 //static
GetCodecBase(const AString & name,bool nameIsType)551 sp<CodecBase> MediaCodec::GetCodecBase(const AString &name, bool nameIsType) {
552 // at this time only ACodec specifies a mime type.
553 if (nameIsType || name.startsWithIgnoreCase("omx.")) {
554 return new ACodec;
555 } else if (name.startsWithIgnoreCase("android.filter.")) {
556 return new MediaFilter;
557 } else {
558 return NULL;
559 }
560 }
561
init(const AString & name,bool nameIsType,bool encoder)562 status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder) {
563 mResourceManagerService->init();
564
565 // save init parameters for reset
566 mInitName = name;
567 mInitNameIsType = nameIsType;
568 mInitIsEncoder = encoder;
569
570 // Current video decoders do not return from OMX_FillThisBuffer
571 // quickly, violating the OpenMAX specs, until that is remedied
572 // we need to invest in an extra looper to free the main event
573 // queue.
574
575 mCodec = GetCodecBase(name, nameIsType);
576 if (mCodec == NULL) {
577 return NAME_NOT_FOUND;
578 }
579
580 bool secureCodec = false;
581 if (nameIsType && !strncasecmp(name.c_str(), "video/", 6)) {
582 mIsVideo = true;
583 } else {
584 AString tmp = name;
585 if (tmp.endsWith(".secure")) {
586 secureCodec = true;
587 tmp.erase(tmp.size() - 7, 7);
588 }
589 const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
590 if (mcl == NULL) {
591 mCodec = NULL; // remove the codec.
592 return NO_INIT; // if called from Java should raise IOException
593 }
594 ssize_t codecIdx = mcl->findCodecByName(tmp.c_str());
595 if (codecIdx >= 0) {
596 const sp<MediaCodecInfo> info = mcl->getCodecInfo(codecIdx);
597 Vector<AString> mimes;
598 info->getSupportedMimes(&mimes);
599 for (size_t i = 0; i < mimes.size(); i++) {
600 if (mimes[i].startsWith("video/")) {
601 mIsVideo = true;
602 break;
603 }
604 }
605 }
606 }
607
608 if (mIsVideo) {
609 // video codec needs dedicated looper
610 if (mCodecLooper == NULL) {
611 mCodecLooper = new ALooper;
612 mCodecLooper->setName("CodecLooper");
613 mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
614 }
615
616 mCodecLooper->registerHandler(mCodec);
617 } else {
618 mLooper->registerHandler(mCodec);
619 }
620
621 mLooper->registerHandler(this);
622
623 mCodec->setCallback(
624 std::unique_ptr<CodecBase::CodecCallback>(
625 new CodecCallback(new AMessage(kWhatCodecNotify, this))));
626 mBufferChannel = mCodec->getBufferChannel();
627 mBufferChannel->setCallback(
628 std::unique_ptr<CodecBase::BufferCallback>(
629 new BufferCallback(new AMessage(kWhatCodecNotify, this))));
630
631 sp<AMessage> msg = new AMessage(kWhatInit, this);
632 msg->setString("name", name);
633 msg->setInt32("nameIsType", nameIsType);
634
635 if (nameIsType) {
636 msg->setInt32("encoder", encoder);
637 }
638
639 if (mAnalyticsItem != NULL) {
640 if (nameIsType) {
641 // name is the mime type
642 mAnalyticsItem->setCString(kCodecMime, name.c_str());
643 } else {
644 mAnalyticsItem->setCString(kCodecCodec, name.c_str());
645 }
646 mAnalyticsItem->setCString(kCodecMode, mIsVideo ? "video" : "audio");
647 if (nameIsType)
648 mAnalyticsItem->setInt32(kCodecEncoder, encoder);
649 }
650
651 status_t err;
652 Vector<MediaResource> resources;
653 MediaResource::Type type =
654 secureCodec ? MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
655 MediaResource::SubType subtype =
656 mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
657 resources.push_back(MediaResource(type, subtype, 1));
658 for (int i = 0; i <= kMaxRetry; ++i) {
659 if (i > 0) {
660 // Don't try to reclaim resource for the first time.
661 if (!mResourceManagerService->reclaimResource(resources)) {
662 break;
663 }
664 }
665
666 sp<AMessage> response;
667 err = PostAndAwaitResponse(msg, &response);
668 if (!isResourceError(err)) {
669 break;
670 }
671 }
672 return err;
673 }
674
setCallback(const sp<AMessage> & callback)675 status_t MediaCodec::setCallback(const sp<AMessage> &callback) {
676 sp<AMessage> msg = new AMessage(kWhatSetCallback, this);
677 msg->setMessage("callback", callback);
678
679 sp<AMessage> response;
680 return PostAndAwaitResponse(msg, &response);
681 }
682
setOnFrameRenderedNotification(const sp<AMessage> & notify)683 status_t MediaCodec::setOnFrameRenderedNotification(const sp<AMessage> ¬ify) {
684 sp<AMessage> msg = new AMessage(kWhatSetNotification, this);
685 msg->setMessage("on-frame-rendered", notify);
686 return msg->post();
687 }
688
configure(const sp<AMessage> & format,const sp<Surface> & nativeWindow,const sp<ICrypto> & crypto,uint32_t flags)689 status_t MediaCodec::configure(
690 const sp<AMessage> &format,
691 const sp<Surface> &nativeWindow,
692 const sp<ICrypto> &crypto,
693 uint32_t flags) {
694 return configure(format, nativeWindow, crypto, NULL, flags);
695 }
696
configure(const sp<AMessage> & format,const sp<Surface> & surface,const sp<ICrypto> & crypto,const sp<IDescrambler> & descrambler,uint32_t flags)697 status_t MediaCodec::configure(
698 const sp<AMessage> &format,
699 const sp<Surface> &surface,
700 const sp<ICrypto> &crypto,
701 const sp<IDescrambler> &descrambler,
702 uint32_t flags) {
703 sp<AMessage> msg = new AMessage(kWhatConfigure, this);
704
705 if (mAnalyticsItem != NULL) {
706 int32_t profile = 0;
707 if (format->findInt32("profile", &profile)) {
708 mAnalyticsItem->setInt32(kCodecProfile, profile);
709 }
710 int32_t level = 0;
711 if (format->findInt32("level", &level)) {
712 mAnalyticsItem->setInt32(kCodecLevel, level);
713 }
714 }
715
716 if (mIsVideo) {
717 format->findInt32("width", &mVideoWidth);
718 format->findInt32("height", &mVideoHeight);
719 if (!format->findInt32("rotation-degrees", &mRotationDegrees)) {
720 mRotationDegrees = 0;
721 }
722
723 if (mAnalyticsItem != NULL) {
724 mAnalyticsItem->setInt32(kCodecWidth, mVideoWidth);
725 mAnalyticsItem->setInt32(kCodecHeight, mVideoHeight);
726 mAnalyticsItem->setInt32(kCodecRotation, mRotationDegrees);
727 int32_t maxWidth = 0;
728 if (format->findInt32("max-width", &maxWidth)) {
729 mAnalyticsItem->setInt32(kCodecMaxWidth, maxWidth);
730 }
731 int32_t maxHeight = 0;
732 if (format->findInt32("max-height", &maxHeight)) {
733 mAnalyticsItem->setInt32(kCodecMaxHeight, maxHeight);
734 }
735 }
736
737 // Prevent possible integer overflow in downstream code.
738 if (mInitIsEncoder
739 && (uint64_t)mVideoWidth * mVideoHeight > (uint64_t)INT32_MAX / 4) {
740 ALOGE("buffer size is too big, width=%d, height=%d", mVideoWidth, mVideoHeight);
741 return BAD_VALUE;
742 }
743 }
744
745 msg->setMessage("format", format);
746 msg->setInt32("flags", flags);
747 msg->setObject("surface", surface);
748
749 if (crypto != NULL || descrambler != NULL) {
750 if (crypto != NULL) {
751 msg->setPointer("crypto", crypto.get());
752 } else {
753 msg->setPointer("descrambler", descrambler.get());
754 }
755 if (mAnalyticsItem != NULL) {
756 // XXX: save indication that it's crypto in some way...
757 mAnalyticsItem->setInt32(kCodecCrypto, 1);
758 }
759 } else if (mFlags & kFlagIsSecure) {
760 ALOGW("Crypto or descrambler should be given for secure codec");
761 }
762
763 // save msg for reset
764 mConfigureMsg = msg;
765
766 status_t err;
767 Vector<MediaResource> resources;
768 MediaResource::Type type = (mFlags & kFlagIsSecure) ?
769 MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
770 MediaResource::SubType subtype =
771 mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
772 resources.push_back(MediaResource(type, subtype, 1));
773 // Don't know the buffer size at this point, but it's fine to use 1 because
774 // the reclaimResource call doesn't consider the requester's buffer size for now.
775 resources.push_back(MediaResource(MediaResource::kGraphicMemory, 1));
776 for (int i = 0; i <= kMaxRetry; ++i) {
777 if (i > 0) {
778 // Don't try to reclaim resource for the first time.
779 if (!mResourceManagerService->reclaimResource(resources)) {
780 break;
781 }
782 }
783
784 sp<AMessage> response;
785 err = PostAndAwaitResponse(msg, &response);
786 if (err != OK && err != INVALID_OPERATION) {
787 // MediaCodec now set state to UNINITIALIZED upon any fatal error.
788 // To maintain backward-compatibility, do a reset() to put codec
789 // back into INITIALIZED state.
790 // But don't reset if the err is INVALID_OPERATION, which means
791 // the configure failure is due to wrong state.
792
793 ALOGE("configure failed with err 0x%08x, resetting...", err);
794 reset();
795 }
796 if (!isResourceError(err)) {
797 break;
798 }
799 }
800 return err;
801 }
802
releaseCrypto()803 status_t MediaCodec::releaseCrypto()
804 {
805 ALOGV("releaseCrypto");
806
807 sp<AMessage> msg = new AMessage(kWhatDrmReleaseCrypto, this);
808
809 sp<AMessage> response;
810 status_t status = msg->postAndAwaitResponse(&response);
811
812 if (status == OK && response != NULL) {
813 CHECK(response->findInt32("status", &status));
814 ALOGV("releaseCrypto ret: %d ", status);
815 }
816 else {
817 ALOGE("releaseCrypto err: %d", status);
818 }
819
820 return status;
821 }
822
onReleaseCrypto(const sp<AMessage> & msg)823 void MediaCodec::onReleaseCrypto(const sp<AMessage>& msg)
824 {
825 status_t status = INVALID_OPERATION;
826 if (mCrypto != NULL) {
827 ALOGV("onReleaseCrypto: mCrypto: %p (%d)", mCrypto.get(), mCrypto->getStrongCount());
828 mBufferChannel->setCrypto(NULL);
829 // TODO change to ALOGV
830 ALOGD("onReleaseCrypto: [before clear] mCrypto: %p (%d)",
831 mCrypto.get(), mCrypto->getStrongCount());
832 mCrypto.clear();
833
834 status = OK;
835 }
836 else {
837 ALOGW("onReleaseCrypto: No mCrypto. err: %d", status);
838 }
839
840 sp<AMessage> response = new AMessage;
841 response->setInt32("status", status);
842
843 sp<AReplyToken> replyID;
844 CHECK(msg->senderAwaitsResponse(&replyID));
845 response->postReply(replyID);
846 }
847
setInputSurface(const sp<PersistentSurface> & surface)848 status_t MediaCodec::setInputSurface(
849 const sp<PersistentSurface> &surface) {
850 sp<AMessage> msg = new AMessage(kWhatSetInputSurface, this);
851 msg->setObject("input-surface", surface.get());
852
853 sp<AMessage> response;
854 return PostAndAwaitResponse(msg, &response);
855 }
856
setSurface(const sp<Surface> & surface)857 status_t MediaCodec::setSurface(const sp<Surface> &surface) {
858 sp<AMessage> msg = new AMessage(kWhatSetSurface, this);
859 msg->setObject("surface", surface);
860
861 sp<AMessage> response;
862 return PostAndAwaitResponse(msg, &response);
863 }
864
createInputSurface(sp<IGraphicBufferProducer> * bufferProducer)865 status_t MediaCodec::createInputSurface(
866 sp<IGraphicBufferProducer>* bufferProducer) {
867 sp<AMessage> msg = new AMessage(kWhatCreateInputSurface, this);
868
869 sp<AMessage> response;
870 status_t err = PostAndAwaitResponse(msg, &response);
871 if (err == NO_ERROR) {
872 // unwrap the sp<IGraphicBufferProducer>
873 sp<RefBase> obj;
874 bool found = response->findObject("input-surface", &obj);
875 CHECK(found);
876 sp<BufferProducerWrapper> wrapper(
877 static_cast<BufferProducerWrapper*>(obj.get()));
878 *bufferProducer = wrapper->getBufferProducer();
879 } else {
880 ALOGW("createInputSurface failed, err=%d", err);
881 }
882 return err;
883 }
884
getGraphicBufferSize()885 uint64_t MediaCodec::getGraphicBufferSize() {
886 if (!mIsVideo) {
887 return 0;
888 }
889
890 uint64_t size = 0;
891 size_t portNum = sizeof(mPortBuffers) / sizeof((mPortBuffers)[0]);
892 for (size_t i = 0; i < portNum; ++i) {
893 // TODO: this is just an estimation, we should get the real buffer size from ACodec.
894 size += mPortBuffers[i].size() * mVideoWidth * mVideoHeight * 3 / 2;
895 }
896 return size;
897 }
898
addResource(MediaResource::Type type,MediaResource::SubType subtype,uint64_t value)899 void MediaCodec::addResource(
900 MediaResource::Type type, MediaResource::SubType subtype, uint64_t value) {
901 Vector<MediaResource> resources;
902 resources.push_back(MediaResource(type, subtype, value));
903 mResourceManagerService->addResource(
904 getId(mResourceManagerClient), mResourceManagerClient, resources);
905 }
906
start()907 status_t MediaCodec::start() {
908 sp<AMessage> msg = new AMessage(kWhatStart, this);
909
910 status_t err;
911 Vector<MediaResource> resources;
912 MediaResource::Type type = (mFlags & kFlagIsSecure) ?
913 MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
914 MediaResource::SubType subtype =
915 mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
916 resources.push_back(MediaResource(type, subtype, 1));
917 // Don't know the buffer size at this point, but it's fine to use 1 because
918 // the reclaimResource call doesn't consider the requester's buffer size for now.
919 resources.push_back(MediaResource(MediaResource::kGraphicMemory, 1));
920 for (int i = 0; i <= kMaxRetry; ++i) {
921 if (i > 0) {
922 // Don't try to reclaim resource for the first time.
923 if (!mResourceManagerService->reclaimResource(resources)) {
924 break;
925 }
926 // Recover codec from previous error before retry start.
927 err = reset();
928 if (err != OK) {
929 ALOGE("retrying start: failed to reset codec");
930 break;
931 }
932 sp<AMessage> response;
933 err = PostAndAwaitResponse(mConfigureMsg, &response);
934 if (err != OK) {
935 ALOGE("retrying start: failed to configure codec");
936 break;
937 }
938 }
939
940 sp<AMessage> response;
941 err = PostAndAwaitResponse(msg, &response);
942 if (!isResourceError(err)) {
943 break;
944 }
945 }
946 return err;
947 }
948
stop()949 status_t MediaCodec::stop() {
950 sp<AMessage> msg = new AMessage(kWhatStop, this);
951
952 sp<AMessage> response;
953 return PostAndAwaitResponse(msg, &response);
954 }
955
hasPendingBuffer(int portIndex)956 bool MediaCodec::hasPendingBuffer(int portIndex) {
957 return std::any_of(
958 mPortBuffers[portIndex].begin(), mPortBuffers[portIndex].end(),
959 [](const BufferInfo &info) { return info.mOwnedByClient; });
960 }
961
hasPendingBuffer()962 bool MediaCodec::hasPendingBuffer() {
963 return hasPendingBuffer(kPortIndexInput) || hasPendingBuffer(kPortIndexOutput);
964 }
965
reclaim(bool force)966 status_t MediaCodec::reclaim(bool force) {
967 ALOGD("MediaCodec::reclaim(%p) %s", this, mInitName.c_str());
968 sp<AMessage> msg = new AMessage(kWhatRelease, this);
969 msg->setInt32("reclaimed", 1);
970 msg->setInt32("force", force ? 1 : 0);
971
972 sp<AMessage> response;
973 status_t ret = PostAndAwaitResponse(msg, &response);
974 if (ret == -ENOENT) {
975 ALOGD("MediaCodec looper is gone, skip reclaim");
976 ret = OK;
977 }
978 return ret;
979 }
980
release()981 status_t MediaCodec::release() {
982 sp<AMessage> msg = new AMessage(kWhatRelease, this);
983
984 sp<AMessage> response;
985 return PostAndAwaitResponse(msg, &response);
986 }
987
reset()988 status_t MediaCodec::reset() {
989 /* When external-facing MediaCodec object is created,
990 it is already initialized. Thus, reset is essentially
991 release() followed by init(), plus clearing the state */
992
993 status_t err = release();
994
995 // unregister handlers
996 if (mCodec != NULL) {
997 if (mCodecLooper != NULL) {
998 mCodecLooper->unregisterHandler(mCodec->id());
999 } else {
1000 mLooper->unregisterHandler(mCodec->id());
1001 }
1002 mCodec = NULL;
1003 }
1004 mLooper->unregisterHandler(id());
1005
1006 mFlags = 0; // clear all flags
1007 mStickyError = OK;
1008
1009 // reset state not reset by setState(UNINITIALIZED)
1010 mReplyID = 0;
1011 mDequeueInputReplyID = 0;
1012 mDequeueOutputReplyID = 0;
1013 mDequeueInputTimeoutGeneration = 0;
1014 mDequeueOutputTimeoutGeneration = 0;
1015 mHaveInputSurface = false;
1016
1017 if (err == OK) {
1018 err = init(mInitName, mInitNameIsType, mInitIsEncoder);
1019 }
1020 return err;
1021 }
1022
queueInputBuffer(size_t index,size_t offset,size_t size,int64_t presentationTimeUs,uint32_t flags,AString * errorDetailMsg)1023 status_t MediaCodec::queueInputBuffer(
1024 size_t index,
1025 size_t offset,
1026 size_t size,
1027 int64_t presentationTimeUs,
1028 uint32_t flags,
1029 AString *errorDetailMsg) {
1030 if (errorDetailMsg != NULL) {
1031 errorDetailMsg->clear();
1032 }
1033
1034 sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
1035 msg->setSize("index", index);
1036 msg->setSize("offset", offset);
1037 msg->setSize("size", size);
1038 msg->setInt64("timeUs", presentationTimeUs);
1039 msg->setInt32("flags", flags);
1040 msg->setPointer("errorDetailMsg", errorDetailMsg);
1041
1042 sp<AMessage> response;
1043 return PostAndAwaitResponse(msg, &response);
1044 }
1045
queueSecureInputBuffer(size_t index,size_t offset,const CryptoPlugin::SubSample * subSamples,size_t numSubSamples,const uint8_t key[16],const uint8_t iv[16],CryptoPlugin::Mode mode,const CryptoPlugin::Pattern & pattern,int64_t presentationTimeUs,uint32_t flags,AString * errorDetailMsg)1046 status_t MediaCodec::queueSecureInputBuffer(
1047 size_t index,
1048 size_t offset,
1049 const CryptoPlugin::SubSample *subSamples,
1050 size_t numSubSamples,
1051 const uint8_t key[16],
1052 const uint8_t iv[16],
1053 CryptoPlugin::Mode mode,
1054 const CryptoPlugin::Pattern &pattern,
1055 int64_t presentationTimeUs,
1056 uint32_t flags,
1057 AString *errorDetailMsg) {
1058 if (errorDetailMsg != NULL) {
1059 errorDetailMsg->clear();
1060 }
1061
1062 sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
1063 msg->setSize("index", index);
1064 msg->setSize("offset", offset);
1065 msg->setPointer("subSamples", (void *)subSamples);
1066 msg->setSize("numSubSamples", numSubSamples);
1067 msg->setPointer("key", (void *)key);
1068 msg->setPointer("iv", (void *)iv);
1069 msg->setInt32("mode", mode);
1070 msg->setInt32("encryptBlocks", pattern.mEncryptBlocks);
1071 msg->setInt32("skipBlocks", pattern.mSkipBlocks);
1072 msg->setInt64("timeUs", presentationTimeUs);
1073 msg->setInt32("flags", flags);
1074 msg->setPointer("errorDetailMsg", errorDetailMsg);
1075
1076 sp<AMessage> response;
1077 status_t err = PostAndAwaitResponse(msg, &response);
1078
1079 return err;
1080 }
1081
dequeueInputBuffer(size_t * index,int64_t timeoutUs)1082 status_t MediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
1083 sp<AMessage> msg = new AMessage(kWhatDequeueInputBuffer, this);
1084 msg->setInt64("timeoutUs", timeoutUs);
1085
1086 sp<AMessage> response;
1087 status_t err;
1088 if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
1089 return err;
1090 }
1091
1092 CHECK(response->findSize("index", index));
1093
1094 return OK;
1095 }
1096
dequeueOutputBuffer(size_t * index,size_t * offset,size_t * size,int64_t * presentationTimeUs,uint32_t * flags,int64_t timeoutUs)1097 status_t MediaCodec::dequeueOutputBuffer(
1098 size_t *index,
1099 size_t *offset,
1100 size_t *size,
1101 int64_t *presentationTimeUs,
1102 uint32_t *flags,
1103 int64_t timeoutUs) {
1104 sp<AMessage> msg = new AMessage(kWhatDequeueOutputBuffer, this);
1105 msg->setInt64("timeoutUs", timeoutUs);
1106
1107 sp<AMessage> response;
1108 status_t err;
1109 if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
1110 return err;
1111 }
1112
1113 CHECK(response->findSize("index", index));
1114 CHECK(response->findSize("offset", offset));
1115 CHECK(response->findSize("size", size));
1116 CHECK(response->findInt64("timeUs", presentationTimeUs));
1117 CHECK(response->findInt32("flags", (int32_t *)flags));
1118
1119 return OK;
1120 }
1121
renderOutputBufferAndRelease(size_t index)1122 status_t MediaCodec::renderOutputBufferAndRelease(size_t index) {
1123 sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this);
1124 msg->setSize("index", index);
1125 msg->setInt32("render", true);
1126
1127 sp<AMessage> response;
1128 return PostAndAwaitResponse(msg, &response);
1129 }
1130
renderOutputBufferAndRelease(size_t index,int64_t timestampNs)1131 status_t MediaCodec::renderOutputBufferAndRelease(size_t index, int64_t timestampNs) {
1132 sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this);
1133 msg->setSize("index", index);
1134 msg->setInt32("render", true);
1135 msg->setInt64("timestampNs", timestampNs);
1136
1137 sp<AMessage> response;
1138 return PostAndAwaitResponse(msg, &response);
1139 }
1140
releaseOutputBuffer(size_t index)1141 status_t MediaCodec::releaseOutputBuffer(size_t index) {
1142 sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this);
1143 msg->setSize("index", index);
1144
1145 sp<AMessage> response;
1146 return PostAndAwaitResponse(msg, &response);
1147 }
1148
signalEndOfInputStream()1149 status_t MediaCodec::signalEndOfInputStream() {
1150 sp<AMessage> msg = new AMessage(kWhatSignalEndOfInputStream, this);
1151
1152 sp<AMessage> response;
1153 return PostAndAwaitResponse(msg, &response);
1154 }
1155
getOutputFormat(sp<AMessage> * format) const1156 status_t MediaCodec::getOutputFormat(sp<AMessage> *format) const {
1157 sp<AMessage> msg = new AMessage(kWhatGetOutputFormat, this);
1158
1159 sp<AMessage> response;
1160 status_t err;
1161 if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
1162 return err;
1163 }
1164
1165 CHECK(response->findMessage("format", format));
1166
1167 return OK;
1168 }
1169
getInputFormat(sp<AMessage> * format) const1170 status_t MediaCodec::getInputFormat(sp<AMessage> *format) const {
1171 sp<AMessage> msg = new AMessage(kWhatGetInputFormat, this);
1172
1173 sp<AMessage> response;
1174 status_t err;
1175 if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
1176 return err;
1177 }
1178
1179 CHECK(response->findMessage("format", format));
1180
1181 return OK;
1182 }
1183
getName(AString * name) const1184 status_t MediaCodec::getName(AString *name) const {
1185 sp<AMessage> msg = new AMessage(kWhatGetName, this);
1186
1187 sp<AMessage> response;
1188 status_t err;
1189 if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
1190 return err;
1191 }
1192
1193 CHECK(response->findString("name", name));
1194
1195 return OK;
1196 }
1197
getMetrics(MediaAnalyticsItem * & reply)1198 status_t MediaCodec::getMetrics(MediaAnalyticsItem * &reply) {
1199
1200 reply = NULL;
1201
1202 // shouldn't happen, but be safe
1203 if (mAnalyticsItem == NULL) {
1204 return UNKNOWN_ERROR;
1205 }
1206
1207 // XXX: go get current values for whatever in-flight data we want
1208
1209 // send it back to the caller.
1210 reply = mAnalyticsItem->dup();
1211
1212 return OK;
1213 }
1214
getInputBuffers(Vector<sp<MediaCodecBuffer>> * buffers) const1215 status_t MediaCodec::getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
1216 sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
1217 msg->setInt32("portIndex", kPortIndexInput);
1218 msg->setPointer("buffers", buffers);
1219
1220 sp<AMessage> response;
1221 return PostAndAwaitResponse(msg, &response);
1222 }
1223
getOutputBuffers(Vector<sp<MediaCodecBuffer>> * buffers) const1224 status_t MediaCodec::getOutputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
1225 sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
1226 msg->setInt32("portIndex", kPortIndexOutput);
1227 msg->setPointer("buffers", buffers);
1228
1229 sp<AMessage> response;
1230 return PostAndAwaitResponse(msg, &response);
1231 }
1232
getOutputBuffer(size_t index,sp<MediaCodecBuffer> * buffer)1233 status_t MediaCodec::getOutputBuffer(size_t index, sp<MediaCodecBuffer> *buffer) {
1234 sp<AMessage> format;
1235 return getBufferAndFormat(kPortIndexOutput, index, buffer, &format);
1236 }
1237
getOutputFormat(size_t index,sp<AMessage> * format)1238 status_t MediaCodec::getOutputFormat(size_t index, sp<AMessage> *format) {
1239 sp<MediaCodecBuffer> buffer;
1240 return getBufferAndFormat(kPortIndexOutput, index, &buffer, format);
1241 }
1242
getInputBuffer(size_t index,sp<MediaCodecBuffer> * buffer)1243 status_t MediaCodec::getInputBuffer(size_t index, sp<MediaCodecBuffer> *buffer) {
1244 sp<AMessage> format;
1245 return getBufferAndFormat(kPortIndexInput, index, buffer, &format);
1246 }
1247
isExecuting() const1248 bool MediaCodec::isExecuting() const {
1249 return mState == STARTED || mState == FLUSHED;
1250 }
1251
getBufferAndFormat(size_t portIndex,size_t index,sp<MediaCodecBuffer> * buffer,sp<AMessage> * format)1252 status_t MediaCodec::getBufferAndFormat(
1253 size_t portIndex, size_t index,
1254 sp<MediaCodecBuffer> *buffer, sp<AMessage> *format) {
1255 // use mutex instead of a context switch
1256 if (mReleasedByResourceManager) {
1257 ALOGE("getBufferAndFormat - resource already released");
1258 return DEAD_OBJECT;
1259 }
1260
1261 if (buffer == NULL) {
1262 ALOGE("getBufferAndFormat - null MediaCodecBuffer");
1263 return INVALID_OPERATION;
1264 }
1265
1266 if (format == NULL) {
1267 ALOGE("getBufferAndFormat - null AMessage");
1268 return INVALID_OPERATION;
1269 }
1270
1271 buffer->clear();
1272 format->clear();
1273
1274 if (!isExecuting()) {
1275 ALOGE("getBufferAndFormat - not executing");
1276 return INVALID_OPERATION;
1277 }
1278
1279 // we do not want mPortBuffers to change during this section
1280 // we also don't want mOwnedByClient to change during this
1281 Mutex::Autolock al(mBufferLock);
1282
1283 std::vector<BufferInfo> &buffers = mPortBuffers[portIndex];
1284 if (index >= buffers.size()) {
1285 ALOGE("getBufferAndFormat - trying to get buffer with "
1286 "bad index (index=%zu buffer_size=%zu)", index, buffers.size());
1287 return INVALID_OPERATION;
1288 }
1289
1290 const BufferInfo &info = buffers[index];
1291 if (!info.mOwnedByClient) {
1292 ALOGE("getBufferAndFormat - invalid operation "
1293 "(the index %zu is not owned by client)", index);
1294 return INVALID_OPERATION;
1295 }
1296
1297 *buffer = info.mData;
1298 *format = info.mData->format();
1299
1300 return OK;
1301 }
1302
flush()1303 status_t MediaCodec::flush() {
1304 sp<AMessage> msg = new AMessage(kWhatFlush, this);
1305
1306 sp<AMessage> response;
1307 return PostAndAwaitResponse(msg, &response);
1308 }
1309
requestIDRFrame()1310 status_t MediaCodec::requestIDRFrame() {
1311 (new AMessage(kWhatRequestIDRFrame, this))->post();
1312
1313 return OK;
1314 }
1315
requestActivityNotification(const sp<AMessage> & notify)1316 void MediaCodec::requestActivityNotification(const sp<AMessage> ¬ify) {
1317 sp<AMessage> msg = new AMessage(kWhatRequestActivityNotification, this);
1318 msg->setMessage("notify", notify);
1319 msg->post();
1320 }
1321
1322 ////////////////////////////////////////////////////////////////////////////////
1323
cancelPendingDequeueOperations()1324 void MediaCodec::cancelPendingDequeueOperations() {
1325 if (mFlags & kFlagDequeueInputPending) {
1326 PostReplyWithError(mDequeueInputReplyID, INVALID_OPERATION);
1327
1328 ++mDequeueInputTimeoutGeneration;
1329 mDequeueInputReplyID = 0;
1330 mFlags &= ~kFlagDequeueInputPending;
1331 }
1332
1333 if (mFlags & kFlagDequeueOutputPending) {
1334 PostReplyWithError(mDequeueOutputReplyID, INVALID_OPERATION);
1335
1336 ++mDequeueOutputTimeoutGeneration;
1337 mDequeueOutputReplyID = 0;
1338 mFlags &= ~kFlagDequeueOutputPending;
1339 }
1340 }
1341
handleDequeueInputBuffer(const sp<AReplyToken> & replyID,bool newRequest)1342 bool MediaCodec::handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest) {
1343 if (!isExecuting() || (mFlags & kFlagIsAsync)
1344 || (newRequest && (mFlags & kFlagDequeueInputPending))) {
1345 PostReplyWithError(replyID, INVALID_OPERATION);
1346 return true;
1347 } else if (mFlags & kFlagStickyError) {
1348 PostReplyWithError(replyID, getStickyError());
1349 return true;
1350 }
1351
1352 ssize_t index = dequeuePortBuffer(kPortIndexInput);
1353
1354 if (index < 0) {
1355 CHECK_EQ(index, -EAGAIN);
1356 return false;
1357 }
1358
1359 sp<AMessage> response = new AMessage;
1360 response->setSize("index", index);
1361 response->postReply(replyID);
1362
1363 return true;
1364 }
1365
handleDequeueOutputBuffer(const sp<AReplyToken> & replyID,bool newRequest)1366 bool MediaCodec::handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest) {
1367 if (!isExecuting() || (mFlags & kFlagIsAsync)
1368 || (newRequest && (mFlags & kFlagDequeueOutputPending))) {
1369 PostReplyWithError(replyID, INVALID_OPERATION);
1370 } else if (mFlags & kFlagStickyError) {
1371 PostReplyWithError(replyID, getStickyError());
1372 } else if (mFlags & kFlagOutputBuffersChanged) {
1373 PostReplyWithError(replyID, INFO_OUTPUT_BUFFERS_CHANGED);
1374 mFlags &= ~kFlagOutputBuffersChanged;
1375 } else if (mFlags & kFlagOutputFormatChanged) {
1376 PostReplyWithError(replyID, INFO_FORMAT_CHANGED);
1377 mFlags &= ~kFlagOutputFormatChanged;
1378 } else {
1379 sp<AMessage> response = new AMessage;
1380 ssize_t index = dequeuePortBuffer(kPortIndexOutput);
1381
1382 if (index < 0) {
1383 CHECK_EQ(index, -EAGAIN);
1384 return false;
1385 }
1386
1387 const sp<MediaCodecBuffer> &buffer =
1388 mPortBuffers[kPortIndexOutput][index].mData;
1389
1390 response->setSize("index", index);
1391 response->setSize("offset", buffer->offset());
1392 response->setSize("size", buffer->size());
1393
1394 int64_t timeUs;
1395 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
1396
1397 response->setInt64("timeUs", timeUs);
1398
1399 int32_t flags;
1400 CHECK(buffer->meta()->findInt32("flags", &flags));
1401
1402 response->setInt32("flags", flags);
1403 response->postReply(replyID);
1404 }
1405
1406 return true;
1407 }
1408
onMessageReceived(const sp<AMessage> & msg)1409 void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1410 switch (msg->what()) {
1411 case kWhatCodecNotify:
1412 {
1413 int32_t what;
1414 CHECK(msg->findInt32("what", &what));
1415
1416 switch (what) {
1417 case kWhatError:
1418 {
1419 int32_t err, actionCode;
1420 CHECK(msg->findInt32("err", &err));
1421 CHECK(msg->findInt32("actionCode", &actionCode));
1422
1423 ALOGE("Codec reported err %#x, actionCode %d, while in state %d",
1424 err, actionCode, mState);
1425 if (err == DEAD_OBJECT) {
1426 mFlags |= kFlagSawMediaServerDie;
1427 mFlags &= ~kFlagIsComponentAllocated;
1428 }
1429
1430 bool sendErrorResponse = true;
1431
1432 switch (mState) {
1433 case INITIALIZING:
1434 {
1435 setState(UNINITIALIZED);
1436 break;
1437 }
1438
1439 case CONFIGURING:
1440 {
1441 if (actionCode == ACTION_CODE_FATAL) {
1442 mAnalyticsItem->setInt32(kCodecError, err);
1443 mAnalyticsItem->setInt32(kCodecErrorState, mState);
1444 flushAnalyticsItem();
1445 initAnalyticsItem();
1446 }
1447 setState(actionCode == ACTION_CODE_FATAL ?
1448 UNINITIALIZED : INITIALIZED);
1449 break;
1450 }
1451
1452 case STARTING:
1453 {
1454 if (actionCode == ACTION_CODE_FATAL) {
1455 mAnalyticsItem->setInt32(kCodecError, err);
1456 mAnalyticsItem->setInt32(kCodecErrorState, mState);
1457 flushAnalyticsItem();
1458 initAnalyticsItem();
1459 }
1460 setState(actionCode == ACTION_CODE_FATAL ?
1461 UNINITIALIZED : CONFIGURED);
1462 break;
1463 }
1464
1465 case RELEASING:
1466 {
1467 // Ignore the error, assuming we'll still get
1468 // the shutdown complete notification. If we
1469 // don't, we'll timeout and force release.
1470 sendErrorResponse = false;
1471 }
1472 // fall-thru
1473 case STOPPING:
1474 {
1475 if (mFlags & kFlagSawMediaServerDie) {
1476 // MediaServer died, there definitely won't
1477 // be a shutdown complete notification after
1478 // all.
1479
1480 // note that we're directly going from
1481 // STOPPING->UNINITIALIZED, instead of the
1482 // usual STOPPING->INITIALIZED state.
1483 setState(UNINITIALIZED);
1484 if (mState == RELEASING) {
1485 mComponentName.clear();
1486 }
1487 (new AMessage)->postReply(mReplyID);
1488 sendErrorResponse = false;
1489 }
1490 break;
1491 }
1492
1493 case FLUSHING:
1494 {
1495 if (actionCode == ACTION_CODE_FATAL) {
1496 mAnalyticsItem->setInt32(kCodecError, err);
1497 mAnalyticsItem->setInt32(kCodecErrorState, mState);
1498 flushAnalyticsItem();
1499 initAnalyticsItem();
1500
1501 setState(UNINITIALIZED);
1502 } else {
1503 setState(
1504 (mFlags & kFlagIsAsync) ? FLUSHED : STARTED);
1505 }
1506 break;
1507 }
1508
1509 case FLUSHED:
1510 case STARTED:
1511 {
1512 sendErrorResponse = false;
1513
1514 setStickyError(err);
1515 postActivityNotificationIfPossible();
1516
1517 cancelPendingDequeueOperations();
1518
1519 if (mFlags & kFlagIsAsync) {
1520 onError(err, actionCode);
1521 }
1522 switch (actionCode) {
1523 case ACTION_CODE_TRANSIENT:
1524 break;
1525 case ACTION_CODE_RECOVERABLE:
1526 setState(INITIALIZED);
1527 break;
1528 default:
1529 mAnalyticsItem->setInt32(kCodecError, err);
1530 mAnalyticsItem->setInt32(kCodecErrorState, mState);
1531 flushAnalyticsItem();
1532 initAnalyticsItem();
1533 setState(UNINITIALIZED);
1534 break;
1535 }
1536 break;
1537 }
1538
1539 default:
1540 {
1541 sendErrorResponse = false;
1542
1543 setStickyError(err);
1544 postActivityNotificationIfPossible();
1545
1546 // actionCode in an uninitialized state is always fatal.
1547 if (mState == UNINITIALIZED) {
1548 actionCode = ACTION_CODE_FATAL;
1549 }
1550 if (mFlags & kFlagIsAsync) {
1551 onError(err, actionCode);
1552 }
1553 switch (actionCode) {
1554 case ACTION_CODE_TRANSIENT:
1555 break;
1556 case ACTION_CODE_RECOVERABLE:
1557 setState(INITIALIZED);
1558 break;
1559 default:
1560 setState(UNINITIALIZED);
1561 break;
1562 }
1563 break;
1564 }
1565 }
1566
1567 if (sendErrorResponse) {
1568 PostReplyWithError(mReplyID, err);
1569 }
1570 break;
1571 }
1572
1573 case kWhatComponentAllocated:
1574 {
1575 CHECK_EQ(mState, INITIALIZING);
1576 setState(INITIALIZED);
1577 mFlags |= kFlagIsComponentAllocated;
1578
1579 CHECK(msg->findString("componentName", &mComponentName));
1580
1581 if (mComponentName.c_str()) {
1582 mAnalyticsItem->setCString(kCodecCodec, mComponentName.c_str());
1583 }
1584
1585 if (mComponentName.startsWith("OMX.google.")) {
1586 mFlags |= kFlagUsesSoftwareRenderer;
1587 } else {
1588 mFlags &= ~kFlagUsesSoftwareRenderer;
1589 }
1590
1591 MediaResource::Type resourceType;
1592 if (mComponentName.endsWith(".secure")) {
1593 mFlags |= kFlagIsSecure;
1594 resourceType = MediaResource::kSecureCodec;
1595 mAnalyticsItem->setInt32(kCodecSecure, 1);
1596 } else {
1597 mFlags &= ~kFlagIsSecure;
1598 resourceType = MediaResource::kNonSecureCodec;
1599 mAnalyticsItem->setInt32(kCodecSecure, 0);
1600 }
1601
1602 if (mIsVideo) {
1603 // audio codec is currently ignored.
1604 addResource(resourceType, MediaResource::kVideoCodec, 1);
1605 }
1606
1607 (new AMessage)->postReply(mReplyID);
1608 break;
1609 }
1610
1611 case kWhatComponentConfigured:
1612 {
1613 if (mState == UNINITIALIZED || mState == INITIALIZED) {
1614 // In case a kWhatError message came in and replied with error,
1615 // we log a warning and ignore.
1616 ALOGW("configure interrupted by error, current state %d", mState);
1617 break;
1618 }
1619 CHECK_EQ(mState, CONFIGURING);
1620
1621 // reset input surface flag
1622 mHaveInputSurface = false;
1623
1624 CHECK(msg->findMessage("input-format", &mInputFormat));
1625 CHECK(msg->findMessage("output-format", &mOutputFormat));
1626 ALOGV("[%s] configured as input format: %s, output format: %s",
1627 mComponentName.c_str(),
1628 mInputFormat->debugString(4).c_str(),
1629 mOutputFormat->debugString(4).c_str());
1630 int32_t usingSwRenderer;
1631 if (mOutputFormat->findInt32("using-sw-renderer", &usingSwRenderer)
1632 && usingSwRenderer) {
1633 mFlags |= kFlagUsesSoftwareRenderer;
1634 }
1635 setState(CONFIGURED);
1636 (new AMessage)->postReply(mReplyID);
1637
1638 // augment our media metrics info, now that we know more things
1639 if (mAnalyticsItem != NULL) {
1640 sp<AMessage> format;
1641 if (mConfigureMsg != NULL &&
1642 mConfigureMsg->findMessage("format", &format)) {
1643 // format includes: mime
1644 AString mime;
1645 if (format->findString("mime", &mime)) {
1646 mAnalyticsItem->setCString(kCodecMime, mime.c_str());
1647 }
1648 }
1649 }
1650 break;
1651 }
1652
1653 case kWhatInputSurfaceCreated:
1654 {
1655 // response to initiateCreateInputSurface()
1656 status_t err = NO_ERROR;
1657 sp<AMessage> response = new AMessage;
1658 if (!msg->findInt32("err", &err)) {
1659 sp<RefBase> obj;
1660 msg->findObject("input-surface", &obj);
1661 CHECK(msg->findMessage("input-format", &mInputFormat));
1662 CHECK(msg->findMessage("output-format", &mOutputFormat));
1663 ALOGV("[%s] input surface created as input format: %s, output format: %s",
1664 mComponentName.c_str(),
1665 mInputFormat->debugString(4).c_str(),
1666 mOutputFormat->debugString(4).c_str());
1667 CHECK(obj != NULL);
1668 response->setObject("input-surface", obj);
1669 mHaveInputSurface = true;
1670 } else {
1671 response->setInt32("err", err);
1672 }
1673 response->postReply(mReplyID);
1674 break;
1675 }
1676
1677 case kWhatInputSurfaceAccepted:
1678 {
1679 // response to initiateSetInputSurface()
1680 status_t err = NO_ERROR;
1681 sp<AMessage> response = new AMessage();
1682 if (!msg->findInt32("err", &err)) {
1683 CHECK(msg->findMessage("input-format", &mInputFormat));
1684 CHECK(msg->findMessage("output-format", &mOutputFormat));
1685 mHaveInputSurface = true;
1686 } else {
1687 response->setInt32("err", err);
1688 }
1689 response->postReply(mReplyID);
1690 break;
1691 }
1692
1693 case kWhatSignaledInputEOS:
1694 {
1695 // response to signalEndOfInputStream()
1696 sp<AMessage> response = new AMessage;
1697 status_t err;
1698 if (msg->findInt32("err", &err)) {
1699 response->setInt32("err", err);
1700 }
1701 response->postReply(mReplyID);
1702 break;
1703 }
1704
1705 case kWhatStartCompleted:
1706 {
1707 CHECK_EQ(mState, STARTING);
1708 if (mIsVideo) {
1709 addResource(
1710 MediaResource::kGraphicMemory,
1711 MediaResource::kUnspecifiedSubType,
1712 getGraphicBufferSize());
1713 }
1714 setState(STARTED);
1715 (new AMessage)->postReply(mReplyID);
1716 break;
1717 }
1718
1719 case kWhatOutputBuffersChanged:
1720 {
1721 mFlags |= kFlagOutputBuffersChanged;
1722 postActivityNotificationIfPossible();
1723 break;
1724 }
1725
1726 case kWhatOutputFramesRendered:
1727 {
1728 // ignore these in all states except running, and check that we have a
1729 // notification set
1730 if (mState == STARTED && mOnFrameRenderedNotification != NULL) {
1731 sp<AMessage> notify = mOnFrameRenderedNotification->dup();
1732 notify->setMessage("data", msg);
1733 notify->post();
1734 }
1735 break;
1736 }
1737
1738 case kWhatFillThisBuffer:
1739 {
1740 /* size_t index = */updateBuffers(kPortIndexInput, msg);
1741
1742 if (mState == FLUSHING
1743 || mState == STOPPING
1744 || mState == RELEASING) {
1745 returnBuffersToCodecOnPort(kPortIndexInput);
1746 break;
1747 }
1748
1749 if (!mCSD.empty()) {
1750 ssize_t index = dequeuePortBuffer(kPortIndexInput);
1751 CHECK_GE(index, 0);
1752
1753 // If codec specific data had been specified as
1754 // part of the format in the call to configure and
1755 // if there's more csd left, we submit it here
1756 // clients only get access to input buffers once
1757 // this data has been exhausted.
1758
1759 status_t err = queueCSDInputBuffer(index);
1760
1761 if (err != OK) {
1762 ALOGE("queueCSDInputBuffer failed w/ error %d",
1763 err);
1764
1765 setStickyError(err);
1766 postActivityNotificationIfPossible();
1767
1768 cancelPendingDequeueOperations();
1769 }
1770 break;
1771 }
1772
1773 if (mFlags & kFlagIsAsync) {
1774 if (!mHaveInputSurface) {
1775 if (mState == FLUSHED) {
1776 mHavePendingInputBuffers = true;
1777 } else {
1778 onInputBufferAvailable();
1779 }
1780 }
1781 } else if (mFlags & kFlagDequeueInputPending) {
1782 CHECK(handleDequeueInputBuffer(mDequeueInputReplyID));
1783
1784 ++mDequeueInputTimeoutGeneration;
1785 mFlags &= ~kFlagDequeueInputPending;
1786 mDequeueInputReplyID = 0;
1787 } else {
1788 postActivityNotificationIfPossible();
1789 }
1790 break;
1791 }
1792
1793 case kWhatDrainThisBuffer:
1794 {
1795 /* size_t index = */updateBuffers(kPortIndexOutput, msg);
1796
1797 if (mState == FLUSHING
1798 || mState == STOPPING
1799 || mState == RELEASING) {
1800 returnBuffersToCodecOnPort(kPortIndexOutput);
1801 break;
1802 }
1803
1804 sp<RefBase> obj;
1805 CHECK(msg->findObject("buffer", &obj));
1806 sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
1807
1808 if (mOutputFormat != buffer->format()) {
1809 mOutputFormat = buffer->format();
1810 ALOGV("[%s] output format changed to: %s",
1811 mComponentName.c_str(), mOutputFormat->debugString(4).c_str());
1812
1813 if (mSoftRenderer == NULL &&
1814 mSurface != NULL &&
1815 (mFlags & kFlagUsesSoftwareRenderer)) {
1816 AString mime;
1817 CHECK(mOutputFormat->findString("mime", &mime));
1818
1819 // TODO: propagate color aspects to software renderer to allow better
1820 // color conversion to RGB. For now, just mark dataspace for YUV
1821 // rendering.
1822 int32_t dataSpace;
1823 if (mOutputFormat->findInt32("android._dataspace", &dataSpace)) {
1824 ALOGD("[%s] setting dataspace on output surface to #%x",
1825 mComponentName.c_str(), dataSpace);
1826 int err = native_window_set_buffers_data_space(
1827 mSurface.get(), (android_dataspace)dataSpace);
1828 ALOGW_IF(err != 0, "failed to set dataspace on surface (%d)", err);
1829 }
1830
1831 if (mime.startsWithIgnoreCase("video/")) {
1832 mSoftRenderer = new SoftwareRenderer(mSurface, mRotationDegrees);
1833 }
1834 }
1835
1836 if (mFlags & kFlagIsEncoder) {
1837 // Before we announce the format change we should
1838 // collect codec specific data and amend the output
1839 // format as necessary.
1840 int32_t flags = 0;
1841 (void) buffer->meta()->findInt32("flags", &flags);
1842 if (flags & BUFFER_FLAG_CODECCONFIG) {
1843 status_t err =
1844 amendOutputFormatWithCodecSpecificData(buffer);
1845
1846 if (err != OK) {
1847 ALOGE("Codec spit out malformed codec "
1848 "specific data!");
1849 }
1850 }
1851 }
1852
1853 if (mFlags & kFlagIsAsync) {
1854 onOutputFormatChanged();
1855 } else {
1856 mFlags |= kFlagOutputFormatChanged;
1857 postActivityNotificationIfPossible();
1858 }
1859
1860 // Notify mCrypto of video resolution changes
1861 if (mCrypto != NULL) {
1862 int32_t left, top, right, bottom, width, height;
1863 if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
1864 mCrypto->notifyResolution(right - left + 1, bottom - top + 1);
1865 } else if (mOutputFormat->findInt32("width", &width)
1866 && mOutputFormat->findInt32("height", &height)) {
1867 mCrypto->notifyResolution(width, height);
1868 }
1869 }
1870 }
1871
1872 if (mFlags & kFlagIsAsync) {
1873 onOutputBufferAvailable();
1874 } else if (mFlags & kFlagDequeueOutputPending) {
1875 CHECK(handleDequeueOutputBuffer(mDequeueOutputReplyID));
1876
1877 ++mDequeueOutputTimeoutGeneration;
1878 mFlags &= ~kFlagDequeueOutputPending;
1879 mDequeueOutputReplyID = 0;
1880 } else {
1881 postActivityNotificationIfPossible();
1882 }
1883
1884 break;
1885 }
1886
1887 case kWhatEOS:
1888 {
1889 // We already notify the client of this by using the
1890 // corresponding flag in "onOutputBufferReady".
1891 break;
1892 }
1893
1894 case kWhatStopCompleted:
1895 {
1896 if (mState != STOPPING) {
1897 ALOGW("Received kWhatStopCompleted in state %d", mState);
1898 break;
1899 }
1900 setState(INITIALIZED);
1901 (new AMessage)->postReply(mReplyID);
1902 break;
1903 }
1904
1905 case kWhatReleaseCompleted:
1906 {
1907 if (mState != RELEASING) {
1908 ALOGW("Received kWhatReleaseCompleted in state %d", mState);
1909 break;
1910 }
1911 setState(UNINITIALIZED);
1912 mComponentName.clear();
1913
1914 mFlags &= ~kFlagIsComponentAllocated;
1915
1916 mResourceManagerService->removeResource(getId(mResourceManagerClient));
1917
1918 (new AMessage)->postReply(mReplyID);
1919 break;
1920 }
1921
1922 case kWhatFlushCompleted:
1923 {
1924 if (mState != FLUSHING) {
1925 ALOGW("received FlushCompleted message in state %d",
1926 mState);
1927 break;
1928 }
1929
1930 if (mFlags & kFlagIsAsync) {
1931 setState(FLUSHED);
1932 } else {
1933 setState(STARTED);
1934 mCodec->signalResume();
1935 }
1936
1937 (new AMessage)->postReply(mReplyID);
1938 break;
1939 }
1940
1941 default:
1942 TRESPASS();
1943 }
1944 break;
1945 }
1946
1947 case kWhatInit:
1948 {
1949 sp<AReplyToken> replyID;
1950 CHECK(msg->senderAwaitsResponse(&replyID));
1951
1952 if (mState != UNINITIALIZED) {
1953 PostReplyWithError(replyID, INVALID_OPERATION);
1954 break;
1955 }
1956
1957 mReplyID = replyID;
1958 setState(INITIALIZING);
1959
1960 AString name;
1961 CHECK(msg->findString("name", &name));
1962
1963 int32_t nameIsType;
1964 int32_t encoder = false;
1965 CHECK(msg->findInt32("nameIsType", &nameIsType));
1966 if (nameIsType) {
1967 CHECK(msg->findInt32("encoder", &encoder));
1968 }
1969
1970 sp<AMessage> format = new AMessage;
1971
1972 if (nameIsType) {
1973 format->setString("mime", name.c_str());
1974 format->setInt32("encoder", encoder);
1975 } else {
1976 format->setString("componentName", name.c_str());
1977 }
1978
1979 mCodec->initiateAllocateComponent(format);
1980 break;
1981 }
1982
1983 case kWhatSetNotification:
1984 {
1985 sp<AMessage> notify;
1986 if (msg->findMessage("on-frame-rendered", ¬ify)) {
1987 mOnFrameRenderedNotification = notify;
1988 }
1989 break;
1990 }
1991
1992 case kWhatSetCallback:
1993 {
1994 sp<AReplyToken> replyID;
1995 CHECK(msg->senderAwaitsResponse(&replyID));
1996
1997 if (mState == UNINITIALIZED
1998 || mState == INITIALIZING
1999 || isExecuting()) {
2000 // callback can't be set after codec is executing,
2001 // or before it's initialized (as the callback
2002 // will be cleared when it goes to INITIALIZED)
2003 PostReplyWithError(replyID, INVALID_OPERATION);
2004 break;
2005 }
2006
2007 sp<AMessage> callback;
2008 CHECK(msg->findMessage("callback", &callback));
2009
2010 mCallback = callback;
2011
2012 if (mCallback != NULL) {
2013 ALOGI("MediaCodec will operate in async mode");
2014 mFlags |= kFlagIsAsync;
2015 } else {
2016 mFlags &= ~kFlagIsAsync;
2017 }
2018
2019 sp<AMessage> response = new AMessage;
2020 response->postReply(replyID);
2021 break;
2022 }
2023
2024 case kWhatConfigure:
2025 {
2026 sp<AReplyToken> replyID;
2027 CHECK(msg->senderAwaitsResponse(&replyID));
2028
2029 if (mState != INITIALIZED) {
2030 PostReplyWithError(replyID, INVALID_OPERATION);
2031 break;
2032 }
2033
2034 sp<RefBase> obj;
2035 CHECK(msg->findObject("surface", &obj));
2036
2037 sp<AMessage> format;
2038 CHECK(msg->findMessage("format", &format));
2039
2040 int32_t push;
2041 if (msg->findInt32("push-blank-buffers-on-shutdown", &push) && push != 0) {
2042 mFlags |= kFlagPushBlankBuffersOnShutdown;
2043 }
2044
2045 if (obj != NULL) {
2046 format->setObject("native-window", obj);
2047 status_t err = handleSetSurface(static_cast<Surface *>(obj.get()));
2048 if (err != OK) {
2049 PostReplyWithError(replyID, err);
2050 break;
2051 }
2052 } else {
2053 handleSetSurface(NULL);
2054 }
2055
2056 mReplyID = replyID;
2057 setState(CONFIGURING);
2058
2059 void *crypto;
2060 if (!msg->findPointer("crypto", &crypto)) {
2061 crypto = NULL;
2062 }
2063
2064 ALOGV("kWhatConfigure: Old mCrypto: %p (%d)",
2065 mCrypto.get(), (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
2066
2067 mCrypto = static_cast<ICrypto *>(crypto);
2068 mBufferChannel->setCrypto(mCrypto);
2069
2070 ALOGV("kWhatConfigure: New mCrypto: %p (%d)",
2071 mCrypto.get(), (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
2072
2073 void *descrambler;
2074 if (!msg->findPointer("descrambler", &descrambler)) {
2075 descrambler = NULL;
2076 }
2077
2078 mDescrambler = static_cast<IDescrambler *>(descrambler);
2079 mBufferChannel->setDescrambler(mDescrambler);
2080
2081 uint32_t flags;
2082 CHECK(msg->findInt32("flags", (int32_t *)&flags));
2083
2084 if (flags & CONFIGURE_FLAG_ENCODE) {
2085 format->setInt32("encoder", true);
2086 mFlags |= kFlagIsEncoder;
2087 }
2088
2089 extractCSD(format);
2090
2091 mCodec->initiateConfigureComponent(format);
2092 break;
2093 }
2094
2095 case kWhatSetSurface:
2096 {
2097 sp<AReplyToken> replyID;
2098 CHECK(msg->senderAwaitsResponse(&replyID));
2099
2100 status_t err = OK;
2101
2102 switch (mState) {
2103 case CONFIGURED:
2104 case STARTED:
2105 case FLUSHED:
2106 {
2107 sp<RefBase> obj;
2108 (void)msg->findObject("surface", &obj);
2109 sp<Surface> surface = static_cast<Surface *>(obj.get());
2110 if (mSurface == NULL) {
2111 // do not support setting surface if it was not set
2112 err = INVALID_OPERATION;
2113 } else if (obj == NULL) {
2114 // do not support unsetting surface
2115 err = BAD_VALUE;
2116 } else {
2117 err = connectToSurface(surface);
2118 if (err == ALREADY_EXISTS) {
2119 // reconnecting to same surface
2120 err = OK;
2121 } else {
2122 if (err == OK) {
2123 if (mFlags & kFlagUsesSoftwareRenderer) {
2124 if (mSoftRenderer != NULL
2125 && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
2126 pushBlankBuffersToNativeWindow(mSurface.get());
2127 }
2128 mSoftRenderer = new SoftwareRenderer(surface);
2129 // TODO: check if this was successful
2130 } else {
2131 err = mCodec->setSurface(surface);
2132 }
2133 }
2134 if (err == OK) {
2135 (void)disconnectFromSurface();
2136 mSurface = surface;
2137 }
2138 }
2139 }
2140 break;
2141 }
2142
2143 default:
2144 err = INVALID_OPERATION;
2145 break;
2146 }
2147
2148 PostReplyWithError(replyID, err);
2149 break;
2150 }
2151
2152 case kWhatCreateInputSurface:
2153 case kWhatSetInputSurface:
2154 {
2155 sp<AReplyToken> replyID;
2156 CHECK(msg->senderAwaitsResponse(&replyID));
2157
2158 // Must be configured, but can't have been started yet.
2159 if (mState != CONFIGURED) {
2160 PostReplyWithError(replyID, INVALID_OPERATION);
2161 break;
2162 }
2163
2164 mReplyID = replyID;
2165 if (msg->what() == kWhatCreateInputSurface) {
2166 mCodec->initiateCreateInputSurface();
2167 } else {
2168 sp<RefBase> obj;
2169 CHECK(msg->findObject("input-surface", &obj));
2170
2171 mCodec->initiateSetInputSurface(
2172 static_cast<PersistentSurface *>(obj.get()));
2173 }
2174 break;
2175 }
2176 case kWhatStart:
2177 {
2178 sp<AReplyToken> replyID;
2179 CHECK(msg->senderAwaitsResponse(&replyID));
2180
2181 if (mState == FLUSHED) {
2182 setState(STARTED);
2183 if (mHavePendingInputBuffers) {
2184 onInputBufferAvailable();
2185 mHavePendingInputBuffers = false;
2186 }
2187 mCodec->signalResume();
2188 PostReplyWithError(replyID, OK);
2189 break;
2190 } else if (mState != CONFIGURED) {
2191 PostReplyWithError(replyID, INVALID_OPERATION);
2192 break;
2193 }
2194
2195 mReplyID = replyID;
2196 setState(STARTING);
2197
2198 mCodec->initiateStart();
2199 break;
2200 }
2201
2202 case kWhatStop:
2203 case kWhatRelease:
2204 {
2205 State targetState =
2206 (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED;
2207
2208 sp<AReplyToken> replyID;
2209 CHECK(msg->senderAwaitsResponse(&replyID));
2210
2211 // already stopped/released
2212 if (mState == UNINITIALIZED && mReleasedByResourceManager) {
2213 sp<AMessage> response = new AMessage;
2214 response->setInt32("err", OK);
2215 response->postReply(replyID);
2216 break;
2217 }
2218
2219 int32_t reclaimed = 0;
2220 msg->findInt32("reclaimed", &reclaimed);
2221 if (reclaimed) {
2222 mReleasedByResourceManager = true;
2223
2224 int32_t force = 0;
2225 msg->findInt32("force", &force);
2226 if (!force && hasPendingBuffer()) {
2227 ALOGW("Can't reclaim codec right now due to pending buffers.");
2228
2229 // return WOULD_BLOCK to ask resource manager to retry later.
2230 sp<AMessage> response = new AMessage;
2231 response->setInt32("err", WOULD_BLOCK);
2232 response->postReply(replyID);
2233
2234 // notify the async client
2235 if (mFlags & kFlagIsAsync) {
2236 onError(DEAD_OBJECT, ACTION_CODE_FATAL);
2237 }
2238 break;
2239 }
2240 }
2241
2242 bool isReleasingAllocatedComponent =
2243 (mFlags & kFlagIsComponentAllocated) && targetState == UNINITIALIZED;
2244 if (!isReleasingAllocatedComponent // See 1
2245 && mState != INITIALIZED
2246 && mState != CONFIGURED && !isExecuting()) {
2247 // 1) Permit release to shut down the component if allocated.
2248 //
2249 // 2) We may be in "UNINITIALIZED" state already and
2250 // also shutdown the encoder/decoder without the
2251 // client being aware of this if media server died while
2252 // we were being stopped. The client would assume that
2253 // after stop() returned, it would be safe to call release()
2254 // and it should be in this case, no harm to allow a release()
2255 // if we're already uninitialized.
2256 sp<AMessage> response = new AMessage;
2257 // TODO: we shouldn't throw an exception for stop/release. Change this to wait until
2258 // the previous stop/release completes and then reply with OK.
2259 status_t err = mState == targetState ? OK : INVALID_OPERATION;
2260 response->setInt32("err", err);
2261 if (err == OK && targetState == UNINITIALIZED) {
2262 mComponentName.clear();
2263 }
2264 response->postReply(replyID);
2265 break;
2266 }
2267
2268 // If we're flushing, or we're stopping but received a release
2269 // request, post the reply for the pending call first, and consider
2270 // it done. The reply token will be replaced after this, and we'll
2271 // no longer be able to reply.
2272 if (mState == FLUSHING || mState == STOPPING) {
2273 (new AMessage)->postReply(mReplyID);
2274 }
2275
2276 if (mFlags & kFlagSawMediaServerDie) {
2277 // It's dead, Jim. Don't expect initiateShutdown to yield
2278 // any useful results now...
2279 setState(UNINITIALIZED);
2280 if (targetState == UNINITIALIZED) {
2281 mComponentName.clear();
2282 }
2283 (new AMessage)->postReply(replyID);
2284 break;
2285 }
2286
2287 // If we already have an error, component may not be able to
2288 // complete the shutdown properly. If we're stopping, post the
2289 // reply now with an error to unblock the client, client can
2290 // release after the failure (instead of ANR).
2291 if (msg->what() == kWhatStop && (mFlags & kFlagStickyError)) {
2292 PostReplyWithError(replyID, getStickyError());
2293 break;
2294 }
2295
2296 mReplyID = replyID;
2297 setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
2298
2299 mCodec->initiateShutdown(
2300 msg->what() == kWhatStop /* keepComponentAllocated */);
2301
2302 returnBuffersToCodec(reclaimed);
2303
2304 if (mSoftRenderer != NULL && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
2305 pushBlankBuffersToNativeWindow(mSurface.get());
2306 }
2307
2308 break;
2309 }
2310
2311 case kWhatDequeueInputBuffer:
2312 {
2313 sp<AReplyToken> replyID;
2314 CHECK(msg->senderAwaitsResponse(&replyID));
2315
2316 if (mFlags & kFlagIsAsync) {
2317 ALOGE("dequeueOutputBuffer can't be used in async mode");
2318 PostReplyWithError(replyID, INVALID_OPERATION);
2319 break;
2320 }
2321
2322 if (mHaveInputSurface) {
2323 ALOGE("dequeueInputBuffer can't be used with input surface");
2324 PostReplyWithError(replyID, INVALID_OPERATION);
2325 break;
2326 }
2327
2328 if (handleDequeueInputBuffer(replyID, true /* new request */)) {
2329 break;
2330 }
2331
2332 int64_t timeoutUs;
2333 CHECK(msg->findInt64("timeoutUs", &timeoutUs));
2334
2335 if (timeoutUs == 0ll) {
2336 PostReplyWithError(replyID, -EAGAIN);
2337 break;
2338 }
2339
2340 mFlags |= kFlagDequeueInputPending;
2341 mDequeueInputReplyID = replyID;
2342
2343 if (timeoutUs > 0ll) {
2344 sp<AMessage> timeoutMsg =
2345 new AMessage(kWhatDequeueInputTimedOut, this);
2346 timeoutMsg->setInt32(
2347 "generation", ++mDequeueInputTimeoutGeneration);
2348 timeoutMsg->post(timeoutUs);
2349 }
2350 break;
2351 }
2352
2353 case kWhatDequeueInputTimedOut:
2354 {
2355 int32_t generation;
2356 CHECK(msg->findInt32("generation", &generation));
2357
2358 if (generation != mDequeueInputTimeoutGeneration) {
2359 // Obsolete
2360 break;
2361 }
2362
2363 CHECK(mFlags & kFlagDequeueInputPending);
2364
2365 PostReplyWithError(mDequeueInputReplyID, -EAGAIN);
2366
2367 mFlags &= ~kFlagDequeueInputPending;
2368 mDequeueInputReplyID = 0;
2369 break;
2370 }
2371
2372 case kWhatQueueInputBuffer:
2373 {
2374 sp<AReplyToken> replyID;
2375 CHECK(msg->senderAwaitsResponse(&replyID));
2376
2377 if (!isExecuting()) {
2378 PostReplyWithError(replyID, INVALID_OPERATION);
2379 break;
2380 } else if (mFlags & kFlagStickyError) {
2381 PostReplyWithError(replyID, getStickyError());
2382 break;
2383 }
2384
2385 status_t err = onQueueInputBuffer(msg);
2386
2387 PostReplyWithError(replyID, err);
2388 break;
2389 }
2390
2391 case kWhatDequeueOutputBuffer:
2392 {
2393 sp<AReplyToken> replyID;
2394 CHECK(msg->senderAwaitsResponse(&replyID));
2395
2396 if (mFlags & kFlagIsAsync) {
2397 ALOGE("dequeueOutputBuffer can't be used in async mode");
2398 PostReplyWithError(replyID, INVALID_OPERATION);
2399 break;
2400 }
2401
2402 if (handleDequeueOutputBuffer(replyID, true /* new request */)) {
2403 break;
2404 }
2405
2406 int64_t timeoutUs;
2407 CHECK(msg->findInt64("timeoutUs", &timeoutUs));
2408
2409 if (timeoutUs == 0ll) {
2410 PostReplyWithError(replyID, -EAGAIN);
2411 break;
2412 }
2413
2414 mFlags |= kFlagDequeueOutputPending;
2415 mDequeueOutputReplyID = replyID;
2416
2417 if (timeoutUs > 0ll) {
2418 sp<AMessage> timeoutMsg =
2419 new AMessage(kWhatDequeueOutputTimedOut, this);
2420 timeoutMsg->setInt32(
2421 "generation", ++mDequeueOutputTimeoutGeneration);
2422 timeoutMsg->post(timeoutUs);
2423 }
2424 break;
2425 }
2426
2427 case kWhatDequeueOutputTimedOut:
2428 {
2429 int32_t generation;
2430 CHECK(msg->findInt32("generation", &generation));
2431
2432 if (generation != mDequeueOutputTimeoutGeneration) {
2433 // Obsolete
2434 break;
2435 }
2436
2437 CHECK(mFlags & kFlagDequeueOutputPending);
2438
2439 PostReplyWithError(mDequeueOutputReplyID, -EAGAIN);
2440
2441 mFlags &= ~kFlagDequeueOutputPending;
2442 mDequeueOutputReplyID = 0;
2443 break;
2444 }
2445
2446 case kWhatReleaseOutputBuffer:
2447 {
2448 sp<AReplyToken> replyID;
2449 CHECK(msg->senderAwaitsResponse(&replyID));
2450
2451 if (!isExecuting()) {
2452 PostReplyWithError(replyID, INVALID_OPERATION);
2453 break;
2454 } else if (mFlags & kFlagStickyError) {
2455 PostReplyWithError(replyID, getStickyError());
2456 break;
2457 }
2458
2459 status_t err = onReleaseOutputBuffer(msg);
2460
2461 PostReplyWithError(replyID, err);
2462 break;
2463 }
2464
2465 case kWhatSignalEndOfInputStream:
2466 {
2467 sp<AReplyToken> replyID;
2468 CHECK(msg->senderAwaitsResponse(&replyID));
2469
2470 if (!isExecuting() || !mHaveInputSurface) {
2471 PostReplyWithError(replyID, INVALID_OPERATION);
2472 break;
2473 } else if (mFlags & kFlagStickyError) {
2474 PostReplyWithError(replyID, getStickyError());
2475 break;
2476 }
2477
2478 mReplyID = replyID;
2479 mCodec->signalEndOfInputStream();
2480 break;
2481 }
2482
2483 case kWhatGetBuffers:
2484 {
2485 sp<AReplyToken> replyID;
2486 CHECK(msg->senderAwaitsResponse(&replyID));
2487 if (!isExecuting() || (mFlags & kFlagIsAsync)) {
2488 PostReplyWithError(replyID, INVALID_OPERATION);
2489 break;
2490 } else if (mFlags & kFlagStickyError) {
2491 PostReplyWithError(replyID, getStickyError());
2492 break;
2493 }
2494
2495 int32_t portIndex;
2496 CHECK(msg->findInt32("portIndex", &portIndex));
2497
2498 Vector<sp<MediaCodecBuffer> > *dstBuffers;
2499 CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
2500
2501 dstBuffers->clear();
2502 // If we're using input surface (either non-persistent created by
2503 // createInputSurface(), or persistent set by setInputSurface()),
2504 // give the client an empty input buffers array.
2505 if (portIndex != kPortIndexInput || !mHaveInputSurface) {
2506 if (portIndex == kPortIndexInput) {
2507 mBufferChannel->getInputBufferArray(dstBuffers);
2508 } else {
2509 mBufferChannel->getOutputBufferArray(dstBuffers);
2510 }
2511 }
2512
2513 (new AMessage)->postReply(replyID);
2514 break;
2515 }
2516
2517 case kWhatFlush:
2518 {
2519 sp<AReplyToken> replyID;
2520 CHECK(msg->senderAwaitsResponse(&replyID));
2521
2522 if (!isExecuting()) {
2523 PostReplyWithError(replyID, INVALID_OPERATION);
2524 break;
2525 } else if (mFlags & kFlagStickyError) {
2526 PostReplyWithError(replyID, getStickyError());
2527 break;
2528 }
2529
2530 mReplyID = replyID;
2531 // TODO: skip flushing if already FLUSHED
2532 setState(FLUSHING);
2533
2534 mCodec->signalFlush();
2535 returnBuffersToCodec();
2536 break;
2537 }
2538
2539 case kWhatGetInputFormat:
2540 case kWhatGetOutputFormat:
2541 {
2542 sp<AMessage> format =
2543 (msg->what() == kWhatGetOutputFormat ? mOutputFormat : mInputFormat);
2544
2545 sp<AReplyToken> replyID;
2546 CHECK(msg->senderAwaitsResponse(&replyID));
2547
2548 if ((mState != CONFIGURED && mState != STARTING &&
2549 mState != STARTED && mState != FLUSHING &&
2550 mState != FLUSHED)
2551 || format == NULL) {
2552 PostReplyWithError(replyID, INVALID_OPERATION);
2553 break;
2554 } else if (mFlags & kFlagStickyError) {
2555 PostReplyWithError(replyID, getStickyError());
2556 break;
2557 }
2558
2559 sp<AMessage> response = new AMessage;
2560 response->setMessage("format", format);
2561 response->postReply(replyID);
2562 break;
2563 }
2564
2565 case kWhatRequestIDRFrame:
2566 {
2567 mCodec->signalRequestIDRFrame();
2568 break;
2569 }
2570
2571 case kWhatRequestActivityNotification:
2572 {
2573 CHECK(mActivityNotify == NULL);
2574 CHECK(msg->findMessage("notify", &mActivityNotify));
2575
2576 postActivityNotificationIfPossible();
2577 break;
2578 }
2579
2580 case kWhatGetName:
2581 {
2582 sp<AReplyToken> replyID;
2583 CHECK(msg->senderAwaitsResponse(&replyID));
2584
2585 if (mComponentName.empty()) {
2586 PostReplyWithError(replyID, INVALID_OPERATION);
2587 break;
2588 }
2589
2590 sp<AMessage> response = new AMessage;
2591 response->setString("name", mComponentName.c_str());
2592 response->postReply(replyID);
2593 break;
2594 }
2595
2596 case kWhatSetParameters:
2597 {
2598 sp<AReplyToken> replyID;
2599 CHECK(msg->senderAwaitsResponse(&replyID));
2600
2601 sp<AMessage> params;
2602 CHECK(msg->findMessage("params", ¶ms));
2603
2604 status_t err = onSetParameters(params);
2605
2606 PostReplyWithError(replyID, err);
2607 break;
2608 }
2609
2610 case kWhatDrmReleaseCrypto:
2611 {
2612 onReleaseCrypto(msg);
2613 break;
2614 }
2615
2616 default:
2617 TRESPASS();
2618 }
2619 }
2620
extractCSD(const sp<AMessage> & format)2621 void MediaCodec::extractCSD(const sp<AMessage> &format) {
2622 mCSD.clear();
2623
2624 size_t i = 0;
2625 for (;;) {
2626 sp<ABuffer> csd;
2627 if (!format->findBuffer(AStringPrintf("csd-%u", i).c_str(), &csd)) {
2628 break;
2629 }
2630 if (csd->size() == 0) {
2631 ALOGW("csd-%zu size is 0", i);
2632 }
2633
2634 mCSD.push_back(csd);
2635 ++i;
2636 }
2637
2638 ALOGV("Found %zu pieces of codec specific data.", mCSD.size());
2639 }
2640
queueCSDInputBuffer(size_t bufferIndex)2641 status_t MediaCodec::queueCSDInputBuffer(size_t bufferIndex) {
2642 CHECK(!mCSD.empty());
2643
2644 const BufferInfo &info = mPortBuffers[kPortIndexInput][bufferIndex];
2645
2646 sp<ABuffer> csd = *mCSD.begin();
2647 mCSD.erase(mCSD.begin());
2648
2649 const sp<MediaCodecBuffer> &codecInputData = info.mData;
2650
2651 if (csd->size() > codecInputData->capacity()) {
2652 return -EINVAL;
2653 }
2654 if (codecInputData->data() == NULL) {
2655 ALOGV("Input buffer %zu is not properly allocated", bufferIndex);
2656 return -EINVAL;
2657 }
2658
2659 memcpy(codecInputData->data(), csd->data(), csd->size());
2660
2661 AString errorDetailMsg;
2662
2663 sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
2664 msg->setSize("index", bufferIndex);
2665 msg->setSize("offset", 0);
2666 msg->setSize("size", csd->size());
2667 msg->setInt64("timeUs", 0ll);
2668 msg->setInt32("flags", BUFFER_FLAG_CODECCONFIG);
2669 msg->setPointer("errorDetailMsg", &errorDetailMsg);
2670
2671 return onQueueInputBuffer(msg);
2672 }
2673
setState(State newState)2674 void MediaCodec::setState(State newState) {
2675 if (newState == INITIALIZED || newState == UNINITIALIZED) {
2676 delete mSoftRenderer;
2677 mSoftRenderer = NULL;
2678
2679 if ( mCrypto != NULL ) {
2680 ALOGV("setState: ~mCrypto: %p (%d)",
2681 mCrypto.get(), (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
2682 }
2683 mCrypto.clear();
2684 mDescrambler.clear();
2685 handleSetSurface(NULL);
2686
2687 mInputFormat.clear();
2688 mOutputFormat.clear();
2689 mFlags &= ~kFlagOutputFormatChanged;
2690 mFlags &= ~kFlagOutputBuffersChanged;
2691 mFlags &= ~kFlagStickyError;
2692 mFlags &= ~kFlagIsEncoder;
2693 mFlags &= ~kFlagIsAsync;
2694 mStickyError = OK;
2695
2696 mActivityNotify.clear();
2697 mCallback.clear();
2698 }
2699
2700 if (newState == UNINITIALIZED) {
2701 // return any straggling buffers, e.g. if we got here on an error
2702 returnBuffersToCodec();
2703
2704 // The component is gone, mediaserver's probably back up already
2705 // but should definitely be back up should we try to instantiate
2706 // another component.. and the cycle continues.
2707 mFlags &= ~kFlagSawMediaServerDie;
2708 }
2709
2710 mState = newState;
2711
2712 cancelPendingDequeueOperations();
2713
2714 updateBatteryStat();
2715 }
2716
returnBuffersToCodec(bool isReclaim)2717 void MediaCodec::returnBuffersToCodec(bool isReclaim) {
2718 returnBuffersToCodecOnPort(kPortIndexInput, isReclaim);
2719 returnBuffersToCodecOnPort(kPortIndexOutput, isReclaim);
2720 }
2721
returnBuffersToCodecOnPort(int32_t portIndex,bool isReclaim)2722 void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex, bool isReclaim) {
2723 CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
2724 Mutex::Autolock al(mBufferLock);
2725
2726 for (size_t i = 0; i < mPortBuffers[portIndex].size(); ++i) {
2727 BufferInfo *info = &mPortBuffers[portIndex][i];
2728
2729 if (info->mData != nullptr) {
2730 sp<MediaCodecBuffer> buffer = info->mData;
2731 if (isReclaim && info->mOwnedByClient) {
2732 ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
2733 portIndex, i);
2734 } else {
2735 info->mOwnedByClient = false;
2736 info->mData.clear();
2737 }
2738 mBufferChannel->discardBuffer(buffer);
2739 }
2740 }
2741
2742 mAvailPortBuffers[portIndex].clear();
2743 }
2744
updateBuffers(int32_t portIndex,const sp<AMessage> & msg)2745 size_t MediaCodec::updateBuffers(
2746 int32_t portIndex, const sp<AMessage> &msg) {
2747 CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
2748 size_t index;
2749 CHECK(msg->findSize("index", &index));
2750 sp<RefBase> obj;
2751 CHECK(msg->findObject("buffer", &obj));
2752 sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
2753
2754 {
2755 Mutex::Autolock al(mBufferLock);
2756 if (mPortBuffers[portIndex].size() <= index) {
2757 mPortBuffers[portIndex].resize(align(index + 1, kNumBuffersAlign));
2758 }
2759 mPortBuffers[portIndex][index].mData = buffer;
2760 }
2761 mAvailPortBuffers[portIndex].push_back(index);
2762
2763 return index;
2764 }
2765
onQueueInputBuffer(const sp<AMessage> & msg)2766 status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg) {
2767 size_t index;
2768 size_t offset;
2769 size_t size;
2770 int64_t timeUs;
2771 uint32_t flags;
2772 CHECK(msg->findSize("index", &index));
2773 CHECK(msg->findSize("offset", &offset));
2774 CHECK(msg->findInt64("timeUs", &timeUs));
2775 CHECK(msg->findInt32("flags", (int32_t *)&flags));
2776
2777 const CryptoPlugin::SubSample *subSamples;
2778 size_t numSubSamples;
2779 const uint8_t *key;
2780 const uint8_t *iv;
2781 CryptoPlugin::Mode mode = CryptoPlugin::kMode_Unencrypted;
2782
2783 // We allow the simpler queueInputBuffer API to be used even in
2784 // secure mode, by fabricating a single unencrypted subSample.
2785 CryptoPlugin::SubSample ss;
2786 CryptoPlugin::Pattern pattern;
2787
2788 if (msg->findSize("size", &size)) {
2789 if (hasCryptoOrDescrambler()) {
2790 ss.mNumBytesOfClearData = size;
2791 ss.mNumBytesOfEncryptedData = 0;
2792
2793 subSamples = &ss;
2794 numSubSamples = 1;
2795 key = NULL;
2796 iv = NULL;
2797 pattern.mEncryptBlocks = 0;
2798 pattern.mSkipBlocks = 0;
2799 }
2800 } else {
2801 if (!hasCryptoOrDescrambler()) {
2802 ALOGE("[%s] queuing secure buffer without mCrypto or mDescrambler!",
2803 mComponentName.c_str());
2804 return -EINVAL;
2805 }
2806
2807 CHECK(msg->findPointer("subSamples", (void **)&subSamples));
2808 CHECK(msg->findSize("numSubSamples", &numSubSamples));
2809 CHECK(msg->findPointer("key", (void **)&key));
2810 CHECK(msg->findPointer("iv", (void **)&iv));
2811 CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
2812 CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
2813
2814 int32_t tmp;
2815 CHECK(msg->findInt32("mode", &tmp));
2816
2817 mode = (CryptoPlugin::Mode)tmp;
2818
2819 size = 0;
2820 for (size_t i = 0; i < numSubSamples; ++i) {
2821 size += subSamples[i].mNumBytesOfClearData;
2822 size += subSamples[i].mNumBytesOfEncryptedData;
2823 }
2824 }
2825
2826 if (index >= mPortBuffers[kPortIndexInput].size()) {
2827 return -ERANGE;
2828 }
2829
2830 BufferInfo *info = &mPortBuffers[kPortIndexInput][index];
2831
2832 if (info->mData == nullptr || !info->mOwnedByClient) {
2833 return -EACCES;
2834 }
2835
2836 if (offset + size > info->mData->capacity()) {
2837 return -EINVAL;
2838 }
2839
2840 info->mData->setRange(offset, size);
2841 info->mData->meta()->setInt64("timeUs", timeUs);
2842 if (flags & BUFFER_FLAG_EOS) {
2843 info->mData->meta()->setInt32("eos", true);
2844 }
2845
2846 if (flags & BUFFER_FLAG_CODECCONFIG) {
2847 info->mData->meta()->setInt32("csd", true);
2848 }
2849
2850 sp<MediaCodecBuffer> buffer = info->mData;
2851 status_t err = OK;
2852 if (hasCryptoOrDescrambler()) {
2853 AString *errorDetailMsg;
2854 CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
2855
2856 err = mBufferChannel->queueSecureInputBuffer(
2857 buffer,
2858 (mFlags & kFlagIsSecure),
2859 key,
2860 iv,
2861 mode,
2862 pattern,
2863 subSamples,
2864 numSubSamples,
2865 errorDetailMsg);
2866 } else {
2867 err = mBufferChannel->queueInputBuffer(buffer);
2868 }
2869
2870 if (err == OK) {
2871 // synchronization boundary for getBufferAndFormat
2872 Mutex::Autolock al(mBufferLock);
2873 info->mOwnedByClient = false;
2874 info->mData.clear();
2875 if (mAnalyticsItem != NULL) {
2876 mAnalyticsItem->addInt64(kCodecBytesIn, size);
2877 }
2878 }
2879
2880 return err;
2881 }
2882
2883 //static
CreateFramesRenderedMessage(const std::list<FrameRenderTracker::Info> & done,sp<AMessage> & msg)2884 size_t MediaCodec::CreateFramesRenderedMessage(
2885 const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg) {
2886 size_t index = 0;
2887
2888 for (std::list<FrameRenderTracker::Info>::const_iterator it = done.cbegin();
2889 it != done.cend(); ++it) {
2890 if (it->getRenderTimeNs() < 0) {
2891 continue; // dropped frame from tracking
2892 }
2893 msg->setInt64(AStringPrintf("%zu-media-time-us", index).c_str(), it->getMediaTimeUs());
2894 msg->setInt64(AStringPrintf("%zu-system-nano", index).c_str(), it->getRenderTimeNs());
2895 ++index;
2896 }
2897 return index;
2898 }
2899
onReleaseOutputBuffer(const sp<AMessage> & msg)2900 status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) {
2901 size_t index;
2902 CHECK(msg->findSize("index", &index));
2903
2904 int32_t render;
2905 if (!msg->findInt32("render", &render)) {
2906 render = 0;
2907 }
2908
2909 if (!isExecuting()) {
2910 return -EINVAL;
2911 }
2912
2913 if (index >= mPortBuffers[kPortIndexOutput].size()) {
2914 return -ERANGE;
2915 }
2916
2917 BufferInfo *info = &mPortBuffers[kPortIndexOutput][index];
2918
2919 if (info->mData == nullptr || !info->mOwnedByClient) {
2920 return -EACCES;
2921 }
2922
2923 // synchronization boundary for getBufferAndFormat
2924 sp<MediaCodecBuffer> buffer;
2925 {
2926 Mutex::Autolock al(mBufferLock);
2927 info->mOwnedByClient = false;
2928 buffer = info->mData;
2929 info->mData.clear();
2930 }
2931
2932 if (render && buffer->size() != 0) {
2933 int64_t mediaTimeUs = -1;
2934 buffer->meta()->findInt64("timeUs", &mediaTimeUs);
2935
2936 int64_t renderTimeNs = 0;
2937 if (!msg->findInt64("timestampNs", &renderTimeNs)) {
2938 // use media timestamp if client did not request a specific render timestamp
2939 ALOGV("using buffer PTS of %lld", (long long)mediaTimeUs);
2940 renderTimeNs = mediaTimeUs * 1000;
2941 }
2942
2943 if (mSoftRenderer != NULL) {
2944 std::list<FrameRenderTracker::Info> doneFrames = mSoftRenderer->render(
2945 buffer->data(), buffer->size(),
2946 mediaTimeUs, renderTimeNs, NULL, buffer->format());
2947
2948 // if we are running, notify rendered frames
2949 if (!doneFrames.empty() && mState == STARTED && mOnFrameRenderedNotification != NULL) {
2950 sp<AMessage> notify = mOnFrameRenderedNotification->dup();
2951 sp<AMessage> data = new AMessage;
2952 if (CreateFramesRenderedMessage(doneFrames, data)) {
2953 notify->setMessage("data", data);
2954 notify->post();
2955 }
2956 }
2957 }
2958 mBufferChannel->renderOutputBuffer(buffer, renderTimeNs);
2959 } else {
2960 mBufferChannel->discardBuffer(buffer);
2961 }
2962
2963 return OK;
2964 }
2965
dequeuePortBuffer(int32_t portIndex)2966 ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) {
2967 CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
2968
2969 List<size_t> *availBuffers = &mAvailPortBuffers[portIndex];
2970
2971 if (availBuffers->empty()) {
2972 return -EAGAIN;
2973 }
2974
2975 size_t index = *availBuffers->begin();
2976 availBuffers->erase(availBuffers->begin());
2977
2978 BufferInfo *info = &mPortBuffers[portIndex][index];
2979 CHECK(!info->mOwnedByClient);
2980 {
2981 Mutex::Autolock al(mBufferLock);
2982 info->mOwnedByClient = true;
2983
2984 // set image-data
2985 if (info->mData->format() != NULL) {
2986 sp<ABuffer> imageData;
2987 if (info->mData->format()->findBuffer("image-data", &imageData)) {
2988 info->mData->meta()->setBuffer("image-data", imageData);
2989 }
2990 int32_t left, top, right, bottom;
2991 if (info->mData->format()->findRect("crop", &left, &top, &right, &bottom)) {
2992 info->mData->meta()->setRect("crop-rect", left, top, right, bottom);
2993 }
2994 }
2995 }
2996
2997 return index;
2998 }
2999
connectToSurface(const sp<Surface> & surface)3000 status_t MediaCodec::connectToSurface(const sp<Surface> &surface) {
3001 status_t err = OK;
3002 if (surface != NULL) {
3003 uint64_t oldId, newId;
3004 if (mSurface != NULL
3005 && surface->getUniqueId(&newId) == NO_ERROR
3006 && mSurface->getUniqueId(&oldId) == NO_ERROR
3007 && newId == oldId) {
3008 ALOGI("[%s] connecting to the same surface. Nothing to do.", mComponentName.c_str());
3009 return ALREADY_EXISTS;
3010 }
3011
3012 err = nativeWindowConnect(surface.get(), "connectToSurface");
3013 if (err == OK) {
3014 // Require a fresh set of buffers after each connect by using a unique generation
3015 // number. Rely on the fact that max supported process id by Linux is 2^22.
3016 // PID is never 0 so we don't have to worry that we use the default generation of 0.
3017 // TODO: come up with a unique scheme if other producers also set the generation number.
3018 static uint32_t mSurfaceGeneration = 0;
3019 uint32_t generation = (getpid() << 10) | (++mSurfaceGeneration & ((1 << 10) - 1));
3020 surface->setGenerationNumber(generation);
3021 ALOGI("[%s] setting surface generation to %u", mComponentName.c_str(), generation);
3022
3023 // HACK: clear any free buffers. Remove when connect will automatically do this.
3024 // This is needed as the consumer may be holding onto stale frames that it can reattach
3025 // to this surface after disconnect/connect, and those free frames would inherit the new
3026 // generation number. Disconnecting after setting a unique generation prevents this.
3027 nativeWindowDisconnect(surface.get(), "connectToSurface(reconnect)");
3028 err = nativeWindowConnect(surface.get(), "connectToSurface(reconnect)");
3029 }
3030
3031 if (err != OK) {
3032 ALOGE("nativeWindowConnect returned an error: %s (%d)", strerror(-err), err);
3033 }
3034 }
3035 // do not return ALREADY_EXISTS unless surfaces are the same
3036 return err == ALREADY_EXISTS ? BAD_VALUE : err;
3037 }
3038
disconnectFromSurface()3039 status_t MediaCodec::disconnectFromSurface() {
3040 status_t err = OK;
3041 if (mSurface != NULL) {
3042 // Resetting generation is not technically needed, but there is no need to keep it either
3043 mSurface->setGenerationNumber(0);
3044 err = nativeWindowDisconnect(mSurface.get(), "disconnectFromSurface");
3045 if (err != OK) {
3046 ALOGW("nativeWindowDisconnect returned an error: %s (%d)", strerror(-err), err);
3047 }
3048 // assume disconnected even on error
3049 mSurface.clear();
3050 }
3051 return err;
3052 }
3053
handleSetSurface(const sp<Surface> & surface)3054 status_t MediaCodec::handleSetSurface(const sp<Surface> &surface) {
3055 status_t err = OK;
3056 if (mSurface != NULL) {
3057 (void)disconnectFromSurface();
3058 }
3059 if (surface != NULL) {
3060 err = connectToSurface(surface);
3061 if (err == OK) {
3062 mSurface = surface;
3063 }
3064 }
3065 return err;
3066 }
3067
onInputBufferAvailable()3068 void MediaCodec::onInputBufferAvailable() {
3069 int32_t index;
3070 while ((index = dequeuePortBuffer(kPortIndexInput)) >= 0) {
3071 sp<AMessage> msg = mCallback->dup();
3072 msg->setInt32("callbackID", CB_INPUT_AVAILABLE);
3073 msg->setInt32("index", index);
3074 msg->post();
3075 }
3076 }
3077
onOutputBufferAvailable()3078 void MediaCodec::onOutputBufferAvailable() {
3079 int32_t index;
3080 while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) {
3081 const sp<MediaCodecBuffer> &buffer =
3082 mPortBuffers[kPortIndexOutput][index].mData;
3083 sp<AMessage> msg = mCallback->dup();
3084 msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE);
3085 msg->setInt32("index", index);
3086 msg->setSize("offset", buffer->offset());
3087 msg->setSize("size", buffer->size());
3088
3089 int64_t timeUs;
3090 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
3091
3092 msg->setInt64("timeUs", timeUs);
3093
3094 int32_t flags;
3095 CHECK(buffer->meta()->findInt32("flags", &flags));
3096
3097 msg->setInt32("flags", flags);
3098
3099 msg->post();
3100 }
3101 }
3102
onError(status_t err,int32_t actionCode,const char * detail)3103 void MediaCodec::onError(status_t err, int32_t actionCode, const char *detail) {
3104 if (mCallback != NULL) {
3105 sp<AMessage> msg = mCallback->dup();
3106 msg->setInt32("callbackID", CB_ERROR);
3107 msg->setInt32("err", err);
3108 msg->setInt32("actionCode", actionCode);
3109
3110 if (detail != NULL) {
3111 msg->setString("detail", detail);
3112 }
3113
3114 msg->post();
3115 }
3116 }
3117
onOutputFormatChanged()3118 void MediaCodec::onOutputFormatChanged() {
3119 if (mCallback != NULL) {
3120 sp<AMessage> msg = mCallback->dup();
3121 msg->setInt32("callbackID", CB_OUTPUT_FORMAT_CHANGED);
3122 msg->setMessage("format", mOutputFormat);
3123 msg->post();
3124 }
3125 }
3126
postActivityNotificationIfPossible()3127 void MediaCodec::postActivityNotificationIfPossible() {
3128 if (mActivityNotify == NULL) {
3129 return;
3130 }
3131
3132 bool isErrorOrOutputChanged =
3133 (mFlags & (kFlagStickyError
3134 | kFlagOutputBuffersChanged
3135 | kFlagOutputFormatChanged));
3136
3137 if (isErrorOrOutputChanged
3138 || !mAvailPortBuffers[kPortIndexInput].empty()
3139 || !mAvailPortBuffers[kPortIndexOutput].empty()) {
3140 mActivityNotify->setInt32("input-buffers",
3141 mAvailPortBuffers[kPortIndexInput].size());
3142
3143 if (isErrorOrOutputChanged) {
3144 // we want consumer to dequeue as many times as it can
3145 mActivityNotify->setInt32("output-buffers", INT32_MAX);
3146 } else {
3147 mActivityNotify->setInt32("output-buffers",
3148 mAvailPortBuffers[kPortIndexOutput].size());
3149 }
3150 mActivityNotify->post();
3151 mActivityNotify.clear();
3152 }
3153 }
3154
setParameters(const sp<AMessage> & params)3155 status_t MediaCodec::setParameters(const sp<AMessage> ¶ms) {
3156 sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
3157 msg->setMessage("params", params);
3158
3159 sp<AMessage> response;
3160 return PostAndAwaitResponse(msg, &response);
3161 }
3162
onSetParameters(const sp<AMessage> & params)3163 status_t MediaCodec::onSetParameters(const sp<AMessage> ¶ms) {
3164 mCodec->signalSetParameters(params);
3165
3166 return OK;
3167 }
3168
amendOutputFormatWithCodecSpecificData(const sp<MediaCodecBuffer> & buffer)3169 status_t MediaCodec::amendOutputFormatWithCodecSpecificData(
3170 const sp<MediaCodecBuffer> &buffer) {
3171 AString mime;
3172 CHECK(mOutputFormat->findString("mime", &mime));
3173
3174 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) {
3175 // Codec specific data should be SPS and PPS in a single buffer,
3176 // each prefixed by a startcode (0x00 0x00 0x00 0x01).
3177 // We separate the two and put them into the output format
3178 // under the keys "csd-0" and "csd-1".
3179
3180 unsigned csdIndex = 0;
3181
3182 const uint8_t *data = buffer->data();
3183 size_t size = buffer->size();
3184
3185 const uint8_t *nalStart;
3186 size_t nalSize;
3187 while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
3188 sp<ABuffer> csd = new ABuffer(nalSize + 4);
3189 memcpy(csd->data(), "\x00\x00\x00\x01", 4);
3190 memcpy(csd->data() + 4, nalStart, nalSize);
3191
3192 mOutputFormat->setBuffer(
3193 AStringPrintf("csd-%u", csdIndex).c_str(), csd);
3194
3195 ++csdIndex;
3196 }
3197
3198 if (csdIndex != 2) {
3199 return ERROR_MALFORMED;
3200 }
3201 } else {
3202 // For everything else we just stash the codec specific data into
3203 // the output format as a single piece of csd under "csd-0".
3204 sp<ABuffer> csd = new ABuffer(buffer->size());
3205 memcpy(csd->data(), buffer->data(), buffer->size());
3206 csd->setRange(0, buffer->size());
3207 mOutputFormat->setBuffer("csd-0", csd);
3208 }
3209
3210 return OK;
3211 }
3212
updateBatteryStat()3213 void MediaCodec::updateBatteryStat() {
3214 if (!mIsVideo) {
3215 return;
3216 }
3217
3218 if (mState == CONFIGURED && !mBatteryStatNotified) {
3219 BatteryNotifier::getInstance().noteStartVideo(mUid);
3220 mBatteryStatNotified = true;
3221 } else if (mState == UNINITIALIZED && mBatteryStatNotified) {
3222 BatteryNotifier::getInstance().noteStopVideo(mUid);
3223 mBatteryStatNotified = false;
3224 }
3225 }
3226
3227 } // namespace android
3228