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