blob: 6faa19f1b58580455027c70f54e058592a0a6970 [file] [log] [blame]
Marco Nelissen0c3be872014-05-01 10:14:44 -07001/*
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
Mark Salyzyn98f28cd2014-06-18 16:32:50 -070017#include <inttypes.h>
18
Marco Nelissenc7a11b22014-05-30 10:13:25 -070019//#define LOG_NDEBUG 0
Marco Nelissen0c3be872014-05-01 10:14:44 -070020#define LOG_TAG "NdkMediaCodec"
21
22#include "NdkMediaCodec.h"
Marco Nelissen050eb322014-05-09 15:10:23 -070023#include "NdkMediaError.h"
24#include "NdkMediaCryptoPriv.h"
Marco Nelissen0c3be872014-05-01 10:14:44 -070025#include "NdkMediaFormatPriv.h"
26
27#include <utils/Log.h>
28#include <utils/StrongPointer.h>
29#include <gui/Surface.h>
30
Marco Nelissen0c3be872014-05-01 10:14:44 -070031#include <media/stagefright/foundation/ALooper.h>
32#include <media/stagefright/foundation/AMessage.h>
Marco Nelissen0c3be872014-05-01 10:14:44 -070033
Praveen Chavan85a53632017-01-31 12:21:33 -080034#include <media/stagefright/PersistentSurface.h>
Marco Nelissen0c3be872014-05-01 10:14:44 -070035#include <media/stagefright/MediaCodec.h>
36#include <media/stagefright/MediaErrors.h>
Wonsik Kim7e34bf52016-08-23 00:09:18 +090037#include <media/MediaCodecBuffer.h>
Praveen Chavan19431582017-01-16 11:56:18 -080038#include <android/native_window.h>
Marco Nelissen0c3be872014-05-01 10:14:44 -070039
40using namespace android;
41
42
Marco Nelissene419d7c2014-05-15 14:17:25 -070043static media_status_t translate_error(status_t err) {
Marco Nelissen0c3be872014-05-01 10:14:44 -070044 if (err == OK) {
Marco Nelissene419d7c2014-05-15 14:17:25 -070045 return AMEDIA_OK;
Marco Nelissen0c3be872014-05-01 10:14:44 -070046 } else if (err == -EAGAIN) {
Marco Nelissene419d7c2014-05-15 14:17:25 -070047 return (media_status_t) AMEDIACODEC_INFO_TRY_AGAIN_LATER;
Marco Nelissen0c3be872014-05-01 10:14:44 -070048 }
49 ALOGE("sf error code: %d", err);
Marco Nelissene419d7c2014-05-15 14:17:25 -070050 return AMEDIA_ERROR_UNKNOWN;
Marco Nelissen0c3be872014-05-01 10:14:44 -070051}
52
Marco Nelissencdb42cd2014-05-08 14:46:05 -070053enum {
54 kWhatActivityNotify,
55 kWhatRequestActivityNotifications,
56 kWhatStopActivityNotifications,
Marco Nelissen0c3be872014-05-01 10:14:44 -070057};
58
Praveen Chavan85a53632017-01-31 12:21:33 -080059struct AMediaCodecPersistentSurface : public Surface {
60 sp<PersistentSurface> mPersistentSurface;
61 AMediaCodecPersistentSurface(
62 const sp<IGraphicBufferProducer>& igbp,
63 const sp<PersistentSurface>& ps)
64 : Surface(igbp) {
65 mPersistentSurface = ps;
66 }
67 virtual ~AMediaCodecPersistentSurface() {
68 //mPersistentSurface ref will be let go off here
69 }
70};
Marco Nelissen0c3be872014-05-01 10:14:44 -070071
Marco Nelissencdb42cd2014-05-08 14:46:05 -070072class CodecHandler: public AHandler {
73private:
74 AMediaCodec* mCodec;
75public:
Chih-Hung Hsieh090ef602016-04-27 10:39:54 -070076 explicit CodecHandler(AMediaCodec *codec);
Marco Nelissencdb42cd2014-05-08 14:46:05 -070077 virtual void onMessageReceived(const sp<AMessage> &msg);
78};
Marco Nelissen0c3be872014-05-01 10:14:44 -070079
Marco Nelissene22a64b2014-05-23 15:49:49 -070080typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
81
Marco Nelissen0c3be872014-05-01 10:14:44 -070082struct AMediaCodec {
83 sp<android::MediaCodec> mCodec;
84 sp<ALooper> mLooper;
85 sp<CodecHandler> mHandler;
Marco Nelissencdb42cd2014-05-08 14:46:05 -070086 sp<AMessage> mActivityNotification;
87 int32_t mGeneration;
88 bool mRequestedActivityNotification;
89 OnCodecEvent mCallback;
90 void *mCallbackUserData;
Marco Nelissen0c3be872014-05-01 10:14:44 -070091};
92
Marco Nelissencdb42cd2014-05-08 14:46:05 -070093CodecHandler::CodecHandler(AMediaCodec *codec) {
94 mCodec = codec;
95}
96
97void 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 {
Lajos Molnar3f274362015-03-05 14:35:41 -0800133 sp<AReplyToken> replyID;
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700134 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
152static void requestActivityNotification(AMediaCodec *codec) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800153 (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post();
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700154}
155
Marco Nelissen0c3be872014-05-01 10:14:44 -0700156extern "C" {
157
158static 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");
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800162 size_t res = mData->mLooper->start(
Marco Nelissen0c3be872014-05-01 10:14:44 -0700163 false, // runOnCallingThread
164 true, // canCallJava XXX
165 PRIORITY_FOREGROUND);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800166 if (res != OK) {
167 ALOGE("Failed to start the looper");
Greg Kaiser4e147802016-03-14 14:44:20 -0700168 AMediaCodec_delete(mData);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800169 return NULL;
170 }
Marco Nelissen0c3be872014-05-01 10:14:44 -0700171 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 }
Andy Hung6bb63ad2015-04-28 19:05:08 -0700176 if (mData->mCodec == NULL) { // failed to create codec
177 AMediaCodec_delete(mData);
178 return NULL;
179 }
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700180 mData->mHandler = new CodecHandler(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700181 mData->mLooper->registerHandler(mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700182 mData->mGeneration = 1;
183 mData->mRequestedActivityNotification = false;
184 mData->mCallback = NULL;
185
Marco Nelissen0c3be872014-05-01 10:14:44 -0700186 return mData;
187}
188
Marco Nelissen3425fd52014-05-14 11:12:46 -0700189EXPORT
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700190AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700191 return createAMediaCodec(name, false, false);
192}
193
Marco Nelissen3425fd52014-05-14 11:12:46 -0700194EXPORT
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700195AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700196 return createAMediaCodec(mime_type, true, false);
197}
198
Marco Nelissen3425fd52014-05-14 11:12:46 -0700199EXPORT
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700200AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
201 return createAMediaCodec(name, true, true);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700202}
203
Marco Nelissen3425fd52014-05-14 11:12:46 -0700204EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700205media_status_t AMediaCodec_delete(AMediaCodec *mData) {
Andy Hung6bb63ad2015-04-28 19:05:08 -0700206 if (mData != NULL) {
207 if (mData->mCodec != NULL) {
208 mData->mCodec->release();
209 mData->mCodec.clear();
210 }
Marco Nelissen0c3be872014-05-01 10:14:44 -0700211
Andy Hung6bb63ad2015-04-28 19:05:08 -0700212 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;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700220 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700221 return AMEDIA_OK;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700222}
223
Marco Nelissen3425fd52014-05-14 11:12:46 -0700224EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700225media_status_t AMediaCodec_configure(
Marco Nelissen050eb322014-05-09 15:10:23 -0700226 AMediaCodec *mData,
227 const AMediaFormat* format,
228 ANativeWindow* window,
229 AMediaCrypto *crypto,
230 uint32_t flags) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700231 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
Marco Nelissen050eb322014-05-09 15:10:23 -0700239 return translate_error(mData->mCodec->configure(nativeFormat, surface,
240 crypto ? crypto->mCrypto : NULL, flags));
Marco Nelissen0c3be872014-05-01 10:14:44 -0700241}
242
Marco Nelissen3425fd52014-05-14 11:12:46 -0700243EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700244media_status_t AMediaCodec_start(AMediaCodec *mData) {
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700245 status_t ret = mData->mCodec->start();
246 if (ret != OK) {
247 return translate_error(ret);
248 }
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800249 mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700250 mData->mActivityNotification->setInt32("generation", mData->mGeneration);
251 requestActivityNotification(mData);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700252 return AMEDIA_OK;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700253}
254
Marco Nelissen3425fd52014-05-14 11:12:46 -0700255EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700256media_status_t AMediaCodec_stop(AMediaCodec *mData) {
257 media_status_t ret = translate_error(mData->mCodec->stop());
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700258
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800259 sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700260 sp<AMessage> response;
261 msg->postAndAwaitResponse(&response);
262 mData->mActivityNotification.clear();
263
264 return ret;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700265}
266
Marco Nelissen3425fd52014-05-14 11:12:46 -0700267EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700268media_status_t AMediaCodec_flush(AMediaCodec *mData) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700269 return translate_error(mData->mCodec->flush());
270}
271
Marco Nelissen3425fd52014-05-14 11:12:46 -0700272EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700273ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
274 size_t idx;
275 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700276 requestActivityNotification(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700277 if (ret == OK) {
278 return idx;
279 }
280 return translate_error(ret);
281}
282
Marco Nelissen3425fd52014-05-14 11:12:46 -0700283EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700284uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
Wonsik Kim7e34bf52016-08-23 00:09:18 +0900285 android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700286 if (mData->mCodec->getInputBuffers(&abufs) == 0) {
287 size_t n = abufs.size();
288 if (idx >= n) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700289 ALOGE("buffer index %zu out of range", idx);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700290 return NULL;
291 }
Wonsik Kim7e34bf52016-08-23 00:09:18 +0900292 if (abufs[idx] == NULL) {
293 ALOGE("buffer index %zu is NULL", idx);
294 return NULL;
295 }
Marco Nelissen0c3be872014-05-01 10:14:44 -0700296 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
Marco Nelissen3425fd52014-05-14 11:12:46 -0700305EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700306uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
Wonsik Kim7e34bf52016-08-23 00:09:18 +0900307 android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700308 if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
309 size_t n = abufs.size();
310 if (idx >= n) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700311 ALOGE("buffer index %zu out of range", idx);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700312 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
Marco Nelissen3425fd52014-05-14 11:12:46 -0700323EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700324media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData,
Marco Nelissen0c3be872014-05-01 10:14:44 -0700325 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
Marco Nelissen3425fd52014-05-14 11:12:46 -0700332EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700333ssize_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);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700342 requestActivityNotification(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700343 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
Marco Nelissen3425fd52014-05-14 11:12:46 -0700362EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700363AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
364 sp<AMessage> format;
365 mData->mCodec->getOutputFormat(&format);
366 return AMediaFormat_fromMsg(&format);
367}
368
Marco Nelissen3425fd52014-05-14 11:12:46 -0700369EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700370media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700371 if (render) {
372 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
373 } else {
374 return translate_error(mData->mCodec->releaseOutputBuffer(idx));
375 }
376}
377
Marco Nelissen3425fd52014-05-14 11:12:46 -0700378EXPORT
Marco Nelissen79e2b622014-05-16 08:07:28 -0700379media_status_t AMediaCodec_releaseOutputBufferAtTime(
380 AMediaCodec *mData, size_t idx, int64_t timestampNs) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700381 ALOGV("render @ %" PRId64, timestampNs);
Marco Nelissen79e2b622014-05-16 08:07:28 -0700382 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
383}
384
Vineeta Srivastava8c35da52016-01-08 17:33:09 -0800385EXPORT
386media_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
Praveen Chavan19431582017-01-16 11:56:18 -0800394EXPORT
395media_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
Praveen Chavan85a53632017-01-31 12:21:33 -0800412EXPORT
413media_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
435EXPORT
436media_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
Praveen Chavanf373e842017-02-01 11:50:15 -0800453EXPORT
454media_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
Robert Shihaf42d3f2017-03-20 16:45:37 -0700466EXPORT
467media_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
Marco Nelissene22a64b2014-05-23 15:49:49 -0700482//EXPORT
Glenn Kastenb187de12014-12-30 08:18:15 -0800483media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
484 void *userdata) {
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700485 mData->mCallback = callback;
486 mData->mCallbackUserData = userdata;
Marco Nelissene419d7c2014-05-15 14:17:25 -0700487 return AMEDIA_OK;
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700488}
489
Marco Nelissen050eb322014-05-09 15:10:23 -0700490typedef struct AMediaCodecCryptoInfo {
491 int numsubsamples;
492 uint8_t key[16];
493 uint8_t iv[16];
Marco Nelissen79e2b622014-05-16 08:07:28 -0700494 cryptoinfo_mode_t mode;
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800495 cryptoinfo_pattern_t pattern;
Marco Nelissen050eb322014-05-09 15:10:23 -0700496 size_t *clearbytes;
497 size_t *encryptedbytes;
498} AMediaCodecCryptoInfo;
499
Marco Nelissen3425fd52014-05-14 11:12:46 -0700500EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700501media_status_t AMediaCodec_queueSecureInputBuffer(
Marco Nelissen050eb322014-05-09 15:10:23 -0700502 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
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800515 CryptoPlugin::Pattern pattern;
516 pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
517 pattern.mSkipBlocks = crypto->pattern.skipBlocks;
518
Marco Nelissen050eb322014-05-09 15:10:23 -0700519 AString errormsg;
520 status_t err = codec->mCodec->queueSecureInputBuffer(idx,
521 offset,
522 subSamples,
523 crypto->numsubsamples,
524 crypto->key,
525 crypto->iv,
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800526 (CryptoPlugin::Mode)crypto->mode,
527 pattern,
Marco Nelissen050eb322014-05-09 15:10:23 -0700528 time,
529 flags,
530 &errormsg);
531 if (err != 0) {
532 ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
533 }
Marco Nelissen829e0972014-05-13 16:22:19 -0700534 delete [] subSamples;
Marco Nelissen050eb322014-05-09 15:10:23 -0700535 return translate_error(err);
536}
537
538
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800539EXPORT
540void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
541 cryptoinfo_pattern_t *pattern) {
542 info->pattern.encryptBlocks = pattern->encryptBlocks;
543 info->pattern.skipBlocks = pattern->skipBlocks;
544}
Marco Nelissen050eb322014-05-09 15:10:23 -0700545
Marco Nelissen3425fd52014-05-14 11:12:46 -0700546EXPORT
Marco Nelissen050eb322014-05-09 15:10:23 -0700547AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
548 int numsubsamples,
549 uint8_t key[16],
550 uint8_t iv[16],
Marco Nelissen79e2b622014-05-16 08:07:28 -0700551 cryptoinfo_mode_t mode,
Marco Nelissen050eb322014-05-09 15:10:23 -0700552 size_t *clearbytes,
553 size_t *encryptedbytes) {
554
555 // size needed to store all the crypto data
Marco Nelissend1fd0272018-07-31 15:12:51 -0700556 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 }
Marco Nelissen050eb322014-05-09 15:10:23 -0700563 AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
564 if (!ret) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700565 ALOGE("couldn't allocate %zu bytes", cryptosize);
Marco Nelissen050eb322014-05-09 15:10:23 -0700566 return NULL;
567 }
568 ret->numsubsamples = numsubsamples;
569 memcpy(ret->key, key, 16);
570 memcpy(ret->iv, iv, 16);
571 ret->mode = mode;
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800572 ret->pattern.encryptBlocks = 0;
573 ret->pattern.skipBlocks = 0;
Marco Nelissen050eb322014-05-09 15:10:23 -0700574
575 // clearbytes and encryptedbytes point at the actual data, which follows
Marco Nelissen829e0972014-05-13 16:22:19 -0700576 ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
577 ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes
Marco Nelissen050eb322014-05-09 15:10:23 -0700578
Marco Nelissen829e0972014-05-13 16:22:19 -0700579 memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
580 memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));
Marco Nelissen050eb322014-05-09 15:10:23 -0700581
582 return ret;
583}
584
585
Marco Nelissen3425fd52014-05-14 11:12:46 -0700586EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700587media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
Marco Nelissen050eb322014-05-09 15:10:23 -0700588 free(info);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700589 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700590}
591
Marco Nelissen3425fd52014-05-14 11:12:46 -0700592EXPORT
Marco Nelissen050eb322014-05-09 15:10:23 -0700593size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
594 return ci->numsubsamples;
595}
596
Marco Nelissen3425fd52014-05-14 11:12:46 -0700597EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700598media_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;
Marco Nelissen050eb322014-05-09 15:10:23 -0700604 }
605 memcpy(dst, ci->key, 16);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700606 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700607}
608
Marco Nelissen3425fd52014-05-14 11:12:46 -0700609EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700610media_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;
Marco Nelissen050eb322014-05-09 15:10:23 -0700616 }
617 memcpy(dst, ci->iv, 16);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700618 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700619}
620
Marco Nelissen3425fd52014-05-14 11:12:46 -0700621EXPORT
Marco Nelissen79e2b622014-05-16 08:07:28 -0700622cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
Marco Nelissen050eb322014-05-09 15:10:23 -0700623 if (!ci) {
Marco Nelissen79e2b622014-05-16 08:07:28 -0700624 return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT;
Marco Nelissen050eb322014-05-09 15:10:23 -0700625 }
626 return ci->mode;
627}
628
Marco Nelissen3425fd52014-05-14 11:12:46 -0700629EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700630media_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;
Marco Nelissen050eb322014-05-09 15:10:23 -0700636 }
637 memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700638 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700639}
640
Marco Nelissen3425fd52014-05-14 11:12:46 -0700641EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700642media_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;
Marco Nelissen050eb322014-05-09 15:10:23 -0700648 }
649 memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700650 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700651}
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700652
Marco Nelissen0c3be872014-05-01 10:14:44 -0700653} // extern "C"
654