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