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 
     24 #include "include/StagefrightMetadataRetriever.h"
     25 
     26 #include <media/IMediaHTTPService.h>
     27 #include <media/stagefright/foundation/ADebug.h>
     28 #include <media/stagefright/ColorConverter.h>
     29 #include <media/stagefright/DataSource.h>
     30 #include <media/stagefright/FileSource.h>
     31 #include <media/stagefright/MediaExtractor.h>
     32 #include <media/stagefright/MetaData.h>
     33 #include <media/stagefright/OMXCodec.h>
     34 #include <media/stagefright/MediaDefs.h>
     35 #include <CharacterEncodingDetector.h>
     36 
     37 namespace android {
     38 
     39 StagefrightMetadataRetriever::StagefrightMetadataRetriever()
     40     : mParsedMetaData(false),
     41       mAlbumArt(NULL) {
     42     ALOGV("StagefrightMetadataRetriever()");
     43 
     44     DataSource::RegisterDefaultSniffers();
     45     CHECK_EQ(mClient.connect(), (status_t)OK);
     46 }
     47 
     48 StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
     49     ALOGV("~StagefrightMetadataRetriever()");
     50 
     51     delete mAlbumArt;
     52     mAlbumArt = NULL;
     53 
     54     mClient.disconnect();
     55 }
     56 
     57 status_t StagefrightMetadataRetriever::setDataSource(
     58         const sp<IMediaHTTPService> &httpService,
     59         const char *uri,
     60         const KeyedVector<String8, String8> *headers) {
     61     ALOGV("setDataSource(%s)", uri);
     62 
     63     mParsedMetaData = false;
     64     mMetaData.clear();
     65     delete mAlbumArt;
     66     mAlbumArt = NULL;
     67 
     68     mSource = DataSource::CreateFromURI(httpService, uri, headers);
     69 
     70     if (mSource == NULL) {
     71         ALOGE("Unable to create data source for '%s'.", uri);
     72         return UNKNOWN_ERROR;
     73     }
     74 
     75     mExtractor = MediaExtractor::Create(mSource);
     76 
     77     if (mExtractor == NULL) {
     78         ALOGE("Unable to instantiate an extractor for '%s'.", uri);
     79 
     80         mSource.clear();
     81 
     82         return UNKNOWN_ERROR;
     83     }
     84 
     85     return OK;
     86 }
     87 
     88 // Warning caller retains ownership of the filedescriptor! Dup it if necessary.
     89 status_t StagefrightMetadataRetriever::setDataSource(
     90         int fd, int64_t offset, int64_t length) {
     91     fd = dup(fd);
     92 
     93     ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
     94 
     95     mParsedMetaData = false;
     96     mMetaData.clear();
     97     delete mAlbumArt;
     98     mAlbumArt = NULL;
     99 
    100     mSource = new FileSource(fd, offset, length);
    101 
    102     status_t err;
    103     if ((err = mSource->initCheck()) != OK) {
    104         mSource.clear();
    105 
    106         return err;
    107     }
    108 
    109     mExtractor = MediaExtractor::Create(mSource);
    110 
    111     if (mExtractor == NULL) {
    112         mSource.clear();
    113 
    114         return UNKNOWN_ERROR;
    115     }
    116 
    117     return OK;
    118 }
    119 
    120 static bool isYUV420PlanarSupported(
    121             OMXClient *client,
    122             const sp<MetaData> &trackMeta) {
    123 
    124     const char *mime;
    125     CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
    126 
    127     Vector<CodecCapabilities> caps;
    128     if (QueryCodecs(client->interface(), mime,
    129                     true, /* queryDecoders */
    130                     true, /* hwCodecOnly */
    131                     &caps) == OK) {
    132 
    133         for (size_t j = 0; j < caps.size(); ++j) {
    134             CodecCapabilities cap = caps[j];
    135             for (size_t i = 0; i < cap.mColorFormats.size(); ++i) {
    136                 if (cap.mColorFormats[i] == OMX_COLOR_FormatYUV420Planar) {
    137                     return true;
    138                 }
    139             }
    140         }
    141     }
    142     return false;
    143 }
    144 
    145 static VideoFrame *extractVideoFrameWithCodecFlags(
    146         OMXClient *client,
    147         const sp<MetaData> &trackMeta,
    148         const sp<MediaSource> &source,
    149         uint32_t flags,
    150         int64_t frameTimeUs,
    151         int seekMode) {
    152 
    153     sp<MetaData> format = source->getFormat();
    154 
    155     // XXX:
    156     // Once all vendors support OMX_COLOR_FormatYUV420Planar, we can
    157     // remove this check and always set the decoder output color format
    158     if (isYUV420PlanarSupported(client, trackMeta)) {
    159         format->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
    160     }
    161 
    162     sp<MediaSource> decoder =
    163         OMXCodec::Create(
    164                 client->interface(), format, false, source,
    165                 NULL, flags | OMXCodec::kClientNeedsFramebuffer);
    166 
    167     if (decoder.get() == NULL) {
    168         ALOGV("unable to instantiate video decoder.");
    169 
    170         return NULL;
    171     }
    172 
    173     status_t err = decoder->start();
    174     if (err != OK) {
    175         ALOGW("OMXCodec::start returned error %d (0x%08x)\n", err, err);
    176         return NULL;
    177     }
    178 
    179     // Read one output buffer, ignore format change notifications
    180     // and spurious empty buffers.
    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         return NULL;
    188     }
    189 
    190     MediaSource::ReadOptions::SeekMode mode =
    191             static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
    192 
    193     int64_t thumbNailTime;
    194     if (frameTimeUs < 0) {
    195         if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)
    196                 || thumbNailTime < 0) {
    197             thumbNailTime = 0;
    198         }
    199         options.setSeekTo(thumbNailTime, mode);
    200     } else {
    201         thumbNailTime = -1;
    202         options.setSeekTo(frameTimeUs, mode);
    203     }
    204 
    205     MediaBuffer *buffer = NULL;
    206     do {
    207         if (buffer != NULL) {
    208             buffer->release();
    209             buffer = NULL;
    210         }
    211         err = decoder->read(&buffer, &options);
    212         options.clearSeekTo();
    213     } while (err == INFO_FORMAT_CHANGED
    214              || (buffer != NULL && buffer->range_length() == 0));
    215 
    216     if (err != OK) {
    217         CHECK(buffer == NULL);
    218 
    219         ALOGV("decoding frame failed.");
    220         decoder->stop();
    221 
    222         return NULL;
    223     }
    224 
    225     ALOGV("successfully decoded video frame.");
    226 
    227     int32_t unreadable;
    228     if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)
    229             && unreadable != 0) {
    230         ALOGV("video frame is unreadable, decoder does not give us access "
    231              "to the video data.");
    232 
    233         buffer->release();
    234         buffer = NULL;
    235 
    236         decoder->stop();
    237 
    238         return NULL;
    239     }
    240 
    241     int64_t timeUs;
    242     CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
    243     if (thumbNailTime >= 0) {
    244         if (timeUs != thumbNailTime) {
    245             const char *mime;
    246             CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
    247 
    248             ALOGV("thumbNailTime = %" PRId64 " us, timeUs = %" PRId64 " us, mime = %s",
    249                  thumbNailTime, timeUs, mime);
    250         }
    251     }
    252 
    253     sp<MetaData> meta = decoder->getFormat();
    254 
    255     int32_t width, height;
    256     CHECK(meta->findInt32(kKeyWidth, &width));
    257     CHECK(meta->findInt32(kKeyHeight, &height));
    258 
    259     int32_t crop_left, crop_top, crop_right, crop_bottom;
    260     if (!meta->findRect(
    261                 kKeyCropRect,
    262                 &crop_left, &crop_top, &crop_right, &crop_bottom)) {
    263         crop_left = crop_top = 0;
    264         crop_right = width - 1;
    265         crop_bottom = height - 1;
    266     }
    267 
    268     int32_t rotationAngle;
    269     if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
    270         rotationAngle = 0;  // By default, no rotation
    271     }
    272 
    273     VideoFrame *frame = new VideoFrame;
    274     frame->mWidth = crop_right - crop_left + 1;
    275     frame->mHeight = crop_bottom - crop_top + 1;
    276     frame->mDisplayWidth = frame->mWidth;
    277     frame->mDisplayHeight = frame->mHeight;
    278     frame->mSize = frame->mWidth * frame->mHeight * 2;
    279     frame->mData = new uint8_t[frame->mSize];
    280     frame->mRotationAngle = rotationAngle;
    281 
    282     int32_t displayWidth, displayHeight;
    283     if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
    284         frame->mDisplayWidth = displayWidth;
    285     }
    286     if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
    287         frame->mDisplayHeight = displayHeight;
    288     }
    289 
    290     int32_t srcFormat;
    291     CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
    292 
    293     ColorConverter converter(
    294             (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
    295 
    296     if (converter.isValid()) {
    297         err = converter.convert(
    298                 (const uint8_t *)buffer->data() + buffer->range_offset(),
    299                 width, height,
    300                 crop_left, crop_top, crop_right, crop_bottom,
    301                 frame->mData,
    302                 frame->mWidth,
    303                 frame->mHeight,
    304                 0, 0, frame->mWidth - 1, frame->mHeight - 1);
    305     } else {
    306         ALOGE("Unable to instantiate color conversion from format 0x%08x to "
    307               "RGB565",
    308               srcFormat);
    309 
    310         err = ERROR_UNSUPPORTED;
    311     }
    312 
    313     buffer->release();
    314     buffer = NULL;
    315 
    316     decoder->stop();
    317 
    318     if (err != OK) {
    319         ALOGE("Colorconverter failed to convert frame.");
    320 
    321         delete frame;
    322         frame = NULL;
    323     }
    324 
    325     return frame;
    326 }
    327 
    328 VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
    329         int64_t timeUs, int option) {
    330 
    331     ALOGV("getFrameAtTime: %" PRId64 " us option: %d", timeUs, option);
    332 
    333     if (mExtractor.get() == NULL) {
    334         ALOGV("no extractor.");
    335         return NULL;
    336     }
    337 
    338     sp<MetaData> fileMeta = mExtractor->getMetaData();
    339 
    340     if (fileMeta == NULL) {
    341         ALOGV("extractor doesn't publish metadata, failed to initialize?");
    342         return NULL;
    343     }
    344 
    345     int32_t drm = 0;
    346     if (fileMeta->findInt32(kKeyIsDRM, &drm) && drm != 0) {
    347         ALOGE("frame grab not allowed.");
    348         return NULL;
    349     }
    350 
    351     size_t n = mExtractor->countTracks();
    352     size_t i;
    353     for (i = 0; i < n; ++i) {
    354         sp<MetaData> meta = mExtractor->getTrackMetaData(i);
    355 
    356         const char *mime;
    357         CHECK(meta->findCString(kKeyMIMEType, &mime));
    358 
    359         if (!strncasecmp(mime, "video/", 6)) {
    360             break;
    361         }
    362     }
    363 
    364     if (i == n) {
    365         ALOGV("no video track found.");
    366         return NULL;
    367     }
    368 
    369     sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
    370             i, MediaExtractor::kIncludeExtensiveMetaData);
    371 
    372     sp<MediaSource> source = mExtractor->getTrack(i);
    373 
    374     if (source.get() == NULL) {
    375         ALOGV("unable to instantiate video track.");
    376         return NULL;
    377     }
    378 
    379     const void *data;
    380     uint32_t type;
    381     size_t dataSize;
    382     if (fileMeta->findData(kKeyAlbumArt, &type, &data, &dataSize)
    383             && mAlbumArt == NULL) {
    384         mAlbumArt = MediaAlbumArt::fromData(dataSize, data);
    385     }
    386 
    387     VideoFrame *frame =
    388         extractVideoFrameWithCodecFlags(
    389                 &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs,
    390                 timeUs, option);
    391 
    392     if (frame == NULL) {
    393         ALOGV("Software decoder failed to extract thumbnail, "
    394              "trying hardware decoder.");
    395 
    396         frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0,
    397                         timeUs, option);
    398     }
    399 
    400     return frame;
    401 }
    402 
    403 MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
    404     ALOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
    405 
    406     if (mExtractor == NULL) {
    407         return NULL;
    408     }
    409 
    410     if (!mParsedMetaData) {
    411         parseMetaData();
    412 
    413         mParsedMetaData = true;
    414     }
    415 
    416     if (mAlbumArt) {
    417         return mAlbumArt->clone();
    418     }
    419 
    420     return NULL;
    421 }
    422 
    423 const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
    424     if (mExtractor == NULL) {
    425         return NULL;
    426     }
    427 
    428     if (!mParsedMetaData) {
    429         parseMetaData();
    430 
    431         mParsedMetaData = true;
    432     }
    433 
    434     ssize_t index = mMetaData.indexOfKey(keyCode);
    435 
    436     if (index < 0) {
    437         return NULL;
    438     }
    439 
    440     return mMetaData.valueAt(index).string();
    441 }
    442 
    443 void StagefrightMetadataRetriever::parseMetaData() {
    444     sp<MetaData> meta = mExtractor->getMetaData();
    445 
    446     if (meta == NULL) {
    447         ALOGV("extractor doesn't publish metadata, failed to initialize?");
    448         return;
    449     }
    450 
    451     struct Map {
    452         int from;
    453         int to;
    454         const char *name;
    455     };
    456     static const Map kMap[] = {
    457         { kKeyMIMEType, METADATA_KEY_MIMETYPE, NULL },
    458         { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER, "tracknumber" },
    459         { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER, "discnumber" },
    460         { kKeyAlbum, METADATA_KEY_ALBUM, "album" },
    461         { kKeyArtist, METADATA_KEY_ARTIST, "artist" },
    462         { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST, "albumartist" },
    463         { kKeyAuthor, METADATA_KEY_AUTHOR, NULL },
    464         { kKeyComposer, METADATA_KEY_COMPOSER, "composer" },
    465         { kKeyDate, METADATA_KEY_DATE, NULL },
    466         { kKeyGenre, METADATA_KEY_GENRE, "genre" },
    467         { kKeyTitle, METADATA_KEY_TITLE, "title" },
    468         { kKeyYear, METADATA_KEY_YEAR, "year" },
    469         { kKeyWriter, METADATA_KEY_WRITER, "writer" },
    470         { kKeyCompilation, METADATA_KEY_COMPILATION, "compilation" },
    471         { kKeyLocation, METADATA_KEY_LOCATION, NULL },
    472     };
    473 
    474     static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
    475 
    476     CharacterEncodingDetector *detector = new CharacterEncodingDetector();
    477 
    478     for (size_t i = 0; i < kNumMapEntries; ++i) {
    479         const char *value;
    480         if (meta->findCString(kMap[i].from, &value)) {
    481             if (kMap[i].name) {
    482                 // add to charset detector
    483                 detector->addTag(kMap[i].name, value);
    484             } else {
    485                 // directly add to output list
    486                 mMetaData.add(kMap[i].to, String8(value));
    487             }
    488         }
    489     }
    490 
    491     detector->detectAndConvert();
    492     int size = detector->size();
    493     if (size) {
    494         for (int i = 0; i < size; i++) {
    495             const char *name;
    496             const char *value;
    497             detector->getTag(i, &name, &value);
    498             for (size_t j = 0; j < kNumMapEntries; ++j) {
    499                 if (kMap[j].name && !strcmp(kMap[j].name, name)) {
    500                     mMetaData.add(kMap[j].to, String8(value));
    501                 }
    502             }
    503         }
    504     }
    505     delete detector;
    506 
    507     const void *data;
    508     uint32_t type;
    509     size_t dataSize;
    510     if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)
    511             && mAlbumArt == NULL) {
    512         mAlbumArt = MediaAlbumArt::fromData(dataSize, data);
    513     }
    514 
    515     size_t numTracks = mExtractor->countTracks();
    516 
    517     char tmp[32];
    518     sprintf(tmp, "%zu", numTracks);
    519 
    520     mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
    521 
    522     bool hasAudio = false;
    523     bool hasVideo = false;
    524     int32_t videoWidth = -1;
    525     int32_t videoHeight = -1;
    526     int32_t audioBitrate = -1;
    527     int32_t rotationAngle = -1;
    528 
    529     // The overall duration is the duration of the longest track.
    530     int64_t maxDurationUs = 0;
    531     String8 timedTextLang;
    532     for (size_t i = 0; i < numTracks; ++i) {
    533         sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
    534 
    535         int64_t durationUs;
    536         if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
    537             if (durationUs > maxDurationUs) {
    538                 maxDurationUs = durationUs;
    539             }
    540         }
    541 
    542         const char *mime;
    543         if (trackMeta->findCString(kKeyMIMEType, &mime)) {
    544             if (!hasAudio && !strncasecmp("audio/", mime, 6)) {
    545                 hasAudio = true;
    546 
    547                 if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
    548                     audioBitrate = -1;
    549                 }
    550             } else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
    551                 hasVideo = true;
    552 
    553                 CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
    554                 CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
    555                 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
    556                     rotationAngle = 0;
    557                 }
    558             } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
    559                 const char *lang;
    560                 trackMeta->findCString(kKeyMediaLanguage, &lang);
    561                 timedTextLang.append(String8(lang));
    562                 timedTextLang.append(String8(":"));
    563             }
    564         }
    565     }
    566 
    567     // To save the language codes for all timed text tracks
    568     // If multiple text tracks present, the format will look
    569     // like "eng:chi"
    570     if (!timedTextLang.isEmpty()) {
    571         mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang);
    572     }
    573 
    574     // The duration value is a string representing the duration in ms.
    575     sprintf(tmp, "%" PRId64, (maxDurationUs + 500) / 1000);
    576     mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
    577 
    578     if (hasAudio) {
    579         mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes"));
    580     }
    581 
    582     if (hasVideo) {
    583         mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes"));
    584 
    585         sprintf(tmp, "%d", videoWidth);
    586         mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp));
    587 
    588         sprintf(tmp, "%d", videoHeight);
    589         mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
    590 
    591         sprintf(tmp, "%d", rotationAngle);
    592         mMetaData.add(METADATA_KEY_VIDEO_ROTATION, String8(tmp));
    593     }
    594 
    595     if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
    596         sprintf(tmp, "%d", audioBitrate);
    597         mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
    598     } else {
    599         off64_t sourceSize;
    600         if (mSource->getSize(&sourceSize) == OK) {
    601             int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs);
    602 
    603             sprintf(tmp, "%" PRId64, avgBitRate);
    604             mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
    605         }
    606     }
    607 
    608     if (numTracks == 1) {
    609         const char *fileMIME;
    610         CHECK(meta->findCString(kKeyMIMEType, &fileMIME));
    611 
    612         if (!strcasecmp(fileMIME, "video/x-matroska")) {
    613             sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0);
    614             const char *trackMIME;
    615             CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME));
    616 
    617             if (!strncasecmp("audio/", trackMIME, 6)) {
    618                 // The matroska file only contains a single audio track,
    619                 // rewrite its mime type.
    620                 mMetaData.add(
    621                         METADATA_KEY_MIMETYPE, String8("audio/x-matroska"));
    622             }
    623         }
    624     }
    625 
    626     // To check whether the media file is drm-protected
    627     if (mExtractor->getDrmFlag()) {
    628         mMetaData.add(METADATA_KEY_IS_DRM, String8("1"));
    629     }
    630 }
    631 
    632 }  // namespace android
    633