1 /*
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 #include <inttypes.h>
18 
19 //#define LOG_NDEBUG 0
20 #define LOG_TAG "NdkMediaCodec"
21 
22 #include "NdkMediaCodec.h"
23 #include "NdkMediaError.h"
24 #include "NdkMediaCryptoPriv.h"
25 #include "NdkMediaFormatPriv.h"
26 
27 #include <utils/Log.h>
28 #include <utils/StrongPointer.h>
29 #include <gui/Surface.h>
30 
31 #include <media/stagefright/foundation/ALooper.h>
32 #include <media/stagefright/foundation/AMessage.h>
33 #include <media/stagefright/foundation/ABuffer.h>
34 
35 #include <media/stagefright/MediaCodec.h>
36 #include <media/stagefright/MediaErrors.h>
37 
38 using namespace android;
39 
40 
translate_error(status_t err)41 static media_status_t translate_error(status_t err) {
42     if (err == OK) {
43         return AMEDIA_OK;
44     } else if (err == -EAGAIN) {
45         return (media_status_t) AMEDIACODEC_INFO_TRY_AGAIN_LATER;
46     }
47     ALOGE("sf error code: %d", err);
48     return AMEDIA_ERROR_UNKNOWN;
49 }
50 
51 enum {
52     kWhatActivityNotify,
53     kWhatRequestActivityNotifications,
54     kWhatStopActivityNotifications,
55 };
56 
57 
58 class CodecHandler: public AHandler {
59 private:
60     AMediaCodec* mCodec;
61 public:
62     CodecHandler(AMediaCodec *codec);
63     virtual void onMessageReceived(const sp<AMessage> &msg);
64 };
65 
66 typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
67 
68 struct AMediaCodec {
69     sp<android::MediaCodec> mCodec;
70     sp<ALooper> mLooper;
71     sp<CodecHandler> mHandler;
72     sp<AMessage> mActivityNotification;
73     int32_t mGeneration;
74     bool mRequestedActivityNotification;
75     OnCodecEvent mCallback;
76     void *mCallbackUserData;
77 };
78 
CodecHandler(AMediaCodec * codec)79 CodecHandler::CodecHandler(AMediaCodec *codec) {
80     mCodec = codec;
81 }
82 
onMessageReceived(const sp<AMessage> & msg)83 void CodecHandler::onMessageReceived(const sp<AMessage> &msg) {
84 
85     switch (msg->what()) {
86         case kWhatRequestActivityNotifications:
87         {
88             if (mCodec->mRequestedActivityNotification) {
89                 break;
90             }
91 
92             mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification);
93             mCodec->mRequestedActivityNotification = true;
94             break;
95         }
96 
97         case kWhatActivityNotify:
98         {
99             {
100                 int32_t generation;
101                 msg->findInt32("generation", &generation);
102 
103                 if (generation != mCodec->mGeneration) {
104                     // stale
105                     break;
106                 }
107 
108                 mCodec->mRequestedActivityNotification = false;
109             }
110 
111             if (mCodec->mCallback) {
112                 mCodec->mCallback(mCodec, mCodec->mCallbackUserData);
113             }
114             break;
115         }
116 
117         case kWhatStopActivityNotifications:
118         {
119             sp<AReplyToken> replyID;
120             msg->senderAwaitsResponse(&replyID);
121 
122             mCodec->mGeneration++;
123             mCodec->mRequestedActivityNotification = false;
124 
125             sp<AMessage> response = new AMessage;
126             response->postReply(replyID);
127             break;
128         }
129 
130         default:
131             ALOGE("shouldn't be here");
132             break;
133     }
134 
135 }
136 
137 
requestActivityNotification(AMediaCodec * codec)138 static void requestActivityNotification(AMediaCodec *codec) {
139     (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post();
140 }
141 
142 extern "C" {
143 
createAMediaCodec(const char * name,bool name_is_type,bool encoder)144 static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool encoder) {
145     AMediaCodec *mData = new AMediaCodec();
146     mData->mLooper = new ALooper;
147     mData->mLooper->setName("NDK MediaCodec_looper");
148     status_t ret = mData->mLooper->start(
149             false,      // runOnCallingThread
150             true,       // canCallJava XXX
151             PRIORITY_FOREGROUND);
152     if (name_is_type) {
153         mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder);
154     } else {
155         mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name);
156     }
157     if (mData->mCodec == NULL) {  // failed to create codec
158         AMediaCodec_delete(mData);
159         return NULL;
160     }
161     mData->mHandler = new CodecHandler(mData);
162     mData->mLooper->registerHandler(mData->mHandler);
163     mData->mGeneration = 1;
164     mData->mRequestedActivityNotification = false;
165     mData->mCallback = NULL;
166 
167     return mData;
168 }
169 
170 EXPORT
AMediaCodec_createCodecByName(const char * name)171 AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
172     return createAMediaCodec(name, false, false);
173 }
174 
175 EXPORT
AMediaCodec_createDecoderByType(const char * mime_type)176 AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
177     return createAMediaCodec(mime_type, true, false);
178 }
179 
180 EXPORT
AMediaCodec_createEncoderByType(const char * name)181 AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
182     return createAMediaCodec(name, true, true);
183 }
184 
185 EXPORT
AMediaCodec_delete(AMediaCodec * mData)186 media_status_t AMediaCodec_delete(AMediaCodec *mData) {
187     if (mData != NULL) {
188         if (mData->mCodec != NULL) {
189             mData->mCodec->release();
190             mData->mCodec.clear();
191         }
192 
193         if (mData->mLooper != NULL) {
194             if (mData->mHandler != NULL) {
195                 mData->mLooper->unregisterHandler(mData->mHandler->id());
196             }
197             mData->mLooper->stop();
198             mData->mLooper.clear();
199         }
200         delete mData;
201     }
202     return AMEDIA_OK;
203 }
204 
205 EXPORT
AMediaCodec_configure(AMediaCodec * mData,const AMediaFormat * format,ANativeWindow * window,AMediaCrypto * crypto,uint32_t flags)206 media_status_t AMediaCodec_configure(
207         AMediaCodec *mData,
208         const AMediaFormat* format,
209         ANativeWindow* window,
210         AMediaCrypto *crypto,
211         uint32_t flags) {
212     sp<AMessage> nativeFormat;
213     AMediaFormat_getFormat(format, &nativeFormat);
214     ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str());
215     sp<Surface> surface = NULL;
216     if (window != NULL) {
217         surface = (Surface*) window;
218     }
219 
220     return translate_error(mData->mCodec->configure(nativeFormat, surface,
221             crypto ? crypto->mCrypto : NULL, flags));
222 }
223 
224 EXPORT
AMediaCodec_start(AMediaCodec * mData)225 media_status_t AMediaCodec_start(AMediaCodec *mData) {
226     status_t ret =  mData->mCodec->start();
227     if (ret != OK) {
228         return translate_error(ret);
229     }
230     mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler);
231     mData->mActivityNotification->setInt32("generation", mData->mGeneration);
232     requestActivityNotification(mData);
233     return AMEDIA_OK;
234 }
235 
236 EXPORT
AMediaCodec_stop(AMediaCodec * mData)237 media_status_t AMediaCodec_stop(AMediaCodec *mData) {
238     media_status_t ret = translate_error(mData->mCodec->stop());
239 
240     sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler);
241     sp<AMessage> response;
242     msg->postAndAwaitResponse(&response);
243     mData->mActivityNotification.clear();
244 
245     return ret;
246 }
247 
248 EXPORT
AMediaCodec_flush(AMediaCodec * mData)249 media_status_t AMediaCodec_flush(AMediaCodec *mData) {
250     return translate_error(mData->mCodec->flush());
251 }
252 
253 EXPORT
AMediaCodec_dequeueInputBuffer(AMediaCodec * mData,int64_t timeoutUs)254 ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
255     size_t idx;
256     status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
257     requestActivityNotification(mData);
258     if (ret == OK) {
259         return idx;
260     }
261     return translate_error(ret);
262 }
263 
264 EXPORT
AMediaCodec_getInputBuffer(AMediaCodec * mData,size_t idx,size_t * out_size)265 uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
266     android::Vector<android::sp<android::ABuffer> > abufs;
267     if (mData->mCodec->getInputBuffers(&abufs) == 0) {
268         size_t n = abufs.size();
269         if (idx >= n) {
270             ALOGE("buffer index %zu out of range", idx);
271             return NULL;
272         }
273         if (out_size != NULL) {
274             *out_size = abufs[idx]->capacity();
275         }
276         return abufs[idx]->data();
277     }
278     ALOGE("couldn't get input buffers");
279     return NULL;
280 }
281 
282 EXPORT
AMediaCodec_getOutputBuffer(AMediaCodec * mData,size_t idx,size_t * out_size)283 uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
284     android::Vector<android::sp<android::ABuffer> > abufs;
285     if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
286         size_t n = abufs.size();
287         if (idx >= n) {
288             ALOGE("buffer index %zu out of range", idx);
289             return NULL;
290         }
291         if (out_size != NULL) {
292             *out_size = abufs[idx]->capacity();
293         }
294         return abufs[idx]->data();
295     }
296     ALOGE("couldn't get output buffers");
297     return NULL;
298 }
299 
300 EXPORT
AMediaCodec_queueInputBuffer(AMediaCodec * mData,size_t idx,off_t offset,size_t size,uint64_t time,uint32_t flags)301 media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData,
302         size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) {
303 
304     AString errorMsg;
305     status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg);
306     return translate_error(ret);
307 }
308 
309 EXPORT
AMediaCodec_dequeueOutputBuffer(AMediaCodec * mData,AMediaCodecBufferInfo * info,int64_t timeoutUs)310 ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
311         AMediaCodecBufferInfo *info, int64_t timeoutUs) {
312     size_t idx;
313     size_t offset;
314     size_t size;
315     uint32_t flags;
316     int64_t presentationTimeUs;
317     status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs,
318             &flags, timeoutUs);
319     requestActivityNotification(mData);
320     switch (ret) {
321         case OK:
322             info->offset = offset;
323             info->size = size;
324             info->flags = flags;
325             info->presentationTimeUs = presentationTimeUs;
326             return idx;
327         case -EAGAIN:
328             return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
329         case android::INFO_FORMAT_CHANGED:
330             return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED;
331         case INFO_OUTPUT_BUFFERS_CHANGED:
332             return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED;
333         default:
334             break;
335     }
336     return translate_error(ret);
337 }
338 
339 EXPORT
AMediaCodec_getOutputFormat(AMediaCodec * mData)340 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
341     sp<AMessage> format;
342     mData->mCodec->getOutputFormat(&format);
343     return AMediaFormat_fromMsg(&format);
344 }
345 
346 EXPORT
AMediaCodec_releaseOutputBuffer(AMediaCodec * mData,size_t idx,bool render)347 media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
348     if (render) {
349         return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
350     } else {
351         return translate_error(mData->mCodec->releaseOutputBuffer(idx));
352     }
353 }
354 
355 EXPORT
AMediaCodec_releaseOutputBufferAtTime(AMediaCodec * mData,size_t idx,int64_t timestampNs)356 media_status_t AMediaCodec_releaseOutputBufferAtTime(
357         AMediaCodec *mData, size_t idx, int64_t timestampNs) {
358     ALOGV("render @ %" PRId64, timestampNs);
359     return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
360 }
361 
362 //EXPORT
AMediaCodec_setNotificationCallback(AMediaCodec * mData,OnCodecEvent callback,void * userdata)363 media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
364         void *userdata) {
365     mData->mCallback = callback;
366     mData->mCallbackUserData = userdata;
367     return AMEDIA_OK;
368 }
369 
370 typedef struct AMediaCodecCryptoInfo {
371         int numsubsamples;
372         uint8_t key[16];
373         uint8_t iv[16];
374         cryptoinfo_mode_t mode;
375         size_t *clearbytes;
376         size_t *encryptedbytes;
377 } AMediaCodecCryptoInfo;
378 
379 EXPORT
AMediaCodec_queueSecureInputBuffer(AMediaCodec * codec,size_t idx,off_t offset,AMediaCodecCryptoInfo * crypto,uint64_t time,uint32_t flags)380 media_status_t AMediaCodec_queueSecureInputBuffer(
381         AMediaCodec* codec,
382         size_t idx,
383         off_t offset,
384         AMediaCodecCryptoInfo* crypto,
385         uint64_t time,
386         uint32_t flags) {
387 
388     CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples];
389     for (int i = 0; i < crypto->numsubsamples; i++) {
390         subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i];
391         subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
392     }
393 
394     AString errormsg;
395     status_t err  = codec->mCodec->queueSecureInputBuffer(idx,
396             offset,
397             subSamples,
398             crypto->numsubsamples,
399             crypto->key,
400             crypto->iv,
401             (CryptoPlugin::Mode) crypto->mode,
402             time,
403             flags,
404             &errormsg);
405     if (err != 0) {
406         ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
407     }
408     delete [] subSamples;
409     return translate_error(err);
410 }
411 
412 
413 
414 EXPORT
AMediaCodecCryptoInfo_new(int numsubsamples,uint8_t key[16],uint8_t iv[16],cryptoinfo_mode_t mode,size_t * clearbytes,size_t * encryptedbytes)415 AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
416         int numsubsamples,
417         uint8_t key[16],
418         uint8_t iv[16],
419         cryptoinfo_mode_t mode,
420         size_t *clearbytes,
421         size_t *encryptedbytes) {
422 
423     // size needed to store all the crypto data
424     size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
425     AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
426     if (!ret) {
427         ALOGE("couldn't allocate %zu bytes", cryptosize);
428         return NULL;
429     }
430     ret->numsubsamples = numsubsamples;
431     memcpy(ret->key, key, 16);
432     memcpy(ret->iv, iv, 16);
433     ret->mode = mode;
434 
435     // clearbytes and encryptedbytes point at the actual data, which follows
436     ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
437     ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes
438 
439     memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
440     memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));
441 
442     return ret;
443 }
444 
445 
446 EXPORT
AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo * info)447 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
448     free(info);
449     return AMEDIA_OK;
450 }
451 
452 EXPORT
AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo * ci)453 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
454     return ci->numsubsamples;
455 }
456 
457 EXPORT
AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo * ci,uint8_t * dst)458 media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
459     if (!ci) {
460         return AMEDIA_ERROR_INVALID_OBJECT;
461     }
462     if (!dst) {
463         return AMEDIA_ERROR_INVALID_PARAMETER;
464     }
465     memcpy(dst, ci->key, 16);
466     return AMEDIA_OK;
467 }
468 
469 EXPORT
AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo * ci,uint8_t * dst)470 media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
471     if (!ci) {
472         return AMEDIA_ERROR_INVALID_OBJECT;
473     }
474     if (!dst) {
475         return AMEDIA_ERROR_INVALID_PARAMETER;
476     }
477     memcpy(dst, ci->iv, 16);
478     return AMEDIA_OK;
479 }
480 
481 EXPORT
AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo * ci)482 cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
483     if (!ci) {
484         return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT;
485     }
486     return ci->mode;
487 }
488 
489 EXPORT
AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo * ci,size_t * dst)490 media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
491     if (!ci) {
492         return AMEDIA_ERROR_INVALID_OBJECT;
493     }
494     if (!dst) {
495         return AMEDIA_ERROR_INVALID_PARAMETER;
496     }
497     memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
498     return AMEDIA_OK;
499 }
500 
501 EXPORT
AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo * ci,size_t * dst)502 media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
503     if (!ci) {
504         return AMEDIA_ERROR_INVALID_OBJECT;
505     }
506     if (!dst) {
507         return AMEDIA_ERROR_INVALID_PARAMETER;
508     }
509     memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
510     return AMEDIA_OK;
511 }
512 
513 } // extern "C"
514 
515