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 status_t ret = mData->mLooper->start( 149 false, // runOnCallingThread 150 true, // canCallJava XXX 151 PRIORITY_FOREGROUND); 152 if (name_is_type) { 153 mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder); 154 } else { 155 mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name); 156 } 157 if (mData->mCodec == NULL) { // failed to create codec 158 AMediaCodec_delete(mData); 159 return NULL; 160 } 161 mData->mHandler = new CodecHandler(mData); 162 mData->mLooper->registerHandler(mData->mHandler); 163 mData->mGeneration = 1; 164 mData->mRequestedActivityNotification = false; 165 mData->mCallback = NULL; 166 167 return mData; 168 } 169 170 EXPORT 171 AMediaCodec* AMediaCodec_createCodecByName(const char *name) { 172 return createAMediaCodec(name, false, false); 173 } 174 175 EXPORT 176 AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) { 177 return createAMediaCodec(mime_type, true, false); 178 } 179 180 EXPORT 181 AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { 182 return createAMediaCodec(name, true, true); 183 } 184 185 EXPORT 186 media_status_t AMediaCodec_delete(AMediaCodec *mData) { 187 if (mData != NULL) { 188 if (mData->mCodec != NULL) { 189 mData->mCodec->release(); 190 mData->mCodec.clear(); 191 } 192 193 if (mData->mLooper != NULL) { 194 if (mData->mHandler != NULL) { 195 mData->mLooper->unregisterHandler(mData->mHandler->id()); 196 } 197 mData->mLooper->stop(); 198 mData->mLooper.clear(); 199 } 200 delete mData; 201 } 202 return AMEDIA_OK; 203 } 204 205 EXPORT 206 media_status_t AMediaCodec_configure( 207 AMediaCodec *mData, 208 const AMediaFormat* format, 209 ANativeWindow* window, 210 AMediaCrypto *crypto, 211 uint32_t flags) { 212 sp<AMessage> nativeFormat; 213 AMediaFormat_getFormat(format, &nativeFormat); 214 ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); 215 sp<Surface> surface = NULL; 216 if (window != NULL) { 217 surface = (Surface*) window; 218 } 219 220 return translate_error(mData->mCodec->configure(nativeFormat, surface, 221 crypto ? crypto->mCrypto : NULL, flags)); 222 } 223 224 EXPORT 225 media_status_t AMediaCodec_start(AMediaCodec *mData) { 226 status_t ret = mData->mCodec->start(); 227 if (ret != OK) { 228 return translate_error(ret); 229 } 230 mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler); 231 mData->mActivityNotification->setInt32("generation", mData->mGeneration); 232 requestActivityNotification(mData); 233 return AMEDIA_OK; 234 } 235 236 EXPORT 237 media_status_t AMediaCodec_stop(AMediaCodec *mData) { 238 media_status_t ret = translate_error(mData->mCodec->stop()); 239 240 sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler); 241 sp<AMessage> response; 242 msg->postAndAwaitResponse(&response); 243 mData->mActivityNotification.clear(); 244 245 return ret; 246 } 247 248 EXPORT 249 media_status_t AMediaCodec_flush(AMediaCodec *mData) { 250 return translate_error(mData->mCodec->flush()); 251 } 252 253 EXPORT 254 ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { 255 size_t idx; 256 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs); 257 requestActivityNotification(mData); 258 if (ret == OK) { 259 return idx; 260 } 261 return translate_error(ret); 262 } 263 264 EXPORT 265 uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 266 android::Vector<android::sp<android::ABuffer> > abufs; 267 if (mData->mCodec->getInputBuffers(&abufs) == 0) { 268 size_t n = abufs.size(); 269 if (idx >= n) { 270 ALOGE("buffer index %zu out of range", idx); 271 return NULL; 272 } 273 if (out_size != NULL) { 274 *out_size = abufs[idx]->capacity(); 275 } 276 return abufs[idx]->data(); 277 } 278 ALOGE("couldn't get input buffers"); 279 return NULL; 280 } 281 282 EXPORT 283 uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 284 android::Vector<android::sp<android::ABuffer> > abufs; 285 if (mData->mCodec->getOutputBuffers(&abufs) == 0) { 286 size_t n = abufs.size(); 287 if (idx >= n) { 288 ALOGE("buffer index %zu out of range", idx); 289 return NULL; 290 } 291 if (out_size != NULL) { 292 *out_size = abufs[idx]->capacity(); 293 } 294 return abufs[idx]->data(); 295 } 296 ALOGE("couldn't get output buffers"); 297 return NULL; 298 } 299 300 EXPORT 301 media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData, 302 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { 303 304 AString errorMsg; 305 status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg); 306 return translate_error(ret); 307 } 308 309 EXPORT 310 ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData, 311 AMediaCodecBufferInfo *info, int64_t timeoutUs) { 312 size_t idx; 313 size_t offset; 314 size_t size; 315 uint32_t flags; 316 int64_t presentationTimeUs; 317 status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs, 318 &flags, timeoutUs); 319 requestActivityNotification(mData); 320 switch (ret) { 321 case OK: 322 info->offset = offset; 323 info->size = size; 324 info->flags = flags; 325 info->presentationTimeUs = presentationTimeUs; 326 return idx; 327 case -EAGAIN: 328 return AMEDIACODEC_INFO_TRY_AGAIN_LATER; 329 case android::INFO_FORMAT_CHANGED: 330 return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED; 331 case INFO_OUTPUT_BUFFERS_CHANGED: 332 return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED; 333 default: 334 break; 335 } 336 return translate_error(ret); 337 } 338 339 EXPORT 340 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { 341 sp<AMessage> format; 342 mData->mCodec->getOutputFormat(&format); 343 return AMediaFormat_fromMsg(&format); 344 } 345 346 EXPORT 347 media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) { 348 if (render) { 349 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx)); 350 } else { 351 return translate_error(mData->mCodec->releaseOutputBuffer(idx)); 352 } 353 } 354 355 EXPORT 356 media_status_t AMediaCodec_releaseOutputBufferAtTime( 357 AMediaCodec *mData, size_t idx, int64_t timestampNs) { 358 ALOGV("render @ %" PRId64, timestampNs); 359 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs)); 360 } 361 362 //EXPORT 363 media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, 364 void *userdata) { 365 mData->mCallback = callback; 366 mData->mCallbackUserData = userdata; 367 return AMEDIA_OK; 368 } 369 370 typedef struct AMediaCodecCryptoInfo { 371 int numsubsamples; 372 uint8_t key[16]; 373 uint8_t iv[16]; 374 cryptoinfo_mode_t mode; 375 size_t *clearbytes; 376 size_t *encryptedbytes; 377 } AMediaCodecCryptoInfo; 378 379 EXPORT 380 media_status_t AMediaCodec_queueSecureInputBuffer( 381 AMediaCodec* codec, 382 size_t idx, 383 off_t offset, 384 AMediaCodecCryptoInfo* crypto, 385 uint64_t time, 386 uint32_t flags) { 387 388 CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples]; 389 for (int i = 0; i < crypto->numsubsamples; i++) { 390 subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i]; 391 subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i]; 392 } 393 394 AString errormsg; 395 status_t err = codec->mCodec->queueSecureInputBuffer(idx, 396 offset, 397 subSamples, 398 crypto->numsubsamples, 399 crypto->key, 400 crypto->iv, 401 (CryptoPlugin::Mode) crypto->mode, 402 time, 403 flags, 404 &errormsg); 405 if (err != 0) { 406 ALOGE("queSecureInputBuffer: %s", errormsg.c_str()); 407 } 408 delete [] subSamples; 409 return translate_error(err); 410 } 411 412 413 414 EXPORT 415 AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( 416 int numsubsamples, 417 uint8_t key[16], 418 uint8_t iv[16], 419 cryptoinfo_mode_t mode, 420 size_t *clearbytes, 421 size_t *encryptedbytes) { 422 423 // size needed to store all the crypto data 424 size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2; 425 AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize); 426 if (!ret) { 427 ALOGE("couldn't allocate %zu bytes", cryptosize); 428 return NULL; 429 } 430 ret->numsubsamples = numsubsamples; 431 memcpy(ret->key, key, 16); 432 memcpy(ret->iv, iv, 16); 433 ret->mode = mode; 434 435 // clearbytes and encryptedbytes point at the actual data, which follows 436 ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct 437 ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes 438 439 memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t)); 440 memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t)); 441 442 return ret; 443 } 444 445 446 EXPORT 447 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) { 448 free(info); 449 return AMEDIA_OK; 450 } 451 452 EXPORT 453 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) { 454 return ci->numsubsamples; 455 } 456 457 EXPORT 458 media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) { 459 if (!ci) { 460 return AMEDIA_ERROR_INVALID_OBJECT; 461 } 462 if (!dst) { 463 return AMEDIA_ERROR_INVALID_PARAMETER; 464 } 465 memcpy(dst, ci->key, 16); 466 return AMEDIA_OK; 467 } 468 469 EXPORT 470 media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) { 471 if (!ci) { 472 return AMEDIA_ERROR_INVALID_OBJECT; 473 } 474 if (!dst) { 475 return AMEDIA_ERROR_INVALID_PARAMETER; 476 } 477 memcpy(dst, ci->iv, 16); 478 return AMEDIA_OK; 479 } 480 481 EXPORT 482 cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { 483 if (!ci) { 484 return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT; 485 } 486 return ci->mode; 487 } 488 489 EXPORT 490 media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { 491 if (!ci) { 492 return AMEDIA_ERROR_INVALID_OBJECT; 493 } 494 if (!dst) { 495 return AMEDIA_ERROR_INVALID_PARAMETER; 496 } 497 memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples); 498 return AMEDIA_OK; 499 } 500 501 EXPORT 502 media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { 503 if (!ci) { 504 return AMEDIA_ERROR_INVALID_OBJECT; 505 } 506 if (!dst) { 507 return AMEDIA_ERROR_INVALID_PARAMETER; 508 } 509 memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples); 510 return AMEDIA_OK; 511 } 512 513 } // extern "C" 514 515