stagefright.cpp revision fed045821d5eae63b34549cb44b7d26602f5c543
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 "include/LiveSession.h" 35#include "include/NuCachedSource2.h" 36#include <media/stagefright/AudioPlayer.h> 37#include <media/stagefright/DataSource.h> 38#include <media/stagefright/JPEGSource.h> 39#include <media/stagefright/MediaDefs.h> 40#include <media/stagefright/MediaErrors.h> 41#include <media/stagefright/MediaExtractor.h> 42#include <media/stagefright/MediaSource.h> 43#include <media/stagefright/MetaData.h> 44#include <media/stagefright/OMXClient.h> 45#include <media/stagefright/OMXCodec.h> 46#include <media/mediametadataretriever.h> 47 48#include <media/stagefright/foundation/hexdump.h> 49#include <media/stagefright/MPEG2TSWriter.h> 50#include <media/stagefright/MPEG4Writer.h> 51 52#include <private/media/VideoFrame.h> 53#include <SkBitmap.h> 54#include <SkImageEncoder.h> 55 56#include <fcntl.h> 57 58#include <gui/SurfaceTextureClient.h> 59 60#include <surfaceflinger/ISurfaceComposer.h> 61#include <surfaceflinger/SurfaceComposerClient.h> 62 63using namespace android; 64 65static long gNumRepetitions; 66static long gMaxNumFrames; // 0 means decode all available. 67static long gReproduceBug; // if not -1. 68static bool gPreferSoftwareCodec; 69static bool gForceToUseHardwareCodec; 70static bool gPlaybackAudio; 71static bool gWriteMP4; 72static bool gDisplayHistogram; 73static String8 gWriteMP4Filename; 74 75static sp<ANativeWindow> gSurface; 76 77#define USE_SURFACE_COMPOSER 0 78 79static int64_t getNowUs() { 80 struct timeval tv; 81 gettimeofday(&tv, NULL); 82 83 return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll; 84} 85 86static int CompareIncreasing(const int64_t *a, const int64_t *b) { 87 return (*a) < (*b) ? -1 : (*a) > (*b) ? 1 : 0; 88} 89 90static void displayDecodeHistogram(Vector<int64_t> *decodeTimesUs) { 91 printf("decode times:\n"); 92 93 decodeTimesUs->sort(CompareIncreasing); 94 95 size_t n = decodeTimesUs->size(); 96 int64_t minUs = decodeTimesUs->itemAt(0); 97 int64_t maxUs = decodeTimesUs->itemAt(n - 1); 98 99 printf("min decode time %lld us (%.2f secs)\n", minUs, minUs / 1E6); 100 printf("max decode time %lld us (%.2f secs)\n", maxUs, maxUs / 1E6); 101 102 size_t counts[100]; 103 for (size_t i = 0; i < 100; ++i) { 104 counts[i] = 0; 105 } 106 107 for (size_t i = 0; i < n; ++i) { 108 int64_t x = decodeTimesUs->itemAt(i); 109 110 size_t slot = ((x - minUs) * 100) / (maxUs - minUs); 111 if (slot == 100) { slot = 99; } 112 113 ++counts[slot]; 114 } 115 116 for (size_t i = 0; i < 100; ++i) { 117 int64_t slotUs = minUs + (i * (maxUs - minUs) / 100); 118 119 double fps = 1E6 / slotUs; 120 printf("[%.2f fps]: %d\n", fps, counts[i]); 121 } 122} 123 124static void displayAVCProfileLevelIfPossible(const sp<MetaData>& meta) { 125 uint32_t type; 126 const void *data; 127 size_t size; 128 if (meta->findData(kKeyAVCC, &type, &data, &size)) { 129 const uint8_t *ptr = (const uint8_t *)data; 130 CHECK(size >= 7); 131 CHECK(ptr[0] == 1); // configurationVersion == 1 132 uint8_t profile = ptr[1]; 133 uint8_t level = ptr[3]; 134 fprintf(stderr, "AVC video profile %d and level %d\n", profile, level); 135 } 136} 137 138static void playSource(OMXClient *client, sp<MediaSource> &source) { 139 sp<MetaData> meta = source->getFormat(); 140 141 const char *mime; 142 CHECK(meta->findCString(kKeyMIMEType, &mime)); 143 144 sp<MediaSource> rawSource; 145 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) { 146 rawSource = source; 147 } else { 148 int flags = 0; 149 if (gPreferSoftwareCodec) { 150 flags |= OMXCodec::kPreferSoftwareCodecs; 151 } 152 if (gForceToUseHardwareCodec) { 153 CHECK(!gPreferSoftwareCodec); 154 flags |= OMXCodec::kHardwareCodecsOnly; 155 } 156 rawSource = OMXCodec::Create( 157 client->interface(), meta, false /* createEncoder */, source, 158 NULL /* matchComponentName */, 159 flags, 160 gSurface); 161 162 if (rawSource == NULL) { 163 fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime); 164 return; 165 } 166 displayAVCProfileLevelIfPossible(meta); 167 } 168 169 source.clear(); 170 171 status_t err = rawSource->start(); 172 173 if (err != OK) { 174 fprintf(stderr, "rawSource returned error %d (0x%08x)\n", err, err); 175 return; 176 } 177 178 if (gPlaybackAudio) { 179 AudioPlayer *player = new AudioPlayer(NULL); 180 player->setSource(rawSource); 181 rawSource.clear(); 182 183 player->start(true /* sourceAlreadyStarted */); 184 185 status_t finalStatus; 186 while (!player->reachedEOS(&finalStatus)) { 187 usleep(100000ll); 188 } 189 190 delete player; 191 player = NULL; 192 193 return; 194 } else if (gReproduceBug >= 3 && gReproduceBug <= 5) { 195 int64_t durationUs; 196 CHECK(meta->findInt64(kKeyDuration, &durationUs)); 197 198 status_t err; 199 MediaBuffer *buffer; 200 MediaSource::ReadOptions options; 201 int64_t seekTimeUs = -1; 202 for (;;) { 203 err = rawSource->read(&buffer, &options); 204 options.clearSeekTo(); 205 206 bool shouldSeek = false; 207 if (err == INFO_FORMAT_CHANGED) { 208 CHECK(buffer == NULL); 209 210 printf("format changed.\n"); 211 continue; 212 } else if (err != OK) { 213 printf("reached EOF.\n"); 214 215 shouldSeek = true; 216 } else { 217 int64_t timestampUs; 218 CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs)); 219 220 bool failed = false; 221 222 if (seekTimeUs >= 0) { 223 int64_t diff = timestampUs - seekTimeUs; 224 225 if (diff < 0) { 226 diff = -diff; 227 } 228 229 if ((gReproduceBug == 4 && diff > 500000) 230 || (gReproduceBug == 5 && timestampUs < 0)) { 231 printf("wanted: %.2f secs, got: %.2f secs\n", 232 seekTimeUs / 1E6, timestampUs / 1E6); 233 234 printf("ERROR: "); 235 failed = true; 236 } 237 } 238 239 printf("buffer has timestamp %lld us (%.2f secs)\n", 240 timestampUs, timestampUs / 1E6); 241 242 buffer->release(); 243 buffer = NULL; 244 245 if (failed) { 246 break; 247 } 248 249 shouldSeek = ((double)rand() / RAND_MAX) < 0.1; 250 251 if (gReproduceBug == 3) { 252 shouldSeek = false; 253 } 254 } 255 256 seekTimeUs = -1; 257 258 if (shouldSeek) { 259 seekTimeUs = (rand() * (float)durationUs) / RAND_MAX; 260 options.setSeekTo(seekTimeUs); 261 262 printf("seeking to %lld us (%.2f secs)\n", 263 seekTimeUs, seekTimeUs / 1E6); 264 } 265 } 266 267 rawSource->stop(); 268 269 return; 270 } 271 272 int n = 0; 273 int64_t startTime = getNowUs(); 274 275 long numIterationsLeft = gNumRepetitions; 276 MediaSource::ReadOptions options; 277 278 int64_t sumDecodeUs = 0; 279 int64_t totalBytes = 0; 280 281 Vector<int64_t> decodeTimesUs; 282 283 while (numIterationsLeft-- > 0) { 284 long numFrames = 0; 285 286 MediaBuffer *buffer; 287 288 for (;;) { 289 int64_t startDecodeUs = getNowUs(); 290 status_t err = rawSource->read(&buffer, &options); 291 int64_t delayDecodeUs = getNowUs() - startDecodeUs; 292 293 options.clearSeekTo(); 294 295 if (err != OK) { 296 CHECK(buffer == NULL); 297 298 if (err == INFO_FORMAT_CHANGED) { 299 printf("format changed.\n"); 300 continue; 301 } 302 303 break; 304 } 305 306 if (buffer->range_length() > 0) { 307 if (gDisplayHistogram && n > 0) { 308 // Ignore the first time since it includes some setup 309 // cost. 310 decodeTimesUs.push(delayDecodeUs); 311 } 312 313 if ((n++ % 16) == 0) { 314 printf("."); 315 fflush(stdout); 316 } 317 } 318 319 sumDecodeUs += delayDecodeUs; 320 totalBytes += buffer->range_length(); 321 322 buffer->release(); 323 buffer = NULL; 324 325 ++numFrames; 326 if (gMaxNumFrames > 0 && numFrames == gMaxNumFrames) { 327 break; 328 } 329 330 if (gReproduceBug == 1 && numFrames == 40) { 331 printf("seeking past the end now."); 332 options.setSeekTo(0x7fffffffL); 333 } else if (gReproduceBug == 2 && numFrames == 40) { 334 printf("seeking to 5 secs."); 335 options.setSeekTo(5000000); 336 } 337 } 338 339 printf("$"); 340 fflush(stdout); 341 342 options.setSeekTo(0); 343 } 344 345 rawSource->stop(); 346 printf("\n"); 347 348 int64_t delay = getNowUs() - startTime; 349 if (!strncasecmp("video/", mime, 6)) { 350 printf("avg. %.2f fps\n", n * 1E6 / delay); 351 352 printf("avg. time to decode one buffer %.2f usecs\n", 353 (double)sumDecodeUs / n); 354 355 printf("decoded a total of %d frame(s).\n", n); 356 357 if (gDisplayHistogram) { 358 displayDecodeHistogram(&decodeTimesUs); 359 } 360 } else if (!strncasecmp("audio/", mime, 6)) { 361 // Frame count makes less sense for audio, as the output buffer 362 // sizes may be different across decoders. 363 printf("avg. %.2f KB/sec\n", totalBytes / 1024 * 1E6 / delay); 364 365 printf("decoded a total of %lld bytes\n", totalBytes); 366 } 367} 368 369//////////////////////////////////////////////////////////////////////////////// 370 371struct DetectSyncSource : public MediaSource { 372 DetectSyncSource(const sp<MediaSource> &source); 373 374 virtual status_t start(MetaData *params = NULL); 375 virtual status_t stop(); 376 virtual sp<MetaData> getFormat(); 377 378 virtual status_t read( 379 MediaBuffer **buffer, const ReadOptions *options); 380 381private: 382 enum StreamType { 383 AVC, 384 MPEG4, 385 H263, 386 OTHER, 387 }; 388 389 sp<MediaSource> mSource; 390 StreamType mStreamType; 391 bool mSawFirstIDRFrame; 392 393 DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource); 394}; 395 396DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source) 397 : mSource(source), 398 mStreamType(OTHER), 399 mSawFirstIDRFrame(false) { 400 const char *mime; 401 CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); 402 403 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 404 mStreamType = AVC; 405 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) { 406 mStreamType = MPEG4; 407 CHECK(!"sync frame detection not implemented yet for MPEG4"); 408 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) { 409 mStreamType = H263; 410 CHECK(!"sync frame detection not implemented yet for H.263"); 411 } 412} 413 414status_t DetectSyncSource::start(MetaData *params) { 415 mSawFirstIDRFrame = false; 416 417 return mSource->start(params); 418} 419 420status_t DetectSyncSource::stop() { 421 return mSource->stop(); 422} 423 424sp<MetaData> DetectSyncSource::getFormat() { 425 return mSource->getFormat(); 426} 427 428static bool isIDRFrame(MediaBuffer *buffer) { 429 const uint8_t *data = 430 (const uint8_t *)buffer->data() + buffer->range_offset(); 431 size_t size = buffer->range_length(); 432 for (size_t i = 0; i + 3 < size; ++i) { 433 if (!memcmp("\x00\x00\x01", &data[i], 3)) { 434 uint8_t nalType = data[i + 3] & 0x1f; 435 if (nalType == 5) { 436 return true; 437 } 438 } 439 } 440 441 return false; 442} 443 444status_t DetectSyncSource::read( 445 MediaBuffer **buffer, const ReadOptions *options) { 446 for (;;) { 447 status_t err = mSource->read(buffer, options); 448 449 if (err != OK) { 450 return err; 451 } 452 453 if (mStreamType == AVC) { 454 bool isIDR = isIDRFrame(*buffer); 455 (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, isIDR); 456 if (isIDR) { 457 mSawFirstIDRFrame = true; 458 } 459 } else { 460 (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, true); 461 } 462 463 if (mStreamType != AVC || mSawFirstIDRFrame) { 464 break; 465 } 466 467 // Ignore everything up to the first IDR frame. 468 (*buffer)->release(); 469 *buffer = NULL; 470 } 471 472 return OK; 473} 474 475//////////////////////////////////////////////////////////////////////////////// 476 477static void writeSourcesToMP4( 478 Vector<sp<MediaSource> > &sources, bool syncInfoPresent) { 479#if 0 480 sp<MPEG4Writer> writer = 481 new MPEG4Writer(gWriteMP4Filename.string()); 482#else 483 sp<MPEG2TSWriter> writer = 484 new MPEG2TSWriter(gWriteMP4Filename.string()); 485#endif 486 487 // at most one minute. 488 writer->setMaxFileDuration(60000000ll); 489 490 for (size_t i = 0; i < sources.size(); ++i) { 491 sp<MediaSource> source = sources.editItemAt(i); 492 493 CHECK_EQ(writer->addSource( 494 syncInfoPresent ? source : new DetectSyncSource(source)), 495 (status_t)OK); 496 } 497 498 sp<MetaData> params = new MetaData; 499 params->setInt32(kKeyNotRealTime, true); 500 CHECK_EQ(writer->start(params.get()), (status_t)OK); 501 502 while (!writer->reachedEOS()) { 503 usleep(100000); 504 } 505 writer->stop(); 506} 507 508static void performSeekTest(const sp<MediaSource> &source) { 509 CHECK_EQ((status_t)OK, source->start()); 510 511 int64_t durationUs; 512 CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs)); 513 514 for (int64_t seekTimeUs = 0; seekTimeUs <= durationUs; 515 seekTimeUs += 60000ll) { 516 MediaSource::ReadOptions options; 517 options.setSeekTo( 518 seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 519 520 MediaBuffer *buffer; 521 status_t err; 522 for (;;) { 523 err = source->read(&buffer, &options); 524 525 options.clearSeekTo(); 526 527 if (err == INFO_FORMAT_CHANGED) { 528 CHECK(buffer == NULL); 529 continue; 530 } 531 532 if (err != OK) { 533 CHECK(buffer == NULL); 534 break; 535 } 536 537 if (buffer->range_length() > 0) { 538 break; 539 } 540 541 CHECK(buffer != NULL); 542 543 buffer->release(); 544 buffer = NULL; 545 } 546 547 if (err == OK) { 548 int64_t timeUs; 549 CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); 550 551 printf("%lld\t%lld\t%lld\n", seekTimeUs, timeUs, seekTimeUs - timeUs); 552 553 buffer->release(); 554 buffer = NULL; 555 } else { 556 printf("ERROR\n"); 557 break; 558 } 559 } 560 561 CHECK_EQ((status_t)OK, source->stop()); 562} 563 564static void usage(const char *me) { 565 fprintf(stderr, "usage: %s\n", me); 566 fprintf(stderr, " -h(elp)\n"); 567 fprintf(stderr, " -a(udio)\n"); 568 fprintf(stderr, " -n repetitions\n"); 569 fprintf(stderr, " -l(ist) components\n"); 570 fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n"); 571 fprintf(stderr, " -b bug to reproduce\n"); 572 fprintf(stderr, " -p(rofiles) dump decoder profiles supported\n"); 573 fprintf(stderr, " -t(humbnail) extract video thumbnail or album art\n"); 574 fprintf(stderr, " -s(oftware) prefer software codec\n"); 575 fprintf(stderr, " -r(hardware) force to use hardware codec\n"); 576 fprintf(stderr, " -o playback audio\n"); 577 fprintf(stderr, " -w(rite) filename (write to .mp4 file)\n"); 578 fprintf(stderr, " -k seek test\n"); 579 fprintf(stderr, " -x display a histogram of decoding times/fps " 580 "(video only)\n"); 581 fprintf(stderr, " -S allocate buffers from a surface\n"); 582} 583 584int main(int argc, char **argv) { 585 android::ProcessState::self()->startThreadPool(); 586 587 bool audioOnly = false; 588 bool listComponents = false; 589 bool dumpProfiles = false; 590 bool extractThumbnail = false; 591 bool seekTest = false; 592 bool useSurfaceAlloc = false; 593 gNumRepetitions = 1; 594 gMaxNumFrames = 0; 595 gReproduceBug = -1; 596 gPreferSoftwareCodec = false; 597 gForceToUseHardwareCodec = false; 598 gPlaybackAudio = false; 599 gWriteMP4 = false; 600 gDisplayHistogram = false; 601 602 sp<ALooper> looper; 603 sp<ARTSPController> rtspController; 604 sp<LiveSession> liveSession; 605 606 int res; 607 while ((res = getopt(argc, argv, "han:lm:b:ptsrow:kxS")) >= 0) { 608 switch (res) { 609 case 'a': 610 { 611 audioOnly = true; 612 break; 613 } 614 615 case 'l': 616 { 617 listComponents = true; 618 break; 619 } 620 621 case 'm': 622 case 'n': 623 case 'b': 624 { 625 char *end; 626 long x = strtol(optarg, &end, 10); 627 628 if (*end != '\0' || end == optarg || x <= 0) { 629 x = 1; 630 } 631 632 if (res == 'n') { 633 gNumRepetitions = x; 634 } else if (res == 'm') { 635 gMaxNumFrames = x; 636 } else { 637 CHECK_EQ(res, 'b'); 638 gReproduceBug = x; 639 } 640 break; 641 } 642 643 case 'w': 644 { 645 gWriteMP4 = true; 646 gWriteMP4Filename.setTo(optarg); 647 break; 648 } 649 650 case 'p': 651 { 652 dumpProfiles = true; 653 break; 654 } 655 656 case 't': 657 { 658 extractThumbnail = true; 659 break; 660 } 661 662 case 's': 663 { 664 gPreferSoftwareCodec = true; 665 break; 666 } 667 668 case 'r': 669 { 670 gForceToUseHardwareCodec = true; 671 break; 672 } 673 674 case 'o': 675 { 676 gPlaybackAudio = true; 677 break; 678 } 679 680 case 'k': 681 { 682 seekTest = true; 683 break; 684 } 685 686 case 'x': 687 { 688 gDisplayHistogram = true; 689 break; 690 } 691 692 case 'S': 693 { 694 useSurfaceAlloc = true; 695 break; 696 } 697 698 case '?': 699 case 'h': 700 default: 701 { 702 usage(argv[0]); 703 exit(1); 704 break; 705 } 706 } 707 } 708 709 if (gPlaybackAudio && !audioOnly) { 710 // This doesn't make any sense if we're decoding the video track. 711 gPlaybackAudio = false; 712 } 713 714 argc -= optind; 715 argv += optind; 716 717 if (extractThumbnail) { 718 sp<IServiceManager> sm = defaultServiceManager(); 719 sp<IBinder> binder = sm->getService(String16("media.player")); 720 sp<IMediaPlayerService> service = 721 interface_cast<IMediaPlayerService>(binder); 722 723 CHECK(service.get() != NULL); 724 725 sp<IMediaMetadataRetriever> retriever = 726 service->createMetadataRetriever(getpid()); 727 728 CHECK(retriever != NULL); 729 730 for (int k = 0; k < argc; ++k) { 731 const char *filename = argv[k]; 732 733 bool failed = true; 734 CHECK_EQ(retriever->setDataSource(filename), (status_t)OK); 735 sp<IMemory> mem = 736 retriever->getFrameAtTime(-1, 737 MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 738 739 if (mem != NULL) { 740 failed = false; 741 printf("getFrameAtTime(%s) => OK\n", filename); 742 743 VideoFrame *frame = (VideoFrame *)mem->pointer(); 744 745 SkBitmap bitmap; 746 bitmap.setConfig( 747 SkBitmap::kRGB_565_Config, frame->mWidth, frame->mHeight); 748 749 bitmap.setPixels((uint8_t *)frame + sizeof(VideoFrame)); 750 751 CHECK(SkImageEncoder::EncodeFile( 752 "/sdcard/out.jpg", bitmap, 753 SkImageEncoder::kJPEG_Type, 754 SkImageEncoder::kDefaultQuality)); 755 } 756 757 { 758 mem = retriever->extractAlbumArt(); 759 760 if (mem != NULL) { 761 failed = false; 762 printf("extractAlbumArt(%s) => OK\n", filename); 763 } 764 } 765 766 if (failed) { 767 printf("both getFrameAtTime and extractAlbumArt " 768 "failed on file '%s'.\n", filename); 769 } 770 } 771 772 return 0; 773 } 774 775 if (dumpProfiles) { 776 sp<IServiceManager> sm = defaultServiceManager(); 777 sp<IBinder> binder = sm->getService(String16("media.player")); 778 sp<IMediaPlayerService> service = 779 interface_cast<IMediaPlayerService>(binder); 780 781 CHECK(service.get() != NULL); 782 783 sp<IOMX> omx = service->getOMX(); 784 CHECK(omx.get() != NULL); 785 786 const char *kMimeTypes[] = { 787 MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4, 788 MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC, 789 MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB, 790 MEDIA_MIMETYPE_AUDIO_MPEG 791 }; 792 793 for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); 794 ++k) { 795 printf("type '%s':\n", kMimeTypes[k]); 796 797 Vector<CodecCapabilities> results; 798 CHECK_EQ(QueryCodecs(omx, kMimeTypes[k], 799 true, // queryDecoders 800 &results), (status_t)OK); 801 802 for (size_t i = 0; i < results.size(); ++i) { 803 printf(" decoder '%s' supports ", 804 results[i].mComponentName.string()); 805 806 if (results[i].mProfileLevels.size() == 0) { 807 printf("NOTHING.\n"); 808 continue; 809 } 810 811 for (size_t j = 0; j < results[i].mProfileLevels.size(); ++j) { 812 const CodecProfileLevel &profileLevel = 813 results[i].mProfileLevels[j]; 814 815 printf("%s%ld/%ld", j > 0 ? ", " : "", 816 profileLevel.mProfile, profileLevel.mLevel); 817 } 818 819 printf("\n"); 820 } 821 } 822 } 823 824 if (listComponents) { 825 sp<IServiceManager> sm = defaultServiceManager(); 826 sp<IBinder> binder = sm->getService(String16("media.player")); 827 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 828 829 CHECK(service.get() != NULL); 830 831 sp<IOMX> omx = service->getOMX(); 832 CHECK(omx.get() != NULL); 833 834 List<IOMX::ComponentInfo> list; 835 omx->listNodes(&list); 836 837 for (List<IOMX::ComponentInfo>::iterator it = list.begin(); 838 it != list.end(); ++it) { 839 printf("%s\n", (*it).mName.string()); 840 } 841 } 842 843 sp<SurfaceComposerClient> composerClient; 844 sp<SurfaceControl> control; 845 846 if (useSurfaceAlloc && !audioOnly) { 847#if USE_SURFACE_COMPOSER 848 composerClient = new SurfaceComposerClient; 849 CHECK_EQ(composerClient->initCheck(), (status_t)OK); 850 851 control = composerClient->createSurface( 852 getpid(), 853 String8("A Surface"), 854 0, 855 1280, 856 800, 857 PIXEL_FORMAT_RGB_565, 858 0); 859 860 CHECK(control != NULL); 861 CHECK(control->isValid()); 862 863 CHECK_EQ(composerClient->openTransaction(), (status_t)OK); 864 CHECK_EQ(control->setLayer(30000), (status_t)OK); 865 CHECK_EQ(control->show(), (status_t)OK); 866 CHECK_EQ(composerClient->closeTransaction(), (status_t)OK); 867 868 gSurface = control->getSurface(); 869 CHECK(gSurface != NULL); 870#else 871 sp<SurfaceTexture> texture = new SurfaceTexture(0 /* tex */); 872 gSurface = new SurfaceTextureClient(texture); 873#endif 874 } 875 876 DataSource::RegisterDefaultSniffers(); 877 878 OMXClient client; 879 status_t err = client.connect(); 880 881 for (int k = 0; k < argc; ++k) { 882 bool syncInfoPresent = true; 883 884 const char *filename = argv[k]; 885 886 sp<DataSource> dataSource = DataSource::CreateFromURI(filename); 887 888 if (strncasecmp(filename, "sine:", 5) 889 && strncasecmp(filename, "rtsp://", 7) 890 && strncasecmp(filename, "httplive://", 11) 891 && dataSource == NULL) { 892 fprintf(stderr, "Unable to create data source.\n"); 893 return 1; 894 } 895 896 bool isJPEG = false; 897 898 size_t len = strlen(filename); 899 if (len >= 4 && !strcasecmp(filename + len - 4, ".jpg")) { 900 isJPEG = true; 901 } 902 903 Vector<sp<MediaSource> > mediaSources; 904 sp<MediaSource> mediaSource; 905 906 if (isJPEG) { 907 mediaSource = new JPEGSource(dataSource); 908 if (gWriteMP4) { 909 mediaSources.push(mediaSource); 910 } 911 } else if (!strncasecmp("sine:", filename, 5)) { 912 char *end; 913 long sampleRate = strtol(filename + 5, &end, 10); 914 915 if (end == filename + 5) { 916 sampleRate = 44100; 917 } 918 mediaSource = new SineSource(sampleRate, 1); 919 if (gWriteMP4) { 920 mediaSources.push(mediaSource); 921 } 922 } else { 923 sp<MediaExtractor> extractor; 924 925 if (!strncasecmp("rtsp://", filename, 7)) { 926 if (looper == NULL) { 927 looper = new ALooper; 928 looper->start(); 929 } 930 931 rtspController = new ARTSPController(looper); 932 status_t err = rtspController->connect(filename); 933 if (err != OK) { 934 fprintf(stderr, "could not connect to rtsp server.\n"); 935 return -1; 936 } 937 938 extractor = rtspController.get(); 939 940 syncInfoPresent = false; 941 } else if (!strncasecmp("httplive://", filename, 11)) { 942 String8 uri("http://"); 943 uri.append(filename + 11); 944 945 if (looper == NULL) { 946 looper = new ALooper; 947 looper->start(); 948 } 949 liveSession = new LiveSession; 950 looper->registerHandler(liveSession); 951 952 liveSession->connect(uri.string()); 953 dataSource = liveSession->getDataSource(); 954 955 extractor = 956 MediaExtractor::Create( 957 dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 958 959 syncInfoPresent = false; 960 } else { 961 extractor = MediaExtractor::Create(dataSource); 962 if (extractor == NULL) { 963 fprintf(stderr, "could not create extractor.\n"); 964 return -1; 965 } 966 967 sp<MetaData> meta = extractor->getMetaData(); 968 969 if (meta != NULL) { 970 const char *mime; 971 CHECK(meta->findCString(kKeyMIMEType, &mime)); 972 973 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { 974 syncInfoPresent = false; 975 } 976 } 977 } 978 979 size_t numTracks = extractor->countTracks(); 980 981 if (gWriteMP4) { 982 bool haveAudio = false; 983 bool haveVideo = false; 984 for (size_t i = 0; i < numTracks; ++i) { 985 sp<MediaSource> source = extractor->getTrack(i); 986 987 const char *mime; 988 CHECK(source->getFormat()->findCString( 989 kKeyMIMEType, &mime)); 990 991 bool useTrack = false; 992 if (!haveAudio && !strncasecmp("audio/", mime, 6)) { 993 haveAudio = true; 994 useTrack = true; 995 } else if (!haveVideo && !strncasecmp("video/", mime, 6)) { 996 haveVideo = true; 997 useTrack = true; 998 } 999 1000 if (useTrack) { 1001 mediaSources.push(source); 1002 1003 if (haveAudio && haveVideo) { 1004 break; 1005 } 1006 } 1007 } 1008 } else { 1009 sp<MetaData> meta; 1010 size_t i; 1011 for (i = 0; i < numTracks; ++i) { 1012 meta = extractor->getTrackMetaData( 1013 i, MediaExtractor::kIncludeExtensiveMetaData); 1014 1015 const char *mime; 1016 meta->findCString(kKeyMIMEType, &mime); 1017 1018 if (audioOnly && !strncasecmp(mime, "audio/", 6)) { 1019 break; 1020 } 1021 1022 if (!audioOnly && !strncasecmp(mime, "video/", 6)) { 1023 break; 1024 } 1025 1026 meta = NULL; 1027 } 1028 1029 if (meta == NULL) { 1030 fprintf(stderr, 1031 "No suitable %s track found. The '-a' option will " 1032 "target audio tracks only, the default is to target " 1033 "video tracks only.\n", 1034 audioOnly ? "audio" : "video"); 1035 return -1; 1036 } 1037 1038 int64_t thumbTimeUs; 1039 if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) { 1040 printf("thumbnailTime: %lld us (%.2f secs)\n", 1041 thumbTimeUs, thumbTimeUs / 1E6); 1042 } 1043 1044 mediaSource = extractor->getTrack(i); 1045 } 1046 } 1047 1048 if (gWriteMP4) { 1049 writeSourcesToMP4(mediaSources, syncInfoPresent); 1050 } else if (seekTest) { 1051 performSeekTest(mediaSource); 1052 } else { 1053 playSource(&client, mediaSource); 1054 } 1055 1056 if (rtspController != NULL) { 1057 rtspController->disconnect(); 1058 rtspController.clear(); 1059 1060 sleep(3); 1061 } 1062 } 1063 1064 if (useSurfaceAlloc && !audioOnly) { 1065 gSurface.clear(); 1066 1067#if USE_SURFACE_COMPOSER 1068 composerClient->dispose(); 1069#endif 1070 } 1071 1072 client.disconnect(); 1073 1074 return 0; 1075} 1076