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 "NdkMediaCryptoPriv.h"
25 #include "NdkMediaFormatPriv.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 = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
815     AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
816     if (!ret) {
817         ALOGE("couldn't allocate %zu bytes", cryptosize);
818         return NULL;
819     }
820     ret->numsubsamples = numsubsamples;
821     memcpy(ret->key, key, 16);
822     memcpy(ret->iv, iv, 16);
823     ret->mode = mode;
824     ret->pattern.encryptBlocks = 0;
825     ret->pattern.skipBlocks = 0;
826 
827     // clearbytes and encryptedbytes point at the actual data, which follows
828     ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
829     ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes
830 
831     memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
832     memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));
833 
834     return ret;
835 }
836 
837 
838 EXPORT
AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo * info)839 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
840     free(info);
841     return AMEDIA_OK;
842 }
843 
844 EXPORT
AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo * ci)845 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
846     return ci->numsubsamples;
847 }
848 
849 EXPORT
AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo * ci,uint8_t * dst)850 media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
851     if (!ci) {
852         return AMEDIA_ERROR_INVALID_OBJECT;
853     }
854     if (!dst) {
855         return AMEDIA_ERROR_INVALID_PARAMETER;
856     }
857     memcpy(dst, ci->key, 16);
858     return AMEDIA_OK;
859 }
860 
861 EXPORT
AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo * ci,uint8_t * dst)862 media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
863     if (!ci) {
864         return AMEDIA_ERROR_INVALID_OBJECT;
865     }
866     if (!dst) {
867         return AMEDIA_ERROR_INVALID_PARAMETER;
868     }
869     memcpy(dst, ci->iv, 16);
870     return AMEDIA_OK;
871 }
872 
873 EXPORT
AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo * ci)874 cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
875     if (!ci) {
876         return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT;
877     }
878     return ci->mode;
879 }
880 
881 EXPORT
AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo * ci,size_t * dst)882 media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
883     if (!ci) {
884         return AMEDIA_ERROR_INVALID_OBJECT;
885     }
886     if (!dst) {
887         return AMEDIA_ERROR_INVALID_PARAMETER;
888     }
889     memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
890     return AMEDIA_OK;
891 }
892 
893 EXPORT
AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo * ci,size_t * dst)894 media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
895     if (!ci) {
896         return AMEDIA_ERROR_INVALID_OBJECT;
897     }
898     if (!dst) {
899         return AMEDIA_ERROR_INVALID_PARAMETER;
900     }
901     memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
902     return AMEDIA_OK;
903 }
904 
905 } // extern "C"
906 
907