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