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