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