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