Home | History | Annotate | Download | only in ndk
      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 
     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 
     79 CodecHandler::CodecHandler(AMediaCodec *codec) {
     80     mCodec = codec;
     81 }
     82 
     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 
    138 static void requestActivityNotification(AMediaCodec *codec) {
    139     (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post();
    140 }
    141 
    142 extern "C" {
    143 
    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
    171 AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
    172     return createAMediaCodec(name, false, false);
    173 }
    174 
    175 EXPORT
    176 AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
    177     return createAMediaCodec(mime_type, true, false);
    178 }
    179 
    180 EXPORT
    181 AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
    182     return createAMediaCodec(name, true, true);
    183 }
    184 
    185 EXPORT
    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
    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
    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
    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
    249 media_status_t AMediaCodec_flush(AMediaCodec *mData) {
    250     return translate_error(mData->mCodec->flush());
    251 }
    252 
    253 EXPORT
    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
    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
    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
    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
    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
    340 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
    341     sp<AMessage> format;
    342     mData->mCodec->getOutputFormat(&format);
    343     return AMediaFormat_fromMsg(&format);
    344 }
    345 
    346 EXPORT
    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
    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
    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
    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
    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
    447 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
    448     free(info);
    449     return AMEDIA_OK;
    450 }
    451 
    452 EXPORT
    453 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
    454     return ci->numsubsamples;
    455 }
    456 
    457 EXPORT
    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
    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
    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
    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
    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