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