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