NdkMediaCodec.cpp revision 8c35da50221e6d87e49c13ad2f058f265b3b29c4
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 38using namespace android; 39 40 41static 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 51enum { 52 kWhatActivityNotify, 53 kWhatRequestActivityNotifications, 54 kWhatStopActivityNotifications, 55}; 56 57 58class CodecHandler: public AHandler { 59private: 60 AMediaCodec* mCodec; 61public: 62 CodecHandler(AMediaCodec *codec); 63 virtual void onMessageReceived(const sp<AMessage> &msg); 64}; 65 66typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata); 67 68struct 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 79CodecHandler::CodecHandler(AMediaCodec *codec) { 80 mCodec = codec; 81} 82 83void 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 138static void requestActivityNotification(AMediaCodec *codec) { 139 (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post(); 140} 141 142extern "C" { 143 144static 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 170EXPORT 171AMediaCodec* AMediaCodec_createCodecByName(const char *name) { 172 return createAMediaCodec(name, false, false); 173} 174 175EXPORT 176AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) { 177 return createAMediaCodec(mime_type, true, false); 178} 179 180EXPORT 181AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { 182 return createAMediaCodec(name, true, true); 183} 184 185EXPORT 186media_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 205EXPORT 206media_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 224EXPORT 225media_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 236EXPORT 237media_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 248EXPORT 249media_status_t AMediaCodec_flush(AMediaCodec *mData) { 250 return translate_error(mData->mCodec->flush()); 251} 252 253EXPORT 254ssize_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 264EXPORT 265uint8_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 282EXPORT 283uint8_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 300EXPORT 301media_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 309EXPORT 310ssize_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 339EXPORT 340AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { 341 sp<AMessage> format; 342 mData->mCodec->getOutputFormat(&format); 343 return AMediaFormat_fromMsg(&format); 344} 345 346EXPORT 347media_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 355EXPORT 356media_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 362EXPORT 363media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) { 364 sp<Surface> surface = NULL; 365 if (window != NULL) { 366 surface = (Surface*) window; 367 } 368 return translate_error(mData->mCodec->setSurface(surface)); 369} 370 371//EXPORT 372media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, 373 void *userdata) { 374 mData->mCallback = callback; 375 mData->mCallbackUserData = userdata; 376 return AMEDIA_OK; 377} 378 379typedef struct AMediaCodecCryptoInfo { 380 int numsubsamples; 381 uint8_t key[16]; 382 uint8_t iv[16]; 383 cryptoinfo_mode_t mode; 384 cryptoinfo_pattern_t pattern; 385 size_t *clearbytes; 386 size_t *encryptedbytes; 387} AMediaCodecCryptoInfo; 388 389EXPORT 390media_status_t AMediaCodec_queueSecureInputBuffer( 391 AMediaCodec* codec, 392 size_t idx, 393 off_t offset, 394 AMediaCodecCryptoInfo* crypto, 395 uint64_t time, 396 uint32_t flags) { 397 398 CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples]; 399 for (int i = 0; i < crypto->numsubsamples; i++) { 400 subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i]; 401 subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i]; 402 } 403 404 CryptoPlugin::Pattern pattern; 405 pattern.mEncryptBlocks = crypto->pattern.encryptBlocks; 406 pattern.mSkipBlocks = crypto->pattern.skipBlocks; 407 408 AString errormsg; 409 status_t err = codec->mCodec->queueSecureInputBuffer(idx, 410 offset, 411 subSamples, 412 crypto->numsubsamples, 413 crypto->key, 414 crypto->iv, 415 (CryptoPlugin::Mode)crypto->mode, 416 pattern, 417 time, 418 flags, 419 &errormsg); 420 if (err != 0) { 421 ALOGE("queSecureInputBuffer: %s", errormsg.c_str()); 422 } 423 delete [] subSamples; 424 return translate_error(err); 425} 426 427 428EXPORT 429void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info, 430 cryptoinfo_pattern_t *pattern) { 431 info->pattern.encryptBlocks = pattern->encryptBlocks; 432 info->pattern.skipBlocks = pattern->skipBlocks; 433} 434 435EXPORT 436AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( 437 int numsubsamples, 438 uint8_t key[16], 439 uint8_t iv[16], 440 cryptoinfo_mode_t mode, 441 size_t *clearbytes, 442 size_t *encryptedbytes) { 443 444 // size needed to store all the crypto data 445 size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2; 446 AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize); 447 if (!ret) { 448 ALOGE("couldn't allocate %zu bytes", cryptosize); 449 return NULL; 450 } 451 ret->numsubsamples = numsubsamples; 452 memcpy(ret->key, key, 16); 453 memcpy(ret->iv, iv, 16); 454 ret->mode = mode; 455 ret->pattern.encryptBlocks = 0; 456 ret->pattern.skipBlocks = 0; 457 458 // clearbytes and encryptedbytes point at the actual data, which follows 459 ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct 460 ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes 461 462 memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t)); 463 memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t)); 464 465 return ret; 466} 467 468 469EXPORT 470media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) { 471 free(info); 472 return AMEDIA_OK; 473} 474 475EXPORT 476size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) { 477 return ci->numsubsamples; 478} 479 480EXPORT 481media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_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->key, 16); 489 return AMEDIA_OK; 490} 491 492EXPORT 493media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_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->iv, 16); 501 return AMEDIA_OK; 502} 503 504EXPORT 505cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { 506 if (!ci) { 507 return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT; 508 } 509 return ci->mode; 510} 511 512EXPORT 513media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { 514 if (!ci) { 515 return AMEDIA_ERROR_INVALID_OBJECT; 516 } 517 if (!dst) { 518 return AMEDIA_ERROR_INVALID_PARAMETER; 519 } 520 memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples); 521 return AMEDIA_OK; 522} 523 524EXPORT 525media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { 526 if (!ci) { 527 return AMEDIA_ERROR_INVALID_OBJECT; 528 } 529 if (!dst) { 530 return AMEDIA_ERROR_INVALID_PARAMETER; 531 } 532 memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples); 533 return AMEDIA_OK; 534} 535 536} // extern "C" 537 538