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