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