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