MPEG4Writer.cpp revision a4d7b69074e5d7584bff2bbbfe4205979006f1ff
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 if (mProperties.empty()) { 1966 mProperties.push_back(mOwner->addProperty_l({ 1967 .type = FOURCC('h', 'v', 'c', 'C'), 1968 .hvcc = ABuffer::CreateAsCopy(mCodecSpecificData, mCodecSpecificDataSize) 1969 })); 1970 1971 mProperties.push_back(mOwner->addProperty_l({ 1972 .type = FOURCC('i', 's', 'p', 'e'), 1973 .width = (mNumTiles > 1) ? mGridWidth : mWidth, 1974 .height = (mNumTiles > 1) ? mGridHeight : mHeight, 1975 })); 1976 } 1977 1978 uint16_t itemId = mOwner->addItem_l({ 1979 .itemType = "hvc1", 1980 .isPrimary = (mNumTiles > 1) ? false : (mIsPrimary != 0), 1981 .isHidden = (mNumTiles > 1), 1982 .offset = (uint32_t)offset, 1983 .size = (uint32_t)size, 1984 .properties = mProperties, 1985 }); 1986 1987 mTileIndex++; 1988 if (mNumTiles > 1) { 1989 mDimgRefs.push_back(itemId); 1990 1991 if (mTileIndex == mNumTiles) { 1992 mProperties.clear(); 1993 mProperties.push_back(mOwner->addProperty_l({ 1994 .type = FOURCC('i', 's', 'p', 'e'), 1995 .width = mWidth, 1996 .height = mHeight, 1997 })); 1998 mOwner->addItem_l({ 1999 .itemType = "grid", 2000 .isPrimary = (mIsPrimary != 0), 2001 .isHidden = false, 2002 .rows = (uint32_t)mGridRows, 2003 .cols = (uint32_t)mGridCols, 2004 .width = (uint32_t)mWidth, 2005 .height = (uint32_t)mHeight, 2006 .properties = mProperties, 2007 .dimgRefs = mDimgRefs, 2008 }); 2009 } 2010 } 2011} 2012 2013void MPEG4Writer::Track::setTimeScale() { 2014 ALOGV("setTimeScale"); 2015 // Default time scale 2016 mTimeScale = 90000; 2017 2018 if (mIsAudio) { 2019 // Use the sampling rate as the default time scale for audio track. 2020 int32_t sampleRate; 2021 bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 2022 CHECK(success); 2023 mTimeScale = sampleRate; 2024 } 2025 2026 // If someone would like to overwrite the timescale, use user-supplied value. 2027 int32_t timeScale; 2028 if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 2029 mTimeScale = timeScale; 2030 } 2031 2032 CHECK_GT(mTimeScale, 0); 2033} 2034 2035void MPEG4Writer::onMessageReceived(const sp<AMessage> &msg) { 2036 switch (msg->what()) { 2037 case kWhatSwitch: 2038 { 2039 finishCurrentSession(); 2040 mLock.lock(); 2041 int fd = mNextFd; 2042 mNextFd = -1; 2043 mLock.unlock(); 2044 initInternal(fd, false /*isFirstSession*/); 2045 start(mStartMeta.get()); 2046 mSwitchPending = false; 2047 notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED, 0); 2048 break; 2049 } 2050 default: 2051 TRESPASS(); 2052 } 2053} 2054 2055void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 2056 const char *mime; 2057 2058 CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 2059 2060 uint32_t type; 2061 const void *data = NULL; 2062 size_t size = 0; 2063 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 2064 mMeta->findData(kKeyAVCC, &type, &data, &size); 2065 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) || 2066 !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) { 2067 mMeta->findData(kKeyHVCC, &type, &data, &size); 2068 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 2069 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 2070 if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 2071 ESDS esds(data, size); 2072 if (esds.getCodecSpecificInfo(&data, &size) == OK && 2073 data != NULL && 2074 copyCodecSpecificData((uint8_t*)data, size) == OK) { 2075 mGotAllCodecSpecificData = true; 2076 } 2077 return; 2078 } 2079 } 2080 if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) { 2081 mGotAllCodecSpecificData = true; 2082 } 2083} 2084 2085MPEG4Writer::Track::~Track() { 2086 stop(); 2087 2088 delete mStszTableEntries; 2089 delete mStcoTableEntries; 2090 delete mCo64TableEntries; 2091 delete mStscTableEntries; 2092 delete mSttsTableEntries; 2093 delete mStssTableEntries; 2094 delete mCttsTableEntries; 2095 2096 mStszTableEntries = NULL; 2097 mStcoTableEntries = NULL; 2098 mCo64TableEntries = NULL; 2099 mStscTableEntries = NULL; 2100 mSttsTableEntries = NULL; 2101 mStssTableEntries = NULL; 2102 mCttsTableEntries = NULL; 2103 2104 if (mCodecSpecificData != NULL) { 2105 free(mCodecSpecificData); 2106 mCodecSpecificData = NULL; 2107 } 2108} 2109 2110void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 2111 ALOGV("initTrackingProgressStatus"); 2112 mPreviousTrackTimeUs = -1; 2113 mTrackingProgressStatus = false; 2114 mTrackEveryTimeDurationUs = 0; 2115 { 2116 int64_t timeUs; 2117 if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 2118 ALOGV("Receive request to track progress status for every %" PRId64 " us", timeUs); 2119 mTrackEveryTimeDurationUs = timeUs; 2120 mTrackingProgressStatus = true; 2121 } 2122 } 2123} 2124 2125// static 2126void *MPEG4Writer::ThreadWrapper(void *me) { 2127 ALOGV("ThreadWrapper: %p", me); 2128 MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 2129 writer->threadFunc(); 2130 return NULL; 2131} 2132 2133void MPEG4Writer::bufferChunk(const Chunk& chunk) { 2134 ALOGV("bufferChunk: %p", chunk.mTrack); 2135 Mutex::Autolock autolock(mLock); 2136 CHECK_EQ(mDone, false); 2137 2138 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 2139 it != mChunkInfos.end(); ++it) { 2140 2141 if (chunk.mTrack == it->mTrack) { // Found owner 2142 it->mChunks.push_back(chunk); 2143 mChunkReadyCondition.signal(); 2144 return; 2145 } 2146 } 2147 2148 CHECK(!"Received a chunk for a unknown track"); 2149} 2150 2151void MPEG4Writer::writeChunkToFile(Chunk* chunk) { 2152 ALOGV("writeChunkToFile: %" PRId64 " from %s track", 2153 chunk->mTimeStampUs, chunk->mTrack->getTrackType()); 2154 2155 int32_t isFirstSample = true; 2156 bool usePrefix = chunk->mTrack->usePrefix(); 2157 while (!chunk->mSamples.empty()) { 2158 List<MediaBuffer *>::iterator it = chunk->mSamples.begin(); 2159 2160 size_t bytesWritten; 2161 off64_t offset = addSample_l(*it, usePrefix, &bytesWritten); 2162 2163 if (chunk->mTrack->isHeic()) { 2164 chunk->mTrack->addItemOffsetAndSize(offset, bytesWritten); 2165 } else if (isFirstSample) { 2166 chunk->mTrack->addChunkOffset(offset); 2167 isFirstSample = false; 2168 } 2169 2170 (*it)->release(); 2171 (*it) = NULL; 2172 chunk->mSamples.erase(it); 2173 } 2174 chunk->mSamples.clear(); 2175} 2176 2177void MPEG4Writer::writeAllChunks() { 2178 ALOGV("writeAllChunks"); 2179 size_t outstandingChunks = 0; 2180 Chunk chunk; 2181 while (findChunkToWrite(&chunk)) { 2182 writeChunkToFile(&chunk); 2183 ++outstandingChunks; 2184 } 2185 2186 sendSessionSummary(); 2187 2188 mChunkInfos.clear(); 2189 ALOGD("%zu chunks are written in the last batch", outstandingChunks); 2190} 2191 2192bool MPEG4Writer::findChunkToWrite(Chunk *chunk) { 2193 ALOGV("findChunkToWrite"); 2194 2195 int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 2196 Track *track = NULL; 2197 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 2198 it != mChunkInfos.end(); ++it) { 2199 if (!it->mChunks.empty()) { 2200 List<Chunk>::iterator chunkIt = it->mChunks.begin(); 2201 if (chunkIt->mTimeStampUs < minTimestampUs) { 2202 minTimestampUs = chunkIt->mTimeStampUs; 2203 track = it->mTrack; 2204 } 2205 } 2206 } 2207 2208 if (track == NULL) { 2209 ALOGV("Nothing to be written after all"); 2210 return false; 2211 } 2212 2213 if (mIsFirstChunk) { 2214 mIsFirstChunk = false; 2215 } 2216 2217 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 2218 it != mChunkInfos.end(); ++it) { 2219 if (it->mTrack == track) { 2220 *chunk = *(it->mChunks.begin()); 2221 it->mChunks.erase(it->mChunks.begin()); 2222 CHECK_EQ(chunk->mTrack, track); 2223 2224 int64_t interChunkTimeUs = 2225 chunk->mTimeStampUs - it->mPrevChunkTimestampUs; 2226 if (interChunkTimeUs > it->mPrevChunkTimestampUs) { 2227 it->mMaxInterChunkDurUs = interChunkTimeUs; 2228 } 2229 2230 return true; 2231 } 2232 } 2233 2234 return false; 2235} 2236 2237void MPEG4Writer::threadFunc() { 2238 ALOGV("threadFunc"); 2239 2240 prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0); 2241 2242 Mutex::Autolock autoLock(mLock); 2243 while (!mDone) { 2244 Chunk chunk; 2245 bool chunkFound = false; 2246 2247 while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) { 2248 mChunkReadyCondition.wait(mLock); 2249 } 2250 2251 // In real time recording mode, write without holding the lock in order 2252 // to reduce the blocking time for media track threads. 2253 // Otherwise, hold the lock until the existing chunks get written to the 2254 // file. 2255 if (chunkFound) { 2256 if (mIsRealTimeRecording) { 2257 mLock.unlock(); 2258 } 2259 writeChunkToFile(&chunk); 2260 if (mIsRealTimeRecording) { 2261 mLock.lock(); 2262 } 2263 } 2264 } 2265 2266 writeAllChunks(); 2267} 2268 2269status_t MPEG4Writer::startWriterThread() { 2270 ALOGV("startWriterThread"); 2271 2272 mDone = false; 2273 mIsFirstChunk = true; 2274 mDriftTimeUs = 0; 2275 for (List<Track *>::iterator it = mTracks.begin(); 2276 it != mTracks.end(); ++it) { 2277 ChunkInfo info; 2278 info.mTrack = *it; 2279 info.mPrevChunkTimestampUs = 0; 2280 info.mMaxInterChunkDurUs = 0; 2281 mChunkInfos.push_back(info); 2282 } 2283 2284 pthread_attr_t attr; 2285 pthread_attr_init(&attr); 2286 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 2287 pthread_create(&mThread, &attr, ThreadWrapper, this); 2288 pthread_attr_destroy(&attr); 2289 mWriterThreadStarted = true; 2290 return OK; 2291} 2292 2293 2294status_t MPEG4Writer::Track::start(MetaData *params) { 2295 if (!mDone && mPaused) { 2296 mPaused = false; 2297 mResumed = true; 2298 return OK; 2299 } 2300 2301 int64_t startTimeUs; 2302 if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 2303 startTimeUs = 0; 2304 } 2305 mStartTimeRealUs = startTimeUs; 2306 2307 int32_t rotationDegrees; 2308 if (mIsVideo && params && params->findInt32(kKeyRotation, &rotationDegrees)) { 2309 mRotation = rotationDegrees; 2310 } 2311 2312 initTrackingProgressStatus(params); 2313 2314 sp<MetaData> meta = new MetaData; 2315 if (mOwner->isRealTimeRecording() && mOwner->numTracks() > 1) { 2316 /* 2317 * This extra delay of accepting incoming audio/video signals 2318 * helps to align a/v start time at the beginning of a recording 2319 * session, and it also helps eliminate the "recording" sound for 2320 * camcorder applications. 2321 * 2322 * If client does not set the start time offset, we fall back to 2323 * use the default initial delay value. 2324 */ 2325 int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 2326 if (startTimeOffsetUs < 0) { // Start time offset was not set 2327 startTimeOffsetUs = kInitialDelayTimeUs; 2328 } 2329 startTimeUs += startTimeOffsetUs; 2330 ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs); 2331 } 2332 2333 meta->setInt64(kKeyTime, startTimeUs); 2334 2335 status_t err = mSource->start(meta.get()); 2336 if (err != OK) { 2337 mDone = mReachedEOS = true; 2338 return err; 2339 } 2340 2341 pthread_attr_t attr; 2342 pthread_attr_init(&attr); 2343 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 2344 2345 mDone = false; 2346 mStarted = true; 2347 mTrackDurationUs = 0; 2348 mReachedEOS = false; 2349 mEstimatedTrackSizeBytes = 0; 2350 mMdatSizeBytes = 0; 2351 mMaxChunkDurationUs = 0; 2352 mLastDecodingTimeUs = -1; 2353 2354 pthread_create(&mThread, &attr, ThreadWrapper, this); 2355 pthread_attr_destroy(&attr); 2356 2357 return OK; 2358} 2359 2360status_t MPEG4Writer::Track::pause() { 2361 mPaused = true; 2362 return OK; 2363} 2364 2365status_t MPEG4Writer::Track::stop(bool stopSource) { 2366 ALOGD("%s track stopping. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop"); 2367 if (!mStarted) { 2368 ALOGE("Stop() called but track is not started"); 2369 return ERROR_END_OF_STREAM; 2370 } 2371 2372 if (mDone) { 2373 return OK; 2374 } 2375 2376 if (stopSource) { 2377 ALOGD("%s track source stopping", getTrackType()); 2378 mSource->stop(); 2379 ALOGD("%s track source stopped", getTrackType()); 2380 } 2381 2382 // Set mDone to be true after sucessfully stop mSource as mSource may be still outputting 2383 // buffers to the writer. 2384 mDone = true; 2385 2386 void *dummy; 2387 pthread_join(mThread, &dummy); 2388 status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); 2389 2390 ALOGD("%s track stopped. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop"); 2391 return err; 2392} 2393 2394bool MPEG4Writer::Track::reachedEOS() { 2395 return mReachedEOS; 2396} 2397 2398// static 2399void *MPEG4Writer::Track::ThreadWrapper(void *me) { 2400 Track *track = static_cast<Track *>(me); 2401 2402 status_t err = track->threadEntry(); 2403 return (void *)(uintptr_t)err; 2404} 2405 2406static void getNalUnitType(uint8_t byte, uint8_t* type) { 2407 ALOGV("getNalUnitType: %d", byte); 2408 2409 // nal_unit_type: 5-bit unsigned integer 2410 *type = (byte & 0x1F); 2411} 2412 2413const uint8_t *MPEG4Writer::Track::parseParamSet( 2414 const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 2415 2416 ALOGV("parseParamSet"); 2417 CHECK(type == kNalUnitTypeSeqParamSet || 2418 type == kNalUnitTypePicParamSet); 2419 2420 const uint8_t *nextStartCode = findNextNalStartCode(data, length); 2421 *paramSetLen = nextStartCode - data; 2422 if (*paramSetLen == 0) { 2423 ALOGE("Param set is malformed, since its length is 0"); 2424 return NULL; 2425 } 2426 2427 AVCParamSet paramSet(*paramSetLen, data); 2428 if (type == kNalUnitTypeSeqParamSet) { 2429 if (*paramSetLen < 4) { 2430 ALOGE("Seq parameter set malformed"); 2431 return NULL; 2432 } 2433 if (mSeqParamSets.empty()) { 2434 mProfileIdc = data[1]; 2435 mProfileCompatible = data[2]; 2436 mLevelIdc = data[3]; 2437 } else { 2438 if (mProfileIdc != data[1] || 2439 mProfileCompatible != data[2] || 2440 mLevelIdc != data[3]) { 2441 // COULD DO: set profile/level to the lowest required to support all SPSs 2442 ALOGE("Inconsistent profile/level found in seq parameter sets"); 2443 return NULL; 2444 } 2445 } 2446 mSeqParamSets.push_back(paramSet); 2447 } else { 2448 mPicParamSets.push_back(paramSet); 2449 } 2450 return nextStartCode; 2451} 2452 2453status_t MPEG4Writer::Track::copyAVCCodecSpecificData( 2454 const uint8_t *data, size_t size) { 2455 ALOGV("copyAVCCodecSpecificData"); 2456 2457 // 2 bytes for each of the parameter set length field 2458 // plus the 7 bytes for the header 2459 return copyCodecSpecificData(data, size, 4 + 7); 2460} 2461 2462status_t MPEG4Writer::Track::copyHEVCCodecSpecificData( 2463 const uint8_t *data, size_t size) { 2464 ALOGV("copyHEVCCodecSpecificData"); 2465 2466 // Min length of HEVC CSD is 23. (ISO/IEC 14496-15:2014 Chapter 8.3.3.1.2) 2467 return copyCodecSpecificData(data, size, 23); 2468} 2469 2470status_t MPEG4Writer::Track::copyCodecSpecificData( 2471 const uint8_t *data, size_t size, size_t minLength) { 2472 if (size < minLength) { 2473 ALOGE("Codec specific data length too short: %zu", size); 2474 return ERROR_MALFORMED; 2475 } 2476 2477 mCodecSpecificData = malloc(size); 2478 if (mCodecSpecificData == NULL) { 2479 ALOGE("Failed allocating codec specific data"); 2480 return NO_MEMORY; 2481 } 2482 mCodecSpecificDataSize = size; 2483 memcpy(mCodecSpecificData, data, size); 2484 return OK; 2485} 2486 2487status_t MPEG4Writer::Track::parseAVCCodecSpecificData( 2488 const uint8_t *data, size_t size) { 2489 2490 ALOGV("parseAVCCodecSpecificData"); 2491 // Data starts with a start code. 2492 // SPS and PPS are separated with start codes. 2493 // Also, SPS must come before PPS 2494 uint8_t type = kNalUnitTypeSeqParamSet; 2495 bool gotSps = false; 2496 bool gotPps = false; 2497 const uint8_t *tmp = data; 2498 const uint8_t *nextStartCode = data; 2499 size_t bytesLeft = size; 2500 size_t paramSetLen = 0; 2501 mCodecSpecificDataSize = 0; 2502 while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 2503 getNalUnitType(*(tmp + 4), &type); 2504 if (type == kNalUnitTypeSeqParamSet) { 2505 if (gotPps) { 2506 ALOGE("SPS must come before PPS"); 2507 return ERROR_MALFORMED; 2508 } 2509 if (!gotSps) { 2510 gotSps = true; 2511 } 2512 nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 2513 } else if (type == kNalUnitTypePicParamSet) { 2514 if (!gotSps) { 2515 ALOGE("SPS must come before PPS"); 2516 return ERROR_MALFORMED; 2517 } 2518 if (!gotPps) { 2519 gotPps = true; 2520 } 2521 nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 2522 } else { 2523 ALOGE("Only SPS and PPS Nal units are expected"); 2524 return ERROR_MALFORMED; 2525 } 2526 2527 if (nextStartCode == NULL) { 2528 return ERROR_MALFORMED; 2529 } 2530 2531 // Move on to find the next parameter set 2532 bytesLeft -= nextStartCode - tmp; 2533 tmp = nextStartCode; 2534 mCodecSpecificDataSize += (2 + paramSetLen); 2535 } 2536 2537 { 2538 // Check on the number of seq parameter sets 2539 size_t nSeqParamSets = mSeqParamSets.size(); 2540 if (nSeqParamSets == 0) { 2541 ALOGE("Cound not find sequence parameter set"); 2542 return ERROR_MALFORMED; 2543 } 2544 2545 if (nSeqParamSets > 0x1F) { 2546 ALOGE("Too many seq parameter sets (%zu) found", nSeqParamSets); 2547 return ERROR_MALFORMED; 2548 } 2549 } 2550 2551 { 2552 // Check on the number of pic parameter sets 2553 size_t nPicParamSets = mPicParamSets.size(); 2554 if (nPicParamSets == 0) { 2555 ALOGE("Cound not find picture parameter set"); 2556 return ERROR_MALFORMED; 2557 } 2558 if (nPicParamSets > 0xFF) { 2559 ALOGE("Too many pic parameter sets (%zd) found", nPicParamSets); 2560 return ERROR_MALFORMED; 2561 } 2562 } 2563// FIXME: 2564// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above 2565// and remove #if 0 2566#if 0 2567 { 2568 // Check on the profiles 2569 // These profiles requires additional parameter set extensions 2570 if (mProfileIdc == 100 || mProfileIdc == 110 || 2571 mProfileIdc == 122 || mProfileIdc == 144) { 2572 ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 2573 return BAD_VALUE; 2574 } 2575 } 2576#endif 2577 return OK; 2578} 2579 2580status_t MPEG4Writer::Track::makeAVCCodecSpecificData( 2581 const uint8_t *data, size_t size) { 2582 2583 if (mCodecSpecificData != NULL) { 2584 ALOGE("Already have codec specific data"); 2585 return ERROR_MALFORMED; 2586 } 2587 2588 if (size < 4) { 2589 ALOGE("Codec specific data length too short: %zu", size); 2590 return ERROR_MALFORMED; 2591 } 2592 2593 // Data is in the form of AVCCodecSpecificData 2594 if (memcmp("\x00\x00\x00\x01", data, 4)) { 2595 return copyAVCCodecSpecificData(data, size); 2596 } 2597 2598 if (parseAVCCodecSpecificData(data, size) != OK) { 2599 return ERROR_MALFORMED; 2600 } 2601 2602 // ISO 14496-15: AVC file format 2603 mCodecSpecificDataSize += 7; // 7 more bytes in the header 2604 mCodecSpecificData = malloc(mCodecSpecificDataSize); 2605 if (mCodecSpecificData == NULL) { 2606 mCodecSpecificDataSize = 0; 2607 ALOGE("Failed allocating codec specific data"); 2608 return NO_MEMORY; 2609 } 2610 uint8_t *header = (uint8_t *)mCodecSpecificData; 2611 header[0] = 1; // version 2612 header[1] = mProfileIdc; // profile indication 2613 header[2] = mProfileCompatible; // profile compatibility 2614 header[3] = mLevelIdc; 2615 2616 // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 2617 if (mOwner->useNalLengthFour()) { 2618 header[4] = 0xfc | 3; // length size == 4 bytes 2619 } else { 2620 header[4] = 0xfc | 1; // length size == 2 bytes 2621 } 2622 2623 // 3-bit '111' followed by 5-bit numSequenceParameterSets 2624 int nSequenceParamSets = mSeqParamSets.size(); 2625 header[5] = 0xe0 | nSequenceParamSets; 2626 header += 6; 2627 for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 2628 it != mSeqParamSets.end(); ++it) { 2629 // 16-bit sequence parameter set length 2630 uint16_t seqParamSetLength = it->mLength; 2631 header[0] = seqParamSetLength >> 8; 2632 header[1] = seqParamSetLength & 0xff; 2633 2634 // SPS NAL unit (sequence parameter length bytes) 2635 memcpy(&header[2], it->mData, seqParamSetLength); 2636 header += (2 + seqParamSetLength); 2637 } 2638 2639 // 8-bit nPictureParameterSets 2640 int nPictureParamSets = mPicParamSets.size(); 2641 header[0] = nPictureParamSets; 2642 header += 1; 2643 for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 2644 it != mPicParamSets.end(); ++it) { 2645 // 16-bit picture parameter set length 2646 uint16_t picParamSetLength = it->mLength; 2647 header[0] = picParamSetLength >> 8; 2648 header[1] = picParamSetLength & 0xff; 2649 2650 // PPS Nal unit (picture parameter set length bytes) 2651 memcpy(&header[2], it->mData, picParamSetLength); 2652 header += (2 + picParamSetLength); 2653 } 2654 2655 return OK; 2656} 2657 2658 2659status_t MPEG4Writer::Track::parseHEVCCodecSpecificData( 2660 const uint8_t *data, size_t size, HevcParameterSets ¶mSets) { 2661 2662 ALOGV("parseHEVCCodecSpecificData"); 2663 const uint8_t *tmp = data; 2664 const uint8_t *nextStartCode = data; 2665 size_t bytesLeft = size; 2666 while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 2667 nextStartCode = findNextNalStartCode(tmp + 4, bytesLeft - 4); 2668 status_t err = paramSets.addNalUnit(tmp + 4, (nextStartCode - tmp) - 4); 2669 if (err != OK) { 2670 return ERROR_MALFORMED; 2671 } 2672 2673 // Move on to find the next parameter set 2674 bytesLeft -= nextStartCode - tmp; 2675 tmp = nextStartCode; 2676 } 2677 2678 size_t csdSize = 23; 2679 const size_t numNalUnits = paramSets.getNumNalUnits(); 2680 for (size_t i = 0; i < ARRAY_SIZE(kMandatoryHevcNalUnitTypes); ++i) { 2681 int type = kMandatoryHevcNalUnitTypes[i]; 2682 size_t numParamSets = paramSets.getNumNalUnitsOfType(type); 2683 if (numParamSets == 0) { 2684 ALOGE("Cound not find NAL unit of type %d", type); 2685 return ERROR_MALFORMED; 2686 } 2687 } 2688 for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) { 2689 int type = kHevcNalUnitTypes[i]; 2690 size_t numParamSets = paramSets.getNumNalUnitsOfType(type); 2691 if (numParamSets > 0xffff) { 2692 ALOGE("Too many seq parameter sets (%zu) found", numParamSets); 2693 return ERROR_MALFORMED; 2694 } 2695 csdSize += 3; 2696 for (size_t j = 0; j < numNalUnits; ++j) { 2697 if (paramSets.getType(j) != type) { 2698 continue; 2699 } 2700 csdSize += 2 + paramSets.getSize(j); 2701 } 2702 } 2703 mCodecSpecificDataSize = csdSize; 2704 return OK; 2705} 2706 2707status_t MPEG4Writer::Track::makeHEVCCodecSpecificData( 2708 const uint8_t *data, size_t size) { 2709 2710 if (mCodecSpecificData != NULL) { 2711 ALOGE("Already have codec specific data"); 2712 return ERROR_MALFORMED; 2713 } 2714 2715 if (size < 4) { 2716 ALOGE("Codec specific data length too short: %zu", size); 2717 return ERROR_MALFORMED; 2718 } 2719 2720 // Data is in the form of HEVCCodecSpecificData 2721 if (memcmp("\x00\x00\x00\x01", data, 4)) { 2722 return copyHEVCCodecSpecificData(data, size); 2723 } 2724 2725 HevcParameterSets paramSets; 2726 if (parseHEVCCodecSpecificData(data, size, paramSets) != OK) { 2727 ALOGE("failed parsing codec specific data"); 2728 return ERROR_MALFORMED; 2729 } 2730 2731 mCodecSpecificData = malloc(mCodecSpecificDataSize); 2732 if (mCodecSpecificData == NULL) { 2733 mCodecSpecificDataSize = 0; 2734 ALOGE("Failed allocating codec specific data"); 2735 return NO_MEMORY; 2736 } 2737 status_t err = paramSets.makeHvcc((uint8_t *)mCodecSpecificData, 2738 &mCodecSpecificDataSize, mOwner->useNalLengthFour() ? 4 : 2); 2739 if (err != OK) { 2740 ALOGE("failed constructing HVCC atom"); 2741 return err; 2742 } 2743 2744 return OK; 2745} 2746 2747/* 2748 * Updates the drift time from the audio track so that 2749 * the video track can get the updated drift time information 2750 * from the file writer. The fluctuation of the drift time of the audio 2751 * encoding path is smoothed out with a simple filter by giving a larger 2752 * weight to more recently drift time. The filter coefficients, 0.5 and 0.5, 2753 * are heuristically determined. 2754 */ 2755void MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) { 2756 int64_t driftTimeUs = 0; 2757 if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) { 2758 int64_t prevDriftTimeUs = mOwner->getDriftTimeUs(); 2759 int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1; 2760 mOwner->setDriftTimeUs(timeUs); 2761 } 2762} 2763 2764void MPEG4Writer::Track::dumpTimeStamps() { 2765 ALOGE("Dumping %s track's last 10 frames timestamp and frame type ", getTrackType()); 2766 std::string timeStampString; 2767 for (std::list<TimestampDebugHelperEntry>::iterator entry = mTimestampDebugHelper.begin(); 2768 entry != mTimestampDebugHelper.end(); ++entry) { 2769 timeStampString += "(" + std::to_string(entry->pts)+ 2770 "us, " + std::to_string(entry->dts) + "us " + entry->frameType + ") "; 2771 } 2772 ALOGE("%s", timeStampString.c_str()); 2773} 2774 2775status_t MPEG4Writer::Track::threadEntry() { 2776 int32_t count = 0; 2777 const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 2778 const bool hasMultipleTracks = (mOwner->numTracks() > 1); 2779 int64_t chunkTimestampUs = 0; 2780 int32_t nChunks = 0; 2781 int32_t nActualFrames = 0; // frames containing non-CSD data (non-0 length) 2782 int32_t nZeroLengthFrames = 0; 2783 int64_t lastTimestampUs = 0; // Previous sample time stamp 2784 int64_t lastDurationUs = 0; // Between the previous two samples 2785 int64_t currDurationTicks = 0; // Timescale based ticks 2786 int64_t lastDurationTicks = 0; // Timescale based ticks 2787 int32_t sampleCount = 1; // Sample count in the current stts table entry 2788 uint32_t previousSampleSize = 0; // Size of the previous sample 2789 int64_t previousPausedDurationUs = 0; 2790 int64_t timestampUs = 0; 2791 int64_t cttsOffsetTimeUs = 0; 2792 int64_t currCttsOffsetTimeTicks = 0; // Timescale based ticks 2793 int64_t lastCttsOffsetTimeTicks = -1; // Timescale based ticks 2794 int32_t cttsSampleCount = 0; // Sample count in the current ctts table entry 2795 uint32_t lastSamplesPerChunk = 0; 2796 2797 if (mIsAudio) { 2798 prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0); 2799 } else if (mIsVideo) { 2800 prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0); 2801 } else { 2802 prctl(PR_SET_NAME, (unsigned long)"MetadataTrackEncoding", 0, 0, 0); 2803 } 2804 2805 if (mOwner->isRealTimeRecording()) { 2806 androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO); 2807 } 2808 2809 sp<MetaData> meta_data; 2810 2811 status_t err = OK; 2812 MediaBuffer *buffer; 2813 const char *trackName = getTrackType(); 2814 while (!mDone && (err = mSource->read(&buffer)) == OK) { 2815 if (buffer->range_length() == 0) { 2816 buffer->release(); 2817 buffer = NULL; 2818 ++nZeroLengthFrames; 2819 continue; 2820 } 2821 2822 // If the codec specific data has not been received yet, delay pause. 2823 // After the codec specific data is received, discard what we received 2824 // when the track is to be paused. 2825 if (mPaused && !mResumed) { 2826 buffer->release(); 2827 buffer = NULL; 2828 continue; 2829 } 2830 2831 ++count; 2832 2833 int32_t isCodecConfig; 2834 if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 2835 && isCodecConfig) { 2836 // if config format (at track addition) already had CSD, keep that 2837 // UNLESS we have not received any frames yet. 2838 // TODO: for now the entire CSD has to come in one frame for encoders, even though 2839 // they need to be spread out for decoders. 2840 if (mGotAllCodecSpecificData && nActualFrames > 0) { 2841 ALOGI("ignoring additional CSD for video track after first frame"); 2842 } else { 2843 mMeta = mSource->getFormat(); // get output format after format change 2844 status_t err; 2845 if (mIsAvc) { 2846 err = makeAVCCodecSpecificData( 2847 (const uint8_t *)buffer->data() 2848 + buffer->range_offset(), 2849 buffer->range_length()); 2850 } else if (mIsHevc || mIsHeic) { 2851 err = makeHEVCCodecSpecificData( 2852 (const uint8_t *)buffer->data() 2853 + buffer->range_offset(), 2854 buffer->range_length()); 2855 } else if (mIsMPEG4) { 2856 copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(), 2857 buffer->range_length()); 2858 } 2859 } 2860 2861 buffer->release(); 2862 buffer = NULL; 2863 if (OK != err) { 2864 mSource->stop(); 2865 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, 2866 mTrackId | MEDIA_RECORDER_TRACK_ERROR_GENERAL, err); 2867 break; 2868 } 2869 2870 mGotAllCodecSpecificData = true; 2871 continue; 2872 } 2873 2874 // Per-frame metadata sample's size must be smaller than max allowed. 2875 if (!mIsVideo && !mIsAudio && !mIsHeic && 2876 buffer->range_length() >= kMaxMetadataSize) { 2877 ALOGW("Buffer size is %zu. Maximum metadata buffer size is %lld for %s track", 2878 buffer->range_length(), (long long)kMaxMetadataSize, trackName); 2879 buffer->release(); 2880 mSource->stop(); 2881 mIsMalformed = true; 2882 break; 2883 } 2884 2885 ++nActualFrames; 2886 2887 // Make a deep copy of the MediaBuffer and Metadata and release 2888 // the original as soon as we can 2889 MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 2890 memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 2891 buffer->range_length()); 2892 copy->set_range(0, buffer->range_length()); 2893 meta_data = new MetaData(*buffer->meta_data().get()); 2894 buffer->release(); 2895 buffer = NULL; 2896 2897 if (usePrefix()) StripStartcode(copy); 2898 2899 size_t sampleSize = copy->range_length(); 2900 if (usePrefix()) { 2901 if (mOwner->useNalLengthFour()) { 2902 sampleSize += 4; 2903 } else { 2904 sampleSize += 2; 2905 } 2906 } 2907 2908 // Max file size or duration handling 2909 mMdatSizeBytes += sampleSize; 2910 updateTrackSizeEstimate(); 2911 2912 if (mOwner->exceedsFileSizeLimit()) { 2913 if (mOwner->switchFd() != OK) { 2914 ALOGW("Recorded file size exceeds limit %" PRId64 "bytes", 2915 mOwner->mMaxFileSizeLimitBytes); 2916 mSource->stop(); 2917 mOwner->notify( 2918 MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 2919 } else { 2920 ALOGV("%s Current recorded file size exceeds limit %" PRId64 "bytes. Switching output", 2921 getTrackType(), mOwner->mMaxFileSizeLimitBytes); 2922 } 2923 copy->release(); 2924 break; 2925 } 2926 2927 if (mOwner->exceedsFileDurationLimit()) { 2928 ALOGW("Recorded file duration exceeds limit %" PRId64 "microseconds", 2929 mOwner->mMaxFileDurationLimitUs); 2930 mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 2931 copy->release(); 2932 mSource->stop(); 2933 break; 2934 } 2935 2936 if (mOwner->approachingFileSizeLimit()) { 2937 mOwner->notifyApproachingLimit(); 2938 } 2939 2940 int32_t isSync = false; 2941 meta_data->findInt32(kKeyIsSyncFrame, &isSync); 2942 CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 2943 2944 // For video, skip the first several non-key frames until getting the first key frame. 2945 if (mIsVideo && !mGotStartKeyFrame && !isSync) { 2946 ALOGD("Video skip non-key frame"); 2947 copy->release(); 2948 continue; 2949 } 2950 if (mIsVideo && isSync) { 2951 mGotStartKeyFrame = true; 2952 } 2953//////////////////////////////////////////////////////////////////////////////// 2954 2955 if (!mIsHeic) { 2956 if (mStszTableEntries->count() == 0) { 2957 mFirstSampleTimeRealUs = systemTime() / 1000; 2958 mStartTimestampUs = timestampUs; 2959 mOwner->setStartTimestampUs(mStartTimestampUs); 2960 previousPausedDurationUs = mStartTimestampUs; 2961 } 2962 2963 if (mResumed) { 2964 int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 2965 if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) { 2966 copy->release(); 2967 mSource->stop(); 2968 mIsMalformed = true; 2969 break; 2970 } 2971 2972 int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 2973 if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) { 2974 copy->release(); 2975 mSource->stop(); 2976 mIsMalformed = true; 2977 break; 2978 } 2979 2980 previousPausedDurationUs += pausedDurationUs - lastDurationUs; 2981 mResumed = false; 2982 } 2983 TimestampDebugHelperEntry timestampDebugEntry; 2984 timestampUs -= previousPausedDurationUs; 2985 timestampDebugEntry.pts = timestampUs; 2986 if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { 2987 copy->release(); 2988 mSource->stop(); 2989 mIsMalformed = true; 2990 break; 2991 } 2992 2993 if (mIsVideo) { 2994 /* 2995 * Composition time: timestampUs 2996 * Decoding time: decodingTimeUs 2997 * Composition time offset = composition time - decoding time 2998 */ 2999 int64_t decodingTimeUs; 3000 CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs)); 3001 decodingTimeUs -= previousPausedDurationUs; 3002 3003 // ensure non-negative, monotonic decoding time 3004 if (mLastDecodingTimeUs < 0) { 3005 decodingTimeUs = std::max((int64_t)0, decodingTimeUs); 3006 } else { 3007 // increase decoding time by at least the larger vaule of 1 tick and 3008 // 0.1 milliseconds. This needs to take into account the possible 3009 // delta adjustment in DurationTicks in below. 3010 decodingTimeUs = std::max(mLastDecodingTimeUs + 3011 std::max(100, divUp(1000000, mTimeScale)), decodingTimeUs); 3012 } 3013 3014 mLastDecodingTimeUs = decodingTimeUs; 3015 timestampDebugEntry.dts = decodingTimeUs; 3016 timestampDebugEntry.frameType = isSync ? "Key frame" : "Non-Key frame"; 3017 // Insert the timestamp into the mTimestampDebugHelper 3018 if (mTimestampDebugHelper.size() >= kTimestampDebugCount) { 3019 mTimestampDebugHelper.pop_front(); 3020 } 3021 mTimestampDebugHelper.push_back(timestampDebugEntry); 3022 3023 cttsOffsetTimeUs = 3024 timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs; 3025 if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) { 3026 copy->release(); 3027 mSource->stop(); 3028 mIsMalformed = true; 3029 break; 3030 } 3031 3032 timestampUs = decodingTimeUs; 3033 ALOGV("decoding time: %" PRId64 " and ctts offset time: %" PRId64, 3034 timestampUs, cttsOffsetTimeUs); 3035 3036 // Update ctts box table if necessary 3037 currCttsOffsetTimeTicks = 3038 (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL; 3039 if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) { 3040 copy->release(); 3041 mSource->stop(); 3042 mIsMalformed = true; 3043 break; 3044 } 3045 3046 if (mStszTableEntries->count() == 0) { 3047 // Force the first ctts table entry to have one single entry 3048 // so that we can do adjustment for the initial track start 3049 // time offset easily in writeCttsBox(). 3050 lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks; 3051 addOneCttsTableEntry(1, currCttsOffsetTimeTicks); 3052 cttsSampleCount = 0; // No sample in ctts box is pending 3053 } else { 3054 if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) { 3055 addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks); 3056 lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks; 3057 cttsSampleCount = 1; // One sample in ctts box is pending 3058 } else { 3059 ++cttsSampleCount; 3060 } 3061 } 3062 3063 // Update ctts time offset range 3064 if (mStszTableEntries->count() == 0) { 3065 mMinCttsOffsetTicks = currCttsOffsetTimeTicks; 3066 mMaxCttsOffsetTicks = currCttsOffsetTimeTicks; 3067 } else { 3068 if (currCttsOffsetTimeTicks > mMaxCttsOffsetTicks) { 3069 mMaxCttsOffsetTicks = currCttsOffsetTimeTicks; 3070 } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTicks) { 3071 mMinCttsOffsetTicks = currCttsOffsetTimeTicks; 3072 mMinCttsOffsetTimeUs = cttsOffsetTimeUs; 3073 } 3074 } 3075 } 3076 3077 if (mOwner->isRealTimeRecording()) { 3078 if (mIsAudio) { 3079 updateDriftTime(meta_data); 3080 } 3081 } 3082 3083 if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { 3084 copy->release(); 3085 mSource->stop(); 3086 mIsMalformed = true; 3087 break; 3088 } 3089 3090 ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64, 3091 trackName, timestampUs, previousPausedDurationUs); 3092 if (timestampUs > mTrackDurationUs) { 3093 mTrackDurationUs = timestampUs; 3094 } 3095 3096 // We need to use the time scale based ticks, rather than the 3097 // timestamp itself to determine whether we have to use a new 3098 // stts entry, since we may have rounding errors. 3099 // The calculation is intended to reduce the accumulated 3100 // rounding errors. 3101 currDurationTicks = 3102 ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 3103 (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 3104 if (currDurationTicks < 0ll) { 3105 ALOGE("do not support out of order frames (timestamp: %lld < last: %lld for %s track", 3106 (long long)timestampUs, (long long)lastTimestampUs, trackName); 3107 copy->release(); 3108 mSource->stop(); 3109 mIsMalformed = true; 3110 break; 3111 } 3112 3113 // if the duration is different for this sample, see if it is close enough to the previous 3114 // duration that we can fudge it and use the same value, to avoid filling the stts table 3115 // with lots of near-identical entries. 3116 // "close enough" here means that the current duration needs to be adjusted by less 3117 // than 0.1 milliseconds 3118 if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) { 3119 int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL 3120 + (mTimeScale / 2)) / mTimeScale; 3121 if (deltaUs > -100 && deltaUs < 100) { 3122 // use previous ticks, and adjust timestamp as if it was actually that number 3123 // of ticks 3124 currDurationTicks = lastDurationTicks; 3125 timestampUs += deltaUs; 3126 } 3127 } 3128 mStszTableEntries->add(htonl(sampleSize)); 3129 if (mStszTableEntries->count() > 2) { 3130 3131 // Force the first sample to have its own stts entry so that 3132 // we can adjust its value later to maintain the A/V sync. 3133 if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) { 3134 addOneSttsTableEntry(sampleCount, lastDurationTicks); 3135 sampleCount = 1; 3136 } else { 3137 ++sampleCount; 3138 } 3139 3140 } 3141 if (mSamplesHaveSameSize) { 3142 if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) { 3143 mSamplesHaveSameSize = false; 3144 } 3145 previousSampleSize = sampleSize; 3146 } 3147 ALOGV("%s timestampUs/lastTimestampUs: %" PRId64 "/%" PRId64, 3148 trackName, timestampUs, lastTimestampUs); 3149 lastDurationUs = timestampUs - lastTimestampUs; 3150 lastDurationTicks = currDurationTicks; 3151 lastTimestampUs = timestampUs; 3152 3153 if (isSync != 0) { 3154 addOneStssTableEntry(mStszTableEntries->count()); 3155 } 3156 3157 if (mTrackingProgressStatus) { 3158 if (mPreviousTrackTimeUs <= 0) { 3159 mPreviousTrackTimeUs = mStartTimestampUs; 3160 } 3161 trackProgressStatus(timestampUs); 3162 } 3163 } 3164 if (!hasMultipleTracks) { 3165 size_t bytesWritten; 3166 off64_t offset = mOwner->addSample_l(copy, usePrefix(), &bytesWritten); 3167 3168 if (mIsHeic) { 3169 addItemOffsetAndSize(offset, bytesWritten); 3170 } else { 3171 uint32_t count = (mOwner->use32BitFileOffset() 3172 ? mStcoTableEntries->count() 3173 : mCo64TableEntries->count()); 3174 3175 if (count == 0) { 3176 addChunkOffset(offset); 3177 } 3178 } 3179 copy->release(); 3180 copy = NULL; 3181 continue; 3182 } 3183 3184 mChunkSamples.push_back(copy); 3185 if (mIsHeic) { 3186 bufferChunk(0 /*timestampUs*/); 3187 ++nChunks; 3188 } else if (interleaveDurationUs == 0) { 3189 addOneStscTableEntry(++nChunks, 1); 3190 bufferChunk(timestampUs); 3191 } else { 3192 if (chunkTimestampUs == 0) { 3193 chunkTimestampUs = timestampUs; 3194 } else { 3195 int64_t chunkDurationUs = timestampUs - chunkTimestampUs; 3196 if (chunkDurationUs > interleaveDurationUs) { 3197 if (chunkDurationUs > mMaxChunkDurationUs) { 3198 mMaxChunkDurationUs = chunkDurationUs; 3199 } 3200 ++nChunks; 3201 if (nChunks == 1 || // First chunk 3202 lastSamplesPerChunk != mChunkSamples.size()) { 3203 lastSamplesPerChunk = mChunkSamples.size(); 3204 addOneStscTableEntry(nChunks, lastSamplesPerChunk); 3205 } 3206 bufferChunk(timestampUs); 3207 chunkTimestampUs = timestampUs; 3208 } 3209 } 3210 } 3211 3212 } 3213 3214 if (isTrackMalFormed()) { 3215 dumpTimeStamps(); 3216 err = ERROR_MALFORMED; 3217 } 3218 3219 mOwner->trackProgressStatus(mTrackId, -1, err); 3220 3221 if (mIsHeic) { 3222 if (!mChunkSamples.empty()) { 3223 bufferChunk(0); 3224 ++nChunks; 3225 } 3226 } else { 3227 // Last chunk 3228 if (!hasMultipleTracks) { 3229 addOneStscTableEntry(1, mStszTableEntries->count()); 3230 } else if (!mChunkSamples.empty()) { 3231 addOneStscTableEntry(++nChunks, mChunkSamples.size()); 3232 bufferChunk(timestampUs); 3233 } 3234 3235 // We don't really know how long the last frame lasts, since 3236 // there is no frame time after it, just repeat the previous 3237 // frame's duration. 3238 if (mStszTableEntries->count() == 1) { 3239 lastDurationUs = 0; // A single sample's duration 3240 lastDurationTicks = 0; 3241 } else { 3242 ++sampleCount; // Count for the last sample 3243 } 3244 3245 if (mStszTableEntries->count() <= 2) { 3246 addOneSttsTableEntry(1, lastDurationTicks); 3247 if (sampleCount - 1 > 0) { 3248 addOneSttsTableEntry(sampleCount - 1, lastDurationTicks); 3249 } 3250 } else { 3251 addOneSttsTableEntry(sampleCount, lastDurationTicks); 3252 } 3253 3254 // The last ctts box may not have been written yet, and this 3255 // is to make sure that we write out the last ctts box. 3256 if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) { 3257 if (cttsSampleCount > 0) { 3258 addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks); 3259 } 3260 } 3261 3262 mTrackDurationUs += lastDurationUs; 3263 } 3264 mReachedEOS = true; 3265 3266 sendTrackSummary(hasMultipleTracks); 3267 3268 ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", 3269 count, nZeroLengthFrames, mStszTableEntries->count(), trackName); 3270 if (mIsAudio) { 3271 ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs()); 3272 } 3273 3274 if (err == ERROR_END_OF_STREAM) { 3275 return OK; 3276 } 3277 return err; 3278} 3279 3280bool MPEG4Writer::Track::isTrackMalFormed() const { 3281 if (mIsMalformed) { 3282 return true; 3283 } 3284 3285 if (!mIsHeic && mStszTableEntries->count() == 0) { // no samples written 3286 ALOGE("The number of recorded samples is 0"); 3287 return true; 3288 } 3289 3290 if (mIsVideo && mStssTableEntries->count() == 0) { // no sync frames for video 3291 ALOGE("There are no sync frames for video track"); 3292 return true; 3293 } 3294 3295 if (OK != checkCodecSpecificData()) { // no codec specific data 3296 return true; 3297 } 3298 3299 return false; 3300} 3301 3302void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { 3303 3304 // Send track summary only if test mode is enabled. 3305 if (!isTestModeEnabled()) { 3306 return; 3307 } 3308 3309 int trackNum = (mTrackId << 28); 3310 3311 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3312 trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE, 3313 mIsAudio ? 0: 1); 3314 3315 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3316 trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS, 3317 mTrackDurationUs / 1000); 3318 3319 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3320 trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES, 3321 mStszTableEntries->count()); 3322 3323 { 3324 // The system delay time excluding the requested initial delay that 3325 // is used to eliminate the recording sound. 3326 int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 3327 if (startTimeOffsetUs < 0) { // Start time offset was not set 3328 startTimeOffsetUs = kInitialDelayTimeUs; 3329 } 3330 int64_t initialDelayUs = 3331 mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs; 3332 3333 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3334 trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS, 3335 (initialDelayUs) / 1000); 3336 } 3337 3338 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3339 trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES, 3340 mMdatSizeBytes / 1024); 3341 3342 if (hasMultipleTracks) { 3343 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3344 trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS, 3345 mMaxChunkDurationUs / 1000); 3346 3347 int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 3348 if (mStartTimestampUs != moovStartTimeUs) { 3349 int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 3350 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3351 trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS, 3352 startTimeOffsetUs / 1000); 3353 } 3354 } 3355} 3356 3357void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 3358 ALOGV("trackProgressStatus: %" PRId64 " us", timeUs); 3359 3360 if (mTrackEveryTimeDurationUs > 0 && 3361 timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 3362 ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs); 3363 mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); 3364 mPreviousTrackTimeUs = timeUs; 3365 } 3366} 3367 3368void MPEG4Writer::trackProgressStatus( 3369 size_t trackId, int64_t timeUs, status_t err) { 3370 Mutex::Autolock lock(mLock); 3371 int32_t trackNum = (trackId << 28); 3372 3373 // Error notification 3374 // Do not consider ERROR_END_OF_STREAM an error 3375 if (err != OK && err != ERROR_END_OF_STREAM) { 3376 notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, 3377 trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL, 3378 err); 3379 return; 3380 } 3381 3382 if (timeUs == -1) { 3383 // Send completion notification 3384 notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3385 trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, 3386 err); 3387 } else { 3388 // Send progress status 3389 notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 3390 trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME, 3391 timeUs / 1000); 3392 } 3393} 3394 3395void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { 3396 ALOGV("setDriftTimeUs: %" PRId64 " us", driftTimeUs); 3397 Mutex::Autolock autolock(mLock); 3398 mDriftTimeUs = driftTimeUs; 3399} 3400 3401int64_t MPEG4Writer::getDriftTimeUs() { 3402 ALOGV("getDriftTimeUs: %" PRId64 " us", mDriftTimeUs); 3403 Mutex::Autolock autolock(mLock); 3404 return mDriftTimeUs; 3405} 3406 3407bool MPEG4Writer::isRealTimeRecording() const { 3408 return mIsRealTimeRecording; 3409} 3410 3411bool MPEG4Writer::useNalLengthFour() { 3412 return mUse4ByteNalLength; 3413} 3414 3415void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 3416 ALOGV("bufferChunk"); 3417 3418 Chunk chunk(this, timestampUs, mChunkSamples); 3419 mOwner->bufferChunk(chunk); 3420 mChunkSamples.clear(); 3421} 3422 3423int64_t MPEG4Writer::Track::getDurationUs() const { 3424 return mTrackDurationUs + getStartTimeOffsetTimeUs(); 3425} 3426 3427int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 3428 return mEstimatedTrackSizeBytes; 3429} 3430 3431int32_t MPEG4Writer::Track::getMetaSizeIncrease() const { 3432 CHECK(mIsHeic); 3433 return 20 // 1. 'ispe' property 3434 + (8 + mCodecSpecificDataSize) // 2. 'hvcC' property 3435 + (20 // 3. extra 'ispe' 3436 + (8 + 2 + 2 + mNumTiles * 2) // 4. 'dimg' ref 3437 + 12) // 5. ImageGrid in 'idat' (worst case) 3438 * (mNumTiles > 1) // - (3~5: applicable only if grid) 3439 + (16 // 6. increase to 'iloc' 3440 + 21 // 7. increase to 'iinf' 3441 + (3 + 2 * 2)) // 8. increase to 'ipma' (worst case) 3442 * (mNumTiles + 1); // - (6~8: are per-item) 3443} 3444 3445status_t MPEG4Writer::Track::checkCodecSpecificData() const { 3446 const char *mime; 3447 CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 3448 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 3449 !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 3450 !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) || 3451 !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime) || 3452 !strcasecmp(MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, mime)) { 3453 if (!mCodecSpecificData || 3454 mCodecSpecificDataSize <= 0) { 3455 ALOGE("Missing codec specific data"); 3456 return ERROR_MALFORMED; 3457 } 3458 } else { 3459 if (mCodecSpecificData || 3460 mCodecSpecificDataSize > 0) { 3461 ALOGE("Unexepected codec specific data found"); 3462 return ERROR_MALFORMED; 3463 } 3464 } 3465 return OK; 3466} 3467 3468const char *MPEG4Writer::Track::getTrackType() const { 3469 return mIsAudio ? "Audio" : 3470 mIsVideo ? "Video" : 3471 mIsHeic ? "Image" : 3472 "Metadata"; 3473} 3474 3475void MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) { 3476 uint32_t now = getMpeg4Time(); 3477 mOwner->beginBox("trak"); 3478 writeTkhdBox(now); 3479 mOwner->beginBox("mdia"); 3480 writeMdhdBox(now); 3481 writeHdlrBox(); 3482 mOwner->beginBox("minf"); 3483 if (mIsAudio) { 3484 writeSmhdBox(); 3485 } else if (mIsVideo) { 3486 writeVmhdBox(); 3487 } else { 3488 writeNmhdBox(); 3489 } 3490 writeDinfBox(); 3491 writeStblBox(use32BitOffset); 3492 mOwner->endBox(); // minf 3493 mOwner->endBox(); // mdia 3494 mOwner->endBox(); // trak 3495} 3496 3497int64_t MPEG4Writer::Track::getMinCttsOffsetTimeUs() { 3498 // For video tracks with ctts table, this should return the minimum ctts 3499 // offset in the table. For non-video tracks or video tracks without ctts 3500 // table, this will return kMaxCttsOffsetTimeUs. 3501 if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) { 3502 return kMaxCttsOffsetTimeUs; 3503 } 3504 return mMinCttsOffsetTimeUs; 3505} 3506 3507void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) { 3508 mOwner->beginBox("stbl"); 3509 mOwner->beginBox("stsd"); 3510 mOwner->writeInt32(0); // version=0, flags=0 3511 mOwner->writeInt32(1); // entry count 3512 if (mIsAudio) { 3513 writeAudioFourCCBox(); 3514 } else if (mIsVideo) { 3515 writeVideoFourCCBox(); 3516 } else { 3517 writeMetadataFourCCBox(); 3518 } 3519 mOwner->endBox(); // stsd 3520 writeSttsBox(); 3521 if (mIsVideo) { 3522 writeCttsBox(); 3523 writeStssBox(); 3524 } 3525 writeStszBox(); 3526 writeStscBox(); 3527 writeStcoBox(use32BitOffset); 3528 mOwner->endBox(); // stbl 3529} 3530 3531void MPEG4Writer::Track::writeMetadataFourCCBox() { 3532 const char *mime; 3533 bool success = mMeta->findCString(kKeyMIMEType, &mime); 3534 CHECK(success); 3535 const char *fourcc = getFourCCForMime(mime); 3536 if (fourcc == NULL) { 3537 ALOGE("Unknown mime type '%s'.", mime); 3538 TRESPASS(); 3539 } 3540 mOwner->beginBox(fourcc); // TextMetaDataSampleEntry 3541 mOwner->writeCString(mime); // metadata mime_format 3542 mOwner->endBox(); // mett 3543} 3544 3545void MPEG4Writer::Track::writeVideoFourCCBox() { 3546 const char *mime; 3547 bool success = mMeta->findCString(kKeyMIMEType, &mime); 3548 CHECK(success); 3549 const char *fourcc = getFourCCForMime(mime); 3550 if (fourcc == NULL) { 3551 ALOGE("Unknown mime type '%s'.", mime); 3552 TRESPASS(); 3553 } 3554 3555 mOwner->beginBox(fourcc); // video format 3556 mOwner->writeInt32(0); // reserved 3557 mOwner->writeInt16(0); // reserved 3558 mOwner->writeInt16(1); // data ref index 3559 mOwner->writeInt16(0); // predefined 3560 mOwner->writeInt16(0); // reserved 3561 mOwner->writeInt32(0); // predefined 3562 mOwner->writeInt32(0); // predefined 3563 mOwner->writeInt32(0); // predefined 3564 3565 int32_t width, height; 3566 success = mMeta->findInt32(kKeyWidth, &width); 3567 success = success && mMeta->findInt32(kKeyHeight, &height); 3568 CHECK(success); 3569 3570 mOwner->writeInt16(width); 3571 mOwner->writeInt16(height); 3572 mOwner->writeInt32(0x480000); // horiz resolution 3573 mOwner->writeInt32(0x480000); // vert resolution 3574 mOwner->writeInt32(0); // reserved 3575 mOwner->writeInt16(1); // frame count 3576 mOwner->writeInt8(0); // compressor string length 3577 mOwner->write(" ", 31); 3578 mOwner->writeInt16(0x18); // depth 3579 mOwner->writeInt16(-1); // predefined 3580 3581 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 3582 writeMp4vEsdsBox(); 3583 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 3584 writeD263Box(); 3585 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 3586 writeAvccBox(); 3587 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { 3588 writeHvccBox(); 3589 } 3590 3591 writePaspBox(); 3592 writeColrBox(); 3593 mOwner->endBox(); // mp4v, s263 or avc1 3594} 3595 3596void MPEG4Writer::Track::writeColrBox() { 3597 ColorAspects aspects; 3598 memset(&aspects, 0, sizeof(aspects)); 3599 // TRICKY: using | instead of || because we want to execute all findInt32-s 3600 if (mMeta->findInt32(kKeyColorPrimaries, (int32_t*)&aspects.mPrimaries) 3601 | mMeta->findInt32(kKeyTransferFunction, (int32_t*)&aspects.mTransfer) 3602 | mMeta->findInt32(kKeyColorMatrix, (int32_t*)&aspects.mMatrixCoeffs) 3603 | mMeta->findInt32(kKeyColorRange, (int32_t*)&aspects.mRange)) { 3604 int32_t primaries, transfer, coeffs; 3605 bool fullRange; 3606 ColorUtils::convertCodecColorAspectsToIsoAspects( 3607 aspects, &primaries, &transfer, &coeffs, &fullRange); 3608 mOwner->beginBox("colr"); 3609 mOwner->writeFourcc("nclx"); 3610 mOwner->writeInt16(primaries); 3611 mOwner->writeInt16(transfer); 3612 mOwner->writeInt16(coeffs); 3613 mOwner->writeInt8(int8_t(fullRange ? 0x80 : 0x0)); 3614 mOwner->endBox(); // colr 3615 } 3616} 3617 3618void MPEG4Writer::Track::writeAudioFourCCBox() { 3619 const char *mime; 3620 bool success = mMeta->findCString(kKeyMIMEType, &mime); 3621 CHECK(success); 3622 const char *fourcc = getFourCCForMime(mime); 3623 if (fourcc == NULL) { 3624 ALOGE("Unknown mime type '%s'.", mime); 3625 TRESPASS(); 3626 } 3627 3628 mOwner->beginBox(fourcc); // audio format 3629 mOwner->writeInt32(0); // reserved 3630 mOwner->writeInt16(0); // reserved 3631 mOwner->writeInt16(0x1); // data ref index 3632 mOwner->writeInt32(0); // reserved 3633 mOwner->writeInt32(0); // reserved 3634 int32_t nChannels; 3635 CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 3636 mOwner->writeInt16(nChannels); // channel count 3637 mOwner->writeInt16(16); // sample size 3638 mOwner->writeInt16(0); // predefined 3639 mOwner->writeInt16(0); // reserved 3640 3641 int32_t samplerate; 3642 success = mMeta->findInt32(kKeySampleRate, &samplerate); 3643 CHECK(success); 3644 mOwner->writeInt32(samplerate << 16); 3645 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 3646 writeMp4aEsdsBox(); 3647 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 3648 !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 3649 writeDamrBox(); 3650 } 3651 mOwner->endBox(); 3652} 3653 3654void MPEG4Writer::Track::writeMp4aEsdsBox() { 3655 mOwner->beginBox("esds"); 3656 CHECK(mCodecSpecificData); 3657 CHECK_GT(mCodecSpecificDataSize, 0u); 3658 3659 // Make sure all sizes encode to a single byte. 3660 CHECK_LT(mCodecSpecificDataSize + 23, 128u); 3661 3662 mOwner->writeInt32(0); // version=0, flags=0 3663 mOwner->writeInt8(0x03); // ES_DescrTag 3664 mOwner->writeInt8(23 + mCodecSpecificDataSize); 3665 mOwner->writeInt16(0x0000);// ES_ID 3666 mOwner->writeInt8(0x00); 3667 3668 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 3669 mOwner->writeInt8(15 + mCodecSpecificDataSize); 3670 mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 3671 mOwner->writeInt8(0x15); // streamType AudioStream 3672 3673 mOwner->writeInt16(0x03); // XXX 3674 mOwner->writeInt8(0x00); // buffer size 24-bit (0x300) 3675 3676 int32_t avgBitrate = 0; 3677 (void)mMeta->findInt32(kKeyBitRate, &avgBitrate); 3678 int32_t maxBitrate = 0; 3679 (void)mMeta->findInt32(kKeyMaxBitRate, &maxBitrate); 3680 mOwner->writeInt32(maxBitrate); 3681 mOwner->writeInt32(avgBitrate); 3682 3683 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 3684 mOwner->writeInt8(mCodecSpecificDataSize); 3685 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 3686 3687 static const uint8_t kData2[] = { 3688 0x06, // SLConfigDescriptorTag 3689 0x01, 3690 0x02 3691 }; 3692 mOwner->write(kData2, sizeof(kData2)); 3693 3694 mOwner->endBox(); // esds 3695} 3696 3697void MPEG4Writer::Track::writeMp4vEsdsBox() { 3698 CHECK(mCodecSpecificData); 3699 CHECK_GT(mCodecSpecificDataSize, 0u); 3700 3701 // Make sure all sizes encode to a single byte. 3702 CHECK_LT(23 + mCodecSpecificDataSize, 128u); 3703 3704 mOwner->beginBox("esds"); 3705 3706 mOwner->writeInt32(0); // version=0, flags=0 3707 3708 mOwner->writeInt8(0x03); // ES_DescrTag 3709 mOwner->writeInt8(23 + mCodecSpecificDataSize); 3710 mOwner->writeInt16(0x0000); // ES_ID 3711 mOwner->writeInt8(0x1f); 3712 3713 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 3714 mOwner->writeInt8(15 + mCodecSpecificDataSize); 3715 mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 3716 mOwner->writeInt8(0x11); // streamType VisualStream 3717 3718 static const uint8_t kData[] = { 3719 0x01, 0x77, 0x00, // buffer size 96000 bytes 3720 }; 3721 mOwner->write(kData, sizeof(kData)); 3722 3723 int32_t avgBitrate = 0; 3724 (void)mMeta->findInt32(kKeyBitRate, &avgBitrate); 3725 int32_t maxBitrate = 0; 3726 (void)mMeta->findInt32(kKeyMaxBitRate, &maxBitrate); 3727 mOwner->writeInt32(maxBitrate); 3728 mOwner->writeInt32(avgBitrate); 3729 3730 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 3731 3732 mOwner->writeInt8(mCodecSpecificDataSize); 3733 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 3734 3735 static const uint8_t kData2[] = { 3736 0x06, // SLConfigDescriptorTag 3737 0x01, 3738 0x02 3739 }; 3740 mOwner->write(kData2, sizeof(kData2)); 3741 3742 mOwner->endBox(); // esds 3743} 3744 3745void MPEG4Writer::Track::writeTkhdBox(uint32_t now) { 3746 mOwner->beginBox("tkhd"); 3747 // Flags = 7 to indicate that the track is enabled, and 3748 // part of the presentation 3749 mOwner->writeInt32(0x07); // version=0, flags=7 3750 mOwner->writeInt32(now); // creation time 3751 mOwner->writeInt32(now); // modification time 3752 mOwner->writeInt32(mTrackId); // track id starts with 1 3753 mOwner->writeInt32(0); // reserved 3754 int64_t trakDurationUs = getDurationUs(); 3755 int32_t mvhdTimeScale = mOwner->getTimeScale(); 3756 int32_t tkhdDuration = 3757 (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 3758 mOwner->writeInt32(tkhdDuration); // in mvhd timescale 3759 mOwner->writeInt32(0); // reserved 3760 mOwner->writeInt32(0); // reserved 3761 mOwner->writeInt16(0); // layer 3762 mOwner->writeInt16(0); // alternate group 3763 mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 3764 mOwner->writeInt16(0); // reserved 3765 3766 mOwner->writeCompositionMatrix(mRotation); // matrix 3767 3768 if (!mIsVideo) { 3769 mOwner->writeInt32(0); 3770 mOwner->writeInt32(0); 3771 } else { 3772 int32_t width, height; 3773 bool success = mMeta->findInt32(kKeyDisplayWidth, &width); 3774 success = success && mMeta->findInt32(kKeyDisplayHeight, &height); 3775 3776 // Use width/height if display width/height are not present. 3777 if (!success) { 3778 success = mMeta->findInt32(kKeyWidth, &width); 3779 success = success && mMeta->findInt32(kKeyHeight, &height); 3780 } 3781 CHECK(success); 3782 3783 mOwner->writeInt32(width << 16); // 32-bit fixed-point value 3784 mOwner->writeInt32(height << 16); // 32-bit fixed-point value 3785 } 3786 mOwner->endBox(); // tkhd 3787} 3788 3789void MPEG4Writer::Track::writeVmhdBox() { 3790 mOwner->beginBox("vmhd"); 3791 mOwner->writeInt32(0x01); // version=0, flags=1 3792 mOwner->writeInt16(0); // graphics mode 3793 mOwner->writeInt16(0); // opcolor 3794 mOwner->writeInt16(0); 3795 mOwner->writeInt16(0); 3796 mOwner->endBox(); 3797} 3798 3799void MPEG4Writer::Track::writeSmhdBox() { 3800 mOwner->beginBox("smhd"); 3801 mOwner->writeInt32(0); // version=0, flags=0 3802 mOwner->writeInt16(0); // balance 3803 mOwner->writeInt16(0); // reserved 3804 mOwner->endBox(); 3805} 3806 3807void MPEG4Writer::Track::writeNmhdBox() { 3808 mOwner->beginBox("nmhd"); 3809 mOwner->writeInt32(0); // version=0, flags=0 3810 mOwner->endBox(); 3811} 3812 3813void MPEG4Writer::Track::writeHdlrBox() { 3814 mOwner->beginBox("hdlr"); 3815 mOwner->writeInt32(0); // version=0, flags=0 3816 mOwner->writeInt32(0); // component type: should be mhlr 3817 mOwner->writeFourcc(mIsAudio ? "soun" : (mIsVideo ? "vide" : "meta")); // component subtype 3818 mOwner->writeInt32(0); // reserved 3819 mOwner->writeInt32(0); // reserved 3820 mOwner->writeInt32(0); // reserved 3821 // Removing "r" for the name string just makes the string 4 byte aligned 3822 mOwner->writeCString(mIsAudio ? "SoundHandle": (mIsVideo ? "VideoHandle" : "MetadHandle")); 3823 mOwner->endBox(); 3824} 3825 3826void MPEG4Writer::Track::writeMdhdBox(uint32_t now) { 3827 int64_t trakDurationUs = getDurationUs(); 3828 int64_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 3829 mOwner->beginBox("mdhd"); 3830 3831 if (mdhdDuration > UINT32_MAX) { 3832 mOwner->writeInt32((1 << 24)); // version=1, flags=0 3833 mOwner->writeInt64((int64_t)now); // creation time 3834 mOwner->writeInt64((int64_t)now); // modification time 3835 mOwner->writeInt32(mTimeScale); // media timescale 3836 mOwner->writeInt64(mdhdDuration); // media timescale 3837 } else { 3838 mOwner->writeInt32(0); // version=0, flags=0 3839 mOwner->writeInt32(now); // creation time 3840 mOwner->writeInt32(now); // modification time 3841 mOwner->writeInt32(mTimeScale); // media timescale 3842 mOwner->writeInt32((int32_t)mdhdDuration); // use media timescale 3843 } 3844 // Language follows the three letter standard ISO-639-2/T 3845 // 'e', 'n', 'g' for "English", for instance. 3846 // Each character is packed as the difference between its ASCII value and 0x60. 3847 // For "English", these are 00101, 01110, 00111. 3848 // XXX: Where is the padding bit located: 0x15C7? 3849 const char *lang = NULL; 3850 int16_t langCode = 0; 3851 if (mMeta->findCString(kKeyMediaLanguage, &lang) && lang && strnlen(lang, 3) > 2) { 3852 langCode = ((lang[0] & 0x1f) << 10) | ((lang[1] & 0x1f) << 5) | (lang[2] & 0x1f); 3853 } 3854 mOwner->writeInt16(langCode); // language code 3855 mOwner->writeInt16(0); // predefined 3856 mOwner->endBox(); 3857} 3858 3859void MPEG4Writer::Track::writeDamrBox() { 3860 // 3gpp2 Spec AMRSampleEntry fields 3861 mOwner->beginBox("damr"); 3862 mOwner->writeCString(" "); // vendor: 4 bytes 3863 mOwner->writeInt8(0); // decoder version 3864 mOwner->writeInt16(0x83FF); // mode set: all enabled 3865 mOwner->writeInt8(0); // mode change period 3866 mOwner->writeInt8(1); // frames per sample 3867 mOwner->endBox(); 3868} 3869 3870void MPEG4Writer::Track::writeUrlBox() { 3871 // The table index here refers to the sample description index 3872 // in the sample table entries. 3873 mOwner->beginBox("url "); 3874 mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 3875 mOwner->endBox(); // url 3876} 3877 3878void MPEG4Writer::Track::writeDrefBox() { 3879 mOwner->beginBox("dref"); 3880 mOwner->writeInt32(0); // version=0, flags=0 3881 mOwner->writeInt32(1); // entry count (either url or urn) 3882 writeUrlBox(); 3883 mOwner->endBox(); // dref 3884} 3885 3886void MPEG4Writer::Track::writeDinfBox() { 3887 mOwner->beginBox("dinf"); 3888 writeDrefBox(); 3889 mOwner->endBox(); // dinf 3890} 3891 3892void MPEG4Writer::Track::writeAvccBox() { 3893 CHECK(mCodecSpecificData); 3894 CHECK_GE(mCodecSpecificDataSize, 5u); 3895 3896 // Patch avcc's lengthSize field to match the number 3897 // of bytes we use to indicate the size of a nal unit. 3898 uint8_t *ptr = (uint8_t *)mCodecSpecificData; 3899 ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1); 3900 mOwner->beginBox("avcC"); 3901 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 3902 mOwner->endBox(); // avcC 3903} 3904 3905 3906void MPEG4Writer::Track::writeHvccBox() { 3907 CHECK(mCodecSpecificData); 3908 CHECK_GE(mCodecSpecificDataSize, 5u); 3909 3910 // Patch avcc's lengthSize field to match the number 3911 // of bytes we use to indicate the size of a nal unit. 3912 uint8_t *ptr = (uint8_t *)mCodecSpecificData; 3913 ptr[21] = (ptr[21] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1); 3914 mOwner->beginBox("hvcC"); 3915 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 3916 mOwner->endBox(); // hvcC 3917} 3918 3919void MPEG4Writer::Track::writeD263Box() { 3920 mOwner->beginBox("d263"); 3921 mOwner->writeInt32(0); // vendor 3922 mOwner->writeInt8(0); // decoder version 3923 mOwner->writeInt8(10); // level: 10 3924 mOwner->writeInt8(0); // profile: 0 3925 mOwner->endBox(); // d263 3926} 3927 3928// This is useful if the pixel is not square 3929void MPEG4Writer::Track::writePaspBox() { 3930 mOwner->beginBox("pasp"); 3931 mOwner->writeInt32(1 << 16); // hspacing 3932 mOwner->writeInt32(1 << 16); // vspacing 3933 mOwner->endBox(); // pasp 3934} 3935 3936int64_t MPEG4Writer::Track::getStartTimeOffsetTimeUs() const { 3937 int64_t trackStartTimeOffsetUs = 0; 3938 int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 3939 if (mStartTimestampUs != -1 && mStartTimestampUs != moovStartTimeUs) { 3940 CHECK_GT(mStartTimestampUs, moovStartTimeUs); 3941 trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 3942 } 3943 return trackStartTimeOffsetUs; 3944} 3945 3946int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const { 3947 return (getStartTimeOffsetTimeUs() * mTimeScale + 500000LL) / 1000000LL; 3948} 3949 3950void MPEG4Writer::Track::writeSttsBox() { 3951 mOwner->beginBox("stts"); 3952 mOwner->writeInt32(0); // version=0, flags=0 3953 if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) { 3954 // For non-vdeio tracks or video tracks without ctts table, 3955 // adjust duration of first sample for tracks to account for 3956 // first sample not starting at the media start time. 3957 // TODO: consider signaling this using some offset 3958 // as this is not quite correct. 3959 uint32_t duration; 3960 CHECK(mSttsTableEntries->get(duration, 1)); 3961 duration = htonl(duration); // Back to host byte order 3962 mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1); 3963 } 3964 mSttsTableEntries->write(mOwner); 3965 mOwner->endBox(); // stts 3966} 3967 3968void MPEG4Writer::Track::writeCttsBox() { 3969 // There is no B frame at all 3970 if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) { 3971 return; 3972 } 3973 3974 // Do not write ctts box when there is no need to have it. 3975 if (mCttsTableEntries->count() == 0) { 3976 return; 3977 } 3978 3979 ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]", 3980 mCttsTableEntries->count(), mMinCttsOffsetTicks, mMaxCttsOffsetTicks); 3981 3982 mOwner->beginBox("ctts"); 3983 mOwner->writeInt32(0); // version=0, flags=0 3984 int64_t deltaTimeUs = kMaxCttsOffsetTimeUs - getStartTimeOffsetTimeUs(); 3985 int64_t delta = (deltaTimeUs * mTimeScale + 500000LL) / 1000000LL; 3986 mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) { 3987 // entries are <count, ctts> pairs; adjust only ctts 3988 uint32_t duration = htonl(value[1]); // back to host byte order 3989 // Prevent overflow and underflow 3990 if (delta > duration) { 3991 duration = 0; 3992 } else if (delta < 0 && UINT32_MAX + delta < duration) { 3993 duration = UINT32_MAX; 3994 } else { 3995 duration -= delta; 3996 } 3997 value[1] = htonl(duration); 3998 }); 3999 mCttsTableEntries->write(mOwner); 4000 mOwner->endBox(); // ctts 4001} 4002 4003void MPEG4Writer::Track::writeStssBox() { 4004 mOwner->beginBox("stss"); 4005 mOwner->writeInt32(0); // version=0, flags=0 4006 mStssTableEntries->write(mOwner); 4007 mOwner->endBox(); // stss 4008} 4009 4010void MPEG4Writer::Track::writeStszBox() { 4011 mOwner->beginBox("stsz"); 4012 mOwner->writeInt32(0); // version=0, flags=0 4013 mOwner->writeInt32(0); 4014 mStszTableEntries->write(mOwner); 4015 mOwner->endBox(); // stsz 4016} 4017 4018void MPEG4Writer::Track::writeStscBox() { 4019 mOwner->beginBox("stsc"); 4020 mOwner->writeInt32(0); // version=0, flags=0 4021 mStscTableEntries->write(mOwner); 4022 mOwner->endBox(); // stsc 4023} 4024 4025void MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) { 4026 mOwner->beginBox(use32BitOffset? "stco": "co64"); 4027 mOwner->writeInt32(0); // version=0, flags=0 4028 if (use32BitOffset) { 4029 mStcoTableEntries->write(mOwner); 4030 } else { 4031 mCo64TableEntries->write(mOwner); 4032 } 4033 mOwner->endBox(); // stco or co64 4034} 4035 4036void MPEG4Writer::writeUdtaBox() { 4037 beginBox("udta"); 4038 writeGeoDataBox(); 4039 endBox(); 4040} 4041 4042void MPEG4Writer::writeHdlr(const char *handlerType) { 4043 beginBox("hdlr"); 4044 writeInt32(0); // Version, Flags 4045 writeInt32(0); // Predefined 4046 writeFourcc(handlerType); 4047 writeInt32(0); // Reserved[0] 4048 writeInt32(0); // Reserved[1] 4049 writeInt32(0); // Reserved[2] 4050 writeInt8(0); // Name (empty) 4051 endBox(); 4052} 4053 4054void MPEG4Writer::writeKeys() { 4055 size_t count = mMetaKeys->countEntries(); 4056 4057 beginBox("keys"); 4058 writeInt32(0); // Version, Flags 4059 writeInt32(count); // Entry_count 4060 for (size_t i = 0; i < count; i++) { 4061 AMessage::Type type; 4062 const char *key = mMetaKeys->getEntryNameAt(i, &type); 4063 size_t n = strlen(key); 4064 writeInt32(n + 8); 4065 writeFourcc("mdta"); 4066 write(key, n); // write without the \0 4067 } 4068 endBox(); 4069} 4070 4071void MPEG4Writer::writeIlst() { 4072 size_t count = mMetaKeys->countEntries(); 4073 4074 beginBox("ilst"); 4075 for (size_t i = 0; i < count; i++) { 4076 beginBox(i + 1); // key id (1-based) 4077 beginBox("data"); 4078 AMessage::Type type; 4079 const char *key = mMetaKeys->getEntryNameAt(i, &type); 4080 switch (type) { 4081 case AMessage::kTypeString: 4082 { 4083 AString val; 4084 CHECK(mMetaKeys->findString(key, &val)); 4085 writeInt32(1); // type = UTF8 4086 writeInt32(0); // default country/language 4087 write(val.c_str(), strlen(val.c_str())); // write without \0 4088 break; 4089 } 4090 4091 case AMessage::kTypeFloat: 4092 { 4093 float val; 4094 CHECK(mMetaKeys->findFloat(key, &val)); 4095 writeInt32(23); // type = float32 4096 writeInt32(0); // default country/language 4097 writeInt32(*reinterpret_cast<int32_t *>(&val)); 4098 break; 4099 } 4100 4101 case AMessage::kTypeInt32: 4102 { 4103 int32_t val; 4104 CHECK(mMetaKeys->findInt32(key, &val)); 4105 writeInt32(67); // type = signed int32 4106 writeInt32(0); // default country/language 4107 writeInt32(val); 4108 break; 4109 } 4110 4111 default: 4112 { 4113 ALOGW("Unsupported key type, writing 0 instead"); 4114 writeInt32(77); // type = unsigned int32 4115 writeInt32(0); // default country/language 4116 writeInt32(0); 4117 break; 4118 } 4119 } 4120 endBox(); // data 4121 endBox(); // key id 4122 } 4123 endBox(); // ilst 4124} 4125 4126void MPEG4Writer::writeMoovLevelMetaBox() { 4127 size_t count = mMetaKeys->countEntries(); 4128 if (count == 0) { 4129 return; 4130 } 4131 4132 beginBox("meta"); 4133 writeHdlr("mdta"); 4134 writeKeys(); 4135 writeIlst(); 4136 endBox(); 4137} 4138 4139void MPEG4Writer::writeIlocBox() { 4140 beginBox("iloc"); 4141 // Use version 1 to allow construction method 1 that refers to 4142 // data in idat box inside meta box. 4143 writeInt32(0x01000000); // Version = 1, Flags = 0 4144 writeInt16(0x4400); // offset_size = length_size = 4 4145 // base_offset_size = index_size = 0 4146 4147 // 16-bit item_count 4148 size_t itemCount = mItems.size(); 4149 if (itemCount > 65535) { 4150 ALOGW("Dropping excess items: itemCount %zu", itemCount); 4151 itemCount = 65535; 4152 } 4153 writeInt16((uint16_t)itemCount); 4154 4155 for (size_t i = 0; i < itemCount; i++) { 4156 writeInt16(mItems[i].itemId); 4157 bool isGrid = mItems[i].isGrid(); 4158 4159 writeInt16(isGrid ? 1 : 0); // construction_method 4160 writeInt16(0); // data_reference_index = 0 4161 writeInt16(1); // extent_count = 1 4162 4163 if (isGrid) { 4164 // offset into the 'idat' box 4165 writeInt32(mNumGrids++ * 8); 4166 writeInt32(8); 4167 } else { 4168 writeInt32(mItems[i].offset); 4169 writeInt32(mItems[i].size); 4170 } 4171 } 4172 endBox(); 4173} 4174 4175void MPEG4Writer::writeInfeBox( 4176 uint16_t itemId, const char *itemType, uint32_t flags) { 4177 beginBox("infe"); 4178 writeInt32(0x02000000 | flags); // Version = 2, Flags = 0 4179 writeInt16(itemId); 4180 writeInt16(0); //item_protection_index = 0 4181 writeFourcc(itemType); 4182 writeCString(""); // item_name 4183 endBox(); 4184} 4185 4186void MPEG4Writer::writeIinfBox() { 4187 beginBox("iinf"); 4188 writeInt32(0); // Version = 0, Flags = 0 4189 4190 // 16-bit item_count 4191 size_t itemCount = mItems.size(); 4192 if (itemCount > 65535) { 4193 ALOGW("Dropping excess items: itemCount %zu", itemCount); 4194 itemCount = 65535; 4195 } 4196 4197 writeInt16((uint16_t)itemCount); 4198 for (size_t i = 0; i < itemCount; i++) { 4199 writeInfeBox(mItems[i].itemId, mItems[i].itemType, 4200 mItems[i].isHidden ? 1 : 0); 4201 } 4202 4203 endBox(); 4204} 4205 4206void MPEG4Writer::writeIdatBox() { 4207 beginBox("idat"); 4208 4209 for (size_t i = 0; i < mItems.size(); i++) { 4210 if (mItems[i].isGrid()) { 4211 writeInt8(0); // version 4212 // flags == 1 means 32-bit width,height 4213 int8_t flags = (mItems[i].width > 65535 || mItems[i].height > 65535); 4214 writeInt8(flags); 4215 writeInt8(mItems[i].rows - 1); 4216 writeInt8(mItems[i].cols - 1); 4217 if (flags) { 4218 writeInt32(mItems[i].width); 4219 writeInt32(mItems[i].height); 4220 } else { 4221 writeInt16((uint16_t)mItems[i].width); 4222 writeInt16((uint16_t)mItems[i].height); 4223 } 4224 } 4225 } 4226 4227 endBox(); 4228} 4229 4230void MPEG4Writer::writeIrefBox() { 4231 beginBox("iref"); 4232 writeInt32(0); // Version = 0, Flags = 0 4233 { 4234 for (size_t i = 0; i < mItems.size(); i++) { 4235 if (!mItems[i].isGrid()) { 4236 continue; 4237 } 4238 beginBox("dimg"); 4239 writeInt16(mItems[i].itemId); 4240 size_t refCount = mItems[i].dimgRefs.size(); 4241 if (refCount > 65535) { 4242 ALOGW("too many entries in dimg"); 4243 refCount = 65535; 4244 } 4245 writeInt16((uint16_t)refCount); 4246 for (size_t refIndex = 0; refIndex < refCount; refIndex++) { 4247 writeInt16(mItems[i].dimgRefs[refIndex]); 4248 } 4249 endBox(); 4250 } 4251 } 4252 endBox(); 4253} 4254 4255void MPEG4Writer::writePitmBox() { 4256 beginBox("pitm"); 4257 writeInt32(0); // Version = 0, Flags = 0 4258 writeInt16(mPrimaryItemId); 4259 endBox(); 4260} 4261 4262void MPEG4Writer::writeIpcoBox() { 4263 beginBox("ipco"); 4264 size_t numProperties = mProperties.size(); 4265 if (numProperties > 32767) { 4266 ALOGW("Dropping excess properties: numProperties %zu", numProperties); 4267 numProperties = 32767; 4268 } 4269 for (size_t propIndex = 0; propIndex < numProperties; propIndex++) { 4270 if (mProperties[propIndex].type == FOURCC('h', 'v', 'c', 'C')) { 4271 beginBox("hvcC"); 4272 sp<ABuffer> hvcc = mProperties[propIndex].hvcc; 4273 // Patch avcc's lengthSize field to match the number 4274 // of bytes we use to indicate the size of a nal unit. 4275 uint8_t *ptr = (uint8_t *)hvcc->data(); 4276 ptr[21] = (ptr[21] & 0xfc) | (useNalLengthFour() ? 3 : 1); 4277 write(hvcc->data(), hvcc->size()); 4278 endBox(); 4279 } else if (mProperties[propIndex].type == FOURCC('i', 's', 'p', 'e')) { 4280 beginBox("ispe"); 4281 writeInt32(0); // Version = 0, Flags = 0 4282 writeInt32(mProperties[propIndex].width); 4283 writeInt32(mProperties[propIndex].height); 4284 endBox(); 4285 } else { 4286 ALOGW("Skipping unrecognized property: type 0x%08x", 4287 mProperties[propIndex].type); 4288 } 4289 } 4290 endBox(); 4291} 4292 4293void MPEG4Writer::writeIpmaBox() { 4294 beginBox("ipma"); 4295 uint32_t flags = (mProperties.size() > 127) ? 1 : 0; 4296 writeInt32(flags); // Version = 0 4297 4298 writeInt32(mAssociationEntryCount); 4299 for (size_t itemIndex = 0; itemIndex < mItems.size(); itemIndex++) { 4300 const Vector<uint16_t> &properties = mItems[itemIndex].properties; 4301 if (properties.empty()) { 4302 continue; 4303 } 4304 writeInt16(mItems[itemIndex].itemId); 4305 4306 size_t entryCount = properties.size(); 4307 if (entryCount > 255) { 4308 ALOGW("Dropping excess associations: entryCount %zu", entryCount); 4309 entryCount = 255; 4310 } 4311 writeInt8((uint8_t)entryCount); 4312 for (size_t propIndex = 0; propIndex < entryCount; propIndex++) { 4313 if (flags & 1) { 4314 writeInt16((1 << 15) | properties[propIndex]); 4315 } else { 4316 writeInt8((1 << 7) | properties[propIndex]); 4317 } 4318 } 4319 } 4320 endBox(); 4321} 4322 4323void MPEG4Writer::writeIprpBox() { 4324 beginBox("iprp"); 4325 writeIpcoBox(); 4326 writeIpmaBox(); 4327 endBox(); 4328} 4329 4330void MPEG4Writer::writeFileLevelMetaBox() { 4331 if (mItems.empty()) { 4332 ALOGE("no valid item was found"); 4333 return; 4334 } 4335 4336 // patch up the mPrimaryItemId and count items with prop associations 4337 uint16_t firstVisibleItemId = 0; 4338 for (size_t index = 0; index < mItems.size(); index++) { 4339 if (mItems[index].isPrimary) { 4340 mPrimaryItemId = mItems[index].itemId; 4341 } else if (!firstVisibleItemId && !mItems[index].isHidden) { 4342 firstVisibleItemId = mItems[index].itemId; 4343 } 4344 4345 if (!mItems[index].properties.empty()) { 4346 mAssociationEntryCount++; 4347 } 4348 } 4349 4350 if (mPrimaryItemId == 0) { 4351 if (firstVisibleItemId > 0) { 4352 ALOGW("didn't find primary, using first visible item"); 4353 mPrimaryItemId = firstVisibleItemId; 4354 } else { 4355 ALOGW("no primary and no visible item, using first item"); 4356 mPrimaryItemId = mItems[0].itemId; 4357 } 4358 } 4359 4360 beginBox("meta"); 4361 writeInt32(0); // Version = 0, Flags = 0 4362 writeHdlr("pict"); 4363 writeIlocBox(); 4364 writeIinfBox(); 4365 writePitmBox(); 4366 writeIprpBox(); 4367 if (mNumGrids > 0) { 4368 writeIdatBox(); 4369 writeIrefBox(); 4370 } 4371 endBox(); 4372} 4373 4374uint16_t MPEG4Writer::addProperty_l(const ItemProperty &prop) { 4375 char typeStr[5]; 4376 MakeFourCCString(prop.type, typeStr); 4377 ALOGV("addProperty_l: %s", typeStr); 4378 4379 mProperties.push_back(prop); 4380 4381 // returning 1-based property index 4382 return mProperties.size(); 4383} 4384 4385uint16_t MPEG4Writer::addItem_l(const ItemInfo &info) { 4386 ALOGV("addItem_l: type %s, offset %u, size %u", 4387 info.itemType, info.offset, info.size); 4388 4389 size_t index = mItems.size(); 4390 mItems.push_back(info); 4391 4392 // make the item id start at 10000 4393 mItems.editItemAt(index).itemId = index + 10000; 4394 4395#if (LOG_NDEBUG==0) 4396 if (!info.properties.empty()) { 4397 AString str; 4398 for (size_t i = 0; i < info.properties.size(); i++) { 4399 if (i > 0) { 4400 str.append(", "); 4401 } 4402 str.append(info.properties[i]); 4403 } 4404 ALOGV("addItem_l: id %d, properties: %s", mItems[index].itemId, str.c_str()); 4405 } 4406#endif // (LOG_NDEBUG==0) 4407 4408 return mItems[index].itemId; 4409} 4410 4411/* 4412 * Geodata is stored according to ISO-6709 standard. 4413 */ 4414void MPEG4Writer::writeGeoDataBox() { 4415 beginBox("\xA9xyz"); 4416 /* 4417 * For historical reasons, any user data start 4418 * with "\0xA9", must be followed by its assoicated 4419 * language code. 4420 * 0x0012: text string length 4421 * 0x15c7: lang (locale) code: en 4422 */ 4423 writeInt32(0x001215c7); 4424 writeLatitude(mLatitudex10000); 4425 writeLongitude(mLongitudex10000); 4426 writeInt8(0x2F); 4427 endBox(); 4428} 4429 4430} // namespace android 4431