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