• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&copy);
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