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