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