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