MPEG4Writer.cpp revision 2dec2b5be2056c6d9428897dc672185872d30d17
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 "MPEG4Writer" 19#include <utils/Log.h> 20 21#include <arpa/inet.h> 22 23#include <ctype.h> 24#include <pthread.h> 25 26#include <media/stagefright/MPEG4Writer.h> 27#include <media/stagefright/MediaBuffer.h> 28#include <media/stagefright/MetaData.h> 29#include <media/stagefright/MediaDebug.h> 30#include <media/stagefright/MediaDefs.h> 31#include <media/stagefright/MediaErrors.h> 32#include <media/stagefright/MediaSource.h> 33#include <media/stagefright/Utils.h> 34#include <media/mediarecorder.h> 35#include <cutils/properties.h> 36 37namespace android { 38 39class MPEG4Writer::Track { 40public: 41 Track(MPEG4Writer *owner, const sp<MediaSource> &source); 42 ~Track(); 43 44 status_t start(int64_t startTimeUs); 45 void stop(); 46 void pause(); 47 bool reachedEOS(); 48 49 int64_t getDurationUs() const; 50 int64_t getEstimatedTrackSizeBytes() const; 51 void writeTrackHeader(int32_t trackID, bool use32BitOffset = true); 52 53private: 54 MPEG4Writer *mOwner; 55 sp<MetaData> mMeta; 56 sp<MediaSource> mSource; 57 volatile bool mDone; 58 volatile bool mPaused; 59 volatile bool mResumed; 60 int64_t mMaxTimeStampUs; 61 int64_t mEstimatedTrackSizeBytes; 62 63 pthread_t mThread; 64 65 struct SampleInfo { 66 size_t size; 67 int64_t timestamp; 68 }; 69 List<SampleInfo> mSampleInfos; 70 bool mSamplesHaveSameSize; 71 72 List<MediaBuffer *> mChunkSamples; 73 List<off_t> mChunkOffsets; 74 75 struct StscTableEntry { 76 77 StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id) 78 : firstChunk(chunk), 79 samplesPerChunk(samples), 80 sampleDescriptionId(id) {} 81 82 uint32_t firstChunk; 83 uint32_t samplesPerChunk; 84 uint32_t sampleDescriptionId; 85 }; 86 List<StscTableEntry> mStscTableEntries; 87 88 List<int32_t> mStssTableEntries; 89 List<int64_t> mChunkDurations; 90 91 struct SttsTableEntry { 92 93 SttsTableEntry(uint32_t count, uint32_t duration) 94 : sampleCount(count), sampleDuration(duration) {} 95 96 uint32_t sampleCount; 97 uint32_t sampleDuration; 98 }; 99 List<SttsTableEntry> mSttsTableEntries; 100 101 void *mCodecSpecificData; 102 size_t mCodecSpecificDataSize; 103 bool mGotAllCodecSpecificData; 104 105 bool mReachedEOS; 106 int64_t mStartTimestampUs; 107 108 static void *ThreadWrapper(void *me); 109 void threadEntry(); 110 111 status_t makeAVCCodecSpecificData( 112 const uint8_t *data, size_t size); 113 void writeOneChunk(bool isAvc); 114 void logStatisticalData(bool isAudio); 115 void findMinMaxFrameRates(float *minFps, float *maxFps); 116 void findMinMaxChunkDurations(int64_t *min, int64_t *max); 117 118 Track(const Track &); 119 Track &operator=(const Track &); 120}; 121 122#define USE_NALLEN_FOUR 1 123 124MPEG4Writer::MPEG4Writer(const char *filename) 125 : mFile(fopen(filename, "wb")), 126 mUse32BitOffset(true), 127 mPaused(false), 128 mStarted(false), 129 mOffset(0), 130 mMdatOffset(0), 131 mEstimatedMoovBoxSize(0), 132 mInterleaveDurationUs(500000) { 133 CHECK(mFile != NULL); 134} 135 136MPEG4Writer::MPEG4Writer(int fd) 137 : mFile(fdopen(fd, "wb")), 138 mUse32BitOffset(true), 139 mPaused(false), 140 mStarted(false), 141 mOffset(0), 142 mMdatOffset(0), 143 mEstimatedMoovBoxSize(0), 144 mInterleaveDurationUs(500000) { 145 CHECK(mFile != NULL); 146} 147 148MPEG4Writer::~MPEG4Writer() { 149 stop(); 150 151 for (List<Track *>::iterator it = mTracks.begin(); 152 it != mTracks.end(); ++it) { 153 delete *it; 154 } 155 mTracks.clear(); 156} 157 158status_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 159 Track *track = new Track(this, source); 160 mTracks.push_back(track); 161 162 return OK; 163} 164 165status_t MPEG4Writer::startTracks() { 166 int64_t startTimeUs = systemTime() / 1000; 167 for (List<Track *>::iterator it = mTracks.begin(); 168 it != mTracks.end(); ++it) { 169 status_t err = (*it)->start(startTimeUs); 170 171 if (err != OK) { 172 for (List<Track *>::iterator it2 = mTracks.begin(); 173 it2 != it; ++it2) { 174 (*it2)->stop(); 175 } 176 177 return err; 178 } 179 } 180 return OK; 181} 182 183int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 184 // This implementation is highly experimental/heurisitic. 185 // 186 // Statistical analysis shows that metadata usually accounts 187 // for a small portion of the total file size, usually < 0.6%. 188 // Currently, lets set to 0.4% for now. 189 190 // The default MIN_MOOV_BOX_SIZE is set to 0.4% x 1MB, 191 // where 1MB is the common file size limit for MMS application. 192 // The default MAX _MOOV_BOX_SIZE value is based on about 4 193 // minute video recording with a bit rate about 3 Mbps, because 194 // statistics also show that most of the video captured are going 195 // to be less than 3 minutes. 196 197 // If the estimation is wrong, we will pay the price of wasting 198 // some reserved space. This should not happen so often statistically. 199 static const int32_t factor = mUse32BitOffset? 1: 2; 200 static const int64_t MIN_MOOV_BOX_SIZE = 4 * 1024; // 4 KB 201 static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 202 int64_t size = MIN_MOOV_BOX_SIZE; 203 204 if (mMaxFileSizeLimitBytes != 0) { 205 size = mMaxFileSizeLimitBytes * 4 / 1000; 206 } else if (mMaxFileDurationLimitUs != 0) { 207 if (bitRate <= 0) { 208 // We could not estimate the file size since bitRate is not set. 209 size = MIN_MOOV_BOX_SIZE; 210 } else { 211 size = ((mMaxFileDurationLimitUs * bitRate * 4) / 1000 / 8000000); 212 } 213 } 214 if (size < MIN_MOOV_BOX_SIZE) { 215 size = MIN_MOOV_BOX_SIZE; 216 } 217 218 // Any long duration recording will be probably end up with 219 // non-streamable mp4 file. 220 if (size > MAX_MOOV_BOX_SIZE) { 221 size = MAX_MOOV_BOX_SIZE; 222 } 223 224 LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" 225 " moov size %lld bytes", 226 mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 227 return factor * size; 228} 229 230status_t MPEG4Writer::start(MetaData *param) { 231 if (mFile == NULL) { 232 return UNKNOWN_ERROR; 233 } 234 235 int32_t use64BitOffset; 236 if (param && 237 param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 238 use64BitOffset) { 239 mUse32BitOffset = false; 240 } 241 242 // System property can overwrite the file offset bits parameter 243 char value[PROPERTY_VALUE_MAX]; 244 if (property_get("media.stagefright.record-64bits", value, NULL) 245 && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 246 mUse32BitOffset = false; 247 } 248 249 mStartTimestampUs = -1; 250 if (mStarted) { 251 if (mPaused) { 252 mPaused = false; 253 return startTracks(); 254 } 255 return OK; 256 } 257 258 mStreamableFile = true; 259 mWriteMoovBoxToMemory = false; 260 mMoovBoxBuffer = NULL; 261 mMoovBoxBufferOffset = 0; 262 263 beginBox("ftyp"); 264 writeFourcc("isom"); 265 writeInt32(0); 266 writeFourcc("isom"); 267 endBox(); 268 269 mFreeBoxOffset = mOffset; 270 271 if (mEstimatedMoovBoxSize == 0) { 272 int32_t bitRate = -1; 273 if (param) { 274 param->findInt32(kKeyBitRate, &bitRate); 275 } 276 mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 277 } 278 CHECK(mEstimatedMoovBoxSize >= 8); 279 fseeko(mFile, mFreeBoxOffset, SEEK_SET); 280 writeInt32(mEstimatedMoovBoxSize); 281 write("free", 4); 282 283 mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 284 mOffset = mMdatOffset; 285 fseeko(mFile, mMdatOffset, SEEK_SET); 286 if (mUse32BitOffset) { 287 write("????mdat", 8); 288 } else { 289 write("\x00\x00\x00\x01mdat????????", 16); 290 } 291 292 status_t err = startTracks(); 293 if (err != OK) { 294 return err; 295 } 296 mStarted = true; 297 return OK; 298} 299 300void MPEG4Writer::pause() { 301 if (mFile == NULL) { 302 return; 303 } 304 mPaused = true; 305 for (List<Track *>::iterator it = mTracks.begin(); 306 it != mTracks.end(); ++it) { 307 (*it)->pause(); 308 } 309} 310 311void MPEG4Writer::stop() { 312 if (mFile == NULL) { 313 return; 314 } 315 316 int64_t max_duration = 0; 317 for (List<Track *>::iterator it = mTracks.begin(); 318 it != mTracks.end(); ++it) { 319 (*it)->stop(); 320 321 int64_t duration = (*it)->getDurationUs(); 322 if (duration > max_duration) { 323 max_duration = duration; 324 } 325 } 326 327 328 // Fix up the size of the 'mdat' chunk. 329 if (mUse32BitOffset) { 330 fseeko(mFile, mMdatOffset, SEEK_SET); 331 int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset)); 332 fwrite(&size, 1, 4, mFile); 333 } else { 334 fseeko(mFile, mMdatOffset + 8, SEEK_SET); 335 int64_t size = mOffset - mMdatOffset; 336 size = hton64(size); 337 fwrite(&size, 1, 8, mFile); 338 } 339 fseeko(mFile, mOffset, SEEK_SET); 340 341 time_t now = time(NULL); 342 const off_t moovOffset = mOffset; 343 mWriteMoovBoxToMemory = true; 344 mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 345 mMoovBoxBufferOffset = 0; 346 CHECK(mMoovBoxBuffer != NULL); 347 int32_t timeScale = 1000; 348 int32_t duration = max_duration / timeScale; 349 350 beginBox("moov"); 351 352 beginBox("mvhd"); 353 writeInt32(0); // version=0, flags=0 354 writeInt32(now); // creation time 355 writeInt32(now); // modification time 356 writeInt32(timeScale); // timescale 357 writeInt32(duration); 358 writeInt32(0x10000); // rate: 1.0 359 writeInt16(0x100); // volume 360 writeInt16(0); // reserved 361 writeInt32(0); // reserved 362 writeInt32(0); // reserved 363 writeInt32(0x10000); // matrix 364 writeInt32(0); 365 writeInt32(0); 366 writeInt32(0); 367 writeInt32(0x10000); 368 writeInt32(0); 369 writeInt32(0); 370 writeInt32(0); 371 writeInt32(0x40000000); 372 writeInt32(0); // predefined 373 writeInt32(0); // predefined 374 writeInt32(0); // predefined 375 writeInt32(0); // predefined 376 writeInt32(0); // predefined 377 writeInt32(0); // predefined 378 writeInt32(mTracks.size() + 1); // nextTrackID 379 endBox(); // mvhd 380 381 int32_t id = 1; 382 for (List<Track *>::iterator it = mTracks.begin(); 383 it != mTracks.end(); ++it, ++id) { 384 (*it)->writeTrackHeader(id, mUse32BitOffset); 385 } 386 endBox(); // moov 387 388 mWriteMoovBoxToMemory = false; 389 if (mStreamableFile) { 390 CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize); 391 392 // Moov box 393 fseeko(mFile, mFreeBoxOffset, SEEK_SET); 394 mOffset = mFreeBoxOffset; 395 write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, mFile); 396 397 // Free box 398 fseeko(mFile, mOffset, SEEK_SET); 399 writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 400 write("free", 4); 401 402 // Free temp memory 403 free(mMoovBoxBuffer); 404 mMoovBoxBuffer = NULL; 405 mMoovBoxBufferOffset = 0; 406 } else { 407 LOGI("The mp4 file will not be streamable."); 408 } 409 410 CHECK(mBoxes.empty()); 411 412 fflush(mFile); 413 fclose(mFile); 414 mFile = NULL; 415 mStarted = false; 416} 417 418status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 419 mInterleaveDurationUs = durationUs; 420 return OK; 421} 422 423void MPEG4Writer::lock() { 424 mLock.lock(); 425} 426 427void MPEG4Writer::unlock() { 428 mLock.unlock(); 429} 430 431off_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 432 off_t old_offset = mOffset; 433 434 fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 435 1, buffer->range_length(), mFile); 436 437 mOffset += buffer->range_length(); 438 439 return old_offset; 440} 441 442static void StripStartcode(MediaBuffer *buffer) { 443 if (buffer->range_length() < 4) { 444 return; 445 } 446 447 const uint8_t *ptr = 448 (const uint8_t *)buffer->data() + buffer->range_offset(); 449 450 if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 451 buffer->set_range( 452 buffer->range_offset() + 4, buffer->range_length() - 4); 453 } 454} 455 456off_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 457 off_t old_offset = mOffset; 458 459 size_t length = buffer->range_length(); 460 461#if USE_NALLEN_FOUR 462 uint8_t x = length >> 24; 463 fwrite(&x, 1, 1, mFile); 464 x = (length >> 16) & 0xff; 465 fwrite(&x, 1, 1, mFile); 466 x = (length >> 8) & 0xff; 467 fwrite(&x, 1, 1, mFile); 468 x = length & 0xff; 469 fwrite(&x, 1, 1, mFile); 470#else 471 CHECK(length < 65536); 472 473 uint8_t x = length >> 8; 474 fwrite(&x, 1, 1, mFile); 475 x = length & 0xff; 476 fwrite(&x, 1, 1, mFile); 477#endif 478 479 fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 480 1, length, mFile); 481 482#if USE_NALLEN_FOUR 483 mOffset += length + 4; 484#else 485 mOffset += length + 2; 486#endif 487 488 return old_offset; 489} 490 491size_t MPEG4Writer::write( 492 const void *ptr, size_t size, size_t nmemb, FILE *stream) { 493 494 const size_t bytes = size * nmemb; 495 if (mWriteMoovBoxToMemory) { 496 off_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 497 if (moovBoxSize > mEstimatedMoovBoxSize) { 498 for (List<off_t>::iterator it = mBoxes.begin(); 499 it != mBoxes.end(); ++it) { 500 (*it) += mOffset; 501 } 502 fseeko(mFile, mOffset, SEEK_SET); 503 fwrite(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, stream); 504 fwrite(ptr, size, nmemb, stream); 505 mOffset += (bytes + mMoovBoxBufferOffset); 506 free(mMoovBoxBuffer); 507 mMoovBoxBuffer = NULL; 508 mMoovBoxBufferOffset = 0; 509 mWriteMoovBoxToMemory = false; 510 mStreamableFile = false; 511 } else { 512 memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 513 mMoovBoxBufferOffset += bytes; 514 } 515 } else { 516 fwrite(ptr, size, nmemb, stream); 517 mOffset += bytes; 518 } 519 return bytes; 520} 521 522void MPEG4Writer::beginBox(const char *fourcc) { 523 CHECK_EQ(strlen(fourcc), 4); 524 525 mBoxes.push_back(mWriteMoovBoxToMemory? 526 mMoovBoxBufferOffset: mOffset); 527 528 writeInt32(0); 529 writeFourcc(fourcc); 530} 531 532void MPEG4Writer::endBox() { 533 CHECK(!mBoxes.empty()); 534 535 off_t offset = *--mBoxes.end(); 536 mBoxes.erase(--mBoxes.end()); 537 538 if (mWriteMoovBoxToMemory) { 539 int32_t x = htonl(mMoovBoxBufferOffset - offset); 540 memcpy(mMoovBoxBuffer + offset, &x, 4); 541 } else { 542 fseeko(mFile, offset, SEEK_SET); 543 writeInt32(mOffset - offset); 544 mOffset -= 4; 545 fseeko(mFile, mOffset, SEEK_SET); 546 } 547} 548 549void MPEG4Writer::writeInt8(int8_t x) { 550 write(&x, 1, 1, mFile); 551} 552 553void MPEG4Writer::writeInt16(int16_t x) { 554 x = htons(x); 555 write(&x, 1, 2, mFile); 556} 557 558void MPEG4Writer::writeInt32(int32_t x) { 559 x = htonl(x); 560 write(&x, 1, 4, mFile); 561} 562 563void MPEG4Writer::writeInt64(int64_t x) { 564 x = hton64(x); 565 write(&x, 1, 8, mFile); 566} 567 568void MPEG4Writer::writeCString(const char *s) { 569 size_t n = strlen(s); 570 write(s, 1, n + 1, mFile); 571} 572 573void MPEG4Writer::writeFourcc(const char *s) { 574 CHECK_EQ(strlen(s), 4); 575 write(s, 1, 4, mFile); 576} 577 578void MPEG4Writer::write(const void *data, size_t size) { 579 write(data, 1, size, mFile); 580} 581 582bool MPEG4Writer::exceedsFileSizeLimit() { 583 // No limit 584 if (mMaxFileSizeLimitBytes == 0) { 585 return false; 586 } 587 588 int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 589 for (List<Track *>::iterator it = mTracks.begin(); 590 it != mTracks.end(); ++it) { 591 nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 592 } 593 return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes); 594} 595 596bool MPEG4Writer::exceedsFileDurationLimit() { 597 // No limit 598 if (mMaxFileDurationLimitUs == 0) { 599 return false; 600 } 601 602 for (List<Track *>::iterator it = mTracks.begin(); 603 it != mTracks.end(); ++it) { 604 if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 605 return true; 606 } 607 } 608 return false; 609} 610 611bool MPEG4Writer::reachedEOS() { 612 bool allDone = true; 613 for (List<Track *>::iterator it = mTracks.begin(); 614 it != mTracks.end(); ++it) { 615 if (!(*it)->reachedEOS()) { 616 allDone = false; 617 break; 618 } 619 } 620 621 return allDone; 622} 623 624void MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 625 LOGI("setStartTimestampUs: %lld", timeUs); 626 CHECK(timeUs >= 0); 627 Mutex::Autolock autoLock(mLock); 628 if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 629 mStartTimestampUs = timeUs; 630 LOGI("Earliest track starting time: %lld", mStartTimestampUs); 631 } 632} 633 634int64_t MPEG4Writer::getStartTimestampUs() { 635 LOGI("getStartTimestampUs: %lld", mStartTimestampUs); 636 Mutex::Autolock autoLock(mLock); 637 return mStartTimestampUs; 638} 639 640size_t MPEG4Writer::numTracks() { 641 Mutex::Autolock autolock(mLock); 642 return mTracks.size(); 643} 644 645//////////////////////////////////////////////////////////////////////////////// 646 647MPEG4Writer::Track::Track( 648 MPEG4Writer *owner, const sp<MediaSource> &source) 649 : mOwner(owner), 650 mMeta(source->getFormat()), 651 mSource(source), 652 mDone(false), 653 mPaused(false), 654 mResumed(false), 655 mMaxTimeStampUs(0), 656 mEstimatedTrackSizeBytes(0), 657 mSamplesHaveSameSize(true), 658 mCodecSpecificData(NULL), 659 mCodecSpecificDataSize(0), 660 mGotAllCodecSpecificData(false), 661 mReachedEOS(false) { 662} 663 664MPEG4Writer::Track::~Track() { 665 stop(); 666 667 if (mCodecSpecificData != NULL) { 668 free(mCodecSpecificData); 669 mCodecSpecificData = NULL; 670 } 671} 672 673status_t MPEG4Writer::Track::start(int64_t startTimeUs) { 674 if (!mDone && mPaused) { 675 mPaused = false; 676 mResumed = true; 677 return OK; 678 } 679 680 sp<MetaData> meta = new MetaData; 681 meta->setInt64(kKeyTime, startTimeUs); 682 status_t err = mSource->start(meta.get()); 683 if (err != OK) { 684 mDone = mReachedEOS = true; 685 return err; 686 } 687 688 pthread_attr_t attr; 689 pthread_attr_init(&attr); 690 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 691 692 mDone = false; 693 mMaxTimeStampUs = 0; 694 mReachedEOS = false; 695 mEstimatedTrackSizeBytes = 0; 696 697 pthread_create(&mThread, &attr, ThreadWrapper, this); 698 pthread_attr_destroy(&attr); 699 700 return OK; 701} 702 703void MPEG4Writer::Track::pause() { 704 mPaused = true; 705} 706 707void MPEG4Writer::Track::stop() { 708 if (mDone) { 709 return; 710 } 711 712 mDone = true; 713 714 void *dummy; 715 pthread_join(mThread, &dummy); 716 717 mSource->stop(); 718} 719 720bool MPEG4Writer::Track::reachedEOS() { 721 return mReachedEOS; 722} 723 724// static 725void *MPEG4Writer::Track::ThreadWrapper(void *me) { 726 Track *track = static_cast<Track *>(me); 727 728 track->threadEntry(); 729 730 return NULL; 731} 732 733#include <ctype.h> 734static void hexdump(const void *_data, size_t size) { 735 const uint8_t *data = (const uint8_t *)_data; 736 size_t offset = 0; 737 while (offset < size) { 738 printf("0x%04x ", offset); 739 740 size_t n = size - offset; 741 if (n > 16) { 742 n = 16; 743 } 744 745 for (size_t i = 0; i < 16; ++i) { 746 if (i == 8) { 747 printf(" "); 748 } 749 750 if (offset + i < size) { 751 printf("%02x ", data[offset + i]); 752 } else { 753 printf(" "); 754 } 755 } 756 757 printf(" "); 758 759 for (size_t i = 0; i < n; ++i) { 760 if (isprint(data[offset + i])) { 761 printf("%c", data[offset + i]); 762 } else { 763 printf("."); 764 } 765 } 766 767 printf("\n"); 768 769 offset += 16; 770 } 771} 772 773 774status_t MPEG4Writer::Track::makeAVCCodecSpecificData( 775 const uint8_t *data, size_t size) { 776 // hexdump(data, size); 777 778 if (mCodecSpecificData != NULL) { 779 LOGE("Already have codec specific data"); 780 return ERROR_MALFORMED; 781 } 782 783 if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) { 784 LOGE("Must start with a start code"); 785 return ERROR_MALFORMED; 786 } 787 788 size_t picParamOffset = 4; 789 while (picParamOffset + 3 < size 790 && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) { 791 ++picParamOffset; 792 } 793 794 if (picParamOffset + 3 >= size) { 795 LOGE("Could not find start-code for pictureParameterSet"); 796 return ERROR_MALFORMED; 797 } 798 799 size_t seqParamSetLength = picParamOffset - 4; 800 size_t picParamSetLength = size - picParamOffset - 4; 801 802 mCodecSpecificDataSize = 803 6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2; 804 805 mCodecSpecificData = malloc(mCodecSpecificDataSize); 806 uint8_t *header = (uint8_t *)mCodecSpecificData; 807 header[0] = 1; 808 header[1] = 0x42; // profile 809 header[2] = 0x80; 810 header[3] = 0x1e; // level 811 812#if USE_NALLEN_FOUR 813 header[4] = 0xfc | 3; // length size == 4 bytes 814#else 815 header[4] = 0xfc | 1; // length size == 2 bytes 816#endif 817 818 header[5] = 0xe0 | 1; 819 header[6] = seqParamSetLength >> 8; 820 header[7] = seqParamSetLength & 0xff; 821 memcpy(&header[8], &data[4], seqParamSetLength); 822 header += 8 + seqParamSetLength; 823 header[0] = 1; 824 header[1] = picParamSetLength >> 8; 825 header[2] = picParamSetLength & 0xff; 826 memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength); 827 828 return OK; 829} 830 831void MPEG4Writer::Track::threadEntry() { 832 sp<MetaData> meta = mSource->getFormat(); 833 const char *mime; 834 meta->findCString(kKeyMIMEType, &mime); 835 bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 836 !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 837 bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 838 bool is_audio = !strncasecmp(mime, "audio/", 6); 839 int32_t count = 0; 840 const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 841 int64_t chunkTimestampUs = 0; 842 int32_t nChunks = 0; 843 int32_t nZeroLengthFrames = 0; 844 int64_t lastTimestamp = 0; // Timestamp of the previous sample 845 int64_t lastDuration = 0; // Time spacing between the previous two samples 846 int32_t sampleCount = 1; // Sample count in the current stts table entry 847 uint32_t previousSampleSize = 0; // Size of the previous sample 848 int64_t previousPausedDurationUs = 0; 849 sp<MetaData> meta_data; 850 851 MediaBuffer *buffer; 852 while (!mDone && mSource->read(&buffer) == OK) { 853 if (buffer->range_length() == 0) { 854 buffer->release(); 855 buffer = NULL; 856 ++nZeroLengthFrames; 857 continue; 858 } 859 860 // If the codec specific data has not been received yet, delay pause. 861 // After the codec specific data is received, discard what we received 862 // when the track is to be paused. 863 if (mPaused && !mResumed) { 864 buffer->release(); 865 buffer = NULL; 866 continue; 867 } 868 869 ++count; 870 871 int32_t isCodecConfig; 872 if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 873 && isCodecConfig) { 874 CHECK(!mGotAllCodecSpecificData); 875 876 if (is_avc) { 877 status_t err = makeAVCCodecSpecificData( 878 (const uint8_t *)buffer->data() 879 + buffer->range_offset(), 880 buffer->range_length()); 881 CHECK_EQ(OK, err); 882 } else if (is_mpeg4) { 883 mCodecSpecificDataSize = buffer->range_length(); 884 mCodecSpecificData = malloc(mCodecSpecificDataSize); 885 memcpy(mCodecSpecificData, 886 (const uint8_t *)buffer->data() 887 + buffer->range_offset(), 888 buffer->range_length()); 889 } 890 891 buffer->release(); 892 buffer = NULL; 893 894 mGotAllCodecSpecificData = true; 895 continue; 896 } else if (!mGotAllCodecSpecificData && 897 count == 1 && is_mpeg4 && mCodecSpecificData == NULL) { 898 // The TI mpeg4 encoder does not properly set the 899 // codec-specific-data flag. 900 901 const uint8_t *data = 902 (const uint8_t *)buffer->data() + buffer->range_offset(); 903 904 const size_t size = buffer->range_length(); 905 906 size_t offset = 0; 907 while (offset + 3 < size) { 908 if (data[offset] == 0x00 && data[offset + 1] == 0x00 909 && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) { 910 break; 911 } 912 913 ++offset; 914 } 915 916 // CHECK(offset + 3 < size); 917 if (offset + 3 >= size) { 918 // XXX assume the entire first chunk of data is the codec specific 919 // data. 920 offset = size; 921 } 922 923 mCodecSpecificDataSize = offset; 924 mCodecSpecificData = malloc(offset); 925 memcpy(mCodecSpecificData, data, offset); 926 927 buffer->set_range(buffer->range_offset() + offset, size - offset); 928 929 if (size == offset) { 930 buffer->release(); 931 buffer = NULL; 932 933 continue; 934 } 935 936 mGotAllCodecSpecificData = true; 937 } else if (!mGotAllCodecSpecificData && is_avc && count < 3) { 938 // The TI video encoder does not flag codec specific data 939 // as such and also splits up SPS and PPS across two buffers. 940 941 const uint8_t *data = 942 (const uint8_t *)buffer->data() + buffer->range_offset(); 943 944 size_t size = buffer->range_length(); 945 946 CHECK(count == 2 || mCodecSpecificData == NULL); 947 948 size_t offset = mCodecSpecificDataSize; 949 mCodecSpecificDataSize += size + 4; 950 mCodecSpecificData = 951 realloc(mCodecSpecificData, mCodecSpecificDataSize); 952 953 memcpy((uint8_t *)mCodecSpecificData + offset, 954 "\x00\x00\x00\x01", 4); 955 956 memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size); 957 958 buffer->release(); 959 buffer = NULL; 960 961 if (count == 2) { 962 void *tmp = mCodecSpecificData; 963 size = mCodecSpecificDataSize; 964 mCodecSpecificData = NULL; 965 mCodecSpecificDataSize = 0; 966 967 status_t err = makeAVCCodecSpecificData( 968 (const uint8_t *)tmp, size); 969 free(tmp); 970 tmp = NULL; 971 CHECK_EQ(OK, err); 972 973 mGotAllCodecSpecificData = true; 974 } 975 976 continue; 977 } 978 979 if (!mGotAllCodecSpecificData) { 980 mGotAllCodecSpecificData = true; 981 } 982 983 // Make a deep copy of the MediaBuffer and Metadata and release 984 // the original as soon as we can 985 MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 986 memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 987 buffer->range_length()); 988 copy->set_range(0, buffer->range_length()); 989 meta_data = new MetaData(*buffer->meta_data().get()); 990 buffer->release(); 991 buffer = NULL; 992 993 if (is_avc) StripStartcode(copy); 994 995 SampleInfo info; 996 info.size = is_avc 997#if USE_NALLEN_FOUR 998 ? copy->range_length() + 4 999#else 1000 ? copy->range_length() + 2 1001#endif 1002 : copy->range_length(); 1003 1004 // Max file size or duration handling 1005 mEstimatedTrackSizeBytes += info.size; 1006 if (mOwner->exceedsFileSizeLimit()) { 1007 mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 1008 break; 1009 } 1010 if (mOwner->exceedsFileDurationLimit()) { 1011 mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 1012 break; 1013 } 1014 1015 1016 int32_t isSync = false; 1017 meta_data->findInt32(kKeyIsSyncFrame, &isSync); 1018 1019 int64_t timestampUs; 1020 CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 1021 1022//////////////////////////////////////////////////////////////////////////////// 1023 if (mSampleInfos.empty()) { 1024 mStartTimestampUs = timestampUs; 1025 mOwner->setStartTimestampUs(mStartTimestampUs); 1026 } 1027 1028 if (mResumed) { 1029 previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - 1000 * lastDuration); 1030 mResumed = false; 1031 } 1032 1033 timestampUs -= previousPausedDurationUs; 1034 LOGV("time stamp: %lld and previous paused duration %lld", 1035 timestampUs, previousPausedDurationUs); 1036 if (timestampUs > mMaxTimeStampUs) { 1037 mMaxTimeStampUs = timestampUs; 1038 } 1039 1040 // Our timestamp is in ms. 1041 info.timestamp = (timestampUs + 500) / 1000; 1042 mSampleInfos.push_back(info); 1043 if (mSampleInfos.size() > 2) { 1044 if (lastDuration != info.timestamp - lastTimestamp) { 1045 SttsTableEntry sttsEntry(sampleCount, lastDuration); 1046 mSttsTableEntries.push_back(sttsEntry); 1047 sampleCount = 1; 1048 } else { 1049 ++sampleCount; 1050 } 1051 } 1052 if (mSamplesHaveSameSize) { 1053 if (mSampleInfos.size() >= 2 && previousSampleSize != info.size) { 1054 mSamplesHaveSameSize = false; 1055 } 1056 previousSampleSize = info.size; 1057 } 1058 lastDuration = info.timestamp - lastTimestamp; 1059 lastTimestamp = info.timestamp; 1060 1061 if (isSync != 0) { 1062 mStssTableEntries.push_back(mSampleInfos.size()); 1063 } 1064 1065 if (mOwner->numTracks() == 1) { 1066 off_t offset = is_avc? mOwner->addLengthPrefixedSample_l(copy) 1067 : mOwner->addSample_l(copy); 1068 if (mChunkOffsets.empty()) { 1069 mChunkOffsets.push_back(offset); 1070 } 1071 copy->release(); 1072 copy = NULL; 1073 continue; 1074 } 1075 1076 mChunkSamples.push_back(copy); 1077 if (interleaveDurationUs == 0) { 1078 StscTableEntry stscEntry(++nChunks, 1, 1); 1079 mStscTableEntries.push_back(stscEntry); 1080 writeOneChunk(is_avc); 1081 } else { 1082 if (chunkTimestampUs == 0) { 1083 chunkTimestampUs = timestampUs; 1084 } else { 1085 if (timestampUs - chunkTimestampUs > interleaveDurationUs) { 1086 ++nChunks; 1087 mChunkDurations.push_back(timestampUs - chunkTimestampUs); 1088 if (nChunks == 1 || // First chunk 1089 (--(mStscTableEntries.end()))->samplesPerChunk != 1090 mChunkSamples.size()) { 1091 StscTableEntry stscEntry(nChunks, 1092 mChunkSamples.size(), 1); 1093 mStscTableEntries.push_back(stscEntry); 1094 } 1095 writeOneChunk(is_avc); 1096 chunkTimestampUs = timestampUs; 1097 } 1098 } 1099 } 1100 1101 } 1102 1103 if (mSampleInfos.empty()) { 1104 mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_STOP_PREMATURELY, 0); 1105 } 1106 1107 // Last chunk 1108 if (mOwner->numTracks() == 1) { 1109 StscTableEntry stscEntry(1, mSampleInfos.size(), 1); 1110 mStscTableEntries.push_back(stscEntry); 1111 } else if (!mChunkSamples.empty()) { 1112 ++nChunks; 1113 StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1); 1114 mStscTableEntries.push_back(stscEntry); 1115 writeOneChunk(is_avc); 1116 } 1117 1118 // We don't really know how long the last frame lasts, since 1119 // there is no frame time after it, just repeat the previous 1120 // frame's duration. 1121 if (mSampleInfos.size() == 1) { 1122 lastDuration = 0; // A single sample's duration 1123 } else { 1124 ++sampleCount; // Count for the last sample 1125 } 1126 SttsTableEntry sttsEntry(sampleCount, lastDuration); 1127 mSttsTableEntries.push_back(sttsEntry); 1128 mReachedEOS = true; 1129 LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s", 1130 count, nZeroLengthFrames, mSampleInfos.size(), is_audio? "audio": "video"); 1131 1132 logStatisticalData(is_audio); 1133} 1134 1135void MPEG4Writer::Track::findMinMaxFrameRates(float *minFps, float *maxFps) { 1136 int32_t minSampleDuration = 0x7FFFFFFF; 1137 int32_t maxSampleDuration = 0; 1138 for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 1139 it != mSttsTableEntries.end(); ++it) { 1140 int32_t sampleDuration = static_cast<int32_t>(it->sampleDuration); 1141 if (sampleDuration > maxSampleDuration) { 1142 maxSampleDuration = sampleDuration; 1143 } else if (sampleDuration < minSampleDuration) { 1144 minSampleDuration = sampleDuration; 1145 } 1146 } 1147 CHECK(minSampleDuration != 0 && maxSampleDuration != 0); 1148 *minFps = 1000.0 / maxSampleDuration; 1149 *maxFps = 1000.0 / minSampleDuration; 1150} 1151 1152// Don't count the last duration 1153void MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) { 1154 int64_t duration = mOwner->interleaveDuration(); 1155 int64_t minChunkDuration = duration; 1156 int64_t maxChunkDuration = duration; 1157 if (mChunkDurations.size() > 1) { 1158 for (List<int64_t>::iterator it = mChunkDurations.begin(); 1159 it != --mChunkDurations.end(); ++it) { 1160 if (minChunkDuration > (*it)) { 1161 minChunkDuration = (*it); 1162 } else if (maxChunkDuration < (*it)) { 1163 maxChunkDuration = (*it); 1164 } 1165 } 1166 } 1167 *min = minChunkDuration; 1168 *max = maxChunkDuration; 1169} 1170 1171void MPEG4Writer::Track::logStatisticalData(bool isAudio) { 1172 if (mMaxTimeStampUs <= 0 || mSampleInfos.empty()) { 1173 LOGI("nothing is recorded"); 1174 return; 1175 } 1176 1177 bool collectStats = false; 1178 char value[PROPERTY_VALUE_MAX]; 1179 if (property_get("media.stagefright.record-stats", value, NULL) 1180 && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 1181 collectStats = true; 1182 } 1183 1184 if (collectStats) { 1185 if (isAudio) { 1186 LOGI("audio track - duration %lld us", mMaxTimeStampUs); 1187 } else { 1188 float fps = (mSampleInfos.size() * 1000000.0) / mMaxTimeStampUs; 1189 float minFps; 1190 float maxFps; 1191 findMinMaxFrameRates(&minFps, &maxFps); 1192 LOGI("video track - duration %lld us", mMaxTimeStampUs); 1193 LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f", 1194 minFps, fps, maxFps); 1195 } 1196 1197 int64_t totalBytes = 0; 1198 for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 1199 it != mSampleInfos.end(); ++it) { 1200 totalBytes += it->size; 1201 } 1202 float bitRate = (totalBytes * 8000000.0) / mMaxTimeStampUs; 1203 LOGI("avg bit rate (bps): %.2f", bitRate); 1204 1205 int64_t duration = mOwner->interleaveDuration(); 1206 if (duration != 0) { // If interleaving is enabled 1207 int64_t minChunk, maxChunk; 1208 findMinMaxChunkDurations(&minChunk, &maxChunk); 1209 LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld", 1210 minChunk, duration, maxChunk); 1211 } 1212 } 1213} 1214 1215void MPEG4Writer::Track::writeOneChunk(bool isAvc) { 1216 mOwner->lock(); 1217 for (List<MediaBuffer *>::iterator it = mChunkSamples.begin(); 1218 it != mChunkSamples.end(); ++it) { 1219 off_t offset = isAvc? mOwner->addLengthPrefixedSample_l(*it) 1220 : mOwner->addSample_l(*it); 1221 if (it == mChunkSamples.begin()) { 1222 mChunkOffsets.push_back(offset); 1223 } 1224 } 1225 mOwner->unlock(); 1226 while (!mChunkSamples.empty()) { 1227 List<MediaBuffer *>::iterator it = mChunkSamples.begin(); 1228 (*it)->release(); 1229 (*it) = NULL; 1230 mChunkSamples.erase(it); 1231 } 1232 mChunkSamples.clear(); 1233} 1234 1235int64_t MPEG4Writer::Track::getDurationUs() const { 1236 return mMaxTimeStampUs; 1237} 1238 1239int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 1240 return mEstimatedTrackSizeBytes; 1241} 1242 1243void MPEG4Writer::Track::writeTrackHeader( 1244 int32_t trackID, bool use32BitOffset) { 1245 const char *mime; 1246 bool success = mMeta->findCString(kKeyMIMEType, &mime); 1247 CHECK(success); 1248 1249 bool is_audio = !strncasecmp(mime, "audio/", 6); 1250 int32_t timeScale = 1000; 1251 int32_t duration = getDurationUs() / timeScale; 1252 1253 time_t now = time(NULL); 1254 1255 mOwner->beginBox("trak"); 1256 1257 mOwner->beginBox("tkhd"); 1258 // Flags = 7 to indicate that the track is enabled, and 1259 // part of the presentation 1260 mOwner->writeInt32(0x07); // version=0, flags=7 1261 mOwner->writeInt32(now); // creation time 1262 mOwner->writeInt32(now); // modification time 1263 mOwner->writeInt32(trackID); 1264 mOwner->writeInt32(0); // reserved 1265 mOwner->writeInt32(duration); 1266 mOwner->writeInt32(0); // reserved 1267 mOwner->writeInt32(0); // reserved 1268 mOwner->writeInt16(0); // layer 1269 mOwner->writeInt16(0); // alternate group 1270 mOwner->writeInt16(is_audio ? 0x100 : 0); // volume 1271 mOwner->writeInt16(0); // reserved 1272 1273 mOwner->writeInt32(0x10000); // matrix 1274 mOwner->writeInt32(0); 1275 mOwner->writeInt32(0); 1276 mOwner->writeInt32(0); 1277 mOwner->writeInt32(0x10000); 1278 mOwner->writeInt32(0); 1279 mOwner->writeInt32(0); 1280 mOwner->writeInt32(0); 1281 mOwner->writeInt32(0x40000000); 1282 1283 if (is_audio) { 1284 mOwner->writeInt32(0); 1285 mOwner->writeInt32(0); 1286 } else { 1287 int32_t width, height; 1288 bool success = mMeta->findInt32(kKeyWidth, &width); 1289 success = success && mMeta->findInt32(kKeyHeight, &height); 1290 CHECK(success); 1291 1292 mOwner->writeInt32(width << 16); // 32-bit fixed-point value 1293 mOwner->writeInt32(height << 16); // 32-bit fixed-point value 1294 } 1295 mOwner->endBox(); // tkhd 1296 1297 int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 1298 if (mStartTimestampUs != moovStartTimeUs) { 1299 mOwner->beginBox("edts"); 1300 mOwner->beginBox("elst"); 1301 mOwner->writeInt32(0); // version=0, flags=0: 32-bit time 1302 mOwner->writeInt32(2); // never ends with an empty list 1303 int64_t durationMs = 1304 (mStartTimestampUs - moovStartTimeUs) / 1000; 1305 mOwner->writeInt32(durationMs); // edit duration 1306 mOwner->writeInt32(-1); // empty edit box to signal starting time offset 1307 mOwner->writeInt32(1 << 16); // x1 rate 1308 mOwner->writeInt32(duration); 1309 mOwner->writeInt32(0); 1310 mOwner->writeInt32(1 << 16); 1311 mOwner->endBox(); 1312 mOwner->endBox(); 1313 } 1314 1315 mOwner->beginBox("mdia"); 1316 1317 mOwner->beginBox("mdhd"); 1318 mOwner->writeInt32(0); // version=0, flags=0 1319 mOwner->writeInt32(now); // creation time 1320 mOwner->writeInt32(now); // modification time 1321 mOwner->writeInt32(timeScale); // timescale 1322 mOwner->writeInt32(duration); // duration 1323 // Language follows the three letter standard ISO-639-2/T 1324 // 'e', 'n', 'g' for "English", for instance. 1325 // Each character is packed as the difference between its ASCII value and 0x60. 1326 // For "English", these are 00101, 01110, 00111. 1327 // XXX: Where is the padding bit located: 0x15C7? 1328 mOwner->writeInt16(0); // language code 1329 mOwner->writeInt16(0); // predefined 1330 mOwner->endBox(); 1331 1332 mOwner->beginBox("hdlr"); 1333 mOwner->writeInt32(0); // version=0, flags=0 1334 mOwner->writeInt32(0); // component type: should be mhlr 1335 mOwner->writeFourcc(is_audio ? "soun" : "vide"); // component subtype 1336 mOwner->writeInt32(0); // reserved 1337 mOwner->writeInt32(0); // reserved 1338 mOwner->writeInt32(0); // reserved 1339 // Removing "r" for the name string just makes the string 4 byte aligned 1340 mOwner->writeCString(is_audio ? "SoundHandle": "VideoHandle"); // name 1341 mOwner->endBox(); 1342 1343 mOwner->beginBox("minf"); 1344 if (is_audio) { 1345 mOwner->beginBox("smhd"); 1346 mOwner->writeInt32(0); // version=0, flags=0 1347 mOwner->writeInt16(0); // balance 1348 mOwner->writeInt16(0); // reserved 1349 mOwner->endBox(); 1350 } else { 1351 mOwner->beginBox("vmhd"); 1352 mOwner->writeInt32(0x01); // version=0, flags=1 1353 mOwner->writeInt16(0); // graphics mode 1354 mOwner->writeInt16(0); // opcolor 1355 mOwner->writeInt16(0); 1356 mOwner->writeInt16(0); 1357 mOwner->endBox(); 1358 } 1359 1360 mOwner->beginBox("dinf"); 1361 mOwner->beginBox("dref"); 1362 mOwner->writeInt32(0); // version=0, flags=0 1363 mOwner->writeInt32(1); // entry count (either url or urn) 1364 // The table index here refers to the sample description index 1365 // in the sample table entries. 1366 mOwner->beginBox("url "); 1367 mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 1368 mOwner->endBox(); // url 1369 mOwner->endBox(); // dref 1370 mOwner->endBox(); // dinf 1371 1372 mOwner->beginBox("stbl"); 1373 1374 mOwner->beginBox("stsd"); 1375 mOwner->writeInt32(0); // version=0, flags=0 1376 mOwner->writeInt32(1); // entry count 1377 if (is_audio) { 1378 const char *fourcc = NULL; 1379 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 1380 fourcc = "samr"; 1381 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 1382 fourcc = "sawb"; 1383 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 1384 fourcc = "mp4a"; 1385 } else { 1386 LOGE("Unknown mime type '%s'.", mime); 1387 CHECK(!"should not be here, unknown mime type."); 1388 } 1389 1390 mOwner->beginBox(fourcc); // audio format 1391 mOwner->writeInt32(0); // reserved 1392 mOwner->writeInt16(0); // reserved 1393 mOwner->writeInt16(0x1); // data ref index 1394 mOwner->writeInt32(0); // reserved 1395 mOwner->writeInt32(0); // reserved 1396 int32_t nChannels; 1397 CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 1398 mOwner->writeInt16(nChannels); // channel count 1399 mOwner->writeInt16(16); // sample size 1400 mOwner->writeInt16(0); // predefined 1401 mOwner->writeInt16(0); // reserved 1402 1403 int32_t samplerate; 1404 bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 1405 CHECK(success); 1406 1407 mOwner->writeInt32(samplerate << 16); 1408 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 1409 mOwner->beginBox("esds"); 1410 1411 mOwner->writeInt32(0); // version=0, flags=0 1412 mOwner->writeInt8(0x03); // ES_DescrTag 1413 mOwner->writeInt8(23 + mCodecSpecificDataSize); 1414 mOwner->writeInt16(0x0000);// ES_ID 1415 mOwner->writeInt8(0x00); 1416 1417 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 1418 mOwner->writeInt8(15 + mCodecSpecificDataSize); 1419 mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 1420 mOwner->writeInt8(0x15); // streamType AudioStream 1421 1422 mOwner->writeInt16(0x03); // XXX 1423 mOwner->writeInt8(0x00); // buffer size 24-bit 1424 mOwner->writeInt32(96000); // max bit rate 1425 mOwner->writeInt32(96000); // avg bit rate 1426 1427 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 1428 mOwner->writeInt8(mCodecSpecificDataSize); 1429 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 1430 1431 static const uint8_t kData2[] = { 1432 0x06, // SLConfigDescriptorTag 1433 0x01, 1434 0x02 1435 }; 1436 mOwner->write(kData2, sizeof(kData2)); 1437 1438 mOwner->endBox(); // esds 1439 } 1440 mOwner->endBox(); 1441 } else { 1442 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 1443 mOwner->beginBox("mp4v"); 1444 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 1445 mOwner->beginBox("s263"); 1446 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 1447 mOwner->beginBox("avc1"); 1448 } else { 1449 LOGE("Unknown mime type '%s'.", mime); 1450 CHECK(!"should not be here, unknown mime type."); 1451 } 1452 1453 mOwner->writeInt32(0); // reserved 1454 mOwner->writeInt16(0); // reserved 1455 mOwner->writeInt16(1); // data ref index 1456 mOwner->writeInt16(0); // predefined 1457 mOwner->writeInt16(0); // reserved 1458 mOwner->writeInt32(0); // predefined 1459 mOwner->writeInt32(0); // predefined 1460 mOwner->writeInt32(0); // predefined 1461 1462 int32_t width, height; 1463 bool success = mMeta->findInt32(kKeyWidth, &width); 1464 success = success && mMeta->findInt32(kKeyHeight, &height); 1465 CHECK(success); 1466 1467 mOwner->writeInt16(width); 1468 mOwner->writeInt16(height); 1469 mOwner->writeInt32(0x480000); // horiz resolution 1470 mOwner->writeInt32(0x480000); // vert resolution 1471 mOwner->writeInt32(0); // reserved 1472 mOwner->writeInt16(1); // frame count 1473 mOwner->write(" ", 32); 1474 mOwner->writeInt16(0x18); // depth 1475 mOwner->writeInt16(-1); // predefined 1476 1477 CHECK(23 + mCodecSpecificDataSize < 128); 1478 1479 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 1480 mOwner->beginBox("esds"); 1481 1482 mOwner->writeInt32(0); // version=0, flags=0 1483 1484 mOwner->writeInt8(0x03); // ES_DescrTag 1485 mOwner->writeInt8(23 + mCodecSpecificDataSize); 1486 mOwner->writeInt16(0x0000); // ES_ID 1487 mOwner->writeInt8(0x1f); 1488 1489 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 1490 mOwner->writeInt8(15 + mCodecSpecificDataSize); 1491 mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 1492 mOwner->writeInt8(0x11); // streamType VisualStream 1493 1494 static const uint8_t kData[] = { 1495 0x01, 0x77, 0x00, 1496 0x00, 0x03, 0xe8, 0x00, 1497 0x00, 0x03, 0xe8, 0x00 1498 }; 1499 mOwner->write(kData, sizeof(kData)); 1500 1501 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 1502 1503 mOwner->writeInt8(mCodecSpecificDataSize); 1504 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 1505 1506 static const uint8_t kData2[] = { 1507 0x06, // SLConfigDescriptorTag 1508 0x01, 1509 0x02 1510 }; 1511 mOwner->write(kData2, sizeof(kData2)); 1512 1513 mOwner->endBox(); // esds 1514 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 1515 mOwner->beginBox("d263"); 1516 1517 mOwner->writeInt32(0); // vendor 1518 mOwner->writeInt8(0); // decoder version 1519 mOwner->writeInt8(10); // level: 10 1520 mOwner->writeInt8(0); // profile: 0 1521 1522 mOwner->endBox(); // d263 1523 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 1524 mOwner->beginBox("avcC"); 1525 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 1526 mOwner->endBox(); // avcC 1527 } 1528 1529 mOwner->beginBox("pasp"); 1530 // This is useful if the pixel is not square 1531 mOwner->writeInt32(1 << 16); // hspacing 1532 mOwner->writeInt32(1 << 16); // vspacing 1533 mOwner->endBox(); // pasp 1534 mOwner->endBox(); // mp4v, s263 or avc1 1535 } 1536 mOwner->endBox(); // stsd 1537 1538 mOwner->beginBox("stts"); 1539 mOwner->writeInt32(0); // version=0, flags=0 1540 mOwner->writeInt32(mSttsTableEntries.size()); 1541 for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 1542 it != mSttsTableEntries.end(); ++it) { 1543 mOwner->writeInt32(it->sampleCount); 1544 mOwner->writeInt32(it->sampleDuration); 1545 } 1546 mOwner->endBox(); // stts 1547 1548 if (!is_audio) { 1549 mOwner->beginBox("stss"); 1550 mOwner->writeInt32(0); // version=0, flags=0 1551 mOwner->writeInt32(mStssTableEntries.size()); // number of sync frames 1552 for (List<int32_t>::iterator it = mStssTableEntries.begin(); 1553 it != mStssTableEntries.end(); ++it) { 1554 mOwner->writeInt32(*it); 1555 } 1556 mOwner->endBox(); // stss 1557 } 1558 1559 mOwner->beginBox("stsz"); 1560 mOwner->writeInt32(0); // version=0, flags=0 1561 if (mSamplesHaveSameSize) { 1562 List<SampleInfo>::iterator it = mSampleInfos.begin(); 1563 mOwner->writeInt32(it->size); // default sample size 1564 } else { 1565 mOwner->writeInt32(0); 1566 } 1567 mOwner->writeInt32(mSampleInfos.size()); 1568 if (!mSamplesHaveSameSize) { 1569 for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 1570 it != mSampleInfos.end(); ++it) { 1571 mOwner->writeInt32((*it).size); 1572 } 1573 } 1574 mOwner->endBox(); // stsz 1575 1576 mOwner->beginBox("stsc"); 1577 mOwner->writeInt32(0); // version=0, flags=0 1578 mOwner->writeInt32(mStscTableEntries.size()); 1579 for (List<StscTableEntry>::iterator it = mStscTableEntries.begin(); 1580 it != mStscTableEntries.end(); ++it) { 1581 mOwner->writeInt32(it->firstChunk); 1582 mOwner->writeInt32(it->samplesPerChunk); 1583 mOwner->writeInt32(it->sampleDescriptionId); 1584 } 1585 mOwner->endBox(); // stsc 1586 mOwner->beginBox(use32BitOffset? "stco": "co64"); 1587 mOwner->writeInt32(0); // version=0, flags=0 1588 mOwner->writeInt32(mChunkOffsets.size()); 1589 for (List<off_t>::iterator it = mChunkOffsets.begin(); 1590 it != mChunkOffsets.end(); ++it) { 1591 if (use32BitOffset) { 1592 mOwner->writeInt32(static_cast<int32_t>(*it)); 1593 } else { 1594 mOwner->writeInt64((*it)); 1595 } 1596 } 1597 mOwner->endBox(); // co64 1598 1599 mOwner->endBox(); // stbl 1600 mOwner->endBox(); // minf 1601 mOwner->endBox(); // mdia 1602 mOwner->endBox(); // trak 1603} 1604 1605} // namespace android 1606