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