NdkMediaCodec.cpp revision 829e097f832b4c4c41733f9b77121888204d993e
17624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko/* 27624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * Copyright (C) 2014 The Android Open Source Project 37624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * 47624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * Licensed under the Apache License, Version 2.0 (the "License"); 57624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * you may not use this file except in compliance with the License. 67624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * You may obtain a copy of the License at 77624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * 87624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * http://www.apache.org/licenses/LICENSE-2.0 97624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * 107624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * Unless required by applicable law or agreed to in writing, software 117624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * distributed under the License is distributed on an "AS IS" BASIS, 127624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * See the License for the specific language governing permissions and 147624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko * limitations under the License. 157624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko */ 167624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko 177624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#define LOG_NDEBUG 0 187624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#define LOG_TAG "NdkMediaCodec" 197624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko 2080afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko#include "NdkMediaCodec.h" 217624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#include "NdkMediaError.h" 227624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#include "NdkMediaCryptoPriv.h" 237624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#include "NdkMediaFormatPriv.h" 247624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko 257624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#include <utils/Log.h> 267624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#include <utils/StrongPointer.h> 277624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#include <gui/Surface.h> 287624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko 297624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#include <media/stagefright/foundation/ALooper.h> 307624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#include <media/stagefright/foundation/AMessage.h> 317624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#include <media/stagefright/foundation/ABuffer.h> 327624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko 337624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#include <media/stagefright/MediaCodec.h> 347624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#include <media/stagefright/MediaErrors.h> 357624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko 367624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Markousing namespace android; 377624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko 38c380191f3048db2a3796d65db8e5d5a5e7b08c65Serguei Katkov 39c380191f3048db2a3796d65db8e5d5a5e7b08c65Serguei Katkovstatic int translate_error(status_t err) { 40c380191f3048db2a3796d65db8e5d5a5e7b08c65Serguei Katkov if (err == OK) { 417624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko return OK; 427624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko } else if (err == -EAGAIN) { 437624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko return AMEDIACODEC_INFO_TRY_AGAIN_LATER; 447624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko } 457624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko ALOGE("sf error code: %d", err); 467624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko return AMEDIAERROR_GENERIC; 477624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko} 487624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko 49c380191f3048db2a3796d65db8e5d5a5e7b08c65Serguei Katkovenum { 50c380191f3048db2a3796d65db8e5d5a5e7b08c65Serguei Katkov kWhatActivityNotify, 517624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko kWhatRequestActivityNotifications, 527624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko kWhatStopActivityNotifications, 537624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko}; 547624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko 557624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko 56542451cc546779f5c67840e105c51205a1b0a8fdAndreas Gampeclass CodecHandler: public AHandler { 577624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Markoprivate: 587624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko AMediaCodec* mCodec; 597624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Markopublic: 607624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko CodecHandler(AMediaCodec *codec); 617624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko virtual void onMessageReceived(const sp<AMessage> &msg); 627624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko}; 637624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko 647624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Markostruct AMediaCodec { 657624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko sp<android::MediaCodec> mCodec; 667624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko sp<ALooper> mLooper; 677624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko sp<CodecHandler> mHandler; 687624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko sp<AMessage> mActivityNotification; 69 int32_t mGeneration; 70 bool mRequestedActivityNotification; 71 OnCodecEvent mCallback; 72 void *mCallbackUserData; 73}; 74 75CodecHandler::CodecHandler(AMediaCodec *codec) { 76 mCodec = codec; 77} 78 79void CodecHandler::onMessageReceived(const sp<AMessage> &msg) { 80 81 switch (msg->what()) { 82 case kWhatRequestActivityNotifications: 83 { 84 if (mCodec->mRequestedActivityNotification) { 85 break; 86 } 87 88 mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification); 89 mCodec->mRequestedActivityNotification = true; 90 break; 91 } 92 93 case kWhatActivityNotify: 94 { 95 { 96 int32_t generation; 97 msg->findInt32("generation", &generation); 98 99 if (generation != mCodec->mGeneration) { 100 // stale 101 break; 102 } 103 104 mCodec->mRequestedActivityNotification = false; 105 } 106 107 if (mCodec->mCallback) { 108 mCodec->mCallback(mCodec, mCodec->mCallbackUserData); 109 } 110 break; 111 } 112 113 case kWhatStopActivityNotifications: 114 { 115 uint32_t replyID; 116 msg->senderAwaitsResponse(&replyID); 117 118 mCodec->mGeneration++; 119 mCodec->mRequestedActivityNotification = false; 120 121 sp<AMessage> response = new AMessage; 122 response->postReply(replyID); 123 break; 124 } 125 126 default: 127 ALOGE("shouldn't be here"); 128 break; 129 } 130 131} 132 133 134static void requestActivityNotification(AMediaCodec *codec) { 135 (new AMessage(kWhatRequestActivityNotifications, codec->mHandler->id()))->post(); 136} 137 138extern "C" { 139 140static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool encoder) { 141 AMediaCodec *mData = new AMediaCodec(); 142 mData->mLooper = new ALooper; 143 mData->mLooper->setName("NDK MediaCodec_looper"); 144 status_t ret = mData->mLooper->start( 145 false, // runOnCallingThread 146 true, // canCallJava XXX 147 PRIORITY_FOREGROUND); 148 if (name_is_type) { 149 mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder); 150 } else { 151 mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name); 152 } 153 mData->mHandler = new CodecHandler(mData); 154 mData->mLooper->registerHandler(mData->mHandler); 155 mData->mGeneration = 1; 156 mData->mRequestedActivityNotification = false; 157 mData->mCallback = NULL; 158 159 return mData; 160} 161 162 163AMediaCodec* AMediaCodec_createCodecByName(const char *name) { 164 return createAMediaCodec(name, false, false); 165} 166 167AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) { 168 return createAMediaCodec(mime_type, true, false); 169} 170 171AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { 172 return createAMediaCodec(name, true, true); 173} 174 175int AMediaCodec_delete(AMediaCodec *mData) { 176 if (mData->mCodec != NULL) { 177 mData->mCodec->release(); 178 mData->mCodec.clear(); 179 } 180 181 if (mData->mLooper != NULL) { 182 mData->mLooper->unregisterHandler(mData->mHandler->id()); 183 mData->mLooper->stop(); 184 mData->mLooper.clear(); 185 } 186 delete mData; 187 return OK; 188} 189 190int AMediaCodec_configure( 191 AMediaCodec *mData, 192 const AMediaFormat* format, 193 ANativeWindow* window, 194 AMediaCrypto *crypto, 195 uint32_t flags) { 196 sp<AMessage> nativeFormat; 197 AMediaFormat_getFormat(format, &nativeFormat); 198 ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); 199 sp<Surface> surface = NULL; 200 if (window != NULL) { 201 surface = (Surface*) window; 202 } 203 204 return translate_error(mData->mCodec->configure(nativeFormat, surface, 205 crypto ? crypto->mCrypto : NULL, flags)); 206} 207 208int AMediaCodec_start(AMediaCodec *mData) { 209 status_t ret = mData->mCodec->start(); 210 if (ret != OK) { 211 return translate_error(ret); 212 } 213 mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler->id()); 214 mData->mActivityNotification->setInt32("generation", mData->mGeneration); 215 requestActivityNotification(mData); 216 return OK; 217} 218 219int AMediaCodec_stop(AMediaCodec *mData) { 220 int ret = translate_error(mData->mCodec->stop()); 221 222 sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler->id()); 223 sp<AMessage> response; 224 msg->postAndAwaitResponse(&response); 225 mData->mActivityNotification.clear(); 226 227 return ret; 228} 229 230int AMediaCodec_flush(AMediaCodec *mData) { 231 return translate_error(mData->mCodec->flush()); 232} 233 234ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { 235 size_t idx; 236 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs); 237 requestActivityNotification(mData); 238 if (ret == OK) { 239 return idx; 240 } 241 return translate_error(ret); 242} 243 244uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 245 android::Vector<android::sp<android::ABuffer> > abufs; 246 if (mData->mCodec->getInputBuffers(&abufs) == 0) { 247 size_t n = abufs.size(); 248 if (idx >= n) { 249 ALOGE("buffer index %d out of range", idx); 250 return NULL; 251 } 252 if (out_size != NULL) { 253 *out_size = abufs[idx]->capacity(); 254 } 255 return abufs[idx]->data(); 256 } 257 ALOGE("couldn't get input buffers"); 258 return NULL; 259} 260 261uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 262 android::Vector<android::sp<android::ABuffer> > abufs; 263 if (mData->mCodec->getOutputBuffers(&abufs) == 0) { 264 size_t n = abufs.size(); 265 if (idx >= n) { 266 ALOGE("buffer index %d out of range", idx); 267 return NULL; 268 } 269 if (out_size != NULL) { 270 *out_size = abufs[idx]->capacity(); 271 } 272 return abufs[idx]->data(); 273 } 274 ALOGE("couldn't get output buffers"); 275 return NULL; 276} 277 278int AMediaCodec_queueInputBuffer(AMediaCodec *mData, 279 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { 280 281 AString errorMsg; 282 status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg); 283 return translate_error(ret); 284} 285 286ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData, 287 AMediaCodecBufferInfo *info, int64_t timeoutUs) { 288 size_t idx; 289 size_t offset; 290 size_t size; 291 uint32_t flags; 292 int64_t presentationTimeUs; 293 status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs, 294 &flags, timeoutUs); 295 requestActivityNotification(mData); 296 switch (ret) { 297 case OK: 298 info->offset = offset; 299 info->size = size; 300 info->flags = flags; 301 info->presentationTimeUs = presentationTimeUs; 302 return idx; 303 case -EAGAIN: 304 return AMEDIACODEC_INFO_TRY_AGAIN_LATER; 305 case android::INFO_FORMAT_CHANGED: 306 return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED; 307 case INFO_OUTPUT_BUFFERS_CHANGED: 308 return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED; 309 default: 310 break; 311 } 312 return translate_error(ret); 313} 314 315AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { 316 sp<AMessage> format; 317 mData->mCodec->getOutputFormat(&format); 318 return AMediaFormat_fromMsg(&format); 319} 320 321int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) { 322 if (render) { 323 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx)); 324 } else { 325 return translate_error(mData->mCodec->releaseOutputBuffer(idx)); 326 } 327} 328 329int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) { 330 mData->mCallback = callback; 331 mData->mCallbackUserData = userdata; 332 return OK; 333} 334 335typedef struct AMediaCodecCryptoInfo { 336 int numsubsamples; 337 uint8_t key[16]; 338 uint8_t iv[16]; 339 uint32_t mode; 340 size_t *clearbytes; 341 size_t *encryptedbytes; 342} AMediaCodecCryptoInfo; 343 344int AMediaCodec_queueSecureInputBuffer( 345 AMediaCodec* codec, 346 size_t idx, 347 off_t offset, 348 AMediaCodecCryptoInfo* crypto, 349 uint64_t time, 350 uint32_t flags) { 351 352 CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples]; 353 for (int i = 0; i < crypto->numsubsamples; i++) { 354 subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i]; 355 subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i]; 356 } 357 358 AString errormsg; 359 status_t err = codec->mCodec->queueSecureInputBuffer(idx, 360 offset, 361 subSamples, 362 crypto->numsubsamples, 363 crypto->key, 364 crypto->iv, 365 (CryptoPlugin::Mode) crypto->mode, 366 time, 367 flags, 368 &errormsg); 369 if (err != 0) { 370 ALOGE("queSecureInputBuffer: %s", errormsg.c_str()); 371 } 372 delete [] subSamples; 373 return translate_error(err); 374} 375 376 377 378AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( 379 int numsubsamples, 380 uint8_t key[16], 381 uint8_t iv[16], 382 uint32_t mode, 383 size_t *clearbytes, 384 size_t *encryptedbytes) { 385 386 // size needed to store all the crypto data 387 size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2; 388 AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize); 389 if (!ret) { 390 ALOGE("couldn't allocate %d bytes", cryptosize); 391 return NULL; 392 } 393 ret->numsubsamples = numsubsamples; 394 memcpy(ret->key, key, 16); 395 memcpy(ret->iv, iv, 16); 396 ret->mode = mode; 397 398 // clearbytes and encryptedbytes point at the actual data, which follows 399 ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct 400 ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes 401 402 memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t)); 403 memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t)); 404 405 return ret; 406} 407 408 409int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) { 410 free(info); 411 return OK; 412} 413 414size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) { 415 return ci->numsubsamples; 416} 417 418int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) { 419 if (!dst || !ci) { 420 return AMEDIAERROR_UNSUPPORTED; 421 } 422 memcpy(dst, ci->key, 16); 423 return OK; 424} 425 426int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) { 427 if (!dst || !ci) { 428 return AMEDIAERROR_UNSUPPORTED; 429 } 430 memcpy(dst, ci->iv, 16); 431 return OK; 432} 433 434uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { 435 if (!ci) { 436 return AMEDIAERROR_UNSUPPORTED; 437 } 438 return ci->mode; 439} 440 441int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { 442 if (!dst || !ci) { 443 return AMEDIAERROR_UNSUPPORTED; 444 } 445 memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples); 446 return OK; 447} 448 449int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { 450 if (!dst || !ci) { 451 return AMEDIAERROR_UNSUPPORTED; 452 } 453 memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples); 454 return OK; 455} 456 457} // extern "C" 458 459