MP3Extractor.cpp revision 2944eca607304a095ea43ba2b8f0b9de61249f9f
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 "MP3Extractor" 19#include <utils/Log.h> 20 21#include "include/MP3Extractor.h" 22 23#include "include/avc_utils.h" 24#include "include/ID3.h" 25#include "include/VBRISeeker.h" 26#include "include/XINGSeeker.h" 27 28#include <media/stagefright/foundation/ADebug.h> 29#include <media/stagefright/foundation/AMessage.h> 30#include <media/stagefright/DataSource.h> 31#include <media/stagefright/MediaBuffer.h> 32#include <media/stagefright/MediaBufferGroup.h> 33#include <media/stagefright/MediaDefs.h> 34#include <media/stagefright/MediaErrors.h> 35#include <media/stagefright/MediaSource.h> 36#include <media/stagefright/MetaData.h> 37#include <media/stagefright/Utils.h> 38#include <utils/String8.h> 39 40namespace android { 41 42// Everything must match except for 43// protection, bitrate, padding, private bits, mode, mode extension, 44// copyright bit, original bit and emphasis. 45// Yes ... there are things that must indeed match... 46static const uint32_t kMask = 0xfffe0c00; 47 48static bool Resync( 49 const sp<DataSource> &source, uint32_t match_header, 50 off64_t *inout_pos, off64_t *post_id3_pos, uint32_t *out_header) { 51 if (post_id3_pos != NULL) { 52 *post_id3_pos = 0; 53 } 54 55 if (*inout_pos == 0) { 56 // Skip an optional ID3 header if syncing at the very beginning 57 // of the datasource. 58 59 for (;;) { 60 uint8_t id3header[10]; 61 if (source->readAt(*inout_pos, id3header, sizeof(id3header)) 62 < (ssize_t)sizeof(id3header)) { 63 // If we can't even read these 10 bytes, we might as well bail 64 // out, even if there _were_ 10 bytes of valid mp3 audio data... 65 return false; 66 } 67 68 if (memcmp("ID3", id3header, 3)) { 69 break; 70 } 71 72 // Skip the ID3v2 header. 73 74 size_t len = 75 ((id3header[6] & 0x7f) << 21) 76 | ((id3header[7] & 0x7f) << 14) 77 | ((id3header[8] & 0x7f) << 7) 78 | (id3header[9] & 0x7f); 79 80 len += 10; 81 82 *inout_pos += len; 83 84 LOGV("skipped ID3 tag, new starting offset is %lld (0x%016llx)", 85 *inout_pos, *inout_pos); 86 } 87 88 if (post_id3_pos != NULL) { 89 *post_id3_pos = *inout_pos; 90 } 91 } 92 93 off64_t pos = *inout_pos; 94 bool valid = false; 95 96 const size_t kMaxReadBytes = 1024; 97 const size_t kMaxBytesChecked = 128 * 1024; 98 uint8_t buf[kMaxReadBytes]; 99 ssize_t bytesToRead = kMaxReadBytes; 100 ssize_t totalBytesRead = 0; 101 ssize_t remainingBytes = 0; 102 bool reachEOS = false; 103 uint8_t *tmp = buf; 104 105 do { 106 if (pos >= *inout_pos + kMaxBytesChecked) { 107 // Don't scan forever. 108 LOGV("giving up at offset %lld", pos); 109 break; 110 } 111 112 if (remainingBytes < 4) { 113 if (reachEOS) { 114 break; 115 } else { 116 memcpy(buf, tmp, remainingBytes); 117 bytesToRead = kMaxReadBytes - remainingBytes; 118 119 /* 120 * The next read position should start from the end of 121 * the last buffer, and thus should include the remaining 122 * bytes in the buffer. 123 */ 124 totalBytesRead = source->readAt(pos + remainingBytes, 125 buf + remainingBytes, 126 bytesToRead); 127 if (totalBytesRead <= 0) { 128 break; 129 } 130 reachEOS = (totalBytesRead != bytesToRead); 131 totalBytesRead += remainingBytes; 132 remainingBytes = totalBytesRead; 133 tmp = buf; 134 continue; 135 } 136 } 137 138 uint32_t header = U32_AT(tmp); 139 140 if (match_header != 0 && (header & kMask) != (match_header & kMask)) { 141 ++pos; 142 ++tmp; 143 --remainingBytes; 144 continue; 145 } 146 147 size_t frame_size; 148 int sample_rate, num_channels, bitrate; 149 if (!GetMPEGAudioFrameSize( 150 header, &frame_size, 151 &sample_rate, &num_channels, &bitrate)) { 152 ++pos; 153 ++tmp; 154 --remainingBytes; 155 continue; 156 } 157 158 LOGV("found possible 1st frame at %lld (header = 0x%08x)", pos, header); 159 160 // We found what looks like a valid frame, 161 // now find its successors. 162 163 off64_t test_pos = pos + frame_size; 164 165 valid = true; 166 for (int j = 0; j < 3; ++j) { 167 uint8_t tmp[4]; 168 if (source->readAt(test_pos, tmp, 4) < 4) { 169 valid = false; 170 break; 171 } 172 173 uint32_t test_header = U32_AT(tmp); 174 175 LOGV("subsequent header is %08x", test_header); 176 177 if ((test_header & kMask) != (header & kMask)) { 178 valid = false; 179 break; 180 } 181 182 size_t test_frame_size; 183 if (!GetMPEGAudioFrameSize( 184 test_header, &test_frame_size)) { 185 valid = false; 186 break; 187 } 188 189 LOGV("found subsequent frame #%d at %lld", j + 2, test_pos); 190 191 test_pos += test_frame_size; 192 } 193 194 if (valid) { 195 *inout_pos = pos; 196 197 if (out_header != NULL) { 198 *out_header = header; 199 } 200 } else { 201 LOGV("no dice, no valid sequence of frames found."); 202 } 203 204 ++pos; 205 ++tmp; 206 --remainingBytes; 207 } while (!valid); 208 209 return valid; 210} 211 212class MP3Source : public MediaSource { 213public: 214 MP3Source( 215 const sp<MetaData> &meta, const sp<DataSource> &source, 216 off64_t first_frame_pos, uint32_t fixed_header, 217 const sp<MP3Seeker> &seeker); 218 219 virtual status_t start(MetaData *params = NULL); 220 virtual status_t stop(); 221 222 virtual sp<MetaData> getFormat(); 223 224 virtual status_t read( 225 MediaBuffer **buffer, const ReadOptions *options = NULL); 226 227protected: 228 virtual ~MP3Source(); 229 230private: 231 sp<MetaData> mMeta; 232 sp<DataSource> mDataSource; 233 off64_t mFirstFramePos; 234 uint32_t mFixedHeader; 235 off64_t mCurrentPos; 236 int64_t mCurrentTimeUs; 237 bool mStarted; 238 sp<MP3Seeker> mSeeker; 239 MediaBufferGroup *mGroup; 240 241 int64_t mBasisTimeUs; 242 int64_t mSamplesRead; 243 244 MP3Source(const MP3Source &); 245 MP3Source &operator=(const MP3Source &); 246}; 247 248MP3Extractor::MP3Extractor( 249 const sp<DataSource> &source, const sp<AMessage> &meta) 250 : mInitCheck(NO_INIT), 251 mDataSource(source), 252 mFirstFramePos(-1), 253 mFixedHeader(0) { 254 off64_t pos = 0; 255 off64_t post_id3_pos; 256 uint32_t header; 257 bool success; 258 259 int64_t meta_offset; 260 uint32_t meta_header; 261 int64_t meta_post_id3_offset; 262 if (meta != NULL 263 && meta->findInt64("offset", &meta_offset) 264 && meta->findInt32("header", (int32_t *)&meta_header) 265 && meta->findInt64("post-id3-offset", &meta_post_id3_offset)) { 266 // The sniffer has already done all the hard work for us, simply 267 // accept its judgement. 268 pos = (off64_t)meta_offset; 269 header = meta_header; 270 post_id3_pos = (off64_t)meta_post_id3_offset; 271 272 success = true; 273 } else { 274 success = Resync(mDataSource, 0, &pos, &post_id3_pos, &header); 275 } 276 277 if (!success) { 278 // mInitCheck will remain NO_INIT 279 return; 280 } 281 282 mFirstFramePos = pos; 283 mFixedHeader = header; 284 285 size_t frame_size; 286 int sample_rate; 287 int num_channels; 288 int bitrate; 289 GetMPEGAudioFrameSize( 290 header, &frame_size, &sample_rate, &num_channels, &bitrate); 291 292 unsigned layer = 4 - ((header >> 17) & 3); 293 294 mMeta = new MetaData; 295 296 switch (layer) { 297 case 1: 298 mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I); 299 break; 300 case 2: 301 mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II); 302 break; 303 case 3: 304 mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); 305 break; 306 default: 307 TRESPASS(); 308 } 309 310 mMeta->setInt32(kKeySampleRate, sample_rate); 311 mMeta->setInt32(kKeyBitRate, bitrate * 1000); 312 mMeta->setInt32(kKeyChannelCount, num_channels); 313 314 mSeeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos); 315 316 if (mSeeker == NULL) { 317 mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos); 318 } 319 320 int64_t durationUs; 321 322 if (mSeeker == NULL || !mSeeker->getDuration(&durationUs)) { 323 off64_t fileSize; 324 if (mDataSource->getSize(&fileSize) == OK) { 325 durationUs = 8000LL * (fileSize - mFirstFramePos) / bitrate; 326 } else { 327 durationUs = -1; 328 } 329 } 330 331 if (durationUs >= 0) { 332 mMeta->setInt64(kKeyDuration, durationUs); 333 } 334 335 mInitCheck = OK; 336} 337 338size_t MP3Extractor::countTracks() { 339 return mInitCheck != OK ? 0 : 1; 340} 341 342sp<MediaSource> MP3Extractor::getTrack(size_t index) { 343 if (mInitCheck != OK || index != 0) { 344 return NULL; 345 } 346 347 return new MP3Source( 348 mMeta, mDataSource, mFirstFramePos, mFixedHeader, 349 mSeeker); 350} 351 352sp<MetaData> MP3Extractor::getTrackMetaData(size_t index, uint32_t flags) { 353 if (mInitCheck != OK || index != 0) { 354 return NULL; 355 } 356 357 return mMeta; 358} 359 360//////////////////////////////////////////////////////////////////////////////// 361 362MP3Source::MP3Source( 363 const sp<MetaData> &meta, const sp<DataSource> &source, 364 off64_t first_frame_pos, uint32_t fixed_header, 365 const sp<MP3Seeker> &seeker) 366 : mMeta(meta), 367 mDataSource(source), 368 mFirstFramePos(first_frame_pos), 369 mFixedHeader(fixed_header), 370 mCurrentPos(0), 371 mCurrentTimeUs(0), 372 mStarted(false), 373 mSeeker(seeker), 374 mGroup(NULL), 375 mBasisTimeUs(0), 376 mSamplesRead(0) { 377} 378 379MP3Source::~MP3Source() { 380 if (mStarted) { 381 stop(); 382 } 383} 384 385status_t MP3Source::start(MetaData *) { 386 CHECK(!mStarted); 387 388 mGroup = new MediaBufferGroup; 389 390 const size_t kMaxFrameSize = 32768; 391 mGroup->add_buffer(new MediaBuffer(kMaxFrameSize)); 392 393 mCurrentPos = mFirstFramePos; 394 mCurrentTimeUs = 0; 395 396 mBasisTimeUs = mCurrentTimeUs; 397 mSamplesRead = 0; 398 399 mStarted = true; 400 401 return OK; 402} 403 404status_t MP3Source::stop() { 405 CHECK(mStarted); 406 407 delete mGroup; 408 mGroup = NULL; 409 410 mStarted = false; 411 412 return OK; 413} 414 415sp<MetaData> MP3Source::getFormat() { 416 return mMeta; 417} 418 419status_t MP3Source::read( 420 MediaBuffer **out, const ReadOptions *options) { 421 *out = NULL; 422 423 int64_t seekTimeUs; 424 ReadOptions::SeekMode mode; 425 bool seekCBR = false; 426 427 if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) { 428 int64_t actualSeekTimeUs = seekTimeUs; 429 if (mSeeker == NULL 430 || !mSeeker->getOffsetForTime(&actualSeekTimeUs, &mCurrentPos)) { 431 int32_t bitrate; 432 if (!mMeta->findInt32(kKeyBitRate, &bitrate)) { 433 // bitrate is in bits/sec. 434 LOGI("no bitrate"); 435 436 return ERROR_UNSUPPORTED; 437 } 438 439 mCurrentTimeUs = seekTimeUs; 440 mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 8000000; 441 seekCBR = true; 442 } else { 443 mCurrentTimeUs = actualSeekTimeUs; 444 } 445 446 mBasisTimeUs = mCurrentTimeUs; 447 mSamplesRead = 0; 448 } 449 450 MediaBuffer *buffer; 451 status_t err = mGroup->acquire_buffer(&buffer); 452 if (err != OK) { 453 return err; 454 } 455 456 size_t frame_size; 457 int bitrate; 458 int num_samples; 459 int sample_rate; 460 for (;;) { 461 ssize_t n = mDataSource->readAt(mCurrentPos, buffer->data(), 4); 462 if (n < 4) { 463 buffer->release(); 464 buffer = NULL; 465 466 return ERROR_END_OF_STREAM; 467 } 468 469 uint32_t header = U32_AT((const uint8_t *)buffer->data()); 470 471 if ((header & kMask) == (mFixedHeader & kMask) 472 && GetMPEGAudioFrameSize( 473 header, &frame_size, &sample_rate, NULL, 474 &bitrate, &num_samples)) { 475 476 // re-calculate mCurrentTimeUs because we might have called Resync() 477 if (seekCBR) { 478 mCurrentTimeUs = (mCurrentPos - mFirstFramePos) * 8000 / bitrate; 479 mBasisTimeUs = mCurrentTimeUs; 480 } 481 482 break; 483 } 484 485 // Lost sync. 486 LOGV("lost sync! header = 0x%08x, old header = 0x%08x\n", header, mFixedHeader); 487 488 off64_t pos = mCurrentPos; 489 if (!Resync(mDataSource, mFixedHeader, &pos, NULL, NULL)) { 490 LOGE("Unable to resync. Signalling end of stream."); 491 492 buffer->release(); 493 buffer = NULL; 494 495 return ERROR_END_OF_STREAM; 496 } 497 498 mCurrentPos = pos; 499 500 // Try again with the new position. 501 } 502 503 CHECK(frame_size <= buffer->size()); 504 505 ssize_t n = mDataSource->readAt(mCurrentPos, buffer->data(), frame_size); 506 if (n < (ssize_t)frame_size) { 507 buffer->release(); 508 buffer = NULL; 509 510 return ERROR_END_OF_STREAM; 511 } 512 513 buffer->set_range(0, frame_size); 514 515 buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs); 516 buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1); 517 518 mCurrentPos += frame_size; 519 520 mSamplesRead += num_samples; 521 mCurrentTimeUs = mBasisTimeUs + ((mSamplesRead * 1000000) / sample_rate); 522 523 *out = buffer; 524 525 return OK; 526} 527 528sp<MetaData> MP3Extractor::getMetaData() { 529 sp<MetaData> meta = new MetaData; 530 531 if (mInitCheck != OK) { 532 return meta; 533 } 534 535 meta->setCString(kKeyMIMEType, "audio/mpeg"); 536 537 ID3 id3(mDataSource); 538 539 if (!id3.isValid()) { 540 return meta; 541 } 542 543 struct Map { 544 int key; 545 const char *tag1; 546 const char *tag2; 547 }; 548 static const Map kMap[] = { 549 { kKeyAlbum, "TALB", "TAL" }, 550 { kKeyArtist, "TPE1", "TP1" }, 551 { kKeyAlbumArtist, "TPE2", "TP2" }, 552 { kKeyComposer, "TCOM", "TCM" }, 553 { kKeyGenre, "TCON", "TCO" }, 554 { kKeyTitle, "TIT2", "TT2" }, 555 { kKeyYear, "TYE", "TYER" }, 556 { kKeyAuthor, "TXT", "TEXT" }, 557 { kKeyCDTrackNumber, "TRK", "TRCK" }, 558 { kKeyDiscNumber, "TPA", "TPOS" }, 559 { kKeyCompilation, "TCP", "TCMP" }, 560 }; 561 static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]); 562 563 for (size_t i = 0; i < kNumMapEntries; ++i) { 564 ID3::Iterator *it = new ID3::Iterator(id3, kMap[i].tag1); 565 if (it->done()) { 566 delete it; 567 it = new ID3::Iterator(id3, kMap[i].tag2); 568 } 569 570 if (it->done()) { 571 delete it; 572 continue; 573 } 574 575 String8 s; 576 it->getString(&s); 577 delete it; 578 579 meta->setCString(kMap[i].key, s); 580 } 581 582 size_t dataSize; 583 String8 mime; 584 const void *data = id3.getAlbumArt(&dataSize, &mime); 585 586 if (data) { 587 meta->setData(kKeyAlbumArt, MetaData::TYPE_NONE, data, dataSize); 588 meta->setCString(kKeyAlbumArtMIME, mime.string()); 589 } 590 591 return meta; 592} 593 594bool SniffMP3( 595 const sp<DataSource> &source, String8 *mimeType, 596 float *confidence, sp<AMessage> *meta) { 597 off64_t pos = 0; 598 off64_t post_id3_pos; 599 uint32_t header; 600 if (!Resync(source, 0, &pos, &post_id3_pos, &header)) { 601 return false; 602 } 603 604 *meta = new AMessage; 605 (*meta)->setInt64("offset", pos); 606 (*meta)->setInt32("header", header); 607 (*meta)->setInt64("post-id3-offset", post_id3_pos); 608 609 *mimeType = MEDIA_MIMETYPE_AUDIO_MPEG; 610 *confidence = 0.2f; 611 612 return true; 613} 614 615} // namespace android 616