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