stagefright.cpp revision bbc38312e4521cfd4299203591ef366b7624f043
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "stagefright"
19#include <media/stagefright/foundation/ADebug.h>
20
21#include <sys/time.h>
22
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26
27#include "SineSource.h"
28
29#include <binder/IServiceManager.h>
30#include <binder/ProcessState.h>
31#include <media/IMediaPlayerService.h>
32#include <media/stagefright/foundation/ALooper.h>
33#include "include/ARTSPController.h"
34#include <media/stagefright/AudioPlayer.h>
35#include <media/stagefright/DataSource.h>
36#include <media/stagefright/JPEGSource.h>
37#include <media/stagefright/MediaDefs.h>
38#include <media/stagefright/MediaErrors.h>
39#include <media/stagefright/MediaExtractor.h>
40#include <media/stagefright/MediaSource.h>
41#include <media/stagefright/MetaData.h>
42#include <media/stagefright/OMXClient.h>
43#include <media/stagefright/OMXCodec.h>
44#include <media/mediametadataretriever.h>
45
46#include <media/stagefright/foundation/hexdump.h>
47#include <media/stagefright/MPEG4Writer.h>
48
49#include <fcntl.h>
50
51using namespace android;
52
53static long gNumRepetitions;
54static long gMaxNumFrames;  // 0 means decode all available.
55static long gReproduceBug;  // if not -1.
56static bool gPreferSoftwareCodec;
57static bool gPlaybackAudio;
58static bool gWriteMP4;
59static String8 gWriteMP4Filename;
60
61static int64_t getNowUs() {
62    struct timeval tv;
63    gettimeofday(&tv, NULL);
64
65    return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll;
66}
67
68static void playSource(OMXClient *client, sp<MediaSource> &source) {
69    sp<MetaData> meta = source->getFormat();
70
71    const char *mime;
72    CHECK(meta->findCString(kKeyMIMEType, &mime));
73
74    sp<MediaSource> rawSource;
75    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) {
76        rawSource = source;
77    } else {
78        rawSource = OMXCodec::Create(
79            client->interface(), meta, false /* createEncoder */, source,
80            NULL /* matchComponentName */,
81            gPreferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0);
82
83        if (rawSource == NULL) {
84            fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime);
85            return;
86        }
87    }
88
89    source.clear();
90
91    status_t err = rawSource->start();
92
93    if (err != OK) {
94        fprintf(stderr, "rawSource returned error %d (0x%08x)\n", err, err);
95        return;
96    }
97
98    if (gPlaybackAudio) {
99        AudioPlayer *player = new AudioPlayer(NULL);
100        player->setSource(rawSource);
101        rawSource.clear();
102
103        player->start(true /* sourceAlreadyStarted */);
104
105        status_t finalStatus;
106        while (!player->reachedEOS(&finalStatus)) {
107            usleep(100000ll);
108        }
109
110        delete player;
111        player = NULL;
112
113        return;
114    } else if (gReproduceBug >= 3 && gReproduceBug <= 5) {
115        int64_t durationUs;
116        CHECK(meta->findInt64(kKeyDuration, &durationUs));
117
118        status_t err;
119        MediaBuffer *buffer;
120        MediaSource::ReadOptions options;
121        int64_t seekTimeUs = -1;
122        for (;;) {
123            err = rawSource->read(&buffer, &options);
124            options.clearSeekTo();
125
126            bool shouldSeek = false;
127            if (err == INFO_FORMAT_CHANGED) {
128                CHECK(buffer == NULL);
129
130                printf("format changed.\n");
131                continue;
132            } else if (err != OK) {
133                printf("reached EOF.\n");
134
135                shouldSeek = true;
136            } else {
137                int64_t timestampUs;
138                CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
139
140                bool failed = false;
141
142                if (seekTimeUs >= 0) {
143                    int64_t diff = timestampUs - seekTimeUs;
144
145                    if (diff < 0) {
146                        diff = -diff;
147                    }
148
149                    if ((gReproduceBug == 4 && diff > 500000)
150                        || (gReproduceBug == 5 && timestampUs < 0)) {
151                        printf("wanted: %.2f secs, got: %.2f secs\n",
152                               seekTimeUs / 1E6, timestampUs / 1E6);
153
154                        printf("ERROR: ");
155                        failed = true;
156                    }
157                }
158
159                printf("buffer has timestamp %lld us (%.2f secs)\n",
160                       timestampUs, timestampUs / 1E6);
161
162                buffer->release();
163                buffer = NULL;
164
165                if (failed) {
166                    break;
167                }
168
169                shouldSeek = ((double)rand() / RAND_MAX) < 0.1;
170
171                if (gReproduceBug == 3) {
172                    shouldSeek = false;
173                }
174            }
175
176            seekTimeUs = -1;
177
178            if (shouldSeek) {
179                seekTimeUs = (rand() * (float)durationUs) / RAND_MAX;
180                options.setSeekTo(seekTimeUs);
181
182                printf("seeking to %lld us (%.2f secs)\n",
183                       seekTimeUs, seekTimeUs / 1E6);
184            }
185        }
186
187        rawSource->stop();
188
189        return;
190    }
191
192    int n = 0;
193    int64_t startTime = getNowUs();
194
195    long numIterationsLeft = gNumRepetitions;
196    MediaSource::ReadOptions options;
197
198    int64_t sumDecodeUs = 0;
199    int64_t totalBytes = 0;
200
201    while (numIterationsLeft-- > 0) {
202        long numFrames = 0;
203
204        MediaBuffer *buffer;
205
206        for (;;) {
207            int64_t startDecodeUs = getNowUs();
208            status_t err = rawSource->read(&buffer, &options);
209            int64_t delayDecodeUs = getNowUs() - startDecodeUs;
210
211            options.clearSeekTo();
212
213            if (err != OK) {
214                CHECK(buffer == NULL);
215
216                if (err == INFO_FORMAT_CHANGED) {
217                    printf("format changed.\n");
218                    continue;
219                }
220
221                break;
222            }
223
224            if (buffer->range_length() > 0 && (n++ % 16) == 0) {
225                printf(".");
226                fflush(stdout);
227            }
228
229            sumDecodeUs += delayDecodeUs;
230            totalBytes += buffer->range_length();
231
232            buffer->release();
233            buffer = NULL;
234
235            ++numFrames;
236            if (gMaxNumFrames > 0 && numFrames == gMaxNumFrames) {
237                break;
238            }
239
240            if (gReproduceBug == 1 && numFrames == 40) {
241                printf("seeking past the end now.");
242                options.setSeekTo(0x7fffffffL);
243            } else if (gReproduceBug == 2 && numFrames == 40) {
244                printf("seeking to 5 secs.");
245                options.setSeekTo(5000000);
246            }
247        }
248
249        printf("$");
250        fflush(stdout);
251
252        options.setSeekTo(0);
253    }
254
255    rawSource->stop();
256    printf("\n");
257
258    int64_t delay = getNowUs() - startTime;
259    if (!strncasecmp("video/", mime, 6)) {
260        printf("avg. %.2f fps\n", n * 1E6 / delay);
261
262        printf("avg. time to decode one buffer %.2f usecs\n",
263               (double)sumDecodeUs / n);
264
265        printf("decoded a total of %d frame(s).\n", n);
266    } else if (!strncasecmp("audio/", mime, 6)) {
267        // Frame count makes less sense for audio, as the output buffer
268        // sizes may be different across decoders.
269        printf("avg. %.2f KB/sec\n", totalBytes / 1024 * 1E6 / delay);
270
271        printf("decoded a total of %lld bytes\n", totalBytes);
272    }
273}
274
275////////////////////////////////////////////////////////////////////////////////
276
277struct DetectSyncSource : public MediaSource {
278    DetectSyncSource(const sp<MediaSource> &source);
279
280    virtual status_t start(MetaData *params = NULL);
281    virtual status_t stop();
282    virtual sp<MetaData> getFormat();
283
284    virtual status_t read(
285            MediaBuffer **buffer, const ReadOptions *options);
286
287private:
288    sp<MediaSource> mSource;
289    bool mIsAVC;
290
291    DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource);
292};
293
294DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source)
295    : mSource(source),
296      mIsAVC(false) {
297    const char *mime;
298    CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
299
300    mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
301}
302
303status_t DetectSyncSource::start(MetaData *params) {
304    return mSource->start(params);
305}
306
307status_t DetectSyncSource::stop() {
308    return mSource->stop();
309}
310
311sp<MetaData> DetectSyncSource::getFormat() {
312    return mSource->getFormat();
313}
314
315static bool isIDRFrame(MediaBuffer *buffer) {
316    const uint8_t *data =
317        (const uint8_t *)buffer->data() + buffer->range_offset();
318    size_t size = buffer->range_length();
319    for (size_t i = 0; i + 3 < size; ++i) {
320        if (!memcmp("\x00\x00\x01", &data[i], 3)) {
321            uint8_t nalType = data[i + 3] & 0x1f;
322            if (nalType == 5) {
323                return true;
324            }
325        }
326    }
327
328    return false;
329}
330
331status_t DetectSyncSource::read(
332        MediaBuffer **buffer, const ReadOptions *options) {
333    status_t err = mSource->read(buffer, options);
334
335    if (err != OK) {
336        return err;
337    }
338
339    if (mIsAVC && isIDRFrame(*buffer)) {
340        (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, true);
341    } else {
342        (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, false);
343    }
344
345    return OK;
346}
347
348////////////////////////////////////////////////////////////////////////////////
349
350static void writeSourceToMP4(
351        sp<MediaSource> &source, bool syncInfoPresent) {
352    if (!syncInfoPresent) {
353        source = new DetectSyncSource(source);
354    }
355
356    sp<MPEG4Writer> writer =
357        new MPEG4Writer(gWriteMP4Filename.string());
358
359    // at most one minute.
360    writer->setMaxFileDuration(60000000ll);
361
362    CHECK_EQ(writer->addSource(source), (status_t)OK);
363
364    sp<MetaData> params = new MetaData;
365    params->setInt32(kKeyNotRealTime, true);
366    CHECK_EQ(writer->start(params.get()), (status_t)OK);
367
368    while (!writer->reachedEOS()) {
369        usleep(100000);
370    }
371    writer->stop();
372}
373
374static void performSeekTest(const sp<MediaSource> &source) {
375    CHECK_EQ((status_t)OK, source->start());
376
377    int64_t durationUs;
378    CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs));
379
380    for (int64_t seekTimeUs = 0; seekTimeUs <= durationUs;
381            seekTimeUs += 60000ll) {
382        MediaSource::ReadOptions options;
383        options.setSeekTo(
384                seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
385
386        MediaBuffer *buffer;
387        status_t err;
388        for (;;) {
389            err = source->read(&buffer, &options);
390
391            options.clearSeekTo();
392
393            if (err == INFO_FORMAT_CHANGED) {
394                CHECK(buffer == NULL);
395                continue;
396            }
397
398            if (err != OK) {
399                CHECK(buffer == NULL);
400                break;
401            }
402
403            if (buffer->range_length() > 0) {
404                break;
405            }
406
407            CHECK(buffer != NULL);
408
409            buffer->release();
410            buffer = NULL;
411        }
412
413        if (err == OK) {
414            int64_t timeUs;
415            CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
416
417            printf("%lld\t%lld\t%lld\n", seekTimeUs, timeUs, seekTimeUs - timeUs);
418
419            buffer->release();
420            buffer = NULL;
421        } else {
422            printf("ERROR\n");
423            break;
424        }
425    }
426
427    CHECK_EQ((status_t)OK, source->stop());
428}
429
430static void usage(const char *me) {
431    fprintf(stderr, "usage: %s\n", me);
432    fprintf(stderr, "       -h(elp)\n");
433    fprintf(stderr, "       -a(udio)\n");
434    fprintf(stderr, "       -n repetitions\n");
435    fprintf(stderr, "       -l(ist) components\n");
436    fprintf(stderr, "       -m max-number-of-frames-to-decode in each pass\n");
437    fprintf(stderr, "       -b bug to reproduce\n");
438    fprintf(stderr, "       -p(rofiles) dump decoder profiles supported\n");
439    fprintf(stderr, "       -t(humbnail) extract video thumbnail or album art\n");
440    fprintf(stderr, "       -s(oftware) prefer software codec\n");
441    fprintf(stderr, "       -o playback audio\n");
442    fprintf(stderr, "       -w(rite) filename (write to .mp4 file)\n");
443    fprintf(stderr, "       -k seek test\n");
444}
445
446int main(int argc, char **argv) {
447    android::ProcessState::self()->startThreadPool();
448
449    bool audioOnly = false;
450    bool listComponents = false;
451    bool dumpProfiles = false;
452    bool extractThumbnail = false;
453    bool seekTest = false;
454    gNumRepetitions = 1;
455    gMaxNumFrames = 0;
456    gReproduceBug = -1;
457    gPreferSoftwareCodec = false;
458    gPlaybackAudio = false;
459    gWriteMP4 = false;
460
461    sp<ALooper> looper;
462    sp<ARTSPController> rtspController;
463
464    int res;
465    while ((res = getopt(argc, argv, "han:lm:b:ptsow:k")) >= 0) {
466        switch (res) {
467            case 'a':
468            {
469                audioOnly = true;
470                break;
471            }
472
473            case 'l':
474            {
475                listComponents = true;
476                break;
477            }
478
479            case 'm':
480            case 'n':
481            case 'b':
482            {
483                char *end;
484                long x = strtol(optarg, &end, 10);
485
486                if (*end != '\0' || end == optarg || x <= 0) {
487                    x = 1;
488                }
489
490                if (res == 'n') {
491                    gNumRepetitions = x;
492                } else if (res == 'm') {
493                    gMaxNumFrames = x;
494                } else {
495                    CHECK_EQ(res, 'b');
496                    gReproduceBug = x;
497                }
498                break;
499            }
500
501            case 'w':
502            {
503                gWriteMP4 = true;
504                gWriteMP4Filename.setTo(optarg);
505                break;
506            }
507
508            case 'p':
509            {
510                dumpProfiles = true;
511                break;
512            }
513
514            case 't':
515            {
516                extractThumbnail = true;
517                break;
518            }
519
520            case 's':
521            {
522                gPreferSoftwareCodec = true;
523                break;
524            }
525
526            case 'o':
527            {
528                gPlaybackAudio = true;
529                break;
530            }
531
532            case 'k':
533            {
534                seekTest = true;
535                break;
536            }
537
538            case '?':
539            case 'h':
540            default:
541            {
542                usage(argv[0]);
543                exit(1);
544                break;
545            }
546        }
547    }
548
549    if (gPlaybackAudio && !audioOnly) {
550        // This doesn't make any sense if we're decoding the video track.
551        gPlaybackAudio = false;
552    }
553
554    argc -= optind;
555    argv += optind;
556
557    if (extractThumbnail) {
558        sp<IServiceManager> sm = defaultServiceManager();
559        sp<IBinder> binder = sm->getService(String16("media.player"));
560        sp<IMediaPlayerService> service =
561            interface_cast<IMediaPlayerService>(binder);
562
563        CHECK(service.get() != NULL);
564
565        sp<IMediaMetadataRetriever> retriever =
566            service->createMetadataRetriever(getpid());
567
568        CHECK(retriever != NULL);
569
570        for (int k = 0; k < argc; ++k) {
571            const char *filename = argv[k];
572
573            CHECK_EQ(retriever->setDataSource(filename), (status_t)OK);
574            CHECK_EQ(retriever->setMode(
575                        METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL),
576                     (status_t)OK);
577
578            sp<IMemory> mem = retriever->captureFrame();
579
580            if (mem != NULL) {
581                printf("captureFrame(%s) => OK\n", filename);
582            } else {
583                mem = retriever->extractAlbumArt();
584
585                if (mem != NULL) {
586                    printf("extractAlbumArt(%s) => OK\n", filename);
587                } else {
588                    printf("both captureFrame and extractAlbumArt "
589                           "failed on file '%s'.\n", filename);
590                }
591            }
592        }
593
594        return 0;
595    }
596
597    if (dumpProfiles) {
598        sp<IServiceManager> sm = defaultServiceManager();
599        sp<IBinder> binder = sm->getService(String16("media.player"));
600        sp<IMediaPlayerService> service =
601            interface_cast<IMediaPlayerService>(binder);
602
603        CHECK(service.get() != NULL);
604
605        sp<IOMX> omx = service->getOMX();
606        CHECK(omx.get() != NULL);
607
608        const char *kMimeTypes[] = {
609            MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
610            MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC,
611            MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB,
612            MEDIA_MIMETYPE_AUDIO_MPEG
613        };
614
615        for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]);
616             ++k) {
617            printf("type '%s':\n", kMimeTypes[k]);
618
619            Vector<CodecCapabilities> results;
620            CHECK_EQ(QueryCodecs(omx, kMimeTypes[k],
621                                 true, // queryDecoders
622                                 &results), (status_t)OK);
623
624            for (size_t i = 0; i < results.size(); ++i) {
625                printf("  decoder '%s' supports ",
626                       results[i].mComponentName.string());
627
628                if (results[i].mProfileLevels.size() == 0) {
629                    printf("NOTHING.\n");
630                    continue;
631                }
632
633                for (size_t j = 0; j < results[i].mProfileLevels.size(); ++j) {
634                    const CodecProfileLevel &profileLevel =
635                        results[i].mProfileLevels[j];
636
637                    printf("%s%ld/%ld", j > 0 ? ", " : "",
638                           profileLevel.mProfile, profileLevel.mLevel);
639                }
640
641                printf("\n");
642            }
643        }
644    }
645
646    if (listComponents) {
647        sp<IServiceManager> sm = defaultServiceManager();
648        sp<IBinder> binder = sm->getService(String16("media.player"));
649        sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
650
651        CHECK(service.get() != NULL);
652
653        sp<IOMX> omx = service->getOMX();
654        CHECK(omx.get() != NULL);
655
656        List<IOMX::ComponentInfo> list;
657        omx->listNodes(&list);
658
659        for (List<IOMX::ComponentInfo>::iterator it = list.begin();
660             it != list.end(); ++it) {
661            printf("%s\n", (*it).mName.string());
662        }
663    }
664
665    DataSource::RegisterDefaultSniffers();
666
667    OMXClient client;
668    status_t err = client.connect();
669
670    for (int k = 0; k < argc; ++k) {
671        bool syncInfoPresent = true;
672
673        const char *filename = argv[k];
674
675        sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
676
677        if ((strncasecmp(filename, "sine:", 5)
678                && strncasecmp(filename, "rtsp://", 7)) && dataSource == NULL) {
679            fprintf(stderr, "Unable to create data source.\n");
680            return 1;
681        }
682
683        bool isJPEG = false;
684
685        size_t len = strlen(filename);
686        if (len >= 4 && !strcasecmp(filename + len - 4, ".jpg")) {
687            isJPEG = true;
688        }
689
690        sp<MediaSource> mediaSource;
691
692        if (isJPEG) {
693            mediaSource = new JPEGSource(dataSource);
694        } else if (!strncasecmp("sine:", filename, 5)) {
695            char *end;
696            long sampleRate = strtol(filename + 5, &end, 10);
697
698            if (end == filename + 5) {
699                sampleRate = 44100;
700            }
701            mediaSource = new SineSource(sampleRate, 1);
702        } else {
703            sp<MediaExtractor> extractor;
704
705            if (!strncasecmp("rtsp://", filename, 7)) {
706                if (looper == NULL) {
707                    looper = new ALooper;
708                    looper->start();
709                }
710
711                rtspController = new ARTSPController(looper);
712                status_t err = rtspController->connect(filename);
713                if (err != OK) {
714                    fprintf(stderr, "could not connect to rtsp server.\n");
715                    return -1;
716                }
717
718                extractor = rtspController.get();
719
720                syncInfoPresent = false;
721            } else {
722                extractor = MediaExtractor::Create(dataSource);
723                if (extractor == NULL) {
724                    fprintf(stderr, "could not create extractor.\n");
725                    return -1;
726                }
727            }
728
729            size_t numTracks = extractor->countTracks();
730
731            sp<MetaData> meta;
732            size_t i;
733            for (i = 0; i < numTracks; ++i) {
734                meta = extractor->getTrackMetaData(
735                        i, MediaExtractor::kIncludeExtensiveMetaData);
736
737                const char *mime;
738                meta->findCString(kKeyMIMEType, &mime);
739
740                if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
741                    break;
742                }
743
744                if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
745                    break;
746                }
747
748                meta = NULL;
749            }
750
751            if (meta == NULL) {
752                fprintf(stderr,
753                        "No suitable %s track found. The '-a' option will "
754                        "target audio tracks only, the default is to target "
755                        "video tracks only.\n",
756                        audioOnly ? "audio" : "video");
757                return -1;
758            }
759
760            int64_t thumbTimeUs;
761            if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) {
762                printf("thumbnailTime: %lld us (%.2f secs)\n",
763                       thumbTimeUs, thumbTimeUs / 1E6);
764            }
765
766            mediaSource = extractor->getTrack(i);
767        }
768
769        if (gWriteMP4) {
770            writeSourceToMP4(mediaSource, syncInfoPresent);
771        } else if (seekTest) {
772            performSeekTest(mediaSource);
773        } else {
774            playSource(&client, mediaSource);
775        }
776
777        if (rtspController != NULL) {
778            rtspController->disconnect();
779            rtspController.clear();
780
781            sleep(3);
782        }
783    }
784
785    client.disconnect();
786
787    return 0;
788}
789