MPEG4Writer.cpp revision e76dba7af9589d9ed7b116eec3a74168a8352925
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 20#include <arpa/inet.h> 21#include <fcntl.h> 22#include <inttypes.h> 23#include <pthread.h> 24#include <sys/prctl.h> 25#include <sys/stat.h> 26#include <sys/types.h> 27#include <unistd.h> 28 29#include <utils/Log.h> 30 31#include <media/stagefright/foundation/ADebug.h> 32#include <media/stagefright/foundation/AMessage.h> 33#include <media/stagefright/MPEG4Writer.h> 34#include <media/stagefright/MediaBuffer.h> 35#include <media/stagefright/MetaData.h> 36#include <media/stagefright/MediaDefs.h> 37#include <media/stagefright/MediaErrors.h> 38#include <media/stagefright/MediaSource.h> 39#include <media/stagefright/Utils.h> 40#include <media/mediarecorder.h> 41#include <cutils/properties.h> 42 43#include "include/ESDS.h" 44 45 46#ifndef __predict_false 47#define __predict_false(exp) __builtin_expect((exp) != 0, 0) 48#endif 49 50#define WARN_UNLESS(condition, message, ...) \ 51( (__predict_false(condition)) ? false : ({ \ 52 ALOGW("Condition %s failed " message, #condition, ##__VA_ARGS__); \ 53 true; \ 54})) 55 56namespace android { 57 58static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024; 59static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32 60 // filesystem file size 61 // used by most SD cards 62static const uint8_t kNalUnitTypeSeqParamSet = 0x07; 63static const uint8_t kNalUnitTypePicParamSet = 0x08; 64static const int64_t kInitialDelayTimeUs = 700000LL; 65 66class MPEG4Writer::Track { 67public: 68 Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId); 69 70 ~Track(); 71 72 status_t start(MetaData *params); 73 status_t stop(); 74 status_t pause(); 75 bool reachedEOS(); 76 77 int64_t getDurationUs() const; 78 int64_t getEstimatedTrackSizeBytes() const; 79 void writeTrackHeader(bool use32BitOffset = true); 80 void bufferChunk(int64_t timestampUs); 81 bool isAvc() const { return mIsAvc; } 82 bool isAudio() const { return mIsAudio; } 83 bool isMPEG4() const { return mIsMPEG4; } 84 void addChunkOffset(off64_t offset); 85 int32_t getTrackId() const { return mTrackId; } 86 status_t dump(int fd, const Vector<String16>& args) const; 87 88private: 89 enum { 90 kMaxCttsOffsetTimeUs = 1000000LL, // 1 second 91 kSampleArraySize = 1000, 92 }; 93 94 // A helper class to handle faster write box with table entries 95 template<class TYPE> 96 struct ListTableEntries { 97 ListTableEntries(uint32_t elementCapacity, uint32_t entryCapacity) 98 : mElementCapacity(elementCapacity), 99 mEntryCapacity(entryCapacity), 100 mTotalNumTableEntries(0), 101 mNumValuesInCurrEntry(0), 102 mCurrTableEntriesElement(NULL) { 103 CHECK_GT(mElementCapacity, 0); 104 CHECK_GT(mEntryCapacity, 0); 105 } 106 107 // Free the allocated memory. 108 ~ListTableEntries() { 109 while (!mTableEntryList.empty()) { 110 typename List<TYPE *>::iterator it = mTableEntryList.begin(); 111 delete[] (*it); 112 mTableEntryList.erase(it); 113 } 114 } 115 116 // Replace the value at the given position by the given value. 117 // There must be an existing value at the given position. 118 // @arg value must be in network byte order 119 // @arg pos location the value must be in. 120 void set(const TYPE& value, uint32_t pos) { 121 CHECK_LT(pos, mTotalNumTableEntries * mEntryCapacity); 122 123 typename List<TYPE *>::iterator it = mTableEntryList.begin(); 124 uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity)); 125 while (it != mTableEntryList.end() && iterations > 0) { 126 ++it; 127 --iterations; 128 } 129 CHECK(it != mTableEntryList.end()); 130 CHECK_EQ(iterations, 0); 131 132 (*it)[(pos % (mElementCapacity * mEntryCapacity))] = value; 133 } 134 135 // Get the value at the given position by the given value. 136 // @arg value the retrieved value at the position in network byte order. 137 // @arg pos location the value must be in. 138 // @return true if a value is found. 139 bool get(TYPE& value, uint32_t pos) const { 140 if (pos >= mTotalNumTableEntries * mEntryCapacity) { 141 return false; 142 } 143 144 typename List<TYPE *>::iterator it = mTableEntryList.begin(); 145 uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity)); 146 while (it != mTableEntryList.end() && iterations > 0) { 147 ++it; 148 --iterations; 149 } 150 CHECK(it != mTableEntryList.end()); 151 CHECK_EQ(iterations, 0); 152 153 value = (*it)[(pos % (mElementCapacity * mEntryCapacity))]; 154 return true; 155 } 156 157 // Store a single value. 158 // @arg value must be in network byte order. 159 void add(const TYPE& value) { 160 CHECK_LT(mNumValuesInCurrEntry, mElementCapacity); 161 uint32_t nEntries = mTotalNumTableEntries % mElementCapacity; 162 uint32_t nValues = mNumValuesInCurrEntry % mEntryCapacity; 163 if (nEntries == 0 && nValues == 0) { 164 mCurrTableEntriesElement = new TYPE[mEntryCapacity * mElementCapacity]; 165 CHECK(mCurrTableEntriesElement != NULL); 166 mTableEntryList.push_back(mCurrTableEntriesElement); 167 } 168 169 uint32_t pos = nEntries * mEntryCapacity + nValues; 170 mCurrTableEntriesElement[pos] = value; 171 172 ++mNumValuesInCurrEntry; 173 if ((mNumValuesInCurrEntry % mEntryCapacity) == 0) { 174 ++mTotalNumTableEntries; 175 mNumValuesInCurrEntry = 0; 176 } 177 } 178 179 // Write out the table entries: 180 // 1. the number of entries goes first 181 // 2. followed by the values in the table enties in order 182 // @arg writer the writer to actual write to the storage 183 void write(MPEG4Writer *writer) const { 184 CHECK_EQ(mNumValuesInCurrEntry % mEntryCapacity, 0); 185 uint32_t nEntries = mTotalNumTableEntries; 186 writer->writeInt32(nEntries); 187 for (typename List<TYPE *>::iterator it = mTableEntryList.begin(); 188 it != mTableEntryList.end(); ++it) { 189 CHECK_GT(nEntries, 0); 190 if (nEntries >= mElementCapacity) { 191 writer->write(*it, sizeof(TYPE) * mEntryCapacity, mElementCapacity); 192 nEntries -= mElementCapacity; 193 } else { 194 writer->write(*it, sizeof(TYPE) * mEntryCapacity, nEntries); 195 break; 196 } 197 } 198 } 199 200 // Return the number of entries in the table. 201 uint32_t count() const { return mTotalNumTableEntries; } 202 203 private: 204 uint32_t mElementCapacity; // # entries in an element 205 uint32_t mEntryCapacity; // # of values in each entry 206 uint32_t mTotalNumTableEntries; 207 uint32_t mNumValuesInCurrEntry; // up to mEntryCapacity 208 TYPE *mCurrTableEntriesElement; 209 mutable List<TYPE *> mTableEntryList; 210 211 DISALLOW_EVIL_CONSTRUCTORS(ListTableEntries); 212 }; 213 214 215 216 MPEG4Writer *mOwner; 217 sp<MetaData> mMeta; 218 sp<MediaSource> mSource; 219 volatile bool mDone; 220 volatile bool mPaused; 221 volatile bool mResumed; 222 volatile bool mStarted; 223 bool mIsAvc; 224 bool mIsAudio; 225 bool mIsMPEG4; 226 int32_t mTrackId; 227 int64_t mTrackDurationUs; 228 int64_t mMaxChunkDurationUs; 229 230 int64_t mEstimatedTrackSizeBytes; 231 int64_t mMdatSizeBytes; 232 int32_t mTimeScale; 233 234 pthread_t mThread; 235 236 237 List<MediaBuffer *> mChunkSamples; 238 239 bool mSamplesHaveSameSize; 240 ListTableEntries<uint32_t> *mStszTableEntries; 241 242 ListTableEntries<uint32_t> *mStcoTableEntries; 243 ListTableEntries<off64_t> *mCo64TableEntries; 244 ListTableEntries<uint32_t> *mStscTableEntries; 245 ListTableEntries<uint32_t> *mStssTableEntries; 246 ListTableEntries<uint32_t> *mSttsTableEntries; 247 ListTableEntries<uint32_t> *mCttsTableEntries; 248 249 int64_t mMinCttsOffsetTimeUs; 250 int64_t mMaxCttsOffsetTimeUs; 251 252 // Sequence parameter set or picture parameter set 253 struct AVCParamSet { 254 AVCParamSet(uint16_t length, const uint8_t *data) 255 : mLength(length), mData(data) {} 256 257 uint16_t mLength; 258 const uint8_t *mData; 259 }; 260 List<AVCParamSet> mSeqParamSets; 261 List<AVCParamSet> mPicParamSets; 262 uint8_t mProfileIdc; 263 uint8_t mProfileCompatible; 264 uint8_t mLevelIdc; 265 266 void *mCodecSpecificData; 267 size_t mCodecSpecificDataSize; 268 bool mGotAllCodecSpecificData; 269 bool mTrackingProgressStatus; 270 271 bool mReachedEOS; 272 int64_t mStartTimestampUs; 273 int64_t mStartTimeRealUs; 274 int64_t mFirstSampleTimeRealUs; 275 int64_t mPreviousTrackTimeUs; 276 int64_t mTrackEveryTimeDurationUs; 277 278 // Update the audio track's drift information. 279 void updateDriftTime(const sp<MetaData>& meta); 280 281 int32_t getStartTimeOffsetScaledTime() const; 282 283 static void *ThreadWrapper(void *me); 284 status_t threadEntry(); 285 286 const uint8_t *parseParamSet( 287 const uint8_t *data, size_t length, int type, size_t *paramSetLen); 288 289 status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size); 290 status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size); 291 status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size); 292 293 // Track authoring progress status 294 void trackProgressStatus(int64_t timeUs, status_t err = OK); 295 void initTrackingProgressStatus(MetaData *params); 296 297 void getCodecSpecificDataFromInputFormatIfPossible(); 298 299 // Determine the track time scale 300 // If it is an audio track, try to use the sampling rate as 301 // the time scale; however, if user chooses the overwrite 302 // value, the user-supplied time scale will be used. 303 void setTimeScale(); 304 305 // Simple validation on the codec specific data 306 status_t checkCodecSpecificData() const; 307 int32_t mRotation; 308 309 void updateTrackSizeEstimate(); 310 void addOneStscTableEntry(size_t chunkId, size_t sampleId); 311 void addOneStssTableEntry(size_t sampleId); 312 313 // Duration is time scale based 314 void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur); 315 void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur); 316 317 bool isTrackMalFormed() const; 318 void sendTrackSummary(bool hasMultipleTracks); 319 320 // Write the boxes 321 void writeStcoBox(bool use32BitOffset); 322 void writeStscBox(); 323 void writeStszBox(); 324 void writeStssBox(); 325 void writeSttsBox(); 326 void writeCttsBox(); 327 void writeD263Box(); 328 void writePaspBox(); 329 void writeAvccBox(); 330 void writeUrlBox(); 331 void writeDrefBox(); 332 void writeDinfBox(); 333 void writeDamrBox(); 334 void writeMdhdBox(uint32_t now); 335 void writeSmhdBox(); 336 void writeVmhdBox(); 337 void writeHdlrBox(); 338 void writeTkhdBox(uint32_t now); 339 void writeMp4aEsdsBox(); 340 void writeMp4vEsdsBox(); 341 void writeAudioFourCCBox(); 342 void writeVideoFourCCBox(); 343 void writeStblBox(bool use32BitOffset); 344 345 Track(const Track &); 346 Track &operator=(const Track &); 347}; 348 349MPEG4Writer::MPEG4Writer(int fd) 350 : mFd(dup(fd)), 351 mInitCheck(mFd < 0? NO_INIT: OK), 352 mIsRealTimeRecording(true), 353 mUse4ByteNalLength(true), 354 mUse32BitOffset(true), 355 mIsFileSizeLimitExplicitlyRequested(false), 356 mPaused(false), 357 mStarted(false), 358 mWriterThreadStarted(false), 359 mOffset(0), 360 mMdatOffset(0), 361 mEstimatedMoovBoxSize(0), 362 mInterleaveDurationUs(1000000), 363 mLatitudex10000(0), 364 mLongitudex10000(0), 365 mAreGeoTagsAvailable(false), 366 mMetaKeys(new AMessage()), 367 mStartTimeOffsetMs(-1) { 368} 369 370MPEG4Writer::~MPEG4Writer() { 371 reset(); 372 373 while (!mTracks.empty()) { 374 List<Track *>::iterator it = mTracks.begin(); 375 delete *it; 376 (*it) = NULL; 377 mTracks.erase(it); 378 } 379 mTracks.clear(); 380} 381 382status_t MPEG4Writer::dump( 383 int fd, const Vector<String16>& args) { 384 const size_t SIZE = 256; 385 char buffer[SIZE]; 386 String8 result; 387 snprintf(buffer, SIZE, " MPEG4Writer %p\n", this); 388 result.append(buffer); 389 snprintf(buffer, SIZE, " mStarted: %s\n", mStarted? "true": "false"); 390 result.append(buffer); 391 ::write(fd, result.string(), result.size()); 392 for (List<Track *>::iterator it = mTracks.begin(); 393 it != mTracks.end(); ++it) { 394 (*it)->dump(fd, args); 395 } 396 return OK; 397} 398 399status_t MPEG4Writer::Track::dump( 400 int fd, const Vector<String16>& /* args */) const { 401 const size_t SIZE = 256; 402 char buffer[SIZE]; 403 String8 result; 404 snprintf(buffer, SIZE, " %s track\n", mIsAudio? "Audio": "Video"); 405 result.append(buffer); 406 snprintf(buffer, SIZE, " reached EOS: %s\n", 407 mReachedEOS? "true": "false"); 408 result.append(buffer); 409 snprintf(buffer, SIZE, " frames encoded : %d\n", mStszTableEntries->count()); 410 result.append(buffer); 411 snprintf(buffer, SIZE, " duration encoded : %" PRId64 " us\n", mTrackDurationUs); 412 result.append(buffer); 413 ::write(fd, result.string(), result.size()); 414 return OK; 415} 416 417status_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 418 Mutex::Autolock l(mLock); 419 if (mStarted) { 420 ALOGE("Attempt to add source AFTER recording is started"); 421 return UNKNOWN_ERROR; 422 } 423 424 // At most 2 tracks can be supported. 425 if (mTracks.size() >= 2) { 426 ALOGE("Too many tracks (%zu) to add", mTracks.size()); 427 return ERROR_UNSUPPORTED; 428 } 429 430 CHECK(source.get() != NULL); 431 432 // A track of type other than video or audio is not supported. 433 const char *mime; 434 source->getFormat()->findCString(kKeyMIMEType, &mime); 435 bool isAudio = !strncasecmp(mime, "audio/", 6); 436 bool isVideo = !strncasecmp(mime, "video/", 6); 437 if (!isAudio && !isVideo) { 438 ALOGE("Track (%s) other than video or audio is not supported", 439 mime); 440 return ERROR_UNSUPPORTED; 441 } 442 443 // At this point, we know the track to be added is either 444 // video or audio. Thus, we only need to check whether it 445 // is an audio track or not (if it is not, then it must be 446 // a video track). 447 448 // No more than one video or one audio track is supported. 449 for (List<Track*>::iterator it = mTracks.begin(); 450 it != mTracks.end(); ++it) { 451 if ((*it)->isAudio() == isAudio) { 452 ALOGE("%s track already exists", isAudio? "Audio": "Video"); 453 return ERROR_UNSUPPORTED; 454 } 455 } 456 457 // This is the first track of either audio or video. 458 // Go ahead to add the track. 459 Track *track = new Track(this, source, 1 + mTracks.size()); 460 mTracks.push_back(track); 461 462 return OK; 463} 464 465status_t MPEG4Writer::startTracks(MetaData *params) { 466 if (mTracks.empty()) { 467 ALOGE("No source added"); 468 return INVALID_OPERATION; 469 } 470 471 for (List<Track *>::iterator it = mTracks.begin(); 472 it != mTracks.end(); ++it) { 473 status_t err = (*it)->start(params); 474 475 if (err != OK) { 476 for (List<Track *>::iterator it2 = mTracks.begin(); 477 it2 != it; ++it2) { 478 (*it2)->stop(); 479 } 480 481 return err; 482 } 483 } 484 return OK; 485} 486 487int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 488 // This implementation is highly experimental/heurisitic. 489 // 490 // Statistical analysis shows that metadata usually accounts 491 // for a small portion of the total file size, usually < 0.6%. 492 493 // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2, 494 // where 1MB is the common file size limit for MMS application. 495 // The default MAX _MOOV_BOX_SIZE value is based on about 3 496 // minute video recording with a bit rate about 3 Mbps, because 497 // statistics also show that most of the video captured are going 498 // to be less than 3 minutes. 499 500 // If the estimation is wrong, we will pay the price of wasting 501 // some reserved space. This should not happen so often statistically. 502 static const int32_t factor = mUse32BitOffset? 1: 2; 503 static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024; // 3 KB 504 static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 505 int64_t size = MIN_MOOV_BOX_SIZE; 506 507 // Max file size limit is set 508 if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 509 size = mMaxFileSizeLimitBytes * 6 / 1000; 510 } 511 512 // Max file duration limit is set 513 if (mMaxFileDurationLimitUs != 0) { 514 if (bitRate > 0) { 515 int64_t size2 = 516 ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000); 517 if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 518 // When both file size and duration limits are set, 519 // we use the smaller limit of the two. 520 if (size > size2) { 521 size = size2; 522 } 523 } else { 524 // Only max file duration limit is set 525 size = size2; 526 } 527 } 528 } 529 530 if (size < MIN_MOOV_BOX_SIZE) { 531 size = MIN_MOOV_BOX_SIZE; 532 } 533 534 // Any long duration recording will be probably end up with 535 // non-streamable mp4 file. 536 if (size > MAX_MOOV_BOX_SIZE) { 537 size = MAX_MOOV_BOX_SIZE; 538 } 539 540 ALOGI("limits: %" PRId64 "/%" PRId64 " bytes/us, bit rate: %d bps and the" 541 " estimated moov size %" PRId64 " bytes", 542 mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 543 return factor * size; 544} 545 546status_t MPEG4Writer::start(MetaData *param) { 547 if (mInitCheck != OK) { 548 return UNKNOWN_ERROR; 549 } 550 551 /* 552 * Check mMaxFileSizeLimitBytes at the beginning 553 * since mMaxFileSizeLimitBytes may be implicitly 554 * changed later for 32-bit file offset even if 555 * user does not ask to set it explicitly. 556 */ 557 if (mMaxFileSizeLimitBytes != 0) { 558 mIsFileSizeLimitExplicitlyRequested = true; 559 } 560 561 int32_t use64BitOffset; 562 if (param && 563 param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 564 use64BitOffset) { 565 mUse32BitOffset = false; 566 } 567 568 if (mUse32BitOffset) { 569 // Implicit 32 bit file size limit 570 if (mMaxFileSizeLimitBytes == 0) { 571 mMaxFileSizeLimitBytes = kMax32BitFileSize; 572 } 573 574 // If file size is set to be larger than the 32 bit file 575 // size limit, treat it as an error. 576 if (mMaxFileSizeLimitBytes > kMax32BitFileSize) { 577 ALOGW("32-bit file size limit (%" PRId64 " bytes) too big. " 578 "It is changed to %" PRId64 " bytes", 579 mMaxFileSizeLimitBytes, kMax32BitFileSize); 580 mMaxFileSizeLimitBytes = kMax32BitFileSize; 581 } 582 } 583 584 int32_t use2ByteNalLength; 585 if (param && 586 param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) && 587 use2ByteNalLength) { 588 mUse4ByteNalLength = false; 589 } 590 591 int32_t isRealTimeRecording; 592 if (param && param->findInt32(kKeyRealTimeRecording, &isRealTimeRecording)) { 593 mIsRealTimeRecording = isRealTimeRecording; 594 } 595 596 mStartTimestampUs = -1; 597 598 if (mStarted) { 599 if (mPaused) { 600 mPaused = false; 601 return startTracks(param); 602 } 603 return OK; 604 } 605 606 if (!param || 607 !param->findInt32(kKeyTimeScale, &mTimeScale)) { 608 mTimeScale = 1000; 609 } 610 CHECK_GT(mTimeScale, 0); 611 ALOGV("movie time scale: %d", mTimeScale); 612 613 /* 614 * When the requested file size limit is small, the priority 615 * is to meet the file size limit requirement, rather than 616 * to make the file streamable. mStreamableFile does not tell 617 * whether the actual recorded file is streamable or not. 618 */ 619 mStreamableFile = 620 (mMaxFileSizeLimitBytes != 0 && 621 mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes); 622 623 /* 624 * mWriteMoovBoxToMemory is true if the amount of data in moov box is 625 * smaller than the reserved free space at the beginning of a file, AND 626 * when the content of moov box is constructed. Note that video/audio 627 * frame data is always written to the file but not in the memory. 628 * 629 * Before stop()/reset() is called, mWriteMoovBoxToMemory is always 630 * false. When reset() is called at the end of a recording session, 631 * Moov box needs to be constructed. 632 * 633 * 1) Right before a moov box is constructed, mWriteMoovBoxToMemory 634 * to set to mStreamableFile so that if 635 * the file is intended to be streamable, it is set to true; 636 * otherwise, it is set to false. When the value is set to false, 637 * all the content of the moov box is written immediately to 638 * the end of the file. When the value is set to true, all the 639 * content of the moov box is written to an in-memory cache, 640 * mMoovBoxBuffer, util the following condition happens. Note 641 * that the size of the in-memory cache is the same as the 642 * reserved free space at the beginning of the file. 643 * 644 * 2) While the data of the moov box is written to an in-memory 645 * cache, the data size is checked against the reserved space. 646 * If the data size surpasses the reserved space, subsequent moov 647 * data could no longer be hold in the in-memory cache. This also 648 * indicates that the reserved space was too small. At this point, 649 * _all_ moov data must be written to the end of the file. 650 * mWriteMoovBoxToMemory must be set to false to direct the write 651 * to the file. 652 * 653 * 3) If the data size in moov box is smaller than the reserved 654 * space after moov box is completely constructed, the in-memory 655 * cache copy of the moov box is written to the reserved free 656 * space. Thus, immediately after the moov is completedly 657 * constructed, mWriteMoovBoxToMemory is always set to false. 658 */ 659 mWriteMoovBoxToMemory = false; 660 mMoovBoxBuffer = NULL; 661 mMoovBoxBufferOffset = 0; 662 663 writeFtypBox(param); 664 665 mFreeBoxOffset = mOffset; 666 667 if (mEstimatedMoovBoxSize == 0) { 668 int32_t bitRate = -1; 669 if (param) { 670 param->findInt32(kKeyBitRate, &bitRate); 671 } 672 mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 673 } 674 CHECK_GE(mEstimatedMoovBoxSize, 8); 675 if (mStreamableFile) { 676 // Reserve a 'free' box only for streamable file 677 lseek64(mFd, mFreeBoxOffset, SEEK_SET); 678 writeInt32(mEstimatedMoovBoxSize); 679 write("free", 4); 680 mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 681 } else { 682 mMdatOffset = mOffset; 683 } 684 685 mOffset = mMdatOffset; 686 lseek64(mFd, mMdatOffset, SEEK_SET); 687 if (mUse32BitOffset) { 688 write("????mdat", 8); 689 } else { 690 write("\x00\x00\x00\x01mdat????????", 16); 691 } 692 693 status_t err = startWriterThread(); 694 if (err != OK) { 695 return err; 696 } 697 698 err = startTracks(param); 699 if (err != OK) { 700 return err; 701 } 702 703 mStarted = true; 704 return OK; 705} 706 707bool MPEG4Writer::use32BitFileOffset() const { 708 return mUse32BitOffset; 709} 710 711status_t MPEG4Writer::pause() { 712 if (mInitCheck != OK) { 713 return OK; 714 } 715 mPaused = true; 716 status_t err = OK; 717 for (List<Track *>::iterator it = mTracks.begin(); 718 it != mTracks.end(); ++it) { 719 status_t status = (*it)->pause(); 720 if (status != OK) { 721 err = status; 722 } 723 } 724 return err; 725} 726 727void MPEG4Writer::stopWriterThread() { 728 ALOGD("Stopping writer thread"); 729 if (!mWriterThreadStarted) { 730 return; 731 } 732 733 { 734 Mutex::Autolock autolock(mLock); 735 736 mDone = true; 737 mChunkReadyCondition.signal(); 738 } 739 740 void *dummy; 741 pthread_join(mThread, &dummy); 742 mWriterThreadStarted = false; 743 ALOGD("Writer thread stopped"); 744} 745 746/* 747 * MP4 file standard defines a composition matrix: 748 * | a b u | 749 * | c d v | 750 * | x y w | 751 * 752 * the element in the matrix is stored in the following 753 * order: {a, b, u, c, d, v, x, y, w}, 754 * where a, b, c, d, x, and y is in 16.16 format, while 755 * u, v and w is in 2.30 format. 756 */ 757void MPEG4Writer::writeCompositionMatrix(int degrees) { 758 ALOGV("writeCompositionMatrix"); 759 uint32_t a = 0x00010000; 760 uint32_t b = 0; 761 uint32_t c = 0; 762 uint32_t d = 0x00010000; 763 switch (degrees) { 764 case 0: 765 break; 766 case 90: 767 a = 0; 768 b = 0x00010000; 769 c = 0xFFFF0000; 770 d = 0; 771 break; 772 case 180: 773 a = 0xFFFF0000; 774 d = 0xFFFF0000; 775 break; 776 case 270: 777 a = 0; 778 b = 0xFFFF0000; 779 c = 0x00010000; 780 d = 0; 781 break; 782 default: 783 CHECK(!"Should never reach this unknown rotation"); 784 break; 785 } 786 787 writeInt32(a); // a 788 writeInt32(b); // b 789 writeInt32(0); // u 790 writeInt32(c); // c 791 writeInt32(d); // d 792 writeInt32(0); // v 793 writeInt32(0); // x 794 writeInt32(0); // y 795 writeInt32(0x40000000); // w 796} 797 798void MPEG4Writer::release() { 799 close(mFd); 800 mFd = -1; 801 mInitCheck = NO_INIT; 802 mStarted = false; 803} 804 805status_t MPEG4Writer::reset() { 806 if (mInitCheck != OK) { 807 return OK; 808 } else { 809 if (!mWriterThreadStarted || 810 !mStarted) { 811 if (mWriterThreadStarted) { 812 stopWriterThread(); 813 } 814 release(); 815 return OK; 816 } 817 } 818 819 status_t err = OK; 820 int64_t maxDurationUs = 0; 821 int64_t minDurationUs = 0x7fffffffffffffffLL; 822 for (List<Track *>::iterator it = mTracks.begin(); 823 it != mTracks.end(); ++it) { 824 status_t status = (*it)->stop(); 825 if (err == OK && status != OK) { 826 err = status; 827 } 828 829 int64_t durationUs = (*it)->getDurationUs(); 830 if (durationUs > maxDurationUs) { 831 maxDurationUs = durationUs; 832 } 833 if (durationUs < minDurationUs) { 834 minDurationUs = durationUs; 835 } 836 } 837 838 if (mTracks.size() > 1) { 839 ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", 840 minDurationUs, maxDurationUs); 841 } 842 843 stopWriterThread(); 844 845 // Do not write out movie header on error. 846 if (err != OK) { 847 release(); 848 return err; 849 } 850 851 // Fix up the size of the 'mdat' chunk. 852 if (mUse32BitOffset) { 853 lseek64(mFd, mMdatOffset, SEEK_SET); 854 uint32_t size = htonl(static_cast<uint32_t>(mOffset - mMdatOffset)); 855 ::write(mFd, &size, 4); 856 } else { 857 lseek64(mFd, mMdatOffset + 8, SEEK_SET); 858 uint64_t size = mOffset - mMdatOffset; 859 size = hton64(size); 860 ::write(mFd, &size, 8); 861 } 862 lseek64(mFd, mOffset, SEEK_SET); 863 864 // Construct moov box now 865 mMoovBoxBufferOffset = 0; 866 mWriteMoovBoxToMemory = mStreamableFile; 867 if (mWriteMoovBoxToMemory) { 868 // There is no need to allocate in-memory cache 869 // for moov box if the file is not streamable. 870 871 mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 872 CHECK(mMoovBoxBuffer != NULL); 873 } 874 writeMoovBox(maxDurationUs); 875 876 // mWriteMoovBoxToMemory could be set to false in 877 // MPEG4Writer::write() method 878 if (mWriteMoovBoxToMemory) { 879 mWriteMoovBoxToMemory = false; 880 // Content of the moov box is saved in the cache, and the in-memory 881 // moov box needs to be written to the file in a single shot. 882 883 CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize); 884 885 // Moov box 886 lseek64(mFd, mFreeBoxOffset, SEEK_SET); 887 mOffset = mFreeBoxOffset; 888 write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset); 889 890 // Free box 891 lseek64(mFd, mOffset, SEEK_SET); 892 writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 893 write("free", 4); 894 } else { 895 ALOGI("The mp4 file will not be streamable."); 896 } 897 898 // Free in-memory cache for moov box 899 if (mMoovBoxBuffer != NULL) { 900 free(mMoovBoxBuffer); 901 mMoovBoxBuffer = NULL; 902 mMoovBoxBufferOffset = 0; 903 } 904 905 CHECK(mBoxes.empty()); 906 907 release(); 908 return err; 909} 910 911uint32_t MPEG4Writer::getMpeg4Time() { 912 time_t now = time(NULL); 913 // MP4 file uses time counting seconds since midnight, Jan. 1, 1904 914 // while time function returns Unix epoch values which starts 915 // at 1970-01-01. Lets add the number of seconds between them 916 uint32_t mpeg4Time = now + (66 * 365 + 17) * (24 * 60 * 60); 917 return mpeg4Time; 918} 919 920void MPEG4Writer::writeMvhdBox(int64_t durationUs) { 921 uint32_t now = getMpeg4Time(); 922 beginBox("mvhd"); 923 writeInt32(0); // version=0, flags=0 924 writeInt32(now); // creation time 925 writeInt32(now); // modification time 926 writeInt32(mTimeScale); // mvhd timescale 927 int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6; 928 writeInt32(duration); 929 writeInt32(0x10000); // rate: 1.0 930 writeInt16(0x100); // volume 931 writeInt16(0); // reserved 932 writeInt32(0); // reserved 933 writeInt32(0); // reserved 934 writeCompositionMatrix(0); // matrix 935 writeInt32(0); // predefined 936 writeInt32(0); // predefined 937 writeInt32(0); // predefined 938 writeInt32(0); // predefined 939 writeInt32(0); // predefined 940 writeInt32(0); // predefined 941 writeInt32(mTracks.size() + 1); // nextTrackID 942 endBox(); // mvhd 943} 944 945void MPEG4Writer::writeMoovBox(int64_t durationUs) { 946 beginBox("moov"); 947 writeMvhdBox(durationUs); 948 if (mAreGeoTagsAvailable) { 949 writeUdtaBox(); 950 } 951 writeMetaBox(); 952 int32_t id = 1; 953 for (List<Track *>::iterator it = mTracks.begin(); 954 it != mTracks.end(); ++it, ++id) { 955 (*it)->writeTrackHeader(mUse32BitOffset); 956 } 957 endBox(); // moov 958} 959 960void MPEG4Writer::writeFtypBox(MetaData *param) { 961 beginBox("ftyp"); 962 963 int32_t fileType; 964 if (param && param->findInt32(kKeyFileType, &fileType) && 965 fileType != OUTPUT_FORMAT_MPEG_4) { 966 writeFourcc("3gp4"); 967 writeInt32(0); 968 writeFourcc("isom"); 969 writeFourcc("3gp4"); 970 } else { 971 writeFourcc("mp42"); 972 writeInt32(0); 973 writeFourcc("isom"); 974 writeFourcc("mp42"); 975 } 976 977 endBox(); 978} 979 980static bool isTestModeEnabled() { 981#if (PROPERTY_VALUE_MAX < 5) 982#error "PROPERTY_VALUE_MAX must be at least 5" 983#endif 984 985 // Test mode is enabled only if rw.media.record.test system 986 // property is enabled. 987 char value[PROPERTY_VALUE_MAX]; 988 if (property_get("rw.media.record.test", value, NULL) && 989 (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) { 990 return true; 991 } 992 return false; 993} 994 995void MPEG4Writer::sendSessionSummary() { 996 // Send session summary only if test mode is enabled 997 if (!isTestModeEnabled()) { 998 return; 999 } 1000 1001 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 1002 it != mChunkInfos.end(); ++it) { 1003 int trackNum = it->mTrack->getTrackId() << 28; 1004 notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 1005 trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS, 1006 it->mMaxInterChunkDurUs); 1007 } 1008} 1009 1010status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 1011 mInterleaveDurationUs = durationUs; 1012 return OK; 1013} 1014 1015void MPEG4Writer::lock() { 1016 mLock.lock(); 1017} 1018 1019void MPEG4Writer::unlock() { 1020 mLock.unlock(); 1021} 1022 1023off64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 1024 off64_t old_offset = mOffset; 1025 1026 ::write(mFd, 1027 (const uint8_t *)buffer->data() + buffer->range_offset(), 1028 buffer->range_length()); 1029 1030 mOffset += buffer->range_length(); 1031 1032 return old_offset; 1033} 1034 1035static void StripStartcode(MediaBuffer *buffer) { 1036 if (buffer->range_length() < 4) { 1037 return; 1038 } 1039 1040 const uint8_t *ptr = 1041 (const uint8_t *)buffer->data() + buffer->range_offset(); 1042 1043 if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 1044 buffer->set_range( 1045 buffer->range_offset() + 4, buffer->range_length() - 4); 1046 } 1047} 1048 1049off64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 1050 off64_t old_offset = mOffset; 1051 1052 size_t length = buffer->range_length(); 1053 1054 if (mUse4ByteNalLength) { 1055 uint8_t x = length >> 24; 1056 ::write(mFd, &x, 1); 1057 x = (length >> 16) & 0xff; 1058 ::write(mFd, &x, 1); 1059 x = (length >> 8) & 0xff; 1060 ::write(mFd, &x, 1); 1061 x = length & 0xff; 1062 ::write(mFd, &x, 1); 1063 1064 ::write(mFd, 1065 (const uint8_t *)buffer->data() + buffer->range_offset(), 1066 length); 1067 1068 mOffset += length + 4; 1069 } else { 1070 CHECK_LT(length, 65536); 1071 1072 uint8_t x = length >> 8; 1073 ::write(mFd, &x, 1); 1074 x = length & 0xff; 1075 ::write(mFd, &x, 1); 1076 ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length); 1077 mOffset += length + 2; 1078 } 1079 1080 return old_offset; 1081} 1082 1083size_t MPEG4Writer::write( 1084 const void *ptr, size_t size, size_t nmemb) { 1085 1086 const size_t bytes = size * nmemb; 1087 if (mWriteMoovBoxToMemory) { 1088 1089 off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 1090 if (moovBoxSize > mEstimatedMoovBoxSize) { 1091 // The reserved moov box at the beginning of the file 1092 // is not big enough. Moov box should be written to 1093 // the end of the file from now on, but not to the 1094 // in-memory cache. 1095 1096 // We write partial moov box that is in the memory to 1097 // the file first. 1098 for (List<off64_t>::iterator it = mBoxes.begin(); 1099 it != mBoxes.end(); ++it) { 1100 (*it) += mOffset; 1101 } 1102 lseek64(mFd, mOffset, SEEK_SET); 1103 ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset); 1104 ::write(mFd, ptr, bytes); 1105 mOffset += (bytes + mMoovBoxBufferOffset); 1106 1107 // All subsequent moov box content will be written 1108 // to the end of the file. 1109 mWriteMoovBoxToMemory = false; 1110 } else { 1111 memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 1112 mMoovBoxBufferOffset += bytes; 1113 } 1114 } else { 1115 ::write(mFd, ptr, size * nmemb); 1116 mOffset += bytes; 1117 } 1118 return bytes; 1119} 1120 1121void MPEG4Writer::beginBox(uint32_t id) { 1122 mBoxes.push_back(mWriteMoovBoxToMemory? 1123 mMoovBoxBufferOffset: mOffset); 1124 1125 writeInt32(0); 1126 writeInt32(id); 1127} 1128 1129void MPEG4Writer::beginBox(const char *fourcc) { 1130 CHECK_EQ(strlen(fourcc), 4); 1131 1132 mBoxes.push_back(mWriteMoovBoxToMemory? 1133 mMoovBoxBufferOffset: mOffset); 1134 1135 writeInt32(0); 1136 writeFourcc(fourcc); 1137} 1138 1139void MPEG4Writer::endBox() { 1140 CHECK(!mBoxes.empty()); 1141 1142 off64_t offset = *--mBoxes.end(); 1143 mBoxes.erase(--mBoxes.end()); 1144 1145 if (mWriteMoovBoxToMemory) { 1146 int32_t x = htonl(mMoovBoxBufferOffset - offset); 1147 memcpy(mMoovBoxBuffer + offset, &x, 4); 1148 } else { 1149 lseek64(mFd, offset, SEEK_SET); 1150 writeInt32(mOffset - offset); 1151 mOffset -= 4; 1152 lseek64(mFd, mOffset, SEEK_SET); 1153 } 1154} 1155 1156void MPEG4Writer::writeInt8(int8_t x) { 1157 write(&x, 1, 1); 1158} 1159 1160void MPEG4Writer::writeInt16(int16_t x) { 1161 x = htons(x); 1162 write(&x, 1, 2); 1163} 1164 1165void MPEG4Writer::writeInt32(int32_t x) { 1166 x = htonl(x); 1167 write(&x, 1, 4); 1168} 1169 1170void MPEG4Writer::writeInt64(int64_t x) { 1171 x = hton64(x); 1172 write(&x, 1, 8); 1173} 1174 1175void MPEG4Writer::writeCString(const char *s) { 1176 size_t n = strlen(s); 1177 write(s, 1, n + 1); 1178} 1179 1180void MPEG4Writer::writeFourcc(const char *s) { 1181 CHECK_EQ(strlen(s), 4); 1182 write(s, 1, 4); 1183} 1184 1185 1186// Written in +/-DD.DDDD format 1187void MPEG4Writer::writeLatitude(int degreex10000) { 1188 bool isNegative = (degreex10000 < 0); 1189 char sign = isNegative? '-': '+'; 1190 1191 // Handle the whole part 1192 char str[9]; 1193 int wholePart = degreex10000 / 10000; 1194 if (wholePart == 0) { 1195 snprintf(str, 5, "%c%.2d.", sign, wholePart); 1196 } else { 1197 snprintf(str, 5, "%+.2d.", wholePart); 1198 } 1199 1200 // Handle the fractional part 1201 int fractionalPart = degreex10000 - (wholePart * 10000); 1202 if (fractionalPart < 0) { 1203 fractionalPart = -fractionalPart; 1204 } 1205 snprintf(&str[4], 5, "%.4d", fractionalPart); 1206 1207 // Do not write the null terminator 1208 write(str, 1, 8); 1209} 1210 1211// Written in +/- DDD.DDDD format 1212void MPEG4Writer::writeLongitude(int degreex10000) { 1213 bool isNegative = (degreex10000 < 0); 1214 char sign = isNegative? '-': '+'; 1215 1216 // Handle the whole part 1217 char str[10]; 1218 int wholePart = degreex10000 / 10000; 1219 if (wholePart == 0) { 1220 snprintf(str, 6, "%c%.3d.", sign, wholePart); 1221 } else { 1222 snprintf(str, 6, "%+.3d.", wholePart); 1223 } 1224 1225 // Handle the fractional part 1226 int fractionalPart = degreex10000 - (wholePart * 10000); 1227 if (fractionalPart < 0) { 1228 fractionalPart = -fractionalPart; 1229 } 1230 snprintf(&str[5], 5, "%.4d", fractionalPart); 1231 1232 // Do not write the null terminator 1233 write(str, 1, 9); 1234} 1235 1236/* 1237 * Geodata is stored according to ISO-6709 standard. 1238 * latitudex10000 is latitude in degrees times 10000, and 1239 * longitudex10000 is longitude in degrees times 10000. 1240 * The range for the latitude is in [-90, +90], and 1241 * The range for the longitude is in [-180, +180] 1242 */ 1243status_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) { 1244 // Is latitude or longitude out of range? 1245 if (latitudex10000 < -900000 || latitudex10000 > 900000 || 1246 longitudex10000 < -1800000 || longitudex10000 > 1800000) { 1247 return BAD_VALUE; 1248 } 1249 1250 mLatitudex10000 = latitudex10000; 1251 mLongitudex10000 = longitudex10000; 1252 mAreGeoTagsAvailable = true; 1253 return OK; 1254} 1255 1256status_t MPEG4Writer::setCaptureRate(float captureFps) { 1257 if (captureFps <= 0.0f) { 1258 return BAD_VALUE; 1259 } 1260 1261 mMetaKeys->setFloat("com.android.capture.fps", captureFps); 1262 return OK; 1263} 1264 1265void MPEG4Writer::write(const void *data, size_t size) { 1266 write(data, 1, size); 1267} 1268 1269bool MPEG4Writer::isFileStreamable() const { 1270 return mStreamableFile; 1271} 1272 1273bool MPEG4Writer::exceedsFileSizeLimit() { 1274 // No limit 1275 if (mMaxFileSizeLimitBytes == 0) { 1276 return false; 1277 } 1278 1279 int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 1280 for (List<Track *>::iterator it = mTracks.begin(); 1281 it != mTracks.end(); ++it) { 1282 nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 1283 } 1284 1285 if (!mStreamableFile) { 1286 // Add 1024 bytes as error tolerance 1287 return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes; 1288 } 1289 // Be conservative in the estimate: do not exceed 95% of 1290 // the target file limit. For small target file size limit, though, 1291 // this will not help. 1292 return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100); 1293} 1294 1295bool MPEG4Writer::exceedsFileDurationLimit() { 1296 // No limit 1297 if (mMaxFileDurationLimitUs == 0) { 1298 return false; 1299 } 1300 1301 for (List<Track *>::iterator it = mTracks.begin(); 1302 it != mTracks.end(); ++it) { 1303 if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 1304 return true; 1305 } 1306 } 1307 return false; 1308} 1309 1310bool MPEG4Writer::reachedEOS() { 1311 bool allDone = true; 1312 for (List<Track *>::iterator it = mTracks.begin(); 1313 it != mTracks.end(); ++it) { 1314 if (!(*it)->reachedEOS()) { 1315 allDone = false; 1316 break; 1317 } 1318 } 1319 1320 return allDone; 1321} 1322 1323void MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 1324 ALOGI("setStartTimestampUs: %" PRId64, timeUs); 1325 CHECK_GE(timeUs, 0ll); 1326 Mutex::Autolock autoLock(mLock); 1327 if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 1328 mStartTimestampUs = timeUs; 1329 ALOGI("Earliest track starting time: %" PRId64, mStartTimestampUs); 1330 } 1331} 1332 1333int64_t MPEG4Writer::getStartTimestampUs() { 1334 Mutex::Autolock autoLock(mLock); 1335 return mStartTimestampUs; 1336} 1337 1338size_t MPEG4Writer::numTracks() { 1339 Mutex::Autolock autolock(mLock); 1340 return mTracks.size(); 1341} 1342 1343//////////////////////////////////////////////////////////////////////////////// 1344 1345MPEG4Writer::Track::Track( 1346 MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId) 1347 : mOwner(owner), 1348 mMeta(source->getFormat()), 1349 mSource(source), 1350 mDone(false), 1351 mPaused(false), 1352 mResumed(false), 1353 mStarted(false), 1354 mTrackId(trackId), 1355 mTrackDurationUs(0), 1356 mEstimatedTrackSizeBytes(0), 1357 mSamplesHaveSameSize(true), 1358 mStszTableEntries(new ListTableEntries<uint32_t>(1000, 1)), 1359 mStcoTableEntries(new ListTableEntries<uint32_t>(1000, 1)), 1360 mCo64TableEntries(new ListTableEntries<off64_t>(1000, 1)), 1361 mStscTableEntries(new ListTableEntries<uint32_t>(1000, 3)), 1362 mStssTableEntries(new ListTableEntries<uint32_t>(1000, 1)), 1363 mSttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)), 1364 mCttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)), 1365 mCodecSpecificData(NULL), 1366 mCodecSpecificDataSize(0), 1367 mGotAllCodecSpecificData(false), 1368 mReachedEOS(false), 1369 mRotation(0) { 1370 getCodecSpecificDataFromInputFormatIfPossible(); 1371 1372 const char *mime; 1373 mMeta->findCString(kKeyMIMEType, &mime); 1374 mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 1375 mIsAudio = !strncasecmp(mime, "audio/", 6); 1376 mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 1377 !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 1378 1379 setTimeScale(); 1380} 1381 1382void MPEG4Writer::Track::updateTrackSizeEstimate() { 1383 1384 uint32_t stcoBoxCount = (mOwner->use32BitFileOffset() 1385 ? mStcoTableEntries->count() 1386 : mCo64TableEntries->count()); 1387 int64_t stcoBoxSizeBytes = stcoBoxCount * 4; 1388 int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4); 1389 1390 mEstimatedTrackSizeBytes = mMdatSizeBytes; // media data size 1391 if (!mOwner->isFileStreamable()) { 1392 // Reserved free space is not large enough to hold 1393 // all meta data and thus wasted. 1394 mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 + // stsc box size 1395 mStssTableEntries->count() * 4 + // stss box size 1396 mSttsTableEntries->count() * 8 + // stts box size 1397 mCttsTableEntries->count() * 8 + // ctts box size 1398 stcoBoxSizeBytes + // stco box size 1399 stszBoxSizeBytes; // stsz box size 1400 } 1401} 1402 1403void MPEG4Writer::Track::addOneStscTableEntry( 1404 size_t chunkId, size_t sampleId) { 1405 1406 mStscTableEntries->add(htonl(chunkId)); 1407 mStscTableEntries->add(htonl(sampleId)); 1408 mStscTableEntries->add(htonl(1)); 1409} 1410 1411void MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) { 1412 mStssTableEntries->add(htonl(sampleId)); 1413} 1414 1415void MPEG4Writer::Track::addOneSttsTableEntry( 1416 size_t sampleCount, int32_t duration) { 1417 1418 if (duration == 0) { 1419 ALOGW("0-duration samples found: %zu", sampleCount); 1420 } 1421 mSttsTableEntries->add(htonl(sampleCount)); 1422 mSttsTableEntries->add(htonl(duration)); 1423} 1424 1425void MPEG4Writer::Track::addOneCttsTableEntry( 1426 size_t sampleCount, int32_t duration) { 1427 1428 if (mIsAudio) { 1429 return; 1430 } 1431 mCttsTableEntries->add(htonl(sampleCount)); 1432 mCttsTableEntries->add(htonl(duration)); 1433} 1434 1435void MPEG4Writer::Track::addChunkOffset(off64_t offset) { 1436 if (mOwner->use32BitFileOffset()) { 1437 uint32_t value = offset; 1438 mStcoTableEntries->add(htonl(value)); 1439 } else { 1440 mCo64TableEntries->add(hton64(offset)); 1441 } 1442} 1443 1444void MPEG4Writer::Track::setTimeScale() { 1445 ALOGV("setTimeScale"); 1446 // Default time scale 1447 mTimeScale = 90000; 1448 1449 if (mIsAudio) { 1450 // Use the sampling rate as the default time scale for audio track. 1451 int32_t sampleRate; 1452 bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 1453 CHECK(success); 1454 mTimeScale = sampleRate; 1455 } 1456 1457 // If someone would like to overwrite the timescale, use user-supplied value. 1458 int32_t timeScale; 1459 if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 1460 mTimeScale = timeScale; 1461 } 1462 1463 CHECK_GT(mTimeScale, 0); 1464} 1465 1466void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 1467 const char *mime; 1468 CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 1469 1470 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 1471 uint32_t type; 1472 const void *data; 1473 size_t size; 1474 if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { 1475 mCodecSpecificData = malloc(size); 1476 mCodecSpecificDataSize = size; 1477 memcpy(mCodecSpecificData, data, size); 1478 mGotAllCodecSpecificData = true; 1479 } 1480 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 1481 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 1482 uint32_t type; 1483 const void *data; 1484 size_t size; 1485 if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 1486 ESDS esds(data, size); 1487 if (esds.getCodecSpecificInfo(&data, &size) == OK) { 1488 mCodecSpecificData = malloc(size); 1489 mCodecSpecificDataSize = size; 1490 memcpy(mCodecSpecificData, data, size); 1491 mGotAllCodecSpecificData = true; 1492 } 1493 } 1494 } 1495} 1496 1497MPEG4Writer::Track::~Track() { 1498 stop(); 1499 1500 delete mStszTableEntries; 1501 delete mStcoTableEntries; 1502 delete mCo64TableEntries; 1503 delete mStscTableEntries; 1504 delete mSttsTableEntries; 1505 delete mStssTableEntries; 1506 delete mCttsTableEntries; 1507 1508 mStszTableEntries = NULL; 1509 mStcoTableEntries = NULL; 1510 mCo64TableEntries = NULL; 1511 mStscTableEntries = NULL; 1512 mSttsTableEntries = NULL; 1513 mStssTableEntries = NULL; 1514 mCttsTableEntries = NULL; 1515 1516 if (mCodecSpecificData != NULL) { 1517 free(mCodecSpecificData); 1518 mCodecSpecificData = NULL; 1519 } 1520} 1521 1522void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 1523 ALOGV("initTrackingProgressStatus"); 1524 mPreviousTrackTimeUs = -1; 1525 mTrackingProgressStatus = false; 1526 mTrackEveryTimeDurationUs = 0; 1527 { 1528 int64_t timeUs; 1529 if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 1530 ALOGV("Receive request to track progress status for every %" PRId64 " us", timeUs); 1531 mTrackEveryTimeDurationUs = timeUs; 1532 mTrackingProgressStatus = true; 1533 } 1534 } 1535} 1536 1537// static 1538void *MPEG4Writer::ThreadWrapper(void *me) { 1539 ALOGV("ThreadWrapper: %p", me); 1540 MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 1541 writer->threadFunc(); 1542 return NULL; 1543} 1544 1545void MPEG4Writer::bufferChunk(const Chunk& chunk) { 1546 ALOGV("bufferChunk: %p", chunk.mTrack); 1547 Mutex::Autolock autolock(mLock); 1548 CHECK_EQ(mDone, false); 1549 1550 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 1551 it != mChunkInfos.end(); ++it) { 1552 1553 if (chunk.mTrack == it->mTrack) { // Found owner 1554 it->mChunks.push_back(chunk); 1555 mChunkReadyCondition.signal(); 1556 return; 1557 } 1558 } 1559 1560 CHECK(!"Received a chunk for a unknown track"); 1561} 1562 1563void MPEG4Writer::writeChunkToFile(Chunk* chunk) { 1564 ALOGV("writeChunkToFile: %" PRId64 " from %s track", 1565 chunk->mTimeStampUs, chunk->mTrack->isAudio()? "audio": "video"); 1566 1567 int32_t isFirstSample = true; 1568 while (!chunk->mSamples.empty()) { 1569 List<MediaBuffer *>::iterator it = chunk->mSamples.begin(); 1570 1571 off64_t offset = chunk->mTrack->isAvc() 1572 ? addLengthPrefixedSample_l(*it) 1573 : addSample_l(*it); 1574 1575 if (isFirstSample) { 1576 chunk->mTrack->addChunkOffset(offset); 1577 isFirstSample = false; 1578 } 1579 1580 (*it)->release(); 1581 (*it) = NULL; 1582 chunk->mSamples.erase(it); 1583 } 1584 chunk->mSamples.clear(); 1585} 1586 1587void MPEG4Writer::writeAllChunks() { 1588 ALOGV("writeAllChunks"); 1589 size_t outstandingChunks = 0; 1590 Chunk chunk; 1591 while (findChunkToWrite(&chunk)) { 1592 writeChunkToFile(&chunk); 1593 ++outstandingChunks; 1594 } 1595 1596 sendSessionSummary(); 1597 1598 mChunkInfos.clear(); 1599 ALOGD("%zu chunks are written in the last batch", outstandingChunks); 1600} 1601 1602bool MPEG4Writer::findChunkToWrite(Chunk *chunk) { 1603 ALOGV("findChunkToWrite"); 1604 1605 int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 1606 Track *track = NULL; 1607 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 1608 it != mChunkInfos.end(); ++it) { 1609 if (!it->mChunks.empty()) { 1610 List<Chunk>::iterator chunkIt = it->mChunks.begin(); 1611 if (chunkIt->mTimeStampUs < minTimestampUs) { 1612 minTimestampUs = chunkIt->mTimeStampUs; 1613 track = it->mTrack; 1614 } 1615 } 1616 } 1617 1618 if (track == NULL) { 1619 ALOGV("Nothing to be written after all"); 1620 return false; 1621 } 1622 1623 if (mIsFirstChunk) { 1624 mIsFirstChunk = false; 1625 } 1626 1627 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 1628 it != mChunkInfos.end(); ++it) { 1629 if (it->mTrack == track) { 1630 *chunk = *(it->mChunks.begin()); 1631 it->mChunks.erase(it->mChunks.begin()); 1632 CHECK_EQ(chunk->mTrack, track); 1633 1634 int64_t interChunkTimeUs = 1635 chunk->mTimeStampUs - it->mPrevChunkTimestampUs; 1636 if (interChunkTimeUs > it->mPrevChunkTimestampUs) { 1637 it->mMaxInterChunkDurUs = interChunkTimeUs; 1638 } 1639 1640 return true; 1641 } 1642 } 1643 1644 return false; 1645} 1646 1647void MPEG4Writer::threadFunc() { 1648 ALOGV("threadFunc"); 1649 1650 prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0); 1651 1652 Mutex::Autolock autoLock(mLock); 1653 while (!mDone) { 1654 Chunk chunk; 1655 bool chunkFound = false; 1656 1657 while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) { 1658 mChunkReadyCondition.wait(mLock); 1659 } 1660 1661 // In real time recording mode, write without holding the lock in order 1662 // to reduce the blocking time for media track threads. 1663 // Otherwise, hold the lock until the existing chunks get written to the 1664 // file. 1665 if (chunkFound) { 1666 if (mIsRealTimeRecording) { 1667 mLock.unlock(); 1668 } 1669 writeChunkToFile(&chunk); 1670 if (mIsRealTimeRecording) { 1671 mLock.lock(); 1672 } 1673 } 1674 } 1675 1676 writeAllChunks(); 1677} 1678 1679status_t MPEG4Writer::startWriterThread() { 1680 ALOGV("startWriterThread"); 1681 1682 mDone = false; 1683 mIsFirstChunk = true; 1684 mDriftTimeUs = 0; 1685 for (List<Track *>::iterator it = mTracks.begin(); 1686 it != mTracks.end(); ++it) { 1687 ChunkInfo info; 1688 info.mTrack = *it; 1689 info.mPrevChunkTimestampUs = 0; 1690 info.mMaxInterChunkDurUs = 0; 1691 mChunkInfos.push_back(info); 1692 } 1693 1694 pthread_attr_t attr; 1695 pthread_attr_init(&attr); 1696 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 1697 pthread_create(&mThread, &attr, ThreadWrapper, this); 1698 pthread_attr_destroy(&attr); 1699 mWriterThreadStarted = true; 1700 return OK; 1701} 1702 1703 1704status_t MPEG4Writer::Track::start(MetaData *params) { 1705 if (!mDone && mPaused) { 1706 mPaused = false; 1707 mResumed = true; 1708 return OK; 1709 } 1710 1711 int64_t startTimeUs; 1712 if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 1713 startTimeUs = 0; 1714 } 1715 mStartTimeRealUs = startTimeUs; 1716 1717 int32_t rotationDegrees; 1718 if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) { 1719 mRotation = rotationDegrees; 1720 } 1721 1722 initTrackingProgressStatus(params); 1723 1724 sp<MetaData> meta = new MetaData; 1725 if (mOwner->isRealTimeRecording() && mOwner->numTracks() > 1) { 1726 /* 1727 * This extra delay of accepting incoming audio/video signals 1728 * helps to align a/v start time at the beginning of a recording 1729 * session, and it also helps eliminate the "recording" sound for 1730 * camcorder applications. 1731 * 1732 * If client does not set the start time offset, we fall back to 1733 * use the default initial delay value. 1734 */ 1735 int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 1736 if (startTimeOffsetUs < 0) { // Start time offset was not set 1737 startTimeOffsetUs = kInitialDelayTimeUs; 1738 } 1739 startTimeUs += startTimeOffsetUs; 1740 ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs); 1741 } 1742 1743 meta->setInt64(kKeyTime, startTimeUs); 1744 1745 status_t err = mSource->start(meta.get()); 1746 if (err != OK) { 1747 mDone = mReachedEOS = true; 1748 return err; 1749 } 1750 1751 pthread_attr_t attr; 1752 pthread_attr_init(&attr); 1753 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 1754 1755 mDone = false; 1756 mStarted = true; 1757 mTrackDurationUs = 0; 1758 mReachedEOS = false; 1759 mEstimatedTrackSizeBytes = 0; 1760 mMdatSizeBytes = 0; 1761 mMaxChunkDurationUs = 0; 1762 1763 pthread_create(&mThread, &attr, ThreadWrapper, this); 1764 pthread_attr_destroy(&attr); 1765 1766 return OK; 1767} 1768 1769status_t MPEG4Writer::Track::pause() { 1770 mPaused = true; 1771 return OK; 1772} 1773 1774status_t MPEG4Writer::Track::stop() { 1775 ALOGD("%s track stopping", mIsAudio? "Audio": "Video"); 1776 if (!mStarted) { 1777 ALOGE("Stop() called but track is not started"); 1778 return ERROR_END_OF_STREAM; 1779 } 1780 1781 if (mDone) { 1782 return OK; 1783 } 1784 mDone = true; 1785 1786 ALOGD("%s track source stopping", mIsAudio? "Audio": "Video"); 1787 mSource->stop(); 1788 ALOGD("%s track source stopped", mIsAudio? "Audio": "Video"); 1789 1790 void *dummy; 1791 pthread_join(mThread, &dummy); 1792 status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); 1793 1794 ALOGD("%s track stopped", mIsAudio? "Audio": "Video"); 1795 return err; 1796} 1797 1798bool MPEG4Writer::Track::reachedEOS() { 1799 return mReachedEOS; 1800} 1801 1802// static 1803void *MPEG4Writer::Track::ThreadWrapper(void *me) { 1804 Track *track = static_cast<Track *>(me); 1805 1806 status_t err = track->threadEntry(); 1807 return (void *)(uintptr_t)err; 1808} 1809 1810static void getNalUnitType(uint8_t byte, uint8_t* type) { 1811 ALOGV("getNalUnitType: %d", byte); 1812 1813 // nal_unit_type: 5-bit unsigned integer 1814 *type = (byte & 0x1F); 1815} 1816 1817static const uint8_t *findNextStartCode( 1818 const uint8_t *data, size_t length) { 1819 1820 ALOGV("findNextStartCode: %p %zu", data, length); 1821 1822 size_t bytesLeft = length; 1823 while (bytesLeft > 4 && 1824 memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) { 1825 --bytesLeft; 1826 } 1827 if (bytesLeft <= 4) { 1828 bytesLeft = 0; // Last parameter set 1829 } 1830 return &data[length - bytesLeft]; 1831} 1832 1833const uint8_t *MPEG4Writer::Track::parseParamSet( 1834 const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 1835 1836 ALOGV("parseParamSet"); 1837 CHECK(type == kNalUnitTypeSeqParamSet || 1838 type == kNalUnitTypePicParamSet); 1839 1840 const uint8_t *nextStartCode = findNextStartCode(data, length); 1841 *paramSetLen = nextStartCode - data; 1842 if (*paramSetLen == 0) { 1843 ALOGE("Param set is malformed, since its length is 0"); 1844 return NULL; 1845 } 1846 1847 AVCParamSet paramSet(*paramSetLen, data); 1848 if (type == kNalUnitTypeSeqParamSet) { 1849 if (*paramSetLen < 4) { 1850 ALOGE("Seq parameter set malformed"); 1851 return NULL; 1852 } 1853 if (mSeqParamSets.empty()) { 1854 mProfileIdc = data[1]; 1855 mProfileCompatible = data[2]; 1856 mLevelIdc = data[3]; 1857 } else { 1858 if (mProfileIdc != data[1] || 1859 mProfileCompatible != data[2] || 1860 mLevelIdc != data[3]) { 1861 ALOGE("Inconsistent profile/level found in seq parameter sets"); 1862 return NULL; 1863 } 1864 } 1865 mSeqParamSets.push_back(paramSet); 1866 } else { 1867 mPicParamSets.push_back(paramSet); 1868 } 1869 return nextStartCode; 1870} 1871 1872status_t MPEG4Writer::Track::copyAVCCodecSpecificData( 1873 const uint8_t *data, size_t size) { 1874 ALOGV("copyAVCCodecSpecificData"); 1875 1876 // 2 bytes for each of the parameter set length field 1877 // plus the 7 bytes for the header 1878 if (size < 4 + 7) { 1879 ALOGE("Codec specific data length too short: %zu", size); 1880 return ERROR_MALFORMED; 1881 } 1882 1883 mCodecSpecificDataSize = size; 1884 mCodecSpecificData = malloc(size); 1885 memcpy(mCodecSpecificData, data, size); 1886 return OK; 1887} 1888 1889status_t MPEG4Writer::Track::parseAVCCodecSpecificData( 1890 const uint8_t *data, size_t size) { 1891 1892 ALOGV("parseAVCCodecSpecificData"); 1893 // Data starts with a start code. 1894 // SPS and PPS are separated with start codes. 1895 // Also, SPS must come before PPS 1896 uint8_t type = kNalUnitTypeSeqParamSet; 1897 bool gotSps = false; 1898 bool gotPps = false; 1899 const uint8_t *tmp = data; 1900 const uint8_t *nextStartCode = data; 1901 size_t bytesLeft = size; 1902 size_t paramSetLen = 0; 1903 mCodecSpecificDataSize = 0; 1904 while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 1905 getNalUnitType(*(tmp + 4), &type); 1906 if (type == kNalUnitTypeSeqParamSet) { 1907 if (gotPps) { 1908 ALOGE("SPS must come before PPS"); 1909 return ERROR_MALFORMED; 1910 } 1911 if (!gotSps) { 1912 gotSps = true; 1913 } 1914 nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 1915 } else if (type == kNalUnitTypePicParamSet) { 1916 if (!gotSps) { 1917 ALOGE("SPS must come before PPS"); 1918 return ERROR_MALFORMED; 1919 } 1920 if (!gotPps) { 1921 gotPps = true; 1922 } 1923 nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 1924 } else { 1925 ALOGE("Only SPS and PPS Nal units are expected"); 1926 return ERROR_MALFORMED; 1927 } 1928 1929 if (nextStartCode == NULL) { 1930 return ERROR_MALFORMED; 1931 } 1932 1933 // Move on to find the next parameter set 1934 bytesLeft -= nextStartCode - tmp; 1935 tmp = nextStartCode; 1936 mCodecSpecificDataSize += (2 + paramSetLen); 1937 } 1938 1939 { 1940 // Check on the number of seq parameter sets 1941 size_t nSeqParamSets = mSeqParamSets.size(); 1942 if (nSeqParamSets == 0) { 1943 ALOGE("Cound not find sequence parameter set"); 1944 return ERROR_MALFORMED; 1945 } 1946 1947 if (nSeqParamSets > 0x1F) { 1948 ALOGE("Too many seq parameter sets (%zu) found", nSeqParamSets); 1949 return ERROR_MALFORMED; 1950 } 1951 } 1952 1953 { 1954 // Check on the number of pic parameter sets 1955 size_t nPicParamSets = mPicParamSets.size(); 1956 if (nPicParamSets == 0) { 1957 ALOGE("Cound not find picture parameter set"); 1958 return ERROR_MALFORMED; 1959 } 1960 if (nPicParamSets > 0xFF) { 1961 ALOGE("Too many pic parameter sets (%zd) found", nPicParamSets); 1962 return ERROR_MALFORMED; 1963 } 1964 } 1965// FIXME: 1966// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above 1967// and remove #if 0 1968#if 0 1969 { 1970 // Check on the profiles 1971 // These profiles requires additional parameter set extensions 1972 if (mProfileIdc == 100 || mProfileIdc == 110 || 1973 mProfileIdc == 122 || mProfileIdc == 144) { 1974 ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 1975 return BAD_VALUE; 1976 } 1977 } 1978#endif 1979 return OK; 1980} 1981 1982status_t MPEG4Writer::Track::makeAVCCodecSpecificData( 1983 const uint8_t *data, size_t size) { 1984 1985 if (mCodecSpecificData != NULL) { 1986 ALOGE("Already have codec specific data"); 1987 return ERROR_MALFORMED; 1988 } 1989 1990 if (size < 4) { 1991 ALOGE("Codec specific data length too short: %zu", size); 1992 return ERROR_MALFORMED; 1993 } 1994 1995 // Data is in the form of AVCCodecSpecificData 1996 if (memcmp("\x00\x00\x00\x01", data, 4)) { 1997 return copyAVCCodecSpecificData(data, size); 1998 } 1999 2000 if (parseAVCCodecSpecificData(data, size) != OK) { 2001 return ERROR_MALFORMED; 2002 } 2003 2004 // ISO 14496-15: AVC file format 2005 mCodecSpecificDataSize += 7; // 7 more bytes in the header 2006 mCodecSpecificData = malloc(mCodecSpecificDataSize); 2007 uint8_t *header = (uint8_t *)mCodecSpecificData; 2008 header[0] = 1; // version 2009 header[1] = mProfileIdc; // profile indication 2010 header[2] = mProfileCompatible; // profile compatibility 2011 header[3] = mLevelIdc; 2012 2013 // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 2014 if (mOwner->useNalLengthFour()) { 2015 header[4] = 0xfc | 3; // length size == 4 bytes 2016 } else { 2017 header[4] = 0xfc | 1; // length size == 2 bytes 2018 } 2019 2020 // 3-bit '111' followed by 5-bit numSequenceParameterSets 2021 int nSequenceParamSets = mSeqParamSets.size(); 2022 header[5] = 0xe0 | nSequenceParamSets; 2023 header += 6; 2024 for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 2025 it != mSeqParamSets.end(); ++it) { 2026 // 16-bit sequence parameter set length 2027 uint16_t seqParamSetLength = it->mLength; 2028 header[0] = seqParamSetLength >> 8; 2029 header[1] = seqParamSetLength & 0xff; 2030 2031 // SPS NAL unit (sequence parameter length bytes) 2032 memcpy(&header[2], it->mData, seqParamSetLength); 2033 header += (2 + seqParamSetLength); 2034 } 2035 2036 // 8-bit nPictureParameterSets 2037 int nPictureParamSets = mPicParamSets.size(); 2038 header[0] = nPictureParamSets; 2039 header += 1; 2040 for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 2041 it != mPicParamSets.end(); ++it) { 2042 // 16-bit picture parameter set length 2043 uint16_t picParamSetLength = it->mLength; 2044 header[0] = picParamSetLength >> 8; 2045 header[1] = picParamSetLength & 0xff; 2046 2047 // PPS Nal unit (picture parameter set length bytes) 2048 memcpy(&header[2], it->mData, picParamSetLength); 2049 header += (2 + picParamSetLength); 2050 } 2051 2052 return OK; 2053} 2054 2055/* 2056 * Updates the drift time from the audio track so that 2057 * the video track can get the updated drift time information 2058 * from the file writer. The fluctuation of the drift time of the audio 2059 * encoding path is smoothed out with a simple filter by giving a larger 2060 * weight to more recently drift time. The filter coefficients, 0.5 and 0.5, 2061 * are heuristically determined. 2062 */ 2063void MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) { 2064 int64_t driftTimeUs = 0; 2065 if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) { 2066 int64_t prevDriftTimeUs = mOwner->getDriftTimeUs(); 2067 int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1; 2068 mOwner->setDriftTimeUs(timeUs); 2069 } 2070} 2071 2072status_t MPEG4Writer::Track::threadEntry() { 2073 int32_t count = 0; 2074 const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 2075 const bool hasMultipleTracks = (mOwner->numTracks() > 1); 2076 int64_t chunkTimestampUs = 0; 2077 int32_t nChunks = 0; 2078 int32_t nZeroLengthFrames = 0; 2079 int64_t lastTimestampUs = 0; // Previous sample time stamp 2080 int64_t lastDurationUs = 0; // Between the previous two samples 2081 int64_t currDurationTicks = 0; // Timescale based ticks 2082 int64_t lastDurationTicks = 0; // Timescale based ticks 2083 int32_t sampleCount = 1; // Sample count in the current stts table entry 2084 uint32_t previousSampleSize = 0; // Size of the previous sample 2085 int64_t previousPausedDurationUs = 0; 2086 int64_t timestampUs = 0; 2087 int64_t cttsOffsetTimeUs = 0; 2088 int64_t currCttsOffsetTimeTicks = 0; // Timescale based ticks 2089 int64_t lastCttsOffsetTimeTicks = -1; // Timescale based ticks 2090 int32_t cttsSampleCount = 0; // Sample count in the current ctts table entry 2091 uint32_t lastSamplesPerChunk = 0; 2092 2093 if (mIsAudio) { 2094 prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0); 2095 } else { 2096 prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0); 2097 } 2098 2099 if (mOwner->isRealTimeRecording()) { 2100 androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO); 2101 } 2102 2103 sp<MetaData> meta_data; 2104 2105 status_t err = OK; 2106 MediaBuffer *buffer; 2107 const char *trackName = mIsAudio ? "Audio" : "Video"; 2108 while (!mDone && (err = mSource->read(&buffer)) == OK) { 2109 if (buffer->range_length() == 0) { 2110 buffer->release(); 2111 buffer = NULL; 2112 ++nZeroLengthFrames; 2113 continue; 2114 } 2115 2116 // If the codec specific data has not been received yet, delay pause. 2117 // After the codec specific data is received, discard what we received 2118 // when the track is to be paused. 2119 if (mPaused && !mResumed) { 2120 buffer->release(); 2121 buffer = NULL; 2122 continue; 2123 } 2124 2125 ++count; 2126 2127 int32_t isCodecConfig; 2128 if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 2129 && isCodecConfig) { 2130 CHECK(!mGotAllCodecSpecificData); 2131 2132 if (mIsAvc) { 2133 status_t err = makeAVCCodecSpecificData( 2134 (const uint8_t *)buffer->data() 2135 + buffer->range_offset(), 2136 buffer->range_length()); 2137 CHECK_EQ((status_t)OK, err); 2138 } else if (mIsMPEG4) { 2139 mCodecSpecificDataSize = buffer->range_length(); 2140 mCodecSpecificData = malloc(mCodecSpecificDataSize); 2141 memcpy(mCodecSpecificData, 2142 (const uint8_t *)buffer->data() 2143 + buffer->range_offset(), 2144 buffer->range_length()); 2145 } 2146 2147 buffer->release(); 2148 buffer = NULL; 2149 2150 mGotAllCodecSpecificData = true; 2151 continue; 2152 } 2153 2154 // Make a deep copy of the MediaBuffer and Metadata and release 2155 // the original as soon as we can 2156 MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 2157 memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 2158 buffer->range_length()); 2159 copy->set_range(0, buffer->range_length()); 2160 meta_data = new MetaData(*buffer->meta_data().get()); 2161 buffer->release(); 2162 buffer = NULL; 2163 2164 if (mIsAvc) StripStartcode(copy); 2165 2166 size_t sampleSize = copy->range_length(); 2167 if (mIsAvc) { 2168 if (mOwner->useNalLengthFour()) { 2169 sampleSize += 4; 2170 } else { 2171 sampleSize += 2; 2172 } 2173 } 2174 2175 // Max file size or duration handling 2176 mMdatSizeBytes += sampleSize; 2177 updateTrackSizeEstimate(); 2178 2179 if (mOwner->exceedsFileSizeLimit()) { 2180 mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 2181 break; 2182 } 2183 if (mOwner->exceedsFileDurationLimit()) { 2184 mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 2185 break; 2186 } 2187 2188 2189 int32_t isSync = false; 2190 meta_data->findInt32(kKeyIsSyncFrame, &isSync); 2191 CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 2192 2193//////////////////////////////////////////////////////////////////////////////// 2194 if (mStszTableEntries->count() == 0) { 2195 mFirstSampleTimeRealUs = systemTime() / 1000; 2196 mStartTimestampUs = timestampUs; 2197 mOwner->setStartTimestampUs(mStartTimestampUs); 2198 previousPausedDurationUs = mStartTimestampUs; 2199 } 2200 2201 if (mResumed) { 2202 int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 2203 if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) { 2204 copy->release(); 2205 return ERROR_MALFORMED; 2206 } 2207 2208 int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 2209 if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) { 2210 copy->release(); 2211 return ERROR_MALFORMED; 2212 } 2213 2214 previousPausedDurationUs += pausedDurationUs - lastDurationUs; 2215 mResumed = false; 2216 } 2217 2218 timestampUs -= previousPausedDurationUs; 2219 if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { 2220 copy->release(); 2221 return ERROR_MALFORMED; 2222 } 2223 2224 if (!mIsAudio) { 2225 /* 2226 * Composition time: timestampUs 2227 * Decoding time: decodingTimeUs 2228 * Composition time offset = composition time - decoding time 2229 */ 2230 int64_t decodingTimeUs; 2231 CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs)); 2232 decodingTimeUs -= previousPausedDurationUs; 2233 cttsOffsetTimeUs = 2234 timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs; 2235 if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) { 2236 copy->release(); 2237 return ERROR_MALFORMED; 2238 } 2239 2240 timestampUs = decodingTimeUs; 2241 ALOGV("decoding time: %" PRId64 " and ctts offset time: %" PRId64, 2242 timestampUs, cttsOffsetTimeUs); 2243 2244 // Update ctts box table if necessary 2245 currCttsOffsetTimeTicks = 2246 (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL; 2247 if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) { 2248 copy->release(); 2249 return ERROR_MALFORMED; 2250 } 2251 2252 if (mStszTableEntries->count() == 0) { 2253 // Force the first ctts table entry to have one single entry 2254 // so that we can do adjustment for the initial track start 2255 // time offset easily in writeCttsBox(). 2256 lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks; 2257 addOneCttsTableEntry(1, currCttsOffsetTimeTicks); 2258 cttsSampleCount = 0; // No sample in ctts box is pending 2259 } else { 2260 if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) { 2261 addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks); 2262 lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks; 2263 cttsSampleCount = 1; // One sample in ctts box is pending 2264 } else { 2265 ++cttsSampleCount; 2266 } 2267 } 2268 2269 // Update ctts time offset range 2270 if (mStszTableEntries->count() == 0) { 2271 mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2272 mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2273 } else { 2274 if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) { 2275 mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2276 } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) { 2277 mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2278 } 2279 } 2280 2281 } 2282 2283 if (mOwner->isRealTimeRecording()) { 2284 if (mIsAudio) { 2285 updateDriftTime(meta_data); 2286 } 2287 } 2288 2289 if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { 2290 copy->release(); 2291 return ERROR_MALFORMED; 2292 } 2293 2294 ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64, 2295 trackName, timestampUs, previousPausedDurationUs); 2296 if (timestampUs > mTrackDurationUs) { 2297 mTrackDurationUs = timestampUs; 2298 } 2299 2300 // We need to use the time scale based ticks, rather than the 2301 // timestamp itself to determine whether we have to use a new 2302 // stts entry, since we may have rounding errors. 2303 // The calculation is intended to reduce the accumulated 2304 // rounding errors. 2305 currDurationTicks = 2306 ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 2307 (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2308 if (currDurationTicks < 0ll) { 2309 ALOGE("timestampUs %" PRId64 " < lastTimestampUs %" PRId64 " for %s track", 2310 timestampUs, lastTimestampUs, trackName); 2311 copy->release(); 2312 return UNKNOWN_ERROR; 2313 } 2314 2315 // if the duration is different for this sample, see if it is close enough to the previous 2316 // duration that we can fudge it and use the same value, to avoid filling the stts table 2317 // with lots of near-identical entries. 2318 // "close enough" here means that the current duration needs to be adjusted by less 2319 // than 0.1 milliseconds 2320 if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) { 2321 int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL 2322 + (mTimeScale / 2)) / mTimeScale; 2323 if (deltaUs > -100 && deltaUs < 100) { 2324 // use previous ticks, and adjust timestamp as if it was actually that number 2325 // of ticks 2326 currDurationTicks = lastDurationTicks; 2327 timestampUs += deltaUs; 2328 } 2329 } 2330 2331 mStszTableEntries->add(htonl(sampleSize)); 2332 if (mStszTableEntries->count() > 2) { 2333 2334 // Force the first sample to have its own stts entry so that 2335 // we can adjust its value later to maintain the A/V sync. 2336 if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) { 2337 addOneSttsTableEntry(sampleCount, lastDurationTicks); 2338 sampleCount = 1; 2339 } else { 2340 ++sampleCount; 2341 } 2342 2343 } 2344 if (mSamplesHaveSameSize) { 2345 if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) { 2346 mSamplesHaveSameSize = false; 2347 } 2348 previousSampleSize = sampleSize; 2349 } 2350 ALOGV("%s timestampUs/lastTimestampUs: %" PRId64 "/%" PRId64, 2351 trackName, timestampUs, lastTimestampUs); 2352 lastDurationUs = timestampUs - lastTimestampUs; 2353 lastDurationTicks = currDurationTicks; 2354 lastTimestampUs = timestampUs; 2355 2356 if (isSync != 0) { 2357 addOneStssTableEntry(mStszTableEntries->count()); 2358 } 2359 2360 if (mTrackingProgressStatus) { 2361 if (mPreviousTrackTimeUs <= 0) { 2362 mPreviousTrackTimeUs = mStartTimestampUs; 2363 } 2364 trackProgressStatus(timestampUs); 2365 } 2366 if (!hasMultipleTracks) { 2367 off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy) 2368 : mOwner->addSample_l(copy); 2369 2370 uint32_t count = (mOwner->use32BitFileOffset() 2371 ? mStcoTableEntries->count() 2372 : mCo64TableEntries->count()); 2373 2374 if (count == 0) { 2375 addChunkOffset(offset); 2376 } 2377 copy->release(); 2378 copy = NULL; 2379 continue; 2380 } 2381 2382 mChunkSamples.push_back(copy); 2383 if (interleaveDurationUs == 0) { 2384 addOneStscTableEntry(++nChunks, 1); 2385 bufferChunk(timestampUs); 2386 } else { 2387 if (chunkTimestampUs == 0) { 2388 chunkTimestampUs = timestampUs; 2389 } else { 2390 int64_t chunkDurationUs = timestampUs - chunkTimestampUs; 2391 if (chunkDurationUs > interleaveDurationUs) { 2392 if (chunkDurationUs > mMaxChunkDurationUs) { 2393 mMaxChunkDurationUs = chunkDurationUs; 2394 } 2395 ++nChunks; 2396 if (nChunks == 1 || // First chunk 2397 lastSamplesPerChunk != mChunkSamples.size()) { 2398 lastSamplesPerChunk = mChunkSamples.size(); 2399 addOneStscTableEntry(nChunks, lastSamplesPerChunk); 2400 } 2401 bufferChunk(timestampUs); 2402 chunkTimestampUs = timestampUs; 2403 } 2404 } 2405 } 2406 2407 } 2408 2409 if (isTrackMalFormed()) { 2410 err = ERROR_MALFORMED; 2411 } 2412 2413 mOwner->trackProgressStatus(mTrackId, -1, err); 2414 2415 // Last chunk 2416 if (!hasMultipleTracks) { 2417 addOneStscTableEntry(1, mStszTableEntries->count()); 2418 } else if (!mChunkSamples.empty()) { 2419 addOneStscTableEntry(++nChunks, mChunkSamples.size()); 2420 bufferChunk(timestampUs); 2421 } 2422 2423 // We don't really know how long the last frame lasts, since 2424 // there is no frame time after it, just repeat the previous 2425 // frame's duration. 2426 if (mStszTableEntries->count() == 1) { 2427 lastDurationUs = 0; // A single sample's duration 2428 lastDurationTicks = 0; 2429 } else { 2430 ++sampleCount; // Count for the last sample 2431 } 2432 2433 if (mStszTableEntries->count() <= 2) { 2434 addOneSttsTableEntry(1, lastDurationTicks); 2435 if (sampleCount - 1 > 0) { 2436 addOneSttsTableEntry(sampleCount - 1, lastDurationTicks); 2437 } 2438 } else { 2439 addOneSttsTableEntry(sampleCount, lastDurationTicks); 2440 } 2441 2442 // The last ctts box may not have been written yet, and this 2443 // is to make sure that we write out the last ctts box. 2444 if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) { 2445 if (cttsSampleCount > 0) { 2446 addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks); 2447 } 2448 } 2449 2450 mTrackDurationUs += lastDurationUs; 2451 mReachedEOS = true; 2452 2453 sendTrackSummary(hasMultipleTracks); 2454 2455 ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", 2456 count, nZeroLengthFrames, mStszTableEntries->count(), trackName); 2457 if (mIsAudio) { 2458 ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs()); 2459 } 2460 2461 if (err == ERROR_END_OF_STREAM) { 2462 return OK; 2463 } 2464 return err; 2465} 2466 2467bool MPEG4Writer::Track::isTrackMalFormed() const { 2468 if (mStszTableEntries->count() == 0) { // no samples written 2469 ALOGE("The number of recorded samples is 0"); 2470 return true; 2471 } 2472 2473 if (!mIsAudio && mStssTableEntries->count() == 0) { // no sync frames for video 2474 ALOGE("There are no sync frames for video track"); 2475 return true; 2476 } 2477 2478 if (OK != checkCodecSpecificData()) { // no codec specific data 2479 return true; 2480 } 2481 2482 return false; 2483} 2484 2485void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { 2486 2487 // Send track summary only if test mode is enabled. 2488 if (!isTestModeEnabled()) { 2489 return; 2490 } 2491 2492 int trackNum = (mTrackId << 28); 2493 2494 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2495 trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE, 2496 mIsAudio? 0: 1); 2497 2498 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2499 trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS, 2500 mTrackDurationUs / 1000); 2501 2502 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2503 trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES, 2504 mStszTableEntries->count()); 2505 2506 { 2507 // The system delay time excluding the requested initial delay that 2508 // is used to eliminate the recording sound. 2509 int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 2510 if (startTimeOffsetUs < 0) { // Start time offset was not set 2511 startTimeOffsetUs = kInitialDelayTimeUs; 2512 } 2513 int64_t initialDelayUs = 2514 mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs; 2515 2516 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2517 trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS, 2518 (initialDelayUs) / 1000); 2519 } 2520 2521 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2522 trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES, 2523 mMdatSizeBytes / 1024); 2524 2525 if (hasMultipleTracks) { 2526 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2527 trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS, 2528 mMaxChunkDurationUs / 1000); 2529 2530 int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 2531 if (mStartTimestampUs != moovStartTimeUs) { 2532 int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 2533 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2534 trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS, 2535 startTimeOffsetUs / 1000); 2536 } 2537 } 2538} 2539 2540void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 2541 ALOGV("trackProgressStatus: %" PRId64 " us", timeUs); 2542 2543 if (mTrackEveryTimeDurationUs > 0 && 2544 timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 2545 ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs); 2546 mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); 2547 mPreviousTrackTimeUs = timeUs; 2548 } 2549} 2550 2551void MPEG4Writer::trackProgressStatus( 2552 size_t trackId, int64_t timeUs, status_t err) { 2553 Mutex::Autolock lock(mLock); 2554 int32_t trackNum = (trackId << 28); 2555 2556 // Error notification 2557 // Do not consider ERROR_END_OF_STREAM an error 2558 if (err != OK && err != ERROR_END_OF_STREAM) { 2559 notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, 2560 trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL, 2561 err); 2562 return; 2563 } 2564 2565 if (timeUs == -1) { 2566 // Send completion notification 2567 notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2568 trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, 2569 err); 2570 } else { 2571 // Send progress status 2572 notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2573 trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME, 2574 timeUs / 1000); 2575 } 2576} 2577 2578void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { 2579 ALOGV("setDriftTimeUs: %" PRId64 " us", driftTimeUs); 2580 Mutex::Autolock autolock(mLock); 2581 mDriftTimeUs = driftTimeUs; 2582} 2583 2584int64_t MPEG4Writer::getDriftTimeUs() { 2585 ALOGV("getDriftTimeUs: %" PRId64 " us", mDriftTimeUs); 2586 Mutex::Autolock autolock(mLock); 2587 return mDriftTimeUs; 2588} 2589 2590bool MPEG4Writer::isRealTimeRecording() const { 2591 return mIsRealTimeRecording; 2592} 2593 2594bool MPEG4Writer::useNalLengthFour() { 2595 return mUse4ByteNalLength; 2596} 2597 2598void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 2599 ALOGV("bufferChunk"); 2600 2601 Chunk chunk(this, timestampUs, mChunkSamples); 2602 mOwner->bufferChunk(chunk); 2603 mChunkSamples.clear(); 2604} 2605 2606int64_t MPEG4Writer::Track::getDurationUs() const { 2607 return mTrackDurationUs; 2608} 2609 2610int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 2611 return mEstimatedTrackSizeBytes; 2612} 2613 2614status_t MPEG4Writer::Track::checkCodecSpecificData() const { 2615 const char *mime; 2616 CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 2617 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 2618 !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 2619 !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2620 if (!mCodecSpecificData || 2621 mCodecSpecificDataSize <= 0) { 2622 ALOGE("Missing codec specific data"); 2623 return ERROR_MALFORMED; 2624 } 2625 } else { 2626 if (mCodecSpecificData || 2627 mCodecSpecificDataSize > 0) { 2628 ALOGE("Unexepected codec specific data found"); 2629 return ERROR_MALFORMED; 2630 } 2631 } 2632 return OK; 2633} 2634 2635void MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) { 2636 2637 ALOGV("%s track time scale: %d", 2638 mIsAudio? "Audio": "Video", mTimeScale); 2639 2640 uint32_t now = getMpeg4Time(); 2641 mOwner->beginBox("trak"); 2642 writeTkhdBox(now); 2643 mOwner->beginBox("mdia"); 2644 writeMdhdBox(now); 2645 writeHdlrBox(); 2646 mOwner->beginBox("minf"); 2647 if (mIsAudio) { 2648 writeSmhdBox(); 2649 } else { 2650 writeVmhdBox(); 2651 } 2652 writeDinfBox(); 2653 writeStblBox(use32BitOffset); 2654 mOwner->endBox(); // minf 2655 mOwner->endBox(); // mdia 2656 mOwner->endBox(); // trak 2657} 2658 2659void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) { 2660 mOwner->beginBox("stbl"); 2661 mOwner->beginBox("stsd"); 2662 mOwner->writeInt32(0); // version=0, flags=0 2663 mOwner->writeInt32(1); // entry count 2664 if (mIsAudio) { 2665 writeAudioFourCCBox(); 2666 } else { 2667 writeVideoFourCCBox(); 2668 } 2669 mOwner->endBox(); // stsd 2670 writeSttsBox(); 2671 writeCttsBox(); 2672 if (!mIsAudio) { 2673 writeStssBox(); 2674 } 2675 writeStszBox(); 2676 writeStscBox(); 2677 writeStcoBox(use32BitOffset); 2678 mOwner->endBox(); // stbl 2679} 2680 2681void MPEG4Writer::Track::writeVideoFourCCBox() { 2682 const char *mime; 2683 bool success = mMeta->findCString(kKeyMIMEType, &mime); 2684 CHECK(success); 2685 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2686 mOwner->beginBox("mp4v"); 2687 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 2688 mOwner->beginBox("s263"); 2689 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2690 mOwner->beginBox("avc1"); 2691 } else { 2692 ALOGE("Unknown mime type '%s'.", mime); 2693 CHECK(!"should not be here, unknown mime type."); 2694 } 2695 2696 mOwner->writeInt32(0); // reserved 2697 mOwner->writeInt16(0); // reserved 2698 mOwner->writeInt16(1); // data ref index 2699 mOwner->writeInt16(0); // predefined 2700 mOwner->writeInt16(0); // reserved 2701 mOwner->writeInt32(0); // predefined 2702 mOwner->writeInt32(0); // predefined 2703 mOwner->writeInt32(0); // predefined 2704 2705 int32_t width, height; 2706 success = mMeta->findInt32(kKeyWidth, &width); 2707 success = success && mMeta->findInt32(kKeyHeight, &height); 2708 CHECK(success); 2709 2710 mOwner->writeInt16(width); 2711 mOwner->writeInt16(height); 2712 mOwner->writeInt32(0x480000); // horiz resolution 2713 mOwner->writeInt32(0x480000); // vert resolution 2714 mOwner->writeInt32(0); // reserved 2715 mOwner->writeInt16(1); // frame count 2716 mOwner->writeInt8(0); // compressor string length 2717 mOwner->write(" ", 31); 2718 mOwner->writeInt16(0x18); // depth 2719 mOwner->writeInt16(-1); // predefined 2720 2721 CHECK_LT(23 + mCodecSpecificDataSize, 128); 2722 2723 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2724 writeMp4vEsdsBox(); 2725 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 2726 writeD263Box(); 2727 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2728 writeAvccBox(); 2729 } 2730 2731 writePaspBox(); 2732 mOwner->endBox(); // mp4v, s263 or avc1 2733} 2734 2735void MPEG4Writer::Track::writeAudioFourCCBox() { 2736 const char *mime; 2737 bool success = mMeta->findCString(kKeyMIMEType, &mime); 2738 CHECK(success); 2739 const char *fourcc = NULL; 2740 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 2741 fourcc = "samr"; 2742 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 2743 fourcc = "sawb"; 2744 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2745 fourcc = "mp4a"; 2746 } else { 2747 ALOGE("Unknown mime type '%s'.", mime); 2748 CHECK(!"should not be here, unknown mime type."); 2749 } 2750 2751 mOwner->beginBox(fourcc); // audio format 2752 mOwner->writeInt32(0); // reserved 2753 mOwner->writeInt16(0); // reserved 2754 mOwner->writeInt16(0x1); // data ref index 2755 mOwner->writeInt32(0); // reserved 2756 mOwner->writeInt32(0); // reserved 2757 int32_t nChannels; 2758 CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 2759 mOwner->writeInt16(nChannels); // channel count 2760 mOwner->writeInt16(16); // sample size 2761 mOwner->writeInt16(0); // predefined 2762 mOwner->writeInt16(0); // reserved 2763 2764 int32_t samplerate; 2765 success = mMeta->findInt32(kKeySampleRate, &samplerate); 2766 CHECK(success); 2767 mOwner->writeInt32(samplerate << 16); 2768 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2769 writeMp4aEsdsBox(); 2770 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 2771 !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 2772 writeDamrBox(); 2773 } 2774 mOwner->endBox(); 2775} 2776 2777void MPEG4Writer::Track::writeMp4aEsdsBox() { 2778 mOwner->beginBox("esds"); 2779 CHECK(mCodecSpecificData); 2780 CHECK_GT(mCodecSpecificDataSize, 0); 2781 2782 // Make sure all sizes encode to a single byte. 2783 CHECK_LT(mCodecSpecificDataSize + 23, 128); 2784 2785 mOwner->writeInt32(0); // version=0, flags=0 2786 mOwner->writeInt8(0x03); // ES_DescrTag 2787 mOwner->writeInt8(23 + mCodecSpecificDataSize); 2788 mOwner->writeInt16(0x0000);// ES_ID 2789 mOwner->writeInt8(0x00); 2790 2791 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2792 mOwner->writeInt8(15 + mCodecSpecificDataSize); 2793 mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 2794 mOwner->writeInt8(0x15); // streamType AudioStream 2795 2796 mOwner->writeInt16(0x03); // XXX 2797 mOwner->writeInt8(0x00); // buffer size 24-bit 2798 mOwner->writeInt32(96000); // max bit rate 2799 mOwner->writeInt32(96000); // avg bit rate 2800 2801 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2802 mOwner->writeInt8(mCodecSpecificDataSize); 2803 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2804 2805 static const uint8_t kData2[] = { 2806 0x06, // SLConfigDescriptorTag 2807 0x01, 2808 0x02 2809 }; 2810 mOwner->write(kData2, sizeof(kData2)); 2811 2812 mOwner->endBox(); // esds 2813} 2814 2815void MPEG4Writer::Track::writeMp4vEsdsBox() { 2816 CHECK(mCodecSpecificData); 2817 CHECK_GT(mCodecSpecificDataSize, 0); 2818 mOwner->beginBox("esds"); 2819 2820 mOwner->writeInt32(0); // version=0, flags=0 2821 2822 mOwner->writeInt8(0x03); // ES_DescrTag 2823 mOwner->writeInt8(23 + mCodecSpecificDataSize); 2824 mOwner->writeInt16(0x0000); // ES_ID 2825 mOwner->writeInt8(0x1f); 2826 2827 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2828 mOwner->writeInt8(15 + mCodecSpecificDataSize); 2829 mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 2830 mOwner->writeInt8(0x11); // streamType VisualStream 2831 2832 static const uint8_t kData[] = { 2833 0x01, 0x77, 0x00, 2834 0x00, 0x03, 0xe8, 0x00, 2835 0x00, 0x03, 0xe8, 0x00 2836 }; 2837 mOwner->write(kData, sizeof(kData)); 2838 2839 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2840 2841 mOwner->writeInt8(mCodecSpecificDataSize); 2842 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2843 2844 static const uint8_t kData2[] = { 2845 0x06, // SLConfigDescriptorTag 2846 0x01, 2847 0x02 2848 }; 2849 mOwner->write(kData2, sizeof(kData2)); 2850 2851 mOwner->endBox(); // esds 2852} 2853 2854void MPEG4Writer::Track::writeTkhdBox(uint32_t now) { 2855 mOwner->beginBox("tkhd"); 2856 // Flags = 7 to indicate that the track is enabled, and 2857 // part of the presentation 2858 mOwner->writeInt32(0x07); // version=0, flags=7 2859 mOwner->writeInt32(now); // creation time 2860 mOwner->writeInt32(now); // modification time 2861 mOwner->writeInt32(mTrackId); // track id starts with 1 2862 mOwner->writeInt32(0); // reserved 2863 int64_t trakDurationUs = getDurationUs(); 2864 int32_t mvhdTimeScale = mOwner->getTimeScale(); 2865 int32_t tkhdDuration = 2866 (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 2867 mOwner->writeInt32(tkhdDuration); // in mvhd timescale 2868 mOwner->writeInt32(0); // reserved 2869 mOwner->writeInt32(0); // reserved 2870 mOwner->writeInt16(0); // layer 2871 mOwner->writeInt16(0); // alternate group 2872 mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 2873 mOwner->writeInt16(0); // reserved 2874 2875 mOwner->writeCompositionMatrix(mRotation); // matrix 2876 2877 if (mIsAudio) { 2878 mOwner->writeInt32(0); 2879 mOwner->writeInt32(0); 2880 } else { 2881 int32_t width, height; 2882 bool success = mMeta->findInt32(kKeyWidth, &width); 2883 success = success && mMeta->findInt32(kKeyHeight, &height); 2884 CHECK(success); 2885 2886 mOwner->writeInt32(width << 16); // 32-bit fixed-point value 2887 mOwner->writeInt32(height << 16); // 32-bit fixed-point value 2888 } 2889 mOwner->endBox(); // tkhd 2890} 2891 2892void MPEG4Writer::Track::writeVmhdBox() { 2893 mOwner->beginBox("vmhd"); 2894 mOwner->writeInt32(0x01); // version=0, flags=1 2895 mOwner->writeInt16(0); // graphics mode 2896 mOwner->writeInt16(0); // opcolor 2897 mOwner->writeInt16(0); 2898 mOwner->writeInt16(0); 2899 mOwner->endBox(); 2900} 2901 2902void MPEG4Writer::Track::writeSmhdBox() { 2903 mOwner->beginBox("smhd"); 2904 mOwner->writeInt32(0); // version=0, flags=0 2905 mOwner->writeInt16(0); // balance 2906 mOwner->writeInt16(0); // reserved 2907 mOwner->endBox(); 2908} 2909 2910void MPEG4Writer::Track::writeHdlrBox() { 2911 mOwner->beginBox("hdlr"); 2912 mOwner->writeInt32(0); // version=0, flags=0 2913 mOwner->writeInt32(0); // component type: should be mhlr 2914 mOwner->writeFourcc(mIsAudio ? "soun" : "vide"); // component subtype 2915 mOwner->writeInt32(0); // reserved 2916 mOwner->writeInt32(0); // reserved 2917 mOwner->writeInt32(0); // reserved 2918 // Removing "r" for the name string just makes the string 4 byte aligned 2919 mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle"); // name 2920 mOwner->endBox(); 2921} 2922 2923void MPEG4Writer::Track::writeMdhdBox(uint32_t now) { 2924 int64_t trakDurationUs = getDurationUs(); 2925 mOwner->beginBox("mdhd"); 2926 mOwner->writeInt32(0); // version=0, flags=0 2927 mOwner->writeInt32(now); // creation time 2928 mOwner->writeInt32(now); // modification time 2929 mOwner->writeInt32(mTimeScale); // media timescale 2930 int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 2931 mOwner->writeInt32(mdhdDuration); // use media timescale 2932 // Language follows the three letter standard ISO-639-2/T 2933 // 'e', 'n', 'g' for "English", for instance. 2934 // Each character is packed as the difference between its ASCII value and 0x60. 2935 // For "English", these are 00101, 01110, 00111. 2936 // XXX: Where is the padding bit located: 0x15C7? 2937 mOwner->writeInt16(0); // language code 2938 mOwner->writeInt16(0); // predefined 2939 mOwner->endBox(); 2940} 2941 2942void MPEG4Writer::Track::writeDamrBox() { 2943 // 3gpp2 Spec AMRSampleEntry fields 2944 mOwner->beginBox("damr"); 2945 mOwner->writeCString(" "); // vendor: 4 bytes 2946 mOwner->writeInt8(0); // decoder version 2947 mOwner->writeInt16(0x83FF); // mode set: all enabled 2948 mOwner->writeInt8(0); // mode change period 2949 mOwner->writeInt8(1); // frames per sample 2950 mOwner->endBox(); 2951} 2952 2953void MPEG4Writer::Track::writeUrlBox() { 2954 // The table index here refers to the sample description index 2955 // in the sample table entries. 2956 mOwner->beginBox("url "); 2957 mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 2958 mOwner->endBox(); // url 2959} 2960 2961void MPEG4Writer::Track::writeDrefBox() { 2962 mOwner->beginBox("dref"); 2963 mOwner->writeInt32(0); // version=0, flags=0 2964 mOwner->writeInt32(1); // entry count (either url or urn) 2965 writeUrlBox(); 2966 mOwner->endBox(); // dref 2967} 2968 2969void MPEG4Writer::Track::writeDinfBox() { 2970 mOwner->beginBox("dinf"); 2971 writeDrefBox(); 2972 mOwner->endBox(); // dinf 2973} 2974 2975void MPEG4Writer::Track::writeAvccBox() { 2976 CHECK(mCodecSpecificData); 2977 CHECK_GE(mCodecSpecificDataSize, 5); 2978 2979 // Patch avcc's lengthSize field to match the number 2980 // of bytes we use to indicate the size of a nal unit. 2981 uint8_t *ptr = (uint8_t *)mCodecSpecificData; 2982 ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1); 2983 mOwner->beginBox("avcC"); 2984 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2985 mOwner->endBox(); // avcC 2986} 2987 2988void MPEG4Writer::Track::writeD263Box() { 2989 mOwner->beginBox("d263"); 2990 mOwner->writeInt32(0); // vendor 2991 mOwner->writeInt8(0); // decoder version 2992 mOwner->writeInt8(10); // level: 10 2993 mOwner->writeInt8(0); // profile: 0 2994 mOwner->endBox(); // d263 2995} 2996 2997// This is useful if the pixel is not square 2998void MPEG4Writer::Track::writePaspBox() { 2999 mOwner->beginBox("pasp"); 3000 mOwner->writeInt32(1 << 16); // hspacing 3001 mOwner->writeInt32(1 << 16); // vspacing 3002 mOwner->endBox(); // pasp 3003} 3004 3005int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const { 3006 int64_t trackStartTimeOffsetUs = 0; 3007 int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 3008 if (mStartTimestampUs != moovStartTimeUs) { 3009 CHECK_GT(mStartTimestampUs, moovStartTimeUs); 3010 trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 3011 } 3012 return (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL; 3013} 3014 3015void MPEG4Writer::Track::writeSttsBox() { 3016 mOwner->beginBox("stts"); 3017 mOwner->writeInt32(0); // version=0, flags=0 3018 uint32_t duration; 3019 CHECK(mSttsTableEntries->get(duration, 1)); 3020 duration = htonl(duration); // Back to host byte order 3021 mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1); 3022 mSttsTableEntries->write(mOwner); 3023 mOwner->endBox(); // stts 3024} 3025 3026void MPEG4Writer::Track::writeCttsBox() { 3027 if (mIsAudio) { // ctts is not for audio 3028 return; 3029 } 3030 3031 // There is no B frame at all 3032 if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) { 3033 return; 3034 } 3035 3036 // Do not write ctts box when there is no need to have it. 3037 if (mCttsTableEntries->count() == 0) { 3038 return; 3039 } 3040 3041 ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]", 3042 mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs); 3043 3044 mOwner->beginBox("ctts"); 3045 mOwner->writeInt32(0); // version=0, flags=0 3046 uint32_t duration; 3047 CHECK(mCttsTableEntries->get(duration, 1)); 3048 duration = htonl(duration); // Back host byte order 3049 mCttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime() - mMinCttsOffsetTimeUs), 1); 3050 mCttsTableEntries->write(mOwner); 3051 mOwner->endBox(); // ctts 3052} 3053 3054void MPEG4Writer::Track::writeStssBox() { 3055 mOwner->beginBox("stss"); 3056 mOwner->writeInt32(0); // version=0, flags=0 3057 mStssTableEntries->write(mOwner); 3058 mOwner->endBox(); // stss 3059} 3060 3061void MPEG4Writer::Track::writeStszBox() { 3062 mOwner->beginBox("stsz"); 3063 mOwner->writeInt32(0); // version=0, flags=0 3064 mOwner->writeInt32(0); 3065 mStszTableEntries->write(mOwner); 3066 mOwner->endBox(); // stsz 3067} 3068 3069void MPEG4Writer::Track::writeStscBox() { 3070 mOwner->beginBox("stsc"); 3071 mOwner->writeInt32(0); // version=0, flags=0 3072 mStscTableEntries->write(mOwner); 3073 mOwner->endBox(); // stsc 3074} 3075 3076void MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) { 3077 mOwner->beginBox(use32BitOffset? "stco": "co64"); 3078 mOwner->writeInt32(0); // version=0, flags=0 3079 if (use32BitOffset) { 3080 mStcoTableEntries->write(mOwner); 3081 } else { 3082 mCo64TableEntries->write(mOwner); 3083 } 3084 mOwner->endBox(); // stco or co64 3085} 3086 3087void MPEG4Writer::writeUdtaBox() { 3088 beginBox("udta"); 3089 writeGeoDataBox(); 3090 endBox(); 3091} 3092 3093void MPEG4Writer::writeHdlr() { 3094 beginBox("hdlr"); 3095 writeInt32(0); // Version, Flags 3096 writeInt32(0); // Predefined 3097 writeFourcc("mdta"); 3098 writeInt32(0); // Reserved[0] 3099 writeInt32(0); // Reserved[1] 3100 writeInt32(0); // Reserved[2] 3101 writeInt8(0); // Name (empty) 3102 endBox(); 3103} 3104 3105void MPEG4Writer::writeKeys() { 3106 size_t count = mMetaKeys->countEntries(); 3107 3108 beginBox("keys"); 3109 writeInt32(0); // Version, Flags 3110 writeInt32(count); // Entry_count 3111 for (size_t i = 0; i < count; i++) { 3112 AMessage::Type type; 3113 const char *key = mMetaKeys->getEntryNameAt(i, &type); 3114 size_t n = strlen(key); 3115 writeInt32(n + 8); 3116 writeFourcc("mdta"); 3117 write(key, n); // write without the \0 3118 } 3119 endBox(); 3120} 3121 3122void MPEG4Writer::writeIlst() { 3123 size_t count = mMetaKeys->countEntries(); 3124 3125 // meta data key types 3126 static const int32_t kKeyType_BE32Float = 23; 3127 static const int32_t kKeyType_BE32SignedInteger = 67; 3128 static const int32_t kKeyType_BE32UnsignedInteger = 77; 3129 3130 beginBox("ilst"); 3131 for (size_t i = 0; i < count; i++) { 3132 beginBox(i + 1); // key id (1-based) 3133 beginBox("data"); 3134 AMessage::Type type; 3135 const char *key = mMetaKeys->getEntryNameAt(i, &type); 3136 switch (type) { 3137 case AMessage::kTypeFloat: 3138 { 3139 float val; 3140 CHECK(mMetaKeys->findFloat(key, &val)); 3141 writeInt32(kKeyType_BE32Float); 3142 writeInt32(*reinterpret_cast<int32_t *>(&val)); 3143 break; 3144 } 3145 3146 case AMessage::kTypeInt32: 3147 { 3148 int32_t val; 3149 CHECK(mMetaKeys->findInt32(key, &val)); 3150 writeInt32(kKeyType_BE32SignedInteger); 3151 writeInt32(val); 3152 break; 3153 } 3154 3155 default: 3156 { 3157 ALOGW("Unsupported key type, writing 0 instead"); 3158 writeInt32(kKeyType_BE32UnsignedInteger); 3159 writeInt32(0); 3160 break; 3161 } 3162 } 3163 endBox(); // data 3164 endBox(); // key id 3165 } 3166 endBox(); // ilst 3167} 3168 3169void MPEG4Writer::writeMetaBox() { 3170 size_t count = mMetaKeys->countEntries(); 3171 if (count == 0) { 3172 return; 3173 } 3174 3175 beginBox("meta"); 3176 writeHdlr(); 3177 writeKeys(); 3178 writeIlst(); 3179 endBox(); 3180} 3181 3182 3183/* 3184 * Geodata is stored according to ISO-6709 standard. 3185 */ 3186void MPEG4Writer::writeGeoDataBox() { 3187 beginBox("\xA9xyz"); 3188 /* 3189 * For historical reasons, any user data start 3190 * with "\0xA9", must be followed by its assoicated 3191 * language code. 3192 * 0x0012: text string length 3193 * 0x15c7: lang (locale) code: en 3194 */ 3195 writeInt32(0x001215c7); 3196 writeLatitude(mLatitudex10000); 3197 writeLongitude(mLongitudex10000); 3198 writeInt8(0x2F); 3199 endBox(); 3200} 3201 3202} // namespace android 3203