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