StagefrightMetadataRetriever.cpp revision ce0febae177d1816ee7a6750ed9fba52472b9a71
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/ColorConverter.h> 24#include <media/stagefright/DataSource.h> 25#include <media/stagefright/FileSource.h> 26#include <media/stagefright/MediaDebug.h> 27#include <media/stagefright/MediaExtractor.h> 28#include <media/stagefright/MetaData.h> 29#include <media/stagefright/OMXCodec.h> 30 31namespace android { 32 33StagefrightMetadataRetriever::StagefrightMetadataRetriever() 34 : mParsedMetaData(false), 35 mAlbumArt(NULL) { 36 LOGV("StagefrightMetadataRetriever()"); 37 38 DataSource::RegisterDefaultSniffers(); 39 CHECK_EQ(mClient.connect(), OK); 40} 41 42StagefrightMetadataRetriever::~StagefrightMetadataRetriever() { 43 LOGV("~StagefrightMetadataRetriever()"); 44 45 delete mAlbumArt; 46 mAlbumArt = NULL; 47 48 mClient.disconnect(); 49} 50 51status_t StagefrightMetadataRetriever::setDataSource(const char *uri) { 52 LOGV("setDataSource(%s)", uri); 53 54 mParsedMetaData = false; 55 mMetaData.clear(); 56 delete mAlbumArt; 57 mAlbumArt = NULL; 58 59 mSource = DataSource::CreateFromURI(uri); 60 61 if (mSource == NULL) { 62 return UNKNOWN_ERROR; 63 } 64 65 mExtractor = MediaExtractor::Create(mSource); 66 67 if (mExtractor == NULL) { 68 mSource.clear(); 69 70 return UNKNOWN_ERROR; 71 } 72 73 return OK; 74} 75 76// Warning caller retains ownership of the filedescriptor! Dup it if necessary. 77status_t StagefrightMetadataRetriever::setDataSource( 78 int fd, int64_t offset, int64_t length) { 79 fd = dup(fd); 80 81 LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); 82 83 mParsedMetaData = false; 84 mMetaData.clear(); 85 delete mAlbumArt; 86 mAlbumArt = NULL; 87 88 mSource = new FileSource(fd, offset, length); 89 90 status_t err; 91 if ((err = mSource->initCheck()) != OK) { 92 mSource.clear(); 93 94 return err; 95 } 96 97 mExtractor = MediaExtractor::Create(mSource); 98 99 if (mExtractor == NULL) { 100 mSource.clear(); 101 102 return UNKNOWN_ERROR; 103 } 104 105 return OK; 106} 107 108static VideoFrame *extractVideoFrameWithCodecFlags( 109 OMXClient *client, 110 const sp<MetaData> &trackMeta, 111 const sp<MediaSource> &source, uint32_t flags) { 112 sp<MediaSource> decoder = 113 OMXCodec::Create( 114 client->interface(), source->getFormat(), false, source, 115 NULL, flags | OMXCodec::kClientNeedsFramebuffer); 116 117 if (decoder.get() == NULL) { 118 LOGV("unable to instantiate video decoder."); 119 120 return NULL; 121 } 122 123 status_t err = decoder->start(); 124 if (err != OK) { 125 LOGW("OMXCodec::start returned error %d (0x%08x)\n", err, err); 126 return NULL; 127 } 128 129 // Read one output buffer, ignore format change notifications 130 // and spurious empty buffers. 131 132 MediaSource::ReadOptions options; 133 int64_t thumbNailTime; 134 if (trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) { 135 options.setSeekTo(thumbNailTime); 136 } else { 137 thumbNailTime = -1; 138 } 139 140 MediaBuffer *buffer = NULL; 141 do { 142 if (buffer != NULL) { 143 buffer->release(); 144 buffer = NULL; 145 } 146 err = decoder->read(&buffer, &options); 147 options.clearSeekTo(); 148 } while (err == INFO_FORMAT_CHANGED 149 || (buffer != NULL && buffer->range_length() == 0)); 150 151 if (err != OK) { 152 CHECK_EQ(buffer, NULL); 153 154 LOGV("decoding frame failed."); 155 decoder->stop(); 156 157 return NULL; 158 } 159 160 LOGV("successfully decoded video frame."); 161 162 int32_t unreadable; 163 if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable) 164 && unreadable != 0) { 165 LOGV("video frame is unreadable, decoder does not give us access " 166 "to the video data."); 167 168 buffer->release(); 169 buffer = NULL; 170 171 decoder->stop(); 172 173 return NULL; 174 } 175 176 int64_t timeUs; 177 CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); 178 if (thumbNailTime >= 0) { 179 if (timeUs != thumbNailTime) { 180 const char *mime; 181 CHECK(trackMeta->findCString(kKeyMIMEType, &mime)); 182 183 LOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s", 184 thumbNailTime, timeUs, mime); 185 } 186 } 187 188 sp<MetaData> meta = decoder->getFormat(); 189 190 int32_t width, height; 191 CHECK(meta->findInt32(kKeyWidth, &width)); 192 CHECK(meta->findInt32(kKeyHeight, &height)); 193 194 int32_t rotationAngle; 195 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) { 196 rotationAngle = 0; // By default, no rotation 197 } 198 199 VideoFrame *frame = new VideoFrame; 200 frame->mWidth = width; 201 frame->mHeight = height; 202 frame->mDisplayWidth = width; 203 frame->mDisplayHeight = height; 204 frame->mSize = width * height * 2; 205 frame->mData = new uint8_t[frame->mSize]; 206 frame->mRotationAngle = rotationAngle; 207 208 int32_t srcFormat; 209 CHECK(meta->findInt32(kKeyColorFormat, &srcFormat)); 210 211 ColorConverter converter( 212 (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565); 213 CHECK(converter.isValid()); 214 215 converter.convert( 216 width, height, 217 (const uint8_t *)buffer->data() + buffer->range_offset(), 218 0, 219 frame->mData, width * 2); 220 221 buffer->release(); 222 buffer = NULL; 223 224 decoder->stop(); 225 226 return frame; 227} 228 229VideoFrame *StagefrightMetadataRetriever::captureFrame() { 230 LOGV("captureFrame"); 231 232 if (0 == (mMode & METADATA_MODE_FRAME_CAPTURE_ONLY)) { 233 LOGV("captureFrame disabled by mode (0x%08x)", mMode); 234 235 return NULL; 236 } 237 238 if (mExtractor.get() == NULL) { 239 LOGV("no extractor."); 240 return NULL; 241 } 242 243 size_t n = mExtractor->countTracks(); 244 size_t i; 245 for (i = 0; i < n; ++i) { 246 sp<MetaData> meta = mExtractor->getTrackMetaData(i); 247 248 const char *mime; 249 CHECK(meta->findCString(kKeyMIMEType, &mime)); 250 251 if (!strncasecmp(mime, "video/", 6)) { 252 break; 253 } 254 } 255 256 if (i == n) { 257 LOGV("no video track found."); 258 return NULL; 259 } 260 261 sp<MetaData> trackMeta = mExtractor->getTrackMetaData( 262 i, MediaExtractor::kIncludeExtensiveMetaData); 263 264 sp<MediaSource> source = mExtractor->getTrack(i); 265 266 if (source.get() == NULL) { 267 LOGV("unable to instantiate video track."); 268 return NULL; 269 } 270 271 VideoFrame *frame = 272 extractVideoFrameWithCodecFlags( 273 &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs); 274 275 if (frame == NULL) { 276 LOGV("Software decoder failed to extract thumbnail, " 277 "trying hardware decoder."); 278 279 frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0); 280 } 281 282 return frame; 283} 284 285MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() { 286 LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO"); 287 288 if (0 == (mMode & METADATA_MODE_METADATA_RETRIEVAL_ONLY)) { 289 LOGV("extractAlbumArt/metadata retrieval disabled by mode"); 290 291 return NULL; 292 } 293 294 if (mExtractor == NULL) { 295 return NULL; 296 } 297 298 if (!mParsedMetaData) { 299 parseMetaData(); 300 301 mParsedMetaData = true; 302 } 303 304 if (mAlbumArt) { 305 return new MediaAlbumArt(*mAlbumArt); 306 } 307 308 return NULL; 309} 310 311const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) { 312 if (0 == (mMode & METADATA_MODE_METADATA_RETRIEVAL_ONLY)) { 313 LOGV("extractAlbumArt/metadata retrieval disabled by mode"); 314 315 return NULL; 316 } 317 318 if (mExtractor == NULL) { 319 return NULL; 320 } 321 322 if (!mParsedMetaData) { 323 parseMetaData(); 324 325 mParsedMetaData = true; 326 } 327 328 ssize_t index = mMetaData.indexOfKey(keyCode); 329 330 if (index < 0) { 331 return NULL; 332 } 333 334 return strdup(mMetaData.valueAt(index).string()); 335} 336 337void StagefrightMetadataRetriever::parseMetaData() { 338 sp<MetaData> meta = mExtractor->getMetaData(); 339 340 struct Map { 341 int from; 342 int to; 343 }; 344 static const Map kMap[] = { 345 { kKeyMIMEType, METADATA_KEY_MIMETYPE }, 346 { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER }, 347 { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER }, 348 { kKeyAlbum, METADATA_KEY_ALBUM }, 349 { kKeyArtist, METADATA_KEY_ARTIST }, 350 { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST }, 351 { kKeyAuthor, METADATA_KEY_AUTHOR }, 352 { kKeyComposer, METADATA_KEY_COMPOSER }, 353 { kKeyDate, METADATA_KEY_DATE }, 354 { kKeyGenre, METADATA_KEY_GENRE }, 355 { kKeyTitle, METADATA_KEY_TITLE }, 356 { kKeyYear, METADATA_KEY_YEAR }, 357 { kKeyWriter, METADATA_KEY_WRITER }, 358 }; 359 static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]); 360 361 for (size_t i = 0; i < kNumMapEntries; ++i) { 362 const char *value; 363 if (meta->findCString(kMap[i].from, &value)) { 364 mMetaData.add(kMap[i].to, String8(value)); 365 } 366 } 367 368 const void *data; 369 uint32_t type; 370 size_t dataSize; 371 if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)) { 372 mAlbumArt = new MediaAlbumArt; 373 mAlbumArt->mSize = dataSize; 374 mAlbumArt->mData = new uint8_t[dataSize]; 375 memcpy(mAlbumArt->mData, data, dataSize); 376 } 377 378 size_t numTracks = mExtractor->countTracks(); 379 380 char tmp[32]; 381 sprintf(tmp, "%d", numTracks); 382 383 mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp)); 384 385 // The overall duration is the duration of the longest track. 386 int64_t maxDurationUs = 0; 387 for (size_t i = 0; i < numTracks; ++i) { 388 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i); 389 390 int64_t durationUs; 391 if (trackMeta->findInt64(kKeyDuration, &durationUs)) { 392 if (durationUs > maxDurationUs) { 393 maxDurationUs = durationUs; 394 } 395 } 396 } 397 398 // The duration value is a string representing the duration in ms. 399 sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000); 400 mMetaData.add(METADATA_KEY_DURATION, String8(tmp)); 401 402 if (numTracks == 1) { 403 const char *fileMIME; 404 CHECK(meta->findCString(kKeyMIMEType, &fileMIME)); 405 406 if (!strcasecmp(fileMIME, "video/x-matroska")) { 407 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0); 408 const char *trackMIME; 409 CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME)); 410 411 if (!strncasecmp("audio/", trackMIME, 6)) { 412 // The matroska file only contains a single audio track, 413 // rewrite its mime type. 414 mMetaData.add( 415 METADATA_KEY_MIMETYPE, String8("audio/x-matroska")); 416 } 417 } 418 } 419} 420 421 422} // namespace android 423