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