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