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