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