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