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