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