codec.cpp revision 4b75a9c8b93a90749bc5d22912ad0d96c12f4ecf
1/* 2 * Copyright (C) 2012 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 "codec" 19#include <utils/Log.h> 20 21#include "SimplePlayer.h" 22 23#include <binder/IServiceManager.h> 24#include <binder/ProcessState.h> 25#include <media/ICrypto.h> 26#include <media/IMediaPlayerService.h> 27#include <media/stagefright/foundation/ABuffer.h> 28#include <media/stagefright/foundation/ADebug.h> 29#include <media/stagefright/foundation/ALooper.h> 30#include <media/stagefright/foundation/AMessage.h> 31#include <media/stagefright/DataSource.h> 32#include <media/stagefright/MediaCodec.h> 33#include <media/stagefright/MediaCodecList.h> 34#include <media/stagefright/MediaDefs.h> 35#include <media/stagefright/NuMediaExtractor.h> 36#include <gui/SurfaceComposerClient.h> 37 38static void usage(const char *me) { 39 fprintf(stderr, "usage: %s [-a] use audio\n" 40 "\t\t[-v] use video\n" 41 "\t\t[-p] playback\n" 42 "\t\t[-S] allocate buffers from a surface\n" 43 "\t\t[-D] decrypt input buffers\n", 44 me); 45 46 exit(1); 47} 48 49namespace android { 50 51struct CodecState { 52 sp<MediaCodec> mCodec; 53 Vector<sp<ABuffer> > mCSD; 54 size_t mCSDIndex; 55 Vector<sp<ABuffer> > mInBuffers; 56 Vector<sp<ABuffer> > mOutBuffers; 57 bool mSignalledInputEOS; 58 bool mSawOutputEOS; 59 int64_t mNumBuffersDecoded; 60 int64_t mNumBytesDecoded; 61 bool mIsAudio; 62}; 63 64static sp<ICrypto> makeCrypto( 65 const uint8_t uuid[16], const void *data, size_t size) { 66 sp<IServiceManager> sm = defaultServiceManager(); 67 68 sp<IBinder> binder = 69 sm->getService(String16("media.player")); 70 71 sp<IMediaPlayerService> service = 72 interface_cast<IMediaPlayerService>(binder); 73 74 CHECK(service != NULL); 75 76 sp<ICrypto> crypto = service->makeCrypto(); 77 78 if (crypto == NULL || crypto->initCheck() != OK) { 79 return NULL; 80 } 81 82 status_t err = crypto->createPlugin(uuid, data, size); 83 84 if (err != OK) { 85 return NULL; 86 } 87 88 return crypto; 89} 90 91} // namespace android 92 93static int decode( 94 const android::sp<android::ALooper> &looper, 95 const char *path, 96 bool useAudio, 97 bool useVideo, 98 const android::sp<android::Surface> &surface, 99 bool decryptInputBuffers) { 100 using namespace android; 101 102 static int64_t kTimeout = 500ll; 103 104 sp<NuMediaExtractor> extractor = new NuMediaExtractor; 105 if (extractor->setDataSource(path) != OK) { 106 fprintf(stderr, "unable to instantiate extractor.\n"); 107 return 1; 108 } 109 110 sp<ICrypto> crypto; 111 112 KeyedVector<size_t, CodecState> stateByTrack; 113 114 bool haveAudio = false; 115 bool haveVideo = false; 116 for (size_t i = 0; i < extractor->countTracks(); ++i) { 117 sp<AMessage> format; 118 status_t err = extractor->getTrackFormat(i, &format); 119 CHECK_EQ(err, (status_t)OK); 120 121 AString mime; 122 CHECK(format->findString("mime", &mime)); 123 124 bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6); 125 bool isVideo = !strncasecmp(mime.c_str(), "video/", 6); 126 127 if (useAudio && !haveAudio && isAudio) { 128 haveAudio = true; 129 } else if (useVideo && !haveVideo && isVideo) { 130 haveVideo = true; 131 } else { 132 continue; 133 } 134 135 ALOGV("selecting track %d", i); 136 137 err = extractor->selectTrack(i); 138 CHECK_EQ(err, (status_t)OK); 139 140 CodecState *state = 141 &stateByTrack.editValueAt(stateByTrack.add(i, CodecState())); 142 143 state->mNumBytesDecoded = 0; 144 state->mNumBuffersDecoded = 0; 145 state->mIsAudio = isAudio; 146 147 if (decryptInputBuffers && crypto == NULL) { 148 sp<ABuffer> emm; 149 CHECK(format->findBuffer("emm", &emm)); 150 151 sp<ABuffer> ecm; 152 CHECK(format->findBuffer("ecm", &ecm)); 153 154 struct WVOpaqueInitData { 155 uint8_t mEMM[16]; 156 uint8_t mECM[32]; 157 158 } opaque; 159 160 CHECK_EQ(emm->size(), sizeof(opaque.mEMM)); 161 memcpy(opaque.mEMM, emm->data(), emm->size()); 162 163 CHECK_EQ(ecm->size(), 80u); 164 // bytes 16..47 of the original ecm stream data. 165 memcpy(opaque.mECM, ecm->data() + 16, 32); 166 167 static const uint8_t kUUIDWidevine[16] = { 168 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 169 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 170 }; 171 172 crypto = makeCrypto(kUUIDWidevine, &opaque, sizeof(opaque)); 173 CHECK(crypto != NULL); 174 CHECK_EQ(crypto->initCheck(), (status_t)OK); 175 } 176 177 if (decryptInputBuffers 178 && crypto->requiresSecureDecoderComponent(mime.c_str())) { 179 static const MediaCodecList *list = MediaCodecList::getInstance(); 180 181 ssize_t index = 182 list->findCodecByType(mime.c_str(), false /* encoder */); 183 184 CHECK_GE(index, 0); 185 186 const char *componentName = list->getCodecName(index); 187 188 AString fullName = componentName; 189 fullName.append(".secure"); 190 191 state->mCodec = MediaCodec::CreateByComponentName( 192 looper, fullName.c_str()); 193 } else { 194 state->mCodec = MediaCodec::CreateByType( 195 looper, mime.c_str(), false /* encoder */); 196 } 197 198 CHECK(state->mCodec != NULL); 199 200 err = state->mCodec->configure( 201 format, isVideo ? surface : NULL, 202 crypto, 203 0 /* flags */); 204 205 CHECK_EQ(err, (status_t)OK); 206 207 size_t j = 0; 208 sp<ABuffer> buffer; 209 while (format->findBuffer(StringPrintf("csd-%d", j).c_str(), &buffer)) { 210 state->mCSD.push_back(buffer); 211 212 ++j; 213 } 214 215 state->mCSDIndex = 0; 216 state->mSignalledInputEOS = false; 217 state->mSawOutputEOS = false; 218 219 ALOGV("got %d pieces of codec specific data.", state->mCSD.size()); 220 } 221 222 CHECK(!stateByTrack.isEmpty()); 223 224 int64_t startTimeUs = ALooper::GetNowUs(); 225 226 for (size_t i = 0; i < stateByTrack.size(); ++i) { 227 CodecState *state = &stateByTrack.editValueAt(i); 228 229 sp<MediaCodec> codec = state->mCodec; 230 231 CHECK_EQ((status_t)OK, codec->start()); 232 233 CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers)); 234 CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers)); 235 236 ALOGV("got %d input and %d output buffers", 237 state->mInBuffers.size(), state->mOutBuffers.size()); 238 239 while (state->mCSDIndex < state->mCSD.size()) { 240 size_t index; 241 status_t err = codec->dequeueInputBuffer(&index, -1ll); 242 CHECK_EQ(err, (status_t)OK); 243 244 const sp<ABuffer> &srcBuffer = 245 state->mCSD.itemAt(state->mCSDIndex++); 246 247 const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index); 248 249 memcpy(buffer->data(), srcBuffer->data(), srcBuffer->size()); 250 251 err = codec->queueInputBuffer( 252 index, 253 0 /* offset */, 254 srcBuffer->size(), 255 0ll /* timeUs */, 256 MediaCodec::BUFFER_FLAG_CODECCONFIG); 257 258 CHECK_EQ(err, (status_t)OK); 259 } 260 } 261 262 bool sawInputEOS = false; 263 264 for (;;) { 265 if (!sawInputEOS) { 266 size_t trackIndex; 267 status_t err = extractor->getSampleTrackIndex(&trackIndex); 268 269 if (err != OK) { 270 ALOGV("saw input eos"); 271 sawInputEOS = true; 272 } else { 273 CodecState *state = &stateByTrack.editValueFor(trackIndex); 274 275 size_t index; 276 err = state->mCodec->dequeueInputBuffer(&index, kTimeout); 277 278 if (err == OK) { 279 ALOGV("filling input buffer %d", index); 280 281 const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index); 282 283 err = extractor->readSampleData(buffer); 284 CHECK_EQ(err, (status_t)OK); 285 286 int64_t timeUs; 287 err = extractor->getSampleTime(&timeUs); 288 CHECK_EQ(err, (status_t)OK); 289 290 uint32_t bufferFlags = 0; 291 292 uint32_t sampleFlags; 293 err = extractor->getSampleFlags(&sampleFlags); 294 CHECK_EQ(err, (status_t)OK); 295 296 if (sampleFlags & NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED) { 297 CHECK(decryptInputBuffers); 298 299 CryptoPlugin::SubSample ss; 300 ss.mNumBytesOfClearData = 0; 301 ss.mNumBytesOfEncryptedData = buffer->size(); 302 303 err = state->mCodec->queueSecureInputBuffer( 304 index, 305 0 /* offset */, 306 &ss, 307 1 /* numSubSamples */, 308 NULL /* key */, 309 NULL /* iv */, 310 CryptoPlugin::kMode_AES_WV, 311 timeUs, 312 bufferFlags); 313 } else { 314 err = state->mCodec->queueInputBuffer( 315 index, 316 0 /* offset */, 317 buffer->size(), 318 timeUs, 319 bufferFlags); 320 } 321 322 CHECK_EQ(err, (status_t)OK); 323 324 extractor->advance(); 325 } else { 326 CHECK_EQ(err, -EAGAIN); 327 } 328 } 329 } else { 330 for (size_t i = 0; i < stateByTrack.size(); ++i) { 331 CodecState *state = &stateByTrack.editValueAt(i); 332 333 if (!state->mSignalledInputEOS) { 334 size_t index; 335 status_t err = 336 state->mCodec->dequeueInputBuffer(&index, kTimeout); 337 338 if (err == OK) { 339 ALOGV("signalling input EOS on track %d", i); 340 341 err = state->mCodec->queueInputBuffer( 342 index, 343 0 /* offset */, 344 0 /* size */, 345 0ll /* timeUs */, 346 MediaCodec::BUFFER_FLAG_EOS); 347 348 CHECK_EQ(err, (status_t)OK); 349 350 state->mSignalledInputEOS = true; 351 } else { 352 CHECK_EQ(err, -EAGAIN); 353 } 354 } 355 } 356 } 357 358 bool sawOutputEOSOnAllTracks = true; 359 for (size_t i = 0; i < stateByTrack.size(); ++i) { 360 CodecState *state = &stateByTrack.editValueAt(i); 361 if (!state->mSawOutputEOS) { 362 sawOutputEOSOnAllTracks = false; 363 break; 364 } 365 } 366 367 if (sawOutputEOSOnAllTracks) { 368 break; 369 } 370 371 for (size_t i = 0; i < stateByTrack.size(); ++i) { 372 CodecState *state = &stateByTrack.editValueAt(i); 373 374 if (state->mSawOutputEOS) { 375 continue; 376 } 377 378 size_t index; 379 size_t offset; 380 size_t size; 381 int64_t presentationTimeUs; 382 uint32_t flags; 383 status_t err = state->mCodec->dequeueOutputBuffer( 384 &index, &offset, &size, &presentationTimeUs, &flags, 385 kTimeout); 386 387 if (err == OK) { 388 ALOGV("draining output buffer %d, time = %lld us", 389 index, presentationTimeUs); 390 391 ++state->mNumBuffersDecoded; 392 state->mNumBytesDecoded += size; 393 394 err = state->mCodec->releaseOutputBuffer(index); 395 CHECK_EQ(err, (status_t)OK); 396 397 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 398 ALOGV("reached EOS on output."); 399 400 state->mSawOutputEOS = true; 401 } 402 } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) { 403 ALOGV("INFO_OUTPUT_BUFFERS_CHANGED"); 404 CHECK_EQ((status_t)OK, 405 state->mCodec->getOutputBuffers(&state->mOutBuffers)); 406 407 ALOGV("got %d output buffers", state->mOutBuffers.size()); 408 } else if (err == INFO_FORMAT_CHANGED) { 409 sp<AMessage> format; 410 CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format)); 411 412 ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str()); 413 } else { 414 CHECK_EQ(err, -EAGAIN); 415 } 416 } 417 } 418 419 int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs; 420 421 for (size_t i = 0; i < stateByTrack.size(); ++i) { 422 CodecState *state = &stateByTrack.editValueAt(i); 423 424 CHECK_EQ((status_t)OK, state->mCodec->release()); 425 426 if (state->mIsAudio) { 427 printf("track %d: %lld bytes received. %.2f KB/sec\n", 428 i, 429 state->mNumBytesDecoded, 430 state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs); 431 } else { 432 printf("track %d: %lld frames decoded, %.2f fps. %lld bytes " 433 "received. %.2f KB/sec\n", 434 i, 435 state->mNumBuffersDecoded, 436 state->mNumBuffersDecoded * 1E6 / elapsedTimeUs, 437 state->mNumBytesDecoded, 438 state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs); 439 } 440 } 441 442 return 0; 443} 444 445int main(int argc, char **argv) { 446 using namespace android; 447 448 const char *me = argv[0]; 449 450 bool useAudio = false; 451 bool useVideo = false; 452 bool playback = false; 453 bool useSurface = false; 454 bool decryptInputBuffers = false; 455 456 int res; 457 while ((res = getopt(argc, argv, "havpSD")) >= 0) { 458 switch (res) { 459 case 'a': 460 { 461 useAudio = true; 462 break; 463 } 464 465 case 'v': 466 { 467 useVideo = true; 468 break; 469 } 470 471 case 'p': 472 { 473 playback = true; 474 break; 475 } 476 477 case 'S': 478 { 479 useSurface = true; 480 break; 481 } 482 483 case 'D': 484 { 485 decryptInputBuffers = true; 486 break; 487 } 488 489 case '?': 490 case 'h': 491 default: 492 { 493 usage(me); 494 } 495 } 496 } 497 498 argc -= optind; 499 argv += optind; 500 501 if (argc != 1) { 502 usage(me); 503 } 504 505 if (!useAudio && !useVideo) { 506 useAudio = useVideo = true; 507 } 508 509 ProcessState::self()->startThreadPool(); 510 511 DataSource::RegisterDefaultSniffers(); 512 513 sp<ALooper> looper = new ALooper; 514 looper->start(); 515 516 sp<SurfaceComposerClient> composerClient; 517 sp<SurfaceControl> control; 518 sp<Surface> surface; 519 520 if (playback || (useSurface && useVideo)) { 521 composerClient = new SurfaceComposerClient; 522 CHECK_EQ(composerClient->initCheck(), (status_t)OK); 523 524 ssize_t displayWidth = composerClient->getDisplayWidth(0); 525 ssize_t displayHeight = composerClient->getDisplayHeight(0); 526 527 ALOGV("display is %ld x %ld\n", displayWidth, displayHeight); 528 529 control = composerClient->createSurface( 530 String8("A Surface"), 531 0, 532 displayWidth, 533 displayHeight, 534 PIXEL_FORMAT_RGB_565, 535 0); 536 537 CHECK(control != NULL); 538 CHECK(control->isValid()); 539 540 SurfaceComposerClient::openGlobalTransaction(); 541 CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK); 542 CHECK_EQ(control->show(), (status_t)OK); 543 SurfaceComposerClient::closeGlobalTransaction(); 544 545 surface = control->getSurface(); 546 CHECK(surface != NULL); 547 } 548 549 if (playback) { 550 sp<SimplePlayer> player = new SimplePlayer; 551 looper->registerHandler(player); 552 553 player->setDataSource(argv[0]); 554 player->setSurface(surface->getSurfaceTexture()); 555 player->start(); 556 sleep(60); 557 player->stop(); 558 player->reset(); 559 } else { 560 decode(looper, argv[0], 561 useAudio, useVideo, surface, decryptInputBuffers); 562 } 563 564 if (playback || (useSurface && useVideo)) { 565 composerClient->dispose(); 566 } 567 568 looper->stop(); 569 570 return 0; 571} 572