StagefrightMetadataRetriever.cpp revision 7f7d52ac18dfc3c6d8f6267dad29306613e9bd0e
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, 112 uint32_t flags, 113 int64_t frameTimeUs, 114 int seekMode) { 115 sp<MediaSource> decoder = 116 OMXCodec::Create( 117 client->interface(), source->getFormat(), false, source, 118 NULL, flags | OMXCodec::kClientNeedsFramebuffer); 119 120 if (decoder.get() == NULL) { 121 LOGV("unable to instantiate video decoder."); 122 123 return NULL; 124 } 125 126 status_t err = decoder->start(); 127 if (err != OK) { 128 LOGW("OMXCodec::start returned error %d (0x%08x)\n", err, err); 129 return NULL; 130 } 131 132 // Read one output buffer, ignore format change notifications 133 // and spurious empty buffers. 134 135 MediaSource::ReadOptions options; 136 if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC || 137 seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) { 138 139 LOGE("Unknown seek mode: %d", seekMode); 140 return NULL; 141 } 142 143 MediaSource::ReadOptions::SeekMode mode = 144 static_cast<MediaSource::ReadOptions::SeekMode>(seekMode); 145 146 int64_t thumbNailTime; 147 if (frameTimeUs < 0) { 148 if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) { 149 thumbNailTime = 0; 150 } 151 options.setSeekTo(thumbNailTime, mode); 152 } else { 153 thumbNailTime = -1; 154 options.setSeekTo(frameTimeUs, mode); 155 } 156 157 MediaBuffer *buffer = NULL; 158 do { 159 if (buffer != NULL) { 160 buffer->release(); 161 buffer = NULL; 162 } 163 err = decoder->read(&buffer, &options); 164 options.clearSeekTo(); 165 } while (err == INFO_FORMAT_CHANGED 166 || (buffer != NULL && buffer->range_length() == 0)); 167 168 if (err != OK) { 169 CHECK_EQ(buffer, NULL); 170 171 LOGV("decoding frame failed."); 172 decoder->stop(); 173 174 return NULL; 175 } 176 177 LOGV("successfully decoded video frame."); 178 179 int32_t unreadable; 180 if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable) 181 && unreadable != 0) { 182 LOGV("video frame is unreadable, decoder does not give us access " 183 "to the video data."); 184 185 buffer->release(); 186 buffer = NULL; 187 188 decoder->stop(); 189 190 return NULL; 191 } 192 193 int64_t timeUs; 194 CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); 195 if (thumbNailTime >= 0) { 196 if (timeUs != thumbNailTime) { 197 const char *mime; 198 CHECK(trackMeta->findCString(kKeyMIMEType, &mime)); 199 200 LOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s", 201 thumbNailTime, timeUs, mime); 202 } 203 } 204 205 sp<MetaData> meta = decoder->getFormat(); 206 207 int32_t width, height; 208 CHECK(meta->findInt32(kKeyWidth, &width)); 209 CHECK(meta->findInt32(kKeyHeight, &height)); 210 211 int32_t crop_left, crop_top, crop_right, crop_bottom; 212 if (!meta->findRect( 213 kKeyCropRect, 214 &crop_left, &crop_top, &crop_right, &crop_bottom)) { 215 crop_left = crop_top = 0; 216 crop_right = width - 1; 217 crop_bottom = height - 1; 218 } 219 220 int32_t rotationAngle; 221 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) { 222 rotationAngle = 0; // By default, no rotation 223 } 224 225 VideoFrame *frame = new VideoFrame; 226 frame->mWidth = crop_right - crop_left + 1; 227 frame->mHeight = crop_bottom - crop_top + 1; 228 frame->mDisplayWidth = frame->mWidth; 229 frame->mDisplayHeight = frame->mHeight; 230 frame->mSize = frame->mWidth * frame->mHeight * 2; 231 frame->mData = new uint8_t[frame->mSize]; 232 frame->mRotationAngle = rotationAngle; 233 234 int32_t srcFormat; 235 CHECK(meta->findInt32(kKeyColorFormat, &srcFormat)); 236 237 ColorConverter converter( 238 (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565); 239 CHECK(converter.isValid()); 240 241 err = converter.convert( 242 (const uint8_t *)buffer->data() + buffer->range_offset(), 243 width, height, 244 crop_left, crop_top, crop_right, crop_bottom, 245 frame->mData, 246 frame->mWidth, 247 frame->mHeight, 248 0, 0, frame->mWidth - 1, frame->mHeight - 1); 249 250 buffer->release(); 251 buffer = NULL; 252 253 decoder->stop(); 254 255 if (err != OK) { 256 LOGE("Colorconverter failed to convert frame."); 257 258 delete frame; 259 frame = NULL; 260 } 261 262 return frame; 263} 264 265VideoFrame *StagefrightMetadataRetriever::getFrameAtTime( 266 int64_t timeUs, int option) { 267 268 LOGV("getFrameAtTime: %lld us option: %d", timeUs, option); 269 270 if (mExtractor.get() == NULL) { 271 LOGV("no extractor."); 272 return NULL; 273 } 274 275 size_t n = mExtractor->countTracks(); 276 size_t i; 277 for (i = 0; i < n; ++i) { 278 sp<MetaData> meta = mExtractor->getTrackMetaData(i); 279 280 const char *mime; 281 CHECK(meta->findCString(kKeyMIMEType, &mime)); 282 283 if (!strncasecmp(mime, "video/", 6)) { 284 break; 285 } 286 } 287 288 if (i == n) { 289 LOGV("no video track found."); 290 return NULL; 291 } 292 293 sp<MetaData> trackMeta = mExtractor->getTrackMetaData( 294 i, MediaExtractor::kIncludeExtensiveMetaData); 295 296 sp<MediaSource> source = mExtractor->getTrack(i); 297 298 if (source.get() == NULL) { 299 LOGV("unable to instantiate video track."); 300 return NULL; 301 } 302 303 VideoFrame *frame = 304 extractVideoFrameWithCodecFlags( 305 &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs, 306 timeUs, option); 307 308 if (frame == NULL) { 309 LOGV("Software decoder failed to extract thumbnail, " 310 "trying hardware decoder."); 311 312 frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0, 313 timeUs, option); 314 } 315 316 return frame; 317} 318 319MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() { 320 LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO"); 321 322 if (mExtractor == NULL) { 323 return NULL; 324 } 325 326 if (!mParsedMetaData) { 327 parseMetaData(); 328 329 mParsedMetaData = true; 330 } 331 332 if (mAlbumArt) { 333 return new MediaAlbumArt(*mAlbumArt); 334 } 335 336 return NULL; 337} 338 339const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) { 340 if (mExtractor == NULL) { 341 return NULL; 342 } 343 344 if (!mParsedMetaData) { 345 parseMetaData(); 346 347 mParsedMetaData = true; 348 } 349 350 ssize_t index = mMetaData.indexOfKey(keyCode); 351 352 if (index < 0) { 353 return NULL; 354 } 355 356 return strdup(mMetaData.valueAt(index).string()); 357} 358 359void StagefrightMetadataRetriever::parseMetaData() { 360 sp<MetaData> meta = mExtractor->getMetaData(); 361 362 struct Map { 363 int from; 364 int to; 365 }; 366 static const Map kMap[] = { 367 { kKeyMIMEType, METADATA_KEY_MIMETYPE }, 368 { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER }, 369 { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER }, 370 { kKeyAlbum, METADATA_KEY_ALBUM }, 371 { kKeyArtist, METADATA_KEY_ARTIST }, 372 { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST }, 373 { kKeyAuthor, METADATA_KEY_AUTHOR }, 374 { kKeyComposer, METADATA_KEY_COMPOSER }, 375 { kKeyDate, METADATA_KEY_DATE }, 376 { kKeyGenre, METADATA_KEY_GENRE }, 377 { kKeyTitle, METADATA_KEY_TITLE }, 378 { kKeyYear, METADATA_KEY_YEAR }, 379 { kKeyWriter, METADATA_KEY_WRITER }, 380 { kKeyCompilation, METADATA_KEY_COMPILATION }, 381 }; 382 static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]); 383 384 for (size_t i = 0; i < kNumMapEntries; ++i) { 385 const char *value; 386 if (meta->findCString(kMap[i].from, &value)) { 387 mMetaData.add(kMap[i].to, String8(value)); 388 } 389 } 390 391 const void *data; 392 uint32_t type; 393 size_t dataSize; 394 if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)) { 395 mAlbumArt = new MediaAlbumArt; 396 mAlbumArt->mSize = dataSize; 397 mAlbumArt->mData = new uint8_t[dataSize]; 398 memcpy(mAlbumArt->mData, data, dataSize); 399 } 400 401 size_t numTracks = mExtractor->countTracks(); 402 403 char tmp[32]; 404 sprintf(tmp, "%d", numTracks); 405 406 mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp)); 407 408 // The overall duration is the duration of the longest track. 409 int64_t maxDurationUs = 0; 410 for (size_t i = 0; i < numTracks; ++i) { 411 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i); 412 413 int64_t durationUs; 414 if (trackMeta->findInt64(kKeyDuration, &durationUs)) { 415 if (durationUs > maxDurationUs) { 416 maxDurationUs = durationUs; 417 } 418 } 419 } 420 421 // The duration value is a string representing the duration in ms. 422 sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000); 423 mMetaData.add(METADATA_KEY_DURATION, String8(tmp)); 424 425 if (numTracks == 1) { 426 const char *fileMIME; 427 CHECK(meta->findCString(kKeyMIMEType, &fileMIME)); 428 429 if (!strcasecmp(fileMIME, "video/x-matroska")) { 430 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0); 431 const char *trackMIME; 432 CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME)); 433 434 if (!strncasecmp("audio/", trackMIME, 6)) { 435 // The matroska file only contains a single audio track, 436 // rewrite its mime type. 437 mMetaData.add( 438 METADATA_KEY_MIMETYPE, String8("audio/x-matroska")); 439 } 440 } 441 } 442} 443 444} // namespace android 445