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