StagefrightMetadataRetriever.cpp revision 16afe2fb439cab6125bb46a07a8078d4ce1c1ea5
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 && trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) { 148 options.setSeekTo(thumbNailTime, mode); 149 } else { 150 thumbNailTime = -1; 151 options.setSeekTo(frameTimeUs, mode); 152 } 153 154 MediaBuffer *buffer = NULL; 155 do { 156 if (buffer != NULL) { 157 buffer->release(); 158 buffer = NULL; 159 } 160 err = decoder->read(&buffer, &options); 161 options.clearSeekTo(); 162 } while (err == INFO_FORMAT_CHANGED 163 || (buffer != NULL && buffer->range_length() == 0)); 164 165 if (err != OK) { 166 CHECK_EQ(buffer, NULL); 167 168 LOGV("decoding frame failed."); 169 decoder->stop(); 170 171 return NULL; 172 } 173 174 LOGV("successfully decoded video frame."); 175 176 int32_t unreadable; 177 if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable) 178 && unreadable != 0) { 179 LOGV("video frame is unreadable, decoder does not give us access " 180 "to the video data."); 181 182 buffer->release(); 183 buffer = NULL; 184 185 decoder->stop(); 186 187 return NULL; 188 } 189 190 int64_t timeUs; 191 CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); 192 if (thumbNailTime >= 0) { 193 if (timeUs != thumbNailTime) { 194 const char *mime; 195 CHECK(trackMeta->findCString(kKeyMIMEType, &mime)); 196 197 LOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s", 198 thumbNailTime, timeUs, mime); 199 } 200 } 201 202 sp<MetaData> meta = decoder->getFormat(); 203 204 int32_t width, height; 205 CHECK(meta->findInt32(kKeyWidth, &width)); 206 CHECK(meta->findInt32(kKeyHeight, &height)); 207 208 int32_t crop_left, crop_top, crop_right, crop_bottom; 209 if (!meta->findRect( 210 kKeyCropRect, 211 &crop_left, &crop_top, &crop_right, &crop_bottom)) { 212 crop_left = crop_top = 0; 213 crop_right = width - 1; 214 crop_bottom = height - 1; 215 } 216 217 int32_t rotationAngle; 218 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) { 219 rotationAngle = 0; // By default, no rotation 220 } 221 222 VideoFrame *frame = new VideoFrame; 223 frame->mWidth = crop_right - crop_left + 1; 224 frame->mHeight = crop_bottom - crop_top + 1; 225 frame->mDisplayWidth = frame->mWidth; 226 frame->mDisplayHeight = frame->mHeight; 227 frame->mSize = frame->mWidth * frame->mHeight * 2; 228 frame->mData = new uint8_t[frame->mSize]; 229 frame->mRotationAngle = rotationAngle; 230 231 int32_t srcFormat; 232 CHECK(meta->findInt32(kKeyColorFormat, &srcFormat)); 233 234 ColorConverter converter( 235 (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565); 236 CHECK(converter.isValid()); 237 238 converter.convert( 239 (const uint8_t *)buffer->data() + buffer->range_offset(), 240 width, height, 241 crop_left, crop_top, crop_right, crop_bottom, 242 frame->mData, 243 frame->mWidth, 244 frame->mHeight, 245 0, 0, frame->mWidth - 1, frame->mHeight - 1); 246 247 buffer->release(); 248 buffer = NULL; 249 250 decoder->stop(); 251 252 return frame; 253} 254 255VideoFrame *StagefrightMetadataRetriever::getFrameAtTime( 256 int64_t timeUs, int option) { 257 258 LOGV("getFrameAtTime: %lld us option: %d", timeUs, option); 259 if (0 == (mMode & METADATA_MODE_FRAME_CAPTURE_ONLY)) { 260 LOGV("captureFrame disabled by mode (0x%08x)", mMode); 261 262 return NULL; 263 } 264 265 if (mExtractor.get() == NULL) { 266 LOGV("no extractor."); 267 return NULL; 268 } 269 270 size_t n = mExtractor->countTracks(); 271 size_t i; 272 for (i = 0; i < n; ++i) { 273 sp<MetaData> meta = mExtractor->getTrackMetaData(i); 274 275 const char *mime; 276 CHECK(meta->findCString(kKeyMIMEType, &mime)); 277 278 if (!strncasecmp(mime, "video/", 6)) { 279 break; 280 } 281 } 282 283 if (i == n) { 284 LOGV("no video track found."); 285 return NULL; 286 } 287 288 sp<MetaData> trackMeta = mExtractor->getTrackMetaData( 289 i, MediaExtractor::kIncludeExtensiveMetaData); 290 291 sp<MediaSource> source = mExtractor->getTrack(i); 292 293 if (source.get() == NULL) { 294 LOGV("unable to instantiate video track."); 295 return NULL; 296 } 297 298 VideoFrame *frame = 299 extractVideoFrameWithCodecFlags( 300 &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs, 301 timeUs, option); 302 303 if (frame == NULL) { 304 LOGV("Software decoder failed to extract thumbnail, " 305 "trying hardware decoder."); 306 307 frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0, 308 timeUs, option); 309 } 310 311 return frame; 312} 313 314MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() { 315 LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO"); 316 317 if (0 == (mMode & METADATA_MODE_METADATA_RETRIEVAL_ONLY)) { 318 LOGV("extractAlbumArt/metadata retrieval disabled by mode"); 319 320 return NULL; 321 } 322 323 if (mExtractor == NULL) { 324 return NULL; 325 } 326 327 if (!mParsedMetaData) { 328 parseMetaData(); 329 330 mParsedMetaData = true; 331 } 332 333 if (mAlbumArt) { 334 return new MediaAlbumArt(*mAlbumArt); 335 } 336 337 return NULL; 338} 339 340const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) { 341 if (0 == (mMode & METADATA_MODE_METADATA_RETRIEVAL_ONLY)) { 342 LOGV("extractAlbumArt/metadata retrieval disabled by mode"); 343 344 return NULL; 345 } 346 347 if (mExtractor == NULL) { 348 return NULL; 349 } 350 351 if (!mParsedMetaData) { 352 parseMetaData(); 353 354 mParsedMetaData = true; 355 } 356 357 ssize_t index = mMetaData.indexOfKey(keyCode); 358 359 if (index < 0) { 360 return NULL; 361 } 362 363 return strdup(mMetaData.valueAt(index).string()); 364} 365 366void StagefrightMetadataRetriever::parseMetaData() { 367 sp<MetaData> meta = mExtractor->getMetaData(); 368 369 struct Map { 370 int from; 371 int to; 372 }; 373 static const Map kMap[] = { 374 { kKeyMIMEType, METADATA_KEY_MIMETYPE }, 375 { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER }, 376 { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER }, 377 { kKeyAlbum, METADATA_KEY_ALBUM }, 378 { kKeyArtist, METADATA_KEY_ARTIST }, 379 { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST }, 380 { kKeyAuthor, METADATA_KEY_AUTHOR }, 381 { kKeyComposer, METADATA_KEY_COMPOSER }, 382 { kKeyDate, METADATA_KEY_DATE }, 383 { kKeyGenre, METADATA_KEY_GENRE }, 384 { kKeyTitle, METADATA_KEY_TITLE }, 385 { kKeyYear, METADATA_KEY_YEAR }, 386 { kKeyWriter, METADATA_KEY_WRITER }, 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