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     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
    176 AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
    177     return createAMediaCodec(name, false, false);
    178 }
    179 
    180 EXPORT
    181 AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
    182     return createAMediaCodec(mime_type, true, false);
    183 }
    184 
    185 EXPORT
    186 AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
    187     return createAMediaCodec(name, true, true);
    188 }
    189 
    190 EXPORT
    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
    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
    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
    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
    254 media_status_t AMediaCodec_flush(AMediaCodec *mData) {
    255     return translate_error(mData->mCodec->flush());
    256 }
    257 
    258 EXPORT
    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
    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
    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
    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
    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
    345 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
    346     sp<AMessage> format;
    347     mData->mCodec->getOutputFormat(&format);
    348     return AMediaFormat_fromMsg(&format);
    349 }
    350 
    351 EXPORT
    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
    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
    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
    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
    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
    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
    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
    475 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
    476     free(info);
    477     return AMEDIA_OK;
    478 }
    479 
    480 EXPORT
    481 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
    482     return ci->numsubsamples;
    483 }
    484 
    485 EXPORT
    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
    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
    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
    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
    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