1 /*
2 * Copyright (C) 2014 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 #include <inttypes.h>
18
19 //#define LOG_NDEBUG 0
20 #define LOG_TAG "NdkMediaCodec"
21
22 #include <media/NdkMediaCodecPlatform.h>
23 #include <media/NdkMediaError.h>
24 #include <media/NdkMediaFormatPriv.h>
25 #include "NdkMediaCryptoPriv.h"
26
27 #include <utils/Log.h>
28 #include <utils/StrongPointer.h>
29 #include <gui/Surface.h>
30
31 #include <media/stagefright/foundation/ALooper.h>
32 #include <media/stagefright/foundation/AMessage.h>
33
34 #include <media/stagefright/PersistentSurface.h>
35 #include <media/stagefright/MediaCodec.h>
36 #include <media/stagefright/MediaErrors.h>
37 #include <media/MediaCodecBuffer.h>
38 #include <android/native_window.h>
39
40 using namespace android;
41
42
translate_error(status_t err)43 static media_status_t translate_error(status_t err) {
44 if (err == OK) {
45 return AMEDIA_OK;
46 } else if (err == -EAGAIN) {
47 return (media_status_t) AMEDIACODEC_INFO_TRY_AGAIN_LATER;
48 } else if (err == NO_MEMORY) {
49 return AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
50 } else if (err == DEAD_OBJECT) {
51 return AMEDIACODEC_ERROR_RECLAIMED;
52 }
53 ALOGE("sf error code: %d", err);
54 return AMEDIA_ERROR_UNKNOWN;
55 }
56
57 enum {
58 kWhatActivityNotify,
59 kWhatAsyncNotify,
60 kWhatRequestActivityNotifications,
61 kWhatStopActivityNotifications,
62 };
63
64 struct AMediaCodecPersistentSurface : public Surface {
65 sp<PersistentSurface> mPersistentSurface;
AMediaCodecPersistentSurfaceAMediaCodecPersistentSurface66 AMediaCodecPersistentSurface(
67 const sp<IGraphicBufferProducer>& igbp,
68 const sp<PersistentSurface>& ps)
69 : Surface(igbp) {
70 mPersistentSurface = ps;
71 }
~AMediaCodecPersistentSurfaceAMediaCodecPersistentSurface72 virtual ~AMediaCodecPersistentSurface() {
73 //mPersistentSurface ref will be let go off here
74 }
75 };
76
77 class CodecHandler: public AHandler {
78 private:
79 AMediaCodec* mCodec;
80 public:
81 explicit CodecHandler(AMediaCodec *codec);
82 virtual void onMessageReceived(const sp<AMessage> &msg);
83 };
84
85 typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
86
87 struct AMediaCodec {
88 sp<android::MediaCodec> mCodec;
89 sp<ALooper> mLooper;
90 sp<CodecHandler> mHandler;
91 sp<AMessage> mActivityNotification;
92 int32_t mGeneration;
93 bool mRequestedActivityNotification;
94 OnCodecEvent mCallback;
95 void *mCallbackUserData;
96
97 sp<AMessage> mAsyncNotify;
98 mutable Mutex mAsyncCallbackLock;
99 AMediaCodecOnAsyncNotifyCallback mAsyncCallback;
100 void *mAsyncCallbackUserData;
101 };
102
CodecHandler(AMediaCodec * codec)103 CodecHandler::CodecHandler(AMediaCodec *codec) {
104 mCodec = codec;
105 }
106
onMessageReceived(const sp<AMessage> & msg)107 void CodecHandler::onMessageReceived(const sp<AMessage> &msg) {
108
109 switch (msg->what()) {
110 case kWhatRequestActivityNotifications:
111 {
112 if (mCodec->mRequestedActivityNotification) {
113 break;
114 }
115
116 mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification);
117 mCodec->mRequestedActivityNotification = true;
118 break;
119 }
120
121 case kWhatActivityNotify:
122 {
123 {
124 int32_t generation;
125 msg->findInt32("generation", &generation);
126
127 if (generation != mCodec->mGeneration) {
128 // stale
129 break;
130 }
131
132 mCodec->mRequestedActivityNotification = false;
133 }
134
135 if (mCodec->mCallback) {
136 mCodec->mCallback(mCodec, mCodec->mCallbackUserData);
137 }
138 break;
139 }
140
141 case kWhatAsyncNotify:
142 {
143 int32_t cbID;
144 if (!msg->findInt32("callbackID", &cbID)) {
145 ALOGE("kWhatAsyncNotify: callbackID is expected.");
146 break;
147 }
148
149 ALOGV("kWhatAsyncNotify: cbID = %d", cbID);
150
151 switch (cbID) {
152 case MediaCodec::CB_INPUT_AVAILABLE:
153 {
154 int32_t index;
155 if (!msg->findInt32("index", &index)) {
156 ALOGE("CB_INPUT_AVAILABLE: index is expected.");
157 break;
158 }
159
160 Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
161 if (mCodec->mAsyncCallbackUserData != NULL
162 || mCodec->mAsyncCallback.onAsyncInputAvailable != NULL) {
163 mCodec->mAsyncCallback.onAsyncInputAvailable(
164 mCodec,
165 mCodec->mAsyncCallbackUserData,
166 index);
167 }
168
169 break;
170 }
171
172 case MediaCodec::CB_OUTPUT_AVAILABLE:
173 {
174 int32_t index;
175 size_t offset;
176 size_t size;
177 int64_t timeUs;
178 int32_t flags;
179
180 if (!msg->findInt32("index", &index)) {
181 ALOGE("CB_OUTPUT_AVAILABLE: index is expected.");
182 break;
183 }
184 if (!msg->findSize("offset", &offset)) {
185 ALOGE("CB_OUTPUT_AVAILABLE: offset is expected.");
186 break;
187 }
188 if (!msg->findSize("size", &size)) {
189 ALOGE("CB_OUTPUT_AVAILABLE: size is expected.");
190 break;
191 }
192 if (!msg->findInt64("timeUs", &timeUs)) {
193 ALOGE("CB_OUTPUT_AVAILABLE: timeUs is expected.");
194 break;
195 }
196 if (!msg->findInt32("flags", &flags)) {
197 ALOGE("CB_OUTPUT_AVAILABLE: flags is expected.");
198 break;
199 }
200
201 AMediaCodecBufferInfo bufferInfo = {
202 (int32_t)offset,
203 (int32_t)size,
204 timeUs,
205 (uint32_t)flags};
206
207 Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
208 if (mCodec->mAsyncCallbackUserData != NULL
209 || mCodec->mAsyncCallback.onAsyncOutputAvailable != NULL) {
210 mCodec->mAsyncCallback.onAsyncOutputAvailable(
211 mCodec,
212 mCodec->mAsyncCallbackUserData,
213 index,
214 &bufferInfo);
215 }
216
217 break;
218 }
219
220 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
221 {
222 sp<AMessage> format;
223 if (!msg->findMessage("format", &format)) {
224 ALOGE("CB_OUTPUT_FORMAT_CHANGED: format is expected.");
225 break;
226 }
227
228 // Here format is MediaCodec's internal copy of output format.
229 // Make a copy since the client might modify it.
230 sp<AMessage> copy;
231 if (format != nullptr) {
232 copy = format->dup();
233 }
234 AMediaFormat *aMediaFormat = AMediaFormat_fromMsg(©);
235
236 Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
237 if (mCodec->mAsyncCallbackUserData != NULL
238 || mCodec->mAsyncCallback.onAsyncFormatChanged != NULL) {
239 mCodec->mAsyncCallback.onAsyncFormatChanged(
240 mCodec,
241 mCodec->mAsyncCallbackUserData,
242 aMediaFormat);
243 }
244
245 break;
246 }
247
248 case MediaCodec::CB_ERROR:
249 {
250 status_t err;
251 int32_t actionCode;
252 AString detail;
253 if (!msg->findInt32("err", &err)) {
254 ALOGE("CB_ERROR: err is expected.");
255 break;
256 }
257 if (!msg->findInt32("actionCode", &actionCode)) {
258 ALOGE("CB_ERROR: actionCode is expected.");
259 break;
260 }
261 msg->findString("detail", &detail);
262 ALOGE("Codec reported error(0x%x), actionCode(%d), detail(%s)",
263 err, actionCode, detail.c_str());
264
265 Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
266 if (mCodec->mAsyncCallbackUserData != NULL
267 || mCodec->mAsyncCallback.onAsyncError != NULL) {
268 mCodec->mAsyncCallback.onAsyncError(
269 mCodec,
270 mCodec->mAsyncCallbackUserData,
271 translate_error(err),
272 actionCode,
273 detail.c_str());
274 }
275
276 break;
277 }
278
279 default:
280 {
281 ALOGE("kWhatAsyncNotify: callbackID(%d) is unexpected.", cbID);
282 break;
283 }
284 }
285 break;
286 }
287
288 case kWhatStopActivityNotifications:
289 {
290 sp<AReplyToken> replyID;
291 msg->senderAwaitsResponse(&replyID);
292
293 mCodec->mGeneration++;
294 mCodec->mRequestedActivityNotification = false;
295
296 sp<AMessage> response = new AMessage;
297 response->postReply(replyID);
298 break;
299 }
300
301 default:
302 ALOGE("shouldn't be here");
303 break;
304 }
305
306 }
307
308
requestActivityNotification(AMediaCodec * codec)309 static void requestActivityNotification(AMediaCodec *codec) {
310 (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post();
311 }
312
313 extern "C" {
314
createAMediaCodec(const char * name,bool name_is_type,bool encoder,pid_t pid=android::MediaCodec::kNoPid,uid_t uid=android::MediaCodec::kNoUid)315 static AMediaCodec * createAMediaCodec(const char *name,
316 bool name_is_type,
317 bool encoder,
318 pid_t pid = android::MediaCodec::kNoPid,
319 uid_t uid = android::MediaCodec::kNoUid) {
320 AMediaCodec *mData = new AMediaCodec();
321 mData->mLooper = new ALooper;
322 mData->mLooper->setName("NDK MediaCodec_looper");
323 size_t res = mData->mLooper->start(
324 false, // runOnCallingThread
325 true, // canCallJava XXX
326 PRIORITY_AUDIO);
327 if (res != OK) {
328 ALOGE("Failed to start the looper");
329 AMediaCodec_delete(mData);
330 return NULL;
331 }
332 if (name_is_type) {
333 mData->mCodec = android::MediaCodec::CreateByType(
334 mData->mLooper,
335 name,
336 encoder,
337 nullptr /* err */,
338 pid,
339 uid);
340 } else {
341 mData->mCodec = android::MediaCodec::CreateByComponentName(
342 mData->mLooper,
343 name,
344 nullptr /* err */,
345 pid,
346 uid);
347 }
348 if (mData->mCodec == NULL) { // failed to create codec
349 AMediaCodec_delete(mData);
350 return NULL;
351 }
352 mData->mHandler = new CodecHandler(mData);
353 mData->mLooper->registerHandler(mData->mHandler);
354 mData->mGeneration = 1;
355 mData->mRequestedActivityNotification = false;
356 mData->mCallback = NULL;
357
358 mData->mAsyncCallback = {};
359 mData->mAsyncCallbackUserData = NULL;
360
361 return mData;
362 }
363
364 EXPORT
AMediaCodec_createCodecByName(const char * name)365 AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
366 return createAMediaCodec(name, false /* name_is_type */, false /* encoder */);
367 }
368
369 EXPORT
AMediaCodec_createDecoderByType(const char * mime_type)370 AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
371 return createAMediaCodec(mime_type, true /* name_is_type */, false /* encoder */);
372 }
373
374 EXPORT
AMediaCodec_createEncoderByType(const char * name)375 AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
376 return createAMediaCodec(name, true /* name_is_type */, true /* encoder */);
377 }
378
379 EXPORT
AMediaCodec_createCodecByNameForClient(const char * name,pid_t pid,uid_t uid)380 AMediaCodec* AMediaCodec_createCodecByNameForClient(const char *name,
381 pid_t pid,
382 uid_t uid) {
383 return createAMediaCodec(name, false /* name_is_type */, false /* encoder */, pid, uid);
384 }
385
386 EXPORT
AMediaCodec_createDecoderByTypeForClient(const char * mime_type,pid_t pid,uid_t uid)387 AMediaCodec* AMediaCodec_createDecoderByTypeForClient(const char *mime_type,
388 pid_t pid,
389 uid_t uid) {
390 return createAMediaCodec(mime_type, true /* name_is_type */, false /* encoder */, pid, uid);
391 }
392
393 EXPORT
AMediaCodec_createEncoderByTypeForClient(const char * name,pid_t pid,uid_t uid)394 AMediaCodec* AMediaCodec_createEncoderByTypeForClient(const char *name,
395 pid_t pid,
396 uid_t uid) {
397 return createAMediaCodec(name, true /* name_is_type */, true /* encoder */, pid, uid);
398 }
399
400 EXPORT
AMediaCodec_delete(AMediaCodec * mData)401 media_status_t AMediaCodec_delete(AMediaCodec *mData) {
402 if (mData != NULL) {
403 if (mData->mCodec != NULL) {
404 mData->mCodec->release();
405 mData->mCodec.clear();
406 }
407
408 if (mData->mLooper != NULL) {
409 if (mData->mHandler != NULL) {
410 mData->mLooper->unregisterHandler(mData->mHandler->id());
411 }
412 mData->mLooper->stop();
413 mData->mLooper.clear();
414 }
415 delete mData;
416 }
417 return AMEDIA_OK;
418 }
419
420 EXPORT
AMediaCodec_getName(AMediaCodec * mData,char ** out_name)421 media_status_t AMediaCodec_getName(
422 AMediaCodec *mData,
423 char** out_name) {
424 if (out_name == NULL) {
425 return AMEDIA_ERROR_INVALID_PARAMETER;
426 }
427
428 AString compName;
429 status_t err = mData->mCodec->getName(&compName);
430 if (err != OK) {
431 return translate_error(err);
432 }
433 *out_name = strdup(compName.c_str());
434 return AMEDIA_OK;
435 }
436
437 EXPORT
AMediaCodec_releaseName(AMediaCodec *,char * name)438 void AMediaCodec_releaseName(
439 AMediaCodec * /* mData */,
440 char* name) {
441 if (name != NULL) {
442 free(name);
443 }
444 }
445
446 EXPORT
AMediaCodec_configure(AMediaCodec * mData,const AMediaFormat * format,ANativeWindow * window,AMediaCrypto * crypto,uint32_t flags)447 media_status_t AMediaCodec_configure(
448 AMediaCodec *mData,
449 const AMediaFormat* format,
450 ANativeWindow* window,
451 AMediaCrypto *crypto,
452 uint32_t flags) {
453 sp<AMessage> nativeFormat;
454 AMediaFormat_getFormat(format, &nativeFormat);
455 ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str());
456 sp<Surface> surface = NULL;
457 if (window != NULL) {
458 surface = (Surface*) window;
459 }
460
461 status_t err = mData->mCodec->configure(nativeFormat, surface,
462 crypto ? crypto->mCrypto : NULL, flags);
463 if (err != OK) {
464 ALOGE("configure: err(%d), failed with format: %s",
465 err, nativeFormat->debugString(0).c_str());
466 }
467 return translate_error(err);
468 }
469
470 EXPORT
AMediaCodec_setAsyncNotifyCallback(AMediaCodec * mData,AMediaCodecOnAsyncNotifyCallback callback,void * userdata)471 media_status_t AMediaCodec_setAsyncNotifyCallback(
472 AMediaCodec *mData,
473 AMediaCodecOnAsyncNotifyCallback callback,
474 void *userdata) {
475 if (mData->mAsyncNotify == NULL && userdata != NULL) {
476 mData->mAsyncNotify = new AMessage(kWhatAsyncNotify, mData->mHandler);
477 status_t err = mData->mCodec->setCallback(mData->mAsyncNotify);
478 if (err != OK) {
479 ALOGE("setAsyncNotifyCallback: err(%d), failed to set async callback", err);
480 return translate_error(err);
481 }
482 }
483
484 Mutex::Autolock _l(mData->mAsyncCallbackLock);
485 mData->mAsyncCallback = callback;
486 mData->mAsyncCallbackUserData = userdata;
487
488 return AMEDIA_OK;
489 }
490
491
492 EXPORT
AMediaCodec_releaseCrypto(AMediaCodec * mData)493 media_status_t AMediaCodec_releaseCrypto(AMediaCodec *mData) {
494 return translate_error(mData->mCodec->releaseCrypto());
495 }
496
497 EXPORT
AMediaCodec_start(AMediaCodec * mData)498 media_status_t AMediaCodec_start(AMediaCodec *mData) {
499 status_t ret = mData->mCodec->start();
500 if (ret != OK) {
501 return translate_error(ret);
502 }
503 mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler);
504 mData->mActivityNotification->setInt32("generation", mData->mGeneration);
505 requestActivityNotification(mData);
506 return AMEDIA_OK;
507 }
508
509 EXPORT
AMediaCodec_stop(AMediaCodec * mData)510 media_status_t AMediaCodec_stop(AMediaCodec *mData) {
511 media_status_t ret = translate_error(mData->mCodec->stop());
512
513 sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler);
514 sp<AMessage> response;
515 msg->postAndAwaitResponse(&response);
516 mData->mActivityNotification.clear();
517
518 return ret;
519 }
520
521 EXPORT
AMediaCodec_flush(AMediaCodec * mData)522 media_status_t AMediaCodec_flush(AMediaCodec *mData) {
523 return translate_error(mData->mCodec->flush());
524 }
525
526 EXPORT
AMediaCodec_dequeueInputBuffer(AMediaCodec * mData,int64_t timeoutUs)527 ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
528 size_t idx;
529 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
530 requestActivityNotification(mData);
531 if (ret == OK) {
532 return idx;
533 }
534 return translate_error(ret);
535 }
536
537 EXPORT
AMediaCodec_getInputBuffer(AMediaCodec * mData,size_t idx,size_t * out_size)538 uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
539 if (mData->mAsyncNotify != NULL) {
540 // Asynchronous mode
541 sp<MediaCodecBuffer> abuf;
542 if (mData->mCodec->getInputBuffer(idx, &abuf) != 0) {
543 return NULL;
544 }
545
546 if (out_size != NULL) {
547 *out_size = abuf->capacity();
548 }
549 return abuf->data();
550 }
551
552 android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
553 if (mData->mCodec->getInputBuffers(&abufs) == 0) {
554 size_t n = abufs.size();
555 if (idx >= n) {
556 ALOGE("buffer index %zu out of range", idx);
557 return NULL;
558 }
559 if (abufs[idx] == NULL) {
560 ALOGE("buffer index %zu is NULL", idx);
561 return NULL;
562 }
563 if (out_size != NULL) {
564 *out_size = abufs[idx]->capacity();
565 }
566 return abufs[idx]->data();
567 }
568 ALOGE("couldn't get input buffers");
569 return NULL;
570 }
571
572 EXPORT
AMediaCodec_getOutputBuffer(AMediaCodec * mData,size_t idx,size_t * out_size)573 uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
574 if (mData->mAsyncNotify != NULL) {
575 // Asynchronous mode
576 sp<MediaCodecBuffer> abuf;
577 if (mData->mCodec->getOutputBuffer(idx, &abuf) != 0) {
578 return NULL;
579 }
580
581 if (out_size != NULL) {
582 *out_size = abuf->capacity();
583 }
584 return abuf->data();
585 }
586
587 android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
588 if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
589 size_t n = abufs.size();
590 if (idx >= n) {
591 ALOGE("buffer index %zu out of range", idx);
592 return NULL;
593 }
594 if (out_size != NULL) {
595 *out_size = abufs[idx]->capacity();
596 }
597 return abufs[idx]->data();
598 }
599 ALOGE("couldn't get output buffers");
600 return NULL;
601 }
602
603 EXPORT
AMediaCodec_queueInputBuffer(AMediaCodec * mData,size_t idx,off_t offset,size_t size,uint64_t time,uint32_t flags)604 media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData,
605 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) {
606
607 AString errorMsg;
608 status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg);
609 return translate_error(ret);
610 }
611
612 EXPORT
AMediaCodec_dequeueOutputBuffer(AMediaCodec * mData,AMediaCodecBufferInfo * info,int64_t timeoutUs)613 ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
614 AMediaCodecBufferInfo *info, int64_t timeoutUs) {
615 size_t idx;
616 size_t offset;
617 size_t size;
618 uint32_t flags;
619 int64_t presentationTimeUs;
620 status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs,
621 &flags, timeoutUs);
622 requestActivityNotification(mData);
623 switch (ret) {
624 case OK:
625 info->offset = offset;
626 info->size = size;
627 info->flags = flags;
628 info->presentationTimeUs = presentationTimeUs;
629 return idx;
630 case -EAGAIN:
631 return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
632 case android::INFO_FORMAT_CHANGED:
633 return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED;
634 case INFO_OUTPUT_BUFFERS_CHANGED:
635 return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED;
636 default:
637 break;
638 }
639 return translate_error(ret);
640 }
641
642 EXPORT
AMediaCodec_getOutputFormat(AMediaCodec * mData)643 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
644 sp<AMessage> format;
645 mData->mCodec->getOutputFormat(&format);
646 return AMediaFormat_fromMsg(&format);
647 }
648
649 EXPORT
AMediaCodec_getInputFormat(AMediaCodec * mData)650 AMediaFormat* AMediaCodec_getInputFormat(AMediaCodec *mData) {
651 sp<AMessage> format;
652 mData->mCodec->getInputFormat(&format);
653 return AMediaFormat_fromMsg(&format);
654 }
655
656 EXPORT
AMediaCodec_getBufferFormat(AMediaCodec * mData,size_t index)657 AMediaFormat* AMediaCodec_getBufferFormat(AMediaCodec *mData, size_t index) {
658 sp<AMessage> format;
659 mData->mCodec->getOutputFormat(index, &format);
660 return AMediaFormat_fromMsg(&format);
661 }
662
663 EXPORT
AMediaCodec_releaseOutputBuffer(AMediaCodec * mData,size_t idx,bool render)664 media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
665 if (render) {
666 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
667 } else {
668 return translate_error(mData->mCodec->releaseOutputBuffer(idx));
669 }
670 }
671
672 EXPORT
AMediaCodec_releaseOutputBufferAtTime(AMediaCodec * mData,size_t idx,int64_t timestampNs)673 media_status_t AMediaCodec_releaseOutputBufferAtTime(
674 AMediaCodec *mData, size_t idx, int64_t timestampNs) {
675 ALOGV("render @ %" PRId64, timestampNs);
676 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
677 }
678
679 EXPORT
AMediaCodec_setOutputSurface(AMediaCodec * mData,ANativeWindow * window)680 media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) {
681 sp<Surface> surface = NULL;
682 if (window != NULL) {
683 surface = (Surface*) window;
684 }
685 return translate_error(mData->mCodec->setSurface(surface));
686 }
687
688 EXPORT
AMediaCodec_createInputSurface(AMediaCodec * mData,ANativeWindow ** surface)689 media_status_t AMediaCodec_createInputSurface(AMediaCodec *mData, ANativeWindow **surface) {
690 if (surface == NULL || mData == NULL) {
691 return AMEDIA_ERROR_INVALID_PARAMETER;
692 }
693 *surface = NULL;
694
695 sp<IGraphicBufferProducer> igbp = NULL;
696 status_t err = mData->mCodec->createInputSurface(&igbp);
697 if (err != NO_ERROR) {
698 return translate_error(err);
699 }
700
701 *surface = new Surface(igbp);
702 ANativeWindow_acquire(*surface);
703 return AMEDIA_OK;
704 }
705
706 EXPORT
AMediaCodec_createPersistentInputSurface(ANativeWindow ** surface)707 media_status_t AMediaCodec_createPersistentInputSurface(ANativeWindow **surface) {
708 if (surface == NULL) {
709 return AMEDIA_ERROR_INVALID_PARAMETER;
710 }
711 *surface = NULL;
712
713 sp<PersistentSurface> ps = MediaCodec::CreatePersistentInputSurface();
714 if (ps == NULL) {
715 return AMEDIA_ERROR_UNKNOWN;
716 }
717
718 sp<IGraphicBufferProducer> igbp = ps->getBufferProducer();
719 if (igbp == NULL) {
720 return AMEDIA_ERROR_UNKNOWN;
721 }
722
723 *surface = new AMediaCodecPersistentSurface(igbp, ps);
724 ANativeWindow_acquire(*surface);
725
726 return AMEDIA_OK;
727 }
728
729 EXPORT
AMediaCodec_setInputSurface(AMediaCodec * mData,ANativeWindow * surface)730 media_status_t AMediaCodec_setInputSurface(
731 AMediaCodec *mData, ANativeWindow *surface) {
732
733 if (surface == NULL || mData == NULL) {
734 return AMEDIA_ERROR_INVALID_PARAMETER;
735 }
736
737 AMediaCodecPersistentSurface *aMediaPersistentSurface =
738 static_cast<AMediaCodecPersistentSurface *>(surface);
739 if (aMediaPersistentSurface->mPersistentSurface == NULL) {
740 return AMEDIA_ERROR_INVALID_PARAMETER;
741 }
742
743 return translate_error(mData->mCodec->setInputSurface(
744 aMediaPersistentSurface->mPersistentSurface));
745 }
746
747 EXPORT
AMediaCodec_setParameters(AMediaCodec * mData,const AMediaFormat * params)748 media_status_t AMediaCodec_setParameters(
749 AMediaCodec *mData, const AMediaFormat* params) {
750 if (params == NULL || mData == NULL) {
751 return AMEDIA_ERROR_INVALID_PARAMETER;
752 }
753 sp<AMessage> nativeParams;
754 AMediaFormat_getFormat(params, &nativeParams);
755 ALOGV("setParameters: %s", nativeParams->debugString(0).c_str());
756
757 return translate_error(mData->mCodec->setParameters(nativeParams));
758 }
759
760 EXPORT
AMediaCodec_signalEndOfInputStream(AMediaCodec * mData)761 media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData) {
762
763 if (mData == NULL) {
764 return AMEDIA_ERROR_INVALID_PARAMETER;
765 }
766
767 status_t err = mData->mCodec->signalEndOfInputStream();
768 if (err == INVALID_OPERATION) {
769 return AMEDIA_ERROR_INVALID_OPERATION;
770 }
771
772 return translate_error(err);
773
774 }
775
776 //EXPORT
AMediaCodec_setNotificationCallback(AMediaCodec * mData,OnCodecEvent callback,void * userdata)777 media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
778 void *userdata) {
779 mData->mCallback = callback;
780 mData->mCallbackUserData = userdata;
781 return AMEDIA_OK;
782 }
783
784 typedef struct AMediaCodecCryptoInfo {
785 int numsubsamples;
786 uint8_t key[16];
787 uint8_t iv[16];
788 cryptoinfo_mode_t mode;
789 cryptoinfo_pattern_t pattern;
790 size_t *clearbytes;
791 size_t *encryptedbytes;
792 } AMediaCodecCryptoInfo;
793
794 EXPORT
AMediaCodec_queueSecureInputBuffer(AMediaCodec * codec,size_t idx,off_t offset,AMediaCodecCryptoInfo * crypto,uint64_t time,uint32_t flags)795 media_status_t AMediaCodec_queueSecureInputBuffer(
796 AMediaCodec* codec,
797 size_t idx,
798 off_t offset,
799 AMediaCodecCryptoInfo* crypto,
800 uint64_t time,
801 uint32_t flags) {
802
803 CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples];
804 for (int i = 0; i < crypto->numsubsamples; i++) {
805 subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i];
806 subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
807 }
808
809 CryptoPlugin::Pattern pattern;
810 pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
811 pattern.mSkipBlocks = crypto->pattern.skipBlocks;
812
813 AString errormsg;
814 status_t err = codec->mCodec->queueSecureInputBuffer(idx,
815 offset,
816 subSamples,
817 crypto->numsubsamples,
818 crypto->key,
819 crypto->iv,
820 (CryptoPlugin::Mode)crypto->mode,
821 pattern,
822 time,
823 flags,
824 &errormsg);
825 if (err != 0) {
826 ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
827 }
828 delete [] subSamples;
829 return translate_error(err);
830 }
831
832 EXPORT
AMediaCodecActionCode_isRecoverable(int32_t actionCode)833 bool AMediaCodecActionCode_isRecoverable(int32_t actionCode) {
834 return (actionCode == ACTION_CODE_RECOVERABLE);
835 }
836
837 EXPORT
AMediaCodecActionCode_isTransient(int32_t actionCode)838 bool AMediaCodecActionCode_isTransient(int32_t actionCode) {
839 return (actionCode == ACTION_CODE_TRANSIENT);
840 }
841
842
843 EXPORT
AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo * info,cryptoinfo_pattern_t * pattern)844 void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
845 cryptoinfo_pattern_t *pattern) {
846 info->pattern.encryptBlocks = pattern->encryptBlocks;
847 info->pattern.skipBlocks = pattern->skipBlocks;
848 }
849
850 EXPORT
AMediaCodecCryptoInfo_new(int numsubsamples,uint8_t key[16],uint8_t iv[16],cryptoinfo_mode_t mode,size_t * clearbytes,size_t * encryptedbytes)851 AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
852 int numsubsamples,
853 uint8_t key[16],
854 uint8_t iv[16],
855 cryptoinfo_mode_t mode,
856 size_t *clearbytes,
857 size_t *encryptedbytes) {
858
859 // size needed to store all the crypto data
860 size_t cryptosize;
861 // = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
862 if (__builtin_mul_overflow(sizeof(size_t) * 2, numsubsamples, &cryptosize) ||
863 __builtin_add_overflow(cryptosize, sizeof(AMediaCodecCryptoInfo), &cryptosize)) {
864 ALOGE("crypto size overflow");
865 return NULL;
866 }
867 AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
868 if (!ret) {
869 ALOGE("couldn't allocate %zu bytes", cryptosize);
870 return NULL;
871 }
872 ret->numsubsamples = numsubsamples;
873 memcpy(ret->key, key, 16);
874 memcpy(ret->iv, iv, 16);
875 ret->mode = mode;
876 ret->pattern.encryptBlocks = 0;
877 ret->pattern.skipBlocks = 0;
878
879 // clearbytes and encryptedbytes point at the actual data, which follows
880 ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
881 ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes
882
883 memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
884 memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));
885
886 return ret;
887 }
888
889
890 EXPORT
AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo * info)891 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
892 free(info);
893 return AMEDIA_OK;
894 }
895
896 EXPORT
AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo * ci)897 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
898 return ci->numsubsamples;
899 }
900
901 EXPORT
AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo * ci,uint8_t * dst)902 media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
903 if (!ci) {
904 return AMEDIA_ERROR_INVALID_OBJECT;
905 }
906 if (!dst) {
907 return AMEDIA_ERROR_INVALID_PARAMETER;
908 }
909 memcpy(dst, ci->key, 16);
910 return AMEDIA_OK;
911 }
912
913 EXPORT
AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo * ci,uint8_t * dst)914 media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
915 if (!ci) {
916 return AMEDIA_ERROR_INVALID_OBJECT;
917 }
918 if (!dst) {
919 return AMEDIA_ERROR_INVALID_PARAMETER;
920 }
921 memcpy(dst, ci->iv, 16);
922 return AMEDIA_OK;
923 }
924
925 EXPORT
AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo * ci)926 cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
927 if (!ci) {
928 return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT;
929 }
930 return ci->mode;
931 }
932
933 EXPORT
AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo * ci,size_t * dst)934 media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
935 if (!ci) {
936 return AMEDIA_ERROR_INVALID_OBJECT;
937 }
938 if (!dst) {
939 return AMEDIA_ERROR_INVALID_PARAMETER;
940 }
941 memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
942 return AMEDIA_OK;
943 }
944
945 EXPORT
AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo * ci,size_t * dst)946 media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
947 if (!ci) {
948 return AMEDIA_ERROR_INVALID_OBJECT;
949 }
950 if (!dst) {
951 return AMEDIA_ERROR_INVALID_PARAMETER;
952 }
953 memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
954 return AMEDIA_OK;
955 }
956
957 EXPORT const char* AMEDIACODEC_KEY_HDR10_PLUS_INFO = AMEDIAFORMAT_KEY_HDR10_PLUS_INFO;
958 EXPORT const char* AMEDIACODEC_KEY_LOW_LATENCY = AMEDIAFORMAT_KEY_LOW_LATENCY;
959 EXPORT const char* AMEDIACODEC_KEY_OFFSET_TIME = "time-offset-us";
960 EXPORT const char* AMEDIACODEC_KEY_REQUEST_SYNC_FRAME = "request-sync";
961 EXPORT const char* AMEDIACODEC_KEY_SUSPEND = "drop-input-frames";
962 EXPORT const char* AMEDIACODEC_KEY_SUSPEND_TIME = "drop-start-time-us";
963 EXPORT const char* AMEDIACODEC_KEY_VIDEO_BITRATE = "video-bitrate";
964
965 } // extern "C"
966
967