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 40using namespace android; 41 42 43static 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 53enum { 54 kWhatActivityNotify, 55 kWhatAsyncNotify, 56 kWhatRequestActivityNotifications, 57 kWhatStopActivityNotifications, 58}; 59 60struct AMediaCodecPersistentSurface : public Surface { 61 sp<PersistentSurface> mPersistentSurface; 62 AMediaCodecPersistentSurface( 63 const sp<IGraphicBufferProducer>& igbp, 64 const sp<PersistentSurface>& ps) 65 : Surface(igbp) { 66 mPersistentSurface = ps; 67 } 68 virtual ~AMediaCodecPersistentSurface() { 69 //mPersistentSurface ref will be let go off here 70 } 71}; 72 73class CodecHandler: public AHandler { 74private: 75 AMediaCodec* mCodec; 76public: 77 explicit CodecHandler(AMediaCodec *codec); 78 virtual void onMessageReceived(const sp<AMessage> &msg); 79}; 80 81typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata); 82 83struct AMediaCodec { 84 sp<android::MediaCodec> mCodec; 85 sp<ALooper> mLooper; 86 sp<CodecHandler> mHandler; 87 sp<AMessage> mActivityNotification; 88 int32_t mGeneration; 89 bool mRequestedActivityNotification; 90 OnCodecEvent mCallback; 91 void *mCallbackUserData; 92 93 sp<AMessage> mAsyncNotify; 94 mutable Mutex mAsyncCallbackLock; 95 AMediaCodecOnAsyncNotifyCallback mAsyncCallback; 96 void *mAsyncCallbackUserData; 97}; 98 99CodecHandler::CodecHandler(AMediaCodec *codec) { 100 mCodec = codec; 101} 102 103void CodecHandler::onMessageReceived(const sp<AMessage> &msg) { 104 105 switch (msg->what()) { 106 case kWhatRequestActivityNotifications: 107 { 108 if (mCodec->mRequestedActivityNotification) { 109 break; 110 } 111 112 mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification); 113 mCodec->mRequestedActivityNotification = true; 114 break; 115 } 116 117 case kWhatActivityNotify: 118 { 119 { 120 int32_t generation; 121 msg->findInt32("generation", &generation); 122 123 if (generation != mCodec->mGeneration) { 124 // stale 125 break; 126 } 127 128 mCodec->mRequestedActivityNotification = false; 129 } 130 131 if (mCodec->mCallback) { 132 mCodec->mCallback(mCodec, mCodec->mCallbackUserData); 133 } 134 break; 135 } 136 137 case kWhatAsyncNotify: 138 { 139 int32_t cbID; 140 if (!msg->findInt32("callbackID", &cbID)) { 141 ALOGE("kWhatAsyncNotify: callbackID is expected."); 142 break; 143 } 144 145 ALOGV("kWhatAsyncNotify: cbID = %d", cbID); 146 147 switch (cbID) { 148 case MediaCodec::CB_INPUT_AVAILABLE: 149 { 150 int32_t index; 151 if (!msg->findInt32("index", &index)) { 152 ALOGE("CB_INPUT_AVAILABLE: index is expected."); 153 break; 154 } 155 156 Mutex::Autolock _l(mCodec->mAsyncCallbackLock); 157 if (mCodec->mAsyncCallbackUserData != NULL 158 || mCodec->mAsyncCallback.onAsyncInputAvailable != NULL) { 159 mCodec->mAsyncCallback.onAsyncInputAvailable( 160 mCodec, 161 mCodec->mAsyncCallbackUserData, 162 index); 163 } 164 165 break; 166 } 167 168 case MediaCodec::CB_OUTPUT_AVAILABLE: 169 { 170 int32_t index; 171 size_t offset; 172 size_t size; 173 int64_t timeUs; 174 int32_t flags; 175 176 if (!msg->findInt32("index", &index)) { 177 ALOGE("CB_OUTPUT_AVAILABLE: index is expected."); 178 break; 179 } 180 if (!msg->findSize("offset", &offset)) { 181 ALOGE("CB_OUTPUT_AVAILABLE: offset is expected."); 182 break; 183 } 184 if (!msg->findSize("size", &size)) { 185 ALOGE("CB_OUTPUT_AVAILABLE: size is expected."); 186 break; 187 } 188 if (!msg->findInt64("timeUs", &timeUs)) { 189 ALOGE("CB_OUTPUT_AVAILABLE: timeUs is expected."); 190 break; 191 } 192 if (!msg->findInt32("flags", &flags)) { 193 ALOGE("CB_OUTPUT_AVAILABLE: flags is expected."); 194 break; 195 } 196 197 AMediaCodecBufferInfo bufferInfo = { 198 (int32_t)offset, 199 (int32_t)size, 200 timeUs, 201 (uint32_t)flags}; 202 203 Mutex::Autolock _l(mCodec->mAsyncCallbackLock); 204 if (mCodec->mAsyncCallbackUserData != NULL 205 || mCodec->mAsyncCallback.onAsyncOutputAvailable != NULL) { 206 mCodec->mAsyncCallback.onAsyncOutputAvailable( 207 mCodec, 208 mCodec->mAsyncCallbackUserData, 209 index, 210 &bufferInfo); 211 } 212 213 break; 214 } 215 216 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED: 217 { 218 sp<AMessage> format; 219 if (!msg->findMessage("format", &format)) { 220 ALOGE("CB_OUTPUT_FORMAT_CHANGED: format is expected."); 221 break; 222 } 223 224 AMediaFormat *aMediaFormat = AMediaFormat_fromMsg(&format); 225 226 Mutex::Autolock _l(mCodec->mAsyncCallbackLock); 227 if (mCodec->mAsyncCallbackUserData != NULL 228 || mCodec->mAsyncCallback.onAsyncFormatChanged != NULL) { 229 mCodec->mAsyncCallback.onAsyncFormatChanged( 230 mCodec, 231 mCodec->mAsyncCallbackUserData, 232 aMediaFormat); 233 } 234 235 break; 236 } 237 238 case MediaCodec::CB_ERROR: 239 { 240 status_t err; 241 int32_t actionCode; 242 AString detail; 243 if (!msg->findInt32("err", &err)) { 244 ALOGE("CB_ERROR: err is expected."); 245 break; 246 } 247 if (!msg->findInt32("action", &actionCode)) { 248 ALOGE("CB_ERROR: action is expected."); 249 break; 250 } 251 msg->findString("detail", &detail); 252 ALOGE("Decoder reported error(0x%x), actionCode(%d), detail(%s)", 253 err, actionCode, detail.c_str()); 254 255 Mutex::Autolock _l(mCodec->mAsyncCallbackLock); 256 if (mCodec->mAsyncCallbackUserData != NULL 257 || mCodec->mAsyncCallback.onAsyncError != NULL) { 258 mCodec->mAsyncCallback.onAsyncError( 259 mCodec, 260 mCodec->mAsyncCallbackUserData, 261 translate_error(err), 262 actionCode, 263 detail.c_str()); 264 } 265 266 break; 267 } 268 269 default: 270 { 271 ALOGE("kWhatAsyncNotify: callbackID(%d) is unexpected.", cbID); 272 break; 273 } 274 } 275 break; 276 } 277 278 case kWhatStopActivityNotifications: 279 { 280 sp<AReplyToken> replyID; 281 msg->senderAwaitsResponse(&replyID); 282 283 mCodec->mGeneration++; 284 mCodec->mRequestedActivityNotification = false; 285 286 sp<AMessage> response = new AMessage; 287 response->postReply(replyID); 288 break; 289 } 290 291 default: 292 ALOGE("shouldn't be here"); 293 break; 294 } 295 296} 297 298 299static void requestActivityNotification(AMediaCodec *codec) { 300 (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post(); 301} 302 303extern "C" { 304 305static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool encoder) { 306 AMediaCodec *mData = new AMediaCodec(); 307 mData->mLooper = new ALooper; 308 mData->mLooper->setName("NDK MediaCodec_looper"); 309 size_t res = mData->mLooper->start( 310 false, // runOnCallingThread 311 true, // canCallJava XXX 312 PRIORITY_AUDIO); 313 if (res != OK) { 314 ALOGE("Failed to start the looper"); 315 AMediaCodec_delete(mData); 316 return NULL; 317 } 318 if (name_is_type) { 319 mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder); 320 } else { 321 mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name); 322 } 323 if (mData->mCodec == NULL) { // failed to create codec 324 AMediaCodec_delete(mData); 325 return NULL; 326 } 327 mData->mHandler = new CodecHandler(mData); 328 mData->mLooper->registerHandler(mData->mHandler); 329 mData->mGeneration = 1; 330 mData->mRequestedActivityNotification = false; 331 mData->mCallback = NULL; 332 333 mData->mAsyncCallback = {}; 334 mData->mAsyncCallbackUserData = NULL; 335 336 return mData; 337} 338 339EXPORT 340AMediaCodec* AMediaCodec_createCodecByName(const char *name) { 341 return createAMediaCodec(name, false, false); 342} 343 344EXPORT 345AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) { 346 return createAMediaCodec(mime_type, true, false); 347} 348 349EXPORT 350AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { 351 return createAMediaCodec(name, true, true); 352} 353 354EXPORT 355media_status_t AMediaCodec_delete(AMediaCodec *mData) { 356 if (mData != NULL) { 357 if (mData->mCodec != NULL) { 358 mData->mCodec->release(); 359 mData->mCodec.clear(); 360 } 361 362 if (mData->mLooper != NULL) { 363 if (mData->mHandler != NULL) { 364 mData->mLooper->unregisterHandler(mData->mHandler->id()); 365 } 366 mData->mLooper->stop(); 367 mData->mLooper.clear(); 368 } 369 delete mData; 370 } 371 return AMEDIA_OK; 372} 373 374EXPORT 375media_status_t AMediaCodec_getName( 376 AMediaCodec *mData, 377 char** out_name) { 378 if (out_name == NULL) { 379 return AMEDIA_ERROR_INVALID_PARAMETER; 380 } 381 382 AString compName; 383 status_t err = mData->mCodec->getName(&compName); 384 if (err != OK) { 385 return translate_error(err); 386 } 387 *out_name = strdup(compName.c_str()); 388 return AMEDIA_OK; 389} 390 391EXPORT 392void AMediaCodec_releaseName( 393 AMediaCodec * /* mData */, 394 char* name) { 395 if (name != NULL) { 396 free(name); 397 } 398} 399 400EXPORT 401media_status_t AMediaCodec_configure( 402 AMediaCodec *mData, 403 const AMediaFormat* format, 404 ANativeWindow* window, 405 AMediaCrypto *crypto, 406 uint32_t flags) { 407 sp<AMessage> nativeFormat; 408 AMediaFormat_getFormat(format, &nativeFormat); 409 ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); 410 sp<Surface> surface = NULL; 411 if (window != NULL) { 412 surface = (Surface*) window; 413 } 414 415 status_t err = mData->mCodec->configure(nativeFormat, surface, 416 crypto ? crypto->mCrypto : NULL, flags); 417 if (err != OK) { 418 ALOGE("configure: err(%d), failed with format: %s", 419 err, nativeFormat->debugString(0).c_str()); 420 } 421 return translate_error(err); 422} 423 424EXPORT 425media_status_t AMediaCodec_setAsyncNotifyCallback( 426 AMediaCodec *mData, 427 AMediaCodecOnAsyncNotifyCallback callback, 428 void *userdata) { 429 if (mData->mAsyncNotify == NULL && userdata != NULL) { 430 mData->mAsyncNotify = new AMessage(kWhatAsyncNotify, mData->mHandler); 431 status_t err = mData->mCodec->setCallback(mData->mAsyncNotify); 432 if (err != OK) { 433 ALOGE("setAsyncNotifyCallback: err(%d), failed to set async callback", err); 434 return translate_error(err); 435 } 436 } 437 438 Mutex::Autolock _l(mData->mAsyncCallbackLock); 439 mData->mAsyncCallback = callback; 440 mData->mAsyncCallbackUserData = userdata; 441 442 return AMEDIA_OK; 443} 444 445 446EXPORT 447media_status_t AMediaCodec_releaseCrypto(AMediaCodec *mData) { 448 return translate_error(mData->mCodec->releaseCrypto()); 449} 450 451EXPORT 452media_status_t AMediaCodec_start(AMediaCodec *mData) { 453 status_t ret = mData->mCodec->start(); 454 if (ret != OK) { 455 return translate_error(ret); 456 } 457 mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler); 458 mData->mActivityNotification->setInt32("generation", mData->mGeneration); 459 requestActivityNotification(mData); 460 return AMEDIA_OK; 461} 462 463EXPORT 464media_status_t AMediaCodec_stop(AMediaCodec *mData) { 465 media_status_t ret = translate_error(mData->mCodec->stop()); 466 467 sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler); 468 sp<AMessage> response; 469 msg->postAndAwaitResponse(&response); 470 mData->mActivityNotification.clear(); 471 472 return ret; 473} 474 475EXPORT 476media_status_t AMediaCodec_flush(AMediaCodec *mData) { 477 return translate_error(mData->mCodec->flush()); 478} 479 480EXPORT 481ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { 482 size_t idx; 483 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs); 484 requestActivityNotification(mData); 485 if (ret == OK) { 486 return idx; 487 } 488 return translate_error(ret); 489} 490 491EXPORT 492uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 493 if (mData->mAsyncNotify != NULL) { 494 // Asynchronous mode 495 sp<MediaCodecBuffer> abuf; 496 if (mData->mCodec->getInputBuffer(idx, &abuf) != 0) { 497 return NULL; 498 } 499 500 if (out_size != NULL) { 501 *out_size = abuf->capacity(); 502 } 503 return abuf->data(); 504 } 505 506 android::Vector<android::sp<android::MediaCodecBuffer> > abufs; 507 if (mData->mCodec->getInputBuffers(&abufs) == 0) { 508 size_t n = abufs.size(); 509 if (idx >= n) { 510 ALOGE("buffer index %zu out of range", idx); 511 return NULL; 512 } 513 if (abufs[idx] == NULL) { 514 ALOGE("buffer index %zu is NULL", idx); 515 return NULL; 516 } 517 if (out_size != NULL) { 518 *out_size = abufs[idx]->capacity(); 519 } 520 return abufs[idx]->data(); 521 } 522 ALOGE("couldn't get input buffers"); 523 return NULL; 524} 525 526EXPORT 527uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 528 if (mData->mAsyncNotify != NULL) { 529 // Asynchronous mode 530 sp<MediaCodecBuffer> abuf; 531 if (mData->mCodec->getOutputBuffer(idx, &abuf) != 0) { 532 return NULL; 533 } 534 535 if (out_size != NULL) { 536 *out_size = abuf->capacity(); 537 } 538 return abuf->data(); 539 } 540 541 android::Vector<android::sp<android::MediaCodecBuffer> > abufs; 542 if (mData->mCodec->getOutputBuffers(&abufs) == 0) { 543 size_t n = abufs.size(); 544 if (idx >= n) { 545 ALOGE("buffer index %zu out of range", idx); 546 return NULL; 547 } 548 if (out_size != NULL) { 549 *out_size = abufs[idx]->capacity(); 550 } 551 return abufs[idx]->data(); 552 } 553 ALOGE("couldn't get output buffers"); 554 return NULL; 555} 556 557EXPORT 558media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData, 559 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { 560 561 AString errorMsg; 562 status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg); 563 return translate_error(ret); 564} 565 566EXPORT 567ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData, 568 AMediaCodecBufferInfo *info, int64_t timeoutUs) { 569 size_t idx; 570 size_t offset; 571 size_t size; 572 uint32_t flags; 573 int64_t presentationTimeUs; 574 status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs, 575 &flags, timeoutUs); 576 requestActivityNotification(mData); 577 switch (ret) { 578 case OK: 579 info->offset = offset; 580 info->size = size; 581 info->flags = flags; 582 info->presentationTimeUs = presentationTimeUs; 583 return idx; 584 case -EAGAIN: 585 return AMEDIACODEC_INFO_TRY_AGAIN_LATER; 586 case android::INFO_FORMAT_CHANGED: 587 return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED; 588 case INFO_OUTPUT_BUFFERS_CHANGED: 589 return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED; 590 default: 591 break; 592 } 593 return translate_error(ret); 594} 595 596EXPORT 597AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { 598 sp<AMessage> format; 599 mData->mCodec->getOutputFormat(&format); 600 return AMediaFormat_fromMsg(&format); 601} 602 603EXPORT 604AMediaFormat* AMediaCodec_getInputFormat(AMediaCodec *mData) { 605 sp<AMessage> format; 606 mData->mCodec->getInputFormat(&format); 607 return AMediaFormat_fromMsg(&format); 608} 609 610EXPORT 611AMediaFormat* AMediaCodec_getBufferFormat(AMediaCodec *mData, size_t index) { 612 sp<AMessage> format; 613 mData->mCodec->getOutputFormat(index, &format); 614 return AMediaFormat_fromMsg(&format); 615} 616 617EXPORT 618media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) { 619 if (render) { 620 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx)); 621 } else { 622 return translate_error(mData->mCodec->releaseOutputBuffer(idx)); 623 } 624} 625 626EXPORT 627media_status_t AMediaCodec_releaseOutputBufferAtTime( 628 AMediaCodec *mData, size_t idx, int64_t timestampNs) { 629 ALOGV("render @ %" PRId64, timestampNs); 630 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs)); 631} 632 633EXPORT 634media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) { 635 sp<Surface> surface = NULL; 636 if (window != NULL) { 637 surface = (Surface*) window; 638 } 639 return translate_error(mData->mCodec->setSurface(surface)); 640} 641 642EXPORT 643media_status_t AMediaCodec_createInputSurface(AMediaCodec *mData, ANativeWindow **surface) { 644 if (surface == NULL || mData == NULL) { 645 return AMEDIA_ERROR_INVALID_PARAMETER; 646 } 647 *surface = NULL; 648 649 sp<IGraphicBufferProducer> igbp = NULL; 650 status_t err = mData->mCodec->createInputSurface(&igbp); 651 if (err != NO_ERROR) { 652 return translate_error(err); 653 } 654 655 *surface = new Surface(igbp); 656 ANativeWindow_acquire(*surface); 657 return AMEDIA_OK; 658} 659 660EXPORT 661media_status_t AMediaCodec_createPersistentInputSurface(ANativeWindow **surface) { 662 if (surface == NULL) { 663 return AMEDIA_ERROR_INVALID_PARAMETER; 664 } 665 *surface = NULL; 666 667 sp<PersistentSurface> ps = MediaCodec::CreatePersistentInputSurface(); 668 if (ps == NULL) { 669 return AMEDIA_ERROR_UNKNOWN; 670 } 671 672 sp<IGraphicBufferProducer> igbp = ps->getBufferProducer(); 673 if (igbp == NULL) { 674 return AMEDIA_ERROR_UNKNOWN; 675 } 676 677 *surface = new AMediaCodecPersistentSurface(igbp, ps); 678 ANativeWindow_acquire(*surface); 679 680 return AMEDIA_OK; 681} 682 683EXPORT 684media_status_t AMediaCodec_setInputSurface( 685 AMediaCodec *mData, ANativeWindow *surface) { 686 687 if (surface == NULL || mData == NULL) { 688 return AMEDIA_ERROR_INVALID_PARAMETER; 689 } 690 691 AMediaCodecPersistentSurface *aMediaPersistentSurface = 692 static_cast<AMediaCodecPersistentSurface *>(surface); 693 if (aMediaPersistentSurface->mPersistentSurface == NULL) { 694 return AMEDIA_ERROR_INVALID_PARAMETER; 695 } 696 697 return translate_error(mData->mCodec->setInputSurface( 698 aMediaPersistentSurface->mPersistentSurface)); 699} 700 701EXPORT 702media_status_t AMediaCodec_setParameters( 703 AMediaCodec *mData, const AMediaFormat* params) { 704 if (params == NULL || mData == NULL) { 705 return AMEDIA_ERROR_INVALID_PARAMETER; 706 } 707 sp<AMessage> nativeParams; 708 AMediaFormat_getFormat(params, &nativeParams); 709 ALOGV("setParameters: %s", nativeParams->debugString(0).c_str()); 710 711 return translate_error(mData->mCodec->setParameters(nativeParams)); 712} 713 714EXPORT 715media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData) { 716 717 if (mData == NULL) { 718 return AMEDIA_ERROR_INVALID_PARAMETER; 719 } 720 721 status_t err = mData->mCodec->signalEndOfInputStream(); 722 if (err == INVALID_OPERATION) { 723 return AMEDIA_ERROR_INVALID_OPERATION; 724 } 725 726 return translate_error(err); 727 728} 729 730//EXPORT 731media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, 732 void *userdata) { 733 mData->mCallback = callback; 734 mData->mCallbackUserData = userdata; 735 return AMEDIA_OK; 736} 737 738typedef struct AMediaCodecCryptoInfo { 739 int numsubsamples; 740 uint8_t key[16]; 741 uint8_t iv[16]; 742 cryptoinfo_mode_t mode; 743 cryptoinfo_pattern_t pattern; 744 size_t *clearbytes; 745 size_t *encryptedbytes; 746} AMediaCodecCryptoInfo; 747 748EXPORT 749media_status_t AMediaCodec_queueSecureInputBuffer( 750 AMediaCodec* codec, 751 size_t idx, 752 off_t offset, 753 AMediaCodecCryptoInfo* crypto, 754 uint64_t time, 755 uint32_t flags) { 756 757 CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples]; 758 for (int i = 0; i < crypto->numsubsamples; i++) { 759 subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i]; 760 subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i]; 761 } 762 763 CryptoPlugin::Pattern pattern; 764 pattern.mEncryptBlocks = crypto->pattern.encryptBlocks; 765 pattern.mSkipBlocks = crypto->pattern.skipBlocks; 766 767 AString errormsg; 768 status_t err = codec->mCodec->queueSecureInputBuffer(idx, 769 offset, 770 subSamples, 771 crypto->numsubsamples, 772 crypto->key, 773 crypto->iv, 774 (CryptoPlugin::Mode)crypto->mode, 775 pattern, 776 time, 777 flags, 778 &errormsg); 779 if (err != 0) { 780 ALOGE("queSecureInputBuffer: %s", errormsg.c_str()); 781 } 782 delete [] subSamples; 783 return translate_error(err); 784} 785 786EXPORT 787bool AMediaCodecActionCode_isRecoverable(int32_t actionCode) { 788 return (actionCode == ACTION_CODE_RECOVERABLE); 789} 790 791EXPORT 792bool AMediaCodecActionCode_isTransient(int32_t actionCode) { 793 return (actionCode == ACTION_CODE_TRANSIENT); 794} 795 796 797EXPORT 798void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info, 799 cryptoinfo_pattern_t *pattern) { 800 info->pattern.encryptBlocks = pattern->encryptBlocks; 801 info->pattern.skipBlocks = pattern->skipBlocks; 802} 803 804EXPORT 805AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( 806 int numsubsamples, 807 uint8_t key[16], 808 uint8_t iv[16], 809 cryptoinfo_mode_t mode, 810 size_t *clearbytes, 811 size_t *encryptedbytes) { 812 813 // size needed to store all the crypto data 814 size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2; 815 AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize); 816 if (!ret) { 817 ALOGE("couldn't allocate %zu bytes", cryptosize); 818 return NULL; 819 } 820 ret->numsubsamples = numsubsamples; 821 memcpy(ret->key, key, 16); 822 memcpy(ret->iv, iv, 16); 823 ret->mode = mode; 824 ret->pattern.encryptBlocks = 0; 825 ret->pattern.skipBlocks = 0; 826 827 // clearbytes and encryptedbytes point at the actual data, which follows 828 ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct 829 ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes 830 831 memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t)); 832 memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t)); 833 834 return ret; 835} 836 837 838EXPORT 839media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) { 840 free(info); 841 return AMEDIA_OK; 842} 843 844EXPORT 845size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) { 846 return ci->numsubsamples; 847} 848 849EXPORT 850media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) { 851 if (!ci) { 852 return AMEDIA_ERROR_INVALID_OBJECT; 853 } 854 if (!dst) { 855 return AMEDIA_ERROR_INVALID_PARAMETER; 856 } 857 memcpy(dst, ci->key, 16); 858 return AMEDIA_OK; 859} 860 861EXPORT 862media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) { 863 if (!ci) { 864 return AMEDIA_ERROR_INVALID_OBJECT; 865 } 866 if (!dst) { 867 return AMEDIA_ERROR_INVALID_PARAMETER; 868 } 869 memcpy(dst, ci->iv, 16); 870 return AMEDIA_OK; 871} 872 873EXPORT 874cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { 875 if (!ci) { 876 return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT; 877 } 878 return ci->mode; 879} 880 881EXPORT 882media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { 883 if (!ci) { 884 return AMEDIA_ERROR_INVALID_OBJECT; 885 } 886 if (!dst) { 887 return AMEDIA_ERROR_INVALID_PARAMETER; 888 } 889 memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples); 890 return AMEDIA_OK; 891} 892 893EXPORT 894media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { 895 if (!ci) { 896 return AMEDIA_ERROR_INVALID_OBJECT; 897 } 898 if (!dst) { 899 return AMEDIA_ERROR_INVALID_PARAMETER; 900 } 901 memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples); 902 return AMEDIA_OK; 903} 904 905} // extern "C" 906 907