• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <inttypes.h>
18 
19 //#define LOG_NDEBUG 0
20 #define LOG_TAG "NdkMediaCodec"
21 
22 #include <media/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     kWhatRequestActivityNotifications,
56     kWhatStopActivityNotifications,
57 };
58 
59 struct AMediaCodecPersistentSurface : public Surface {
60     sp<PersistentSurface> mPersistentSurface;
AMediaCodecPersistentSurfaceAMediaCodecPersistentSurface61     AMediaCodecPersistentSurface(
62             const sp<IGraphicBufferProducer>& igbp,
63             const sp<PersistentSurface>& ps)
64             : Surface(igbp) {
65         mPersistentSurface = ps;
66     }
~AMediaCodecPersistentSurfaceAMediaCodecPersistentSurface67     virtual ~AMediaCodecPersistentSurface() {
68         //mPersistentSurface ref will be let go off here
69     }
70 };
71 
72 class CodecHandler: public AHandler {
73 private:
74     AMediaCodec* mCodec;
75 public:
76     explicit CodecHandler(AMediaCodec *codec);
77     virtual void onMessageReceived(const sp<AMessage> &msg);
78 };
79 
80 typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
81 
82 struct AMediaCodec {
83     sp<android::MediaCodec> mCodec;
84     sp<ALooper> mLooper;
85     sp<CodecHandler> mHandler;
86     sp<AMessage> mActivityNotification;
87     int32_t mGeneration;
88     bool mRequestedActivityNotification;
89     OnCodecEvent mCallback;
90     void *mCallbackUserData;
91 };
92 
CodecHandler(AMediaCodec * codec)93 CodecHandler::CodecHandler(AMediaCodec *codec) {
94     mCodec = codec;
95 }
96 
onMessageReceived(const sp<AMessage> & msg)97 void CodecHandler::onMessageReceived(const sp<AMessage> &msg) {
98 
99     switch (msg->what()) {
100         case kWhatRequestActivityNotifications:
101         {
102             if (mCodec->mRequestedActivityNotification) {
103                 break;
104             }
105 
106             mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification);
107             mCodec->mRequestedActivityNotification = true;
108             break;
109         }
110 
111         case kWhatActivityNotify:
112         {
113             {
114                 int32_t generation;
115                 msg->findInt32("generation", &generation);
116 
117                 if (generation != mCodec->mGeneration) {
118                     // stale
119                     break;
120                 }
121 
122                 mCodec->mRequestedActivityNotification = false;
123             }
124 
125             if (mCodec->mCallback) {
126                 mCodec->mCallback(mCodec, mCodec->mCallbackUserData);
127             }
128             break;
129         }
130 
131         case kWhatStopActivityNotifications:
132         {
133             sp<AReplyToken> replyID;
134             msg->senderAwaitsResponse(&replyID);
135 
136             mCodec->mGeneration++;
137             mCodec->mRequestedActivityNotification = false;
138 
139             sp<AMessage> response = new AMessage;
140             response->postReply(replyID);
141             break;
142         }
143 
144         default:
145             ALOGE("shouldn't be here");
146             break;
147     }
148 
149 }
150 
151 
requestActivityNotification(AMediaCodec * codec)152 static void requestActivityNotification(AMediaCodec *codec) {
153     (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post();
154 }
155 
156 extern "C" {
157 
createAMediaCodec(const char * name,bool name_is_type,bool encoder)158 static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool encoder) {
159     AMediaCodec *mData = new AMediaCodec();
160     mData->mLooper = new ALooper;
161     mData->mLooper->setName("NDK MediaCodec_looper");
162     size_t res = mData->mLooper->start(
163             false,      // runOnCallingThread
164             true,       // canCallJava XXX
165             PRIORITY_FOREGROUND);
166     if (res != OK) {
167         ALOGE("Failed to start the looper");
168         AMediaCodec_delete(mData);
169         return NULL;
170     }
171     if (name_is_type) {
172         mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder);
173     } else {
174         mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name);
175     }
176     if (mData->mCodec == NULL) {  // failed to create codec
177         AMediaCodec_delete(mData);
178         return NULL;
179     }
180     mData->mHandler = new CodecHandler(mData);
181     mData->mLooper->registerHandler(mData->mHandler);
182     mData->mGeneration = 1;
183     mData->mRequestedActivityNotification = false;
184     mData->mCallback = NULL;
185 
186     return mData;
187 }
188 
189 EXPORT
AMediaCodec_createCodecByName(const char * name)190 AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
191     return createAMediaCodec(name, false, false);
192 }
193 
194 EXPORT
AMediaCodec_createDecoderByType(const char * mime_type)195 AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
196     return createAMediaCodec(mime_type, true, false);
197 }
198 
199 EXPORT
AMediaCodec_createEncoderByType(const char * name)200 AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
201     return createAMediaCodec(name, true, true);
202 }
203 
204 EXPORT
AMediaCodec_delete(AMediaCodec * mData)205 media_status_t AMediaCodec_delete(AMediaCodec *mData) {
206     if (mData != NULL) {
207         if (mData->mCodec != NULL) {
208             mData->mCodec->release();
209             mData->mCodec.clear();
210         }
211 
212         if (mData->mLooper != NULL) {
213             if (mData->mHandler != NULL) {
214                 mData->mLooper->unregisterHandler(mData->mHandler->id());
215             }
216             mData->mLooper->stop();
217             mData->mLooper.clear();
218         }
219         delete mData;
220     }
221     return AMEDIA_OK;
222 }
223 
224 EXPORT
AMediaCodec_configure(AMediaCodec * mData,const AMediaFormat * format,ANativeWindow * window,AMediaCrypto * crypto,uint32_t flags)225 media_status_t AMediaCodec_configure(
226         AMediaCodec *mData,
227         const AMediaFormat* format,
228         ANativeWindow* window,
229         AMediaCrypto *crypto,
230         uint32_t flags) {
231     sp<AMessage> nativeFormat;
232     AMediaFormat_getFormat(format, &nativeFormat);
233     ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str());
234     sp<Surface> surface = NULL;
235     if (window != NULL) {
236         surface = (Surface*) window;
237     }
238 
239     return translate_error(mData->mCodec->configure(nativeFormat, surface,
240             crypto ? crypto->mCrypto : NULL, flags));
241 }
242 
243 EXPORT
AMediaCodec_start(AMediaCodec * mData)244 media_status_t AMediaCodec_start(AMediaCodec *mData) {
245     status_t ret =  mData->mCodec->start();
246     if (ret != OK) {
247         return translate_error(ret);
248     }
249     mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler);
250     mData->mActivityNotification->setInt32("generation", mData->mGeneration);
251     requestActivityNotification(mData);
252     return AMEDIA_OK;
253 }
254 
255 EXPORT
AMediaCodec_stop(AMediaCodec * mData)256 media_status_t AMediaCodec_stop(AMediaCodec *mData) {
257     media_status_t ret = translate_error(mData->mCodec->stop());
258 
259     sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler);
260     sp<AMessage> response;
261     msg->postAndAwaitResponse(&response);
262     mData->mActivityNotification.clear();
263 
264     return ret;
265 }
266 
267 EXPORT
AMediaCodec_flush(AMediaCodec * mData)268 media_status_t AMediaCodec_flush(AMediaCodec *mData) {
269     return translate_error(mData->mCodec->flush());
270 }
271 
272 EXPORT
AMediaCodec_dequeueInputBuffer(AMediaCodec * mData,int64_t timeoutUs)273 ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
274     size_t idx;
275     status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
276     requestActivityNotification(mData);
277     if (ret == OK) {
278         return idx;
279     }
280     return translate_error(ret);
281 }
282 
283 EXPORT
AMediaCodec_getInputBuffer(AMediaCodec * mData,size_t idx,size_t * out_size)284 uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
285     android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
286     if (mData->mCodec->getInputBuffers(&abufs) == 0) {
287         size_t n = abufs.size();
288         if (idx >= n) {
289             ALOGE("buffer index %zu out of range", idx);
290             return NULL;
291         }
292         if (abufs[idx] == NULL) {
293             ALOGE("buffer index %zu is NULL", idx);
294             return NULL;
295         }
296         if (out_size != NULL) {
297             *out_size = abufs[idx]->capacity();
298         }
299         return abufs[idx]->data();
300     }
301     ALOGE("couldn't get input buffers");
302     return NULL;
303 }
304 
305 EXPORT
AMediaCodec_getOutputBuffer(AMediaCodec * mData,size_t idx,size_t * out_size)306 uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
307     android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
308     if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
309         size_t n = abufs.size();
310         if (idx >= n) {
311             ALOGE("buffer index %zu out of range", idx);
312             return NULL;
313         }
314         if (out_size != NULL) {
315             *out_size = abufs[idx]->capacity();
316         }
317         return abufs[idx]->data();
318     }
319     ALOGE("couldn't get output buffers");
320     return NULL;
321 }
322 
323 EXPORT
AMediaCodec_queueInputBuffer(AMediaCodec * mData,size_t idx,off_t offset,size_t size,uint64_t time,uint32_t flags)324 media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData,
325         size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) {
326 
327     AString errorMsg;
328     status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg);
329     return translate_error(ret);
330 }
331 
332 EXPORT
AMediaCodec_dequeueOutputBuffer(AMediaCodec * mData,AMediaCodecBufferInfo * info,int64_t timeoutUs)333 ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
334         AMediaCodecBufferInfo *info, int64_t timeoutUs) {
335     size_t idx;
336     size_t offset;
337     size_t size;
338     uint32_t flags;
339     int64_t presentationTimeUs;
340     status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs,
341             &flags, timeoutUs);
342     requestActivityNotification(mData);
343     switch (ret) {
344         case OK:
345             info->offset = offset;
346             info->size = size;
347             info->flags = flags;
348             info->presentationTimeUs = presentationTimeUs;
349             return idx;
350         case -EAGAIN:
351             return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
352         case android::INFO_FORMAT_CHANGED:
353             return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED;
354         case INFO_OUTPUT_BUFFERS_CHANGED:
355             return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED;
356         default:
357             break;
358     }
359     return translate_error(ret);
360 }
361 
362 EXPORT
AMediaCodec_getOutputFormat(AMediaCodec * mData)363 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
364     sp<AMessage> format;
365     mData->mCodec->getOutputFormat(&format);
366     return AMediaFormat_fromMsg(&format);
367 }
368 
369 EXPORT
AMediaCodec_releaseOutputBuffer(AMediaCodec * mData,size_t idx,bool render)370 media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
371     if (render) {
372         return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
373     } else {
374         return translate_error(mData->mCodec->releaseOutputBuffer(idx));
375     }
376 }
377 
378 EXPORT
AMediaCodec_releaseOutputBufferAtTime(AMediaCodec * mData,size_t idx,int64_t timestampNs)379 media_status_t AMediaCodec_releaseOutputBufferAtTime(
380         AMediaCodec *mData, size_t idx, int64_t timestampNs) {
381     ALOGV("render @ %" PRId64, timestampNs);
382     return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
383 }
384 
385 EXPORT
AMediaCodec_setOutputSurface(AMediaCodec * mData,ANativeWindow * window)386 media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) {
387     sp<Surface> surface = NULL;
388     if (window != NULL) {
389         surface = (Surface*) window;
390     }
391     return translate_error(mData->mCodec->setSurface(surface));
392 }
393 
394 EXPORT
AMediaCodec_createInputSurface(AMediaCodec * mData,ANativeWindow ** surface)395 media_status_t AMediaCodec_createInputSurface(AMediaCodec *mData, ANativeWindow **surface) {
396     if (surface == NULL || mData == NULL) {
397         return AMEDIA_ERROR_INVALID_PARAMETER;
398     }
399     *surface = NULL;
400 
401     sp<IGraphicBufferProducer> igbp = NULL;
402     status_t err = mData->mCodec->createInputSurface(&igbp);
403     if (err != NO_ERROR) {
404         return translate_error(err);
405     }
406 
407     *surface = new Surface(igbp);
408     ANativeWindow_acquire(*surface);
409     return AMEDIA_OK;
410 }
411 
412 EXPORT
AMediaCodec_createPersistentInputSurface(ANativeWindow ** surface)413 media_status_t AMediaCodec_createPersistentInputSurface(ANativeWindow **surface) {
414     if (surface == NULL) {
415         return AMEDIA_ERROR_INVALID_PARAMETER;
416     }
417     *surface = NULL;
418 
419     sp<PersistentSurface> ps = MediaCodec::CreatePersistentInputSurface();
420     if (ps == NULL) {
421         return AMEDIA_ERROR_UNKNOWN;
422     }
423 
424     sp<IGraphicBufferProducer> igbp = ps->getBufferProducer();
425     if (igbp == NULL) {
426         return AMEDIA_ERROR_UNKNOWN;
427     }
428 
429     *surface = new AMediaCodecPersistentSurface(igbp, ps);
430     ANativeWindow_acquire(*surface);
431 
432     return AMEDIA_OK;
433 }
434 
435 EXPORT
AMediaCodec_setInputSurface(AMediaCodec * mData,ANativeWindow * surface)436 media_status_t AMediaCodec_setInputSurface(
437         AMediaCodec *mData, ANativeWindow *surface) {
438 
439     if (surface == NULL || mData == NULL) {
440         return AMEDIA_ERROR_INVALID_PARAMETER;
441     }
442 
443     AMediaCodecPersistentSurface *aMediaPersistentSurface =
444             static_cast<AMediaCodecPersistentSurface *>(surface);
445     if (aMediaPersistentSurface->mPersistentSurface == NULL) {
446         return AMEDIA_ERROR_INVALID_PARAMETER;
447     }
448 
449     return translate_error(mData->mCodec->setInputSurface(
450             aMediaPersistentSurface->mPersistentSurface));
451 }
452 
453 EXPORT
AMediaCodec_setParameters(AMediaCodec * mData,const AMediaFormat * params)454 media_status_t AMediaCodec_setParameters(
455         AMediaCodec *mData, const AMediaFormat* params) {
456     if (params == NULL || mData == NULL) {
457         return AMEDIA_ERROR_INVALID_PARAMETER;
458     }
459     sp<AMessage> nativeParams;
460     AMediaFormat_getFormat(params, &nativeParams);
461     ALOGV("setParameters: %s", nativeParams->debugString(0).c_str());
462 
463     return translate_error(mData->mCodec->setParameters(nativeParams));
464 }
465 
466 EXPORT
AMediaCodec_signalEndOfInputStream(AMediaCodec * mData)467 media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData) {
468 
469     if (mData == NULL) {
470         return AMEDIA_ERROR_INVALID_PARAMETER;
471     }
472 
473     status_t err = mData->mCodec->signalEndOfInputStream();
474     if (err == INVALID_OPERATION) {
475         return AMEDIA_ERROR_INVALID_OPERATION;
476     }
477 
478     return translate_error(err);
479 
480 }
481 
482 //EXPORT
AMediaCodec_setNotificationCallback(AMediaCodec * mData,OnCodecEvent callback,void * userdata)483 media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
484         void *userdata) {
485     mData->mCallback = callback;
486     mData->mCallbackUserData = userdata;
487     return AMEDIA_OK;
488 }
489 
490 typedef struct AMediaCodecCryptoInfo {
491         int numsubsamples;
492         uint8_t key[16];
493         uint8_t iv[16];
494         cryptoinfo_mode_t mode;
495         cryptoinfo_pattern_t pattern;
496         size_t *clearbytes;
497         size_t *encryptedbytes;
498 } AMediaCodecCryptoInfo;
499 
500 EXPORT
AMediaCodec_queueSecureInputBuffer(AMediaCodec * codec,size_t idx,off_t offset,AMediaCodecCryptoInfo * crypto,uint64_t time,uint32_t flags)501 media_status_t AMediaCodec_queueSecureInputBuffer(
502         AMediaCodec* codec,
503         size_t idx,
504         off_t offset,
505         AMediaCodecCryptoInfo* crypto,
506         uint64_t time,
507         uint32_t flags) {
508 
509     CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples];
510     for (int i = 0; i < crypto->numsubsamples; i++) {
511         subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i];
512         subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
513     }
514 
515     CryptoPlugin::Pattern pattern;
516     pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
517     pattern.mSkipBlocks = crypto->pattern.skipBlocks;
518 
519     AString errormsg;
520     status_t err  = codec->mCodec->queueSecureInputBuffer(idx,
521             offset,
522             subSamples,
523             crypto->numsubsamples,
524             crypto->key,
525             crypto->iv,
526             (CryptoPlugin::Mode)crypto->mode,
527             pattern,
528             time,
529             flags,
530             &errormsg);
531     if (err != 0) {
532         ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
533     }
534     delete [] subSamples;
535     return translate_error(err);
536 }
537 
538 
539 EXPORT
AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo * info,cryptoinfo_pattern_t * pattern)540 void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
541         cryptoinfo_pattern_t *pattern) {
542     info->pattern.encryptBlocks = pattern->encryptBlocks;
543     info->pattern.skipBlocks = pattern->skipBlocks;
544 }
545 
546 EXPORT
AMediaCodecCryptoInfo_new(int numsubsamples,uint8_t key[16],uint8_t iv[16],cryptoinfo_mode_t mode,size_t * clearbytes,size_t * encryptedbytes)547 AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
548         int numsubsamples,
549         uint8_t key[16],
550         uint8_t iv[16],
551         cryptoinfo_mode_t mode,
552         size_t *clearbytes,
553         size_t *encryptedbytes) {
554 
555     // size needed to store all the crypto data
556     size_t cryptosize;
557     // = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
558     if (__builtin_mul_overflow(sizeof(size_t) * 2, numsubsamples, &cryptosize) ||
559             __builtin_add_overflow(cryptosize, sizeof(AMediaCodecCryptoInfo), &cryptosize)) {
560         ALOGE("crypto size overflow");
561         return NULL;
562     }
563     AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
564     if (!ret) {
565         ALOGE("couldn't allocate %zu bytes", cryptosize);
566         return NULL;
567     }
568     ret->numsubsamples = numsubsamples;
569     memcpy(ret->key, key, 16);
570     memcpy(ret->iv, iv, 16);
571     ret->mode = mode;
572     ret->pattern.encryptBlocks = 0;
573     ret->pattern.skipBlocks = 0;
574 
575     // clearbytes and encryptedbytes point at the actual data, which follows
576     ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
577     ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes
578 
579     memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
580     memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));
581 
582     return ret;
583 }
584 
585 
586 EXPORT
AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo * info)587 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
588     free(info);
589     return AMEDIA_OK;
590 }
591 
592 EXPORT
AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo * ci)593 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
594     return ci->numsubsamples;
595 }
596 
597 EXPORT
AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo * ci,uint8_t * dst)598 media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
599     if (!ci) {
600         return AMEDIA_ERROR_INVALID_OBJECT;
601     }
602     if (!dst) {
603         return AMEDIA_ERROR_INVALID_PARAMETER;
604     }
605     memcpy(dst, ci->key, 16);
606     return AMEDIA_OK;
607 }
608 
609 EXPORT
AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo * ci,uint8_t * dst)610 media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
611     if (!ci) {
612         return AMEDIA_ERROR_INVALID_OBJECT;
613     }
614     if (!dst) {
615         return AMEDIA_ERROR_INVALID_PARAMETER;
616     }
617     memcpy(dst, ci->iv, 16);
618     return AMEDIA_OK;
619 }
620 
621 EXPORT
AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo * ci)622 cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
623     if (!ci) {
624         return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT;
625     }
626     return ci->mode;
627 }
628 
629 EXPORT
AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo * ci,size_t * dst)630 media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
631     if (!ci) {
632         return AMEDIA_ERROR_INVALID_OBJECT;
633     }
634     if (!dst) {
635         return AMEDIA_ERROR_INVALID_PARAMETER;
636     }
637     memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
638     return AMEDIA_OK;
639 }
640 
641 EXPORT
AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo * ci,size_t * dst)642 media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
643     if (!ci) {
644         return AMEDIA_ERROR_INVALID_OBJECT;
645     }
646     if (!dst) {
647         return AMEDIA_ERROR_INVALID_PARAMETER;
648     }
649     memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
650     return AMEDIA_OK;
651 }
652 
653 } // extern "C"
654 
655