blob: 227459a01fba61e132d79c55622f9f1c79b7c5a4 [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);
Ray Essick4e5af242021-11-05 14:20:22 -0700161 if (mCodec->mAsyncCallback.onAsyncInputAvailable != NULL) {
Wei Jia00cc9922017-11-23 08:00:34 -0800162 mCodec->mAsyncCallback.onAsyncInputAvailable(
163 mCodec,
164 mCodec->mAsyncCallbackUserData,
165 index);
166 }
167
168 break;
169 }
170
171 case MediaCodec::CB_OUTPUT_AVAILABLE:
172 {
173 int32_t index;
174 size_t offset;
175 size_t size;
176 int64_t timeUs;
177 int32_t flags;
178
179 if (!msg->findInt32("index", &index)) {
180 ALOGE("CB_OUTPUT_AVAILABLE: index is expected.");
181 break;
182 }
183 if (!msg->findSize("offset", &offset)) {
184 ALOGE("CB_OUTPUT_AVAILABLE: offset is expected.");
185 break;
186 }
187 if (!msg->findSize("size", &size)) {
188 ALOGE("CB_OUTPUT_AVAILABLE: size is expected.");
189 break;
190 }
191 if (!msg->findInt64("timeUs", &timeUs)) {
192 ALOGE("CB_OUTPUT_AVAILABLE: timeUs is expected.");
193 break;
194 }
195 if (!msg->findInt32("flags", &flags)) {
196 ALOGE("CB_OUTPUT_AVAILABLE: flags is expected.");
197 break;
198 }
199
200 AMediaCodecBufferInfo bufferInfo = {
201 (int32_t)offset,
202 (int32_t)size,
203 timeUs,
204 (uint32_t)flags};
205
206 Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
Ray Essick4e5af242021-11-05 14:20:22 -0700207 if (mCodec->mAsyncCallback.onAsyncOutputAvailable != NULL) {
Wei Jia00cc9922017-11-23 08:00:34 -0800208 mCodec->mAsyncCallback.onAsyncOutputAvailable(
209 mCodec,
210 mCodec->mAsyncCallbackUserData,
211 index,
212 &bufferInfo);
213 }
214
215 break;
216 }
217
218 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
219 {
220 sp<AMessage> format;
221 if (!msg->findMessage("format", &format)) {
222 ALOGE("CB_OUTPUT_FORMAT_CHANGED: format is expected.");
223 break;
224 }
225
Chong Zhang1fa26862019-09-16 16:15:00 -0700226 // Here format is MediaCodec's internal copy of output format.
227 // Make a copy since the client might modify it.
228 sp<AMessage> copy;
229 if (format != nullptr) {
230 copy = format->dup();
231 }
232 AMediaFormat *aMediaFormat = AMediaFormat_fromMsg(&copy);
Wei Jia00cc9922017-11-23 08:00:34 -0800233
234 Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
Ray Essick4e5af242021-11-05 14:20:22 -0700235 if (mCodec->mAsyncCallback.onAsyncFormatChanged != NULL) {
Wei Jia00cc9922017-11-23 08:00:34 -0800236 mCodec->mAsyncCallback.onAsyncFormatChanged(
237 mCodec,
238 mCodec->mAsyncCallbackUserData,
239 aMediaFormat);
240 }
241
242 break;
243 }
244
245 case MediaCodec::CB_ERROR:
246 {
247 status_t err;
248 int32_t actionCode;
249 AString detail;
250 if (!msg->findInt32("err", &err)) {
251 ALOGE("CB_ERROR: err is expected.");
252 break;
253 }
Rakesh Kumard5ea3f32019-09-20 17:08:07 +0530254 if (!msg->findInt32("actionCode", &actionCode)) {
255 ALOGE("CB_ERROR: actionCode is expected.");
Wei Jia00cc9922017-11-23 08:00:34 -0800256 break;
257 }
258 msg->findString("detail", &detail);
Chong Zhangeb9aca62020-09-16 12:49:41 -0700259 ALOGE("Codec reported error(0x%x), actionCode(%d), detail(%s)",
Wei Jia00cc9922017-11-23 08:00:34 -0800260 err, actionCode, detail.c_str());
261
262 Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
Ray Essick4e5af242021-11-05 14:20:22 -0700263 if (mCodec->mAsyncCallback.onAsyncError != NULL) {
Wei Jia00cc9922017-11-23 08:00:34 -0800264 mCodec->mAsyncCallback.onAsyncError(
265 mCodec,
266 mCodec->mAsyncCallbackUserData,
267 translate_error(err),
268 actionCode,
269 detail.c_str());
270 }
271
272 break;
273 }
274
275 default:
276 {
277 ALOGE("kWhatAsyncNotify: callbackID(%d) is unexpected.", cbID);
278 break;
279 }
280 }
281 break;
282 }
283
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700284 case kWhatStopActivityNotifications:
285 {
Lajos Molnar3f274362015-03-05 14:35:41 -0800286 sp<AReplyToken> replyID;
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700287 msg->senderAwaitsResponse(&replyID);
288
289 mCodec->mGeneration++;
290 mCodec->mRequestedActivityNotification = false;
291
292 sp<AMessage> response = new AMessage;
293 response->postReply(replyID);
294 break;
295 }
296
297 default:
298 ALOGE("shouldn't be here");
299 break;
300 }
301
302}
303
304
305static void requestActivityNotification(AMediaCodec *codec) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800306 (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post();
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700307}
308
Marco Nelissen0c3be872014-05-01 10:14:44 -0700309extern "C" {
310
Chong Zhangefd1c5c2020-11-18 10:33:13 -0800311static AMediaCodec * createAMediaCodec(const char *name,
312 bool name_is_type,
313 bool encoder,
314 pid_t pid = android::MediaCodec::kNoPid,
315 uid_t uid = android::MediaCodec::kNoUid) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700316 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) {
Chong Zhangefd1c5c2020-11-18 10:33:13 -0800329 mData->mCodec = android::MediaCodec::CreateByType(
330 mData->mLooper,
331 name,
332 encoder,
333 nullptr /* err */,
334 pid,
335 uid);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700336 } else {
Chong Zhangefd1c5c2020-11-18 10:33:13 -0800337 mData->mCodec = android::MediaCodec::CreateByComponentName(
338 mData->mLooper,
339 name,
340 nullptr /* err */,
341 pid,
342 uid);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700343 }
Andy Hung6bb63ad2015-04-28 19:05:08 -0700344 if (mData->mCodec == NULL) { // failed to create codec
345 AMediaCodec_delete(mData);
346 return NULL;
347 }
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700348 mData->mHandler = new CodecHandler(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700349 mData->mLooper->registerHandler(mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700350 mData->mGeneration = 1;
351 mData->mRequestedActivityNotification = false;
352 mData->mCallback = NULL;
353
Wei Jia00cc9922017-11-23 08:00:34 -0800354 mData->mAsyncCallback = {};
355 mData->mAsyncCallbackUserData = NULL;
356
Marco Nelissen0c3be872014-05-01 10:14:44 -0700357 return mData;
358}
359
Marco Nelissen3425fd52014-05-14 11:12:46 -0700360EXPORT
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700361AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
Chong Zhangefd1c5c2020-11-18 10:33:13 -0800362 return createAMediaCodec(name, false /* name_is_type */, false /* encoder */);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700363}
364
Marco Nelissen3425fd52014-05-14 11:12:46 -0700365EXPORT
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700366AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
Chong Zhangefd1c5c2020-11-18 10:33:13 -0800367 return createAMediaCodec(mime_type, true /* name_is_type */, false /* encoder */);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700368}
369
Marco Nelissen3425fd52014-05-14 11:12:46 -0700370EXPORT
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700371AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
Chong Zhangefd1c5c2020-11-18 10:33:13 -0800372 return createAMediaCodec(name, true /* name_is_type */, true /* encoder */);
373}
374
375EXPORT
376AMediaCodec* AMediaCodec_createCodecByNameForClient(const char *name,
377 pid_t pid,
378 uid_t uid) {
379 return createAMediaCodec(name, false /* name_is_type */, false /* encoder */, pid, uid);
380}
381
382EXPORT
383AMediaCodec* AMediaCodec_createDecoderByTypeForClient(const char *mime_type,
384 pid_t pid,
385 uid_t uid) {
386 return createAMediaCodec(mime_type, true /* name_is_type */, false /* encoder */, pid, uid);
387}
388
389EXPORT
390AMediaCodec* AMediaCodec_createEncoderByTypeForClient(const char *name,
391 pid_t pid,
392 uid_t uid) {
393 return createAMediaCodec(name, true /* name_is_type */, true /* encoder */, pid, uid);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700394}
395
Marco Nelissen3425fd52014-05-14 11:12:46 -0700396EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700397media_status_t AMediaCodec_delete(AMediaCodec *mData) {
Andy Hung6bb63ad2015-04-28 19:05:08 -0700398 if (mData != NULL) {
399 if (mData->mCodec != NULL) {
400 mData->mCodec->release();
401 mData->mCodec.clear();
402 }
Marco Nelissen0c3be872014-05-01 10:14:44 -0700403
Andy Hung6bb63ad2015-04-28 19:05:08 -0700404 if (mData->mLooper != NULL) {
405 if (mData->mHandler != NULL) {
406 mData->mLooper->unregisterHandler(mData->mHandler->id());
407 }
408 mData->mLooper->stop();
409 mData->mLooper.clear();
410 }
411 delete mData;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700412 }
Marco Nelissene419d7c2014-05-15 14:17:25 -0700413 return AMEDIA_OK;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700414}
415
Marco Nelissen3425fd52014-05-14 11:12:46 -0700416EXPORT
Wei Jia00cc9922017-11-23 08:00:34 -0800417media_status_t AMediaCodec_getName(
418 AMediaCodec *mData,
419 char** out_name) {
420 if (out_name == NULL) {
421 return AMEDIA_ERROR_INVALID_PARAMETER;
422 }
423
424 AString compName;
425 status_t err = mData->mCodec->getName(&compName);
426 if (err != OK) {
427 return translate_error(err);
428 }
429 *out_name = strdup(compName.c_str());
430 return AMEDIA_OK;
431}
432
433EXPORT
434void AMediaCodec_releaseName(
435 AMediaCodec * /* mData */,
436 char* name) {
437 if (name != NULL) {
438 free(name);
439 }
440}
441
442EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700443media_status_t AMediaCodec_configure(
Marco Nelissen050eb322014-05-09 15:10:23 -0700444 AMediaCodec *mData,
445 const AMediaFormat* format,
446 ANativeWindow* window,
447 AMediaCrypto *crypto,
448 uint32_t flags) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700449 sp<AMessage> nativeFormat;
450 AMediaFormat_getFormat(format, &nativeFormat);
Manisha Jajoob821e1d2021-08-09 15:09:53 +0530451 // create our shallow copy, so we aren't victim to any later changes.
452 sp<AMessage> dupNativeFormat = nativeFormat->dup();
453 ALOGV("configure with format: %s", dupNativeFormat->debugString(0).c_str());
Marco Nelissen0c3be872014-05-01 10:14:44 -0700454 sp<Surface> surface = NULL;
455 if (window != NULL) {
456 surface = (Surface*) window;
457 }
458
Manisha Jajoob821e1d2021-08-09 15:09:53 +0530459 status_t err = mData->mCodec->configure(dupNativeFormat, surface,
Wei Jia00cc9922017-11-23 08:00:34 -0800460 crypto ? crypto->mCrypto : NULL, flags);
461 if (err != OK) {
462 ALOGE("configure: err(%d), failed with format: %s",
Manisha Jajoob821e1d2021-08-09 15:09:53 +0530463 err, dupNativeFormat->debugString(0).c_str());
Wei Jia00cc9922017-11-23 08:00:34 -0800464 }
465 return translate_error(err);
466}
467
468EXPORT
469media_status_t AMediaCodec_setAsyncNotifyCallback(
470 AMediaCodec *mData,
471 AMediaCodecOnAsyncNotifyCallback callback,
472 void *userdata) {
Wei Jia00cc9922017-11-23 08:00:34 -0800473
474 Mutex::Autolock _l(mData->mAsyncCallbackLock);
Ray Essick4e5af242021-11-05 14:20:22 -0700475
476 if (mData->mAsyncNotify == NULL) {
477 mData->mAsyncNotify = new AMessage(kWhatAsyncNotify, mData->mHandler);
478 }
479
480 // always call, codec may have been reset/re-configured since last call.
481 status_t err = mData->mCodec->setCallback(mData->mAsyncNotify);
482 if (err != OK) {
483 ALOGE("setAsyncNotifyCallback: err(%d), failed to set async callback", err);
484 return translate_error(err);
485 }
486
Wei Jia00cc9922017-11-23 08:00:34 -0800487 mData->mAsyncCallback = callback;
488 mData->mAsyncCallbackUserData = userdata;
489
490 return AMEDIA_OK;
491}
492
493
494EXPORT
495media_status_t AMediaCodec_releaseCrypto(AMediaCodec *mData) {
496 return translate_error(mData->mCodec->releaseCrypto());
Marco Nelissen0c3be872014-05-01 10:14:44 -0700497}
498
Marco Nelissen3425fd52014-05-14 11:12:46 -0700499EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700500media_status_t AMediaCodec_start(AMediaCodec *mData) {
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700501 status_t ret = mData->mCodec->start();
502 if (ret != OK) {
503 return translate_error(ret);
504 }
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800505 mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700506 mData->mActivityNotification->setInt32("generation", mData->mGeneration);
507 requestActivityNotification(mData);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700508 return AMEDIA_OK;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700509}
510
Marco Nelissen3425fd52014-05-14 11:12:46 -0700511EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700512media_status_t AMediaCodec_stop(AMediaCodec *mData) {
513 media_status_t ret = translate_error(mData->mCodec->stop());
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700514
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800515 sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700516 sp<AMessage> response;
517 msg->postAndAwaitResponse(&response);
518 mData->mActivityNotification.clear();
519
520 return ret;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700521}
522
Marco Nelissen3425fd52014-05-14 11:12:46 -0700523EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700524media_status_t AMediaCodec_flush(AMediaCodec *mData) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700525 return translate_error(mData->mCodec->flush());
526}
527
Marco Nelissen3425fd52014-05-14 11:12:46 -0700528EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700529ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
530 size_t idx;
531 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700532 requestActivityNotification(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700533 if (ret == OK) {
534 return idx;
535 }
536 return translate_error(ret);
537}
538
Marco Nelissen3425fd52014-05-14 11:12:46 -0700539EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700540uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
Wei Jia00cc9922017-11-23 08:00:34 -0800541 if (mData->mAsyncNotify != NULL) {
542 // Asynchronous mode
543 sp<MediaCodecBuffer> abuf;
544 if (mData->mCodec->getInputBuffer(idx, &abuf) != 0) {
545 return NULL;
546 }
547
548 if (out_size != NULL) {
549 *out_size = abuf->capacity();
550 }
551 return abuf->data();
552 }
553
Wonsik Kim7e34bf52016-08-23 00:09:18 +0900554 android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700555 if (mData->mCodec->getInputBuffers(&abufs) == 0) {
556 size_t n = abufs.size();
557 if (idx >= n) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700558 ALOGE("buffer index %zu out of range", idx);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700559 return NULL;
560 }
Wonsik Kim7e34bf52016-08-23 00:09:18 +0900561 if (abufs[idx] == NULL) {
562 ALOGE("buffer index %zu is NULL", idx);
563 return NULL;
564 }
Marco Nelissen0c3be872014-05-01 10:14:44 -0700565 if (out_size != NULL) {
566 *out_size = abufs[idx]->capacity();
567 }
568 return abufs[idx]->data();
569 }
570 ALOGE("couldn't get input buffers");
571 return NULL;
572}
573
Marco Nelissen3425fd52014-05-14 11:12:46 -0700574EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700575uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
Wei Jia00cc9922017-11-23 08:00:34 -0800576 if (mData->mAsyncNotify != NULL) {
577 // Asynchronous mode
578 sp<MediaCodecBuffer> abuf;
579 if (mData->mCodec->getOutputBuffer(idx, &abuf) != 0) {
580 return NULL;
581 }
582
583 if (out_size != NULL) {
584 *out_size = abuf->capacity();
585 }
586 return abuf->data();
587 }
588
Wonsik Kim7e34bf52016-08-23 00:09:18 +0900589 android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700590 if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
591 size_t n = abufs.size();
592 if (idx >= n) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700593 ALOGE("buffer index %zu out of range", idx);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700594 return NULL;
595 }
596 if (out_size != NULL) {
597 *out_size = abufs[idx]->capacity();
598 }
599 return abufs[idx]->data();
600 }
601 ALOGE("couldn't get output buffers");
602 return NULL;
603}
604
Marco Nelissen3425fd52014-05-14 11:12:46 -0700605EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700606media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData,
Marco Nelissen0c3be872014-05-01 10:14:44 -0700607 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) {
608
609 AString errorMsg;
610 status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg);
611 return translate_error(ret);
612}
613
Marco Nelissen3425fd52014-05-14 11:12:46 -0700614EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700615ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
616 AMediaCodecBufferInfo *info, int64_t timeoutUs) {
617 size_t idx;
618 size_t offset;
619 size_t size;
620 uint32_t flags;
621 int64_t presentationTimeUs;
622 status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs,
623 &flags, timeoutUs);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700624 requestActivityNotification(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700625 switch (ret) {
626 case OK:
627 info->offset = offset;
628 info->size = size;
629 info->flags = flags;
630 info->presentationTimeUs = presentationTimeUs;
631 return idx;
632 case -EAGAIN:
633 return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
634 case android::INFO_FORMAT_CHANGED:
635 return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED;
636 case INFO_OUTPUT_BUFFERS_CHANGED:
637 return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED;
638 default:
639 break;
640 }
641 return translate_error(ret);
642}
643
Marco Nelissen3425fd52014-05-14 11:12:46 -0700644EXPORT
Marco Nelissen0c3be872014-05-01 10:14:44 -0700645AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
646 sp<AMessage> format;
647 mData->mCodec->getOutputFormat(&format);
648 return AMediaFormat_fromMsg(&format);
649}
650
Marco Nelissen3425fd52014-05-14 11:12:46 -0700651EXPORT
Wei Jia00cc9922017-11-23 08:00:34 -0800652AMediaFormat* AMediaCodec_getInputFormat(AMediaCodec *mData) {
653 sp<AMessage> format;
654 mData->mCodec->getInputFormat(&format);
655 return AMediaFormat_fromMsg(&format);
656}
657
658EXPORT
Manikanta Kanamarlapudi2c32f4d2017-07-07 16:24:31 +0530659AMediaFormat* AMediaCodec_getBufferFormat(AMediaCodec *mData, size_t index) {
660 sp<AMessage> format;
661 mData->mCodec->getOutputFormat(index, &format);
662 return AMediaFormat_fromMsg(&format);
663}
664
665EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700666media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700667 if (render) {
668 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
669 } else {
670 return translate_error(mData->mCodec->releaseOutputBuffer(idx));
671 }
672}
673
Marco Nelissen3425fd52014-05-14 11:12:46 -0700674EXPORT
Marco Nelissen79e2b622014-05-16 08:07:28 -0700675media_status_t AMediaCodec_releaseOutputBufferAtTime(
676 AMediaCodec *mData, size_t idx, int64_t timestampNs) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700677 ALOGV("render @ %" PRId64, timestampNs);
Marco Nelissen79e2b622014-05-16 08:07:28 -0700678 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
679}
680
Vineeta Srivastava8c35da52016-01-08 17:33:09 -0800681EXPORT
682media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) {
683 sp<Surface> surface = NULL;
684 if (window != NULL) {
685 surface = (Surface*) window;
686 }
687 return translate_error(mData->mCodec->setSurface(surface));
688}
689
Praveen Chavan19431582017-01-16 11:56:18 -0800690EXPORT
691media_status_t AMediaCodec_createInputSurface(AMediaCodec *mData, ANativeWindow **surface) {
692 if (surface == NULL || mData == NULL) {
693 return AMEDIA_ERROR_INVALID_PARAMETER;
694 }
695 *surface = NULL;
696
697 sp<IGraphicBufferProducer> igbp = NULL;
698 status_t err = mData->mCodec->createInputSurface(&igbp);
699 if (err != NO_ERROR) {
700 return translate_error(err);
701 }
702
703 *surface = new Surface(igbp);
704 ANativeWindow_acquire(*surface);
705 return AMEDIA_OK;
706}
707
Praveen Chavan85a53632017-01-31 12:21:33 -0800708EXPORT
709media_status_t AMediaCodec_createPersistentInputSurface(ANativeWindow **surface) {
710 if (surface == NULL) {
711 return AMEDIA_ERROR_INVALID_PARAMETER;
712 }
713 *surface = NULL;
714
715 sp<PersistentSurface> ps = MediaCodec::CreatePersistentInputSurface();
716 if (ps == NULL) {
717 return AMEDIA_ERROR_UNKNOWN;
718 }
719
720 sp<IGraphicBufferProducer> igbp = ps->getBufferProducer();
721 if (igbp == NULL) {
722 return AMEDIA_ERROR_UNKNOWN;
723 }
724
725 *surface = new AMediaCodecPersistentSurface(igbp, ps);
726 ANativeWindow_acquire(*surface);
727
728 return AMEDIA_OK;
729}
730
731EXPORT
732media_status_t AMediaCodec_setInputSurface(
733 AMediaCodec *mData, ANativeWindow *surface) {
734
735 if (surface == NULL || mData == NULL) {
736 return AMEDIA_ERROR_INVALID_PARAMETER;
737 }
738
739 AMediaCodecPersistentSurface *aMediaPersistentSurface =
740 static_cast<AMediaCodecPersistentSurface *>(surface);
741 if (aMediaPersistentSurface->mPersistentSurface == NULL) {
742 return AMEDIA_ERROR_INVALID_PARAMETER;
743 }
744
745 return translate_error(mData->mCodec->setInputSurface(
746 aMediaPersistentSurface->mPersistentSurface));
747}
748
Praveen Chavanf373e842017-02-01 11:50:15 -0800749EXPORT
750media_status_t AMediaCodec_setParameters(
751 AMediaCodec *mData, const AMediaFormat* params) {
752 if (params == NULL || mData == NULL) {
753 return AMEDIA_ERROR_INVALID_PARAMETER;
754 }
755 sp<AMessage> nativeParams;
756 AMediaFormat_getFormat(params, &nativeParams);
757 ALOGV("setParameters: %s", nativeParams->debugString(0).c_str());
758
759 return translate_error(mData->mCodec->setParameters(nativeParams));
760}
761
Robert Shihaf42d3f2017-03-20 16:45:37 -0700762EXPORT
763media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData) {
764
765 if (mData == NULL) {
766 return AMEDIA_ERROR_INVALID_PARAMETER;
767 }
768
769 status_t err = mData->mCodec->signalEndOfInputStream();
770 if (err == INVALID_OPERATION) {
771 return AMEDIA_ERROR_INVALID_OPERATION;
772 }
773
774 return translate_error(err);
775
776}
777
Marco Nelissene22a64b2014-05-23 15:49:49 -0700778//EXPORT
Glenn Kastenb187de12014-12-30 08:18:15 -0800779media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
780 void *userdata) {
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700781 mData->mCallback = callback;
782 mData->mCallbackUserData = userdata;
Marco Nelissene419d7c2014-05-15 14:17:25 -0700783 return AMEDIA_OK;
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700784}
785
Marco Nelissen050eb322014-05-09 15:10:23 -0700786typedef struct AMediaCodecCryptoInfo {
787 int numsubsamples;
788 uint8_t key[16];
789 uint8_t iv[16];
Marco Nelissen79e2b622014-05-16 08:07:28 -0700790 cryptoinfo_mode_t mode;
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800791 cryptoinfo_pattern_t pattern;
Marco Nelissen050eb322014-05-09 15:10:23 -0700792 size_t *clearbytes;
793 size_t *encryptedbytes;
794} AMediaCodecCryptoInfo;
795
Marco Nelissen3425fd52014-05-14 11:12:46 -0700796EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700797media_status_t AMediaCodec_queueSecureInputBuffer(
Marco Nelissen050eb322014-05-09 15:10:23 -0700798 AMediaCodec* codec,
799 size_t idx,
800 off_t offset,
801 AMediaCodecCryptoInfo* crypto,
802 uint64_t time,
803 uint32_t flags) {
804
805 CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples];
806 for (int i = 0; i < crypto->numsubsamples; i++) {
807 subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i];
808 subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
809 }
810
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800811 CryptoPlugin::Pattern pattern;
812 pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
813 pattern.mSkipBlocks = crypto->pattern.skipBlocks;
814
Marco Nelissen050eb322014-05-09 15:10:23 -0700815 AString errormsg;
816 status_t err = codec->mCodec->queueSecureInputBuffer(idx,
817 offset,
818 subSamples,
819 crypto->numsubsamples,
820 crypto->key,
821 crypto->iv,
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800822 (CryptoPlugin::Mode)crypto->mode,
823 pattern,
Marco Nelissen050eb322014-05-09 15:10:23 -0700824 time,
825 flags,
826 &errormsg);
827 if (err != 0) {
828 ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
829 }
Marco Nelissen829e0972014-05-13 16:22:19 -0700830 delete [] subSamples;
Marco Nelissen050eb322014-05-09 15:10:23 -0700831 return translate_error(err);
832}
833
Wei Jia00cc9922017-11-23 08:00:34 -0800834EXPORT
835bool AMediaCodecActionCode_isRecoverable(int32_t actionCode) {
836 return (actionCode == ACTION_CODE_RECOVERABLE);
837}
838
839EXPORT
840bool AMediaCodecActionCode_isTransient(int32_t actionCode) {
841 return (actionCode == ACTION_CODE_TRANSIENT);
842}
843
Marco Nelissen050eb322014-05-09 15:10:23 -0700844
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800845EXPORT
846void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
847 cryptoinfo_pattern_t *pattern) {
848 info->pattern.encryptBlocks = pattern->encryptBlocks;
849 info->pattern.skipBlocks = pattern->skipBlocks;
850}
Marco Nelissen050eb322014-05-09 15:10:23 -0700851
Marco Nelissen3425fd52014-05-14 11:12:46 -0700852EXPORT
Marco Nelissen050eb322014-05-09 15:10:23 -0700853AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
854 int numsubsamples,
855 uint8_t key[16],
856 uint8_t iv[16],
Marco Nelissen79e2b622014-05-16 08:07:28 -0700857 cryptoinfo_mode_t mode,
Marco Nelissen050eb322014-05-09 15:10:23 -0700858 size_t *clearbytes,
859 size_t *encryptedbytes) {
860
861 // size needed to store all the crypto data
Marco Nelissend1fd0272018-07-31 15:12:51 -0700862 size_t cryptosize;
863 // = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
864 if (__builtin_mul_overflow(sizeof(size_t) * 2, numsubsamples, &cryptosize) ||
865 __builtin_add_overflow(cryptosize, sizeof(AMediaCodecCryptoInfo), &cryptosize)) {
866 ALOGE("crypto size overflow");
867 return NULL;
868 }
Marco Nelissen050eb322014-05-09 15:10:23 -0700869 AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
870 if (!ret) {
Mark Salyzyn98f28cd2014-06-18 16:32:50 -0700871 ALOGE("couldn't allocate %zu bytes", cryptosize);
Marco Nelissen050eb322014-05-09 15:10:23 -0700872 return NULL;
873 }
874 ret->numsubsamples = numsubsamples;
875 memcpy(ret->key, key, 16);
876 memcpy(ret->iv, iv, 16);
877 ret->mode = mode;
Jeff Tinker18cb1ec2015-12-18 11:55:22 -0800878 ret->pattern.encryptBlocks = 0;
879 ret->pattern.skipBlocks = 0;
Marco Nelissen050eb322014-05-09 15:10:23 -0700880
881 // clearbytes and encryptedbytes point at the actual data, which follows
Marco Nelissen829e0972014-05-13 16:22:19 -0700882 ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
883 ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes
Marco Nelissen050eb322014-05-09 15:10:23 -0700884
Marco Nelissen829e0972014-05-13 16:22:19 -0700885 memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
886 memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));
Marco Nelissen050eb322014-05-09 15:10:23 -0700887
888 return ret;
889}
890
891
Marco Nelissen3425fd52014-05-14 11:12:46 -0700892EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700893media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
Marco Nelissen050eb322014-05-09 15:10:23 -0700894 free(info);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700895 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700896}
897
Marco Nelissen3425fd52014-05-14 11:12:46 -0700898EXPORT
Marco Nelissen050eb322014-05-09 15:10:23 -0700899size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
900 return ci->numsubsamples;
901}
902
Marco Nelissen3425fd52014-05-14 11:12:46 -0700903EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700904media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
905 if (!ci) {
906 return AMEDIA_ERROR_INVALID_OBJECT;
907 }
908 if (!dst) {
909 return AMEDIA_ERROR_INVALID_PARAMETER;
Marco Nelissen050eb322014-05-09 15:10:23 -0700910 }
911 memcpy(dst, ci->key, 16);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700912 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700913}
914
Marco Nelissen3425fd52014-05-14 11:12:46 -0700915EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700916media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
917 if (!ci) {
918 return AMEDIA_ERROR_INVALID_OBJECT;
919 }
920 if (!dst) {
921 return AMEDIA_ERROR_INVALID_PARAMETER;
Marco Nelissen050eb322014-05-09 15:10:23 -0700922 }
923 memcpy(dst, ci->iv, 16);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700924 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700925}
926
Marco Nelissen3425fd52014-05-14 11:12:46 -0700927EXPORT
Marco Nelissen79e2b622014-05-16 08:07:28 -0700928cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
Marco Nelissen050eb322014-05-09 15:10:23 -0700929 if (!ci) {
Marco Nelissen79e2b622014-05-16 08:07:28 -0700930 return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT;
Marco Nelissen050eb322014-05-09 15:10:23 -0700931 }
932 return ci->mode;
933}
934
Marco Nelissen3425fd52014-05-14 11:12:46 -0700935EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700936media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
937 if (!ci) {
938 return AMEDIA_ERROR_INVALID_OBJECT;
939 }
940 if (!dst) {
941 return AMEDIA_ERROR_INVALID_PARAMETER;
Marco Nelissen050eb322014-05-09 15:10:23 -0700942 }
943 memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700944 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700945}
946
Marco Nelissen3425fd52014-05-14 11:12:46 -0700947EXPORT
Marco Nelissene419d7c2014-05-15 14:17:25 -0700948media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
949 if (!ci) {
950 return AMEDIA_ERROR_INVALID_OBJECT;
951 }
952 if (!dst) {
953 return AMEDIA_ERROR_INVALID_PARAMETER;
Marco Nelissen050eb322014-05-09 15:10:23 -0700954 }
955 memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
Marco Nelissene419d7c2014-05-15 14:17:25 -0700956 return AMEDIA_OK;
Marco Nelissen050eb322014-05-09 15:10:23 -0700957}
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700958
Ray Essickef058462021-01-24 14:50:08 -0800959EXPORT const char* AMEDIACODEC_KEY_HDR10_PLUS_INFO = AMEDIAFORMAT_KEY_HDR10_PLUS_INFO;
960EXPORT const char* AMEDIACODEC_KEY_LOW_LATENCY = AMEDIAFORMAT_KEY_LOW_LATENCY;
961EXPORT const char* AMEDIACODEC_KEY_OFFSET_TIME = "time-offset-us";
962EXPORT const char* AMEDIACODEC_KEY_REQUEST_SYNC_FRAME = "request-sync";
963EXPORT const char* AMEDIACODEC_KEY_SUSPEND = "drop-input-frames";
964EXPORT const char* AMEDIACODEC_KEY_SUSPEND_TIME = "drop-start-time-us";
965EXPORT const char* AMEDIACODEC_KEY_VIDEO_BITRATE = "video-bitrate";
966
Marco Nelissen0c3be872014-05-01 10:14:44 -0700967} // extern "C"
968