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 <media/NdkMediaCodec.h> 23 #include <media/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 34 #include <media/stagefright/PersistentSurface.h> 35 #include <media/stagefright/MediaCodec.h> 36 #include <media/stagefright/MediaErrors.h> 37 #include <media/MediaCodecBuffer.h> 38 #include <android/native_window.h> 39 40 using namespace android; 41 42 43 static media_status_t translate_error(status_t err) { 44 if (err == OK) { 45 return AMEDIA_OK; 46 } else if (err == -EAGAIN) { 47 return (media_status_t) AMEDIACODEC_INFO_TRY_AGAIN_LATER; 48 } 49 ALOGE("sf error code: %d", err); 50 return AMEDIA_ERROR_UNKNOWN; 51 } 52 53 enum { 54 kWhatActivityNotify, 55 kWhatRequestActivityNotifications, 56 kWhatStopActivityNotifications, 57 }; 58 59 struct AMediaCodecPersistentSurface : public Surface { 60 sp<PersistentSurface> mPersistentSurface; 61 AMediaCodecPersistentSurface( 62 const sp<IGraphicBufferProducer>& igbp, 63 const sp<PersistentSurface>& ps) 64 : Surface(igbp) { 65 mPersistentSurface = ps; 66 } 67 virtual ~AMediaCodecPersistentSurface() { 68 //mPersistentSurface ref will be let go off here 69 } 70 }; 71 72 class CodecHandler: public AHandler { 73 private: 74 AMediaCodec* mCodec; 75 public: 76 explicit CodecHandler(AMediaCodec *codec); 77 virtual void onMessageReceived(const sp<AMessage> &msg); 78 }; 79 80 typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata); 81 82 struct AMediaCodec { 83 sp<android::MediaCodec> mCodec; 84 sp<ALooper> mLooper; 85 sp<CodecHandler> mHandler; 86 sp<AMessage> mActivityNotification; 87 int32_t mGeneration; 88 bool mRequestedActivityNotification; 89 OnCodecEvent mCallback; 90 void *mCallbackUserData; 91 }; 92 93 CodecHandler::CodecHandler(AMediaCodec *codec) { 94 mCodec = codec; 95 } 96 97 void CodecHandler::onMessageReceived(const sp<AMessage> &msg) { 98 99 switch (msg->what()) { 100 case kWhatRequestActivityNotifications: 101 { 102 if (mCodec->mRequestedActivityNotification) { 103 break; 104 } 105 106 mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification); 107 mCodec->mRequestedActivityNotification = true; 108 break; 109 } 110 111 case kWhatActivityNotify: 112 { 113 { 114 int32_t generation; 115 msg->findInt32("generation", &generation); 116 117 if (generation != mCodec->mGeneration) { 118 // stale 119 break; 120 } 121 122 mCodec->mRequestedActivityNotification = false; 123 } 124 125 if (mCodec->mCallback) { 126 mCodec->mCallback(mCodec, mCodec->mCallbackUserData); 127 } 128 break; 129 } 130 131 case kWhatStopActivityNotifications: 132 { 133 sp<AReplyToken> replyID; 134 msg->senderAwaitsResponse(&replyID); 135 136 mCodec->mGeneration++; 137 mCodec->mRequestedActivityNotification = false; 138 139 sp<AMessage> response = new AMessage; 140 response->postReply(replyID); 141 break; 142 } 143 144 default: 145 ALOGE("shouldn't be here"); 146 break; 147 } 148 149 } 150 151 152 static void requestActivityNotification(AMediaCodec *codec) { 153 (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post(); 154 } 155 156 extern "C" { 157 158 static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool encoder) { 159 AMediaCodec *mData = new AMediaCodec(); 160 mData->mLooper = new ALooper; 161 mData->mLooper->setName("NDK MediaCodec_looper"); 162 size_t res = mData->mLooper->start( 163 false, // runOnCallingThread 164 true, // canCallJava XXX 165 PRIORITY_FOREGROUND); 166 if (res != OK) { 167 ALOGE("Failed to start the looper"); 168 AMediaCodec_delete(mData); 169 return NULL; 170 } 171 if (name_is_type) { 172 mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder); 173 } else { 174 mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name); 175 } 176 if (mData->mCodec == NULL) { // failed to create codec 177 AMediaCodec_delete(mData); 178 return NULL; 179 } 180 mData->mHandler = new CodecHandler(mData); 181 mData->mLooper->registerHandler(mData->mHandler); 182 mData->mGeneration = 1; 183 mData->mRequestedActivityNotification = false; 184 mData->mCallback = NULL; 185 186 return mData; 187 } 188 189 EXPORT 190 AMediaCodec* AMediaCodec_createCodecByName(const char *name) { 191 return createAMediaCodec(name, false, false); 192 } 193 194 EXPORT 195 AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) { 196 return createAMediaCodec(mime_type, true, false); 197 } 198 199 EXPORT 200 AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { 201 return createAMediaCodec(name, true, true); 202 } 203 204 EXPORT 205 media_status_t AMediaCodec_delete(AMediaCodec *mData) { 206 if (mData != NULL) { 207 if (mData->mCodec != NULL) { 208 mData->mCodec->release(); 209 mData->mCodec.clear(); 210 } 211 212 if (mData->mLooper != NULL) { 213 if (mData->mHandler != NULL) { 214 mData->mLooper->unregisterHandler(mData->mHandler->id()); 215 } 216 mData->mLooper->stop(); 217 mData->mLooper.clear(); 218 } 219 delete mData; 220 } 221 return AMEDIA_OK; 222 } 223 224 EXPORT 225 media_status_t AMediaCodec_configure( 226 AMediaCodec *mData, 227 const AMediaFormat* format, 228 ANativeWindow* window, 229 AMediaCrypto *crypto, 230 uint32_t flags) { 231 sp<AMessage> nativeFormat; 232 AMediaFormat_getFormat(format, &nativeFormat); 233 ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); 234 sp<Surface> surface = NULL; 235 if (window != NULL) { 236 surface = (Surface*) window; 237 } 238 239 return translate_error(mData->mCodec->configure(nativeFormat, surface, 240 crypto ? crypto->mCrypto : NULL, flags)); 241 } 242 243 EXPORT 244 media_status_t AMediaCodec_start(AMediaCodec *mData) { 245 status_t ret = mData->mCodec->start(); 246 if (ret != OK) { 247 return translate_error(ret); 248 } 249 mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler); 250 mData->mActivityNotification->setInt32("generation", mData->mGeneration); 251 requestActivityNotification(mData); 252 return AMEDIA_OK; 253 } 254 255 EXPORT 256 media_status_t AMediaCodec_stop(AMediaCodec *mData) { 257 media_status_t ret = translate_error(mData->mCodec->stop()); 258 259 sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler); 260 sp<AMessage> response; 261 msg->postAndAwaitResponse(&response); 262 mData->mActivityNotification.clear(); 263 264 return ret; 265 } 266 267 EXPORT 268 media_status_t AMediaCodec_flush(AMediaCodec *mData) { 269 return translate_error(mData->mCodec->flush()); 270 } 271 272 EXPORT 273 ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { 274 size_t idx; 275 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs); 276 requestActivityNotification(mData); 277 if (ret == OK) { 278 return idx; 279 } 280 return translate_error(ret); 281 } 282 283 EXPORT 284 uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 285 android::Vector<android::sp<android::MediaCodecBuffer> > abufs; 286 if (mData->mCodec->getInputBuffers(&abufs) == 0) { 287 size_t n = abufs.size(); 288 if (idx >= n) { 289 ALOGE("buffer index %zu out of range", idx); 290 return NULL; 291 } 292 if (abufs[idx] == NULL) { 293 ALOGE("buffer index %zu is NULL", 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 input buffers"); 302 return NULL; 303 } 304 305 EXPORT 306 uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 307 android::Vector<android::sp<android::MediaCodecBuffer> > abufs; 308 if (mData->mCodec->getOutputBuffers(&abufs) == 0) { 309 size_t n = abufs.size(); 310 if (idx >= n) { 311 ALOGE("buffer index %zu out of range", idx); 312 return NULL; 313 } 314 if (out_size != NULL) { 315 *out_size = abufs[idx]->capacity(); 316 } 317 return abufs[idx]->data(); 318 } 319 ALOGE("couldn't get output buffers"); 320 return NULL; 321 } 322 323 EXPORT 324 media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData, 325 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { 326 327 AString errorMsg; 328 status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg); 329 return translate_error(ret); 330 } 331 332 EXPORT 333 ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData, 334 AMediaCodecBufferInfo *info, int64_t timeoutUs) { 335 size_t idx; 336 size_t offset; 337 size_t size; 338 uint32_t flags; 339 int64_t presentationTimeUs; 340 status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs, 341 &flags, timeoutUs); 342 requestActivityNotification(mData); 343 switch (ret) { 344 case OK: 345 info->offset = offset; 346 info->size = size; 347 info->flags = flags; 348 info->presentationTimeUs = presentationTimeUs; 349 return idx; 350 case -EAGAIN: 351 return AMEDIACODEC_INFO_TRY_AGAIN_LATER; 352 case android::INFO_FORMAT_CHANGED: 353 return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED; 354 case INFO_OUTPUT_BUFFERS_CHANGED: 355 return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED; 356 default: 357 break; 358 } 359 return translate_error(ret); 360 } 361 362 EXPORT 363 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { 364 sp<AMessage> format; 365 mData->mCodec->getOutputFormat(&format); 366 return AMediaFormat_fromMsg(&format); 367 } 368 369 EXPORT 370 media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) { 371 if (render) { 372 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx)); 373 } else { 374 return translate_error(mData->mCodec->releaseOutputBuffer(idx)); 375 } 376 } 377 378 EXPORT 379 media_status_t AMediaCodec_releaseOutputBufferAtTime( 380 AMediaCodec *mData, size_t idx, int64_t timestampNs) { 381 ALOGV("render @ %" PRId64, timestampNs); 382 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs)); 383 } 384 385 EXPORT 386 media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) { 387 sp<Surface> surface = NULL; 388 if (window != NULL) { 389 surface = (Surface*) window; 390 } 391 return translate_error(mData->mCodec->setSurface(surface)); 392 } 393 394 EXPORT 395 media_status_t AMediaCodec_createInputSurface(AMediaCodec *mData, ANativeWindow **surface) { 396 if (surface == NULL || mData == NULL) { 397 return AMEDIA_ERROR_INVALID_PARAMETER; 398 } 399 *surface = NULL; 400 401 sp<IGraphicBufferProducer> igbp = NULL; 402 status_t err = mData->mCodec->createInputSurface(&igbp); 403 if (err != NO_ERROR) { 404 return translate_error(err); 405 } 406 407 *surface = new Surface(igbp); 408 ANativeWindow_acquire(*surface); 409 return AMEDIA_OK; 410 } 411 412 EXPORT 413 media_status_t AMediaCodec_createPersistentInputSurface(ANativeWindow **surface) { 414 if (surface == NULL) { 415 return AMEDIA_ERROR_INVALID_PARAMETER; 416 } 417 *surface = NULL; 418 419 sp<PersistentSurface> ps = MediaCodec::CreatePersistentInputSurface(); 420 if (ps == NULL) { 421 return AMEDIA_ERROR_UNKNOWN; 422 } 423 424 sp<IGraphicBufferProducer> igbp = ps->getBufferProducer(); 425 if (igbp == NULL) { 426 return AMEDIA_ERROR_UNKNOWN; 427 } 428 429 *surface = new AMediaCodecPersistentSurface(igbp, ps); 430 ANativeWindow_acquire(*surface); 431 432 return AMEDIA_OK; 433 } 434 435 EXPORT 436 media_status_t AMediaCodec_setInputSurface( 437 AMediaCodec *mData, ANativeWindow *surface) { 438 439 if (surface == NULL || mData == NULL) { 440 return AMEDIA_ERROR_INVALID_PARAMETER; 441 } 442 443 AMediaCodecPersistentSurface *aMediaPersistentSurface = 444 static_cast<AMediaCodecPersistentSurface *>(surface); 445 if (aMediaPersistentSurface->mPersistentSurface == NULL) { 446 return AMEDIA_ERROR_INVALID_PARAMETER; 447 } 448 449 return translate_error(mData->mCodec->setInputSurface( 450 aMediaPersistentSurface->mPersistentSurface)); 451 } 452 453 EXPORT 454 media_status_t AMediaCodec_setParameters( 455 AMediaCodec *mData, const AMediaFormat* params) { 456 if (params == NULL || mData == NULL) { 457 return AMEDIA_ERROR_INVALID_PARAMETER; 458 } 459 sp<AMessage> nativeParams; 460 AMediaFormat_getFormat(params, &nativeParams); 461 ALOGV("setParameters: %s", nativeParams->debugString(0).c_str()); 462 463 return translate_error(mData->mCodec->setParameters(nativeParams)); 464 } 465 466 EXPORT 467 media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData) { 468 469 if (mData == NULL) { 470 return AMEDIA_ERROR_INVALID_PARAMETER; 471 } 472 473 status_t err = mData->mCodec->signalEndOfInputStream(); 474 if (err == INVALID_OPERATION) { 475 return AMEDIA_ERROR_INVALID_OPERATION; 476 } 477 478 return translate_error(err); 479 480 } 481 482 //EXPORT 483 media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, 484 void *userdata) { 485 mData->mCallback = callback; 486 mData->mCallbackUserData = userdata; 487 return AMEDIA_OK; 488 } 489 490 typedef struct AMediaCodecCryptoInfo { 491 int numsubsamples; 492 uint8_t key[16]; 493 uint8_t iv[16]; 494 cryptoinfo_mode_t mode; 495 cryptoinfo_pattern_t pattern; 496 size_t *clearbytes; 497 size_t *encryptedbytes; 498 } AMediaCodecCryptoInfo; 499 500 EXPORT 501 media_status_t AMediaCodec_queueSecureInputBuffer( 502 AMediaCodec* codec, 503 size_t idx, 504 off_t offset, 505 AMediaCodecCryptoInfo* crypto, 506 uint64_t time, 507 uint32_t flags) { 508 509 CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples]; 510 for (int i = 0; i < crypto->numsubsamples; i++) { 511 subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i]; 512 subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i]; 513 } 514 515 CryptoPlugin::Pattern pattern; 516 pattern.mEncryptBlocks = crypto->pattern.encryptBlocks; 517 pattern.mSkipBlocks = crypto->pattern.skipBlocks; 518 519 AString errormsg; 520 status_t err = codec->mCodec->queueSecureInputBuffer(idx, 521 offset, 522 subSamples, 523 crypto->numsubsamples, 524 crypto->key, 525 crypto->iv, 526 (CryptoPlugin::Mode)crypto->mode, 527 pattern, 528 time, 529 flags, 530 &errormsg); 531 if (err != 0) { 532 ALOGE("queSecureInputBuffer: %s", errormsg.c_str()); 533 } 534 delete [] subSamples; 535 return translate_error(err); 536 } 537 538 539 EXPORT 540 void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info, 541 cryptoinfo_pattern_t *pattern) { 542 info->pattern.encryptBlocks = pattern->encryptBlocks; 543 info->pattern.skipBlocks = pattern->skipBlocks; 544 } 545 546 EXPORT 547 AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( 548 int numsubsamples, 549 uint8_t key[16], 550 uint8_t iv[16], 551 cryptoinfo_mode_t mode, 552 size_t *clearbytes, 553 size_t *encryptedbytes) { 554 555 // size needed to store all the crypto data 556 size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2; 557 AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize); 558 if (!ret) { 559 ALOGE("couldn't allocate %zu bytes", cryptosize); 560 return NULL; 561 } 562 ret->numsubsamples = numsubsamples; 563 memcpy(ret->key, key, 16); 564 memcpy(ret->iv, iv, 16); 565 ret->mode = mode; 566 ret->pattern.encryptBlocks = 0; 567 ret->pattern.skipBlocks = 0; 568 569 // clearbytes and encryptedbytes point at the actual data, which follows 570 ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct 571 ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes 572 573 memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t)); 574 memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t)); 575 576 return ret; 577 } 578 579 580 EXPORT 581 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) { 582 free(info); 583 return AMEDIA_OK; 584 } 585 586 EXPORT 587 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) { 588 return ci->numsubsamples; 589 } 590 591 EXPORT 592 media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) { 593 if (!ci) { 594 return AMEDIA_ERROR_INVALID_OBJECT; 595 } 596 if (!dst) { 597 return AMEDIA_ERROR_INVALID_PARAMETER; 598 } 599 memcpy(dst, ci->key, 16); 600 return AMEDIA_OK; 601 } 602 603 EXPORT 604 media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) { 605 if (!ci) { 606 return AMEDIA_ERROR_INVALID_OBJECT; 607 } 608 if (!dst) { 609 return AMEDIA_ERROR_INVALID_PARAMETER; 610 } 611 memcpy(dst, ci->iv, 16); 612 return AMEDIA_OK; 613 } 614 615 EXPORT 616 cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { 617 if (!ci) { 618 return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT; 619 } 620 return ci->mode; 621 } 622 623 EXPORT 624 media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { 625 if (!ci) { 626 return AMEDIA_ERROR_INVALID_OBJECT; 627 } 628 if (!dst) { 629 return AMEDIA_ERROR_INVALID_PARAMETER; 630 } 631 memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples); 632 return AMEDIA_OK; 633 } 634 635 EXPORT 636 media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { 637 if (!ci) { 638 return AMEDIA_ERROR_INVALID_OBJECT; 639 } 640 if (!dst) { 641 return AMEDIA_ERROR_INVALID_PARAMETER; 642 } 643 memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples); 644 return AMEDIA_OK; 645 } 646 647 } // extern "C" 648 649