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