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