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