MPEG4Writer.cpp revision 56eab8ec67058fe06d6014c56600021e2b965c9e
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 <algorithm> 21 22#include <arpa/inet.h> 23#include <fcntl.h> 24#include <inttypes.h> 25#include <pthread.h> 26#include <sys/prctl.h> 27#include <sys/stat.h> 28#include <sys/types.h> 29#include <unistd.h> 30 31#include <utils/Log.h> 32 33#include <functional> 34 35#include <media/MediaSource.h> 36#include <media/stagefright/foundation/ADebug.h> 37#include <media/stagefright/foundation/AMessage.h> 38#include <media/stagefright/foundation/AUtils.h> 39#include <media/stagefright/foundation/ByteUtils.h> 40#include <media/stagefright/foundation/ColorUtils.h> 41#include <media/stagefright/foundation/avc_utils.h> 42#include <media/stagefright/MPEG4Writer.h> 43#include <media/stagefright/MediaBuffer.h> 44#include <media/stagefright/MetaData.h> 45#include <media/stagefright/MediaDefs.h> 46#include <media/stagefright/MediaErrors.h> 47#include <media/stagefright/Utils.h> 48#include <media/mediarecorder.h> 49#include <cutils/properties.h> 50 51#include "include/ESDS.h" 52#include "include/HevcUtils.h" 53 54#ifndef __predict_false 55#define __predict_false(exp) __builtin_expect((exp) != 0, 0) 56#endif 57 58#define WARN_UNLESS(condition, message, ...) \ 59( (__predict_false(condition)) ? false : ({ \ 60 ALOGW("Condition %s failed " message, #condition, ##__VA_ARGS__); \ 61 true; \ 62})) 63 64namespace android { 65 66static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024; 67static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32 68 // filesystem file size 69 // used by most SD cards 70static const uint8_t kNalUnitTypeSeqParamSet = 0x07; 71static const uint8_t kNalUnitTypePicParamSet = 0x08; 72static const int64_t kInitialDelayTimeUs = 700000LL; 73static const int64_t kMaxMetadataSize = 0x4000000LL; // 64MB max per-frame metadata size 74 75static const char kMetaKey_Version[] = "com.android.version"; 76static const char kMetaKey_Manufacturer[] = "com.android.manufacturer"; 77static const char kMetaKey_Model[] = "com.android.model"; 78 79#ifdef SHOW_BUILD 80static const char kMetaKey_Build[] = "com.android.build"; 81#endif 82static const char kMetaKey_CaptureFps[] = "com.android.capture.fps"; 83static const char kMetaKey_TemporalLayerCount[] = "com.android.video.temporal_layers_count"; 84 85static const int kTimestampDebugCount = 10; 86 87static const uint8_t kMandatoryHevcNalUnitTypes[3] = { 88 kHevcNalUnitTypeVps, 89 kHevcNalUnitTypeSps, 90 kHevcNalUnitTypePps, 91}; 92static const uint8_t kHevcNalUnitTypes[5] = { 93 kHevcNalUnitTypeVps, 94 kHevcNalUnitTypeSps, 95 kHevcNalUnitTypePps, 96 kHevcNalUnitTypePrefixSei, 97 kHevcNalUnitTypeSuffixSei, 98}; 99/* uncomment to include build in meta */ 100//#define SHOW_MODEL_BUILD 1 101 102class MPEG4Writer::Track { 103public: 104 Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId); 105 106 ~Track(); 107 108 status_t start(MetaData *params); 109 status_t stop(bool stopSource = true); 110 status_t pause(); 111 bool reachedEOS(); 112 113 int64_t getDurationUs() const; 114 int64_t getEstimatedTrackSizeBytes() const; 115 int32_t getMetaSizeIncrease() const; 116 void writeTrackHeader(bool use32BitOffset = true); 117 int64_t getMinCttsOffsetTimeUs(); 118 void bufferChunk(int64_t timestampUs); 119 bool isAvc() const { return mIsAvc; } 120 bool isHevc() const { return mIsHevc; } 121 bool isHeic() const { return mIsHeic; } 122 bool isAudio() const { return mIsAudio; } 123 bool isMPEG4() const { return mIsMPEG4; } 124 bool usePrefix() const { return mIsAvc || mIsHevc || mIsHeic; } 125 void addChunkOffset(off64_t offset); 126 void addItemOffsetAndSize(off64_t offset, size_t size); 127 int32_t getTrackId() const { return mTrackId; } 128 status_t dump(int fd, const Vector<String16>& args) const; 129 static const char *getFourCCForMime(const char *mime); 130 const char *getTrackType() const; 131 void resetInternal(); 132 133private: 134 enum { 135 kMaxCttsOffsetTimeUs = 1000000LL, // 1 second 136 kSampleArraySize = 1000, 137 }; 138 139 // A helper class to handle faster write box with table entries 140 template<class TYPE, unsigned ENTRY_SIZE> 141 // ENTRY_SIZE: # of values in each entry 142 struct ListTableEntries { 143 static_assert(ENTRY_SIZE > 0, "ENTRY_SIZE must be positive"); 144 ListTableEntries(uint32_t elementCapacity) 145 : mElementCapacity(elementCapacity), 146 mTotalNumTableEntries(0), 147 mNumValuesInCurrEntry(0), 148 mCurrTableEntriesElement(NULL) { 149 CHECK_GT(mElementCapacity, 0u); 150 // Ensure no integer overflow on allocation in add(). 151 CHECK_LT(ENTRY_SIZE, UINT32_MAX / mElementCapacity); 152 } 153 154 // Free the allocated memory. 155 ~ListTableEntries() { 156 while (!mTableEntryList.empty()) { 157 typename List<TYPE *>::iterator it = mTableEntryList.begin(); 158 delete[] (*it); 159 mTableEntryList.erase(it); 160 } 161 } 162 163 // Replace the value at the given position by the given value. 164 // There must be an existing value at the given position. 165 // @arg value must be in network byte order 166 // @arg pos location the value must be in. 167 void set(const TYPE& value, uint32_t pos) { 168 CHECK_LT(pos, mTotalNumTableEntries * ENTRY_SIZE); 169 170 typename List<TYPE *>::iterator it = mTableEntryList.begin(); 171 uint32_t iterations = (pos / (mElementCapacity * ENTRY_SIZE)); 172 while (it != mTableEntryList.end() && iterations > 0) { 173 ++it; 174 --iterations; 175 } 176 CHECK(it != mTableEntryList.end()); 177 CHECK_EQ(iterations, 0u); 178 179 (*it)[(pos % (mElementCapacity * ENTRY_SIZE))] = value; 180 } 181 182 // Get the value at the given position by the given value. 183 // @arg value the retrieved value at the position in network byte order. 184 // @arg pos location the value must be in. 185 // @return true if a value is found. 186 bool get(TYPE& value, uint32_t pos) const { 187 if (pos >= mTotalNumTableEntries * ENTRY_SIZE) { 188 return false; 189 } 190 191 typename List<TYPE *>::iterator it = mTableEntryList.begin(); 192 uint32_t iterations = (pos / (mElementCapacity * ENTRY_SIZE)); 193 while (it != mTableEntryList.end() && iterations > 0) { 194 ++it; 195 --iterations; 196 } 197 CHECK(it != mTableEntryList.end()); 198 CHECK_EQ(iterations, 0u); 199 200 value = (*it)[(pos % (mElementCapacity * ENTRY_SIZE))]; 201 return true; 202 } 203 204 // adjusts all values by |adjust(value)| 205 void adjustEntries( 206 std::function<void(size_t /* ix */, TYPE(& /* entry */)[ENTRY_SIZE])> update) { 207 size_t nEntries = mTotalNumTableEntries + mNumValuesInCurrEntry / ENTRY_SIZE; 208 size_t ix = 0; 209 for (TYPE *entryArray : mTableEntryList) { 210 size_t num = std::min(nEntries, (size_t)mElementCapacity); 211 for (size_t i = 0; i < num; ++i) { 212 update(ix++, (TYPE(&)[ENTRY_SIZE])(*entryArray)); 213 entryArray += ENTRY_SIZE; 214 } 215 nEntries -= num; 216 } 217 } 218 219 // Store a single value. 220 // @arg value must be in network byte order. 221 void add(const TYPE& value) { 222 CHECK_LT(mNumValuesInCurrEntry, mElementCapacity); 223 uint32_t nEntries = mTotalNumTableEntries % mElementCapacity; 224 uint32_t nValues = mNumValuesInCurrEntry % ENTRY_SIZE; 225 if (nEntries == 0 && nValues == 0) { 226 mCurrTableEntriesElement = new TYPE[ENTRY_SIZE * mElementCapacity]; 227 CHECK(mCurrTableEntriesElement != NULL); 228 mTableEntryList.push_back(mCurrTableEntriesElement); 229 } 230 231 uint32_t pos = nEntries * ENTRY_SIZE + nValues; 232 mCurrTableEntriesElement[pos] = value; 233 234 ++mNumValuesInCurrEntry; 235 if ((mNumValuesInCurrEntry % ENTRY_SIZE) == 0) { 236 ++mTotalNumTableEntries; 237 mNumValuesInCurrEntry = 0; 238 } 239 } 240 241 // Write out the table entries: 242 // 1. the number of entries goes first 243 // 2. followed by the values in the table enties in order 244 // @arg writer the writer to actual write to the storage 245 void write(MPEG4Writer *writer) const { 246 CHECK_EQ(mNumValuesInCurrEntry % ENTRY_SIZE, 0u); 247 uint32_t nEntries = mTotalNumTableEntries; 248 writer->writeInt32(nEntries); 249 for (typename List<TYPE *>::iterator it = mTableEntryList.begin(); 250 it != mTableEntryList.end(); ++it) { 251 CHECK_GT(nEntries, 0u); 252 if (nEntries >= mElementCapacity) { 253 writer->write(*it, sizeof(TYPE) * ENTRY_SIZE, mElementCapacity); 254 nEntries -= mElementCapacity; 255 } else { 256 writer->write(*it, sizeof(TYPE) * ENTRY_SIZE, nEntries); 257 break; 258 } 259 } 260 } 261 262 // Return the number of entries in the table. 263 uint32_t count() const { return mTotalNumTableEntries; } 264 265 private: 266 uint32_t mElementCapacity; // # entries in an element 267 uint32_t mTotalNumTableEntries; 268 uint32_t mNumValuesInCurrEntry; // up to ENTRY_SIZE 269 TYPE *mCurrTableEntriesElement; 270 mutable List<TYPE *> mTableEntryList; 271 272 DISALLOW_EVIL_CONSTRUCTORS(ListTableEntries); 273 }; 274 275 276 277 MPEG4Writer *mOwner; 278 sp<MetaData> mMeta; 279 sp<MediaSource> mSource; 280 volatile bool mDone; 281 volatile bool mPaused; 282 volatile bool mResumed; 283 volatile bool mStarted; 284 bool mIsAvc; 285 bool mIsHevc; 286 bool mIsAudio; 287 bool mIsVideo; 288 bool mIsHeic; 289 bool mIsMPEG4; 290 bool mGotStartKeyFrame; 291 bool mIsMalformed; 292 int32_t mTrackId; 293 int64_t mTrackDurationUs; 294 int64_t mMaxChunkDurationUs; 295 int64_t mLastDecodingTimeUs; 296 297 int64_t mEstimatedTrackSizeBytes; 298 int64_t mMdatSizeBytes; 299 int32_t mTimeScale; 300 301 pthread_t mThread; 302 303 304 List<MediaBuffer *> mChunkSamples; 305 306 bool mSamplesHaveSameSize; 307 ListTableEntries<uint32_t, 1> *mStszTableEntries; 308 309 ListTableEntries<uint32_t, 1> *mStcoTableEntries; 310 ListTableEntries<off64_t, 1> *mCo64TableEntries; 311 ListTableEntries<uint32_t, 3> *mStscTableEntries; 312 ListTableEntries<uint32_t, 1> *mStssTableEntries; 313 ListTableEntries<uint32_t, 2> *mSttsTableEntries; 314 ListTableEntries<uint32_t, 2> *mCttsTableEntries; 315 316 int64_t mMinCttsOffsetTimeUs; 317 int64_t mMinCttsOffsetTicks; 318 int64_t mMaxCttsOffsetTicks; 319 320 // Save the last 10 frames' timestamp and frame type for debug. 321 struct TimestampDebugHelperEntry { 322 int64_t pts; 323 int64_t dts; 324 std::string frameType; 325 }; 326 327 std::list<TimestampDebugHelperEntry> mTimestampDebugHelper; 328 329 // Sequence parameter set or picture parameter set 330 struct AVCParamSet { 331 AVCParamSet(uint16_t length, const uint8_t *data) 332 : mLength(length), mData(data) {} 333 334 uint16_t mLength; 335 const uint8_t *mData; 336 }; 337 List<AVCParamSet> mSeqParamSets; 338 List<AVCParamSet> mPicParamSets; 339 uint8_t mProfileIdc; 340 uint8_t mProfileCompatible; 341 uint8_t mLevelIdc; 342 343 void *mCodecSpecificData; 344 size_t mCodecSpecificDataSize; 345 bool mGotAllCodecSpecificData; 346 bool mTrackingProgressStatus; 347 348 bool mReachedEOS; 349 int64_t mStartTimestampUs; 350 int64_t mStartTimeRealUs; 351 int64_t mFirstSampleTimeRealUs; 352 int64_t mPreviousTrackTimeUs; 353 int64_t mTrackEveryTimeDurationUs; 354 355 int32_t mRotation; 356 357 Vector<uint16_t> mProperties; 358 Vector<uint16_t> mDimgRefs; 359 int32_t mIsPrimary; 360 int32_t mWidth, mHeight; 361 int32_t mGridWidth, mGridHeight; 362 int32_t mGridRows, mGridCols; 363 size_t mNumTiles, mTileIndex; 364 365 // Update the audio track's drift information. 366 void updateDriftTime(const sp<MetaData>& meta); 367 368 void dumpTimeStamps(); 369 370 int64_t getStartTimeOffsetTimeUs() const; 371 int32_t getStartTimeOffsetScaledTime() const; 372 373 static void *ThreadWrapper(void *me); 374 status_t threadEntry(); 375 376 const uint8_t *parseParamSet( 377 const uint8_t *data, size_t length, int type, size_t *paramSetLen); 378 379 status_t copyCodecSpecificData(const uint8_t *data, size_t size, size_t minLength = 0); 380 381 status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size); 382 status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size); 383 status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size); 384 385 status_t makeHEVCCodecSpecificData(const uint8_t *data, size_t size); 386 status_t copyHEVCCodecSpecificData(const uint8_t *data, size_t size); 387 status_t parseHEVCCodecSpecificData( 388 const uint8_t *data, size_t size, HevcParameterSets ¶mSets); 389 390 // Track authoring progress status 391 void trackProgressStatus(int64_t timeUs, status_t err = OK); 392 void initTrackingProgressStatus(MetaData *params); 393 394 void getCodecSpecificDataFromInputFormatIfPossible(); 395 396 // Determine the track time scale 397 // If it is an audio track, try to use the sampling rate as 398 // the time scale; however, if user chooses the overwrite 399 // value, the user-supplied time scale will be used. 400 void setTimeScale(); 401 402 // Simple validation on the codec specific data 403 status_t checkCodecSpecificData() const; 404 405 void updateTrackSizeEstimate(); 406 void addOneStscTableEntry(size_t chunkId, size_t sampleId); 407 void addOneStssTableEntry(size_t sampleId); 408 409 // Duration is time scale based 410 void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur); 411 void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur); 412 413 bool isTrackMalFormed() const; 414 void sendTrackSummary(bool hasMultipleTracks); 415 416 // Write the boxes 417 void writeStcoBox(bool use32BitOffset); 418 void writeStscBox(); 419 void writeStszBox(); 420 void writeStssBox(); 421 void writeSttsBox(); 422 void writeCttsBox(); 423 void writeD263Box(); 424 void writePaspBox(); 425 void writeAvccBox(); 426 void writeHvccBox(); 427 void writeUrlBox(); 428 void writeDrefBox(); 429 void writeDinfBox(); 430 void writeDamrBox(); 431 void writeMdhdBox(uint32_t now); 432 void writeSmhdBox(); 433 void writeVmhdBox(); 434 void writeNmhdBox(); 435 void writeHdlrBox(); 436 void writeTkhdBox(uint32_t now); 437 void writeColrBox(); 438 void writeMp4aEsdsBox(); 439 void writeMp4vEsdsBox(); 440 void writeAudioFourCCBox(); 441 void writeVideoFourCCBox(); 442 void writeMetadataFourCCBox(); 443 void writeStblBox(bool use32BitOffset); 444 445 Track(const Track &); 446 Track &operator=(const Track &); 447}; 448 449MPEG4Writer::MPEG4Writer(int fd) { 450 initInternal(fd, true /*isFirstSession*/); 451} 452 453MPEG4Writer::~MPEG4Writer() { 454 reset(); 455 456 while (!mTracks.empty()) { 457 List<Track *>::iterator it = mTracks.begin(); 458 delete *it; 459 (*it) = NULL; 460 mTracks.erase(it); 461 } 462 mTracks.clear(); 463 464 if (mNextFd != -1) { 465 close(mNextFd); 466 } 467} 468 469void MPEG4Writer::initInternal(int fd, bool isFirstSession) { 470 ALOGV("initInternal"); 471 mFd = dup(fd); 472 mNextFd = -1; 473 mInitCheck = mFd < 0? NO_INIT: OK; 474 475 mInterleaveDurationUs = 1000000; 476 477 mStartTimestampUs = -1ll; 478 mStartTimeOffsetMs = -1; 479 mPaused = false; 480 mStarted = false; 481 mWriterThreadStarted = false; 482 mSendNotify = false; 483 484 // Reset following variables for all the sessions and they will be 485 // initialized in start(MetaData *param). 486 mIsRealTimeRecording = true; 487 mUse4ByteNalLength = true; 488 mUse32BitOffset = true; 489 mOffset = 0; 490 mMdatOffset = 0; 491 mInMemoryCache = NULL; 492 mInMemoryCacheOffset = 0; 493 mInMemoryCacheSize = 0; 494 mWriteBoxToMemory = false; 495 mFreeBoxOffset = 0; 496 mStreamableFile = false; 497 mTimeScale = -1; 498 mHasFileLevelMeta = false; 499 mHasMoovBox = false; 500 mPrimaryItemId = 0; 501 mAssociationEntryCount = 0; 502 mNumGrids = 0; 503 504 // Following variables only need to be set for the first recording session. 505 // And they will stay the same for all the recording sessions. 506 if (isFirstSession) { 507 mMoovExtraSize = 0; 508 mMetaKeys = new AMessage(); 509 addDeviceMeta(); 510 mLatitudex10000 = 0; 511 mLongitudex10000 = 0; 512 mAreGeoTagsAvailable = false; 513 mSwitchPending = false; 514 mIsFileSizeLimitExplicitlyRequested = false; 515 } 516 517 // Verify mFd is seekable 518 off64_t off = lseek64(mFd, 0, SEEK_SET); 519 if (off < 0) { 520 ALOGE("cannot seek mFd: %s (%d) %lld", strerror(errno), errno, (long long)mFd); 521 release(); 522 } 523 for (List<Track *>::iterator it = mTracks.begin(); 524 it != mTracks.end(); ++it) { 525 (*it)->resetInternal(); 526 } 527} 528 529status_t MPEG4Writer::dump( 530 int fd, const Vector<String16>& args) { 531 const size_t SIZE = 256; 532 char buffer[SIZE]; 533 String8 result; 534 snprintf(buffer, SIZE, " MPEG4Writer %p\n", this); 535 result.append(buffer); 536 snprintf(buffer, SIZE, " mStarted: %s\n", mStarted? "true": "false"); 537 result.append(buffer); 538 ::write(fd, result.string(), result.size()); 539 for (List<Track *>::iterator it = mTracks.begin(); 540 it != mTracks.end(); ++it) { 541 (*it)->dump(fd, args); 542 } 543 return OK; 544} 545 546status_t MPEG4Writer::Track::dump( 547 int fd, const Vector<String16>& /* args */) const { 548 const size_t SIZE = 256; 549 char buffer[SIZE]; 550 String8 result; 551 snprintf(buffer, SIZE, " %s track\n", getTrackType()); 552 result.append(buffer); 553 snprintf(buffer, SIZE, " reached EOS: %s\n", 554 mReachedEOS? "true": "false"); 555 result.append(buffer); 556 snprintf(buffer, SIZE, " frames encoded : %d\n", mStszTableEntries->count()); 557 result.append(buffer); 558 snprintf(buffer, SIZE, " duration encoded : %" PRId64 " us\n", mTrackDurationUs); 559 result.append(buffer); 560 ::write(fd, result.string(), result.size()); 561 return OK; 562} 563 564// static 565const char *MPEG4Writer::Track::getFourCCForMime(const char *mime) { 566 if (mime == NULL) { 567 return NULL; 568 } 569 if (!strncasecmp(mime, "audio/", 6)) { 570 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 571 return "samr"; 572 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 573 return "sawb"; 574 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 575 return "mp4a"; 576 } 577 } else if (!strncasecmp(mime, "video/", 6)) { 578 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 579 return "mp4v"; 580 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 581 return "s263"; 582 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 583 return "avc1"; 584 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { 585 return "hvc1"; 586 } 587 } else if (!strncasecmp(mime, "application/", 12)) { 588 return "mett"; 589 } else if (!strcasecmp(MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, mime)) { 590 return "heic"; 591 } else { 592 ALOGE("Track (%s) other than video/audio/metadata is not supported", mime); 593 } 594 return NULL; 595} 596 597status_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 598 Mutex::Autolock l(mLock); 599 if (mStarted) { 600 ALOGE("Attempt to add source AFTER recording is started"); 601 return UNKNOWN_ERROR; 602 } 603 604 CHECK(source.get() != NULL); 605 606 const char *mime; 607 source->getFormat()->findCString(kKeyMIMEType, &mime); 608 609 if (Track::getFourCCForMime(mime) == NULL) { 610 ALOGE("Unsupported mime '%s'", mime); 611 return ERROR_UNSUPPORTED; 612 } 613 614 // This is a metadata track or the first track of either audio or video 615 // Go ahead to add the track. 616 Track *track = new Track(this, source, 1 + mTracks.size()); 617 mTracks.push_back(track); 618 619 mHasMoovBox |= !track->isHeic(); 620 mHasFileLevelMeta |= track->isHeic(); 621 622 return OK; 623} 624 625status_t MPEG4Writer::startTracks(MetaData *params) { 626 if (mTracks.empty()) { 627 ALOGE("No source added"); 628 return INVALID_OPERATION; 629 } 630 631 for (List<Track *>::iterator it = mTracks.begin(); 632 it != mTracks.end(); ++it) { 633 status_t err = (*it)->start(params); 634 635 if (err != OK) { 636 for (List<Track *>::iterator it2 = mTracks.begin(); 637 it2 != it; ++it2) { 638 (*it2)->stop(); 639 } 640 641 return err; 642 } 643 } 644 return OK; 645} 646 647void MPEG4Writer::addDeviceMeta() { 648 // add device info and estimate space in 'moov' 649 char val[PROPERTY_VALUE_MAX]; 650 size_t n; 651 // meta size is estimated by adding up the following: 652 // - meta header structures, which occur only once (total 66 bytes) 653 // - size for each key, which consists of a fixed header (32 bytes), 654 // plus key length and data length. 655 mMoovExtraSize += 66; 656 if (property_get("ro.build.version.release", val, NULL) 657 && (n = strlen(val)) > 0) { 658 mMetaKeys->setString(kMetaKey_Version, val, n + 1); 659 mMoovExtraSize += sizeof(kMetaKey_Version) + n + 32; 660 } 661 662 if (property_get_bool("media.recorder.show_manufacturer_and_model", false)) { 663 if (property_get("ro.product.manufacturer", val, NULL) 664 && (n = strlen(val)) > 0) { 665 mMetaKeys->setString(kMetaKey_Manufacturer, val, n + 1); 666 mMoovExtraSize += sizeof(kMetaKey_Manufacturer) + n + 32; 667 } 668 if (property_get("ro.product.model", val, NULL) 669 && (n = strlen(val)) > 0) { 670 mMetaKeys->setString(kMetaKey_Model, val, n + 1); 671 mMoovExtraSize += sizeof(kMetaKey_Model) + n + 32; 672 } 673 } 674#ifdef SHOW_MODEL_BUILD 675 if (property_get("ro.build.display.id", val, NULL) 676 && (n = strlen(val)) > 0) { 677 mMetaKeys->setString(kMetaKey_Build, val, n + 1); 678 mMoovExtraSize += sizeof(kMetaKey_Build) + n + 32; 679 } 680#endif 681} 682 683int64_t MPEG4Writer::estimateFileLevelMetaSize() { 684 // base meta size 685 int64_t metaSize = 12 // meta fullbox header 686 + 33 // hdlr box 687 + 14 // pitm box 688 + 16 // iloc box (fixed size portion) 689 + 14 // iinf box (fixed size portion) 690 + 32 // iprp box (fixed size protion) 691 + 8 // idat box (when empty) 692 + 12 // iref box (when empty) 693 ; 694 695 for (List<Track *>::iterator it = mTracks.begin(); 696 it != mTracks.end(); ++it) { 697 if ((*it)->isHeic()) { 698 metaSize += (*it)->getMetaSizeIncrease(); 699 } 700 } 701 702 ALOGV("estimated meta size: %lld", (long long) metaSize); 703 704 // Need at least 8-byte padding at the end, otherwise the left-over 705 // freebox may become malformed 706 return metaSize + 8; 707} 708 709int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 710 // This implementation is highly experimental/heurisitic. 711 // 712 // Statistical analysis shows that metadata usually accounts 713 // for a small portion of the total file size, usually < 0.6%. 714 715 // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2, 716 // where 1MB is the common file size limit for MMS application. 717 // The default MAX _MOOV_BOX_SIZE value is based on about 3 718 // minute video recording with a bit rate about 3 Mbps, because 719 // statistics also show that most of the video captured are going 720 // to be less than 3 minutes. 721 722 // If the estimation is wrong, we will pay the price of wasting 723 // some reserved space. This should not happen so often statistically. 724 static const int32_t factor = mUse32BitOffset? 1: 2; 725 static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024; // 3 KB 726 static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 727 int64_t size = MIN_MOOV_BOX_SIZE; 728 729 // Max file size limit is set 730 if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 731 size = mMaxFileSizeLimitBytes * 6 / 1000; 732 } 733 734 // Max file duration limit is set 735 if (mMaxFileDurationLimitUs != 0) { 736 if (bitRate > 0) { 737 int64_t size2 = 738 ((mMaxFileDurationLimitUs / 1000) * bitRate * 6) / 8000000; 739 if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { 740 // When both file size and duration limits are set, 741 // we use the smaller limit of the two. 742 if (size > size2) { 743 size = size2; 744 } 745 } else { 746 // Only max file duration limit is set 747 size = size2; 748 } 749 } 750 } 751 752 if (size < MIN_MOOV_BOX_SIZE) { 753 size = MIN_MOOV_BOX_SIZE; 754 } 755 756 // Any long duration recording will be probably end up with 757 // non-streamable mp4 file. 758 if (size > MAX_MOOV_BOX_SIZE) { 759 size = MAX_MOOV_BOX_SIZE; 760 } 761 762 // Account for the extra stuff (Geo, meta keys, etc.) 763 size += mMoovExtraSize; 764 765 ALOGI("limits: %" PRId64 "/%" PRId64 " bytes/us, bit rate: %d bps and the" 766 " estimated moov size %" PRId64 " bytes", 767 mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 768 769 int64_t estimatedSize = factor * size; 770 CHECK_GE(estimatedSize, 8); 771 772 return estimatedSize; 773} 774 775status_t MPEG4Writer::start(MetaData *param) { 776 if (mInitCheck != OK) { 777 return UNKNOWN_ERROR; 778 } 779 mStartMeta = param; 780 781 /* 782 * Check mMaxFileSizeLimitBytes at the beginning 783 * since mMaxFileSizeLimitBytes may be implicitly 784 * changed later for 32-bit file offset even if 785 * user does not ask to set it explicitly. 786 */ 787 if (mMaxFileSizeLimitBytes != 0) { 788 mIsFileSizeLimitExplicitlyRequested = true; 789 } 790 791 int32_t use64BitOffset; 792 if (param && 793 param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 794 use64BitOffset) { 795 mUse32BitOffset = false; 796 } 797 798 if (mUse32BitOffset) { 799 // Implicit 32 bit file size limit 800 if (mMaxFileSizeLimitBytes == 0) { 801 mMaxFileSizeLimitBytes = kMax32BitFileSize; 802 } 803 804 // If file size is set to be larger than the 32 bit file 805 // size limit, treat it as an error. 806 if (mMaxFileSizeLimitBytes > kMax32BitFileSize) { 807 ALOGW("32-bit file size limit (%" PRId64 " bytes) too big. " 808 "It is changed to %" PRId64 " bytes", 809 mMaxFileSizeLimitBytes, kMax32BitFileSize); 810 mMaxFileSizeLimitBytes = kMax32BitFileSize; 811 } 812 } 813 814 int32_t use2ByteNalLength; 815 if (param && 816 param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) && 817 use2ByteNalLength) { 818 mUse4ByteNalLength = false; 819 } 820 821 int32_t isRealTimeRecording; 822 if (param && param->findInt32(kKeyRealTimeRecording, &isRealTimeRecording)) { 823 mIsRealTimeRecording = isRealTimeRecording; 824 } 825 826 mStartTimestampUs = -1; 827 828 if (mStarted) { 829 if (mPaused) { 830 mPaused = false; 831 return startTracks(param); 832 } 833 return OK; 834 } 835 836 if (!param || 837 !param->findInt32(kKeyTimeScale, &mTimeScale)) { 838 mTimeScale = 1000; 839 } 840 CHECK_GT(mTimeScale, 0); 841 ALOGV("movie time scale: %d", mTimeScale); 842 843 /* 844 * When the requested file size limit is small, the priority 845 * is to meet the file size limit requirement, rather than 846 * to make the file streamable. mStreamableFile does not tell 847 * whether the actual recorded file is streamable or not. 848 */ 849 mStreamableFile = 850 (mMaxFileSizeLimitBytes != 0 && 851 mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes); 852 853 /* 854 * mWriteBoxToMemory is true if the amount of data in a file-level meta or 855 * moov box is smaller than the reserved free space at the beginning of a 856 * file, AND when the content of the box is constructed. Note that video/ 857 * audio frame data is always written to the file but not in the memory. 858 * 859 * Before stop()/reset() is called, mWriteBoxToMemory is always 860 * false. When reset() is called at the end of a recording session, 861 * file-level meta and/or moov box needs to be constructed. 862 * 863 * 1) Right before the box is constructed, mWriteBoxToMemory to set to 864 * mStreamableFile so that if the file is intended to be streamable, it 865 * is set to true; otherwise, it is set to false. When the value is set 866 * to false, all the content of that box is written immediately to 867 * the end of the file. When the value is set to true, all the 868 * content of that box is written to an in-memory cache, 869 * mInMemoryCache, util the following condition happens. Note 870 * that the size of the in-memory cache is the same as the 871 * reserved free space at the beginning of the file. 872 * 873 * 2) While the data of the box is written to an in-memory 874 * cache, the data size is checked against the reserved space. 875 * If the data size surpasses the reserved space, subsequent box data 876 * could no longer be hold in the in-memory cache. This also 877 * indicates that the reserved space was too small. At this point, 878 * _all_ subsequent box data must be written to the end of the file. 879 * mWriteBoxToMemory must be set to false to direct the write 880 * to the file. 881 * 882 * 3) If the data size in the box is smaller than the reserved 883 * space after the box is completely constructed, the in-memory 884 * cache copy of the box is written to the reserved free space. 885 * mWriteBoxToMemory is always set to false after all boxes that 886 * using the in-memory cache have been constructed. 887 */ 888 mWriteBoxToMemory = false; 889 mInMemoryCache = NULL; 890 mInMemoryCacheOffset = 0; 891 892 893 ALOGV("muxer starting: mHasMoovBox %d, mHasFileLevelMeta %d", 894 mHasMoovBox, mHasFileLevelMeta); 895 896 writeFtypBox(param); 897 898 mFreeBoxOffset = mOffset; 899 900 if (mInMemoryCacheSize == 0) { 901 int32_t bitRate = -1; 902 if (mHasFileLevelMeta) { 903 mInMemoryCacheSize += estimateFileLevelMetaSize(); 904 } 905 if (mHasMoovBox) { 906 if (param) { 907 param->findInt32(kKeyBitRate, &bitRate); 908 } 909 mInMemoryCacheSize += estimateMoovBoxSize(bitRate); 910 } 911 } 912 if (mStreamableFile) { 913 // Reserve a 'free' box only for streamable file 914 lseek64(mFd, mFreeBoxOffset, SEEK_SET); 915 writeInt32(mInMemoryCacheSize); 916 write("free", 4); 917 mMdatOffset = mFreeBoxOffset + mInMemoryCacheSize; 918 } else { 919 mMdatOffset = mOffset; 920 } 921 922 mOffset = mMdatOffset; 923 lseek64(mFd, mMdatOffset, SEEK_SET); 924 if (mUse32BitOffset) { 925 write("????mdat", 8); 926 } else { 927 write("\x00\x00\x00\x01mdat????????", 16); 928 } 929 930 status_t err = startWriterThread(); 931 if (err != OK) { 932 return err; 933 } 934 935 err = startTracks(param); 936 if (err != OK) { 937 return err; 938 } 939 940 mStarted = true; 941 return OK; 942} 943 944bool MPEG4Writer::use32BitFileOffset() const { 945 return mUse32BitOffset; 946} 947 948status_t MPEG4Writer::pause() { 949 ALOGW("MPEG4Writer: pause is not supported"); 950 return ERROR_UNSUPPORTED; 951} 952 953void MPEG4Writer::stopWriterThread() { 954 ALOGD("Stopping writer thread"); 955 if (!mWriterThreadStarted) { 956 return; 957 } 958 959 { 960 Mutex::Autolock autolock(mLock); 961 962 mDone = true; 963 mChunkReadyCondition.signal(); 964 } 965 966 void *dummy; 967 pthread_join(mThread, &dummy); 968 mWriterThreadStarted = false; 969 ALOGD("Writer thread stopped"); 970} 971 972/* 973 * MP4 file standard defines a composition matrix: 974 * | a b u | 975 * | c d v | 976 * | x y w | 977 * 978 * the element in the matrix is stored in the following 979 * order: {a, b, u, c, d, v, x, y, w}, 980 * where a, b, c, d, x, and y is in 16.16 format, while 981 * u, v and w is in 2.30 format. 982 */ 983void MPEG4Writer::writeCompositionMatrix(int degrees) { 984 ALOGV("writeCompositionMatrix"); 985 uint32_t a = 0x00010000; 986 uint32_t b = 0; 987 uint32_t c = 0; 988 uint32_t d = 0x00010000; 989 switch (degrees) { 990 case 0: 991 break; 992 case 90: 993 a = 0; 994 b = 0x00010000; 995 c = 0xFFFF0000; 996 d = 0; 997 break; 998 case 180: 999 a = 0xFFFF0000; 1000 d = 0xFFFF0000; 1001 break; 1002 case 270: 1003 a = 0; 1004 b = 0xFFFF0000; 1005 c = 0x00010000; 1006 d = 0; 1007 break; 1008 default: 1009 CHECK(!"Should never reach this unknown rotation"); 1010 break; 1011 } 1012 1013 writeInt32(a); // a 1014 writeInt32(b); // b 1015 writeInt32(0); // u 1016 writeInt32(c); // c 1017 writeInt32(d); // d 1018 writeInt32(0); // v 1019 writeInt32(0); // x 1020 writeInt32(0); // y 1021 writeInt32(0x40000000); // w 1022} 1023 1024void MPEG4Writer::release() { 1025 close(mFd); 1026 mFd = -1; 1027 mInitCheck = NO_INIT; 1028 mStarted = false; 1029 free(mInMemoryCache); 1030 mInMemoryCache = NULL; 1031} 1032 1033void MPEG4Writer::finishCurrentSession() { 1034 reset(false /* stopSource */); 1035} 1036 1037status_t MPEG4Writer::switchFd() { 1038 ALOGV("switchFd"); 1039 Mutex::Autolock l(mLock); 1040 if (mSwitchPending) { 1041 return OK; 1042 } 1043 1044 if (mNextFd == -1) { 1045 ALOGW("No FileDescripter for next recording"); 1046 return INVALID_OPERATION; 1047 } 1048 1049 mSwitchPending = true; 1050 sp<AMessage> msg = new AMessage(kWhatSwitch, mReflector); 1051 status_t err = msg->post(); 1052 1053 return err; 1054} 1055 1056status_t MPEG4Writer::reset(bool stopSource) { 1057 if (mInitCheck != OK) { 1058 return OK; 1059 } else { 1060 if (!mWriterThreadStarted || 1061 !mStarted) { 1062 if (mWriterThreadStarted) { 1063 stopWriterThread(); 1064 } 1065 release(); 1066 return OK; 1067 } 1068 } 1069 1070 status_t err = OK; 1071 int64_t maxDurationUs = 0; 1072 int64_t minDurationUs = 0x7fffffffffffffffLL; 1073 int32_t nonImageTrackCount = 0; 1074 for (List<Track *>::iterator it = mTracks.begin(); 1075 it != mTracks.end(); ++it) { 1076 status_t status = (*it)->stop(stopSource); 1077 if (err == OK && status != OK) { 1078 err = status; 1079 } 1080 1081 // skip image tracks 1082 if ((*it)->isHeic()) continue; 1083 nonImageTrackCount++; 1084 1085 int64_t durationUs = (*it)->getDurationUs(); 1086 if (durationUs > maxDurationUs) { 1087 maxDurationUs = durationUs; 1088 } 1089 if (durationUs < minDurationUs) { 1090 minDurationUs = durationUs; 1091 } 1092 } 1093 1094 if (nonImageTrackCount > 1) { 1095 ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", 1096 minDurationUs, maxDurationUs); 1097 } 1098 1099 stopWriterThread(); 1100 1101 // Do not write out movie header on error. 1102 if (err != OK) { 1103 release(); 1104 return err; 1105 } 1106 1107 // Fix up the size of the 'mdat' chunk. 1108 if (mUse32BitOffset) { 1109 lseek64(mFd, mMdatOffset, SEEK_SET); 1110 uint32_t size = htonl(static_cast<uint32_t>(mOffset - mMdatOffset)); 1111 ::write(mFd, &size, 4); 1112 } else { 1113 lseek64(mFd, mMdatOffset + 8, SEEK_SET); 1114 uint64_t size = mOffset - mMdatOffset; 1115 size = hton64(size); 1116 ::write(mFd, &size, 8); 1117 } 1118 lseek64(mFd, mOffset, SEEK_SET); 1119 1120 // Construct file-level meta and moov box now 1121 mInMemoryCacheOffset = 0; 1122 mWriteBoxToMemory = mStreamableFile; 1123 if (mWriteBoxToMemory) { 1124 // There is no need to allocate in-memory cache 1125 // if the file is not streamable. 1126 1127 mInMemoryCache = (uint8_t *) malloc(mInMemoryCacheSize); 1128 CHECK(mInMemoryCache != NULL); 1129 } 1130 1131 if (mHasFileLevelMeta) { 1132 writeFileLevelMetaBox(); 1133 if (mWriteBoxToMemory) { 1134 writeCachedBoxToFile("meta"); 1135 } else { 1136 ALOGI("The file meta box is written at the end."); 1137 } 1138 } 1139 1140 if (mHasMoovBox) { 1141 writeMoovBox(maxDurationUs); 1142 // mWriteBoxToMemory could be set to false in 1143 // MPEG4Writer::write() method 1144 if (mWriteBoxToMemory) { 1145 writeCachedBoxToFile("moov"); 1146 } else { 1147 ALOGI("The mp4 file will not be streamable."); 1148 } 1149 } 1150 mWriteBoxToMemory = false; 1151 1152 // Free in-memory cache for box writing 1153 if (mInMemoryCache != NULL) { 1154 free(mInMemoryCache); 1155 mInMemoryCache = NULL; 1156 mInMemoryCacheOffset = 0; 1157 } 1158 1159 CHECK(mBoxes.empty()); 1160 1161 release(); 1162 return err; 1163} 1164 1165/* 1166 * Writes currently cached box into file. 1167 * 1168 * Must be called while mWriteBoxToMemory is true, and will not modify 1169 * mWriteBoxToMemory. After the call, remaining cache size will be 1170 * reduced and buffer offset will be set to the beginning of the cache. 1171 */ 1172void MPEG4Writer::writeCachedBoxToFile(const char *type) { 1173 CHECK(mWriteBoxToMemory); 1174 1175 mWriteBoxToMemory = false; 1176 // Content of the box is saved in the cache, and the in-memory 1177 // box needs to be written to the file in a single shot. 1178 1179 CHECK_LE(mInMemoryCacheOffset + 8, mInMemoryCacheSize); 1180 1181 // Cached box 1182 lseek64(mFd, mFreeBoxOffset, SEEK_SET); 1183 mOffset = mFreeBoxOffset; 1184 write(mInMemoryCache, 1, mInMemoryCacheOffset); 1185 1186 // Free box 1187 lseek64(mFd, mOffset, SEEK_SET); 1188 mFreeBoxOffset = mOffset; 1189 writeInt32(mInMemoryCacheSize - mInMemoryCacheOffset); 1190 write("free", 4); 1191 1192 // Rewind buffering to the beginning, and restore mWriteBoxToMemory flag 1193 mInMemoryCacheSize -= mInMemoryCacheOffset; 1194 mInMemoryCacheOffset = 0; 1195 mWriteBoxToMemory = true; 1196 1197 ALOGV("dumped out %s box, estimated size remaining %lld", 1198 type, (long long)mInMemoryCacheSize); 1199} 1200 1201uint32_t MPEG4Writer::getMpeg4Time() { 1202 time_t now = time(NULL); 1203 // MP4 file uses time counting seconds since midnight, Jan. 1, 1904 1204 // while time function returns Unix epoch values which starts 1205 // at 1970-01-01. Lets add the number of seconds between them 1206 static const uint32_t delta = (66 * 365 + 17) * (24 * 60 * 60); 1207 if (now < 0 || uint32_t(now) > UINT32_MAX - delta) { 1208 return 0; 1209 } 1210 uint32_t mpeg4Time = uint32_t(now) + delta; 1211 return mpeg4Time; 1212} 1213 1214void MPEG4Writer::writeMvhdBox(int64_t durationUs) { 1215 uint32_t now = getMpeg4Time(); 1216 beginBox("mvhd"); 1217 writeInt32(0); // version=0, flags=0 1218 writeInt32(now); // creation time 1219 writeInt32(now); // modification time 1220 writeInt32(mTimeScale); // mvhd timescale 1221 int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6; 1222 writeInt32(duration); 1223 writeInt32(0x10000); // rate: 1.0 1224 writeInt16(0x100); // volume 1225 writeInt16(0); // reserved 1226 writeInt32(0); // reserved 1227 writeInt32(0); // reserved 1228 writeCompositionMatrix(0); // matrix 1229 writeInt32(0); // predefined 1230 writeInt32(0); // predefined 1231 writeInt32(0); // predefined 1232 writeInt32(0); // predefined 1233 writeInt32(0); // predefined 1234 writeInt32(0); // predefined 1235 writeInt32(mTracks.size() + 1); // nextTrackID 1236 endBox(); // mvhd 1237} 1238 1239void MPEG4Writer::writeMoovBox(int64_t durationUs) { 1240 beginBox("moov"); 1241 writeMvhdBox(durationUs); 1242 if (mAreGeoTagsAvailable) { 1243 writeUdtaBox(); 1244 } 1245 writeMoovLevelMetaBox(); 1246 // Loop through all the tracks to get the global time offset if there is 1247 // any ctts table appears in a video track. 1248 int64_t minCttsOffsetTimeUs = kMaxCttsOffsetTimeUs; 1249 for (List<Track *>::iterator it = mTracks.begin(); 1250 it != mTracks.end(); ++it) { 1251 if (!(*it)->isHeic()) { 1252 minCttsOffsetTimeUs = 1253 std::min(minCttsOffsetTimeUs, (*it)->getMinCttsOffsetTimeUs()); 1254 } 1255 } 1256 ALOGI("Ajust the moov start time from %lld us -> %lld us", 1257 (long long)mStartTimestampUs, 1258 (long long)(mStartTimestampUs + minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs)); 1259 // Adjust the global start time. 1260 mStartTimestampUs += minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs; 1261 1262 for (List<Track *>::iterator it = mTracks.begin(); 1263 it != mTracks.end(); ++it) { 1264 if (!(*it)->isHeic()) { 1265 (*it)->writeTrackHeader(mUse32BitOffset); 1266 } 1267 } 1268 endBox(); // moov 1269} 1270 1271void MPEG4Writer::writeFtypBox(MetaData *param) { 1272 beginBox("ftyp"); 1273 1274 int32_t fileType; 1275 if (!param || !param->findInt32(kKeyFileType, &fileType)) { 1276 fileType = OUTPUT_FORMAT_MPEG_4; 1277 } 1278 if (fileType != OUTPUT_FORMAT_MPEG_4 && fileType != OUTPUT_FORMAT_HEIF) { 1279 writeFourcc("3gp4"); 1280 writeInt32(0); 1281 writeFourcc("isom"); 1282 writeFourcc("3gp4"); 1283 } else { 1284 // Only write "heic" as major brand if the client specified HEIF 1285 // AND we indeed receive some image heic tracks. 1286 if (fileType == OUTPUT_FORMAT_HEIF && mHasFileLevelMeta) { 1287 writeFourcc("heic"); 1288 } else { 1289 writeFourcc("mp42"); 1290 } 1291 writeInt32(0); 1292 if (mHasFileLevelMeta) { 1293 writeFourcc("mif1"); 1294 writeFourcc("heic"); 1295 } 1296 if (mHasMoovBox) { 1297 writeFourcc("isom"); 1298 writeFourcc("mp42"); 1299 } 1300 } 1301 1302 endBox(); 1303} 1304 1305static bool isTestModeEnabled() { 1306#if (PROPERTY_VALUE_MAX < 5) 1307#error "PROPERTY_VALUE_MAX must be at least 5" 1308#endif 1309 1310 // Test mode is enabled only if rw.media.record.test system 1311 // property is enabled. 1312 if (property_get_bool("rw.media.record.test", false)) { 1313 return true; 1314 } 1315 return false; 1316} 1317 1318void MPEG4Writer::sendSessionSummary() { 1319 // Send session summary only if test mode is enabled 1320 if (!isTestModeEnabled()) { 1321 return; 1322 } 1323 1324 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 1325 it != mChunkInfos.end(); ++it) { 1326 int trackNum = it->mTrack->getTrackId() << 28; 1327 notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 1328 trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS, 1329 it->mMaxInterChunkDurUs); 1330 } 1331} 1332 1333status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 1334 mInterleaveDurationUs = durationUs; 1335 return OK; 1336} 1337 1338void MPEG4Writer::lock() { 1339 mLock.lock(); 1340} 1341 1342void MPEG4Writer::unlock() { 1343 mLock.unlock(); 1344} 1345 1346off64_t MPEG4Writer::addSample_l( 1347 MediaBuffer *buffer, bool usePrefix, size_t *bytesWritten) { 1348 off64_t old_offset = mOffset; 1349 1350 if (usePrefix) { 1351 addMultipleLengthPrefixedSamples_l(buffer); 1352 } else { 1353 ::write(mFd, 1354 (const uint8_t *)buffer->data() + buffer->range_offset(), 1355 buffer->range_length()); 1356 1357 mOffset += buffer->range_length(); 1358 } 1359 1360 *bytesWritten = mOffset - old_offset; 1361 return old_offset; 1362} 1363 1364static void StripStartcode(MediaBuffer *buffer) { 1365 if (buffer->range_length() < 4) { 1366 return; 1367 } 1368 1369 const uint8_t *ptr = 1370 (const uint8_t *)buffer->data() + buffer->range_offset(); 1371 1372 if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 1373 buffer->set_range( 1374 buffer->range_offset() + 4, buffer->range_length() - 4); 1375 } 1376} 1377 1378void MPEG4Writer::addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer) { 1379 const size_t kExtensionNALSearchRange = 64; // bytes to look for non-VCL NALUs 1380 1381 const uint8_t *dataStart = (const uint8_t *)buffer->data() + buffer->range_offset(); 1382 const uint8_t *currentNalStart = dataStart; 1383 const uint8_t *nextNalStart; 1384 const uint8_t *data = dataStart; 1385 size_t nextNalSize; 1386 size_t searchSize = buffer->range_length() > kExtensionNALSearchRange ? 1387 kExtensionNALSearchRange : buffer->range_length(); 1388 1389 while (getNextNALUnit(&data, &searchSize, &nextNalStart, 1390 &nextNalSize, true) == OK) { 1391 size_t currentNalSize = nextNalStart - currentNalStart - 4 /* strip start-code */; 1392 MediaBuffer *nalBuf = new MediaBuffer((void *)currentNalStart, currentNalSize); 1393 addLengthPrefixedSample_l(nalBuf); 1394 nalBuf->release(); 1395 1396 currentNalStart = nextNalStart; 1397 } 1398 1399 size_t currentNalOffset = currentNalStart - dataStart; 1400 buffer->set_range(buffer->range_offset() + currentNalOffset, 1401 buffer->range_length() - currentNalOffset); 1402 addLengthPrefixedSample_l(buffer); 1403} 1404 1405void MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 1406 size_t length = buffer->range_length(); 1407 1408 if (mUse4ByteNalLength) { 1409 uint8_t x = length >> 24; 1410 ::write(mFd, &x, 1); 1411 x = (length >> 16) & 0xff; 1412 ::write(mFd, &x, 1); 1413 x = (length >> 8) & 0xff; 1414 ::write(mFd, &x, 1); 1415 x = length & 0xff; 1416 ::write(mFd, &x, 1); 1417 1418 ::write(mFd, 1419 (const uint8_t *)buffer->data() + buffer->range_offset(), 1420 length); 1421 1422 mOffset += length + 4; 1423 } else { 1424 CHECK_LT(length, 65536u); 1425 1426 uint8_t x = length >> 8; 1427 ::write(mFd, &x, 1); 1428 x = length & 0xff; 1429 ::write(mFd, &x, 1); 1430 ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length); 1431 mOffset += length + 2; 1432 } 1433} 1434 1435size_t MPEG4Writer::write( 1436 const void *ptr, size_t size, size_t nmemb) { 1437 1438 const size_t bytes = size * nmemb; 1439 if (mWriteBoxToMemory) { 1440 1441 off64_t boxSize = 8 + mInMemoryCacheOffset + bytes; 1442 if (boxSize > mInMemoryCacheSize) { 1443 // The reserved free space at the beginning of the file is not big 1444 // enough. Boxes should be written to the end of the file from now 1445 // on, but not to the in-memory cache. 1446 1447 // We write partial box that is in the memory to the file first. 1448 for (List<off64_t>::iterator it = mBoxes.begin(); 1449 it != mBoxes.end(); ++it) { 1450 (*it) += mOffset; 1451 } 1452 lseek64(mFd, mOffset, SEEK_SET); 1453 ::write(mFd, mInMemoryCache, mInMemoryCacheOffset); 1454 ::write(mFd, ptr, bytes); 1455 mOffset += (bytes + mInMemoryCacheOffset); 1456 1457 // All subsequent boxes will be written to the end of the file. 1458 mWriteBoxToMemory = false; 1459 } else { 1460 memcpy(mInMemoryCache + mInMemoryCacheOffset, ptr, bytes); 1461 mInMemoryCacheOffset += bytes; 1462 } 1463 } else { 1464 ::write(mFd, ptr, size * nmemb); 1465 mOffset += bytes; 1466 } 1467 return bytes; 1468} 1469 1470void MPEG4Writer::beginBox(uint32_t id) { 1471 mBoxes.push_back(mWriteBoxToMemory? 1472 mInMemoryCacheOffset: mOffset); 1473 1474 writeInt32(0); 1475 writeInt32(id); 1476} 1477 1478void MPEG4Writer::beginBox(const char *fourcc) { 1479 CHECK_EQ(strlen(fourcc), 4u); 1480 1481 mBoxes.push_back(mWriteBoxToMemory? 1482 mInMemoryCacheOffset: mOffset); 1483 1484 writeInt32(0); 1485 writeFourcc(fourcc); 1486} 1487 1488void MPEG4Writer::endBox() { 1489 CHECK(!mBoxes.empty()); 1490 1491 off64_t offset = *--mBoxes.end(); 1492 mBoxes.erase(--mBoxes.end()); 1493 1494 if (mWriteBoxToMemory) { 1495 int32_t x = htonl(mInMemoryCacheOffset - offset); 1496 memcpy(mInMemoryCache + offset, &x, 4); 1497 } else { 1498 lseek64(mFd, offset, SEEK_SET); 1499 writeInt32(mOffset - offset); 1500 mOffset -= 4; 1501 lseek64(mFd, mOffset, SEEK_SET); 1502 } 1503} 1504 1505void MPEG4Writer::writeInt8(int8_t x) { 1506 write(&x, 1, 1); 1507} 1508 1509void MPEG4Writer::writeInt16(int16_t x) { 1510 x = htons(x); 1511 write(&x, 1, 2); 1512} 1513 1514void MPEG4Writer::writeInt32(int32_t x) { 1515 x = htonl(x); 1516 write(&x, 1, 4); 1517} 1518 1519void MPEG4Writer::writeInt64(int64_t x) { 1520 x = hton64(x); 1521 write(&x, 1, 8); 1522} 1523 1524void MPEG4Writer::writeCString(const char *s) { 1525 size_t n = strlen(s); 1526 write(s, 1, n + 1); 1527} 1528 1529void MPEG4Writer::writeFourcc(const char *s) { 1530 CHECK_EQ(strlen(s), 4u); 1531 write(s, 1, 4); 1532} 1533 1534 1535// Written in +/-DD.DDDD format 1536void MPEG4Writer::writeLatitude(int degreex10000) { 1537 bool isNegative = (degreex10000 < 0); 1538 char sign = isNegative? '-': '+'; 1539 1540 // Handle the whole part 1541 char str[9]; 1542 int wholePart = degreex10000 / 10000; 1543 if (wholePart == 0) { 1544 snprintf(str, 5, "%c%.2d.", sign, wholePart); 1545 } else { 1546 snprintf(str, 5, "%+.2d.", wholePart); 1547 } 1548 1549 // Handle the fractional part 1550 int fractionalPart = degreex10000 - (wholePart * 10000); 1551 if (fractionalPart < 0) { 1552 fractionalPart = -fractionalPart; 1553 } 1554 snprintf(&str[4], 5, "%.4d", fractionalPart); 1555 1556 // Do not write the null terminator 1557 write(str, 1, 8); 1558} 1559 1560// Written in +/- DDD.DDDD format 1561void MPEG4Writer::writeLongitude(int degreex10000) { 1562 bool isNegative = (degreex10000 < 0); 1563 char sign = isNegative? '-': '+'; 1564 1565 // Handle the whole part 1566 char str[10]; 1567 int wholePart = degreex10000 / 10000; 1568 if (wholePart == 0) { 1569 snprintf(str, 6, "%c%.3d.", sign, wholePart); 1570 } else { 1571 snprintf(str, 6, "%+.3d.", wholePart); 1572 } 1573 1574 // Handle the fractional part 1575 int fractionalPart = degreex10000 - (wholePart * 10000); 1576 if (fractionalPart < 0) { 1577 fractionalPart = -fractionalPart; 1578 } 1579 snprintf(&str[5], 5, "%.4d", fractionalPart); 1580 1581 // Do not write the null terminator 1582 write(str, 1, 9); 1583} 1584 1585/* 1586 * Geodata is stored according to ISO-6709 standard. 1587 * latitudex10000 is latitude in degrees times 10000, and 1588 * longitudex10000 is longitude in degrees times 10000. 1589 * The range for the latitude is in [-90, +90], and 1590 * The range for the longitude is in [-180, +180] 1591 */ 1592status_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) { 1593 // Is latitude or longitude out of range? 1594 if (latitudex10000 < -900000 || latitudex10000 > 900000 || 1595 longitudex10000 < -1800000 || longitudex10000 > 1800000) { 1596 return BAD_VALUE; 1597 } 1598 1599 mLatitudex10000 = latitudex10000; 1600 mLongitudex10000 = longitudex10000; 1601 mAreGeoTagsAvailable = true; 1602 mMoovExtraSize += 30; 1603 return OK; 1604} 1605 1606status_t MPEG4Writer::setCaptureRate(float captureFps) { 1607 if (captureFps <= 0.0f) { 1608 return BAD_VALUE; 1609 } 1610 1611 mMetaKeys->setFloat(kMetaKey_CaptureFps, captureFps); 1612 mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32; 1613 1614 return OK; 1615} 1616 1617status_t MPEG4Writer::setTemporalLayerCount(uint32_t layerCount) { 1618 if (layerCount > 9) { 1619 return BAD_VALUE; 1620 } 1621 1622 if (layerCount > 0) { 1623 mMetaKeys->setInt32(kMetaKey_TemporalLayerCount, layerCount); 1624 mMoovExtraSize += sizeof(kMetaKey_TemporalLayerCount) + 4 + 32; 1625 } 1626 1627 return OK; 1628} 1629 1630void MPEG4Writer::notifyApproachingLimit() { 1631 Mutex::Autolock autolock(mLock); 1632 // Only notify once. 1633 if (mSendNotify) { 1634 return; 1635 } 1636 ALOGW("Recorded file size is approaching limit %" PRId64 "bytes", 1637 mMaxFileSizeLimitBytes); 1638 notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING, 0); 1639 mSendNotify = true; 1640} 1641 1642void MPEG4Writer::write(const void *data, size_t size) { 1643 write(data, 1, size); 1644} 1645 1646bool MPEG4Writer::isFileStreamable() const { 1647 return mStreamableFile; 1648} 1649 1650bool MPEG4Writer::exceedsFileSizeLimit() { 1651 // No limit 1652 if (mMaxFileSizeLimitBytes == 0) { 1653 return false; 1654 } 1655 int64_t nTotalBytesEstimate = static_cast<int64_t>(mInMemoryCacheSize); 1656 for (List<Track *>::iterator it = mTracks.begin(); 1657 it != mTracks.end(); ++it) { 1658 nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 1659 } 1660 1661 if (!mStreamableFile) { 1662 // Add 1024 bytes as error tolerance 1663 return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes; 1664 } 1665 1666 // Be conservative in the estimate: do not exceed 95% of 1667 // the target file limit. For small target file size limit, though, 1668 // this will not help. 1669 return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100); 1670} 1671 1672bool MPEG4Writer::approachingFileSizeLimit() { 1673 // No limit 1674 if (mMaxFileSizeLimitBytes == 0) { 1675 return false; 1676 } 1677 1678 int64_t nTotalBytesEstimate = static_cast<int64_t>(mInMemoryCacheSize); 1679 for (List<Track *>::iterator it = mTracks.begin(); 1680 it != mTracks.end(); ++it) { 1681 nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 1682 } 1683 1684 if (!mStreamableFile) { 1685 // Add 1024 bytes as error tolerance 1686 return nTotalBytesEstimate + 1024 >= (90 * mMaxFileSizeLimitBytes) / 100; 1687 } 1688 1689 return (nTotalBytesEstimate >= (90 * mMaxFileSizeLimitBytes) / 100); 1690} 1691 1692bool MPEG4Writer::exceedsFileDurationLimit() { 1693 // No limit 1694 if (mMaxFileDurationLimitUs == 0) { 1695 return false; 1696 } 1697 1698 for (List<Track *>::iterator it = mTracks.begin(); 1699 it != mTracks.end(); ++it) { 1700 if (!(*it)->isHeic() && (*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 1701 return true; 1702 } 1703 } 1704 return false; 1705} 1706 1707bool MPEG4Writer::reachedEOS() { 1708 bool allDone = true; 1709 for (List<Track *>::iterator it = mTracks.begin(); 1710 it != mTracks.end(); ++it) { 1711 if (!(*it)->reachedEOS()) { 1712 allDone = false; 1713 break; 1714 } 1715 } 1716 1717 return allDone; 1718} 1719 1720void MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 1721 ALOGI("setStartTimestampUs: %" PRId64, timeUs); 1722 CHECK_GE(timeUs, 0ll); 1723 Mutex::Autolock autoLock(mLock); 1724 if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 1725 mStartTimestampUs = timeUs; 1726 ALOGI("Earliest track starting time: %" PRId64, mStartTimestampUs); 1727 } 1728} 1729 1730int64_t MPEG4Writer::getStartTimestampUs() { 1731 Mutex::Autolock autoLock(mLock); 1732 return mStartTimestampUs; 1733} 1734 1735size_t MPEG4Writer::numTracks() { 1736 Mutex::Autolock autolock(mLock); 1737 return mTracks.size(); 1738} 1739 1740//////////////////////////////////////////////////////////////////////////////// 1741 1742MPEG4Writer::Track::Track( 1743 MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId) 1744 : mOwner(owner), 1745 mMeta(source->getFormat()), 1746 mSource(source), 1747 mDone(false), 1748 mPaused(false), 1749 mResumed(false), 1750 mStarted(false), 1751 mGotStartKeyFrame(false), 1752 mIsMalformed(false), 1753 mTrackId(trackId), 1754 mTrackDurationUs(0), 1755 mEstimatedTrackSizeBytes(0), 1756 mSamplesHaveSameSize(true), 1757 mStszTableEntries(new ListTableEntries<uint32_t, 1>(1000)), 1758 mStcoTableEntries(new ListTableEntries<uint32_t, 1>(1000)), 1759 mCo64TableEntries(new ListTableEntries<off64_t, 1>(1000)), 1760 mStscTableEntries(new ListTableEntries<uint32_t, 3>(1000)), 1761 mStssTableEntries(new ListTableEntries<uint32_t, 1>(1000)), 1762 mSttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)), 1763 mCttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)), 1764 mMinCttsOffsetTimeUs(0), 1765 mMinCttsOffsetTicks(0), 1766 mMaxCttsOffsetTicks(0), 1767 mCodecSpecificData(NULL), 1768 mCodecSpecificDataSize(0), 1769 mGotAllCodecSpecificData(false), 1770 mReachedEOS(false), 1771 mStartTimestampUs(-1), 1772 mRotation(0), 1773 mIsPrimary(0), 1774 mWidth(0), 1775 mHeight(0), 1776 mGridWidth(0), 1777 mGridHeight(0), 1778 mGridRows(0), 1779 mGridCols(0), 1780 mNumTiles(1), 1781 mTileIndex(0) { 1782 getCodecSpecificDataFromInputFormatIfPossible(); 1783 1784 const char *mime; 1785 mMeta->findCString(kKeyMIMEType, &mime); 1786 mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 1787 mIsHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC); 1788 mIsAudio = !strncasecmp(mime, "audio/", 6); 1789 mIsVideo = !strncasecmp(mime, "video/", 6); 1790 mIsHeic = !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC); 1791 mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 1792 !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 1793 1794 // store temporal layer count 1795 if (mIsVideo) { 1796 int32_t count; 1797 if (mMeta->findInt32(kKeyTemporalLayerCount, &count) && count > 1) { 1798 mOwner->setTemporalLayerCount(count); 1799 } 1800 } 1801 1802 if (!mIsHeic) { 1803 setTimeScale(); 1804 } else { 1805 CHECK(mMeta->findInt32(kKeyWidth, &mWidth) && (mWidth > 0)); 1806 CHECK(mMeta->findInt32(kKeyHeight, &mHeight) && (mHeight > 0)); 1807 1808 int32_t gridWidth, gridHeight, gridRows, gridCols; 1809 if (mMeta->findInt32(kKeyGridWidth, &gridWidth) && (gridWidth > 0) && 1810 mMeta->findInt32(kKeyGridHeight, &gridHeight) && (gridHeight > 0) && 1811 mMeta->findInt32(kKeyGridRows, &gridRows) && (gridRows > 0) && 1812 mMeta->findInt32(kKeyGridCols, &gridCols) && (gridCols > 0)) { 1813 mGridWidth = gridWidth; 1814 mGridHeight = gridHeight; 1815 mGridRows = gridRows; 1816 mGridCols = gridCols; 1817 mNumTiles = gridRows * gridCols; 1818 } 1819 if (!mMeta->findInt32(kKeyTrackIsDefault, &mIsPrimary)) { 1820 mIsPrimary = false; 1821 } 1822 } 1823} 1824 1825// Clear all the internal states except the CSD data. 1826void MPEG4Writer::Track::resetInternal() { 1827 mDone = false; 1828 mPaused = false; 1829 mResumed = false; 1830 mStarted = false; 1831 mGotStartKeyFrame = false; 1832 mIsMalformed = false; 1833 mTrackDurationUs = 0; 1834 mEstimatedTrackSizeBytes = 0; 1835 mSamplesHaveSameSize = 0; 1836 if (mStszTableEntries != NULL) { 1837 delete mStszTableEntries; 1838 mStszTableEntries = new ListTableEntries<uint32_t, 1>(1000); 1839 } 1840 1841 if (mStcoTableEntries != NULL) { 1842 delete mStcoTableEntries; 1843 mStcoTableEntries = new ListTableEntries<uint32_t, 1>(1000); 1844 } 1845 if (mCo64TableEntries != NULL) { 1846 delete mCo64TableEntries; 1847 mCo64TableEntries = new ListTableEntries<off64_t, 1>(1000); 1848 } 1849 1850 if (mStscTableEntries != NULL) { 1851 delete mStscTableEntries; 1852 mStscTableEntries = new ListTableEntries<uint32_t, 3>(1000); 1853 } 1854 if (mStssTableEntries != NULL) { 1855 delete mStssTableEntries; 1856 mStssTableEntries = new ListTableEntries<uint32_t, 1>(1000); 1857 } 1858 if (mSttsTableEntries != NULL) { 1859 delete mSttsTableEntries; 1860 mSttsTableEntries = new ListTableEntries<uint32_t, 2>(1000); 1861 } 1862 if (mCttsTableEntries != NULL) { 1863 delete mCttsTableEntries; 1864 mCttsTableEntries = new ListTableEntries<uint32_t, 2>(1000); 1865 } 1866 mReachedEOS = false; 1867} 1868 1869void MPEG4Writer::Track::updateTrackSizeEstimate() { 1870 mEstimatedTrackSizeBytes = mMdatSizeBytes; // media data size 1871 1872 if (!isHeic() && !mOwner->isFileStreamable()) { 1873 uint32_t stcoBoxCount = (mOwner->use32BitFileOffset() 1874 ? mStcoTableEntries->count() 1875 : mCo64TableEntries->count()); 1876 int64_t stcoBoxSizeBytes = stcoBoxCount * 4; 1877 int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4); 1878 1879 // Reserved free space is not large enough to hold 1880 // all meta data and thus wasted. 1881 mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 + // stsc box size 1882 mStssTableEntries->count() * 4 + // stss box size 1883 mSttsTableEntries->count() * 8 + // stts box size 1884 mCttsTableEntries->count() * 8 + // ctts box size 1885 stcoBoxSizeBytes + // stco box size 1886 stszBoxSizeBytes; // stsz box size 1887 } 1888} 1889 1890void MPEG4Writer::Track::addOneStscTableEntry( 1891 size_t chunkId, size_t sampleId) { 1892 mStscTableEntries->add(htonl(chunkId)); 1893 mStscTableEntries->add(htonl(sampleId)); 1894 mStscTableEntries->add(htonl(1)); 1895} 1896 1897void MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) { 1898 mStssTableEntries->add(htonl(sampleId)); 1899} 1900 1901void MPEG4Writer::Track::addOneSttsTableEntry( 1902 size_t sampleCount, int32_t duration) { 1903 1904 if (duration == 0) { 1905 ALOGW("0-duration samples found: %zu", sampleCount); 1906 } 1907 mSttsTableEntries->add(htonl(sampleCount)); 1908 mSttsTableEntries->add(htonl(duration)); 1909} 1910 1911void MPEG4Writer::Track::addOneCttsTableEntry( 1912 size_t sampleCount, int32_t duration) { 1913 1914 if (!mIsVideo) { 1915 return; 1916 } 1917 mCttsTableEntries->add(htonl(sampleCount)); 1918 mCttsTableEntries->add(htonl(duration)); 1919} 1920 1921status_t MPEG4Writer::setNextFd(int fd) { 1922 ALOGV("addNextFd"); 1923 Mutex::Autolock l(mLock); 1924 if (mLooper == NULL) { 1925 mReflector = new AHandlerReflector<MPEG4Writer>(this); 1926 mLooper = new ALooper; 1927 mLooper->registerHandler(mReflector); 1928 mLooper->start(); 1929 } 1930 1931 if (mNextFd != -1) { 1932 // No need to set a new FD yet. 1933 return INVALID_OPERATION; 1934 } 1935 mNextFd = fd; 1936 return OK; 1937} 1938 1939void MPEG4Writer::Track::addChunkOffset(off64_t offset) { 1940 CHECK(!mIsHeic); 1941 if (mOwner->use32BitFileOffset()) { 1942 uint32_t value = offset; 1943 mStcoTableEntries->add(htonl(value)); 1944 } else { 1945 mCo64TableEntries->add(hton64(offset)); 1946 } 1947} 1948 1949void MPEG4Writer::Track::addItemOffsetAndSize(off64_t offset, size_t size) { 1950 CHECK(mIsHeic); 1951 1952 if (offset > UINT32_MAX || size > UINT32_MAX) { 1953 ALOGE("offset or size is out of range: %lld, %lld", 1954 (long long) offset, (long long) size); 1955 mIsMalformed = true; 1956 } 1957 if (mIsMalformed) { 1958 return; 1959 } 1960 if (mTileIndex >= mNumTiles) { 1961 ALOGW("Ignoring excess tiles!"); 1962 return; 1963 } 1964 1965 // Rotation angle in HEIF is CCW, framework angle is CW. 1966 int32_t heifRotation = 0; 1967 switch(mRotation) { 1968 case 90: heifRotation = 3; break; 1969 case 180: heifRotation = 2; break; 1970 case 270: heifRotation = 1; break; 1971 default: break; // don't set if invalid 1972 } 1973 1974 bool hasGrid = (mNumTiles > 1); 1975 1976 if (mProperties.empty()) { 1977 mProperties.push_back(mOwner->addProperty_l({ 1978 .type = FOURCC('h', 'v', 'c', 'C'), 1979 .hvcc = ABuffer::CreateAsCopy(mCodecSpecificData, mCodecSpecificDataSize) 1980 })); 1981 1982 mProperties.push_back(mOwner->addProperty_l({ 1983 .type = FOURCC('i', 's', 'p', 'e'), 1984 .width = hasGrid ? mGridWidth : mWidth, 1985 .height = hasGrid ? mGridHeight : mHeight, 1986 })); 1987 1988 if (!hasGrid && heifRotation > 0) { 1989 mProperties.push_back(mOwner->addProperty_l({ 1990 .type = FOURCC('i', 'r', 'o', 't'), 1991 .rotation = heifRotation, 1992 })); 1993 } 1994 } 1995 1996 uint16_t itemId = mOwner->addItem_l({ 1997 .itemType = "hvc1", 1998 .isPrimary = hasGrid ? false : (mIsPrimary != 0), 1999 .isHidden = hasGrid, 2000 .offset = (uint32_t)offset, 2001 .size = (uint32_t)size, 2002 .properties = mProperties, 2003 }); 2004 2005 mTileIndex++; 2006 if (hasGrid) { 2007 mDimgRefs.push_back(itemId); 2008 2009 if (mTileIndex == mNumTiles) { 2010 mProperties.clear(); 2011 mProperties.push_back(mOwner->addProperty_l({ 2012 .type = FOURCC('i', 's', 'p', 'e'), 2013 .width = mWidth, 2014 .height = mHeight, 2015 })); 2016 if (heifRotation > 0) { 2017 mProperties.push_back(mOwner->addProperty_l({ 2018 .type = FOURCC('i', 'r', 'o', 't'), 2019 .rotation = heifRotation, 2020 })); 2021 } 2022 mOwner->addItem_l({ 2023 .itemType = "grid", 2024 .isPrimary = (mIsPrimary != 0), 2025 .isHidden = false, 2026 .rows = (uint32_t)mGridRows, 2027 .cols = (uint32_t)mGridCols, 2028 .width = (uint32_t)mWidth, 2029 .height = (uint32_t)mHeight, 2030 .properties = mProperties, 2031 .dimgRefs = mDimgRefs, 2032 }); 2033 } 2034 } 2035} 2036 2037void MPEG4Writer::Track::setTimeScale() { 2038 ALOGV("setTimeScale"); 2039 // Default time scale 2040 mTimeScale = 90000; 2041 2042 if (mIsAudio) { 2043 // Use the sampling rate as the default time scale for audio track. 2044 int32_t sampleRate; 2045 bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 2046 CHECK(success); 2047 mTimeScale = sampleRate; 2048 } 2049 2050 // If someone would like to overwrite the timescale, use user-supplied value. 2051 int32_t timeScale; 2052 if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 2053 mTimeScale = timeScale; 2054 } 2055 2056 CHECK_GT(mTimeScale, 0); 2057} 2058 2059void MPEG4Writer::onMessageReceived(const sp<AMessage> &msg) { 2060 switch (msg->what()) { 2061 case kWhatSwitch: 2062 { 2063 finishCurrentSession(); 2064 mLock.lock(); 2065 int fd = mNextFd; 2066 mNextFd = -1; 2067 mLock.unlock(); 2068 initInternal(fd, false /*isFirstSession*/); 2069 start(mStartMeta.get()); 2070 mSwitchPending = false; 2071 notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED, 0); 2072 break; 2073 } 2074 default: 2075 TRESPASS(); 2076 } 2077} 2078 2079void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 2080 const char *mime; 2081 2082 CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 2083 2084 uint32_t type; 2085 const void *data = NULL; 2086 size_t size = 0; 2087 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 2088 mMeta->findData(kKeyAVCC, &type, &data, &size); 2089 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) || 2090 !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) { 2091 mMeta->findData(kKeyHVCC, &type, &data, &size); 2092 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 2093 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 2094 if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 2095 ESDS esds(data, size); 2096 if (esds.getCodecSpecificInfo(&data, &size) == OK && 2097 data != NULL && 2098 copyCodecSpecificData((uint8_t*)data, size) == OK) { 2099 mGotAllCodecSpecificData = true; 2100 } 2101 return; 2102 } 2103 } 2104 if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) { 2105 mGotAllCodecSpecificData = true; 2106 } 2107} 2108 2109MPEG4Writer::Track::~Track() { 2110 stop(); 2111 2112 delete mStszTableEntries; 2113 delete mStcoTableEntries; 2114 delete mCo64TableEntries; 2115 delete mStscTableEntries; 2116 delete mSttsTableEntries; 2117 delete mStssTableEntries; 2118 delete mCttsTableEntries; 2119 2120 mStszTableEntries = NULL; 2121 mStcoTableEntries = NULL; 2122 mCo64TableEntries = NULL; 2123 mStscTableEntries = NULL; 2124 mSttsTableEntries = NULL; 2125 mStssTableEntries = NULL; 2126 mCttsTableEntries = NULL; 2127 2128 if (mCodecSpecificData != NULL) { 2129 free(mCodecSpecificData); 2130 mCodecSpecificData = NULL; 2131 } 2132} 2133 2134void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 2135 ALOGV("initTrackingProgressStatus"); 2136 mPreviousTrackTimeUs = -1; 2137 mTrackingProgressStatus = false; 2138 mTrackEveryTimeDurationUs = 0; 2139 { 2140 int64_t timeUs; 2141 if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 2142 ALOGV("Receive request to track progress status for every %" PRId64 " us", timeUs); 2143 mTrackEveryTimeDurationUs = timeUs; 2144 mTrackingProgressStatus = true; 2145 } 2146 } 2147} 2148 2149// static 2150void *MPEG4Writer::ThreadWrapper(void *me) { 2151 ALOGV("ThreadWrapper: %p", me); 2152 MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 2153 writer->threadFunc(); 2154 return NULL; 2155} 2156 2157void MPEG4Writer::bufferChunk(const Chunk& chunk) { 2158 ALOGV("bufferChunk: %p", chunk.mTrack); 2159 Mutex::Autolock autolock(mLock); 2160 CHECK_EQ(mDone, false); 2161 2162 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 2163 it != mChunkInfos.end(); ++it) { 2164 2165 if (chunk.mTrack == it->mTrack) { // Found owner 2166 it->mChunks.push_back(chunk); 2167 mChunkReadyCondition.signal(); 2168 return; 2169 } 2170 } 2171 2172 CHECK(!"Received a chunk for a unknown track"); 2173} 2174 2175void MPEG4Writer::writeChunkToFile(Chunk* chunk) { 2176 ALOGV("writeChunkToFile: %" PRId64 " from %s track", 2177 chunk->mTimeStampUs, chunk->mTrack->getTrackType()); 2178 2179 int32_t isFirstSample = true; 2180 bool usePrefix = chunk->mTrack->usePrefix(); 2181 while (!chunk->mSamples.empty()) { 2182 List<MediaBuffer *>::iterator it = chunk->mSamples.begin(); 2183 2184 size_t bytesWritten; 2185 off64_t offset = addSample_l(*it, usePrefix, &bytesWritten); 2186 2187 if (chunk->mTrack->isHeic()) { 2188 chunk->mTrack->addItemOffsetAndSize(offset, bytesWritten); 2189 } else if (isFirstSample) { 2190 chunk->mTrack->addChunkOffset(offset); 2191 isFirstSample = false; 2192 } 2193 2194 (*it)->release(); 2195 (*it) = NULL; 2196 chunk->mSamples.erase(it); 2197 } 2198 chunk->mSamples.clear(); 2199} 2200 2201void MPEG4Writer::writeAllChunks() { 2202 ALOGV("writeAllChunks"); 2203 size_t outstandingChunks = 0; 2204 Chunk chunk; 2205 while (findChunkToWrite(&chunk)) { 2206 writeChunkToFile(&chunk); 2207 ++outstandingChunks; 2208 } 2209 2210 sendSessionSummary(); 2211 2212 mChunkInfos.clear(); 2213 ALOGD("%zu chunks are written in the last batch", outstandingChunks); 2214} 2215 2216bool MPEG4Writer::findChunkToWrite(Chunk *chunk) { 2217 ALOGV("findChunkToWrite"); 2218 2219 int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 2220 Track *track = NULL; 2221 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 2222 it != mChunkInfos.end(); ++it) { 2223 if (!it->mChunks.empty()) { 2224 List<Chunk>::iterator chunkIt = it->mChunks.begin(); 2225 if (chunkIt->mTimeStampUs < minTimestampUs) { 2226 minTimestampUs = chunkIt->mTimeStampUs; 2227 track = it->mTrack; 2228 } 2229 } 2230 } 2231 2232 if (track == NULL) { 2233 ALOGV("Nothing to be written after all"); 2234 return false; 2235 } 2236 2237 if (mIsFirstChunk) { 2238 mIsFirstChunk = false; 2239 } 2240 2241 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 2242 it != mChunkInfos.end(); ++it) { 2243 if (it->mTrack == track) { 2244 *chunk = *(it->mChunks.begin()); 2245 it->mChunks.erase(it->mChunks.begin()); 2246 CHECK_EQ(chunk->mTrack, track); 2247 2248 int64_t interChunkTimeUs = 2249 chunk->mTimeStampUs - it->mPrevChunkTimestampUs; 2250 if (interChunkTimeUs > it->mPrevChunkTimestampUs) { 2251 it->mMaxInterChunkDurUs = interChunkTimeUs; 2252 } 2253 2254 return true; 2255 } 2256 } 2257 2258 return false; 2259} 2260 2261void MPEG4Writer::threadFunc() { 2262 ALOGV("threadFunc"); 2263 2264 prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0); 2265 2266 Mutex::Autolock autoLock(mLock); 2267 while (!mDone) { 2268 Chunk chunk; 2269 bool chunkFound = false; 2270 2271 while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) { 2272 mChunkReadyCondition.wait(mLock); 2273 } 2274 2275 // In real time recording mode, write without holding the lock in order 2276 // to reduce the blocking time for media track threads. 2277 // Otherwise, hold the lock until the existing chunks get written to the 2278 // file. 2279 if (chunkFound) { 2280 if (mIsRealTimeRecording) { 2281 mLock.unlock(); 2282 } 2283 writeChunkToFile(&chunk); 2284 if (mIsRealTimeRecording) { 2285 mLock.lock(); 2286 } 2287 } 2288 } 2289 2290 writeAllChunks(); 2291} 2292 2293status_t MPEG4Writer::startWriterThread() { 2294 ALOGV("startWriterThread"); 2295 2296 mDone = false; 2297 mIsFirstChunk = true; 2298 mDriftTimeUs = 0; 2299 for (List<Track *>::iterator it = mTracks.begin(); 2300 it != mTracks.end(); ++it) { 2301 ChunkInfo info; 2302 info.mTrack = *it; 2303 info.mPrevChunkTimestampUs = 0; 2304 info.mMaxInterChunkDurUs = 0; 2305 mChunkInfos.push_back(info); 2306 } 2307 2308 pthread_attr_t attr; 2309 pthread_attr_init(&attr); 2310 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 2311 pthread_create(&mThread, &attr, ThreadWrapper, this); 2312 pthread_attr_destroy(&attr); 2313 mWriterThreadStarted = true; 2314 return OK; 2315} 2316 2317 2318status_t MPEG4Writer::Track::start(MetaData *params) { 2319 if (!mDone && mPaused) { 2320 mPaused = false; 2321 mResumed = true; 2322 return OK; 2323 } 2324 2325 int64_t startTimeUs; 2326 if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 2327 startTimeUs = 0; 2328 } 2329 mStartTimeRealUs = startTimeUs; 2330 2331 int32_t rotationDegrees; 2332 if ((mIsVideo || mIsHeic) && params && 2333 params->findInt32(kKeyRotation, &rotationDegrees)) { 2334 mRotation = rotationDegrees; 2335 } 2336 2337 initTrackingProgressStatus(params); 2338 2339 sp<MetaData> meta = new MetaData; 2340 if (mOwner->isRealTimeRecording() && mOwner->numTracks() > 1) { 2341 /* 2342 * This extra delay of accepting incoming audio/video signals 2343 * helps to align a/v start time at the beginning of a recording 2344 * session, and it also helps eliminate the "recording" sound for 2345 * camcorder applications. 2346 * 2347 * If client does not set the start time offset, we fall back to 2348 * use the default initial delay value. 2349 */ 2350 int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 2351 if (startTimeOffsetUs < 0) { // Start time offset was not set 2352 startTimeOffsetUs = kInitialDelayTimeUs; 2353 } 2354 startTimeUs += startTimeOffsetUs; 2355 ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs); 2356 } 2357 2358 meta->setInt64(kKeyTime, startTimeUs); 2359 2360 status_t err = mSource->start(meta.get()); 2361 if (err != OK) { 2362 mDone = mReachedEOS = true; 2363 return err; 2364 } 2365 2366 pthread_attr_t attr; 2367 pthread_attr_init(&attr); 2368 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 2369 2370 mDone = false; 2371 mStarted = true; 2372 mTrackDurationUs = 0; 2373 mReachedEOS = false; 2374 mEstimatedTrackSizeBytes = 0; 2375 mMdatSizeBytes = 0; 2376 mMaxChunkDurationUs = 0; 2377 mLastDecodingTimeUs = -1; 2378 2379 pthread_create(&mThread, &attr, ThreadWrapper, this); 2380 pthread_attr_destroy(&attr); 2381 2382 return OK; 2383} 2384 2385status_t MPEG4Writer::Track::pause() { 2386 mPaused = true; 2387 return OK; 2388} 2389 2390status_t MPEG4Writer::Track::stop(bool stopSource) { 2391 ALOGD("%s track stopping. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop"); 2392 if (!mStarted) { 2393 ALOGE("Stop() called but track is not started"); 2394 return ERROR_END_OF_STREAM; 2395 } 2396 2397 if (mDone) { 2398 return OK; 2399 } 2400 2401 if (stopSource) { 2402 ALOGD("%s track source stopping", getTrackType()); 2403 mSource->stop(); 2404 ALOGD("%s track source stopped", getTrackType()); 2405 } 2406 2407 // Set mDone to be true after sucessfully stop mSource as mSource may be still outputting 2408 // buffers to the writer. 2409 mDone = true; 2410 2411 void *dummy; 2412 pthread_join(mThread, &dummy); 2413 status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); 2414 2415 ALOGD("%s track stopped. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop"); 2416 return err; 2417} 2418 2419bool MPEG4Writer::Track::reachedEOS() { 2420 return mReachedEOS; 2421} 2422 2423// static 2424void *MPEG4Writer::Track::ThreadWrapper(void *me) { 2425 Track *track = static_cast<Track *>(me); 2426 2427 status_t err = track->threadEntry(); 2428 return (void *)(uintptr_t)err; 2429} 2430 2431static void getNalUnitType(uint8_t byte, uint8_t* type) { 2432 ALOGV("getNalUnitType: %d", byte); 2433 2434 // nal_unit_type: 5-bit unsigned integer 2435 *type = (byte & 0x1F); 2436} 2437 2438const uint8_t *MPEG4Writer::Track::parseParamSet( 2439 const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 2440 2441 ALOGV("parseParamSet"); 2442 CHECK(type == kNalUnitTypeSeqParamSet || 2443 type == kNalUnitTypePicParamSet); 2444 2445 const uint8_t *nextStartCode = findNextNalStartCode(data, length); 2446 *paramSetLen = nextStartCode - data; 2447 if (*paramSetLen == 0) { 2448 ALOGE("Param set is malformed, since its length is 0"); 2449 return NULL; 2450 } 2451 2452 AVCParamSet paramSet(*paramSetLen, data); 2453 if (type == kNalUnitTypeSeqParamSet) { 2454 if (*paramSetLen < 4) { 2455 ALOGE("Seq parameter set malformed"); 2456 return NULL; 2457 } 2458 if (mSeqParamSets.empty()) { 2459 mProfileIdc = data[1]; 2460 mProfileCompatible = data[2]; 2461 mLevelIdc = data[3]; 2462 } else { 2463 if (mProfileIdc != data[1] || 2464 mProfileCompatible != data[2] || 2465 mLevelIdc != data[3]) { 2466 // COULD DO: set profile/level to the lowest required to support all SPSs 2467 ALOGE("Inconsistent profile/level found in seq parameter sets"); 2468 return NULL; 2469 } 2470 } 2471 mSeqParamSets.push_back(paramSet); 2472 } else { 2473 mPicParamSets.push_back(paramSet); 2474 } 2475 return nextStartCode; 2476} 2477 2478status_t MPEG4Writer::Track::copyAVCCodecSpecificData( 2479 const uint8_t *data, size_t size) { 2480 ALOGV("copyAVCCodecSpecificData"); 2481 2482 // 2 bytes for each of the parameter set length field 2483 // plus the 7 bytes for the header 2484 return copyCodecSpecificData(data, size, 4 + 7); 2485} 2486 2487status_t MPEG4Writer::Track::copyHEVCCodecSpecificData( 2488 const uint8_t *data, size_t size) { 2489 ALOGV("copyHEVCCodecSpecificData"); 2490 2491 // Min length of HEVC CSD is 23. (ISO/IEC 14496-15:2014 Chapter 8.3.3.1.2) 2492 return copyCodecSpecificData(data, size, 23); 2493} 2494 2495status_t MPEG4Writer::Track::copyCodecSpecificData( 2496 const uint8_t *data, size_t size, size_t minLength) { 2497 if (size < minLength) { 2498 ALOGE("Codec specific data length too short: %zu", size); 2499 return ERROR_MALFORMED; 2500 } 2501 2502 mCodecSpecificData = malloc(size); 2503 if (mCodecSpecificData == NULL) { 2504 ALOGE("Failed allocating codec specific data"); 2505 return NO_MEMORY; 2506 } 2507 mCodecSpecificDataSize = size; 2508 memcpy(mCodecSpecificData, data, size); 2509 return OK; 2510} 2511 2512status_t MPEG4Writer::Track::parseAVCCodecSpecificData( 2513 const uint8_t *data, size_t size) { 2514 2515 ALOGV("parseAVCCodecSpecificData"); 2516 // Data starts with a start code. 2517 // SPS and PPS are separated with start codes. 2518 // Also, SPS must come before PPS 2519 uint8_t type = kNalUnitTypeSeqParamSet; 2520 bool gotSps = false; 2521 bool gotPps = false; 2522 const uint8_t *tmp = data; 2523 const uint8_t *nextStartCode = data; 2524 size_t bytesLeft = size; 2525 size_t paramSetLen = 0; 2526 mCodecSpecificDataSize = 0; 2527 while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 2528 getNalUnitType(*(tmp + 4), &type); 2529 if (type == kNalUnitTypeSeqParamSet) { 2530 if (gotPps) { 2531 ALOGE("SPS must come before PPS"); 2532 return ERROR_MALFORMED; 2533 } 2534 if (!gotSps) { 2535 gotSps = true; 2536 } 2537 nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 2538 } else if (type == kNalUnitTypePicParamSet) { 2539 if (!gotSps) { 2540 ALOGE("SPS must come before PPS"); 2541 return ERROR_MALFORMED; 2542 } 2543 if (!gotPps) { 2544 gotPps = true; 2545 } 2546 nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 2547 } else { 2548 ALOGE("Only SPS and PPS Nal units are expected"); 2549 return ERROR_MALFORMED; 2550 } 2551 2552 if (nextStartCode == NULL) { 2553 return ERROR_MALFORMED; 2554 } 2555 2556 // Move on to find the next parameter set 2557 bytesLeft -= nextStartCode - tmp; 2558 tmp = nextStartCode; 2559 mCodecSpecificDataSize += (2 + paramSetLen); 2560 } 2561 2562 { 2563 // Check on the number of seq parameter sets 2564 size_t nSeqParamSets = mSeqParamSets.size(); 2565 if (nSeqParamSets == 0) { 2566 ALOGE("Cound not find sequence parameter set"); 2567 return ERROR_MALFORMED; 2568 } 2569 2570 if (nSeqParamSets > 0x1F) { 2571 ALOGE("Too many seq parameter sets (%zu) found", nSeqParamSets); 2572 return ERROR_MALFORMED; 2573 } 2574 } 2575 2576 { 2577 // Check on the number of pic parameter sets 2578 size_t nPicParamSets = mPicParamSets.size(); 2579 if (nPicParamSets == 0) { 2580 ALOGE("Cound not find picture parameter set"); 2581 return ERROR_MALFORMED; 2582 } 2583 if (nPicParamSets > 0xFF) { 2584 ALOGE("Too many pic parameter sets (%zd) found", nPicParamSets); 2585 return ERROR_MALFORMED; 2586 } 2587 } 2588// FIXME: 2589// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above 2590// and remove #if 0 2591#if 0 2592 { 2593 // Check on the profiles 2594 // These profiles requires additional parameter set extensions 2595 if (mProfileIdc == 100 || mProfileIdc == 110 || 2596 mProfileIdc == 122 || mProfileIdc == 144) { 2597 ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 2598 return BAD_VALUE; 2599 } 2600 } 2601#endif 2602 return OK; 2603} 2604 2605status_t MPEG4Writer::Track::makeAVCCodecSpecificData( 2606 const uint8_t *data, size_t size) { 2607 2608 if (mCodecSpecificData != NULL) { 2609 ALOGE("Already have codec specific data"); 2610 return ERROR_MALFORMED; 2611 } 2612 2613 if (size < 4) { 2614 ALOGE("Codec specific data length too short: %zu", size); 2615 return ERROR_MALFORMED; 2616 } 2617 2618 // Data is in the form of AVCCodecSpecificData 2619 if (memcmp("\x00\x00\x00\x01", data, 4)) { 2620 return copyAVCCodecSpecificData(data, size); 2621 } 2622 2623 if (parseAVCCodecSpecificData(data, size) != OK) { 2624 return ERROR_MALFORMED; 2625 } 2626 2627 // ISO 14496-15: AVC file format 2628 mCodecSpecificDataSize += 7; // 7 more bytes in the header 2629 mCodecSpecificData = malloc(mCodecSpecificDataSize); 2630 if (mCodecSpecificData == NULL) { 2631 mCodecSpecificDataSize = 0; 2632 ALOGE("Failed allocating codec specific data"); 2633 return NO_MEMORY; 2634 } 2635 uint8_t *header = (uint8_t *)mCodecSpecificData; 2636 header[0] = 1; // version 2637 header[1] = mProfileIdc; // profile indication 2638 header[2] = mProfileCompatible; // profile compatibility 2639 header[3] = mLevelIdc; 2640 2641 // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 2642 if (mOwner->useNalLengthFour()) { 2643 header[4] = 0xfc | 3; // length size == 4 bytes 2644 } else { 2645 header[4] = 0xfc | 1; // length size == 2 bytes 2646 } 2647 2648 // 3-bit '111' followed by 5-bit numSequenceParameterSets 2649 int nSequenceParamSets = mSeqParamSets.size(); 2650 header[5] = 0xe0 | nSequenceParamSets; 2651 header += 6; 2652 for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 2653 it != mSeqParamSets.end(); ++it) { 2654 // 16-bit sequence parameter set length 2655 uint16_t seqParamSetLength = it->mLength; 2656 header[0] = seqParamSetLength >> 8; 2657 header[1] = seqParamSetLength & 0xff; 2658 2659 // SPS NAL unit (sequence parameter length bytes) 2660 memcpy(&header[2], it->mData, seqParamSetLength); 2661 header += (2 + seqParamSetLength); 2662 } 2663 2664 // 8-bit nPictureParameterSets 2665 int nPictureParamSets = mPicParamSets.size(); 2666 header[0] = nPictureParamSets; 2667 header += 1; 2668 for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 2669 it != mPicParamSets.end(); ++it) { 2670 // 16-bit picture parameter set length 2671 uint16_t picParamSetLength = it->mLength; 2672 header[0] = picParamSetLength >> 8; 2673 header[1] = picParamSetLength & 0xff; 2674 2675 // PPS Nal unit (picture parameter set length bytes) 2676 memcpy(&header[2], it->mData, picParamSetLength); 2677 header += (2 + picParamSetLength); 2678 } 2679 2680 return OK; 2681} 2682 2683 2684status_t MPEG4Writer::Track::parseHEVCCodecSpecificData( 2685 const uint8_t *data, size_t size, HevcParameterSets ¶mSets) { 2686 2687 ALOGV("parseHEVCCodecSpecificData"); 2688 const uint8_t *tmp = data; 2689 const uint8_t *nextStartCode = data; 2690 size_t bytesLeft = size; 2691 while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 2692 nextStartCode = findNextNalStartCode(tmp + 4, bytesLeft - 4); 2693 status_t err = paramSets.addNalUnit(tmp + 4, (nextStartCode - tmp) - 4); 2694 if (err != OK) { 2695 return ERROR_MALFORMED; 2696 } 2697 2698 // Move on to find the next parameter set 2699 bytesLeft -= nextStartCode - tmp; 2700 tmp = nextStartCode; 2701 } 2702 2703 size_t csdSize = 23; 2704 const size_t numNalUnits = paramSets.getNumNalUnits(); 2705 for (size_t i = 0; i < ARRAY_SIZE(kMandatoryHevcNalUnitTypes); ++i) { 2706 int type = kMandatoryHevcNalUnitTypes[i]; 2707 size_t numParamSets = paramSets.getNumNalUnitsOfType(type); 2708 if (numParamSets == 0) { 2709 ALOGE("Cound not find NAL unit of type %d", type); 2710 return ERROR_MALFORMED; 2711 } 2712 } 2713 for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) { 2714 int type = kHevcNalUnitTypes[i]; 2715 size_t numParamSets = paramSets.getNumNalUnitsOfType(type); 2716 if (numParamSets > 0xffff) { 2717 ALOGE("Too many seq parameter sets (%zu) found", numParamSets); 2718 return ERROR_MALFORMED; 2719 } 2720 csdSize += 3; 2721 for (size_t j = 0; j < numNalUnits; ++j) { 2722 if (paramSets.getType(j) != type) { 2723 continue; 2724 } 2725 csdSize += 2 + paramSets.getSize(j); 2726 } 2727 } 2728 mCodecSpecificDataSize = csdSize; 2729 return OK; 2730} 2731 2732status_t MPEG4Writer::Track::makeHEVCCodecSpecificData( 2733 const uint8_t *data, size_t size) { 2734 2735 if (mCodecSpecificData != NULL) { 2736 ALOGE("Already have codec specific data"); 2737 return ERROR_MALFORMED; 2738 } 2739 2740 if (size < 4) { 2741 ALOGE("Codec specific data length too short: %zu", size); 2742 return ERROR_MALFORMED; 2743 } 2744 2745 // Data is in the form of HEVCCodecSpecificData 2746 if (memcmp("\x00\x00\x00\x01", data, 4)) { 2747 return copyHEVCCodecSpecificData(data, size); 2748 } 2749 2750 HevcParameterSets paramSets; 2751 if (parseHEVCCodecSpecificData(data, size, paramSets) != OK) { 2752 ALOGE("failed parsing codec specific data"); 2753 return ERROR_MALFORMED; 2754 } 2755 2756 mCodecSpecificData = malloc(mCodecSpecificDataSize); 2757 if (mCodecSpecificData == NULL) { 2758 mCodecSpecificDataSize = 0; 2759 ALOGE("Failed allocating codec specific data"); 2760 return NO_MEMORY; 2761 } 2762 status_t err = paramSets.makeHvcc((uint8_t *)mCodecSpecificData, 2763 &mCodecSpecificDataSize, mOwner->useNalLengthFour() ? 4 : 2); 2764 if (err != OK) { 2765 ALOGE("failed constructing HVCC atom"); 2766 return err; 2767 } 2768 2769 return OK; 2770} 2771 2772/* 2773 * Updates the drift time from the audio track so that 2774 * the video track can get the updated drift time information 2775 * from the file writer. The fluctuation of the drift time of the audio 2776 * encoding path is smoothed out with a simple filter by giving a larger 2777 * weight to more recently drift time. The filter coefficients, 0.5 and 0.5, 2778 * are heuristically determined. 2779 */ 2780void MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) { 2781 int64_t driftTimeUs = 0; 2782 if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) { 2783 int64_t prevDriftTimeUs = mOwner->getDriftTimeUs(); 2784 int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1; 2785 mOwner->setDriftTimeUs(timeUs); 2786 } 2787} 2788 2789void MPEG4Writer::Track::dumpTimeStamps() { 2790 ALOGE("Dumping %s track's last 10 frames timestamp and frame type ", getTrackType()); 2791 std::string timeStampString; 2792 for (std::list<TimestampDebugHelperEntry>::iterator entry = mTimestampDebugHelper.begin(); 2793 entry != mTimestampDebugHelper.end(); ++entry) { 2794 timeStampString += "(" + std::to_string(entry->pts)+ 2795 "us, " + std::to_string(entry->dts) + "us " + entry->frameType + ") "; 2796 } 2797 ALOGE("%s", timeStampString.c_str()); 2798} 2799 2800status_t MPEG4Writer::Track::threadEntry() { 2801 int32_t count = 0; 2802 const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 2803 const bool hasMultipleTracks = (mOwner->numTracks() > 1); 2804 int64_t chunkTimestampUs = 0; 2805 int32_t nChunks = 0; 2806 int32_t nActualFrames = 0; // frames containing non-CSD data (non-0 length) 2807 int32_t nZeroLengthFrames = 0; 2808 int64_t lastTimestampUs = 0; // Previous sample time stamp 2809 int64_t lastDurationUs = 0; // Between the previous two samples 2810 int64_t currDurationTicks = 0; // Timescale based ticks 2811 int64_t lastDurationTicks = 0; // Timescale based ticks 2812 int32_t sampleCount = 1; // Sample count in the current stts table entry 2813 uint32_t previousSampleSize = 0; // Size of the previous sample 2814 int64_t previousPausedDurationUs = 0; 2815 int64_t timestampUs = 0; 2816 int64_t cttsOffsetTimeUs = 0; 2817 int64_t currCttsOffsetTimeTicks = 0; // Timescale based ticks 2818 int64_t lastCttsOffsetTimeTicks = -1; // Timescale based ticks 2819 int32_t cttsSampleCount = 0; // Sample count in the current ctts table entry 2820 uint32_t lastSamplesPerChunk = 0; 2821 2822 if (mIsAudio) { 2823 prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0); 2824 } else if (mIsVideo) { 2825 prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0); 2826 } else { 2827 prctl(PR_SET_NAME, (unsigned long)"MetadataTrackEncoding", 0, 0, 0); 2828 } 2829 2830 if (mOwner->isRealTimeRecording()) { 2831 androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO); 2832 } 2833 2834 sp<MetaData> meta_data; 2835 2836 status_t err = OK; 2837 MediaBufferBase *buffer; 2838 const char *trackName = getTrackType(); 2839 while (!mDone && (err = mSource->read(&buffer)) == OK) { 2840 if (buffer->range_length() == 0) { 2841 buffer->release(); 2842 buffer = NULL; 2843 ++nZeroLengthFrames; 2844 continue; 2845 } 2846 2847 // If the codec specific data has not been received yet, delay pause. 2848 // After the codec specific data is received, discard what we received 2849 // when the track is to be paused. 2850 if (mPaused && !mResumed) { 2851 buffer->release(); 2852 buffer = NULL; 2853 continue; 2854 } 2855 2856 ++count; 2857 2858 int32_t isCodecConfig; 2859 if (buffer->meta_data().findInt32(kKeyIsCodecConfig, &isCodecConfig) 2860 && isCodecConfig) { 2861 // if config format (at track addition) already had CSD, keep that 2862 // UNLESS we have not received any frames yet. 2863 // TODO: for now the entire CSD has to come in one frame for encoders, even though 2864 // they need to be spread out for decoders. 2865 if (mGotAllCodecSpecificData && nActualFrames > 0) { 2866 ALOGI("ignoring additional CSD for video track after first frame"); 2867 } else { 2868 mMeta = mSource->getFormat(); // get output format after format change 2869 status_t err; 2870 if (mIsAvc) { 2871 err = makeAVCCodecSpecificData( 2872 (const uint8_t *)buffer->data() 2873 + buffer->range_offset(), 2874 buffer->range_length()); 2875 } else if (mIsHevc || mIsHeic) { 2876 err = makeHEVCCodecSpecificData( 2877 (const uint8_t *)buffer->data() 2878 + buffer->range_offset(), 2879 buffer->range_length()); 2880 } else if (mIsMPEG4) { 2881 copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(), 2882 buffer->range_length()); 2883 } 2884 } 2885 2886 buffer->release(); 2887 buffer = NULL; 2888 if (OK != err) { 2889 mSource->stop(); 2890 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, 2891 mTrackId | MEDIA_RECORDER_TRACK_ERROR_GENERAL, err); 2892 break; 2893 } 2894 2895 mGotAllCodecSpecificData = true; 2896 continue; 2897 } 2898 2899 // Per-frame metadata sample's size must be smaller than max allowed. 2900 if (!mIsVideo && !mIsAudio && !mIsHeic && 2901 buffer->range_length() >= kMaxMetadataSize) { 2902 ALOGW("Buffer size is %zu. Maximum metadata buffer size is %lld for %s track", 2903 buffer->range_length(), (long long)kMaxMetadataSize, trackName); 2904 buffer->release(); 2905 mSource->stop(); 2906 mIsMalformed = true; 2907 break; 2908 } 2909 2910 ++nActualFrames; 2911 2912 // Make a deep copy of the MediaBuffer and Metadata and release 2913 // the original as soon as we can 2914 MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 2915 memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 2916 buffer->range_length()); 2917 copy->set_range(0, buffer->range_length()); 2918 meta_data = new MetaData(buffer->meta_data()); 2919 buffer->release(); 2920 buffer = NULL; 2921 2922 if (usePrefix()) StripStartcode(copy); 2923 2924 size_t sampleSize = copy->range_length(); 2925 if (usePrefix()) { 2926 if (mOwner->useNalLengthFour()) { 2927 sampleSize += 4; 2928 } else { 2929 sampleSize += 2; 2930 } 2931 } 2932 2933 // Max file size or duration handling 2934 mMdatSizeBytes += sampleSize; 2935 updateTrackSizeEstimate(); 2936 2937 if (mOwner->exceedsFileSizeLimit()) { 2938 if (mOwner->switchFd() != OK) { 2939 ALOGW("Recorded file size exceeds limit %" PRId64 "bytes", 2940 mOwner->mMaxFileSizeLimitBytes); 2941 mSource->stop(); 2942 mOwner->notify( 2943 MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 2944 } else { 2945 ALOGV("%s Current recorded file size exceeds limit %" PRId64 "bytes. Switching output", 2946 getTrackType(), mOwner->mMaxFileSizeLimitBytes); 2947 } 2948 copy->release(); 2949 break; 2950 } 2951 2952 if (mOwner->exceedsFileDurationLimit()) { 2953 ALOGW("Recorded file duration exceeds limit %" PRId64 "microseconds", 2954 mOwner->mMaxFileDurationLimitUs); 2955 mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 2956 copy->release(); 2957 mSource->stop(); 2958 break; 2959 } 2960 2961 if (mOwner->approachingFileSizeLimit()) { 2962 mOwner->notifyApproachingLimit(); 2963 } 2964 2965 int32_t isSync = false; 2966 meta_data->findInt32(kKeyIsSyncFrame, &isSync); 2967 CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 2968 2969 // For video, skip the first several non-key frames until getting the first key frame. 2970 if (mIsVideo && !mGotStartKeyFrame && !isSync) { 2971 ALOGD("Video skip non-key frame"); 2972 copy->release(); 2973 continue; 2974 } 2975 if (mIsVideo && isSync) { 2976 mGotStartKeyFrame = true; 2977 } 2978//////////////////////////////////////////////////////////////////////////////// 2979 2980 if (!mIsHeic) { 2981 if (mStszTableEntries->count() == 0) { 2982 mFirstSampleTimeRealUs = systemTime() / 1000; 2983 mStartTimestampUs = timestampUs; 2984 mOwner->setStartTimestampUs(mStartTimestampUs); 2985 previousPausedDurationUs = mStartTimestampUs; 2986 } 2987 2988 if (mResumed) { 2989 int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 2990 if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) { 2991 copy->release(); 2992 mSource->stop(); 2993 mIsMalformed = true; 2994 break; 2995 } 2996 2997 int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 2998 if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) { 2999 copy->release(); 3000 mSource->stop(); 3001 mIsMalformed = true; 3002 break; 3003 } 3004 3005 previousPausedDurationUs += pausedDurationUs - lastDurationUs; 3006 mResumed = false; 3007 } 3008 TimestampDebugHelperEntry timestampDebugEntry; 3009 timestampUs -= previousPausedDurationUs; 3010 timestampDebugEntry.pts = timestampUs; 3011 if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { 3012 copy->release(); 3013 mSource->stop(); 3014 mIsMalformed = true; 3015 break; 3016 } 3017 3018 if (mIsVideo) { 3019 /* 3020 * Composition time: timestampUs 3021 * Decoding time: decodingTimeUs 3022 * Composition time offset = composition time - decoding time 3023 */ 3024 int64_t decodingTimeUs; 3025 CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs)); 3026 decodingTimeUs -= previousPausedDurationUs; 3027 3028 // ensure non-negative, monotonic decoding time 3029 if (mLastDecodingTimeUs < 0) { 3030 decodingTimeUs = std::max((int64_t)0, decodingTimeUs); 3031 } else { 3032 // increase decoding time by at least the larger vaule of 1 tick and 3033 // 0.1 milliseconds. This needs to take into account the possible 3034 // delta adjustment in DurationTicks in below. 3035 decodingTimeUs = std::max(mLastDecodingTimeUs + 3036 std::max(100, divUp(1000000, mTimeScale)), decodingTimeUs); 3037 } 3038 3039 mLastDecodingTimeUs = decodingTimeUs; 3040 timestampDebugEntry.dts = decodingTimeUs; 3041 timestampDebugEntry.frameType = isSync ? "Key frame" : "Non-Key frame"; 3042 // Insert the timestamp into the mTimestampDebugHelper 3043 if (mTimestampDebugHelper.size() >= kTimestampDebugCount) { 3044 mTimestampDebugHelper.pop_front(); 3045 } 3046 mTimestampDebugHelper.push_back(timestampDebugEntry); 3047 3048 cttsOffsetTimeUs = 3049 timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs; 3050 if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) { 3051 copy->release(); 3052 mSource->stop(); 3053 mIsMalformed = true; 3054 break; 3055 } 3056 3057 timestampUs = decodingTimeUs; 3058 ALOGV("decoding time: %" PRId64 " and ctts offset time: %" PRId64, 3059 timestampUs, cttsOffsetTimeUs); 3060 3061 // Update ctts box table if necessary 3062 currCttsOffsetTimeTicks = 3063 (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL; 3064 if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) { 3065 copy->release(); 3066 mSource->stop(); 3067 mIsMalformed = true; 3068 break; 3069 } 3070 3071 if (mStszTableEntries->count() == 0) { 3072 // Force the first ctts table entry to have one single entry 3073 // so that we can do adjustment for the initial track start 3074 // time offset easily in writeCttsBox(). 3075 lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks; 3076 addOneCttsTableEntry(1, currCttsOffsetTimeTicks); 3077 cttsSampleCount = 0; // No sample in ctts box is pending 3078 } else { 3079 if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) { 3080 addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks); 3081 lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks; 3082 cttsSampleCount = 1; // One sample in ctts box is pending 3083 } else { 3084 ++cttsSampleCount; 3085 } 3086 } 3087 3088 // Update ctts time offset range 3089 if (mStszTableEntries->count() == 0) { 3090 mMinCttsOffsetTicks = currCttsOffsetTimeTicks; 3091 mMaxCttsOffsetTicks = currCttsOffsetTimeTicks; 3092 } else { 3093 if (currCttsOffsetTimeTicks > mMaxCttsOffsetTicks) { 3094 mMaxCttsOffsetTicks = currCttsOffsetTimeTicks; 3095 } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTicks) { 3096 mMinCttsOffsetTicks = currCttsOffsetTimeTicks; 3097 mMinCttsOffsetTimeUs = cttsOffsetTimeUs; 3098 } 3099 } 3100 } 3101 3102 if (mOwner->isRealTimeRecording()) { 3103 if (mIsAudio) { 3104 updateDriftTime(meta_data); 3105 } 3106 } 3107 3108 if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { 3109 copy->release(); 3110 mSource->stop(); 3111 mIsMalformed = true; 3112 break; 3113 } 3114 3115 ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64, 3116 trackName, timestampUs, previousPausedDurationUs); 3117 if (timestampUs > mTrackDurationUs) { 3118 mTrackDurationUs = timestampUs; 3119 } 3120 3121 // We need to use the time scale based ticks, rather than the 3122 // timestamp itself to determine whether we have to use a new 3123 // stts entry, since we may have rounding errors. 3124 // The calculation is intended to reduce the accumulated 3125 // rounding errors. 3126 currDurationTicks = 3127 ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 3128 (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 3129 if (currDurationTicks < 0ll) { 3130 ALOGE("do not support out of order frames (timestamp: %lld < last: %lld for %s track", 3131 (long long)timestampUs, (long long)lastTimestampUs, trackName); 3132 copy->release(); 3133 mSource->stop(); 3134 mIsMalformed = true; 3135 break; 3136 } 3137 3138 // if the duration is different for this sample, see if it is close enough to the previous 3139 // duration that we can fudge it and use the same value, to avoid filling the stts table 3140 // with lots of near-identical entries. 3141 // "close enough" here means that the current duration needs to be adjusted by less 3142 // than 0.1 milliseconds 3143 if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) { 3144 int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL 3145 + (mTimeScale / 2)) / mTimeScale; 3146 if (deltaUs > -100 && deltaUs < 100) { 3147 // use previous ticks, and adjust timestamp as if it was actually that number 3148 // of ticks 3149 currDurationTicks = lastDurationTicks; 3150 timestampUs += deltaUs; 3151 } 3152 } 3153 mStszTableEntries->add(htonl(sampleSize)); 3154 if (mStszTableEntries->count() > 2) { 3155 3156 // Force the first sample to have its own stts entry so that 3157 // we can adjust its value later to maintain the A/V sync. 3158 if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) { 3159 addOneSttsTableEntry(sampleCount, lastDurationTicks); 3160 sampleCount = 1; 3161 } else { 3162 ++sampleCount; 3163 } 3164 3165 } 3166 if (mSamplesHaveSameSize) { 3167 if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) { 3168 mSamplesHaveSameSize = false; 3169 } 3170 previousSampleSize = sampleSize; 3171 } 3172 ALOGV("%s timestampUs/lastTimestampUs: %" PRId64 "/%" PRId64, 3173 trackName, timestampUs, lastTimestampUs); 3174 lastDurationUs = timestampUs - lastTimestampUs; 3175 lastDurationTicks = currDurationTicks; 3176 lastTimestampUs = timestampUs; 3177 3178 if (isSync != 0) { 3179 addOneStssTableEntry(mStszTableEntries->count()); 3180 } 3181 3182 if (mTrackingProgressStatus) { 3183 if (mPreviousTrackTimeUs <= 0) { 3184 mPreviousTrackTimeUs = mStartTimestampUs; 3185 } 3186 trackProgressStatus(timestampUs); 3187 } 3188 } 3189 if (!hasMultipleTracks) { 3190 size_t bytesWritten; 3191 off64_t offset = mOwner->addSample_l(copy, usePrefix(), &bytesWritten); 3192 3193 if (mIsHeic) { 3194 addItemOffsetAndSize(offset, bytesWritten); 3195 } else { 3196 uint32_t count = (mOwner->use32BitFileOffset() 3197 ? mStcoTableEntries->count() 3198 : mCo64TableEntries->count()); 3199 3200 if (count == 0) { 3201 addChunkOffset(offset); 3202 } 3203 } 3204 copy->release(); 3205 copy = NULL; 3206 continue; 3207 } 3208 3209 mChunkSamples.push_back(copy); 3210 if (mIsHeic) { 3211 bufferChunk(0 /*timestampUs*/); 3212 ++nChunks; 3213 } else if (interleaveDurationUs == 0) { 3214 addOneStscTableEntry(++nChunks, 1); 3215 bufferChunk(timestampUs); 3216 } else { 3217 if (chunkTimestampUs == 0) { 3218 chunkTimestampUs = timestampUs; 3219 } else { 3220 int64_t chunkDurationUs = timestampUs - chunkTimestampUs; 3221 if (chunkDurationUs > interleaveDurationUs) { 3222 if (chunkDurationUs > mMaxChunkDurationUs) { 3223 mMaxChunkDurationUs = chunkDurationUs; 3224 } 3225 ++nChunks; 3226 if (nChunks == 1 || // First chunk 3227 lastSamplesPerChunk != mChunkSamples.size()) { 3228 lastSamplesPerChunk = mChunkSamples.size(); 3229 addOneStscTableEntry(nChunks, lastSamplesPerChunk); 3230 } 3231 bufferChunk(timestampUs); 3232 chunkTimestampUs = timestampUs; 3233 } 3234 } 3235 } 3236 3237 } 3238 3239 if (isTrackMalFormed()) { 3240 dumpTimeStamps(); 3241 err = ERROR_MALFORMED; 3242 } 3243 3244 mOwner->trackProgressStatus(mTrackId, -1, err); 3245 3246 if (mIsHeic) { 3247 if (!mChunkSamples.empty()) { 3248 bufferChunk(0); 3249 ++nChunks; 3250 } 3251 } else { 3252 // Last chunk 3253 if (!hasMultipleTracks) { 3254 addOneStscTableEntry(1, mStszTableEntries->count()); 3255 } else if (!mChunkSamples.empty()) { 3256 addOneStscTableEntry(++nChunks, mChunkSamples.size()); 3257 bufferChunk(timestampUs); 3258 } 3259 3260 // We don't really know how long the last frame lasts, since 3261 // there is no frame time after it, just repeat the previous 3262 // frame's duration. 3263 if (mStszTableEntries->count() == 1) { 3264 lastDurationUs = 0; // A single sample's duration 3265 lastDurationTicks = 0; 3266 } else { 3267 ++sampleCount; // Count for the last sample 3268 } 3269 3270 if (mStszTableEntries->count() <= 2) { 3271 addOneSttsTableEntry(1, lastDurationTicks); 3272 if (sampleCount - 1 > 0) { 3273 addOneSttsTableEntry(sampleCount - 1, lastDurationTicks); 3274 } 3275 } else { 3276 addOneSttsTableEntry(sampleCount, lastDurationTicks); 3277 } 3278 3279 // The last ctts box may not have been written yet, and this 3280 // is to make sure that we write out the last ctts box. 3281 if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) { 3282 if (cttsSampleCount > 0) { 3283 addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks); 3284 } 3285 } 3286 3287 mTrackDurationUs += lastDurationUs; 3288 } 3289 mReachedEOS = true; 3290 3291 sendTrackSummary(hasMultipleTracks); 3292 3293 ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", 3294 count, nZeroLengthFrames, mStszTableEntries->count(), trackName); 3295 if (mIsAudio) { 3296 ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs()); 3297 } 3298 3299 if (err == ERROR_END_OF_STREAM) { 3300 return OK; 3301 } 3302 return err; 3303} 3304 3305bool MPEG4Writer::Track::isTrackMalFormed() const { 3306 if (mIsMalformed) { 3307 return true; 3308 } 3309 3310 if (!mIsHeic && mStszTableEntries->count() == 0) { // no samples written 3311 ALOGE("The number of recorded samples is 0"); 3312 return true; 3313 } 3314 3315 if (mIsVideo && mStssTableEntries->count() == 0) { // no sync frames for video 3316 ALOGE("There are no sync frames for video track"); 3317 return true; 3318 } 3319 3320 if (OK != checkCodecSpecificData()) { // no codec specific data 3321 return true; 3322 } 3323 3324 return false; 3325} 3326 3327void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { 3328 3329 // Send track summary only if test mode is enabled. 3330 if (!isTestModeEnabled()) { 3331 return; 3332 } 3333 3334 int trackNum = (mTrackId << 28); 3335 3336 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3337 trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE, 3338 mIsAudio ? 0: 1); 3339 3340 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3341 trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS, 3342 mTrackDurationUs / 1000); 3343 3344 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3345 trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES, 3346 mStszTableEntries->count()); 3347 3348 { 3349 // The system delay time excluding the requested initial delay that 3350 // is used to eliminate the recording sound. 3351 int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 3352 if (startTimeOffsetUs < 0) { // Start time offset was not set 3353 startTimeOffsetUs = kInitialDelayTimeUs; 3354 } 3355 int64_t initialDelayUs = 3356 mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs; 3357 3358 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3359 trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS, 3360 (initialDelayUs) / 1000); 3361 } 3362 3363 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3364 trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES, 3365 mMdatSizeBytes / 1024); 3366 3367 if (hasMultipleTracks) { 3368 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3369 trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS, 3370 mMaxChunkDurationUs / 1000); 3371 3372 int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 3373 if (mStartTimestampUs != moovStartTimeUs) { 3374 int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 3375 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3376 trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS, 3377 startTimeOffsetUs / 1000); 3378 } 3379 } 3380} 3381 3382void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 3383 ALOGV("trackProgressStatus: %" PRId64 " us", timeUs); 3384 3385 if (mTrackEveryTimeDurationUs > 0 && 3386 timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 3387 ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs); 3388 mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); 3389 mPreviousTrackTimeUs = timeUs; 3390 } 3391} 3392 3393void MPEG4Writer::trackProgressStatus( 3394 size_t trackId, int64_t timeUs, status_t err) { 3395 Mutex::Autolock lock(mLock); 3396 int32_t trackNum = (trackId << 28); 3397 3398 // Error notification 3399 // Do not consider ERROR_END_OF_STREAM an error 3400 if (err != OK && err != ERROR_END_OF_STREAM) { 3401 notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, 3402 trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL, 3403 err); 3404 return; 3405 } 3406 3407 if (timeUs == -1) { 3408 // Send completion notification 3409 notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3410 trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, 3411 err); 3412 } else { 3413 // Send progress status 3414 notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3415 trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME, 3416 timeUs / 1000); 3417 } 3418} 3419 3420void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { 3421 ALOGV("setDriftTimeUs: %" PRId64 " us", driftTimeUs); 3422 Mutex::Autolock autolock(mLock); 3423 mDriftTimeUs = driftTimeUs; 3424} 3425 3426int64_t MPEG4Writer::getDriftTimeUs() { 3427 ALOGV("getDriftTimeUs: %" PRId64 " us", mDriftTimeUs); 3428 Mutex::Autolock autolock(mLock); 3429 return mDriftTimeUs; 3430} 3431 3432bool MPEG4Writer::isRealTimeRecording() const { 3433 return mIsRealTimeRecording; 3434} 3435 3436bool MPEG4Writer::useNalLengthFour() { 3437 return mUse4ByteNalLength; 3438} 3439 3440void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 3441 ALOGV("bufferChunk"); 3442 3443 Chunk chunk(this, timestampUs, mChunkSamples); 3444 mOwner->bufferChunk(chunk); 3445 mChunkSamples.clear(); 3446} 3447 3448int64_t MPEG4Writer::Track::getDurationUs() const { 3449 return mTrackDurationUs + getStartTimeOffsetTimeUs(); 3450} 3451 3452int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 3453 return mEstimatedTrackSizeBytes; 3454} 3455 3456int32_t MPEG4Writer::Track::getMetaSizeIncrease() const { 3457 CHECK(mIsHeic); 3458 3459 int32_t grid = (mNumTiles > 1); 3460 3461 // Note that the rotation angle is in the file meta, and we don't have 3462 // it until start, so here the calculation has to assume rotation. 3463 3464 // increase to ipco 3465 int32_t increase = 20 * (grid + 1) // 'ispe' property 3466 + (8 + mCodecSpecificDataSize) // 'hvcC' property 3467 + 9; // 'irot' property (worst case) 3468 3469 // increase to iref and idat 3470 if (grid) { 3471 increase += (8 + 2 + 2 + mNumTiles * 2) // 'dimg' in iref 3472 + 12; // ImageGrid in 'idat' (worst case) 3473 } 3474 3475 // increase to iloc, iinf and ipma 3476 increase += (16 // increase to 'iloc' 3477 + 21 // increase to 'iinf' 3478 + (3 + 2 * 2)) // increase to 'ipma' (worst case, 2 props x 2 bytes) 3479 * (mNumTiles + grid); 3480 3481 // adjust to ipma: 3482 // if rotation is present and only one tile, it could ref 3 properties 3483 if (!grid) { 3484 increase += 2; 3485 } 3486 3487 return increase; 3488} 3489 3490status_t MPEG4Writer::Track::checkCodecSpecificData() const { 3491 const char *mime; 3492 CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 3493 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 3494 !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 3495 !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) || 3496 !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime) || 3497 !strcasecmp(MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, mime)) { 3498 if (!mCodecSpecificData || 3499 mCodecSpecificDataSize <= 0) { 3500 ALOGE("Missing codec specific data"); 3501 return ERROR_MALFORMED; 3502 } 3503 } else { 3504 if (mCodecSpecificData || 3505 mCodecSpecificDataSize > 0) { 3506 ALOGE("Unexepected codec specific data found"); 3507 return ERROR_MALFORMED; 3508 } 3509 } 3510 return OK; 3511} 3512 3513const char *MPEG4Writer::Track::getTrackType() const { 3514 return mIsAudio ? "Audio" : 3515 mIsVideo ? "Video" : 3516 mIsHeic ? "Image" : 3517 "Metadata"; 3518} 3519 3520void MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) { 3521 uint32_t now = getMpeg4Time(); 3522 mOwner->beginBox("trak"); 3523 writeTkhdBox(now); 3524 mOwner->beginBox("mdia"); 3525 writeMdhdBox(now); 3526 writeHdlrBox(); 3527 mOwner->beginBox("minf"); 3528 if (mIsAudio) { 3529 writeSmhdBox(); 3530 } else if (mIsVideo) { 3531 writeVmhdBox(); 3532 } else { 3533 writeNmhdBox(); 3534 } 3535 writeDinfBox(); 3536 writeStblBox(use32BitOffset); 3537 mOwner->endBox(); // minf 3538 mOwner->endBox(); // mdia 3539 mOwner->endBox(); // trak 3540} 3541 3542int64_t MPEG4Writer::Track::getMinCttsOffsetTimeUs() { 3543 // For video tracks with ctts table, this should return the minimum ctts 3544 // offset in the table. For non-video tracks or video tracks without ctts 3545 // table, this will return kMaxCttsOffsetTimeUs. 3546 if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) { 3547 return kMaxCttsOffsetTimeUs; 3548 } 3549 return mMinCttsOffsetTimeUs; 3550} 3551 3552void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) { 3553 mOwner->beginBox("stbl"); 3554 mOwner->beginBox("stsd"); 3555 mOwner->writeInt32(0); // version=0, flags=0 3556 mOwner->writeInt32(1); // entry count 3557 if (mIsAudio) { 3558 writeAudioFourCCBox(); 3559 } else if (mIsVideo) { 3560 writeVideoFourCCBox(); 3561 } else { 3562 writeMetadataFourCCBox(); 3563 } 3564 mOwner->endBox(); // stsd 3565 writeSttsBox(); 3566 if (mIsVideo) { 3567 writeCttsBox(); 3568 writeStssBox(); 3569 } 3570 writeStszBox(); 3571 writeStscBox(); 3572 writeStcoBox(use32BitOffset); 3573 mOwner->endBox(); // stbl 3574} 3575 3576void MPEG4Writer::Track::writeMetadataFourCCBox() { 3577 const char *mime; 3578 bool success = mMeta->findCString(kKeyMIMEType, &mime); 3579 CHECK(success); 3580 const char *fourcc = getFourCCForMime(mime); 3581 if (fourcc == NULL) { 3582 ALOGE("Unknown mime type '%s'.", mime); 3583 TRESPASS(); 3584 } 3585 mOwner->beginBox(fourcc); // TextMetaDataSampleEntry 3586 mOwner->writeCString(mime); // metadata mime_format 3587 mOwner->endBox(); // mett 3588} 3589 3590void MPEG4Writer::Track::writeVideoFourCCBox() { 3591 const char *mime; 3592 bool success = mMeta->findCString(kKeyMIMEType, &mime); 3593 CHECK(success); 3594 const char *fourcc = getFourCCForMime(mime); 3595 if (fourcc == NULL) { 3596 ALOGE("Unknown mime type '%s'.", mime); 3597 TRESPASS(); 3598 } 3599 3600 mOwner->beginBox(fourcc); // video format 3601 mOwner->writeInt32(0); // reserved 3602 mOwner->writeInt16(0); // reserved 3603 mOwner->writeInt16(1); // data ref index 3604 mOwner->writeInt16(0); // predefined 3605 mOwner->writeInt16(0); // reserved 3606 mOwner->writeInt32(0); // predefined 3607 mOwner->writeInt32(0); // predefined 3608 mOwner->writeInt32(0); // predefined 3609 3610 int32_t width, height; 3611 success = mMeta->findInt32(kKeyWidth, &width); 3612 success = success && mMeta->findInt32(kKeyHeight, &height); 3613 CHECK(success); 3614 3615 mOwner->writeInt16(width); 3616 mOwner->writeInt16(height); 3617 mOwner->writeInt32(0x480000); // horiz resolution 3618 mOwner->writeInt32(0x480000); // vert resolution 3619 mOwner->writeInt32(0); // reserved 3620 mOwner->writeInt16(1); // frame count 3621 mOwner->writeInt8(0); // compressor string length 3622 mOwner->write(" ", 31); 3623 mOwner->writeInt16(0x18); // depth 3624 mOwner->writeInt16(-1); // predefined 3625 3626 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 3627 writeMp4vEsdsBox(); 3628 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 3629 writeD263Box(); 3630 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 3631 writeAvccBox(); 3632 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { 3633 writeHvccBox(); 3634 } 3635 3636 writePaspBox(); 3637 writeColrBox(); 3638 mOwner->endBox(); // mp4v, s263 or avc1 3639} 3640 3641void MPEG4Writer::Track::writeColrBox() { 3642 ColorAspects aspects; 3643 memset(&aspects, 0, sizeof(aspects)); 3644 // TRICKY: using | instead of || because we want to execute all findInt32-s 3645 if (mMeta->findInt32(kKeyColorPrimaries, (int32_t*)&aspects.mPrimaries) 3646 | mMeta->findInt32(kKeyTransferFunction, (int32_t*)&aspects.mTransfer) 3647 | mMeta->findInt32(kKeyColorMatrix, (int32_t*)&aspects.mMatrixCoeffs) 3648 | mMeta->findInt32(kKeyColorRange, (int32_t*)&aspects.mRange)) { 3649 int32_t primaries, transfer, coeffs; 3650 bool fullRange; 3651 ColorUtils::convertCodecColorAspectsToIsoAspects( 3652 aspects, &primaries, &transfer, &coeffs, &fullRange); 3653 mOwner->beginBox("colr"); 3654 mOwner->writeFourcc("nclx"); 3655 mOwner->writeInt16(primaries); 3656 mOwner->writeInt16(transfer); 3657 mOwner->writeInt16(coeffs); 3658 mOwner->writeInt8(int8_t(fullRange ? 0x80 : 0x0)); 3659 mOwner->endBox(); // colr 3660 } 3661} 3662 3663void MPEG4Writer::Track::writeAudioFourCCBox() { 3664 const char *mime; 3665 bool success = mMeta->findCString(kKeyMIMEType, &mime); 3666 CHECK(success); 3667 const char *fourcc = getFourCCForMime(mime); 3668 if (fourcc == NULL) { 3669 ALOGE("Unknown mime type '%s'.", mime); 3670 TRESPASS(); 3671 } 3672 3673 mOwner->beginBox(fourcc); // audio format 3674 mOwner->writeInt32(0); // reserved 3675 mOwner->writeInt16(0); // reserved 3676 mOwner->writeInt16(0x1); // data ref index 3677 mOwner->writeInt32(0); // reserved 3678 mOwner->writeInt32(0); // reserved 3679 int32_t nChannels; 3680 CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 3681 mOwner->writeInt16(nChannels); // channel count 3682 mOwner->writeInt16(16); // sample size 3683 mOwner->writeInt16(0); // predefined 3684 mOwner->writeInt16(0); // reserved 3685 3686 int32_t samplerate; 3687 success = mMeta->findInt32(kKeySampleRate, &samplerate); 3688 CHECK(success); 3689 mOwner->writeInt32(samplerate << 16); 3690 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 3691 writeMp4aEsdsBox(); 3692 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 3693 !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 3694 writeDamrBox(); 3695 } 3696 mOwner->endBox(); 3697} 3698 3699void MPEG4Writer::Track::writeMp4aEsdsBox() { 3700 mOwner->beginBox("esds"); 3701 CHECK(mCodecSpecificData); 3702 CHECK_GT(mCodecSpecificDataSize, 0u); 3703 3704 // Make sure all sizes encode to a single byte. 3705 CHECK_LT(mCodecSpecificDataSize + 23, 128u); 3706 3707 mOwner->writeInt32(0); // version=0, flags=0 3708 mOwner->writeInt8(0x03); // ES_DescrTag 3709 mOwner->writeInt8(23 + mCodecSpecificDataSize); 3710 mOwner->writeInt16(0x0000);// ES_ID 3711 mOwner->writeInt8(0x00); 3712 3713 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 3714 mOwner->writeInt8(15 + mCodecSpecificDataSize); 3715 mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 3716 mOwner->writeInt8(0x15); // streamType AudioStream 3717 3718 mOwner->writeInt16(0x03); // XXX 3719 mOwner->writeInt8(0x00); // buffer size 24-bit (0x300) 3720 3721 int32_t avgBitrate = 0; 3722 (void)mMeta->findInt32(kKeyBitRate, &avgBitrate); 3723 int32_t maxBitrate = 0; 3724 (void)mMeta->findInt32(kKeyMaxBitRate, &maxBitrate); 3725 mOwner->writeInt32(maxBitrate); 3726 mOwner->writeInt32(avgBitrate); 3727 3728 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 3729 mOwner->writeInt8(mCodecSpecificDataSize); 3730 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 3731 3732 static const uint8_t kData2[] = { 3733 0x06, // SLConfigDescriptorTag 3734 0x01, 3735 0x02 3736 }; 3737 mOwner->write(kData2, sizeof(kData2)); 3738 3739 mOwner->endBox(); // esds 3740} 3741 3742void MPEG4Writer::Track::writeMp4vEsdsBox() { 3743 CHECK(mCodecSpecificData); 3744 CHECK_GT(mCodecSpecificDataSize, 0u); 3745 3746 // Make sure all sizes encode to a single byte. 3747 CHECK_LT(23 + mCodecSpecificDataSize, 128u); 3748 3749 mOwner->beginBox("esds"); 3750 3751 mOwner->writeInt32(0); // version=0, flags=0 3752 3753 mOwner->writeInt8(0x03); // ES_DescrTag 3754 mOwner->writeInt8(23 + mCodecSpecificDataSize); 3755 mOwner->writeInt16(0x0000); // ES_ID 3756 mOwner->writeInt8(0x1f); 3757 3758 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 3759 mOwner->writeInt8(15 + mCodecSpecificDataSize); 3760 mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 3761 mOwner->writeInt8(0x11); // streamType VisualStream 3762 3763 static const uint8_t kData[] = { 3764 0x01, 0x77, 0x00, // buffer size 96000 bytes 3765 }; 3766 mOwner->write(kData, sizeof(kData)); 3767 3768 int32_t avgBitrate = 0; 3769 (void)mMeta->findInt32(kKeyBitRate, &avgBitrate); 3770 int32_t maxBitrate = 0; 3771 (void)mMeta->findInt32(kKeyMaxBitRate, &maxBitrate); 3772 mOwner->writeInt32(maxBitrate); 3773 mOwner->writeInt32(avgBitrate); 3774 3775 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 3776 3777 mOwner->writeInt8(mCodecSpecificDataSize); 3778 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 3779 3780 static const uint8_t kData2[] = { 3781 0x06, // SLConfigDescriptorTag 3782 0x01, 3783 0x02 3784 }; 3785 mOwner->write(kData2, sizeof(kData2)); 3786 3787 mOwner->endBox(); // esds 3788} 3789 3790void MPEG4Writer::Track::writeTkhdBox(uint32_t now) { 3791 mOwner->beginBox("tkhd"); 3792 // Flags = 7 to indicate that the track is enabled, and 3793 // part of the presentation 3794 mOwner->writeInt32(0x07); // version=0, flags=7 3795 mOwner->writeInt32(now); // creation time 3796 mOwner->writeInt32(now); // modification time 3797 mOwner->writeInt32(mTrackId); // track id starts with 1 3798 mOwner->writeInt32(0); // reserved 3799 int64_t trakDurationUs = getDurationUs(); 3800 int32_t mvhdTimeScale = mOwner->getTimeScale(); 3801 int32_t tkhdDuration = 3802 (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 3803 mOwner->writeInt32(tkhdDuration); // in mvhd timescale 3804 mOwner->writeInt32(0); // reserved 3805 mOwner->writeInt32(0); // reserved 3806 mOwner->writeInt16(0); // layer 3807 mOwner->writeInt16(0); // alternate group 3808 mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 3809 mOwner->writeInt16(0); // reserved 3810 3811 mOwner->writeCompositionMatrix(mRotation); // matrix 3812 3813 if (!mIsVideo) { 3814 mOwner->writeInt32(0); 3815 mOwner->writeInt32(0); 3816 } else { 3817 int32_t width, height; 3818 bool success = mMeta->findInt32(kKeyDisplayWidth, &width); 3819 success = success && mMeta->findInt32(kKeyDisplayHeight, &height); 3820 3821 // Use width/height if display width/height are not present. 3822 if (!success) { 3823 success = mMeta->findInt32(kKeyWidth, &width); 3824 success = success && mMeta->findInt32(kKeyHeight, &height); 3825 } 3826 CHECK(success); 3827 3828 mOwner->writeInt32(width << 16); // 32-bit fixed-point value 3829 mOwner->writeInt32(height << 16); // 32-bit fixed-point value 3830 } 3831 mOwner->endBox(); // tkhd 3832} 3833 3834void MPEG4Writer::Track::writeVmhdBox() { 3835 mOwner->beginBox("vmhd"); 3836 mOwner->writeInt32(0x01); // version=0, flags=1 3837 mOwner->writeInt16(0); // graphics mode 3838 mOwner->writeInt16(0); // opcolor 3839 mOwner->writeInt16(0); 3840 mOwner->writeInt16(0); 3841 mOwner->endBox(); 3842} 3843 3844void MPEG4Writer::Track::writeSmhdBox() { 3845 mOwner->beginBox("smhd"); 3846 mOwner->writeInt32(0); // version=0, flags=0 3847 mOwner->writeInt16(0); // balance 3848 mOwner->writeInt16(0); // reserved 3849 mOwner->endBox(); 3850} 3851 3852void MPEG4Writer::Track::writeNmhdBox() { 3853 mOwner->beginBox("nmhd"); 3854 mOwner->writeInt32(0); // version=0, flags=0 3855 mOwner->endBox(); 3856} 3857 3858void MPEG4Writer::Track::writeHdlrBox() { 3859 mOwner->beginBox("hdlr"); 3860 mOwner->writeInt32(0); // version=0, flags=0 3861 mOwner->writeInt32(0); // component type: should be mhlr 3862 mOwner->writeFourcc(mIsAudio ? "soun" : (mIsVideo ? "vide" : "meta")); // component subtype 3863 mOwner->writeInt32(0); // reserved 3864 mOwner->writeInt32(0); // reserved 3865 mOwner->writeInt32(0); // reserved 3866 // Removing "r" for the name string just makes the string 4 byte aligned 3867 mOwner->writeCString(mIsAudio ? "SoundHandle": (mIsVideo ? "VideoHandle" : "MetadHandle")); 3868 mOwner->endBox(); 3869} 3870 3871void MPEG4Writer::Track::writeMdhdBox(uint32_t now) { 3872 int64_t trakDurationUs = getDurationUs(); 3873 int64_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 3874 mOwner->beginBox("mdhd"); 3875 3876 if (mdhdDuration > UINT32_MAX) { 3877 mOwner->writeInt32((1 << 24)); // version=1, flags=0 3878 mOwner->writeInt64((int64_t)now); // creation time 3879 mOwner->writeInt64((int64_t)now); // modification time 3880 mOwner->writeInt32(mTimeScale); // media timescale 3881 mOwner->writeInt64(mdhdDuration); // media timescale 3882 } else { 3883 mOwner->writeInt32(0); // version=0, flags=0 3884 mOwner->writeInt32(now); // creation time 3885 mOwner->writeInt32(now); // modification time 3886 mOwner->writeInt32(mTimeScale); // media timescale 3887 mOwner->writeInt32((int32_t)mdhdDuration); // use media timescale 3888 } 3889 // Language follows the three letter standard ISO-639-2/T 3890 // 'e', 'n', 'g' for "English", for instance. 3891 // Each character is packed as the difference between its ASCII value and 0x60. 3892 // For "English", these are 00101, 01110, 00111. 3893 // XXX: Where is the padding bit located: 0x15C7? 3894 const char *lang = NULL; 3895 int16_t langCode = 0; 3896 if (mMeta->findCString(kKeyMediaLanguage, &lang) && lang && strnlen(lang, 3) > 2) { 3897 langCode = ((lang[0] & 0x1f) << 10) | ((lang[1] & 0x1f) << 5) | (lang[2] & 0x1f); 3898 } 3899 mOwner->writeInt16(langCode); // language code 3900 mOwner->writeInt16(0); // predefined 3901 mOwner->endBox(); 3902} 3903 3904void MPEG4Writer::Track::writeDamrBox() { 3905 // 3gpp2 Spec AMRSampleEntry fields 3906 mOwner->beginBox("damr"); 3907 mOwner->writeCString(" "); // vendor: 4 bytes 3908 mOwner->writeInt8(0); // decoder version 3909 mOwner->writeInt16(0x83FF); // mode set: all enabled 3910 mOwner->writeInt8(0); // mode change period 3911 mOwner->writeInt8(1); // frames per sample 3912 mOwner->endBox(); 3913} 3914 3915void MPEG4Writer::Track::writeUrlBox() { 3916 // The table index here refers to the sample description index 3917 // in the sample table entries. 3918 mOwner->beginBox("url "); 3919 mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 3920 mOwner->endBox(); // url 3921} 3922 3923void MPEG4Writer::Track::writeDrefBox() { 3924 mOwner->beginBox("dref"); 3925 mOwner->writeInt32(0); // version=0, flags=0 3926 mOwner->writeInt32(1); // entry count (either url or urn) 3927 writeUrlBox(); 3928 mOwner->endBox(); // dref 3929} 3930 3931void MPEG4Writer::Track::writeDinfBox() { 3932 mOwner->beginBox("dinf"); 3933 writeDrefBox(); 3934 mOwner->endBox(); // dinf 3935} 3936 3937void MPEG4Writer::Track::writeAvccBox() { 3938 CHECK(mCodecSpecificData); 3939 CHECK_GE(mCodecSpecificDataSize, 5u); 3940 3941 // Patch avcc's lengthSize field to match the number 3942 // of bytes we use to indicate the size of a nal unit. 3943 uint8_t *ptr = (uint8_t *)mCodecSpecificData; 3944 ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1); 3945 mOwner->beginBox("avcC"); 3946 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 3947 mOwner->endBox(); // avcC 3948} 3949 3950 3951void MPEG4Writer::Track::writeHvccBox() { 3952 CHECK(mCodecSpecificData); 3953 CHECK_GE(mCodecSpecificDataSize, 5u); 3954 3955 // Patch avcc's lengthSize field to match the number 3956 // of bytes we use to indicate the size of a nal unit. 3957 uint8_t *ptr = (uint8_t *)mCodecSpecificData; 3958 ptr[21] = (ptr[21] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1); 3959 mOwner->beginBox("hvcC"); 3960 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 3961 mOwner->endBox(); // hvcC 3962} 3963 3964void MPEG4Writer::Track::writeD263Box() { 3965 mOwner->beginBox("d263"); 3966 mOwner->writeInt32(0); // vendor 3967 mOwner->writeInt8(0); // decoder version 3968 mOwner->writeInt8(10); // level: 10 3969 mOwner->writeInt8(0); // profile: 0 3970 mOwner->endBox(); // d263 3971} 3972 3973// This is useful if the pixel is not square 3974void MPEG4Writer::Track::writePaspBox() { 3975 mOwner->beginBox("pasp"); 3976 mOwner->writeInt32(1 << 16); // hspacing 3977 mOwner->writeInt32(1 << 16); // vspacing 3978 mOwner->endBox(); // pasp 3979} 3980 3981int64_t MPEG4Writer::Track::getStartTimeOffsetTimeUs() const { 3982 int64_t trackStartTimeOffsetUs = 0; 3983 int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 3984 if (mStartTimestampUs != -1 && mStartTimestampUs != moovStartTimeUs) { 3985 CHECK_GT(mStartTimestampUs, moovStartTimeUs); 3986 trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 3987 } 3988 return trackStartTimeOffsetUs; 3989} 3990 3991int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const { 3992 return (getStartTimeOffsetTimeUs() * mTimeScale + 500000LL) / 1000000LL; 3993} 3994 3995void MPEG4Writer::Track::writeSttsBox() { 3996 mOwner->beginBox("stts"); 3997 mOwner->writeInt32(0); // version=0, flags=0 3998 if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) { 3999 // For non-vdeio tracks or video tracks without ctts table, 4000 // adjust duration of first sample for tracks to account for 4001 // first sample not starting at the media start time. 4002 // TODO: consider signaling this using some offset 4003 // as this is not quite correct. 4004 uint32_t duration; 4005 CHECK(mSttsTableEntries->get(duration, 1)); 4006 duration = htonl(duration); // Back to host byte order 4007 mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1); 4008 } 4009 mSttsTableEntries->write(mOwner); 4010 mOwner->endBox(); // stts 4011} 4012 4013void MPEG4Writer::Track::writeCttsBox() { 4014 // There is no B frame at all 4015 if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) { 4016 return; 4017 } 4018 4019 // Do not write ctts box when there is no need to have it. 4020 if (mCttsTableEntries->count() == 0) { 4021 return; 4022 } 4023 4024 ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]", 4025 mCttsTableEntries->count(), mMinCttsOffsetTicks, mMaxCttsOffsetTicks); 4026 4027 mOwner->beginBox("ctts"); 4028 mOwner->writeInt32(0); // version=0, flags=0 4029 int64_t deltaTimeUs = kMaxCttsOffsetTimeUs - getStartTimeOffsetTimeUs(); 4030 int64_t delta = (deltaTimeUs * mTimeScale + 500000LL) / 1000000LL; 4031 mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) { 4032 // entries are <count, ctts> pairs; adjust only ctts 4033 uint32_t duration = htonl(value[1]); // back to host byte order 4034 // Prevent overflow and underflow 4035 if (delta > duration) { 4036 duration = 0; 4037 } else if (delta < 0 && UINT32_MAX + delta < duration) { 4038 duration = UINT32_MAX; 4039 } else { 4040 duration -= delta; 4041 } 4042 value[1] = htonl(duration); 4043 }); 4044 mCttsTableEntries->write(mOwner); 4045 mOwner->endBox(); // ctts 4046} 4047 4048void MPEG4Writer::Track::writeStssBox() { 4049 mOwner->beginBox("stss"); 4050 mOwner->writeInt32(0); // version=0, flags=0 4051 mStssTableEntries->write(mOwner); 4052 mOwner->endBox(); // stss 4053} 4054 4055void MPEG4Writer::Track::writeStszBox() { 4056 mOwner->beginBox("stsz"); 4057 mOwner->writeInt32(0); // version=0, flags=0 4058 mOwner->writeInt32(0); 4059 mStszTableEntries->write(mOwner); 4060 mOwner->endBox(); // stsz 4061} 4062 4063void MPEG4Writer::Track::writeStscBox() { 4064 mOwner->beginBox("stsc"); 4065 mOwner->writeInt32(0); // version=0, flags=0 4066 mStscTableEntries->write(mOwner); 4067 mOwner->endBox(); // stsc 4068} 4069 4070void MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) { 4071 mOwner->beginBox(use32BitOffset? "stco": "co64"); 4072 mOwner->writeInt32(0); // version=0, flags=0 4073 if (use32BitOffset) { 4074 mStcoTableEntries->write(mOwner); 4075 } else { 4076 mCo64TableEntries->write(mOwner); 4077 } 4078 mOwner->endBox(); // stco or co64 4079} 4080 4081void MPEG4Writer::writeUdtaBox() { 4082 beginBox("udta"); 4083 writeGeoDataBox(); 4084 endBox(); 4085} 4086 4087void MPEG4Writer::writeHdlr(const char *handlerType) { 4088 beginBox("hdlr"); 4089 writeInt32(0); // Version, Flags 4090 writeInt32(0); // Predefined 4091 writeFourcc(handlerType); 4092 writeInt32(0); // Reserved[0] 4093 writeInt32(0); // Reserved[1] 4094 writeInt32(0); // Reserved[2] 4095 writeInt8(0); // Name (empty) 4096 endBox(); 4097} 4098 4099void MPEG4Writer::writeKeys() { 4100 size_t count = mMetaKeys->countEntries(); 4101 4102 beginBox("keys"); 4103 writeInt32(0); // Version, Flags 4104 writeInt32(count); // Entry_count 4105 for (size_t i = 0; i < count; i++) { 4106 AMessage::Type type; 4107 const char *key = mMetaKeys->getEntryNameAt(i, &type); 4108 size_t n = strlen(key); 4109 writeInt32(n + 8); 4110 writeFourcc("mdta"); 4111 write(key, n); // write without the \0 4112 } 4113 endBox(); 4114} 4115 4116void MPEG4Writer::writeIlst() { 4117 size_t count = mMetaKeys->countEntries(); 4118 4119 beginBox("ilst"); 4120 for (size_t i = 0; i < count; i++) { 4121 beginBox(i + 1); // key id (1-based) 4122 beginBox("data"); 4123 AMessage::Type type; 4124 const char *key = mMetaKeys->getEntryNameAt(i, &type); 4125 switch (type) { 4126 case AMessage::kTypeString: 4127 { 4128 AString val; 4129 CHECK(mMetaKeys->findString(key, &val)); 4130 writeInt32(1); // type = UTF8 4131 writeInt32(0); // default country/language 4132 write(val.c_str(), strlen(val.c_str())); // write without \0 4133 break; 4134 } 4135 4136 case AMessage::kTypeFloat: 4137 { 4138 float val; 4139 CHECK(mMetaKeys->findFloat(key, &val)); 4140 writeInt32(23); // type = float32 4141 writeInt32(0); // default country/language 4142 writeInt32(*reinterpret_cast<int32_t *>(&val)); 4143 break; 4144 } 4145 4146 case AMessage::kTypeInt32: 4147 { 4148 int32_t val; 4149 CHECK(mMetaKeys->findInt32(key, &val)); 4150 writeInt32(67); // type = signed int32 4151 writeInt32(0); // default country/language 4152 writeInt32(val); 4153 break; 4154 } 4155 4156 default: 4157 { 4158 ALOGW("Unsupported key type, writing 0 instead"); 4159 writeInt32(77); // type = unsigned int32 4160 writeInt32(0); // default country/language 4161 writeInt32(0); 4162 break; 4163 } 4164 } 4165 endBox(); // data 4166 endBox(); // key id 4167 } 4168 endBox(); // ilst 4169} 4170 4171void MPEG4Writer::writeMoovLevelMetaBox() { 4172 size_t count = mMetaKeys->countEntries(); 4173 if (count == 0) { 4174 return; 4175 } 4176 4177 beginBox("meta"); 4178 writeHdlr("mdta"); 4179 writeKeys(); 4180 writeIlst(); 4181 endBox(); 4182} 4183 4184void MPEG4Writer::writeIlocBox() { 4185 beginBox("iloc"); 4186 // Use version 1 to allow construction method 1 that refers to 4187 // data in idat box inside meta box. 4188 writeInt32(0x01000000); // Version = 1, Flags = 0 4189 writeInt16(0x4400); // offset_size = length_size = 4 4190 // base_offset_size = index_size = 0 4191 4192 // 16-bit item_count 4193 size_t itemCount = mItems.size(); 4194 if (itemCount > 65535) { 4195 ALOGW("Dropping excess items: itemCount %zu", itemCount); 4196 itemCount = 65535; 4197 } 4198 writeInt16((uint16_t)itemCount); 4199 4200 for (size_t i = 0; i < itemCount; i++) { 4201 writeInt16(mItems[i].itemId); 4202 bool isGrid = mItems[i].isGrid(); 4203 4204 writeInt16(isGrid ? 1 : 0); // construction_method 4205 writeInt16(0); // data_reference_index = 0 4206 writeInt16(1); // extent_count = 1 4207 4208 if (isGrid) { 4209 // offset into the 'idat' box 4210 writeInt32(mNumGrids++ * 8); 4211 writeInt32(8); 4212 } else { 4213 writeInt32(mItems[i].offset); 4214 writeInt32(mItems[i].size); 4215 } 4216 } 4217 endBox(); 4218} 4219 4220void MPEG4Writer::writeInfeBox( 4221 uint16_t itemId, const char *itemType, uint32_t flags) { 4222 beginBox("infe"); 4223 writeInt32(0x02000000 | flags); // Version = 2, Flags = 0 4224 writeInt16(itemId); 4225 writeInt16(0); //item_protection_index = 0 4226 writeFourcc(itemType); 4227 writeCString(""); // item_name 4228 endBox(); 4229} 4230 4231void MPEG4Writer::writeIinfBox() { 4232 beginBox("iinf"); 4233 writeInt32(0); // Version = 0, Flags = 0 4234 4235 // 16-bit item_count 4236 size_t itemCount = mItems.size(); 4237 if (itemCount > 65535) { 4238 ALOGW("Dropping excess items: itemCount %zu", itemCount); 4239 itemCount = 65535; 4240 } 4241 4242 writeInt16((uint16_t)itemCount); 4243 for (size_t i = 0; i < itemCount; i++) { 4244 writeInfeBox(mItems[i].itemId, mItems[i].itemType, 4245 mItems[i].isHidden ? 1 : 0); 4246 } 4247 4248 endBox(); 4249} 4250 4251void MPEG4Writer::writeIdatBox() { 4252 beginBox("idat"); 4253 4254 for (size_t i = 0; i < mItems.size(); i++) { 4255 if (mItems[i].isGrid()) { 4256 writeInt8(0); // version 4257 // flags == 1 means 32-bit width,height 4258 int8_t flags = (mItems[i].width > 65535 || mItems[i].height > 65535); 4259 writeInt8(flags); 4260 writeInt8(mItems[i].rows - 1); 4261 writeInt8(mItems[i].cols - 1); 4262 if (flags) { 4263 writeInt32(mItems[i].width); 4264 writeInt32(mItems[i].height); 4265 } else { 4266 writeInt16((uint16_t)mItems[i].width); 4267 writeInt16((uint16_t)mItems[i].height); 4268 } 4269 } 4270 } 4271 4272 endBox(); 4273} 4274 4275void MPEG4Writer::writeIrefBox() { 4276 beginBox("iref"); 4277 writeInt32(0); // Version = 0, Flags = 0 4278 { 4279 for (size_t i = 0; i < mItems.size(); i++) { 4280 if (!mItems[i].isGrid()) { 4281 continue; 4282 } 4283 beginBox("dimg"); 4284 writeInt16(mItems[i].itemId); 4285 size_t refCount = mItems[i].dimgRefs.size(); 4286 if (refCount > 65535) { 4287 ALOGW("too many entries in dimg"); 4288 refCount = 65535; 4289 } 4290 writeInt16((uint16_t)refCount); 4291 for (size_t refIndex = 0; refIndex < refCount; refIndex++) { 4292 writeInt16(mItems[i].dimgRefs[refIndex]); 4293 } 4294 endBox(); 4295 } 4296 } 4297 endBox(); 4298} 4299 4300void MPEG4Writer::writePitmBox() { 4301 beginBox("pitm"); 4302 writeInt32(0); // Version = 0, Flags = 0 4303 writeInt16(mPrimaryItemId); 4304 endBox(); 4305} 4306 4307void MPEG4Writer::writeIpcoBox() { 4308 beginBox("ipco"); 4309 size_t numProperties = mProperties.size(); 4310 if (numProperties > 32767) { 4311 ALOGW("Dropping excess properties: numProperties %zu", numProperties); 4312 numProperties = 32767; 4313 } 4314 for (size_t propIndex = 0; propIndex < numProperties; propIndex++) { 4315 switch (mProperties[propIndex].type) { 4316 case FOURCC('h', 'v', 'c', 'C'): 4317 { 4318 beginBox("hvcC"); 4319 sp<ABuffer> hvcc = mProperties[propIndex].hvcc; 4320 // Patch avcc's lengthSize field to match the number 4321 // of bytes we use to indicate the size of a nal unit. 4322 uint8_t *ptr = (uint8_t *)hvcc->data(); 4323 ptr[21] = (ptr[21] & 0xfc) | (useNalLengthFour() ? 3 : 1); 4324 write(hvcc->data(), hvcc->size()); 4325 endBox(); 4326 break; 4327 } 4328 case FOURCC('i', 's', 'p', 'e'): 4329 { 4330 beginBox("ispe"); 4331 writeInt32(0); // Version = 0, Flags = 0 4332 writeInt32(mProperties[propIndex].width); 4333 writeInt32(mProperties[propIndex].height); 4334 endBox(); 4335 break; 4336 } 4337 case FOURCC('i', 'r', 'o', 't'): 4338 { 4339 beginBox("irot"); 4340 writeInt8(mProperties[propIndex].rotation); 4341 endBox(); 4342 break; 4343 } 4344 default: 4345 ALOGW("Skipping unrecognized property: type 0x%08x", 4346 mProperties[propIndex].type); 4347 } 4348 } 4349 endBox(); 4350} 4351 4352void MPEG4Writer::writeIpmaBox() { 4353 beginBox("ipma"); 4354 uint32_t flags = (mProperties.size() > 127) ? 1 : 0; 4355 writeInt32(flags); // Version = 0 4356 4357 writeInt32(mAssociationEntryCount); 4358 for (size_t itemIndex = 0; itemIndex < mItems.size(); itemIndex++) { 4359 const Vector<uint16_t> &properties = mItems[itemIndex].properties; 4360 if (properties.empty()) { 4361 continue; 4362 } 4363 writeInt16(mItems[itemIndex].itemId); 4364 4365 size_t entryCount = properties.size(); 4366 if (entryCount > 255) { 4367 ALOGW("Dropping excess associations: entryCount %zu", entryCount); 4368 entryCount = 255; 4369 } 4370 writeInt8((uint8_t)entryCount); 4371 for (size_t propIndex = 0; propIndex < entryCount; propIndex++) { 4372 if (flags & 1) { 4373 writeInt16((1 << 15) | properties[propIndex]); 4374 } else { 4375 writeInt8((1 << 7) | properties[propIndex]); 4376 } 4377 } 4378 } 4379 endBox(); 4380} 4381 4382void MPEG4Writer::writeIprpBox() { 4383 beginBox("iprp"); 4384 writeIpcoBox(); 4385 writeIpmaBox(); 4386 endBox(); 4387} 4388 4389void MPEG4Writer::writeFileLevelMetaBox() { 4390 if (mItems.empty()) { 4391 ALOGE("no valid item was found"); 4392 return; 4393 } 4394 4395 // patch up the mPrimaryItemId and count items with prop associations 4396 uint16_t firstVisibleItemId = 0; 4397 for (size_t index = 0; index < mItems.size(); index++) { 4398 if (mItems[index].isPrimary) { 4399 mPrimaryItemId = mItems[index].itemId; 4400 } else if (!firstVisibleItemId && !mItems[index].isHidden) { 4401 firstVisibleItemId = mItems[index].itemId; 4402 } 4403 4404 if (!mItems[index].properties.empty()) { 4405 mAssociationEntryCount++; 4406 } 4407 } 4408 4409 if (mPrimaryItemId == 0) { 4410 if (firstVisibleItemId > 0) { 4411 ALOGW("didn't find primary, using first visible item"); 4412 mPrimaryItemId = firstVisibleItemId; 4413 } else { 4414 ALOGW("no primary and no visible item, using first item"); 4415 mPrimaryItemId = mItems[0].itemId; 4416 } 4417 } 4418 4419 beginBox("meta"); 4420 writeInt32(0); // Version = 0, Flags = 0 4421 writeHdlr("pict"); 4422 writeIlocBox(); 4423 writeIinfBox(); 4424 writePitmBox(); 4425 writeIprpBox(); 4426 if (mNumGrids > 0) { 4427 writeIdatBox(); 4428 writeIrefBox(); 4429 } 4430 endBox(); 4431} 4432 4433uint16_t MPEG4Writer::addProperty_l(const ItemProperty &prop) { 4434 char typeStr[5]; 4435 MakeFourCCString(prop.type, typeStr); 4436 ALOGV("addProperty_l: %s", typeStr); 4437 4438 mProperties.push_back(prop); 4439 4440 // returning 1-based property index 4441 return mProperties.size(); 4442} 4443 4444uint16_t MPEG4Writer::addItem_l(const ItemInfo &info) { 4445 ALOGV("addItem_l: type %s, offset %u, size %u", 4446 info.itemType, info.offset, info.size); 4447 4448 size_t index = mItems.size(); 4449 mItems.push_back(info); 4450 4451 // make the item id start at 10000 4452 mItems.editItemAt(index).itemId = index + 10000; 4453 4454#if (LOG_NDEBUG==0) 4455 if (!info.properties.empty()) { 4456 AString str; 4457 for (size_t i = 0; i < info.properties.size(); i++) { 4458 if (i > 0) { 4459 str.append(", "); 4460 } 4461 str.append(info.properties[i]); 4462 } 4463 ALOGV("addItem_l: id %d, properties: %s", mItems[index].itemId, str.c_str()); 4464 } 4465#endif // (LOG_NDEBUG==0) 4466 4467 return mItems[index].itemId; 4468} 4469 4470/* 4471 * Geodata is stored according to ISO-6709 standard. 4472 */ 4473void MPEG4Writer::writeGeoDataBox() { 4474 beginBox("\xA9xyz"); 4475 /* 4476 * For historical reasons, any user data start 4477 * with "\0xA9", must be followed by its assoicated 4478 * language code. 4479 * 0x0012: text string length 4480 * 0x15c7: lang (locale) code: en 4481 */ 4482 writeInt32(0x001215c7); 4483 writeLatitude(mLatitudex10000); 4484 writeLongitude(mLongitudex10000); 4485 writeInt8(0x2F); 4486 endBox(); 4487} 4488 4489} // namespace android 4490