Home | History | Annotate | Download | only in stagefright
      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 
     63 using namespace android;
     64 
     65 static long gNumRepetitions;
     66 static long gMaxNumFrames;  // 0 means decode all available.
     67 static long gReproduceBug;  // if not -1.
     68 static bool gPreferSoftwareCodec;
     69 static bool gForceToUseHardwareCodec;
     70 static bool gPlaybackAudio;
     71 static bool gWriteMP4;
     72 static bool gDisplayHistogram;
     73 static String8 gWriteMP4Filename;
     74 
     75 static sp<ANativeWindow> gSurface;
     76 
     77 static 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 
     84 static int CompareIncreasing(const int64_t *a, const int64_t *b) {
     85     return (*a) < (*b) ? -1 : (*a) > (*b) ? 1 : 0;
     86 }
     87 
     88 static 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 
    122 static 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 
    136 static void dumpSource(const sp<MediaSource> &source, const String8 &filename) {
    137     FILE *out = fopen(filename.string(), "wb");
    138 
    139     CHECK_EQ((status_t)OK, source->start());
    140 
    141     status_t err;
    142     for (;;) {
    143         MediaBuffer *mbuf;
    144         err = source->read(&mbuf);
    145 
    146         if (err == INFO_FORMAT_CHANGED) {
    147             continue;
    148         } else if (err != OK) {
    149             break;
    150         }
    151 
    152         CHECK_EQ(
    153                 fwrite((const uint8_t *)mbuf->data() + mbuf->range_offset(),
    154                        1,
    155                        mbuf->range_length(),
    156                        out),
    157                 (ssize_t)mbuf->range_length());
    158 
    159         mbuf->release();
    160         mbuf = NULL;
    161     }
    162 
    163     CHECK_EQ((status_t)OK, source->stop());
    164 
    165     fclose(out);
    166     out = NULL;
    167 }
    168 
    169 static void playSource(OMXClient *client, sp<MediaSource> &source) {
    170     sp<MetaData> meta = source->getFormat();
    171 
    172     const char *mime;
    173     CHECK(meta->findCString(kKeyMIMEType, &mime));
    174 
    175     sp<MediaSource> rawSource;
    176     if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) {
    177         rawSource = source;
    178     } else {
    179         int flags = 0;
    180         if (gPreferSoftwareCodec) {
    181             flags |= OMXCodec::kPreferSoftwareCodecs;
    182         }
    183         if (gForceToUseHardwareCodec) {
    184             CHECK(!gPreferSoftwareCodec);
    185             flags |= OMXCodec::kHardwareCodecsOnly;
    186         }
    187         rawSource = OMXCodec::Create(
    188             client->interface(), meta, false /* createEncoder */, source,
    189             NULL /* matchComponentName */,
    190             flags,
    191             gSurface);
    192 
    193         if (rawSource == NULL) {
    194             fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime);
    195             return;
    196         }
    197         displayAVCProfileLevelIfPossible(meta);
    198     }
    199 
    200     source.clear();
    201 
    202     status_t err = rawSource->start();
    203 
    204     if (err != OK) {
    205         fprintf(stderr, "rawSource returned error %d (0x%08x)\n", err, err);
    206         return;
    207     }
    208 
    209     if (gPlaybackAudio) {
    210         AudioPlayer *player = new AudioPlayer(NULL);
    211         player->setSource(rawSource);
    212         rawSource.clear();
    213 
    214         player->start(true /* sourceAlreadyStarted */);
    215 
    216         status_t finalStatus;
    217         while (!player->reachedEOS(&finalStatus)) {
    218             usleep(100000ll);
    219         }
    220 
    221         delete player;
    222         player = NULL;
    223 
    224         return;
    225     } else if (gReproduceBug >= 3 && gReproduceBug <= 5) {
    226         int64_t durationUs;
    227         CHECK(meta->findInt64(kKeyDuration, &durationUs));
    228 
    229         status_t err;
    230         MediaBuffer *buffer;
    231         MediaSource::ReadOptions options;
    232         int64_t seekTimeUs = -1;
    233         for (;;) {
    234             err = rawSource->read(&buffer, &options);
    235             options.clearSeekTo();
    236 
    237             bool shouldSeek = false;
    238             if (err == INFO_FORMAT_CHANGED) {
    239                 CHECK(buffer == NULL);
    240 
    241                 printf("format changed.\n");
    242                 continue;
    243             } else if (err != OK) {
    244                 printf("reached EOF.\n");
    245 
    246                 shouldSeek = true;
    247             } else {
    248                 int64_t timestampUs;
    249                 CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
    250 
    251                 bool failed = false;
    252 
    253                 if (seekTimeUs >= 0) {
    254                     int64_t diff = timestampUs - seekTimeUs;
    255 
    256                     if (diff < 0) {
    257                         diff = -diff;
    258                     }
    259 
    260                     if ((gReproduceBug == 4 && diff > 500000)
    261                         || (gReproduceBug == 5 && timestampUs < 0)) {
    262                         printf("wanted: %.2f secs, got: %.2f secs\n",
    263                                seekTimeUs / 1E6, timestampUs / 1E6);
    264 
    265                         printf("ERROR: ");
    266                         failed = true;
    267                     }
    268                 }
    269 
    270                 printf("buffer has timestamp %lld us (%.2f secs)\n",
    271                        timestampUs, timestampUs / 1E6);
    272 
    273                 buffer->release();
    274                 buffer = NULL;
    275 
    276                 if (failed) {
    277                     break;
    278                 }
    279 
    280                 shouldSeek = ((double)rand() / RAND_MAX) < 0.1;
    281 
    282                 if (gReproduceBug == 3) {
    283                     shouldSeek = false;
    284                 }
    285             }
    286 
    287             seekTimeUs = -1;
    288 
    289             if (shouldSeek) {
    290                 seekTimeUs = (rand() * (float)durationUs) / RAND_MAX;
    291                 options.setSeekTo(seekTimeUs);
    292 
    293                 printf("seeking to %lld us (%.2f secs)\n",
    294                        seekTimeUs, seekTimeUs / 1E6);
    295             }
    296         }
    297 
    298         rawSource->stop();
    299 
    300         return;
    301     }
    302 
    303     int n = 0;
    304     int64_t startTime = getNowUs();
    305 
    306     long numIterationsLeft = gNumRepetitions;
    307     MediaSource::ReadOptions options;
    308 
    309     int64_t sumDecodeUs = 0;
    310     int64_t totalBytes = 0;
    311 
    312     Vector<int64_t> decodeTimesUs;
    313 
    314     while (numIterationsLeft-- > 0) {
    315         long numFrames = 0;
    316 
    317         MediaBuffer *buffer;
    318 
    319         for (;;) {
    320             int64_t startDecodeUs = getNowUs();
    321             status_t err = rawSource->read(&buffer, &options);
    322             int64_t delayDecodeUs = getNowUs() - startDecodeUs;
    323 
    324             options.clearSeekTo();
    325 
    326             if (err != OK) {
    327                 CHECK(buffer == NULL);
    328 
    329                 if (err == INFO_FORMAT_CHANGED) {
    330                     printf("format changed.\n");
    331                     continue;
    332                 }
    333 
    334                 break;
    335             }
    336 
    337             if (buffer->range_length() > 0) {
    338                 if (gDisplayHistogram && n > 0) {
    339                     // Ignore the first time since it includes some setup
    340                     // cost.
    341                     decodeTimesUs.push(delayDecodeUs);
    342                 }
    343 
    344                 if ((n++ % 16) == 0) {
    345                     printf(".");
    346                     fflush(stdout);
    347                 }
    348             }
    349 
    350             sumDecodeUs += delayDecodeUs;
    351             totalBytes += buffer->range_length();
    352 
    353             buffer->release();
    354             buffer = NULL;
    355 
    356             ++numFrames;
    357             if (gMaxNumFrames > 0 && numFrames == gMaxNumFrames) {
    358                 break;
    359             }
    360 
    361             if (gReproduceBug == 1 && numFrames == 40) {
    362                 printf("seeking past the end now.");
    363                 options.setSeekTo(0x7fffffffL);
    364             } else if (gReproduceBug == 2 && numFrames == 40) {
    365                 printf("seeking to 5 secs.");
    366                 options.setSeekTo(5000000);
    367             }
    368         }
    369 
    370         printf("$");
    371         fflush(stdout);
    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 %lld bytes\n", totalBytes);
    397     }
    398 }
    399 
    400 ////////////////////////////////////////////////////////////////////////////////
    401 
    402 struct DetectSyncSource : public MediaSource {
    403     DetectSyncSource(const sp<MediaSource> &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 
    412 private:
    413     enum StreamType {
    414         AVC,
    415         MPEG4,
    416         H263,
    417         OTHER,
    418     };
    419 
    420     sp<MediaSource> mSource;
    421     StreamType mStreamType;
    422     bool mSawFirstIDRFrame;
    423 
    424     DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource);
    425 };
    426 
    427 DetectSyncSource::DetectSyncSource(const sp<MediaSource> &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 
    445 status_t DetectSyncSource::start(MetaData *params) {
    446     mSawFirstIDRFrame = false;
    447 
    448     return mSource->start(params);
    449 }
    450 
    451 status_t DetectSyncSource::stop() {
    452     return mSource->stop();
    453 }
    454 
    455 sp<MetaData> DetectSyncSource::getFormat() {
    456     return mSource->getFormat();
    457 }
    458 
    459 static 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 
    475 status_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 
    508 static void writeSourcesToMP4(
    509         Vector<sp<MediaSource> > &sources, bool syncInfoPresent) {
    510 #if 0
    511     sp<MPEG4Writer> writer =
    512         new MPEG4Writer(gWriteMP4Filename.string());
    513 #else
    514     sp<MPEG2TSWriter> writer =
    515         new MPEG2TSWriter(gWriteMP4Filename.string());
    516 #endif
    517 
    518     // at most one minute.
    519     writer->setMaxFileDuration(60000000ll);
    520 
    521     for (size_t i = 0; i < sources.size(); ++i) {
    522         sp<MediaSource> source = sources.editItemAt(i);
    523 
    524         CHECK_EQ(writer->addSource(
    525                     syncInfoPresent ? source : new DetectSyncSource(source)),
    526                 (status_t)OK);
    527     }
    528 
    529     sp<MetaData> params = new MetaData;
    530     params->setInt32(kKeyNotRealTime, true);
    531     CHECK_EQ(writer->start(params.get()), (status_t)OK);
    532 
    533     while (!writer->reachedEOS()) {
    534         usleep(100000);
    535     }
    536     writer->stop();
    537 }
    538 
    539 static void performSeekTest(const sp<MediaSource> &source) {
    540     CHECK_EQ((status_t)OK, source->start());
    541 
    542     int64_t durationUs;
    543     CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs));
    544 
    545     for (int64_t seekTimeUs = 0; seekTimeUs <= durationUs;
    546             seekTimeUs += 60000ll) {
    547         MediaSource::ReadOptions options;
    548         options.setSeekTo(
    549                 seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
    550 
    551         MediaBuffer *buffer;
    552         status_t err;
    553         for (;;) {
    554             err = source->read(&buffer, &options);
    555 
    556             options.clearSeekTo();
    557 
    558             if (err == INFO_FORMAT_CHANGED) {
    559                 CHECK(buffer == NULL);
    560                 continue;
    561             }
    562 
    563             if (err != OK) {
    564                 CHECK(buffer == NULL);
    565                 break;
    566             }
    567 
    568             if (buffer->range_length() > 0) {
    569                 break;
    570             }
    571 
    572             CHECK(buffer != NULL);
    573 
    574             buffer->release();
    575             buffer = NULL;
    576         }
    577 
    578         if (err == OK) {
    579             int64_t timeUs;
    580             CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
    581 
    582             printf("%lld\t%lld\t%lld\n", seekTimeUs, timeUs, seekTimeUs - timeUs);
    583 
    584             buffer->release();
    585             buffer = NULL;
    586         } else {
    587             printf("ERROR\n");
    588             break;
    589         }
    590     }
    591 
    592     CHECK_EQ((status_t)OK, source->stop());
    593 }
    594 
    595 static void usage(const char *me) {
    596     fprintf(stderr, "usage: %s\n", me);
    597     fprintf(stderr, "       -h(elp)\n");
    598     fprintf(stderr, "       -a(udio)\n");
    599     fprintf(stderr, "       -n repetitions\n");
    600     fprintf(stderr, "       -l(ist) components\n");
    601     fprintf(stderr, "       -m max-number-of-frames-to-decode in each pass\n");
    602     fprintf(stderr, "       -b bug to reproduce\n");
    603     fprintf(stderr, "       -p(rofiles) dump decoder profiles supported\n");
    604     fprintf(stderr, "       -t(humbnail) extract video thumbnail or album art\n");
    605     fprintf(stderr, "       -s(oftware) prefer software codec\n");
    606     fprintf(stderr, "       -r(hardware) force to use hardware codec\n");
    607     fprintf(stderr, "       -o playback audio\n");
    608     fprintf(stderr, "       -w(rite) filename (write to .mp4 file)\n");
    609     fprintf(stderr, "       -k seek test\n");
    610     fprintf(stderr, "       -x display a histogram of decoding times/fps "
    611                     "(video only)\n");
    612     fprintf(stderr, "       -S allocate buffers from a surface\n");
    613     fprintf(stderr, "       -T allocate buffers from a surface texture\n");
    614     fprintf(stderr, "       -d(ump) filename (raw stream data to a file)\n");
    615 }
    616 
    617 int main(int argc, char **argv) {
    618     android::ProcessState::self()->startThreadPool();
    619 
    620     bool audioOnly = false;
    621     bool listComponents = false;
    622     bool dumpProfiles = false;
    623     bool extractThumbnail = false;
    624     bool seekTest = false;
    625     bool useSurfaceAlloc = false;
    626     bool useSurfaceTexAlloc = false;
    627     bool dumpStream = false;
    628     String8 dumpStreamFilename;
    629     gNumRepetitions = 1;
    630     gMaxNumFrames = 0;
    631     gReproduceBug = -1;
    632     gPreferSoftwareCodec = false;
    633     gForceToUseHardwareCodec = false;
    634     gPlaybackAudio = false;
    635     gWriteMP4 = false;
    636     gDisplayHistogram = false;
    637 
    638     sp<ALooper> looper;
    639     sp<ARTSPController> rtspController;
    640     sp<LiveSession> liveSession;
    641 
    642     int res;
    643     while ((res = getopt(argc, argv, "han:lm:b:ptsrow:kxSTd:")) >= 0) {
    644         switch (res) {
    645             case 'a':
    646             {
    647                 audioOnly = true;
    648                 break;
    649             }
    650 
    651             case 'd':
    652             {
    653                 dumpStream = true;
    654                 dumpStreamFilename.setTo(optarg);
    655                 break;
    656             }
    657 
    658             case 'l':
    659             {
    660                 listComponents = true;
    661                 break;
    662             }
    663 
    664             case 'm':
    665             case 'n':
    666             case 'b':
    667             {
    668                 char *end;
    669                 long x = strtol(optarg, &end, 10);
    670 
    671                 if (*end != '\0' || end == optarg || x <= 0) {
    672                     x = 1;
    673                 }
    674 
    675                 if (res == 'n') {
    676                     gNumRepetitions = x;
    677                 } else if (res == 'm') {
    678                     gMaxNumFrames = x;
    679                 } else {
    680                     CHECK_EQ(res, 'b');
    681                     gReproduceBug = x;
    682                 }
    683                 break;
    684             }
    685 
    686             case 'w':
    687             {
    688                 gWriteMP4 = true;
    689                 gWriteMP4Filename.setTo(optarg);
    690                 break;
    691             }
    692 
    693             case 'p':
    694             {
    695                 dumpProfiles = true;
    696                 break;
    697             }
    698 
    699             case 't':
    700             {
    701                 extractThumbnail = true;
    702                 break;
    703             }
    704 
    705             case 's':
    706             {
    707                 gPreferSoftwareCodec = true;
    708                 break;
    709             }
    710 
    711             case 'r':
    712             {
    713                 gForceToUseHardwareCodec = true;
    714                 break;
    715             }
    716 
    717             case 'o':
    718             {
    719                 gPlaybackAudio = true;
    720                 break;
    721             }
    722 
    723             case 'k':
    724             {
    725                 seekTest = true;
    726                 break;
    727             }
    728 
    729             case 'x':
    730             {
    731                 gDisplayHistogram = true;
    732                 break;
    733             }
    734 
    735             case 'S':
    736             {
    737                 useSurfaceAlloc = true;
    738                 break;
    739             }
    740 
    741             case 'T':
    742             {
    743                 useSurfaceTexAlloc = true;
    744                 break;
    745             }
    746 
    747             case '?':
    748             case 'h':
    749             default:
    750             {
    751                 usage(argv[0]);
    752                 exit(1);
    753                 break;
    754             }
    755         }
    756     }
    757 
    758     if (gPlaybackAudio && !audioOnly) {
    759         // This doesn't make any sense if we're decoding the video track.
    760         gPlaybackAudio = false;
    761     }
    762 
    763     argc -= optind;
    764     argv += optind;
    765 
    766     if (extractThumbnail) {
    767         sp<IServiceManager> sm = defaultServiceManager();
    768         sp<IBinder> binder = sm->getService(String16("media.player"));
    769         sp<IMediaPlayerService> service =
    770             interface_cast<IMediaPlayerService>(binder);
    771 
    772         CHECK(service.get() != NULL);
    773 
    774         sp<IMediaMetadataRetriever> retriever =
    775             service->createMetadataRetriever(getpid());
    776 
    777         CHECK(retriever != NULL);
    778 
    779         for (int k = 0; k < argc; ++k) {
    780             const char *filename = argv[k];
    781 
    782             bool failed = true;
    783             CHECK_EQ(retriever->setDataSource(filename), (status_t)OK);
    784             sp<IMemory> mem =
    785                     retriever->getFrameAtTime(-1,
    786                                     MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
    787 
    788             if (mem != NULL) {
    789                 failed = false;
    790                 printf("getFrameAtTime(%s) => OK\n", filename);
    791 
    792                 VideoFrame *frame = (VideoFrame *)mem->pointer();
    793 
    794                 SkBitmap bitmap;
    795                 bitmap.setConfig(
    796                         SkBitmap::kRGB_565_Config, frame->mWidth, frame->mHeight);
    797 
    798                 bitmap.setPixels((uint8_t *)frame + sizeof(VideoFrame));
    799 
    800                 CHECK(SkImageEncoder::EncodeFile(
    801                             "/sdcard/out.jpg", bitmap,
    802                             SkImageEncoder::kJPEG_Type,
    803                             SkImageEncoder::kDefaultQuality));
    804             }
    805 
    806             {
    807                 mem = retriever->extractAlbumArt();
    808 
    809                 if (mem != NULL) {
    810                     failed = false;
    811                     printf("extractAlbumArt(%s) => OK\n", filename);
    812                 }
    813             }
    814 
    815             if (failed) {
    816                 printf("both getFrameAtTime and extractAlbumArt "
    817                     "failed on file '%s'.\n", filename);
    818             }
    819         }
    820 
    821         return 0;
    822     }
    823 
    824     if (dumpProfiles) {
    825         sp<IServiceManager> sm = defaultServiceManager();
    826         sp<IBinder> binder = sm->getService(String16("media.player"));
    827         sp<IMediaPlayerService> service =
    828             interface_cast<IMediaPlayerService>(binder);
    829 
    830         CHECK(service.get() != NULL);
    831 
    832         sp<IOMX> omx = service->getOMX();
    833         CHECK(omx.get() != NULL);
    834 
    835         const char *kMimeTypes[] = {
    836             MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
    837             MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC,
    838             MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB,
    839             MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
    840             MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
    841             MEDIA_MIMETYPE_VIDEO_VPX
    842         };
    843 
    844         for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]);
    845              ++k) {
    846             printf("type '%s':\n", kMimeTypes[k]);
    847 
    848             Vector<CodecCapabilities> results;
    849             // will retrieve hardware and software codecs
    850             CHECK_EQ(QueryCodecs(omx, kMimeTypes[k],
    851                                  true, // queryDecoders
    852                                  &results), (status_t)OK);
    853 
    854             for (size_t i = 0; i < results.size(); ++i) {
    855                 printf("  decoder '%s' supports ",
    856                        results[i].mComponentName.string());
    857 
    858                 if (results[i].mProfileLevels.size() == 0) {
    859                     printf("NOTHING.\n");
    860                     continue;
    861                 }
    862 
    863                 for (size_t j = 0; j < results[i].mProfileLevels.size(); ++j) {
    864                     const CodecProfileLevel &profileLevel =
    865                         results[i].mProfileLevels[j];
    866 
    867                     printf("%s%ld/%ld", j > 0 ? ", " : "",
    868                            profileLevel.mProfile, profileLevel.mLevel);
    869                 }
    870 
    871                 printf("\n");
    872             }
    873         }
    874     }
    875 
    876     if (listComponents) {
    877         sp<IServiceManager> sm = defaultServiceManager();
    878         sp<IBinder> binder = sm->getService(String16("media.player"));
    879         sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
    880 
    881         CHECK(service.get() != NULL);
    882 
    883         sp<IOMX> omx = service->getOMX();
    884         CHECK(omx.get() != NULL);
    885 
    886         List<IOMX::ComponentInfo> list;
    887         omx->listNodes(&list);
    888 
    889         for (List<IOMX::ComponentInfo>::iterator it = list.begin();
    890              it != list.end(); ++it) {
    891             printf("%s\t Roles: ", (*it).mName.string());
    892             for (List<String8>::iterator itRoles = (*it).mRoles.begin() ;
    893                     itRoles != (*it).mRoles.end() ; ++itRoles) {
    894                 printf("%s\t", (*itRoles).string());
    895             }
    896             printf("\n");
    897         }
    898     }
    899 
    900     sp<SurfaceComposerClient> composerClient;
    901     sp<SurfaceControl> control;
    902 
    903     if ((useSurfaceAlloc || useSurfaceTexAlloc) && !audioOnly) {
    904         if (useSurfaceAlloc) {
    905             composerClient = new SurfaceComposerClient;
    906             CHECK_EQ(composerClient->initCheck(), (status_t)OK);
    907 
    908             control = composerClient->createSurface(
    909                     String8("A Surface"),
    910                     0,
    911                     1280,
    912                     800,
    913                     PIXEL_FORMAT_RGB_565,
    914                     0);
    915 
    916             CHECK(control != NULL);
    917             CHECK(control->isValid());
    918 
    919             SurfaceComposerClient::openGlobalTransaction();
    920             CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
    921             CHECK_EQ(control->show(), (status_t)OK);
    922             SurfaceComposerClient::closeGlobalTransaction();
    923 
    924             gSurface = control->getSurface();
    925             CHECK(gSurface != NULL);
    926         } else {
    927             CHECK(useSurfaceTexAlloc);
    928 
    929             sp<SurfaceTexture> texture = new SurfaceTexture(0 /* tex */);
    930             gSurface = new SurfaceTextureClient(texture);
    931         }
    932 
    933         CHECK_EQ((status_t)OK,
    934                  native_window_api_connect(
    935                      gSurface.get(), NATIVE_WINDOW_API_MEDIA));
    936     }
    937 
    938     DataSource::RegisterDefaultSniffers();
    939 
    940     OMXClient client;
    941     status_t err = client.connect();
    942 
    943     for (int k = 0; k < argc; ++k) {
    944         bool syncInfoPresent = true;
    945 
    946         const char *filename = argv[k];
    947 
    948         sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
    949 
    950         if (strncasecmp(filename, "sine:", 5)
    951                 && strncasecmp(filename, "rtsp://", 7)
    952                 && strncasecmp(filename, "httplive://", 11)
    953                 && dataSource == NULL) {
    954             fprintf(stderr, "Unable to create data source.\n");
    955             return 1;
    956         }
    957 
    958         bool isJPEG = false;
    959 
    960         size_t len = strlen(filename);
    961         if (len >= 4 && !strcasecmp(filename + len - 4, ".jpg")) {
    962             isJPEG = true;
    963         }
    964 
    965         Vector<sp<MediaSource> > mediaSources;
    966         sp<MediaSource> mediaSource;
    967 
    968         if (isJPEG) {
    969             mediaSource = new JPEGSource(dataSource);
    970             if (gWriteMP4) {
    971                 mediaSources.push(mediaSource);
    972             }
    973         } else if (!strncasecmp("sine:", filename, 5)) {
    974             char *end;
    975             long sampleRate = strtol(filename + 5, &end, 10);
    976 
    977             if (end == filename + 5) {
    978                 sampleRate = 44100;
    979             }
    980             mediaSource = new SineSource(sampleRate, 1);
    981             if (gWriteMP4) {
    982                 mediaSources.push(mediaSource);
    983             }
    984         } else {
    985             sp<MediaExtractor> extractor;
    986 
    987             if (!strncasecmp("rtsp://", filename, 7)) {
    988                 if (looper == NULL) {
    989                     looper = new ALooper;
    990                     looper->start();
    991                 }
    992 
    993                 rtspController = new ARTSPController(looper);
    994                 status_t err = rtspController->connect(filename);
    995                 if (err != OK) {
    996                     fprintf(stderr, "could not connect to rtsp server.\n");
    997                     return -1;
    998                 }
    999 
   1000                 extractor = rtspController.get();
   1001 
   1002                 syncInfoPresent = false;
   1003             } else if (!strncasecmp("httplive://", filename, 11)) {
   1004                 String8 uri("http://");
   1005                 uri.append(filename + 11);
   1006 
   1007                 if (looper == NULL) {
   1008                     looper = new ALooper;
   1009                     looper->start();
   1010                 }
   1011                 liveSession = new LiveSession;
   1012                 looper->registerHandler(liveSession);
   1013 
   1014                 liveSession->connect(uri.string());
   1015                 dataSource = liveSession->getDataSource();
   1016 
   1017                 extractor =
   1018                     MediaExtractor::Create(
   1019                             dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
   1020 
   1021                 syncInfoPresent = false;
   1022             } else {
   1023                 extractor = MediaExtractor::Create(dataSource);
   1024                 if (extractor == NULL) {
   1025                     fprintf(stderr, "could not create extractor.\n");
   1026                     return -1;
   1027                 }
   1028 
   1029                 sp<MetaData> meta = extractor->getMetaData();
   1030 
   1031                 if (meta != NULL) {
   1032                     const char *mime;
   1033                     CHECK(meta->findCString(kKeyMIMEType, &mime));
   1034 
   1035                     if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
   1036                         syncInfoPresent = false;
   1037                     }
   1038                 }
   1039             }
   1040 
   1041             size_t numTracks = extractor->countTracks();
   1042 
   1043             if (gWriteMP4) {
   1044                 bool haveAudio = false;
   1045                 bool haveVideo = false;
   1046                 for (size_t i = 0; i < numTracks; ++i) {
   1047                     sp<MediaSource> source = extractor->getTrack(i);
   1048 
   1049                     const char *mime;
   1050                     CHECK(source->getFormat()->findCString(
   1051                                 kKeyMIMEType, &mime));
   1052 
   1053                     bool useTrack = false;
   1054                     if (!haveAudio && !strncasecmp("audio/", mime, 6)) {
   1055                         haveAudio = true;
   1056                         useTrack = true;
   1057                     } else if (!haveVideo && !strncasecmp("video/", mime, 6)) {
   1058                         haveVideo = true;
   1059                         useTrack = true;
   1060                     }
   1061 
   1062                     if (useTrack) {
   1063                         mediaSources.push(source);
   1064 
   1065                         if (haveAudio && haveVideo) {
   1066                             break;
   1067                         }
   1068                     }
   1069                 }
   1070             } else {
   1071                 sp<MetaData> meta;
   1072                 size_t i;
   1073                 for (i = 0; i < numTracks; ++i) {
   1074                     meta = extractor->getTrackMetaData(
   1075                             i, MediaExtractor::kIncludeExtensiveMetaData);
   1076 
   1077                     const char *mime;
   1078                     meta->findCString(kKeyMIMEType, &mime);
   1079 
   1080                     if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
   1081                         break;
   1082                     }
   1083 
   1084                     if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
   1085                         break;
   1086                     }
   1087 
   1088                     meta = NULL;
   1089                 }
   1090 
   1091                 if (meta == NULL) {
   1092                     fprintf(stderr,
   1093                             "No suitable %s track found. The '-a' option will "
   1094                             "target audio tracks only, the default is to target "
   1095                             "video tracks only.\n",
   1096                             audioOnly ? "audio" : "video");
   1097                     return -1;
   1098                 }
   1099 
   1100                 int64_t thumbTimeUs;
   1101                 if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) {
   1102                     printf("thumbnailTime: %lld us (%.2f secs)\n",
   1103                            thumbTimeUs, thumbTimeUs / 1E6);
   1104                 }
   1105 
   1106                 mediaSource = extractor->getTrack(i);
   1107             }
   1108         }
   1109 
   1110         if (gWriteMP4) {
   1111             writeSourcesToMP4(mediaSources, syncInfoPresent);
   1112         } else if (dumpStream) {
   1113             dumpSource(mediaSource, dumpStreamFilename);
   1114         } else if (seekTest) {
   1115             performSeekTest(mediaSource);
   1116         } else {
   1117             playSource(&client, mediaSource);
   1118         }
   1119 
   1120         if (rtspController != NULL) {
   1121             rtspController->disconnect();
   1122             rtspController.clear();
   1123 
   1124             sleep(3);
   1125         }
   1126     }
   1127 
   1128     if ((useSurfaceAlloc || useSurfaceTexAlloc) && !audioOnly) {
   1129         CHECK_EQ((status_t)OK,
   1130                  native_window_api_disconnect(
   1131                      gSurface.get(), NATIVE_WINDOW_API_MEDIA));
   1132 
   1133         gSurface.clear();
   1134 
   1135         if (useSurfaceAlloc) {
   1136             composerClient->dispose();
   1137         }
   1138     }
   1139 
   1140     client.disconnect();
   1141 
   1142     return 0;
   1143 }
   1144