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