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 "StagefrightMetadataRetriever"
19
20#include <inttypes.h>
21
22#include <utils/Log.h>
23#include <gui/Surface.h>
24
25#include "include/avc_utils.h"
26#include "include/StagefrightMetadataRetriever.h"
27
28#include <media/ICrypto.h>
29#include <media/IMediaHTTPService.h>
30
31#include <media/stagefright/foundation/ABuffer.h>
32#include <media/stagefright/foundation/ADebug.h>
33#include <media/stagefright/foundation/AMessage.h>
34#include <media/stagefright/ColorConverter.h>
35#include <media/stagefright/DataSource.h>
36#include <media/stagefright/FileSource.h>
37#include <media/stagefright/MediaBuffer.h>
38#include <media/stagefright/MediaCodec.h>
39#include <media/stagefright/MediaCodecList.h>
40#include <media/stagefright/MediaDefs.h>
41#include <media/stagefright/MediaErrors.h>
42#include <media/stagefright/MediaExtractor.h>
43#include <media/stagefright/MediaSource.h>
44#include <media/stagefright/MetaData.h>
45#include <media/stagefright/Utils.h>
46
47#include <CharacterEncodingDetector.h>
48
49namespace android {
50
51static const int64_t kBufferTimeOutUs = 30000ll; // 30 msec
52static const size_t kRetryCount = 20; // must be >0
53
54StagefrightMetadataRetriever::StagefrightMetadataRetriever()
55    : mParsedMetaData(false),
56      mAlbumArt(NULL) {
57    ALOGV("StagefrightMetadataRetriever()");
58
59    DataSource::RegisterDefaultSniffers();
60}
61
62StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
63    ALOGV("~StagefrightMetadataRetriever()");
64    clearMetadata();
65    if (mSource != NULL) {
66        mSource->close();
67    }
68}
69
70status_t StagefrightMetadataRetriever::setDataSource(
71        const sp<IMediaHTTPService> &httpService,
72        const char *uri,
73        const KeyedVector<String8, String8> *headers) {
74    ALOGV("setDataSource(%s)", uri);
75
76    clearMetadata();
77    mSource = DataSource::CreateFromURI(httpService, uri, headers);
78
79    if (mSource == NULL) {
80        ALOGE("Unable to create data source for '%s'.", uri);
81        return UNKNOWN_ERROR;
82    }
83
84    mExtractor = MediaExtractor::Create(mSource);
85
86    if (mExtractor == NULL) {
87        ALOGE("Unable to instantiate an extractor for '%s'.", uri);
88
89        mSource.clear();
90
91        return UNKNOWN_ERROR;
92    }
93
94    return OK;
95}
96
97// Warning caller retains ownership of the filedescriptor! Dup it if necessary.
98status_t StagefrightMetadataRetriever::setDataSource(
99        int fd, int64_t offset, int64_t length) {
100    fd = dup(fd);
101
102    ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
103
104    clearMetadata();
105    mSource = new FileSource(fd, offset, length);
106
107    status_t err;
108    if ((err = mSource->initCheck()) != OK) {
109        mSource.clear();
110
111        return err;
112    }
113
114    mExtractor = MediaExtractor::Create(mSource);
115
116    if (mExtractor == NULL) {
117        mSource.clear();
118
119        return UNKNOWN_ERROR;
120    }
121
122    return OK;
123}
124
125status_t StagefrightMetadataRetriever::setDataSource(
126        const sp<DataSource>& source) {
127    ALOGV("setDataSource(DataSource)");
128
129    clearMetadata();
130    mSource = source;
131    mExtractor = MediaExtractor::Create(mSource);
132
133    if (mExtractor == NULL) {
134        ALOGE("Failed to instantiate a MediaExtractor.");
135        mSource.clear();
136        return UNKNOWN_ERROR;
137    }
138
139    return OK;
140}
141
142static VideoFrame *extractVideoFrame(
143        const AString &componentName,
144        const sp<MetaData> &trackMeta,
145        const sp<IMediaSource> &source,
146        int64_t frameTimeUs,
147        int seekMode) {
148
149    sp<MetaData> format = source->getFormat();
150
151    sp<AMessage> videoFormat;
152    if (convertMetaDataToMessage(trackMeta, &videoFormat) != OK) {
153        ALOGE("b/23680780");
154        ALOGW("Failed to convert meta data to message");
155        return NULL;
156    }
157
158    // TODO: Use Flexible color instead
159    videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
160
161    status_t err;
162    sp<ALooper> looper = new ALooper;
163    looper->start();
164    sp<MediaCodec> decoder = MediaCodec::CreateByComponentName(
165            looper, componentName, &err);
166
167    if (decoder.get() == NULL || err != OK) {
168        ALOGW("Failed to instantiate decoder [%s]", componentName.c_str());
169        return NULL;
170    }
171
172    err = decoder->configure(videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
173    if (err != OK) {
174        ALOGW("configure returned error %d (%s)", err, asString(err));
175        decoder->release();
176        return NULL;
177    }
178
179    err = decoder->start();
180    if (err != OK) {
181        ALOGW("start returned error %d (%s)", err, asString(err));
182        decoder->release();
183        return NULL;
184    }
185
186    MediaSource::ReadOptions options;
187    if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
188        seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {
189
190        ALOGE("Unknown seek mode: %d", seekMode);
191        decoder->release();
192        return NULL;
193    }
194
195    MediaSource::ReadOptions::SeekMode mode =
196            static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
197
198    int64_t thumbNailTime;
199    if (frameTimeUs < 0) {
200        if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)
201                || thumbNailTime < 0) {
202            thumbNailTime = 0;
203        }
204        options.setSeekTo(thumbNailTime, mode);
205    } else {
206        thumbNailTime = -1;
207        options.setSeekTo(frameTimeUs, mode);
208    }
209
210    err = source->start();
211    if (err != OK) {
212        ALOGW("source failed to start: %d (%s)", err, asString(err));
213        decoder->release();
214        return NULL;
215    }
216
217    Vector<sp<ABuffer> > inputBuffers;
218    err = decoder->getInputBuffers(&inputBuffers);
219    if (err != OK) {
220        ALOGW("failed to get input buffers: %d (%s)", err, asString(err));
221        decoder->release();
222        source->stop();
223        return NULL;
224    }
225
226    Vector<sp<ABuffer> > outputBuffers;
227    err = decoder->getOutputBuffers(&outputBuffers);
228    if (err != OK) {
229        ALOGW("failed to get output buffers: %d (%s)", err, asString(err));
230        decoder->release();
231        source->stop();
232        return NULL;
233    }
234
235    sp<AMessage> outputFormat = NULL;
236    bool haveMoreInputs = true;
237    size_t index, offset, size;
238    int64_t timeUs;
239    size_t retriesLeft = kRetryCount;
240    bool done = false;
241    const char *mime;
242    bool success = format->findCString(kKeyMIMEType, &mime);
243    if (!success) {
244        ALOGE("Could not find mime type");
245        return NULL;
246    }
247
248    bool isAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
249            || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
250
251    do {
252        size_t inputIndex = -1;
253        int64_t ptsUs = 0ll;
254        uint32_t flags = 0;
255        sp<ABuffer> codecBuffer = NULL;
256
257        while (haveMoreInputs) {
258            err = decoder->dequeueInputBuffer(&inputIndex, kBufferTimeOutUs);
259            if (err != OK) {
260                ALOGW("Timed out waiting for input");
261                if (retriesLeft) {
262                    err = OK;
263                }
264                break;
265            }
266            codecBuffer = inputBuffers[inputIndex];
267
268            MediaBuffer *mediaBuffer = NULL;
269
270            err = source->read(&mediaBuffer, &options);
271            options.clearSeekTo();
272            if (err != OK) {
273                ALOGW("Input Error or EOS");
274                haveMoreInputs = false;
275                break;
276            }
277
278            if (mediaBuffer->range_length() > codecBuffer->capacity()) {
279                ALOGE("buffer size (%zu) too large for codec input size (%zu)",
280                        mediaBuffer->range_length(), codecBuffer->capacity());
281                err = BAD_VALUE;
282            } else {
283                codecBuffer->setRange(0, mediaBuffer->range_length());
284
285                CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &ptsUs));
286                memcpy(codecBuffer->data(),
287                        (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
288                        mediaBuffer->range_length());
289                if (isAvcOrHevc && IsIDR(codecBuffer)) {
290                    // Only need to decode one IDR frame.
291                    haveMoreInputs = false;
292                    flags |= MediaCodec::BUFFER_FLAG_EOS;
293                }
294            }
295
296            mediaBuffer->release();
297            break;
298        }
299
300        if (err == OK && inputIndex < inputBuffers.size()) {
301            ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
302                    codecBuffer->size(), ptsUs, flags);
303            err = decoder->queueInputBuffer(
304                    inputIndex,
305                    codecBuffer->offset(),
306                    codecBuffer->size(),
307                    ptsUs,
308                    flags);
309
310            // we don't expect an output from codec config buffer
311            if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
312                continue;
313            }
314        }
315
316        while (err == OK) {
317            // wait for a decoded buffer
318            err = decoder->dequeueOutputBuffer(
319                    &index,
320                    &offset,
321                    &size,
322                    &timeUs,
323                    &flags,
324                    kBufferTimeOutUs);
325
326            if (err == INFO_FORMAT_CHANGED) {
327                ALOGV("Received format change");
328                err = decoder->getOutputFormat(&outputFormat);
329            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
330                ALOGV("Output buffers changed");
331                err = decoder->getOutputBuffers(&outputBuffers);
332            } else {
333                if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) {
334                    ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
335                    err = OK;
336                } else if (err == OK) {
337                    ALOGV("Received an output buffer");
338                    done = true;
339                } else {
340                    ALOGW("Received error %d (%s) instead of output", err, asString(err));
341                    done = true;
342                }
343                break;
344            }
345        }
346    } while (err == OK && !done);
347
348    if (err != OK || size <= 0 || outputFormat == NULL) {
349        ALOGE("Failed to decode thumbnail frame");
350        source->stop();
351        decoder->release();
352        return NULL;
353    }
354
355    ALOGV("successfully decoded video frame.");
356    sp<ABuffer> videoFrameBuffer = outputBuffers.itemAt(index);
357
358    if (thumbNailTime >= 0) {
359        if (timeUs != thumbNailTime) {
360            AString mime;
361            CHECK(outputFormat->findString("mime", &mime));
362
363            ALOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s",
364                    (long long)thumbNailTime, (long long)timeUs, mime.c_str());
365        }
366    }
367
368    int32_t width, height;
369    CHECK(outputFormat->findInt32("width", &width));
370    CHECK(outputFormat->findInt32("height", &height));
371
372    int32_t crop_left, crop_top, crop_right, crop_bottom;
373    if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
374        crop_left = crop_top = 0;
375        crop_right = width - 1;
376        crop_bottom = height - 1;
377    }
378
379    int32_t rotationAngle;
380    if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
381        rotationAngle = 0;  // By default, no rotation
382    }
383
384    VideoFrame *frame = new VideoFrame;
385    frame->mWidth = crop_right - crop_left + 1;
386    frame->mHeight = crop_bottom - crop_top + 1;
387    frame->mDisplayWidth = frame->mWidth;
388    frame->mDisplayHeight = frame->mHeight;
389    frame->mSize = frame->mWidth * frame->mHeight * 2;
390    frame->mData = new uint8_t[frame->mSize];
391    frame->mRotationAngle = rotationAngle;
392
393    int32_t sarWidth, sarHeight;
394    if (trackMeta->findInt32(kKeySARWidth, &sarWidth)
395            && trackMeta->findInt32(kKeySARHeight, &sarHeight)
396            && sarHeight != 0) {
397        frame->mDisplayWidth = (frame->mDisplayWidth * sarWidth) / sarHeight;
398    }
399
400    int32_t srcFormat;
401    CHECK(outputFormat->findInt32("color-format", &srcFormat));
402
403    ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
404
405    if (converter.isValid()) {
406        err = converter.convert(
407                (const uint8_t *)videoFrameBuffer->data(),
408                width, height,
409                crop_left, crop_top, crop_right, crop_bottom,
410                frame->mData,
411                frame->mWidth,
412                frame->mHeight,
413                0, 0, frame->mWidth - 1, frame->mHeight - 1);
414    } else {
415        ALOGE("Unable to convert from format 0x%08x to RGB565", srcFormat);
416
417        err = ERROR_UNSUPPORTED;
418    }
419
420    videoFrameBuffer.clear();
421    source->stop();
422    decoder->releaseOutputBuffer(index);
423    decoder->release();
424
425    if (err != OK) {
426        ALOGE("Colorconverter failed to convert frame.");
427
428        delete frame;
429        frame = NULL;
430    }
431
432    return frame;
433}
434
435VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
436        int64_t timeUs, int option) {
437
438    ALOGV("getFrameAtTime: %" PRId64 " us option: %d", timeUs, option);
439
440    if (mExtractor.get() == NULL) {
441        ALOGV("no extractor.");
442        return NULL;
443    }
444
445    sp<MetaData> fileMeta = mExtractor->getMetaData();
446
447    if (fileMeta == NULL) {
448        ALOGV("extractor doesn't publish metadata, failed to initialize?");
449        return NULL;
450    }
451
452    int32_t drm = 0;
453    if (fileMeta->findInt32(kKeyIsDRM, &drm) && drm != 0) {
454        ALOGE("frame grab not allowed.");
455        return NULL;
456    }
457
458    size_t n = mExtractor->countTracks();
459    size_t i;
460    for (i = 0; i < n; ++i) {
461        sp<MetaData> meta = mExtractor->getTrackMetaData(i);
462
463        const char *mime;
464        CHECK(meta->findCString(kKeyMIMEType, &mime));
465
466        if (!strncasecmp(mime, "video/", 6)) {
467            break;
468        }
469    }
470
471    if (i == n) {
472        ALOGV("no video track found.");
473        return NULL;
474    }
475
476    sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
477            i, MediaExtractor::kIncludeExtensiveMetaData);
478
479    sp<IMediaSource> source = mExtractor->getTrack(i);
480
481    if (source.get() == NULL) {
482        ALOGV("unable to instantiate video track.");
483        return NULL;
484    }
485
486    const void *data;
487    uint32_t type;
488    size_t dataSize;
489    if (fileMeta->findData(kKeyAlbumArt, &type, &data, &dataSize)
490            && mAlbumArt == NULL) {
491        mAlbumArt = MediaAlbumArt::fromData(dataSize, data);
492    }
493
494    const char *mime;
495    CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
496
497    Vector<AString> matchingCodecs;
498    MediaCodecList::findMatchingCodecs(
499            mime,
500            false, /* encoder */
501            MediaCodecList::kPreferSoftwareCodecs,
502            &matchingCodecs);
503
504    for (size_t i = 0; i < matchingCodecs.size(); ++i) {
505        const AString &componentName = matchingCodecs[i];
506        VideoFrame *frame =
507            extractVideoFrame(componentName, trackMeta, source, timeUs, option);
508
509        if (frame != NULL) {
510            return frame;
511        }
512        ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
513    }
514
515    return NULL;
516}
517
518MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
519    ALOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
520
521    if (mExtractor == NULL) {
522        return NULL;
523    }
524
525    if (!mParsedMetaData) {
526        parseMetaData();
527
528        mParsedMetaData = true;
529    }
530
531    if (mAlbumArt) {
532        return mAlbumArt->clone();
533    }
534
535    return NULL;
536}
537
538const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
539    if (mExtractor == NULL) {
540        return NULL;
541    }
542
543    if (!mParsedMetaData) {
544        parseMetaData();
545
546        mParsedMetaData = true;
547    }
548
549    ssize_t index = mMetaData.indexOfKey(keyCode);
550
551    if (index < 0) {
552        return NULL;
553    }
554
555    return mMetaData.valueAt(index).string();
556}
557
558void StagefrightMetadataRetriever::parseMetaData() {
559    sp<MetaData> meta = mExtractor->getMetaData();
560
561    if (meta == NULL) {
562        ALOGV("extractor doesn't publish metadata, failed to initialize?");
563        return;
564    }
565
566    struct Map {
567        int from;
568        int to;
569        const char *name;
570    };
571    static const Map kMap[] = {
572        { kKeyMIMEType, METADATA_KEY_MIMETYPE, NULL },
573        { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER, "tracknumber" },
574        { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER, "discnumber" },
575        { kKeyAlbum, METADATA_KEY_ALBUM, "album" },
576        { kKeyArtist, METADATA_KEY_ARTIST, "artist" },
577        { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST, "albumartist" },
578        { kKeyAuthor, METADATA_KEY_AUTHOR, NULL },
579        { kKeyComposer, METADATA_KEY_COMPOSER, "composer" },
580        { kKeyDate, METADATA_KEY_DATE, NULL },
581        { kKeyGenre, METADATA_KEY_GENRE, "genre" },
582        { kKeyTitle, METADATA_KEY_TITLE, "title" },
583        { kKeyYear, METADATA_KEY_YEAR, "year" },
584        { kKeyWriter, METADATA_KEY_WRITER, "writer" },
585        { kKeyCompilation, METADATA_KEY_COMPILATION, "compilation" },
586        { kKeyLocation, METADATA_KEY_LOCATION, NULL },
587    };
588
589    static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
590
591    CharacterEncodingDetector *detector = new CharacterEncodingDetector();
592
593    for (size_t i = 0; i < kNumMapEntries; ++i) {
594        const char *value;
595        if (meta->findCString(kMap[i].from, &value)) {
596            if (kMap[i].name) {
597                // add to charset detector
598                detector->addTag(kMap[i].name, value);
599            } else {
600                // directly add to output list
601                mMetaData.add(kMap[i].to, String8(value));
602            }
603        }
604    }
605
606    detector->detectAndConvert();
607    int size = detector->size();
608    if (size) {
609        for (int i = 0; i < size; i++) {
610            const char *name;
611            const char *value;
612            detector->getTag(i, &name, &value);
613            for (size_t j = 0; j < kNumMapEntries; ++j) {
614                if (kMap[j].name && !strcmp(kMap[j].name, name)) {
615                    mMetaData.add(kMap[j].to, String8(value));
616                }
617            }
618        }
619    }
620    delete detector;
621
622    const void *data;
623    uint32_t type;
624    size_t dataSize;
625    if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)
626            && mAlbumArt == NULL) {
627        mAlbumArt = MediaAlbumArt::fromData(dataSize, data);
628    }
629
630    size_t numTracks = mExtractor->countTracks();
631
632    char tmp[32];
633    sprintf(tmp, "%zu", numTracks);
634
635    mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
636
637    float captureFps;
638    if (meta->findFloat(kKeyCaptureFramerate, &captureFps)) {
639        sprintf(tmp, "%f", captureFps);
640        mMetaData.add(METADATA_KEY_CAPTURE_FRAMERATE, String8(tmp));
641    }
642
643    bool hasAudio = false;
644    bool hasVideo = false;
645    int32_t videoWidth = -1;
646    int32_t videoHeight = -1;
647    int32_t audioBitrate = -1;
648    int32_t rotationAngle = -1;
649
650    // The overall duration is the duration of the longest track.
651    int64_t maxDurationUs = 0;
652    String8 timedTextLang;
653    for (size_t i = 0; i < numTracks; ++i) {
654        sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
655
656        int64_t durationUs;
657        if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
658            if (durationUs > maxDurationUs) {
659                maxDurationUs = durationUs;
660            }
661        }
662
663        const char *mime;
664        if (trackMeta->findCString(kKeyMIMEType, &mime)) {
665            if (!hasAudio && !strncasecmp("audio/", mime, 6)) {
666                hasAudio = true;
667
668                if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
669                    audioBitrate = -1;
670                }
671            } else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
672                hasVideo = true;
673
674                CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
675                CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
676                if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
677                    rotationAngle = 0;
678                }
679            } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
680                const char *lang;
681                if (trackMeta->findCString(kKeyMediaLanguage, &lang)) {
682                    timedTextLang.append(String8(lang));
683                    timedTextLang.append(String8(":"));
684                } else {
685                    ALOGE("No language found for timed text");
686                }
687            }
688        }
689    }
690
691    // To save the language codes for all timed text tracks
692    // If multiple text tracks present, the format will look
693    // like "eng:chi"
694    if (!timedTextLang.isEmpty()) {
695        mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang);
696    }
697
698    // The duration value is a string representing the duration in ms.
699    sprintf(tmp, "%" PRId64, (maxDurationUs + 500) / 1000);
700    mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
701
702    if (hasAudio) {
703        mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes"));
704    }
705
706    if (hasVideo) {
707        mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes"));
708
709        sprintf(tmp, "%d", videoWidth);
710        mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp));
711
712        sprintf(tmp, "%d", videoHeight);
713        mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
714
715        sprintf(tmp, "%d", rotationAngle);
716        mMetaData.add(METADATA_KEY_VIDEO_ROTATION, String8(tmp));
717    }
718
719    if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
720        sprintf(tmp, "%d", audioBitrate);
721        mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
722    } else {
723        off64_t sourceSize;
724        if (mSource != NULL && mSource->getSize(&sourceSize) == OK) {
725            int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs);
726
727            sprintf(tmp, "%" PRId64, avgBitRate);
728            mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
729        }
730    }
731
732    if (numTracks == 1) {
733        const char *fileMIME;
734        CHECK(meta->findCString(kKeyMIMEType, &fileMIME));
735
736        if (!strcasecmp(fileMIME, "video/x-matroska")) {
737            sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0);
738            const char *trackMIME;
739            CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME));
740
741            if (!strncasecmp("audio/", trackMIME, 6)) {
742                // The matroska file only contains a single audio track,
743                // rewrite its mime type.
744                mMetaData.add(
745                        METADATA_KEY_MIMETYPE, String8("audio/x-matroska"));
746            }
747        }
748    }
749
750    // To check whether the media file is drm-protected
751    if (mExtractor->getDrmFlag()) {
752        mMetaData.add(METADATA_KEY_IS_DRM, String8("1"));
753    }
754}
755
756void StagefrightMetadataRetriever::clearMetadata() {
757    mParsedMetaData = false;
758    mMetaData.clear();
759    delete mAlbumArt;
760    mAlbumArt = NULL;
761}
762
763}  // namespace android
764