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