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, ×tampUs));
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