codec.cpp revision 1bd139a2a68690e80398b70b27ca59550fea0e65
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 bufferFlags |= MediaCodec::BUFFER_FLAG_ENCRYPTED; 300 } 301 302 err = state->mCodec->queueInputBuffer( 303 index, 304 0 /* offset */, 305 buffer->size(), 306 timeUs, 307 bufferFlags); 308 309 CHECK_EQ(err, (status_t)OK); 310 311 extractor->advance(); 312 } else { 313 CHECK_EQ(err, -EAGAIN); 314 } 315 } 316 } else { 317 for (size_t i = 0; i < stateByTrack.size(); ++i) { 318 CodecState *state = &stateByTrack.editValueAt(i); 319 320 if (!state->mSignalledInputEOS) { 321 size_t index; 322 status_t err = 323 state->mCodec->dequeueInputBuffer(&index, kTimeout); 324 325 if (err == OK) { 326 ALOGV("signalling input EOS on track %d", i); 327 328 err = state->mCodec->queueInputBuffer( 329 index, 330 0 /* offset */, 331 0 /* size */, 332 0ll /* timeUs */, 333 MediaCodec::BUFFER_FLAG_EOS); 334 335 CHECK_EQ(err, (status_t)OK); 336 337 state->mSignalledInputEOS = true; 338 } else { 339 CHECK_EQ(err, -EAGAIN); 340 } 341 } 342 } 343 } 344 345 bool sawOutputEOSOnAllTracks = true; 346 for (size_t i = 0; i < stateByTrack.size(); ++i) { 347 CodecState *state = &stateByTrack.editValueAt(i); 348 if (!state->mSawOutputEOS) { 349 sawOutputEOSOnAllTracks = false; 350 break; 351 } 352 } 353 354 if (sawOutputEOSOnAllTracks) { 355 break; 356 } 357 358 for (size_t i = 0; i < stateByTrack.size(); ++i) { 359 CodecState *state = &stateByTrack.editValueAt(i); 360 361 if (state->mSawOutputEOS) { 362 continue; 363 } 364 365 size_t index; 366 size_t offset; 367 size_t size; 368 int64_t presentationTimeUs; 369 uint32_t flags; 370 status_t err = state->mCodec->dequeueOutputBuffer( 371 &index, &offset, &size, &presentationTimeUs, &flags, 372 kTimeout); 373 374 if (err == OK) { 375 ALOGV("draining output buffer %d, time = %lld us", 376 index, presentationTimeUs); 377 378 ++state->mNumBuffersDecoded; 379 state->mNumBytesDecoded += size; 380 381 err = state->mCodec->releaseOutputBuffer(index); 382 CHECK_EQ(err, (status_t)OK); 383 384 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 385 ALOGV("reached EOS on output."); 386 387 state->mSawOutputEOS = true; 388 } 389 } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) { 390 ALOGV("INFO_OUTPUT_BUFFERS_CHANGED"); 391 CHECK_EQ((status_t)OK, 392 state->mCodec->getOutputBuffers(&state->mOutBuffers)); 393 394 ALOGV("got %d output buffers", state->mOutBuffers.size()); 395 } else if (err == INFO_FORMAT_CHANGED) { 396 sp<AMessage> format; 397 CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format)); 398 399 ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str()); 400 } else { 401 CHECK_EQ(err, -EAGAIN); 402 } 403 } 404 } 405 406 int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs; 407 408 for (size_t i = 0; i < stateByTrack.size(); ++i) { 409 CodecState *state = &stateByTrack.editValueAt(i); 410 411 CHECK_EQ((status_t)OK, state->mCodec->release()); 412 413 if (state->mIsAudio) { 414 printf("track %d: %lld bytes received. %.2f KB/sec\n", 415 i, 416 state->mNumBytesDecoded, 417 state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs); 418 } else { 419 printf("track %d: %lld frames decoded, %.2f fps. %lld bytes " 420 "received. %.2f KB/sec\n", 421 i, 422 state->mNumBuffersDecoded, 423 state->mNumBuffersDecoded * 1E6 / elapsedTimeUs, 424 state->mNumBytesDecoded, 425 state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs); 426 } 427 } 428 429 return 0; 430} 431 432int main(int argc, char **argv) { 433 using namespace android; 434 435 const char *me = argv[0]; 436 437 bool useAudio = false; 438 bool useVideo = false; 439 bool playback = false; 440 bool useSurface = false; 441 bool decryptInputBuffers = false; 442 443 int res; 444 while ((res = getopt(argc, argv, "havpSD")) >= 0) { 445 switch (res) { 446 case 'a': 447 { 448 useAudio = true; 449 break; 450 } 451 452 case 'v': 453 { 454 useVideo = true; 455 break; 456 } 457 458 case 'p': 459 { 460 playback = true; 461 break; 462 } 463 464 case 'S': 465 { 466 useSurface = true; 467 break; 468 } 469 470 case 'D': 471 { 472 decryptInputBuffers = true; 473 break; 474 } 475 476 case '?': 477 case 'h': 478 default: 479 { 480 usage(me); 481 } 482 } 483 } 484 485 argc -= optind; 486 argv += optind; 487 488 if (argc != 1) { 489 usage(me); 490 } 491 492 if (!useAudio && !useVideo) { 493 useAudio = useVideo = true; 494 } 495 496 ProcessState::self()->startThreadPool(); 497 498 DataSource::RegisterDefaultSniffers(); 499 500 sp<ALooper> looper = new ALooper; 501 looper->start(); 502 503 sp<SurfaceComposerClient> composerClient; 504 sp<SurfaceControl> control; 505 sp<Surface> surface; 506 507 if (playback || (useSurface && useVideo)) { 508 composerClient = new SurfaceComposerClient; 509 CHECK_EQ(composerClient->initCheck(), (status_t)OK); 510 511 ssize_t displayWidth = composerClient->getDisplayWidth(0); 512 ssize_t displayHeight = composerClient->getDisplayHeight(0); 513 514 ALOGV("display is %ld x %ld\n", displayWidth, displayHeight); 515 516 control = composerClient->createSurface( 517 String8("A Surface"), 518 0, 519 displayWidth, 520 displayHeight, 521 PIXEL_FORMAT_RGB_565, 522 0); 523 524 CHECK(control != NULL); 525 CHECK(control->isValid()); 526 527 SurfaceComposerClient::openGlobalTransaction(); 528 CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK); 529 CHECK_EQ(control->show(), (status_t)OK); 530 SurfaceComposerClient::closeGlobalTransaction(); 531 532 surface = control->getSurface(); 533 CHECK(surface != NULL); 534 } 535 536 if (playback) { 537 sp<SimplePlayer> player = new SimplePlayer; 538 looper->registerHandler(player); 539 540 player->setDataSource(argv[0]); 541 player->setSurface(surface->getSurfaceTexture()); 542 player->start(); 543 sleep(60); 544 player->stop(); 545 player->reset(); 546 } else { 547 decode(looper, argv[0], 548 useAudio, useVideo, surface, decryptInputBuffers); 549 } 550 551 if (playback || (useSurface && useVideo)) { 552 composerClient->dispose(); 553 } 554 555 looper->stop(); 556 557 return 0; 558} 559