NdkMediaCodec.cpp revision f373e84c798b113d274a4d89edfea8afb899d3e2
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 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 kWhatRequestActivityNotifications, 56 kWhatStopActivityNotifications, 57}; 58 59struct 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 72class CodecHandler: public AHandler { 73private: 74 AMediaCodec* mCodec; 75public: 76 explicit CodecHandler(AMediaCodec *codec); 77 virtual void onMessageReceived(const sp<AMessage> &msg); 78}; 79 80typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata); 81 82struct 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 93CodecHandler::CodecHandler(AMediaCodec *codec) { 94 mCodec = codec; 95} 96 97void 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 152static void requestActivityNotification(AMediaCodec *codec) { 153 (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post(); 154} 155 156extern "C" { 157 158static 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 189EXPORT 190AMediaCodec* AMediaCodec_createCodecByName(const char *name) { 191 return createAMediaCodec(name, false, false); 192} 193 194EXPORT 195AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) { 196 return createAMediaCodec(mime_type, true, false); 197} 198 199EXPORT 200AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { 201 return createAMediaCodec(name, true, true); 202} 203 204EXPORT 205media_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 224EXPORT 225media_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 243EXPORT 244media_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 255EXPORT 256media_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 267EXPORT 268media_status_t AMediaCodec_flush(AMediaCodec *mData) { 269 return translate_error(mData->mCodec->flush()); 270} 271 272EXPORT 273ssize_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 283EXPORT 284uint8_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 305EXPORT 306uint8_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 323EXPORT 324media_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 332EXPORT 333ssize_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 362EXPORT 363AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { 364 sp<AMessage> format; 365 mData->mCodec->getOutputFormat(&format); 366 return AMediaFormat_fromMsg(&format); 367} 368 369EXPORT 370media_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 378EXPORT 379media_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 385EXPORT 386media_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 394EXPORT 395media_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 412EXPORT 413media_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 435EXPORT 436media_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 453EXPORT 454media_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 467media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, 468 void *userdata) { 469 mData->mCallback = callback; 470 mData->mCallbackUserData = userdata; 471 return AMEDIA_OK; 472} 473 474typedef struct AMediaCodecCryptoInfo { 475 int numsubsamples; 476 uint8_t key[16]; 477 uint8_t iv[16]; 478 cryptoinfo_mode_t mode; 479 cryptoinfo_pattern_t pattern; 480 size_t *clearbytes; 481 size_t *encryptedbytes; 482} AMediaCodecCryptoInfo; 483 484EXPORT 485media_status_t AMediaCodec_queueSecureInputBuffer( 486 AMediaCodec* codec, 487 size_t idx, 488 off_t offset, 489 AMediaCodecCryptoInfo* crypto, 490 uint64_t time, 491 uint32_t flags) { 492 493 CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples]; 494 for (int i = 0; i < crypto->numsubsamples; i++) { 495 subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i]; 496 subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i]; 497 } 498 499 CryptoPlugin::Pattern pattern; 500 pattern.mEncryptBlocks = crypto->pattern.encryptBlocks; 501 pattern.mSkipBlocks = crypto->pattern.skipBlocks; 502 503 AString errormsg; 504 status_t err = codec->mCodec->queueSecureInputBuffer(idx, 505 offset, 506 subSamples, 507 crypto->numsubsamples, 508 crypto->key, 509 crypto->iv, 510 (CryptoPlugin::Mode)crypto->mode, 511 pattern, 512 time, 513 flags, 514 &errormsg); 515 if (err != 0) { 516 ALOGE("queSecureInputBuffer: %s", errormsg.c_str()); 517 } 518 delete [] subSamples; 519 return translate_error(err); 520} 521 522 523EXPORT 524void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info, 525 cryptoinfo_pattern_t *pattern) { 526 info->pattern.encryptBlocks = pattern->encryptBlocks; 527 info->pattern.skipBlocks = pattern->skipBlocks; 528} 529 530EXPORT 531AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( 532 int numsubsamples, 533 uint8_t key[16], 534 uint8_t iv[16], 535 cryptoinfo_mode_t mode, 536 size_t *clearbytes, 537 size_t *encryptedbytes) { 538 539 // size needed to store all the crypto data 540 size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2; 541 AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize); 542 if (!ret) { 543 ALOGE("couldn't allocate %zu bytes", cryptosize); 544 return NULL; 545 } 546 ret->numsubsamples = numsubsamples; 547 memcpy(ret->key, key, 16); 548 memcpy(ret->iv, iv, 16); 549 ret->mode = mode; 550 ret->pattern.encryptBlocks = 0; 551 ret->pattern.skipBlocks = 0; 552 553 // clearbytes and encryptedbytes point at the actual data, which follows 554 ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct 555 ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes 556 557 memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t)); 558 memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t)); 559 560 return ret; 561} 562 563 564EXPORT 565media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) { 566 free(info); 567 return AMEDIA_OK; 568} 569 570EXPORT 571size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) { 572 return ci->numsubsamples; 573} 574 575EXPORT 576media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) { 577 if (!ci) { 578 return AMEDIA_ERROR_INVALID_OBJECT; 579 } 580 if (!dst) { 581 return AMEDIA_ERROR_INVALID_PARAMETER; 582 } 583 memcpy(dst, ci->key, 16); 584 return AMEDIA_OK; 585} 586 587EXPORT 588media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) { 589 if (!ci) { 590 return AMEDIA_ERROR_INVALID_OBJECT; 591 } 592 if (!dst) { 593 return AMEDIA_ERROR_INVALID_PARAMETER; 594 } 595 memcpy(dst, ci->iv, 16); 596 return AMEDIA_OK; 597} 598 599EXPORT 600cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { 601 if (!ci) { 602 return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT; 603 } 604 return ci->mode; 605} 606 607EXPORT 608media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { 609 if (!ci) { 610 return AMEDIA_ERROR_INVALID_OBJECT; 611 } 612 if (!dst) { 613 return AMEDIA_ERROR_INVALID_PARAMETER; 614 } 615 memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples); 616 return AMEDIA_OK; 617} 618 619EXPORT 620media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { 621 if (!ci) { 622 return AMEDIA_ERROR_INVALID_OBJECT; 623 } 624 if (!dst) { 625 return AMEDIA_ERROR_INVALID_PARAMETER; 626 } 627 memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples); 628 return AMEDIA_OK; 629} 630 631} // extern "C" 632 633