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