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     size_t res = mData->mLooper->start(
149             false,      // runOnCallingThread
150             true,       // canCallJava XXX
151             PRIORITY_FOREGROUND);
152     if (res != OK) {
153         ALOGE("Failed to start the looper");
154         AMediaCodec_delete(mData);
155         return NULL;
156     }
157     if (name_is_type) {
158         mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder);
159     } else {
160         mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name);
161     }
162     if (mData->mCodec == NULL) {  // failed to create codec
163         AMediaCodec_delete(mData);
164         return NULL;
165     }
166     mData->mHandler = new CodecHandler(mData);
167     mData->mLooper->registerHandler(mData->mHandler);
168     mData->mGeneration = 1;
169     mData->mRequestedActivityNotification = false;
170     mData->mCallback = NULL;
171 
172     return mData;
173 }
174 
175 EXPORT
AMediaCodec_createCodecByName(const char * name)176 AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
177     return createAMediaCodec(name, false, false);
178 }
179 
180 EXPORT
AMediaCodec_createDecoderByType(const char * mime_type)181 AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
182     return createAMediaCodec(mime_type, true, false);
183 }
184 
185 EXPORT
AMediaCodec_createEncoderByType(const char * name)186 AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
187     return createAMediaCodec(name, true, true);
188 }
189 
190 EXPORT
AMediaCodec_delete(AMediaCodec * mData)191 media_status_t AMediaCodec_delete(AMediaCodec *mData) {
192     if (mData != NULL) {
193         if (mData->mCodec != NULL) {
194             mData->mCodec->release();
195             mData->mCodec.clear();
196         }
197 
198         if (mData->mLooper != NULL) {
199             if (mData->mHandler != NULL) {
200                 mData->mLooper->unregisterHandler(mData->mHandler->id());
201             }
202             mData->mLooper->stop();
203             mData->mLooper.clear();
204         }
205         delete mData;
206     }
207     return AMEDIA_OK;
208 }
209 
210 EXPORT
AMediaCodec_configure(AMediaCodec * mData,const AMediaFormat * format,ANativeWindow * window,AMediaCrypto * crypto,uint32_t flags)211 media_status_t AMediaCodec_configure(
212         AMediaCodec *mData,
213         const AMediaFormat* format,
214         ANativeWindow* window,
215         AMediaCrypto *crypto,
216         uint32_t flags) {
217     sp<AMessage> nativeFormat;
218     AMediaFormat_getFormat(format, &nativeFormat);
219     ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str());
220     sp<Surface> surface = NULL;
221     if (window != NULL) {
222         surface = (Surface*) window;
223     }
224 
225     return translate_error(mData->mCodec->configure(nativeFormat, surface,
226             crypto ? crypto->mCrypto : NULL, flags));
227 }
228 
229 EXPORT
AMediaCodec_start(AMediaCodec * mData)230 media_status_t AMediaCodec_start(AMediaCodec *mData) {
231     status_t ret =  mData->mCodec->start();
232     if (ret != OK) {
233         return translate_error(ret);
234     }
235     mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler);
236     mData->mActivityNotification->setInt32("generation", mData->mGeneration);
237     requestActivityNotification(mData);
238     return AMEDIA_OK;
239 }
240 
241 EXPORT
AMediaCodec_stop(AMediaCodec * mData)242 media_status_t AMediaCodec_stop(AMediaCodec *mData) {
243     media_status_t ret = translate_error(mData->mCodec->stop());
244 
245     sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler);
246     sp<AMessage> response;
247     msg->postAndAwaitResponse(&response);
248     mData->mActivityNotification.clear();
249 
250     return ret;
251 }
252 
253 EXPORT
AMediaCodec_flush(AMediaCodec * mData)254 media_status_t AMediaCodec_flush(AMediaCodec *mData) {
255     return translate_error(mData->mCodec->flush());
256 }
257 
258 EXPORT
AMediaCodec_dequeueInputBuffer(AMediaCodec * mData,int64_t timeoutUs)259 ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
260     size_t idx;
261     status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
262     requestActivityNotification(mData);
263     if (ret == OK) {
264         return idx;
265     }
266     return translate_error(ret);
267 }
268 
269 EXPORT
AMediaCodec_getInputBuffer(AMediaCodec * mData,size_t idx,size_t * out_size)270 uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
271     android::Vector<android::sp<android::ABuffer> > abufs;
272     if (mData->mCodec->getInputBuffers(&abufs) == 0) {
273         size_t n = abufs.size();
274         if (idx >= n) {
275             ALOGE("buffer index %zu out of range", idx);
276             return NULL;
277         }
278         if (out_size != NULL) {
279             *out_size = abufs[idx]->capacity();
280         }
281         return abufs[idx]->data();
282     }
283     ALOGE("couldn't get input buffers");
284     return NULL;
285 }
286 
287 EXPORT
AMediaCodec_getOutputBuffer(AMediaCodec * mData,size_t idx,size_t * out_size)288 uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
289     android::Vector<android::sp<android::ABuffer> > abufs;
290     if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
291         size_t n = abufs.size();
292         if (idx >= n) {
293             ALOGE("buffer index %zu out of range", idx);
294             return NULL;
295         }
296         if (out_size != NULL) {
297             *out_size = abufs[idx]->capacity();
298         }
299         return abufs[idx]->data();
300     }
301     ALOGE("couldn't get output buffers");
302     return NULL;
303 }
304 
305 EXPORT
AMediaCodec_queueInputBuffer(AMediaCodec * mData,size_t idx,off_t offset,size_t size,uint64_t time,uint32_t flags)306 media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData,
307         size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) {
308 
309     AString errorMsg;
310     status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg);
311     return translate_error(ret);
312 }
313 
314 EXPORT
AMediaCodec_dequeueOutputBuffer(AMediaCodec * mData,AMediaCodecBufferInfo * info,int64_t timeoutUs)315 ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
316         AMediaCodecBufferInfo *info, int64_t timeoutUs) {
317     size_t idx;
318     size_t offset;
319     size_t size;
320     uint32_t flags;
321     int64_t presentationTimeUs;
322     status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs,
323             &flags, timeoutUs);
324     requestActivityNotification(mData);
325     switch (ret) {
326         case OK:
327             info->offset = offset;
328             info->size = size;
329             info->flags = flags;
330             info->presentationTimeUs = presentationTimeUs;
331             return idx;
332         case -EAGAIN:
333             return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
334         case android::INFO_FORMAT_CHANGED:
335             return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED;
336         case INFO_OUTPUT_BUFFERS_CHANGED:
337             return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED;
338         default:
339             break;
340     }
341     return translate_error(ret);
342 }
343 
344 EXPORT
AMediaCodec_getOutputFormat(AMediaCodec * mData)345 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
346     sp<AMessage> format;
347     mData->mCodec->getOutputFormat(&format);
348     return AMediaFormat_fromMsg(&format);
349 }
350 
351 EXPORT
AMediaCodec_releaseOutputBuffer(AMediaCodec * mData,size_t idx,bool render)352 media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
353     if (render) {
354         return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
355     } else {
356         return translate_error(mData->mCodec->releaseOutputBuffer(idx));
357     }
358 }
359 
360 EXPORT
AMediaCodec_releaseOutputBufferAtTime(AMediaCodec * mData,size_t idx,int64_t timestampNs)361 media_status_t AMediaCodec_releaseOutputBufferAtTime(
362         AMediaCodec *mData, size_t idx, int64_t timestampNs) {
363     ALOGV("render @ %" PRId64, timestampNs);
364     return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
365 }
366 
367 EXPORT
AMediaCodec_setOutputSurface(AMediaCodec * mData,ANativeWindow * window)368 media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) {
369     sp<Surface> surface = NULL;
370     if (window != NULL) {
371         surface = (Surface*) window;
372     }
373     return translate_error(mData->mCodec->setSurface(surface));
374 }
375 
376 //EXPORT
AMediaCodec_setNotificationCallback(AMediaCodec * mData,OnCodecEvent callback,void * userdata)377 media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
378         void *userdata) {
379     mData->mCallback = callback;
380     mData->mCallbackUserData = userdata;
381     return AMEDIA_OK;
382 }
383 
384 typedef struct AMediaCodecCryptoInfo {
385         int numsubsamples;
386         uint8_t key[16];
387         uint8_t iv[16];
388         cryptoinfo_mode_t mode;
389         cryptoinfo_pattern_t pattern;
390         size_t *clearbytes;
391         size_t *encryptedbytes;
392 } AMediaCodecCryptoInfo;
393 
394 EXPORT
AMediaCodec_queueSecureInputBuffer(AMediaCodec * codec,size_t idx,off_t offset,AMediaCodecCryptoInfo * crypto,uint64_t time,uint32_t flags)395 media_status_t AMediaCodec_queueSecureInputBuffer(
396         AMediaCodec* codec,
397         size_t idx,
398         off_t offset,
399         AMediaCodecCryptoInfo* crypto,
400         uint64_t time,
401         uint32_t flags) {
402 
403     CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples];
404     for (int i = 0; i < crypto->numsubsamples; i++) {
405         subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i];
406         subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
407     }
408 
409     CryptoPlugin::Pattern pattern;
410     pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
411     pattern.mSkipBlocks = crypto->pattern.skipBlocks;
412 
413     AString errormsg;
414     status_t err  = codec->mCodec->queueSecureInputBuffer(idx,
415             offset,
416             subSamples,
417             crypto->numsubsamples,
418             crypto->key,
419             crypto->iv,
420             (CryptoPlugin::Mode)crypto->mode,
421             pattern,
422             time,
423             flags,
424             &errormsg);
425     if (err != 0) {
426         ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
427     }
428     delete [] subSamples;
429     return translate_error(err);
430 }
431 
432 
433 EXPORT
AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo * info,cryptoinfo_pattern_t * pattern)434 void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
435         cryptoinfo_pattern_t *pattern) {
436     info->pattern.encryptBlocks = pattern->encryptBlocks;
437     info->pattern.skipBlocks = pattern->skipBlocks;
438 }
439 
440 EXPORT
AMediaCodecCryptoInfo_new(int numsubsamples,uint8_t key[16],uint8_t iv[16],cryptoinfo_mode_t mode,size_t * clearbytes,size_t * encryptedbytes)441 AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
442         int numsubsamples,
443         uint8_t key[16],
444         uint8_t iv[16],
445         cryptoinfo_mode_t mode,
446         size_t *clearbytes,
447         size_t *encryptedbytes) {
448 
449     // size needed to store all the crypto data
450     size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
451     AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
452     if (!ret) {
453         ALOGE("couldn't allocate %zu bytes", cryptosize);
454         return NULL;
455     }
456     ret->numsubsamples = numsubsamples;
457     memcpy(ret->key, key, 16);
458     memcpy(ret->iv, iv, 16);
459     ret->mode = mode;
460     ret->pattern.encryptBlocks = 0;
461     ret->pattern.skipBlocks = 0;
462 
463     // clearbytes and encryptedbytes point at the actual data, which follows
464     ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
465     ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes
466 
467     memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
468     memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));
469 
470     return ret;
471 }
472 
473 
474 EXPORT
AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo * info)475 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
476     free(info);
477     return AMEDIA_OK;
478 }
479 
480 EXPORT
AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo * ci)481 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
482     return ci->numsubsamples;
483 }
484 
485 EXPORT
AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo * ci,uint8_t * dst)486 media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
487     if (!ci) {
488         return AMEDIA_ERROR_INVALID_OBJECT;
489     }
490     if (!dst) {
491         return AMEDIA_ERROR_INVALID_PARAMETER;
492     }
493     memcpy(dst, ci->key, 16);
494     return AMEDIA_OK;
495 }
496 
497 EXPORT
AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo * ci,uint8_t * dst)498 media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
499     if (!ci) {
500         return AMEDIA_ERROR_INVALID_OBJECT;
501     }
502     if (!dst) {
503         return AMEDIA_ERROR_INVALID_PARAMETER;
504     }
505     memcpy(dst, ci->iv, 16);
506     return AMEDIA_OK;
507 }
508 
509 EXPORT
AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo * ci)510 cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
511     if (!ci) {
512         return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT;
513     }
514     return ci->mode;
515 }
516 
517 EXPORT
AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo * ci,size_t * dst)518 media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
519     if (!ci) {
520         return AMEDIA_ERROR_INVALID_OBJECT;
521     }
522     if (!dst) {
523         return AMEDIA_ERROR_INVALID_PARAMETER;
524     }
525     memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
526     return AMEDIA_OK;
527 }
528 
529 EXPORT
AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo * ci,size_t * dst)530 media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
531     if (!ci) {
532         return AMEDIA_ERROR_INVALID_OBJECT;
533     }
534     if (!dst) {
535         return AMEDIA_ERROR_INVALID_PARAMETER;
536     }
537     memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
538     return AMEDIA_OK;
539 }
540 
541 } // extern "C"
542 
543