stagefright.cpp revision bbc38312e4521cfd4299203591ef366b7624f043
1/* 2 * Copyright (C) 2009 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 "stagefright" 19#include <media/stagefright/foundation/ADebug.h> 20 21#include <sys/time.h> 22 23#include <stdlib.h> 24#include <string.h> 25#include <unistd.h> 26 27#include "SineSource.h" 28 29#include <binder/IServiceManager.h> 30#include <binder/ProcessState.h> 31#include <media/IMediaPlayerService.h> 32#include <media/stagefright/foundation/ALooper.h> 33#include "include/ARTSPController.h" 34#include <media/stagefright/AudioPlayer.h> 35#include <media/stagefright/DataSource.h> 36#include <media/stagefright/JPEGSource.h> 37#include <media/stagefright/MediaDefs.h> 38#include <media/stagefright/MediaErrors.h> 39#include <media/stagefright/MediaExtractor.h> 40#include <media/stagefright/MediaSource.h> 41#include <media/stagefright/MetaData.h> 42#include <media/stagefright/OMXClient.h> 43#include <media/stagefright/OMXCodec.h> 44#include <media/mediametadataretriever.h> 45 46#include <media/stagefright/foundation/hexdump.h> 47#include <media/stagefright/MPEG4Writer.h> 48 49#include <fcntl.h> 50 51using namespace android; 52 53static long gNumRepetitions; 54static long gMaxNumFrames; // 0 means decode all available. 55static long gReproduceBug; // if not -1. 56static bool gPreferSoftwareCodec; 57static bool gPlaybackAudio; 58static bool gWriteMP4; 59static String8 gWriteMP4Filename; 60 61static int64_t getNowUs() { 62 struct timeval tv; 63 gettimeofday(&tv, NULL); 64 65 return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll; 66} 67 68static void playSource(OMXClient *client, sp<MediaSource> &source) { 69 sp<MetaData> meta = source->getFormat(); 70 71 const char *mime; 72 CHECK(meta->findCString(kKeyMIMEType, &mime)); 73 74 sp<MediaSource> rawSource; 75 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) { 76 rawSource = source; 77 } else { 78 rawSource = OMXCodec::Create( 79 client->interface(), meta, false /* createEncoder */, source, 80 NULL /* matchComponentName */, 81 gPreferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0); 82 83 if (rawSource == NULL) { 84 fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime); 85 return; 86 } 87 } 88 89 source.clear(); 90 91 status_t err = rawSource->start(); 92 93 if (err != OK) { 94 fprintf(stderr, "rawSource returned error %d (0x%08x)\n", err, err); 95 return; 96 } 97 98 if (gPlaybackAudio) { 99 AudioPlayer *player = new AudioPlayer(NULL); 100 player->setSource(rawSource); 101 rawSource.clear(); 102 103 player->start(true /* sourceAlreadyStarted */); 104 105 status_t finalStatus; 106 while (!player->reachedEOS(&finalStatus)) { 107 usleep(100000ll); 108 } 109 110 delete player; 111 player = NULL; 112 113 return; 114 } else if (gReproduceBug >= 3 && gReproduceBug <= 5) { 115 int64_t durationUs; 116 CHECK(meta->findInt64(kKeyDuration, &durationUs)); 117 118 status_t err; 119 MediaBuffer *buffer; 120 MediaSource::ReadOptions options; 121 int64_t seekTimeUs = -1; 122 for (;;) { 123 err = rawSource->read(&buffer, &options); 124 options.clearSeekTo(); 125 126 bool shouldSeek = false; 127 if (err == INFO_FORMAT_CHANGED) { 128 CHECK(buffer == NULL); 129 130 printf("format changed.\n"); 131 continue; 132 } else if (err != OK) { 133 printf("reached EOF.\n"); 134 135 shouldSeek = true; 136 } else { 137 int64_t timestampUs; 138 CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs)); 139 140 bool failed = false; 141 142 if (seekTimeUs >= 0) { 143 int64_t diff = timestampUs - seekTimeUs; 144 145 if (diff < 0) { 146 diff = -diff; 147 } 148 149 if ((gReproduceBug == 4 && diff > 500000) 150 || (gReproduceBug == 5 && timestampUs < 0)) { 151 printf("wanted: %.2f secs, got: %.2f secs\n", 152 seekTimeUs / 1E6, timestampUs / 1E6); 153 154 printf("ERROR: "); 155 failed = true; 156 } 157 } 158 159 printf("buffer has timestamp %lld us (%.2f secs)\n", 160 timestampUs, timestampUs / 1E6); 161 162 buffer->release(); 163 buffer = NULL; 164 165 if (failed) { 166 break; 167 } 168 169 shouldSeek = ((double)rand() / RAND_MAX) < 0.1; 170 171 if (gReproduceBug == 3) { 172 shouldSeek = false; 173 } 174 } 175 176 seekTimeUs = -1; 177 178 if (shouldSeek) { 179 seekTimeUs = (rand() * (float)durationUs) / RAND_MAX; 180 options.setSeekTo(seekTimeUs); 181 182 printf("seeking to %lld us (%.2f secs)\n", 183 seekTimeUs, seekTimeUs / 1E6); 184 } 185 } 186 187 rawSource->stop(); 188 189 return; 190 } 191 192 int n = 0; 193 int64_t startTime = getNowUs(); 194 195 long numIterationsLeft = gNumRepetitions; 196 MediaSource::ReadOptions options; 197 198 int64_t sumDecodeUs = 0; 199 int64_t totalBytes = 0; 200 201 while (numIterationsLeft-- > 0) { 202 long numFrames = 0; 203 204 MediaBuffer *buffer; 205 206 for (;;) { 207 int64_t startDecodeUs = getNowUs(); 208 status_t err = rawSource->read(&buffer, &options); 209 int64_t delayDecodeUs = getNowUs() - startDecodeUs; 210 211 options.clearSeekTo(); 212 213 if (err != OK) { 214 CHECK(buffer == NULL); 215 216 if (err == INFO_FORMAT_CHANGED) { 217 printf("format changed.\n"); 218 continue; 219 } 220 221 break; 222 } 223 224 if (buffer->range_length() > 0 && (n++ % 16) == 0) { 225 printf("."); 226 fflush(stdout); 227 } 228 229 sumDecodeUs += delayDecodeUs; 230 totalBytes += buffer->range_length(); 231 232 buffer->release(); 233 buffer = NULL; 234 235 ++numFrames; 236 if (gMaxNumFrames > 0 && numFrames == gMaxNumFrames) { 237 break; 238 } 239 240 if (gReproduceBug == 1 && numFrames == 40) { 241 printf("seeking past the end now."); 242 options.setSeekTo(0x7fffffffL); 243 } else if (gReproduceBug == 2 && numFrames == 40) { 244 printf("seeking to 5 secs."); 245 options.setSeekTo(5000000); 246 } 247 } 248 249 printf("$"); 250 fflush(stdout); 251 252 options.setSeekTo(0); 253 } 254 255 rawSource->stop(); 256 printf("\n"); 257 258 int64_t delay = getNowUs() - startTime; 259 if (!strncasecmp("video/", mime, 6)) { 260 printf("avg. %.2f fps\n", n * 1E6 / delay); 261 262 printf("avg. time to decode one buffer %.2f usecs\n", 263 (double)sumDecodeUs / n); 264 265 printf("decoded a total of %d frame(s).\n", n); 266 } else if (!strncasecmp("audio/", mime, 6)) { 267 // Frame count makes less sense for audio, as the output buffer 268 // sizes may be different across decoders. 269 printf("avg. %.2f KB/sec\n", totalBytes / 1024 * 1E6 / delay); 270 271 printf("decoded a total of %lld bytes\n", totalBytes); 272 } 273} 274 275//////////////////////////////////////////////////////////////////////////////// 276 277struct DetectSyncSource : public MediaSource { 278 DetectSyncSource(const sp<MediaSource> &source); 279 280 virtual status_t start(MetaData *params = NULL); 281 virtual status_t stop(); 282 virtual sp<MetaData> getFormat(); 283 284 virtual status_t read( 285 MediaBuffer **buffer, const ReadOptions *options); 286 287private: 288 sp<MediaSource> mSource; 289 bool mIsAVC; 290 291 DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource); 292}; 293 294DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source) 295 : mSource(source), 296 mIsAVC(false) { 297 const char *mime; 298 CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); 299 300 mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 301} 302 303status_t DetectSyncSource::start(MetaData *params) { 304 return mSource->start(params); 305} 306 307status_t DetectSyncSource::stop() { 308 return mSource->stop(); 309} 310 311sp<MetaData> DetectSyncSource::getFormat() { 312 return mSource->getFormat(); 313} 314 315static bool isIDRFrame(MediaBuffer *buffer) { 316 const uint8_t *data = 317 (const uint8_t *)buffer->data() + buffer->range_offset(); 318 size_t size = buffer->range_length(); 319 for (size_t i = 0; i + 3 < size; ++i) { 320 if (!memcmp("\x00\x00\x01", &data[i], 3)) { 321 uint8_t nalType = data[i + 3] & 0x1f; 322 if (nalType == 5) { 323 return true; 324 } 325 } 326 } 327 328 return false; 329} 330 331status_t DetectSyncSource::read( 332 MediaBuffer **buffer, const ReadOptions *options) { 333 status_t err = mSource->read(buffer, options); 334 335 if (err != OK) { 336 return err; 337 } 338 339 if (mIsAVC && isIDRFrame(*buffer)) { 340 (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, true); 341 } else { 342 (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, false); 343 } 344 345 return OK; 346} 347 348//////////////////////////////////////////////////////////////////////////////// 349 350static void writeSourceToMP4( 351 sp<MediaSource> &source, bool syncInfoPresent) { 352 if (!syncInfoPresent) { 353 source = new DetectSyncSource(source); 354 } 355 356 sp<MPEG4Writer> writer = 357 new MPEG4Writer(gWriteMP4Filename.string()); 358 359 // at most one minute. 360 writer->setMaxFileDuration(60000000ll); 361 362 CHECK_EQ(writer->addSource(source), (status_t)OK); 363 364 sp<MetaData> params = new MetaData; 365 params->setInt32(kKeyNotRealTime, true); 366 CHECK_EQ(writer->start(params.get()), (status_t)OK); 367 368 while (!writer->reachedEOS()) { 369 usleep(100000); 370 } 371 writer->stop(); 372} 373 374static void performSeekTest(const sp<MediaSource> &source) { 375 CHECK_EQ((status_t)OK, source->start()); 376 377 int64_t durationUs; 378 CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs)); 379 380 for (int64_t seekTimeUs = 0; seekTimeUs <= durationUs; 381 seekTimeUs += 60000ll) { 382 MediaSource::ReadOptions options; 383 options.setSeekTo( 384 seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 385 386 MediaBuffer *buffer; 387 status_t err; 388 for (;;) { 389 err = source->read(&buffer, &options); 390 391 options.clearSeekTo(); 392 393 if (err == INFO_FORMAT_CHANGED) { 394 CHECK(buffer == NULL); 395 continue; 396 } 397 398 if (err != OK) { 399 CHECK(buffer == NULL); 400 break; 401 } 402 403 if (buffer->range_length() > 0) { 404 break; 405 } 406 407 CHECK(buffer != NULL); 408 409 buffer->release(); 410 buffer = NULL; 411 } 412 413 if (err == OK) { 414 int64_t timeUs; 415 CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); 416 417 printf("%lld\t%lld\t%lld\n", seekTimeUs, timeUs, seekTimeUs - timeUs); 418 419 buffer->release(); 420 buffer = NULL; 421 } else { 422 printf("ERROR\n"); 423 break; 424 } 425 } 426 427 CHECK_EQ((status_t)OK, source->stop()); 428} 429 430static void usage(const char *me) { 431 fprintf(stderr, "usage: %s\n", me); 432 fprintf(stderr, " -h(elp)\n"); 433 fprintf(stderr, " -a(udio)\n"); 434 fprintf(stderr, " -n repetitions\n"); 435 fprintf(stderr, " -l(ist) components\n"); 436 fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n"); 437 fprintf(stderr, " -b bug to reproduce\n"); 438 fprintf(stderr, " -p(rofiles) dump decoder profiles supported\n"); 439 fprintf(stderr, " -t(humbnail) extract video thumbnail or album art\n"); 440 fprintf(stderr, " -s(oftware) prefer software codec\n"); 441 fprintf(stderr, " -o playback audio\n"); 442 fprintf(stderr, " -w(rite) filename (write to .mp4 file)\n"); 443 fprintf(stderr, " -k seek test\n"); 444} 445 446int main(int argc, char **argv) { 447 android::ProcessState::self()->startThreadPool(); 448 449 bool audioOnly = false; 450 bool listComponents = false; 451 bool dumpProfiles = false; 452 bool extractThumbnail = false; 453 bool seekTest = false; 454 gNumRepetitions = 1; 455 gMaxNumFrames = 0; 456 gReproduceBug = -1; 457 gPreferSoftwareCodec = false; 458 gPlaybackAudio = false; 459 gWriteMP4 = false; 460 461 sp<ALooper> looper; 462 sp<ARTSPController> rtspController; 463 464 int res; 465 while ((res = getopt(argc, argv, "han:lm:b:ptsow:k")) >= 0) { 466 switch (res) { 467 case 'a': 468 { 469 audioOnly = true; 470 break; 471 } 472 473 case 'l': 474 { 475 listComponents = true; 476 break; 477 } 478 479 case 'm': 480 case 'n': 481 case 'b': 482 { 483 char *end; 484 long x = strtol(optarg, &end, 10); 485 486 if (*end != '\0' || end == optarg || x <= 0) { 487 x = 1; 488 } 489 490 if (res == 'n') { 491 gNumRepetitions = x; 492 } else if (res == 'm') { 493 gMaxNumFrames = x; 494 } else { 495 CHECK_EQ(res, 'b'); 496 gReproduceBug = x; 497 } 498 break; 499 } 500 501 case 'w': 502 { 503 gWriteMP4 = true; 504 gWriteMP4Filename.setTo(optarg); 505 break; 506 } 507 508 case 'p': 509 { 510 dumpProfiles = true; 511 break; 512 } 513 514 case 't': 515 { 516 extractThumbnail = true; 517 break; 518 } 519 520 case 's': 521 { 522 gPreferSoftwareCodec = true; 523 break; 524 } 525 526 case 'o': 527 { 528 gPlaybackAudio = true; 529 break; 530 } 531 532 case 'k': 533 { 534 seekTest = true; 535 break; 536 } 537 538 case '?': 539 case 'h': 540 default: 541 { 542 usage(argv[0]); 543 exit(1); 544 break; 545 } 546 } 547 } 548 549 if (gPlaybackAudio && !audioOnly) { 550 // This doesn't make any sense if we're decoding the video track. 551 gPlaybackAudio = false; 552 } 553 554 argc -= optind; 555 argv += optind; 556 557 if (extractThumbnail) { 558 sp<IServiceManager> sm = defaultServiceManager(); 559 sp<IBinder> binder = sm->getService(String16("media.player")); 560 sp<IMediaPlayerService> service = 561 interface_cast<IMediaPlayerService>(binder); 562 563 CHECK(service.get() != NULL); 564 565 sp<IMediaMetadataRetriever> retriever = 566 service->createMetadataRetriever(getpid()); 567 568 CHECK(retriever != NULL); 569 570 for (int k = 0; k < argc; ++k) { 571 const char *filename = argv[k]; 572 573 CHECK_EQ(retriever->setDataSource(filename), (status_t)OK); 574 CHECK_EQ(retriever->setMode( 575 METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL), 576 (status_t)OK); 577 578 sp<IMemory> mem = retriever->captureFrame(); 579 580 if (mem != NULL) { 581 printf("captureFrame(%s) => OK\n", filename); 582 } else { 583 mem = retriever->extractAlbumArt(); 584 585 if (mem != NULL) { 586 printf("extractAlbumArt(%s) => OK\n", filename); 587 } else { 588 printf("both captureFrame and extractAlbumArt " 589 "failed on file '%s'.\n", filename); 590 } 591 } 592 } 593 594 return 0; 595 } 596 597 if (dumpProfiles) { 598 sp<IServiceManager> sm = defaultServiceManager(); 599 sp<IBinder> binder = sm->getService(String16("media.player")); 600 sp<IMediaPlayerService> service = 601 interface_cast<IMediaPlayerService>(binder); 602 603 CHECK(service.get() != NULL); 604 605 sp<IOMX> omx = service->getOMX(); 606 CHECK(omx.get() != NULL); 607 608 const char *kMimeTypes[] = { 609 MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4, 610 MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC, 611 MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB, 612 MEDIA_MIMETYPE_AUDIO_MPEG 613 }; 614 615 for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); 616 ++k) { 617 printf("type '%s':\n", kMimeTypes[k]); 618 619 Vector<CodecCapabilities> results; 620 CHECK_EQ(QueryCodecs(omx, kMimeTypes[k], 621 true, // queryDecoders 622 &results), (status_t)OK); 623 624 for (size_t i = 0; i < results.size(); ++i) { 625 printf(" decoder '%s' supports ", 626 results[i].mComponentName.string()); 627 628 if (results[i].mProfileLevels.size() == 0) { 629 printf("NOTHING.\n"); 630 continue; 631 } 632 633 for (size_t j = 0; j < results[i].mProfileLevels.size(); ++j) { 634 const CodecProfileLevel &profileLevel = 635 results[i].mProfileLevels[j]; 636 637 printf("%s%ld/%ld", j > 0 ? ", " : "", 638 profileLevel.mProfile, profileLevel.mLevel); 639 } 640 641 printf("\n"); 642 } 643 } 644 } 645 646 if (listComponents) { 647 sp<IServiceManager> sm = defaultServiceManager(); 648 sp<IBinder> binder = sm->getService(String16("media.player")); 649 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 650 651 CHECK(service.get() != NULL); 652 653 sp<IOMX> omx = service->getOMX(); 654 CHECK(omx.get() != NULL); 655 656 List<IOMX::ComponentInfo> list; 657 omx->listNodes(&list); 658 659 for (List<IOMX::ComponentInfo>::iterator it = list.begin(); 660 it != list.end(); ++it) { 661 printf("%s\n", (*it).mName.string()); 662 } 663 } 664 665 DataSource::RegisterDefaultSniffers(); 666 667 OMXClient client; 668 status_t err = client.connect(); 669 670 for (int k = 0; k < argc; ++k) { 671 bool syncInfoPresent = true; 672 673 const char *filename = argv[k]; 674 675 sp<DataSource> dataSource = DataSource::CreateFromURI(filename); 676 677 if ((strncasecmp(filename, "sine:", 5) 678 && strncasecmp(filename, "rtsp://", 7)) && dataSource == NULL) { 679 fprintf(stderr, "Unable to create data source.\n"); 680 return 1; 681 } 682 683 bool isJPEG = false; 684 685 size_t len = strlen(filename); 686 if (len >= 4 && !strcasecmp(filename + len - 4, ".jpg")) { 687 isJPEG = true; 688 } 689 690 sp<MediaSource> mediaSource; 691 692 if (isJPEG) { 693 mediaSource = new JPEGSource(dataSource); 694 } else if (!strncasecmp("sine:", filename, 5)) { 695 char *end; 696 long sampleRate = strtol(filename + 5, &end, 10); 697 698 if (end == filename + 5) { 699 sampleRate = 44100; 700 } 701 mediaSource = new SineSource(sampleRate, 1); 702 } else { 703 sp<MediaExtractor> extractor; 704 705 if (!strncasecmp("rtsp://", filename, 7)) { 706 if (looper == NULL) { 707 looper = new ALooper; 708 looper->start(); 709 } 710 711 rtspController = new ARTSPController(looper); 712 status_t err = rtspController->connect(filename); 713 if (err != OK) { 714 fprintf(stderr, "could not connect to rtsp server.\n"); 715 return -1; 716 } 717 718 extractor = rtspController.get(); 719 720 syncInfoPresent = false; 721 } else { 722 extractor = MediaExtractor::Create(dataSource); 723 if (extractor == NULL) { 724 fprintf(stderr, "could not create extractor.\n"); 725 return -1; 726 } 727 } 728 729 size_t numTracks = extractor->countTracks(); 730 731 sp<MetaData> meta; 732 size_t i; 733 for (i = 0; i < numTracks; ++i) { 734 meta = extractor->getTrackMetaData( 735 i, MediaExtractor::kIncludeExtensiveMetaData); 736 737 const char *mime; 738 meta->findCString(kKeyMIMEType, &mime); 739 740 if (audioOnly && !strncasecmp(mime, "audio/", 6)) { 741 break; 742 } 743 744 if (!audioOnly && !strncasecmp(mime, "video/", 6)) { 745 break; 746 } 747 748 meta = NULL; 749 } 750 751 if (meta == NULL) { 752 fprintf(stderr, 753 "No suitable %s track found. The '-a' option will " 754 "target audio tracks only, the default is to target " 755 "video tracks only.\n", 756 audioOnly ? "audio" : "video"); 757 return -1; 758 } 759 760 int64_t thumbTimeUs; 761 if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) { 762 printf("thumbnailTime: %lld us (%.2f secs)\n", 763 thumbTimeUs, thumbTimeUs / 1E6); 764 } 765 766 mediaSource = extractor->getTrack(i); 767 } 768 769 if (gWriteMP4) { 770 writeSourceToMP4(mediaSource, syncInfoPresent); 771 } else if (seekTest) { 772 performSeekTest(mediaSource); 773 } else { 774 playSource(&client, mediaSource); 775 } 776 777 if (rtspController != NULL) { 778 rtspController->disconnect(); 779 rtspController.clear(); 780 781 sleep(3); 782 } 783 } 784 785 client.disconnect(); 786 787 return 0; 788} 789