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