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 20#include <inttypes.h> 21 22#include <utils/Log.h> 23#include <gui/Surface.h> 24 25#include "include/StagefrightMetadataRetriever.h" 26 27#include <media/ICrypto.h> 28#include <media/IMediaHTTPService.h> 29 30#include <media/stagefright/foundation/ABuffer.h> 31#include <media/stagefright/foundation/ADebug.h> 32#include <media/stagefright/foundation/AMessage.h> 33#include <media/stagefright/ColorConverter.h> 34#include <media/stagefright/DataSource.h> 35#include <media/stagefright/FileSource.h> 36#include <media/stagefright/MediaBuffer.h> 37#include <media/stagefright/MediaCodec.h> 38#include <media/stagefright/MediaDefs.h> 39#include <media/stagefright/MediaErrors.h> 40#include <media/stagefright/MediaExtractor.h> 41#include <media/stagefright/MetaData.h> 42#include <media/stagefright/OMXCodec.h> 43#include <media/stagefright/Utils.h> 44 45#include <CharacterEncodingDetector.h> 46 47namespace android { 48 49static const int64_t kBufferTimeOutUs = 30000ll; // 30 msec 50static const size_t kRetryCount = 20; // must be >0 51 52StagefrightMetadataRetriever::StagefrightMetadataRetriever() 53 : mParsedMetaData(false), 54 mAlbumArt(NULL) { 55 ALOGV("StagefrightMetadataRetriever()"); 56 57 DataSource::RegisterDefaultSniffers(); 58 CHECK_EQ(mClient.connect(), (status_t)OK); 59} 60 61StagefrightMetadataRetriever::~StagefrightMetadataRetriever() { 62 ALOGV("~StagefrightMetadataRetriever()"); 63 clearMetadata(); 64 mClient.disconnect(); 65} 66 67status_t StagefrightMetadataRetriever::setDataSource( 68 const sp<IMediaHTTPService> &httpService, 69 const char *uri, 70 const KeyedVector<String8, String8> *headers) { 71 ALOGV("setDataSource(%s)", uri); 72 73 clearMetadata(); 74 mSource = DataSource::CreateFromURI(httpService, uri, headers); 75 76 if (mSource == NULL) { 77 ALOGE("Unable to create data source for '%s'.", uri); 78 return UNKNOWN_ERROR; 79 } 80 81 mExtractor = MediaExtractor::Create(mSource); 82 83 if (mExtractor == NULL) { 84 ALOGE("Unable to instantiate an extractor for '%s'.", uri); 85 86 mSource.clear(); 87 88 return UNKNOWN_ERROR; 89 } 90 91 return OK; 92} 93 94// Warning caller retains ownership of the filedescriptor! Dup it if necessary. 95status_t StagefrightMetadataRetriever::setDataSource( 96 int fd, int64_t offset, int64_t length) { 97 fd = dup(fd); 98 99 ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length); 100 101 clearMetadata(); 102 mSource = new FileSource(fd, offset, length); 103 104 status_t err; 105 if ((err = mSource->initCheck()) != OK) { 106 mSource.clear(); 107 108 return err; 109 } 110 111 mExtractor = MediaExtractor::Create(mSource); 112 113 if (mExtractor == NULL) { 114 mSource.clear(); 115 116 return UNKNOWN_ERROR; 117 } 118 119 return OK; 120} 121 122status_t StagefrightMetadataRetriever::setDataSource( 123 const sp<DataSource>& source) { 124 ALOGV("setDataSource(DataSource)"); 125 126 clearMetadata(); 127 mSource = source; 128 mExtractor = MediaExtractor::Create(mSource); 129 130 if (mExtractor == NULL) { 131 ALOGE("Failed to instantiate a MediaExtractor."); 132 mSource.clear(); 133 return UNKNOWN_ERROR; 134 } 135 136 return OK; 137} 138 139static VideoFrame *extractVideoFrame( 140 const char *componentName, 141 const sp<MetaData> &trackMeta, 142 const sp<MediaSource> &source, 143 int64_t frameTimeUs, 144 int seekMode) { 145 146 sp<MetaData> format = source->getFormat(); 147 148 sp<AMessage> videoFormat; 149 if (convertMetaDataToMessage(trackMeta, &videoFormat) != OK) { 150 ALOGW("Failed to convert meta data to message"); 151 return NULL; 152 } 153 154 // TODO: Use Flexible color instead 155 videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar); 156 157 status_t err; 158 sp<ALooper> looper = new ALooper; 159 looper->start(); 160 sp<MediaCodec> decoder = MediaCodec::CreateByComponentName( 161 looper, componentName, &err); 162 163 if (decoder.get() == NULL || err != OK) { 164 ALOGW("Failed to instantiate decoder [%s]", componentName); 165 return NULL; 166 } 167 168 err = decoder->configure(videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */); 169 if (err != OK) { 170 ALOGW("configure returned error %d (%s)", err, asString(err)); 171 decoder->release(); 172 return NULL; 173 } 174 175 err = decoder->start(); 176 if (err != OK) { 177 ALOGW("start returned error %d (%s)", err, asString(err)); 178 decoder->release(); 179 return NULL; 180 } 181 182 MediaSource::ReadOptions options; 183 if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC || 184 seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) { 185 186 ALOGE("Unknown seek mode: %d", seekMode); 187 decoder->release(); 188 return NULL; 189 } 190 191 MediaSource::ReadOptions::SeekMode mode = 192 static_cast<MediaSource::ReadOptions::SeekMode>(seekMode); 193 194 int64_t thumbNailTime; 195 if (frameTimeUs < 0) { 196 if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime) 197 || thumbNailTime < 0) { 198 thumbNailTime = 0; 199 } 200 options.setSeekTo(thumbNailTime, mode); 201 } else { 202 thumbNailTime = -1; 203 options.setSeekTo(frameTimeUs, mode); 204 } 205 206 err = source->start(); 207 if (err != OK) { 208 ALOGW("source failed to start: %d (%s)", err, asString(err)); 209 decoder->release(); 210 return NULL; 211 } 212 213 Vector<sp<ABuffer> > inputBuffers; 214 err = decoder->getInputBuffers(&inputBuffers); 215 if (err != OK) { 216 ALOGW("failed to get input buffers: %d (%s)", err, asString(err)); 217 decoder->release(); 218 return NULL; 219 } 220 221 Vector<sp<ABuffer> > outputBuffers; 222 err = decoder->getOutputBuffers(&outputBuffers); 223 if (err != OK) { 224 ALOGW("failed to get output buffers: %d (%s)", err, asString(err)); 225 decoder->release(); 226 return NULL; 227 } 228 229 sp<AMessage> outputFormat = NULL; 230 bool haveMoreInputs = true; 231 size_t index, offset, size; 232 int64_t timeUs; 233 size_t retriesLeft = kRetryCount; 234 bool done = false; 235 236 do { 237 size_t inputIndex = -1; 238 int64_t ptsUs = 0ll; 239 uint32_t flags = 0; 240 sp<ABuffer> codecBuffer = NULL; 241 242 while (haveMoreInputs) { 243 err = decoder->dequeueInputBuffer(&inputIndex, kBufferTimeOutUs); 244 if (err != OK) { 245 ALOGW("Timed out waiting for input"); 246 if (retriesLeft) { 247 err = OK; 248 } 249 break; 250 } 251 codecBuffer = inputBuffers[inputIndex]; 252 253 MediaBuffer *mediaBuffer = NULL; 254 255 err = source->read(&mediaBuffer, &options); 256 options.clearSeekTo(); 257 if (err != OK) { 258 ALOGW("Input Error or EOS"); 259 haveMoreInputs = false; 260 break; 261 } 262 263 if (mediaBuffer->range_length() > codecBuffer->capacity()) { 264 ALOGE("buffer size (%zu) too large for codec input size (%zu)", 265 mediaBuffer->range_length(), codecBuffer->capacity()); 266 err = BAD_VALUE; 267 } else { 268 codecBuffer->setRange(0, mediaBuffer->range_length()); 269 270 CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &ptsUs)); 271 memcpy(codecBuffer->data(), 272 (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(), 273 mediaBuffer->range_length()); 274 } 275 276 mediaBuffer->release(); 277 break; 278 } 279 280 if (err == OK && inputIndex < inputBuffers.size()) { 281 ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x", 282 codecBuffer->size(), ptsUs, flags); 283 err = decoder->queueInputBuffer( 284 inputIndex, 285 codecBuffer->offset(), 286 codecBuffer->size(), 287 ptsUs, 288 flags); 289 290 // we don't expect an output from codec config buffer 291 if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) { 292 continue; 293 } 294 } 295 296 while (err == OK) { 297 // wait for a decoded buffer 298 err = decoder->dequeueOutputBuffer( 299 &index, 300 &offset, 301 &size, 302 &timeUs, 303 &flags, 304 kBufferTimeOutUs); 305 306 if (err == INFO_FORMAT_CHANGED) { 307 ALOGV("Received format change"); 308 err = decoder->getOutputFormat(&outputFormat); 309 } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) { 310 ALOGV("Output buffers changed"); 311 err = decoder->getOutputBuffers(&outputBuffers); 312 } else { 313 if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) { 314 ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft); 315 err = OK; 316 } else if (err == OK) { 317 ALOGV("Received an output buffer"); 318 done = true; 319 } else { 320 ALOGW("Received error %d (%s) instead of output", err, asString(err)); 321 done = true; 322 } 323 break; 324 } 325 } 326 } while (err == OK && !done); 327 328 if (err != OK || size <= 0 || outputFormat == NULL) { 329 ALOGE("Failed to decode thumbnail frame"); 330 source->stop(); 331 decoder->stop(); 332 decoder->release(); 333 return NULL; 334 } 335 336 ALOGV("successfully decoded video frame."); 337 sp<ABuffer> videoFrameBuffer = outputBuffers.itemAt(index); 338 339 if (thumbNailTime >= 0) { 340 if (timeUs != thumbNailTime) { 341 AString mime; 342 CHECK(outputFormat->findString("mime", &mime)); 343 344 ALOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s", 345 (long long)thumbNailTime, (long long)timeUs, mime.c_str()); 346 } 347 } 348 349 int32_t width, height; 350 CHECK(outputFormat->findInt32("width", &width)); 351 CHECK(outputFormat->findInt32("height", &height)); 352 353 int32_t crop_left, crop_top, crop_right, crop_bottom; 354 if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) { 355 crop_left = crop_top = 0; 356 crop_right = width - 1; 357 crop_bottom = height - 1; 358 } 359 360 int32_t rotationAngle; 361 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) { 362 rotationAngle = 0; // By default, no rotation 363 } 364 365 VideoFrame *frame = new VideoFrame; 366 frame->mWidth = crop_right - crop_left + 1; 367 frame->mHeight = crop_bottom - crop_top + 1; 368 frame->mDisplayWidth = frame->mWidth; 369 frame->mDisplayHeight = frame->mHeight; 370 frame->mSize = frame->mWidth * frame->mHeight * 2; 371 frame->mData = new uint8_t[frame->mSize]; 372 frame->mRotationAngle = rotationAngle; 373 374 int32_t sarWidth, sarHeight; 375 if (trackMeta->findInt32(kKeySARWidth, &sarWidth) 376 && trackMeta->findInt32(kKeySARHeight, &sarHeight) 377 && sarHeight != 0) { 378 frame->mDisplayWidth = (frame->mDisplayWidth * sarWidth) / sarHeight; 379 } 380 381 int32_t srcFormat; 382 CHECK(outputFormat->findInt32("color-format", &srcFormat)); 383 384 ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565); 385 386 if (converter.isValid()) { 387 err = converter.convert( 388 (const uint8_t *)videoFrameBuffer->data(), 389 width, height, 390 crop_left, crop_top, crop_right, crop_bottom, 391 frame->mData, 392 frame->mWidth, 393 frame->mHeight, 394 0, 0, frame->mWidth - 1, frame->mHeight - 1); 395 } else { 396 ALOGE("Unable to convert from format 0x%08x to RGB565", srcFormat); 397 398 err = ERROR_UNSUPPORTED; 399 } 400 401 videoFrameBuffer.clear(); 402 source->stop(); 403 decoder->releaseOutputBuffer(index); 404 decoder->stop(); 405 decoder->release(); 406 407 if (err != OK) { 408 ALOGE("Colorconverter failed to convert frame."); 409 410 delete frame; 411 frame = NULL; 412 } 413 414 return frame; 415} 416 417VideoFrame *StagefrightMetadataRetriever::getFrameAtTime( 418 int64_t timeUs, int option) { 419 420 ALOGV("getFrameAtTime: %" PRId64 " us option: %d", timeUs, option); 421 422 if (mExtractor.get() == NULL) { 423 ALOGV("no extractor."); 424 return NULL; 425 } 426 427 sp<MetaData> fileMeta = mExtractor->getMetaData(); 428 429 if (fileMeta == NULL) { 430 ALOGV("extractor doesn't publish metadata, failed to initialize?"); 431 return NULL; 432 } 433 434 int32_t drm = 0; 435 if (fileMeta->findInt32(kKeyIsDRM, &drm) && drm != 0) { 436 ALOGE("frame grab not allowed."); 437 return NULL; 438 } 439 440 size_t n = mExtractor->countTracks(); 441 size_t i; 442 for (i = 0; i < n; ++i) { 443 sp<MetaData> meta = mExtractor->getTrackMetaData(i); 444 445 const char *mime; 446 CHECK(meta->findCString(kKeyMIMEType, &mime)); 447 448 if (!strncasecmp(mime, "video/", 6)) { 449 break; 450 } 451 } 452 453 if (i == n) { 454 ALOGV("no video track found."); 455 return NULL; 456 } 457 458 sp<MetaData> trackMeta = mExtractor->getTrackMetaData( 459 i, MediaExtractor::kIncludeExtensiveMetaData); 460 461 sp<MediaSource> source = mExtractor->getTrack(i); 462 463 if (source.get() == NULL) { 464 ALOGV("unable to instantiate video track."); 465 return NULL; 466 } 467 468 const void *data; 469 uint32_t type; 470 size_t dataSize; 471 if (fileMeta->findData(kKeyAlbumArt, &type, &data, &dataSize) 472 && mAlbumArt == NULL) { 473 mAlbumArt = MediaAlbumArt::fromData(dataSize, data); 474 } 475 476 const char *mime; 477 CHECK(trackMeta->findCString(kKeyMIMEType, &mime)); 478 479 Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs; 480 OMXCodec::findMatchingCodecs( 481 mime, 482 false, /* encoder */ 483 NULL, /* matchComponentName */ 484 OMXCodec::kPreferSoftwareCodecs, 485 &matchingCodecs); 486 487 for (size_t i = 0; i < matchingCodecs.size(); ++i) { 488 const char *componentName = matchingCodecs[i].mName.string(); 489 VideoFrame *frame = 490 extractVideoFrame(componentName, trackMeta, source, timeUs, option); 491 492 if (frame != NULL) { 493 return frame; 494 } 495 ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName); 496 } 497 498 return NULL; 499} 500 501MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() { 502 ALOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO"); 503 504 if (mExtractor == NULL) { 505 return NULL; 506 } 507 508 if (!mParsedMetaData) { 509 parseMetaData(); 510 511 mParsedMetaData = true; 512 } 513 514 if (mAlbumArt) { 515 return mAlbumArt->clone(); 516 } 517 518 return NULL; 519} 520 521const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) { 522 if (mExtractor == NULL) { 523 return NULL; 524 } 525 526 if (!mParsedMetaData) { 527 parseMetaData(); 528 529 mParsedMetaData = true; 530 } 531 532 ssize_t index = mMetaData.indexOfKey(keyCode); 533 534 if (index < 0) { 535 return NULL; 536 } 537 538 return mMetaData.valueAt(index).string(); 539} 540 541void StagefrightMetadataRetriever::parseMetaData() { 542 sp<MetaData> meta = mExtractor->getMetaData(); 543 544 if (meta == NULL) { 545 ALOGV("extractor doesn't publish metadata, failed to initialize?"); 546 return; 547 } 548 549 struct Map { 550 int from; 551 int to; 552 const char *name; 553 }; 554 static const Map kMap[] = { 555 { kKeyMIMEType, METADATA_KEY_MIMETYPE, NULL }, 556 { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER, "tracknumber" }, 557 { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER, "discnumber" }, 558 { kKeyAlbum, METADATA_KEY_ALBUM, "album" }, 559 { kKeyArtist, METADATA_KEY_ARTIST, "artist" }, 560 { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST, "albumartist" }, 561 { kKeyAuthor, METADATA_KEY_AUTHOR, NULL }, 562 { kKeyComposer, METADATA_KEY_COMPOSER, "composer" }, 563 { kKeyDate, METADATA_KEY_DATE, NULL }, 564 { kKeyGenre, METADATA_KEY_GENRE, "genre" }, 565 { kKeyTitle, METADATA_KEY_TITLE, "title" }, 566 { kKeyYear, METADATA_KEY_YEAR, "year" }, 567 { kKeyWriter, METADATA_KEY_WRITER, "writer" }, 568 { kKeyCompilation, METADATA_KEY_COMPILATION, "compilation" }, 569 { kKeyLocation, METADATA_KEY_LOCATION, NULL }, 570 }; 571 572 static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]); 573 574 CharacterEncodingDetector *detector = new CharacterEncodingDetector(); 575 576 for (size_t i = 0; i < kNumMapEntries; ++i) { 577 const char *value; 578 if (meta->findCString(kMap[i].from, &value)) { 579 if (kMap[i].name) { 580 // add to charset detector 581 detector->addTag(kMap[i].name, value); 582 } else { 583 // directly add to output list 584 mMetaData.add(kMap[i].to, String8(value)); 585 } 586 } 587 } 588 589 detector->detectAndConvert(); 590 int size = detector->size(); 591 if (size) { 592 for (int i = 0; i < size; i++) { 593 const char *name; 594 const char *value; 595 detector->getTag(i, &name, &value); 596 for (size_t j = 0; j < kNumMapEntries; ++j) { 597 if (kMap[j].name && !strcmp(kMap[j].name, name)) { 598 mMetaData.add(kMap[j].to, String8(value)); 599 } 600 } 601 } 602 } 603 delete detector; 604 605 const void *data; 606 uint32_t type; 607 size_t dataSize; 608 if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize) 609 && mAlbumArt == NULL) { 610 mAlbumArt = MediaAlbumArt::fromData(dataSize, data); 611 } 612 613 size_t numTracks = mExtractor->countTracks(); 614 615 char tmp[32]; 616 sprintf(tmp, "%zu", numTracks); 617 618 mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp)); 619 620 float captureFps; 621 if (meta->findFloat(kKeyCaptureFramerate, &captureFps)) { 622 sprintf(tmp, "%f", captureFps); 623 mMetaData.add(METADATA_KEY_CAPTURE_FRAMERATE, String8(tmp)); 624 } 625 626 bool hasAudio = false; 627 bool hasVideo = false; 628 int32_t videoWidth = -1; 629 int32_t videoHeight = -1; 630 int32_t audioBitrate = -1; 631 int32_t rotationAngle = -1; 632 633 // The overall duration is the duration of the longest track. 634 int64_t maxDurationUs = 0; 635 String8 timedTextLang; 636 for (size_t i = 0; i < numTracks; ++i) { 637 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i); 638 639 int64_t durationUs; 640 if (trackMeta->findInt64(kKeyDuration, &durationUs)) { 641 if (durationUs > maxDurationUs) { 642 maxDurationUs = durationUs; 643 } 644 } 645 646 const char *mime; 647 if (trackMeta->findCString(kKeyMIMEType, &mime)) { 648 if (!hasAudio && !strncasecmp("audio/", mime, 6)) { 649 hasAudio = true; 650 651 if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) { 652 audioBitrate = -1; 653 } 654 } else if (!hasVideo && !strncasecmp("video/", mime, 6)) { 655 hasVideo = true; 656 657 CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth)); 658 CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight)); 659 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) { 660 rotationAngle = 0; 661 } 662 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { 663 const char *lang; 664 trackMeta->findCString(kKeyMediaLanguage, &lang); 665 timedTextLang.append(String8(lang)); 666 timedTextLang.append(String8(":")); 667 } 668 } 669 } 670 671 // To save the language codes for all timed text tracks 672 // If multiple text tracks present, the format will look 673 // like "eng:chi" 674 if (!timedTextLang.isEmpty()) { 675 mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang); 676 } 677 678 // The duration value is a string representing the duration in ms. 679 sprintf(tmp, "%" PRId64, (maxDurationUs + 500) / 1000); 680 mMetaData.add(METADATA_KEY_DURATION, String8(tmp)); 681 682 if (hasAudio) { 683 mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes")); 684 } 685 686 if (hasVideo) { 687 mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes")); 688 689 sprintf(tmp, "%d", videoWidth); 690 mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp)); 691 692 sprintf(tmp, "%d", videoHeight); 693 mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp)); 694 695 sprintf(tmp, "%d", rotationAngle); 696 mMetaData.add(METADATA_KEY_VIDEO_ROTATION, String8(tmp)); 697 } 698 699 if (numTracks == 1 && hasAudio && audioBitrate >= 0) { 700 sprintf(tmp, "%d", audioBitrate); 701 mMetaData.add(METADATA_KEY_BITRATE, String8(tmp)); 702 } else { 703 off64_t sourceSize; 704 if (mSource->getSize(&sourceSize) == OK) { 705 int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs); 706 707 sprintf(tmp, "%" PRId64, avgBitRate); 708 mMetaData.add(METADATA_KEY_BITRATE, String8(tmp)); 709 } 710 } 711 712 if (numTracks == 1) { 713 const char *fileMIME; 714 CHECK(meta->findCString(kKeyMIMEType, &fileMIME)); 715 716 if (!strcasecmp(fileMIME, "video/x-matroska")) { 717 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0); 718 const char *trackMIME; 719 CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME)); 720 721 if (!strncasecmp("audio/", trackMIME, 6)) { 722 // The matroska file only contains a single audio track, 723 // rewrite its mime type. 724 mMetaData.add( 725 METADATA_KEY_MIMETYPE, String8("audio/x-matroska")); 726 } 727 } 728 } 729 730 // To check whether the media file is drm-protected 731 if (mExtractor->getDrmFlag()) { 732 mMetaData.add(METADATA_KEY_IS_DRM, String8("1")); 733 } 734} 735 736void StagefrightMetadataRetriever::clearMetadata() { 737 mParsedMetaData = false; 738 mMetaData.clear(); 739 delete mAlbumArt; 740 mAlbumArt = NULL; 741} 742 743} // namespace android 744