blob: 1f62fa28aa16bb6311d358093899fab71e6acacc [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
17#define LOG_NDEBUG 0
18#define LOG_TAG "NdkMediaCodec"
19
20#include "NdkMediaCodec.h"
Marco Nelissen050eb322014-05-09 15:10:23 -070021#include "NdkMediaError.h"
22#include "NdkMediaCryptoPriv.h"
Marco Nelissen0c3be872014-05-01 10:14:44 -070023#include "NdkMediaFormatPriv.h"
24
25#include <utils/Log.h>
26#include <utils/StrongPointer.h>
27#include <gui/Surface.h>
28
Marco Nelissen0c3be872014-05-01 10:14:44 -070029#include <media/stagefright/foundation/ALooper.h>
30#include <media/stagefright/foundation/AMessage.h>
31#include <media/stagefright/foundation/ABuffer.h>
32
33#include <media/stagefright/MediaCodec.h>
34#include <media/stagefright/MediaErrors.h>
35
36using namespace android;
37
38
39static int translate_error(status_t err) {
40 if (err == OK) {
41 return OK;
42 } else if (err == -EAGAIN) {
43 return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
44 }
45 ALOGE("sf error code: %d", err);
Marco Nelissen050eb322014-05-09 15:10:23 -070046 return AMEDIAERROR_GENERIC;
Marco Nelissen0c3be872014-05-01 10:14:44 -070047}
48
Marco Nelissencdb42cd2014-05-08 14:46:05 -070049enum {
50 kWhatActivityNotify,
51 kWhatRequestActivityNotifications,
52 kWhatStopActivityNotifications,
Marco Nelissen0c3be872014-05-01 10:14:44 -070053};
54
Marco Nelissen0c3be872014-05-01 10:14:44 -070055
Marco Nelissencdb42cd2014-05-08 14:46:05 -070056class CodecHandler: public AHandler {
57private:
58 AMediaCodec* mCodec;
59public:
60 CodecHandler(AMediaCodec *codec);
61 virtual void onMessageReceived(const sp<AMessage> &msg);
62};
Marco Nelissen0c3be872014-05-01 10:14:44 -070063
64struct AMediaCodec {
65 sp<android::MediaCodec> mCodec;
66 sp<ALooper> mLooper;
67 sp<CodecHandler> mHandler;
Marco Nelissencdb42cd2014-05-08 14:46:05 -070068 sp<AMessage> mActivityNotification;
69 int32_t mGeneration;
70 bool mRequestedActivityNotification;
71 OnCodecEvent mCallback;
72 void *mCallbackUserData;
Marco Nelissen0c3be872014-05-01 10:14:44 -070073};
74
Marco Nelissencdb42cd2014-05-08 14:46:05 -070075CodecHandler::CodecHandler(AMediaCodec *codec) {
76 mCodec = codec;
77}
78
79void CodecHandler::onMessageReceived(const sp<AMessage> &msg) {
80
81 switch (msg->what()) {
82 case kWhatRequestActivityNotifications:
83 {
84 if (mCodec->mRequestedActivityNotification) {
85 break;
86 }
87
88 mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification);
89 mCodec->mRequestedActivityNotification = true;
90 break;
91 }
92
93 case kWhatActivityNotify:
94 {
95 {
96 int32_t generation;
97 msg->findInt32("generation", &generation);
98
99 if (generation != mCodec->mGeneration) {
100 // stale
101 break;
102 }
103
104 mCodec->mRequestedActivityNotification = false;
105 }
106
107 if (mCodec->mCallback) {
108 mCodec->mCallback(mCodec, mCodec->mCallbackUserData);
109 }
110 break;
111 }
112
113 case kWhatStopActivityNotifications:
114 {
115 uint32_t replyID;
116 msg->senderAwaitsResponse(&replyID);
117
118 mCodec->mGeneration++;
119 mCodec->mRequestedActivityNotification = false;
120
121 sp<AMessage> response = new AMessage;
122 response->postReply(replyID);
123 break;
124 }
125
126 default:
127 ALOGE("shouldn't be here");
128 break;
129 }
130
131}
132
133
134static void requestActivityNotification(AMediaCodec *codec) {
135 (new AMessage(kWhatRequestActivityNotifications, codec->mHandler->id()))->post();
136}
137
Marco Nelissen0c3be872014-05-01 10:14:44 -0700138extern "C" {
139
140static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool encoder) {
141 AMediaCodec *mData = new AMediaCodec();
142 mData->mLooper = new ALooper;
143 mData->mLooper->setName("NDK MediaCodec_looper");
144 status_t ret = mData->mLooper->start(
145 false, // runOnCallingThread
146 true, // canCallJava XXX
147 PRIORITY_FOREGROUND);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700148 if (name_is_type) {
149 mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder);
150 } else {
151 mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name);
152 }
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700153 mData->mHandler = new CodecHandler(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700154 mData->mLooper->registerHandler(mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700155 mData->mGeneration = 1;
156 mData->mRequestedActivityNotification = false;
157 mData->mCallback = NULL;
158
Marco Nelissen0c3be872014-05-01 10:14:44 -0700159 return mData;
160}
161
162
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700163AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700164 return createAMediaCodec(name, false, false);
165}
166
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700167AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700168 return createAMediaCodec(mime_type, true, false);
169}
170
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700171AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
172 return createAMediaCodec(name, true, true);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700173}
174
175int AMediaCodec_delete(AMediaCodec *mData) {
176 if (mData->mCodec != NULL) {
177 mData->mCodec->release();
178 mData->mCodec.clear();
179 }
180
181 if (mData->mLooper != NULL) {
182 mData->mLooper->unregisterHandler(mData->mHandler->id());
183 mData->mLooper->stop();
184 mData->mLooper.clear();
185 }
186 delete mData;
187 return OK;
188}
189
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700190int AMediaCodec_configure(
Marco Nelissen050eb322014-05-09 15:10:23 -0700191 AMediaCodec *mData,
192 const AMediaFormat* format,
193 ANativeWindow* window,
194 AMediaCrypto *crypto,
195 uint32_t flags) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700196 sp<AMessage> nativeFormat;
197 AMediaFormat_getFormat(format, &nativeFormat);
198 ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str());
199 sp<Surface> surface = NULL;
200 if (window != NULL) {
201 surface = (Surface*) window;
202 }
203
Marco Nelissen050eb322014-05-09 15:10:23 -0700204 return translate_error(mData->mCodec->configure(nativeFormat, surface,
205 crypto ? crypto->mCrypto : NULL, flags));
Marco Nelissen0c3be872014-05-01 10:14:44 -0700206}
207
208int AMediaCodec_start(AMediaCodec *mData) {
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700209 status_t ret = mData->mCodec->start();
210 if (ret != OK) {
211 return translate_error(ret);
212 }
213 mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler->id());
214 mData->mActivityNotification->setInt32("generation", mData->mGeneration);
215 requestActivityNotification(mData);
216 return OK;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700217}
218
219int AMediaCodec_stop(AMediaCodec *mData) {
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700220 int ret = translate_error(mData->mCodec->stop());
221
222 sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler->id());
223 sp<AMessage> response;
224 msg->postAndAwaitResponse(&response);
225 mData->mActivityNotification.clear();
226
227 return ret;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700228}
229
230int AMediaCodec_flush(AMediaCodec *mData) {
231 return translate_error(mData->mCodec->flush());
232}
233
234ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
235 size_t idx;
236 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700237 requestActivityNotification(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700238 if (ret == OK) {
239 return idx;
240 }
241 return translate_error(ret);
242}
243
244uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
245 android::Vector<android::sp<android::ABuffer> > abufs;
246 if (mData->mCodec->getInputBuffers(&abufs) == 0) {
247 size_t n = abufs.size();
248 if (idx >= n) {
249 ALOGE("buffer index %d out of range", idx);
250 return NULL;
251 }
252 if (out_size != NULL) {
253 *out_size = abufs[idx]->capacity();
254 }
255 return abufs[idx]->data();
256 }
257 ALOGE("couldn't get input buffers");
258 return NULL;
259}
260
261uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
262 android::Vector<android::sp<android::ABuffer> > abufs;
263 if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
264 size_t n = abufs.size();
265 if (idx >= n) {
266 ALOGE("buffer index %d out of range", idx);
267 return NULL;
268 }
269 if (out_size != NULL) {
270 *out_size = abufs[idx]->capacity();
271 }
272 return abufs[idx]->data();
273 }
274 ALOGE("couldn't get output buffers");
275 return NULL;
276}
277
278int AMediaCodec_queueInputBuffer(AMediaCodec *mData,
279 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) {
280
281 AString errorMsg;
282 status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg);
283 return translate_error(ret);
284}
285
286ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
287 AMediaCodecBufferInfo *info, int64_t timeoutUs) {
288 size_t idx;
289 size_t offset;
290 size_t size;
291 uint32_t flags;
292 int64_t presentationTimeUs;
293 status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs,
294 &flags, timeoutUs);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700295 requestActivityNotification(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700296 switch (ret) {
297 case OK:
298 info->offset = offset;
299 info->size = size;
300 info->flags = flags;
301 info->presentationTimeUs = presentationTimeUs;
302 return idx;
303 case -EAGAIN:
304 return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
305 case android::INFO_FORMAT_CHANGED:
306 return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED;
307 case INFO_OUTPUT_BUFFERS_CHANGED:
308 return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED;
309 default:
310 break;
311 }
312 return translate_error(ret);
313}
314
315AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
316 sp<AMessage> format;
317 mData->mCodec->getOutputFormat(&format);
318 return AMediaFormat_fromMsg(&format);
319}
320
321int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
322 if (render) {
323 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
324 } else {
325 return translate_error(mData->mCodec->releaseOutputBuffer(idx));
326 }
327}
328
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700329int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) {
330 mData->mCallback = callback;
331 mData->mCallbackUserData = userdata;
332 return OK;
333}
334
Marco Nelissen050eb322014-05-09 15:10:23 -0700335typedef struct AMediaCodecCryptoInfo {
336 int numsubsamples;
337 uint8_t key[16];
338 uint8_t iv[16];
339 uint32_t mode;
340 size_t *clearbytes;
341 size_t *encryptedbytes;
342} AMediaCodecCryptoInfo;
343
344int AMediaCodec_queueSecureInputBuffer(
345 AMediaCodec* codec,
346 size_t idx,
347 off_t offset,
348 AMediaCodecCryptoInfo* crypto,
349 uint64_t time,
350 uint32_t flags) {
351
352 CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples];
353 for (int i = 0; i < crypto->numsubsamples; i++) {
354 subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i];
355 subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
356 }
357
358 AString errormsg;
359 status_t err = codec->mCodec->queueSecureInputBuffer(idx,
360 offset,
361 subSamples,
362 crypto->numsubsamples,
363 crypto->key,
364 crypto->iv,
365 (CryptoPlugin::Mode) crypto->mode,
366 time,
367 flags,
368 &errormsg);
369 if (err != 0) {
370 ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
371 }
372 delete subSamples;
373 return translate_error(err);
374}
375
376
377
378AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
379 int numsubsamples,
380 uint8_t key[16],
381 uint8_t iv[16],
382 uint32_t mode,
383 size_t *clearbytes,
384 size_t *encryptedbytes) {
385
386 // size needed to store all the crypto data
387 size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
388 AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
389 if (!ret) {
390 ALOGE("couldn't allocate %d bytes", cryptosize);
391 return NULL;
392 }
393 ret->numsubsamples = numsubsamples;
394 memcpy(ret->key, key, 16);
395 memcpy(ret->iv, iv, 16);
396 ret->mode = mode;
397
398 // clearbytes and encryptedbytes point at the actual data, which follows
399 ret->clearbytes = (size_t*) ((&ret->encryptedbytes) + sizeof(ret->encryptedbytes));
400 ret->encryptedbytes = (size_t*) (ret->clearbytes + (sizeof(size_t) * numsubsamples));
401
402 size_t *dst = ret->clearbytes;
403 memcpy(dst, clearbytes, numsubsamples * sizeof(size_t));
404 dst += numsubsamples * sizeof(size_t);
405 memcpy(dst, encryptedbytes, numsubsamples * sizeof(size_t));
406
407 return ret;
408}
409
410
411int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
412 free(info);
413 return OK;
414}
415
416size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
417 return ci->numsubsamples;
418}
419
420int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
421 if (!dst || !ci) {
422 return AMEDIAERROR_UNSUPPORTED;
423 }
424 memcpy(dst, ci->key, 16);
425 return OK;
426}
427
428int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
429 if (!dst || !ci) {
430 return AMEDIAERROR_UNSUPPORTED;
431 }
432 memcpy(dst, ci->iv, 16);
433 return OK;
434}
435
436uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
437 if (!ci) {
438 return AMEDIAERROR_UNSUPPORTED;
439 }
440 return ci->mode;
441}
442
443int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
444 if (!dst || !ci) {
445 return AMEDIAERROR_UNSUPPORTED;
446 }
447 memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
448 return OK;
449}
450
451int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
452 if (!dst || !ci) {
453 return AMEDIAERROR_UNSUPPORTED;
454 }
455 memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
456 return OK;
457}
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700458
Marco Nelissen0c3be872014-05-01 10:14:44 -0700459} // extern "C"
460