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