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