• 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             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(&copy);
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