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