StagefrightMetadataRetriever.cpp revision 8ddeebb93cb41e7a8e9fe763afb6c6016b21fa61
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 int32_t drm = 0; 276 if (mExtractor->getMetaData()->findInt32(kKeyIsDRM, &drm) && drm != 0) { 277 LOGE("frame grab not allowed."); 278 return NULL; 279 } 280 281 size_t n = mExtractor->countTracks(); 282 size_t i; 283 for (i = 0; i < n; ++i) { 284 sp<MetaData> meta = mExtractor->getTrackMetaData(i); 285 286 const char *mime; 287 CHECK(meta->findCString(kKeyMIMEType, &mime)); 288 289 if (!strncasecmp(mime, "video/", 6)) { 290 break; 291 } 292 } 293 294 if (i == n) { 295 LOGV("no video track found."); 296 return NULL; 297 } 298 299 sp<MetaData> trackMeta = mExtractor->getTrackMetaData( 300 i, MediaExtractor::kIncludeExtensiveMetaData); 301 302 sp<MediaSource> source = mExtractor->getTrack(i); 303 304 if (source.get() == NULL) { 305 LOGV("unable to instantiate video track."); 306 return NULL; 307 } 308 309 VideoFrame *frame = 310 extractVideoFrameWithCodecFlags( 311 &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs, 312 timeUs, option); 313 314 if (frame == NULL) { 315 LOGV("Software decoder failed to extract thumbnail, " 316 "trying hardware decoder."); 317 318 frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0, 319 timeUs, option); 320 } 321 322 return frame; 323} 324 325MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() { 326 LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO"); 327 328 if (mExtractor == NULL) { 329 return NULL; 330 } 331 332 if (!mParsedMetaData) { 333 parseMetaData(); 334 335 mParsedMetaData = true; 336 } 337 338 if (mAlbumArt) { 339 return new MediaAlbumArt(*mAlbumArt); 340 } 341 342 return NULL; 343} 344 345const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) { 346 if (mExtractor == NULL) { 347 return NULL; 348 } 349 350 if (!mParsedMetaData) { 351 parseMetaData(); 352 353 mParsedMetaData = true; 354 } 355 356 ssize_t index = mMetaData.indexOfKey(keyCode); 357 358 if (index < 0) { 359 return NULL; 360 } 361 362 return strdup(mMetaData.valueAt(index).string()); 363} 364 365void StagefrightMetadataRetriever::parseMetaData() { 366 sp<MetaData> meta = mExtractor->getMetaData(); 367 368 struct Map { 369 int from; 370 int to; 371 }; 372 static const Map kMap[] = { 373 { kKeyMIMEType, METADATA_KEY_MIMETYPE }, 374 { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER }, 375 { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER }, 376 { kKeyAlbum, METADATA_KEY_ALBUM }, 377 { kKeyArtist, METADATA_KEY_ARTIST }, 378 { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST }, 379 { kKeyAuthor, METADATA_KEY_AUTHOR }, 380 { kKeyComposer, METADATA_KEY_COMPOSER }, 381 { kKeyDate, METADATA_KEY_DATE }, 382 { kKeyGenre, METADATA_KEY_GENRE }, 383 { kKeyTitle, METADATA_KEY_TITLE }, 384 { kKeyYear, METADATA_KEY_YEAR }, 385 { kKeyWriter, METADATA_KEY_WRITER }, 386 { kKeyCompilation, METADATA_KEY_COMPILATION }, 387 }; 388 static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]); 389 390 for (size_t i = 0; i < kNumMapEntries; ++i) { 391 const char *value; 392 if (meta->findCString(kMap[i].from, &value)) { 393 mMetaData.add(kMap[i].to, String8(value)); 394 } 395 } 396 397 const void *data; 398 uint32_t type; 399 size_t dataSize; 400 if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)) { 401 mAlbumArt = new MediaAlbumArt; 402 mAlbumArt->mSize = dataSize; 403 mAlbumArt->mData = new uint8_t[dataSize]; 404 memcpy(mAlbumArt->mData, data, dataSize); 405 } 406 407 size_t numTracks = mExtractor->countTracks(); 408 409 char tmp[32]; 410 sprintf(tmp, "%d", numTracks); 411 412 mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp)); 413 414 // The overall duration is the duration of the longest track. 415 int64_t maxDurationUs = 0; 416 for (size_t i = 0; i < numTracks; ++i) { 417 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i); 418 419 int64_t durationUs; 420 if (trackMeta->findInt64(kKeyDuration, &durationUs)) { 421 if (durationUs > maxDurationUs) { 422 maxDurationUs = durationUs; 423 } 424 } 425 } 426 427 // The duration value is a string representing the duration in ms. 428 sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000); 429 mMetaData.add(METADATA_KEY_DURATION, String8(tmp)); 430 431 if (numTracks == 1) { 432 const char *fileMIME; 433 CHECK(meta->findCString(kKeyMIMEType, &fileMIME)); 434 435 if (!strcasecmp(fileMIME, "video/x-matroska")) { 436 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0); 437 const char *trackMIME; 438 CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME)); 439 440 if (!strncasecmp("audio/", trackMIME, 6)) { 441 // The matroska file only contains a single audio track, 442 // rewrite its mime type. 443 mMetaData.add( 444 METADATA_KEY_MIMETYPE, String8("audio/x-matroska")); 445 } 446 } 447 } 448} 449 450} // namespace android 451