blob: 1055dc47abdd26590f88e48d580c365b762f1e03 [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
Chong Zhangefd1c5c2020-11-18 10:33:13 -080022#include <media/NdkMediaCodecPlatform.h>
Colin Cross7e8d4ba2017-05-04 16:17:42 -070023#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
Chong Zhangefd1c5c2020-11-18 10:33:13 -0800315static AMediaCodec * createAMediaCodec(const char *name,
316 bool name_is_type,
317 bool encoder,
318 pid_t pid = android::MediaCodec::kNoPid,
319 uid_t uid = android::MediaCodec::kNoUid) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700320 AMediaCodec *mData = new AMediaCodec();
321 mData->mLooper = new ALooper;
322 mData->mLooper->setName("NDK MediaCodec_looper");
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800323 size_t res = mData->mLooper->start(
Marco Nelissen0c3be872014-05-01 10:14:44 -0700324 false, // runOnCallingThread
325 true, // canCallJava XXX
Wei Jia00cc9922017-11-23 08:00:34 -0800326 PRIORITY_AUDIO);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800327 if (res != OK) {
328 ALOGE("Failed to start the looper");
Greg Kaiser4e147802016-03-14 14:44:20 -0700329 AMediaCodec_delete(mData);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800330 return NULL;
331 }
Marco Nelissen0c3be872014-05-01 10:14:44 -0700332 if (name_is_type) {
Chong Zhangefd1c5c2020-11-18 10:33:13 -0800333 mData->mCodec = android::MediaCodec::CreateByType(
334 mData->mLooper,
335 name,
336 encoder,
337 nullptr /* err */,
338 pid,
339 uid);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700340 } else {
Chong Zhangefd1c5c2020-11-18 10:33:13 -0800341 mData->mCodec = android::MediaCodec::CreateByComponentName(
342 mData->mLooper,
343 name,
344 nullptr /* err */,
345 pid,
346 uid);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700347 }
Andy Hung6bb63ad2015-04-28 19:05:08 -0700348 if (mData->mCodec == NULL) { // failed to create codec
349 AMediaCodec_delete(mData);
350 return NULL;
351 }
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700352 mData->mHandler = new CodecHandler(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700353 mData->mLooper->registerHandler(mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700354 mData->mGeneration = 1;
355 mData->mRequestedActivityNotification = false;
356 mData->mCallback = NULL;
357
Wei Jia00cc9922017-11-23 08:00:34 -0800358 mData->mAsyncCallback = {};
359 mData->mAsyncCallbackUserData = NULL;
360
Marco Nelissen0c3be872014-05-01 10:14:44 -0700361 return mData;
362}
363
Marco Nelissen3425fd52014-05-14 11:12:46 -0700364EXPORT
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700365AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
Chong Zhangefd1c5c2020-11-18 10:33:13 -0800366 return createAMediaCodec(name, false /* name_is_type */, false /* encoder */);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700367}
368
Marco Nelissen3425fd52014-05-14 11:12:46 -0700369EXPORT
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700370AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
Chong Zhangefd1c5c2020-11-18 10:33:13 -0800371 return createAMediaCodec(mime_type, true /* name_is_type */, false /* encoder */);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700372}
373
Marco Nelissen3425fd52014-05-14 11:12:46 -0700374EXPORT
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700375AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
Chong Zhangefd1c5c2020-11-18 10:33:13 -0800376 return createAMediaCodec(name, true /* name_is_type */, true /* encoder */);
377}
378
379EXPORT
380AMediaCodec* AMediaCodec_createCodecByNameForClient(const char *name,
381 pid_t pid,
382 uid_t uid) {
383 return createAMediaCodec(name, false /* name_is_type */, false /* encoder */, pid, uid);
384}
385
386EXPORT
387AMediaCodec* AMediaCodec_createDecoderByTypeForClient(const char *mime_type,
388 pid_t pid,
389 uid_t uid) {
390 return createAMediaCodec(mime_type, true /* name_is_type */, false /* encoder */, pid, uid);
391}
392
393EXPORT
394AMediaCodec* AMediaCodec_createEncoderByTypeForClient(const char *name,
395 pid_t pid,
396 uid_t uid) {
397 return createAMediaCodec(name, true /* name_is_type */, true /* encoder */, pid, uid);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700398}
399
Marco Nelissen3425fd52014-05-14 11:12:46 -0700400EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700401media_status_t AMediaCodec_delete(AMediaCodec *mData) {
Andy Hung6bb63ad2015-04-28 19:05:08 -0700402 if (mData != NULL) {
403 if (mData->mCodec != NULL) {
404 mData->mCodec->release();
405 mData->mCodec.clear();
406 }
Marco Nelissen0c3be872014-05-01 10:14:44 -0700407
Andy Hung6bb63ad2015-04-28 19:05:08 -0700408 if (mData->mLooper != NULL) {
409 if (mData->mHandler != NULL) {
410 mData->mLooper->unregisterHandler(mData->mHandler->id());
411 }
412 mData->mLooper->stop();
413 mData->mLooper.clear();
414 }
415 delete mData;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700416 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700417 return AMEDIA_OK;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700418}
419
Marco Nelissen3425fd52014-05-14 11:12:46 -0700420EXPORT
Wei Jia00cc9922017-11-23 08:00:34 -0800421media_status_t AMediaCodec_getName(
422 AMediaCodec *mData,
423 char** out_name) {
424 if (out_name == NULL) {
425 return AMEDIA_ERROR_INVALID_PARAMETER;
426 }
427
428 AString compName;
429 status_t err = mData->mCodec->getName(&compName);
430 if (err != OK) {
431 return translate_error(err);
432 }
433 *out_name = strdup(compName.c_str());
434 return AMEDIA_OK;
435}
436
437EXPORT
438void AMediaCodec_releaseName(
439 AMediaCodec * /* mData */,
440 char* name) {
441 if (name != NULL) {
442 free(name);
443 }
444}
445
446EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700447media_status_t AMediaCodec_configure(
Marco Nelissen050eb322014-05-09 15:10:23 -0700448 AMediaCodec *mData,
449 const AMediaFormat* format,
450 ANativeWindow* window,
451 AMediaCrypto *crypto,
452 uint32_t flags) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700453 sp<AMessage> nativeFormat;
454 AMediaFormat_getFormat(format, &nativeFormat);
455 ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str());
456 sp<Surface> surface = NULL;
457 if (window != NULL) {
458 surface = (Surface*) window;
459 }
460
Wei Jia00cc9922017-11-23 08:00:34 -0800461 status_t err = mData->mCodec->configure(nativeFormat, surface,
462 crypto ? crypto->mCrypto : NULL, flags);
463 if (err != OK) {
464 ALOGE("configure: err(%d), failed with format: %s",
465 err, nativeFormat->debugString(0).c_str());
466 }
467 return translate_error(err);
468}
469
470EXPORT
471media_status_t AMediaCodec_setAsyncNotifyCallback(
472 AMediaCodec *mData,
473 AMediaCodecOnAsyncNotifyCallback callback,
474 void *userdata) {
475 if (mData->mAsyncNotify == NULL && userdata != NULL) {
476 mData->mAsyncNotify = new AMessage(kWhatAsyncNotify, mData->mHandler);
477 status_t err = mData->mCodec->setCallback(mData->mAsyncNotify);
478 if (err != OK) {
479 ALOGE("setAsyncNotifyCallback: err(%d), failed to set async callback", err);
480 return translate_error(err);
481 }
482 }
483
484 Mutex::Autolock _l(mData->mAsyncCallbackLock);
485 mData->mAsyncCallback = callback;
486 mData->mAsyncCallbackUserData = userdata;
487
488 return AMEDIA_OK;
489}
490
491
492EXPORT
493media_status_t AMediaCodec_releaseCrypto(AMediaCodec *mData) {
494 return translate_error(mData->mCodec->releaseCrypto());
Marco Nelissen0c3be872014-05-01 10:14:44 -0700495}
496
Marco Nelissen3425fd52014-05-14 11:12:46 -0700497EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700498media_status_t AMediaCodec_start(AMediaCodec *mData) {
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700499 status_t ret = mData->mCodec->start();
500 if (ret != OK) {
501 return translate_error(ret);
502 }
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800503 mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700504 mData->mActivityNotification->setInt32("generation", mData->mGeneration);
505 requestActivityNotification(mData);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700506 return AMEDIA_OK;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700507}
508
Marco Nelissen3425fd52014-05-14 11:12:46 -0700509EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700510media_status_t AMediaCodec_stop(AMediaCodec *mData) {
511 media_status_t ret = translate_error(mData->mCodec->stop());
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700512
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800513 sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700514 sp<AMessage> response;
515 msg->postAndAwaitResponse(&response);
516 mData->mActivityNotification.clear();
517
518 return ret;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700519}
520
Marco Nelissen3425fd52014-05-14 11:12:46 -0700521EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700522media_status_t AMediaCodec_flush(AMediaCodec *mData) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700523 return translate_error(mData->mCodec->flush());
524}
525
Marco Nelissen3425fd52014-05-14 11:12:46 -0700526EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700527ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
528 size_t idx;
529 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700530 requestActivityNotification(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700531 if (ret == OK) {
532 return idx;
533 }
534 return translate_error(ret);
535}
536
Marco Nelissen3425fd52014-05-14 11:12:46 -0700537EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700538uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
Wei Jia00cc9922017-11-23 08:00:34 -0800539 if (mData->mAsyncNotify != NULL) {
540 // Asynchronous mode
541 sp<MediaCodecBuffer> abuf;
542 if (mData->mCodec->getInputBuffer(idx, &abuf) != 0) {
543 return NULL;
544 }
545
546 if (out_size != NULL) {
547 *out_size = abuf->capacity();
548 }
549 return abuf->data();
550 }
551
Wonsik Kim7e34bf52016-08-23 00:09:18 +0900552 android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700553 if (mData->mCodec->getInputBuffers(&abufs) == 0) {
554 size_t n = abufs.size();
555 if (idx >= n) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700556 ALOGE("buffer index %zu out of range", idx);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700557 return NULL;
558 }
Wonsik Kim7e34bf52016-08-23 00:09:18 +0900559 if (abufs[idx] == NULL) {
560 ALOGE("buffer index %zu is NULL", idx);
561 return NULL;
562 }
Marco Nelissen0c3be872014-05-01 10:14:44 -0700563 if (out_size != NULL) {
564 *out_size = abufs[idx]->capacity();
565 }
566 return abufs[idx]->data();
567 }
568 ALOGE("couldn't get input buffers");
569 return NULL;
570}
571
Marco Nelissen3425fd52014-05-14 11:12:46 -0700572EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700573uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
Wei Jia00cc9922017-11-23 08:00:34 -0800574 if (mData->mAsyncNotify != NULL) {
575 // Asynchronous mode
576 sp<MediaCodecBuffer> abuf;
577 if (mData->mCodec->getOutputBuffer(idx, &abuf) != 0) {
578 return NULL;
579 }
580
581 if (out_size != NULL) {
582 *out_size = abuf->capacity();
583 }
584 return abuf->data();
585 }
586
Wonsik Kim7e34bf52016-08-23 00:09:18 +0900587 android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700588 if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
589 size_t n = abufs.size();
590 if (idx >= n) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700591 ALOGE("buffer index %zu out of range", idx);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700592 return NULL;
593 }
594 if (out_size != NULL) {
595 *out_size = abufs[idx]->capacity();
596 }
597 return abufs[idx]->data();
598 }
599 ALOGE("couldn't get output buffers");
600 return NULL;
601}
602
Marco Nelissen3425fd52014-05-14 11:12:46 -0700603EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700604media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData,
Marco Nelissen0c3be872014-05-01 10:14:44 -0700605 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) {
606
607 AString errorMsg;
608 status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg);
609 return translate_error(ret);
610}
611
Marco Nelissen3425fd52014-05-14 11:12:46 -0700612EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700613ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
614 AMediaCodecBufferInfo *info, int64_t timeoutUs) {
615 size_t idx;
616 size_t offset;
617 size_t size;
618 uint32_t flags;
619 int64_t presentationTimeUs;
620 status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs,
621 &flags, timeoutUs);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700622 requestActivityNotification(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700623 switch (ret) {
624 case OK:
625 info->offset = offset;
626 info->size = size;
627 info->flags = flags;
628 info->presentationTimeUs = presentationTimeUs;
629 return idx;
630 case -EAGAIN:
631 return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
632 case android::INFO_FORMAT_CHANGED:
633 return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED;
634 case INFO_OUTPUT_BUFFERS_CHANGED:
635 return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED;
636 default:
637 break;
638 }
639 return translate_error(ret);
640}
641
Marco Nelissen3425fd52014-05-14 11:12:46 -0700642EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700643AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
644 sp<AMessage> format;
645 mData->mCodec->getOutputFormat(&format);
646 return AMediaFormat_fromMsg(&format);
647}
648
Marco Nelissen3425fd52014-05-14 11:12:46 -0700649EXPORT
Wei Jia00cc9922017-11-23 08:00:34 -0800650AMediaFormat* AMediaCodec_getInputFormat(AMediaCodec *mData) {
651 sp<AMessage> format;
652 mData->mCodec->getInputFormat(&format);
653 return AMediaFormat_fromMsg(&format);
654}
655
656EXPORT
Manikanta Kanamarlapudi2c32f4d2017-07-07 16:24:31 +0530657AMediaFormat* AMediaCodec_getBufferFormat(AMediaCodec *mData, size_t index) {
658 sp<AMessage> format;
659 mData->mCodec->getOutputFormat(index, &format);
660 return AMediaFormat_fromMsg(&format);
661}
662
663EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700664media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700665 if (render) {
666 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
667 } else {
668 return translate_error(mData->mCodec->releaseOutputBuffer(idx));
669 }
670}
671
Marco Nelissen3425fd52014-05-14 11:12:46 -0700672EXPORT
Marco Nelissen79e2b622014-05-16 08:07:28 -0700673media_status_t AMediaCodec_releaseOutputBufferAtTime(
674 AMediaCodec *mData, size_t idx, int64_t timestampNs) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700675 ALOGV("render @ %" PRId64, timestampNs);
Marco Nelissen79e2b622014-05-16 08:07:28 -0700676 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
677}
678
Vineeta Srivastava8c35da52016-01-08 17:33:09 -0800679EXPORT
680media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) {
681 sp<Surface> surface = NULL;
682 if (window != NULL) {
683 surface = (Surface*) window;
684 }
685 return translate_error(mData->mCodec->setSurface(surface));
686}
687
Praveen Chavan19431582017-01-16 11:56:18 -0800688EXPORT
689media_status_t AMediaCodec_createInputSurface(AMediaCodec *mData, ANativeWindow **surface) {
690 if (surface == NULL || mData == NULL) {
691 return AMEDIA_ERROR_INVALID_PARAMETER;
692 }
693 *surface = NULL;
694
695 sp<IGraphicBufferProducer> igbp = NULL;
696 status_t err = mData->mCodec->createInputSurface(&igbp);
697 if (err != NO_ERROR) {
698 return translate_error(err);
699 }
700
701 *surface = new Surface(igbp);
702 ANativeWindow_acquire(*surface);
703 return AMEDIA_OK;
704}
705
Praveen Chavan85a53632017-01-31 12:21:33 -0800706EXPORT
707media_status_t AMediaCodec_createPersistentInputSurface(ANativeWindow **surface) {
708 if (surface == NULL) {
709 return AMEDIA_ERROR_INVALID_PARAMETER;
710 }
711 *surface = NULL;
712
713 sp<PersistentSurface> ps = MediaCodec::CreatePersistentInputSurface();
714 if (ps == NULL) {
715 return AMEDIA_ERROR_UNKNOWN;
716 }
717
718 sp<IGraphicBufferProducer> igbp = ps->getBufferProducer();
719 if (igbp == NULL) {
720 return AMEDIA_ERROR_UNKNOWN;
721 }
722
723 *surface = new AMediaCodecPersistentSurface(igbp, ps);
724 ANativeWindow_acquire(*surface);
725
726 return AMEDIA_OK;
727}
728
729EXPORT
730media_status_t AMediaCodec_setInputSurface(
731 AMediaCodec *mData, ANativeWindow *surface) {
732
733 if (surface == NULL || mData == NULL) {
734 return AMEDIA_ERROR_INVALID_PARAMETER;
735 }
736
737 AMediaCodecPersistentSurface *aMediaPersistentSurface =
738 static_cast<AMediaCodecPersistentSurface *>(surface);
739 if (aMediaPersistentSurface->mPersistentSurface == NULL) {
740 return AMEDIA_ERROR_INVALID_PARAMETER;
741 }
742
743 return translate_error(mData->mCodec->setInputSurface(
744 aMediaPersistentSurface->mPersistentSurface));
745}
746
Praveen Chavanf373e842017-02-01 11:50:15 -0800747EXPORT
748media_status_t AMediaCodec_setParameters(
749 AMediaCodec *mData, const AMediaFormat* params) {
750 if (params == NULL || mData == NULL) {
751 return AMEDIA_ERROR_INVALID_PARAMETER;
752 }
753 sp<AMessage> nativeParams;
754 AMediaFormat_getFormat(params, &nativeParams);
755 ALOGV("setParameters: %s", nativeParams->debugString(0).c_str());
756
757 return translate_error(mData->mCodec->setParameters(nativeParams));
758}
759
Robert Shihaf42d3f2017-03-20 16:45:37 -0700760EXPORT
761media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData) {
762
763 if (mData == NULL) {
764 return AMEDIA_ERROR_INVALID_PARAMETER;
765 }
766
767 status_t err = mData->mCodec->signalEndOfInputStream();
768 if (err == INVALID_OPERATION) {
769 return AMEDIA_ERROR_INVALID_OPERATION;
770 }
771
772 return translate_error(err);
773
774}
775
Marco Nelissene22a64b2014-05-23 15:49:49 -0700776//EXPORT
Glenn Kastenb187de12014-12-30 08:18:15 -0800777media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
778 void *userdata) {
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700779 mData->mCallback = callback;
780 mData->mCallbackUserData = userdata;
Marco Nelissene419d7c2014-05-15 14:17:25 -0700781 return AMEDIA_OK;
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700782}
783
Marco Nelissen050eb322014-05-09 15:10:23 -0700784typedef struct AMediaCodecCryptoInfo {
785 int numsubsamples;
786 uint8_t key[16];
787 uint8_t iv[16];
Marco Nelissen79e2b622014-05-16 08:07:28 -0700788 cryptoinfo_mode_t mode;
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800789 cryptoinfo_pattern_t pattern;
Marco Nelissen050eb322014-05-09 15:10:23 -0700790 size_t *clearbytes;
791 size_t *encryptedbytes;
792} AMediaCodecCryptoInfo;
793
Marco Nelissen3425fd52014-05-14 11:12:46 -0700794EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700795media_status_t AMediaCodec_queueSecureInputBuffer(
Marco Nelissen050eb322014-05-09 15:10:23 -0700796 AMediaCodec* codec,
797 size_t idx,
798 off_t offset,
799 AMediaCodecCryptoInfo* crypto,
800 uint64_t time,
801 uint32_t flags) {
802
803 CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples];
804 for (int i = 0; i < crypto->numsubsamples; i++) {
805 subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i];
806 subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
807 }
808
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800809 CryptoPlugin::Pattern pattern;
810 pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
811 pattern.mSkipBlocks = crypto->pattern.skipBlocks;
812
Marco Nelissen050eb322014-05-09 15:10:23 -0700813 AString errormsg;
814 status_t err = codec->mCodec->queueSecureInputBuffer(idx,
815 offset,
816 subSamples,
817 crypto->numsubsamples,
818 crypto->key,
819 crypto->iv,
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800820 (CryptoPlugin::Mode)crypto->mode,
821 pattern,
Marco Nelissen050eb322014-05-09 15:10:23 -0700822 time,
823 flags,
824 &errormsg);
825 if (err != 0) {
826 ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
827 }
Marco Nelissen829e0972014-05-13 16:22:19 -0700828 delete [] subSamples;
Marco Nelissen050eb322014-05-09 15:10:23 -0700829 return translate_error(err);
830}
831
Wei Jia00cc9922017-11-23 08:00:34 -0800832EXPORT
833bool AMediaCodecActionCode_isRecoverable(int32_t actionCode) {
834 return (actionCode == ACTION_CODE_RECOVERABLE);
835}
836
837EXPORT
838bool AMediaCodecActionCode_isTransient(int32_t actionCode) {
839 return (actionCode == ACTION_CODE_TRANSIENT);
840}
841
Marco Nelissen050eb322014-05-09 15:10:23 -0700842
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800843EXPORT
844void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
845 cryptoinfo_pattern_t *pattern) {
846 info->pattern.encryptBlocks = pattern->encryptBlocks;
847 info->pattern.skipBlocks = pattern->skipBlocks;
848}
Marco Nelissen050eb322014-05-09 15:10:23 -0700849
Marco Nelissen3425fd52014-05-14 11:12:46 -0700850EXPORT
Marco Nelissen050eb322014-05-09 15:10:23 -0700851AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
852 int numsubsamples,
853 uint8_t key[16],
854 uint8_t iv[16],
Marco Nelissen79e2b622014-05-16 08:07:28 -0700855 cryptoinfo_mode_t mode,
Marco Nelissen050eb322014-05-09 15:10:23 -0700856 size_t *clearbytes,
857 size_t *encryptedbytes) {
858
859 // size needed to store all the crypto data
Marco Nelissend1fd0272018-07-31 15:12:51 -0700860 size_t cryptosize;
861 // = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
862 if (__builtin_mul_overflow(sizeof(size_t) * 2, numsubsamples, &cryptosize) ||
863 __builtin_add_overflow(cryptosize, sizeof(AMediaCodecCryptoInfo), &cryptosize)) {
864 ALOGE("crypto size overflow");
865 return NULL;
866 }
Marco Nelissen050eb322014-05-09 15:10:23 -0700867 AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
868 if (!ret) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700869 ALOGE("couldn't allocate %zu bytes", cryptosize);
Marco Nelissen050eb322014-05-09 15:10:23 -0700870 return NULL;
871 }
872 ret->numsubsamples = numsubsamples;
873 memcpy(ret->key, key, 16);
874 memcpy(ret->iv, iv, 16);
875 ret->mode = mode;
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800876 ret->pattern.encryptBlocks = 0;
877 ret->pattern.skipBlocks = 0;
Marco Nelissen050eb322014-05-09 15:10:23 -0700878
879 // clearbytes and encryptedbytes point at the actual data, which follows
Marco Nelissen829e0972014-05-13 16:22:19 -0700880 ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
881 ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes
Marco Nelissen050eb322014-05-09 15:10:23 -0700882
Marco Nelissen829e0972014-05-13 16:22:19 -0700883 memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
884 memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));
Marco Nelissen050eb322014-05-09 15:10:23 -0700885
886 return ret;
887}
888
889
Marco Nelissen3425fd52014-05-14 11:12:46 -0700890EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700891media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
Marco Nelissen050eb322014-05-09 15:10:23 -0700892 free(info);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700893 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700894}
895
Marco Nelissen3425fd52014-05-14 11:12:46 -0700896EXPORT
Marco Nelissen050eb322014-05-09 15:10:23 -0700897size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
898 return ci->numsubsamples;
899}
900
Marco Nelissen3425fd52014-05-14 11:12:46 -0700901EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700902media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
903 if (!ci) {
904 return AMEDIA_ERROR_INVALID_OBJECT;
905 }
906 if (!dst) {
907 return AMEDIA_ERROR_INVALID_PARAMETER;
Marco Nelissen050eb322014-05-09 15:10:23 -0700908 }
909 memcpy(dst, ci->key, 16);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700910 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700911}
912
Marco Nelissen3425fd52014-05-14 11:12:46 -0700913EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700914media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
915 if (!ci) {
916 return AMEDIA_ERROR_INVALID_OBJECT;
917 }
918 if (!dst) {
919 return AMEDIA_ERROR_INVALID_PARAMETER;
Marco Nelissen050eb322014-05-09 15:10:23 -0700920 }
921 memcpy(dst, ci->iv, 16);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700922 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700923}
924
Marco Nelissen3425fd52014-05-14 11:12:46 -0700925EXPORT
Marco Nelissen79e2b622014-05-16 08:07:28 -0700926cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
Marco Nelissen050eb322014-05-09 15:10:23 -0700927 if (!ci) {
Marco Nelissen79e2b622014-05-16 08:07:28 -0700928 return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT;
Marco Nelissen050eb322014-05-09 15:10:23 -0700929 }
930 return ci->mode;
931}
932
Marco Nelissen3425fd52014-05-14 11:12:46 -0700933EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700934media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
935 if (!ci) {
936 return AMEDIA_ERROR_INVALID_OBJECT;
937 }
938 if (!dst) {
939 return AMEDIA_ERROR_INVALID_PARAMETER;
Marco Nelissen050eb322014-05-09 15:10:23 -0700940 }
941 memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700942 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700943}
944
Marco Nelissen3425fd52014-05-14 11:12:46 -0700945EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700946media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
947 if (!ci) {
948 return AMEDIA_ERROR_INVALID_OBJECT;
949 }
950 if (!dst) {
951 return AMEDIA_ERROR_INVALID_PARAMETER;
Marco Nelissen050eb322014-05-09 15:10:23 -0700952 }
953 memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700954 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700955}
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700956
Marco Nelissen0c3be872014-05-01 10:14:44 -0700957} // extern "C"
958