blob: d771095b3d2b64d9ce522479e2d356972ff4c2e6 [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
Colin Cross7e8d4ba2017-05-04 16:17:42 -070022#include <media/NdkMediaCodec.h>
23#include <media/NdkMediaError.h>
Marco Nelissen98603d82018-07-17 11:06:55 -070024#include <media/NdkMediaFormatPriv.h>
Marco Nelissen050eb322014-05-09 15:10:23 -070025#include "NdkMediaCryptoPriv.h"
Marco Nelissen0c3be872014-05-01 10:14:44 -070026
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;
Chong Zhangeb9aca62020-09-16 12:49:41 -070048 } else if (err == NO_MEMORY) {
49 return AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
50 } else if (err == DEAD_OBJECT) {
51 return AMEDIACODEC_ERROR_RECLAIMED;
Marco Nelissen0c3be872014-05-01 10:14:44 -070052 }
53 ALOGE("sf error code: %d", err);
Marco Nelissene419d7c2014-05-15 14:17:25 -070054 return AMEDIA_ERROR_UNKNOWN;
Marco Nelissen0c3be872014-05-01 10:14:44 -070055}
56
Marco Nelissencdb42cd2014-05-08 14:46:05 -070057enum {
58 kWhatActivityNotify,
Wei Jia00cc9922017-11-23 08:00:34 -080059 kWhatAsyncNotify,
Marco Nelissencdb42cd2014-05-08 14:46:05 -070060 kWhatRequestActivityNotifications,
61 kWhatStopActivityNotifications,
Marco Nelissen0c3be872014-05-01 10:14:44 -070062};
63
Praveen Chavan85a53632017-01-31 12:21:33 -080064struct AMediaCodecPersistentSurface : public Surface {
65 sp<PersistentSurface> mPersistentSurface;
66 AMediaCodecPersistentSurface(
67 const sp<IGraphicBufferProducer>& igbp,
68 const sp<PersistentSurface>& ps)
69 : Surface(igbp) {
70 mPersistentSurface = ps;
71 }
72 virtual ~AMediaCodecPersistentSurface() {
73 //mPersistentSurface ref will be let go off here
74 }
75};
Marco Nelissen0c3be872014-05-01 10:14:44 -070076
Marco Nelissencdb42cd2014-05-08 14:46:05 -070077class CodecHandler: public AHandler {
78private:
79 AMediaCodec* mCodec;
80public:
Chih-Hung Hsieh090ef602016-04-27 10:39:54 -070081 explicit CodecHandler(AMediaCodec *codec);
Marco Nelissencdb42cd2014-05-08 14:46:05 -070082 virtual void onMessageReceived(const sp<AMessage> &msg);
83};
Marco Nelissen0c3be872014-05-01 10:14:44 -070084
Marco Nelissene22a64b2014-05-23 15:49:49 -070085typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
86
Marco Nelissen0c3be872014-05-01 10:14:44 -070087struct AMediaCodec {
88 sp<android::MediaCodec> mCodec;
89 sp<ALooper> mLooper;
90 sp<CodecHandler> mHandler;
Marco Nelissencdb42cd2014-05-08 14:46:05 -070091 sp<AMessage> mActivityNotification;
92 int32_t mGeneration;
93 bool mRequestedActivityNotification;
94 OnCodecEvent mCallback;
95 void *mCallbackUserData;
Wei Jia00cc9922017-11-23 08:00:34 -080096
97 sp<AMessage> mAsyncNotify;
98 mutable Mutex mAsyncCallbackLock;
99 AMediaCodecOnAsyncNotifyCallback mAsyncCallback;
100 void *mAsyncCallbackUserData;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700101};
102
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700103CodecHandler::CodecHandler(AMediaCodec *codec) {
104 mCodec = codec;
105}
106
107void CodecHandler::onMessageReceived(const sp<AMessage> &msg) {
108
109 switch (msg->what()) {
110 case kWhatRequestActivityNotifications:
111 {
112 if (mCodec->mRequestedActivityNotification) {
113 break;
114 }
115
116 mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification);
117 mCodec->mRequestedActivityNotification = true;
118 break;
119 }
120
121 case kWhatActivityNotify:
122 {
123 {
124 int32_t generation;
125 msg->findInt32("generation", &generation);
126
127 if (generation != mCodec->mGeneration) {
128 // stale
129 break;
130 }
131
132 mCodec->mRequestedActivityNotification = false;
133 }
134
135 if (mCodec->mCallback) {
136 mCodec->mCallback(mCodec, mCodec->mCallbackUserData);
137 }
138 break;
139 }
140
Wei Jia00cc9922017-11-23 08:00:34 -0800141 case kWhatAsyncNotify:
142 {
143 int32_t cbID;
144 if (!msg->findInt32("callbackID", &cbID)) {
145 ALOGE("kWhatAsyncNotify: callbackID is expected.");
146 break;
147 }
148
149 ALOGV("kWhatAsyncNotify: cbID = %d", cbID);
150
151 switch (cbID) {
152 case MediaCodec::CB_INPUT_AVAILABLE:
153 {
154 int32_t index;
155 if (!msg->findInt32("index", &index)) {
156 ALOGE("CB_INPUT_AVAILABLE: index is expected.");
157 break;
158 }
159
160 Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
161 if (mCodec->mAsyncCallbackUserData != NULL
162 || mCodec->mAsyncCallback.onAsyncInputAvailable != NULL) {
163 mCodec->mAsyncCallback.onAsyncInputAvailable(
164 mCodec,
165 mCodec->mAsyncCallbackUserData,
166 index);
167 }
168
169 break;
170 }
171
172 case MediaCodec::CB_OUTPUT_AVAILABLE:
173 {
174 int32_t index;
175 size_t offset;
176 size_t size;
177 int64_t timeUs;
178 int32_t flags;
179
180 if (!msg->findInt32("index", &index)) {
181 ALOGE("CB_OUTPUT_AVAILABLE: index is expected.");
182 break;
183 }
184 if (!msg->findSize("offset", &offset)) {
185 ALOGE("CB_OUTPUT_AVAILABLE: offset is expected.");
186 break;
187 }
188 if (!msg->findSize("size", &size)) {
189 ALOGE("CB_OUTPUT_AVAILABLE: size is expected.");
190 break;
191 }
192 if (!msg->findInt64("timeUs", &timeUs)) {
193 ALOGE("CB_OUTPUT_AVAILABLE: timeUs is expected.");
194 break;
195 }
196 if (!msg->findInt32("flags", &flags)) {
197 ALOGE("CB_OUTPUT_AVAILABLE: flags is expected.");
198 break;
199 }
200
201 AMediaCodecBufferInfo bufferInfo = {
202 (int32_t)offset,
203 (int32_t)size,
204 timeUs,
205 (uint32_t)flags};
206
207 Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
208 if (mCodec->mAsyncCallbackUserData != NULL
209 || mCodec->mAsyncCallback.onAsyncOutputAvailable != NULL) {
210 mCodec->mAsyncCallback.onAsyncOutputAvailable(
211 mCodec,
212 mCodec->mAsyncCallbackUserData,
213 index,
214 &bufferInfo);
215 }
216
217 break;
218 }
219
220 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
221 {
222 sp<AMessage> format;
223 if (!msg->findMessage("format", &format)) {
224 ALOGE("CB_OUTPUT_FORMAT_CHANGED: format is expected.");
225 break;
226 }
227
Chong Zhang1fa26862019-09-16 16:15:00 -0700228 // Here format is MediaCodec's internal copy of output format.
229 // Make a copy since the client might modify it.
230 sp<AMessage> copy;
231 if (format != nullptr) {
232 copy = format->dup();
233 }
234 AMediaFormat *aMediaFormat = AMediaFormat_fromMsg(&copy);
Wei Jia00cc9922017-11-23 08:00:34 -0800235
236 Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
237 if (mCodec->mAsyncCallbackUserData != NULL
238 || mCodec->mAsyncCallback.onAsyncFormatChanged != NULL) {
239 mCodec->mAsyncCallback.onAsyncFormatChanged(
240 mCodec,
241 mCodec->mAsyncCallbackUserData,
242 aMediaFormat);
243 }
244
245 break;
246 }
247
248 case MediaCodec::CB_ERROR:
249 {
250 status_t err;
251 int32_t actionCode;
252 AString detail;
253 if (!msg->findInt32("err", &err)) {
254 ALOGE("CB_ERROR: err is expected.");
255 break;
256 }
Rakesh Kumard5ea3f32019-09-20 17:08:07 +0530257 if (!msg->findInt32("actionCode", &actionCode)) {
258 ALOGE("CB_ERROR: actionCode is expected.");
Wei Jia00cc9922017-11-23 08:00:34 -0800259 break;
260 }
261 msg->findString("detail", &detail);
Chong Zhangeb9aca62020-09-16 12:49:41 -0700262 ALOGE("Codec reported error(0x%x), actionCode(%d), detail(%s)",
Wei Jia00cc9922017-11-23 08:00:34 -0800263 err, actionCode, detail.c_str());
264
265 Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
266 if (mCodec->mAsyncCallbackUserData != NULL
267 || mCodec->mAsyncCallback.onAsyncError != NULL) {
268 mCodec->mAsyncCallback.onAsyncError(
269 mCodec,
270 mCodec->mAsyncCallbackUserData,
271 translate_error(err),
272 actionCode,
273 detail.c_str());
274 }
275
276 break;
277 }
278
279 default:
280 {
281 ALOGE("kWhatAsyncNotify: callbackID(%d) is unexpected.", cbID);
282 break;
283 }
284 }
285 break;
286 }
287
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700288 case kWhatStopActivityNotifications:
289 {
Lajos Molnar3f274362015-03-05 14:35:41 -0800290 sp<AReplyToken> replyID;
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700291 msg->senderAwaitsResponse(&replyID);
292
293 mCodec->mGeneration++;
294 mCodec->mRequestedActivityNotification = false;
295
296 sp<AMessage> response = new AMessage;
297 response->postReply(replyID);
298 break;
299 }
300
301 default:
302 ALOGE("shouldn't be here");
303 break;
304 }
305
306}
307
308
309static void requestActivityNotification(AMediaCodec *codec) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800310 (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post();
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700311}
312
Marco Nelissen0c3be872014-05-01 10:14:44 -0700313extern "C" {
314
315static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool encoder) {
316 AMediaCodec *mData = new AMediaCodec();
317 mData->mLooper = new ALooper;
318 mData->mLooper->setName("NDK MediaCodec_looper");
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800319 size_t res = mData->mLooper->start(
Marco Nelissen0c3be872014-05-01 10:14:44 -0700320 false, // runOnCallingThread
321 true, // canCallJava XXX
Wei Jia00cc9922017-11-23 08:00:34 -0800322 PRIORITY_AUDIO);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800323 if (res != OK) {
324 ALOGE("Failed to start the looper");
Greg Kaiser4e147802016-03-14 14:44:20 -0700325 AMediaCodec_delete(mData);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800326 return NULL;
327 }
Marco Nelissen0c3be872014-05-01 10:14:44 -0700328 if (name_is_type) {
329 mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder);
330 } else {
331 mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name);
332 }
Andy Hung6bb63ad2015-04-28 19:05:08 -0700333 if (mData->mCodec == NULL) { // failed to create codec
334 AMediaCodec_delete(mData);
335 return NULL;
336 }
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700337 mData->mHandler = new CodecHandler(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700338 mData->mLooper->registerHandler(mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700339 mData->mGeneration = 1;
340 mData->mRequestedActivityNotification = false;
341 mData->mCallback = NULL;
342
Wei Jia00cc9922017-11-23 08:00:34 -0800343 mData->mAsyncCallback = {};
344 mData->mAsyncCallbackUserData = NULL;
345
Marco Nelissen0c3be872014-05-01 10:14:44 -0700346 return mData;
347}
348
Marco Nelissen3425fd52014-05-14 11:12:46 -0700349EXPORT
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700350AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700351 return createAMediaCodec(name, false, false);
352}
353
Marco Nelissen3425fd52014-05-14 11:12:46 -0700354EXPORT
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700355AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700356 return createAMediaCodec(mime_type, true, false);
357}
358
Marco Nelissen3425fd52014-05-14 11:12:46 -0700359EXPORT
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700360AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
361 return createAMediaCodec(name, true, true);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700362}
363
Marco Nelissen3425fd52014-05-14 11:12:46 -0700364EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700365media_status_t AMediaCodec_delete(AMediaCodec *mData) {
Andy Hung6bb63ad2015-04-28 19:05:08 -0700366 if (mData != NULL) {
367 if (mData->mCodec != NULL) {
368 mData->mCodec->release();
369 mData->mCodec.clear();
370 }
Marco Nelissen0c3be872014-05-01 10:14:44 -0700371
Andy Hung6bb63ad2015-04-28 19:05:08 -0700372 if (mData->mLooper != NULL) {
373 if (mData->mHandler != NULL) {
374 mData->mLooper->unregisterHandler(mData->mHandler->id());
375 }
376 mData->mLooper->stop();
377 mData->mLooper.clear();
378 }
379 delete mData;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700380 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700381 return AMEDIA_OK;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700382}
383
Marco Nelissen3425fd52014-05-14 11:12:46 -0700384EXPORT
Wei Jia00cc9922017-11-23 08:00:34 -0800385media_status_t AMediaCodec_getName(
386 AMediaCodec *mData,
387 char** out_name) {
388 if (out_name == NULL) {
389 return AMEDIA_ERROR_INVALID_PARAMETER;
390 }
391
392 AString compName;
393 status_t err = mData->mCodec->getName(&compName);
394 if (err != OK) {
395 return translate_error(err);
396 }
397 *out_name = strdup(compName.c_str());
398 return AMEDIA_OK;
399}
400
401EXPORT
402void AMediaCodec_releaseName(
403 AMediaCodec * /* mData */,
404 char* name) {
405 if (name != NULL) {
406 free(name);
407 }
408}
409
410EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700411media_status_t AMediaCodec_configure(
Marco Nelissen050eb322014-05-09 15:10:23 -0700412 AMediaCodec *mData,
413 const AMediaFormat* format,
414 ANativeWindow* window,
415 AMediaCrypto *crypto,
416 uint32_t flags) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700417 sp<AMessage> nativeFormat;
418 AMediaFormat_getFormat(format, &nativeFormat);
419 ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str());
420 sp<Surface> surface = NULL;
421 if (window != NULL) {
422 surface = (Surface*) window;
423 }
424
Wei Jia00cc9922017-11-23 08:00:34 -0800425 status_t err = mData->mCodec->configure(nativeFormat, surface,
426 crypto ? crypto->mCrypto : NULL, flags);
427 if (err != OK) {
428 ALOGE("configure: err(%d), failed with format: %s",
429 err, nativeFormat->debugString(0).c_str());
430 }
431 return translate_error(err);
432}
433
434EXPORT
435media_status_t AMediaCodec_setAsyncNotifyCallback(
436 AMediaCodec *mData,
437 AMediaCodecOnAsyncNotifyCallback callback,
438 void *userdata) {
439 if (mData->mAsyncNotify == NULL && userdata != NULL) {
440 mData->mAsyncNotify = new AMessage(kWhatAsyncNotify, mData->mHandler);
441 status_t err = mData->mCodec->setCallback(mData->mAsyncNotify);
442 if (err != OK) {
443 ALOGE("setAsyncNotifyCallback: err(%d), failed to set async callback", err);
444 return translate_error(err);
445 }
446 }
447
448 Mutex::Autolock _l(mData->mAsyncCallbackLock);
449 mData->mAsyncCallback = callback;
450 mData->mAsyncCallbackUserData = userdata;
451
452 return AMEDIA_OK;
453}
454
455
456EXPORT
457media_status_t AMediaCodec_releaseCrypto(AMediaCodec *mData) {
458 return translate_error(mData->mCodec->releaseCrypto());
Marco Nelissen0c3be872014-05-01 10:14:44 -0700459}
460
Marco Nelissen3425fd52014-05-14 11:12:46 -0700461EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700462media_status_t AMediaCodec_start(AMediaCodec *mData) {
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700463 status_t ret = mData->mCodec->start();
464 if (ret != OK) {
465 return translate_error(ret);
466 }
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800467 mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700468 mData->mActivityNotification->setInt32("generation", mData->mGeneration);
469 requestActivityNotification(mData);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700470 return AMEDIA_OK;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700471}
472
Marco Nelissen3425fd52014-05-14 11:12:46 -0700473EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700474media_status_t AMediaCodec_stop(AMediaCodec *mData) {
475 media_status_t ret = translate_error(mData->mCodec->stop());
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700476
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800477 sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700478 sp<AMessage> response;
479 msg->postAndAwaitResponse(&response);
480 mData->mActivityNotification.clear();
481
482 return ret;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700483}
484
Marco Nelissen3425fd52014-05-14 11:12:46 -0700485EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700486media_status_t AMediaCodec_flush(AMediaCodec *mData) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700487 return translate_error(mData->mCodec->flush());
488}
489
Marco Nelissen3425fd52014-05-14 11:12:46 -0700490EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700491ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
492 size_t idx;
493 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700494 requestActivityNotification(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700495 if (ret == OK) {
496 return idx;
497 }
498 return translate_error(ret);
499}
500
Marco Nelissen3425fd52014-05-14 11:12:46 -0700501EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700502uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
Wei Jia00cc9922017-11-23 08:00:34 -0800503 if (mData->mAsyncNotify != NULL) {
504 // Asynchronous mode
505 sp<MediaCodecBuffer> abuf;
506 if (mData->mCodec->getInputBuffer(idx, &abuf) != 0) {
507 return NULL;
508 }
509
510 if (out_size != NULL) {
511 *out_size = abuf->capacity();
512 }
513 return abuf->data();
514 }
515
Wonsik Kim7e34bf52016-08-23 00:09:18 +0900516 android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700517 if (mData->mCodec->getInputBuffers(&abufs) == 0) {
518 size_t n = abufs.size();
519 if (idx >= n) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700520 ALOGE("buffer index %zu out of range", idx);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700521 return NULL;
522 }
Wonsik Kim7e34bf52016-08-23 00:09:18 +0900523 if (abufs[idx] == NULL) {
524 ALOGE("buffer index %zu is NULL", idx);
525 return NULL;
526 }
Marco Nelissen0c3be872014-05-01 10:14:44 -0700527 if (out_size != NULL) {
528 *out_size = abufs[idx]->capacity();
529 }
530 return abufs[idx]->data();
531 }
532 ALOGE("couldn't get input buffers");
533 return NULL;
534}
535
Marco Nelissen3425fd52014-05-14 11:12:46 -0700536EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700537uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
Wei Jia00cc9922017-11-23 08:00:34 -0800538 if (mData->mAsyncNotify != NULL) {
539 // Asynchronous mode
540 sp<MediaCodecBuffer> abuf;
541 if (mData->mCodec->getOutputBuffer(idx, &abuf) != 0) {
542 return NULL;
543 }
544
545 if (out_size != NULL) {
546 *out_size = abuf->capacity();
547 }
548 return abuf->data();
549 }
550
Wonsik Kim7e34bf52016-08-23 00:09:18 +0900551 android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700552 if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
553 size_t n = abufs.size();
554 if (idx >= n) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700555 ALOGE("buffer index %zu out of range", idx);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700556 return NULL;
557 }
558 if (out_size != NULL) {
559 *out_size = abufs[idx]->capacity();
560 }
561 return abufs[idx]->data();
562 }
563 ALOGE("couldn't get output buffers");
564 return NULL;
565}
566
Marco Nelissen3425fd52014-05-14 11:12:46 -0700567EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700568media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData,
Marco Nelissen0c3be872014-05-01 10:14:44 -0700569 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) {
570
571 AString errorMsg;
572 status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg);
573 return translate_error(ret);
574}
575
Marco Nelissen3425fd52014-05-14 11:12:46 -0700576EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700577ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
578 AMediaCodecBufferInfo *info, int64_t timeoutUs) {
579 size_t idx;
580 size_t offset;
581 size_t size;
582 uint32_t flags;
583 int64_t presentationTimeUs;
584 status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs,
585 &flags, timeoutUs);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700586 requestActivityNotification(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700587 switch (ret) {
588 case OK:
589 info->offset = offset;
590 info->size = size;
591 info->flags = flags;
592 info->presentationTimeUs = presentationTimeUs;
593 return idx;
594 case -EAGAIN:
595 return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
596 case android::INFO_FORMAT_CHANGED:
597 return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED;
598 case INFO_OUTPUT_BUFFERS_CHANGED:
599 return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED;
600 default:
601 break;
602 }
603 return translate_error(ret);
604}
605
Marco Nelissen3425fd52014-05-14 11:12:46 -0700606EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700607AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
608 sp<AMessage> format;
609 mData->mCodec->getOutputFormat(&format);
610 return AMediaFormat_fromMsg(&format);
611}
612
Marco Nelissen3425fd52014-05-14 11:12:46 -0700613EXPORT
Wei Jia00cc9922017-11-23 08:00:34 -0800614AMediaFormat* AMediaCodec_getInputFormat(AMediaCodec *mData) {
615 sp<AMessage> format;
616 mData->mCodec->getInputFormat(&format);
617 return AMediaFormat_fromMsg(&format);
618}
619
620EXPORT
Manikanta Kanamarlapudi2c32f4d2017-07-07 16:24:31 +0530621AMediaFormat* AMediaCodec_getBufferFormat(AMediaCodec *mData, size_t index) {
622 sp<AMessage> format;
623 mData->mCodec->getOutputFormat(index, &format);
624 return AMediaFormat_fromMsg(&format);
625}
626
627EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700628media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700629 if (render) {
630 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
631 } else {
632 return translate_error(mData->mCodec->releaseOutputBuffer(idx));
633 }
634}
635
Marco Nelissen3425fd52014-05-14 11:12:46 -0700636EXPORT
Marco Nelissen79e2b622014-05-16 08:07:28 -0700637media_status_t AMediaCodec_releaseOutputBufferAtTime(
638 AMediaCodec *mData, size_t idx, int64_t timestampNs) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700639 ALOGV("render @ %" PRId64, timestampNs);
Marco Nelissen79e2b622014-05-16 08:07:28 -0700640 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
641}
642
Vineeta Srivastava8c35da52016-01-08 17:33:09 -0800643EXPORT
644media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) {
645 sp<Surface> surface = NULL;
646 if (window != NULL) {
647 surface = (Surface*) window;
648 }
649 return translate_error(mData->mCodec->setSurface(surface));
650}
651
Praveen Chavan19431582017-01-16 11:56:18 -0800652EXPORT
653media_status_t AMediaCodec_createInputSurface(AMediaCodec *mData, ANativeWindow **surface) {
654 if (surface == NULL || mData == NULL) {
655 return AMEDIA_ERROR_INVALID_PARAMETER;
656 }
657 *surface = NULL;
658
659 sp<IGraphicBufferProducer> igbp = NULL;
660 status_t err = mData->mCodec->createInputSurface(&igbp);
661 if (err != NO_ERROR) {
662 return translate_error(err);
663 }
664
665 *surface = new Surface(igbp);
666 ANativeWindow_acquire(*surface);
667 return AMEDIA_OK;
668}
669
Praveen Chavan85a53632017-01-31 12:21:33 -0800670EXPORT
671media_status_t AMediaCodec_createPersistentInputSurface(ANativeWindow **surface) {
672 if (surface == NULL) {
673 return AMEDIA_ERROR_INVALID_PARAMETER;
674 }
675 *surface = NULL;
676
677 sp<PersistentSurface> ps = MediaCodec::CreatePersistentInputSurface();
678 if (ps == NULL) {
679 return AMEDIA_ERROR_UNKNOWN;
680 }
681
682 sp<IGraphicBufferProducer> igbp = ps->getBufferProducer();
683 if (igbp == NULL) {
684 return AMEDIA_ERROR_UNKNOWN;
685 }
686
687 *surface = new AMediaCodecPersistentSurface(igbp, ps);
688 ANativeWindow_acquire(*surface);
689
690 return AMEDIA_OK;
691}
692
693EXPORT
694media_status_t AMediaCodec_setInputSurface(
695 AMediaCodec *mData, ANativeWindow *surface) {
696
697 if (surface == NULL || mData == NULL) {
698 return AMEDIA_ERROR_INVALID_PARAMETER;
699 }
700
701 AMediaCodecPersistentSurface *aMediaPersistentSurface =
702 static_cast<AMediaCodecPersistentSurface *>(surface);
703 if (aMediaPersistentSurface->mPersistentSurface == NULL) {
704 return AMEDIA_ERROR_INVALID_PARAMETER;
705 }
706
707 return translate_error(mData->mCodec->setInputSurface(
708 aMediaPersistentSurface->mPersistentSurface));
709}
710
Praveen Chavanf373e842017-02-01 11:50:15 -0800711EXPORT
712media_status_t AMediaCodec_setParameters(
713 AMediaCodec *mData, const AMediaFormat* params) {
714 if (params == NULL || mData == NULL) {
715 return AMEDIA_ERROR_INVALID_PARAMETER;
716 }
717 sp<AMessage> nativeParams;
718 AMediaFormat_getFormat(params, &nativeParams);
719 ALOGV("setParameters: %s", nativeParams->debugString(0).c_str());
720
721 return translate_error(mData->mCodec->setParameters(nativeParams));
722}
723
Robert Shihaf42d3f2017-03-20 16:45:37 -0700724EXPORT
725media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData) {
726
727 if (mData == NULL) {
728 return AMEDIA_ERROR_INVALID_PARAMETER;
729 }
730
731 status_t err = mData->mCodec->signalEndOfInputStream();
732 if (err == INVALID_OPERATION) {
733 return AMEDIA_ERROR_INVALID_OPERATION;
734 }
735
736 return translate_error(err);
737
738}
739
Marco Nelissene22a64b2014-05-23 15:49:49 -0700740//EXPORT
Glenn Kastenb187de12014-12-30 08:18:15 -0800741media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
742 void *userdata) {
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700743 mData->mCallback = callback;
744 mData->mCallbackUserData = userdata;
Marco Nelissene419d7c2014-05-15 14:17:25 -0700745 return AMEDIA_OK;
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700746}
747
Marco Nelissen050eb322014-05-09 15:10:23 -0700748typedef struct AMediaCodecCryptoInfo {
749 int numsubsamples;
750 uint8_t key[16];
751 uint8_t iv[16];
Marco Nelissen79e2b622014-05-16 08:07:28 -0700752 cryptoinfo_mode_t mode;
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800753 cryptoinfo_pattern_t pattern;
Marco Nelissen050eb322014-05-09 15:10:23 -0700754 size_t *clearbytes;
755 size_t *encryptedbytes;
756} AMediaCodecCryptoInfo;
757
Marco Nelissen3425fd52014-05-14 11:12:46 -0700758EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700759media_status_t AMediaCodec_queueSecureInputBuffer(
Marco Nelissen050eb322014-05-09 15:10:23 -0700760 AMediaCodec* codec,
761 size_t idx,
762 off_t offset,
763 AMediaCodecCryptoInfo* crypto,
764 uint64_t time,
765 uint32_t flags) {
766
767 CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples];
768 for (int i = 0; i < crypto->numsubsamples; i++) {
769 subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i];
770 subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
771 }
772
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800773 CryptoPlugin::Pattern pattern;
774 pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
775 pattern.mSkipBlocks = crypto->pattern.skipBlocks;
776
Marco Nelissen050eb322014-05-09 15:10:23 -0700777 AString errormsg;
778 status_t err = codec->mCodec->queueSecureInputBuffer(idx,
779 offset,
780 subSamples,
781 crypto->numsubsamples,
782 crypto->key,
783 crypto->iv,
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800784 (CryptoPlugin::Mode)crypto->mode,
785 pattern,
Marco Nelissen050eb322014-05-09 15:10:23 -0700786 time,
787 flags,
788 &errormsg);
789 if (err != 0) {
790 ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
791 }
Marco Nelissen829e0972014-05-13 16:22:19 -0700792 delete [] subSamples;
Marco Nelissen050eb322014-05-09 15:10:23 -0700793 return translate_error(err);
794}
795
Wei Jia00cc9922017-11-23 08:00:34 -0800796EXPORT
797bool AMediaCodecActionCode_isRecoverable(int32_t actionCode) {
798 return (actionCode == ACTION_CODE_RECOVERABLE);
799}
800
801EXPORT
802bool AMediaCodecActionCode_isTransient(int32_t actionCode) {
803 return (actionCode == ACTION_CODE_TRANSIENT);
804}
805
Marco Nelissen050eb322014-05-09 15:10:23 -0700806
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800807EXPORT
808void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
809 cryptoinfo_pattern_t *pattern) {
810 info->pattern.encryptBlocks = pattern->encryptBlocks;
811 info->pattern.skipBlocks = pattern->skipBlocks;
812}
Marco Nelissen050eb322014-05-09 15:10:23 -0700813
Marco Nelissen3425fd52014-05-14 11:12:46 -0700814EXPORT
Marco Nelissen050eb322014-05-09 15:10:23 -0700815AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
816 int numsubsamples,
817 uint8_t key[16],
818 uint8_t iv[16],
Marco Nelissen79e2b622014-05-16 08:07:28 -0700819 cryptoinfo_mode_t mode,
Marco Nelissen050eb322014-05-09 15:10:23 -0700820 size_t *clearbytes,
821 size_t *encryptedbytes) {
822
823 // size needed to store all the crypto data
Marco Nelissend1fd0272018-07-31 15:12:51 -0700824 size_t cryptosize;
825 // = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
826 if (__builtin_mul_overflow(sizeof(size_t) * 2, numsubsamples, &cryptosize) ||
827 __builtin_add_overflow(cryptosize, sizeof(AMediaCodecCryptoInfo), &cryptosize)) {
828 ALOGE("crypto size overflow");
829 return NULL;
830 }
Marco Nelissen050eb322014-05-09 15:10:23 -0700831 AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
832 if (!ret) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700833 ALOGE("couldn't allocate %zu bytes", cryptosize);
Marco Nelissen050eb322014-05-09 15:10:23 -0700834 return NULL;
835 }
836 ret->numsubsamples = numsubsamples;
837 memcpy(ret->key, key, 16);
838 memcpy(ret->iv, iv, 16);
839 ret->mode = mode;
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800840 ret->pattern.encryptBlocks = 0;
841 ret->pattern.skipBlocks = 0;
Marco Nelissen050eb322014-05-09 15:10:23 -0700842
843 // clearbytes and encryptedbytes point at the actual data, which follows
Marco Nelissen829e0972014-05-13 16:22:19 -0700844 ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
845 ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes
Marco Nelissen050eb322014-05-09 15:10:23 -0700846
Marco Nelissen829e0972014-05-13 16:22:19 -0700847 memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
848 memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));
Marco Nelissen050eb322014-05-09 15:10:23 -0700849
850 return ret;
851}
852
853
Marco Nelissen3425fd52014-05-14 11:12:46 -0700854EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700855media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
Marco Nelissen050eb322014-05-09 15:10:23 -0700856 free(info);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700857 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700858}
859
Marco Nelissen3425fd52014-05-14 11:12:46 -0700860EXPORT
Marco Nelissen050eb322014-05-09 15:10:23 -0700861size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
862 return ci->numsubsamples;
863}
864
Marco Nelissen3425fd52014-05-14 11:12:46 -0700865EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700866media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
867 if (!ci) {
868 return AMEDIA_ERROR_INVALID_OBJECT;
869 }
870 if (!dst) {
871 return AMEDIA_ERROR_INVALID_PARAMETER;
Marco Nelissen050eb322014-05-09 15:10:23 -0700872 }
873 memcpy(dst, ci->key, 16);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700874 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700875}
876
Marco Nelissen3425fd52014-05-14 11:12:46 -0700877EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700878media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
879 if (!ci) {
880 return AMEDIA_ERROR_INVALID_OBJECT;
881 }
882 if (!dst) {
883 return AMEDIA_ERROR_INVALID_PARAMETER;
Marco Nelissen050eb322014-05-09 15:10:23 -0700884 }
885 memcpy(dst, ci->iv, 16);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700886 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700887}
888
Marco Nelissen3425fd52014-05-14 11:12:46 -0700889EXPORT
Marco Nelissen79e2b622014-05-16 08:07:28 -0700890cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
Marco Nelissen050eb322014-05-09 15:10:23 -0700891 if (!ci) {
Marco Nelissen79e2b622014-05-16 08:07:28 -0700892 return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT;
Marco Nelissen050eb322014-05-09 15:10:23 -0700893 }
894 return ci->mode;
895}
896
Marco Nelissen3425fd52014-05-14 11:12:46 -0700897EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700898media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
899 if (!ci) {
900 return AMEDIA_ERROR_INVALID_OBJECT;
901 }
902 if (!dst) {
903 return AMEDIA_ERROR_INVALID_PARAMETER;
Marco Nelissen050eb322014-05-09 15:10:23 -0700904 }
905 memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700906 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700907}
908
Marco Nelissen3425fd52014-05-14 11:12:46 -0700909EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700910media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
911 if (!ci) {
912 return AMEDIA_ERROR_INVALID_OBJECT;
913 }
914 if (!dst) {
915 return AMEDIA_ERROR_INVALID_PARAMETER;
Marco Nelissen050eb322014-05-09 15:10:23 -0700916 }
917 memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700918 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700919}
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700920
Marco Nelissen0c3be872014-05-01 10:14:44 -0700921} // extern "C"
922