MPEG4Writer.cpp revision ffb9710d2c6a323519f499e5900b16cd3cd067bd
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 free(mMoovBoxBuffer); 845 mMoovBoxBuffer = NULL; 846} 847 848status_t MPEG4Writer::reset() { 849 if (mInitCheck != OK) { 850 return OK; 851 } else { 852 if (!mWriterThreadStarted || 853 !mStarted) { 854 if (mWriterThreadStarted) { 855 stopWriterThread(); 856 } 857 release(); 858 return OK; 859 } 860 } 861 862 status_t err = OK; 863 int64_t maxDurationUs = 0; 864 int64_t minDurationUs = 0x7fffffffffffffffLL; 865 for (List<Track *>::iterator it = mTracks.begin(); 866 it != mTracks.end(); ++it) { 867 status_t status = (*it)->stop(); 868 if (err == OK && status != OK) { 869 err = status; 870 } 871 872 int64_t durationUs = (*it)->getDurationUs(); 873 if (durationUs > maxDurationUs) { 874 maxDurationUs = durationUs; 875 } 876 if (durationUs < minDurationUs) { 877 minDurationUs = durationUs; 878 } 879 } 880 881 if (mTracks.size() > 1) { 882 ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", 883 minDurationUs, maxDurationUs); 884 } 885 886 stopWriterThread(); 887 888 // Do not write out movie header on error. 889 if (err != OK) { 890 release(); 891 return err; 892 } 893 894 // Fix up the size of the 'mdat' chunk. 895 if (mUse32BitOffset) { 896 lseek64(mFd, mMdatOffset, SEEK_SET); 897 uint32_t size = htonl(static_cast<uint32_t>(mOffset - mMdatOffset)); 898 ::write(mFd, &size, 4); 899 } else { 900 lseek64(mFd, mMdatOffset + 8, SEEK_SET); 901 uint64_t size = mOffset - mMdatOffset; 902 size = hton64(size); 903 ::write(mFd, &size, 8); 904 } 905 lseek64(mFd, mOffset, SEEK_SET); 906 907 // Construct moov box now 908 mMoovBoxBufferOffset = 0; 909 mWriteMoovBoxToMemory = mStreamableFile; 910 if (mWriteMoovBoxToMemory) { 911 // There is no need to allocate in-memory cache 912 // for moov box if the file is not streamable. 913 914 mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 915 CHECK(mMoovBoxBuffer != NULL); 916 } 917 writeMoovBox(maxDurationUs); 918 919 // mWriteMoovBoxToMemory could be set to false in 920 // MPEG4Writer::write() method 921 if (mWriteMoovBoxToMemory) { 922 mWriteMoovBoxToMemory = false; 923 // Content of the moov box is saved in the cache, and the in-memory 924 // moov box needs to be written to the file in a single shot. 925 926 CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize); 927 928 // Moov box 929 lseek64(mFd, mFreeBoxOffset, SEEK_SET); 930 mOffset = mFreeBoxOffset; 931 write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset); 932 933 // Free box 934 lseek64(mFd, mOffset, SEEK_SET); 935 writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 936 write("free", 4); 937 } else { 938 ALOGI("The mp4 file will not be streamable."); 939 } 940 941 // Free in-memory cache for moov box 942 if (mMoovBoxBuffer != NULL) { 943 free(mMoovBoxBuffer); 944 mMoovBoxBuffer = NULL; 945 mMoovBoxBufferOffset = 0; 946 } 947 948 CHECK(mBoxes.empty()); 949 950 release(); 951 return err; 952} 953 954uint32_t MPEG4Writer::getMpeg4Time() { 955 time_t now = time(NULL); 956 // MP4 file uses time counting seconds since midnight, Jan. 1, 1904 957 // while time function returns Unix epoch values which starts 958 // at 1970-01-01. Lets add the number of seconds between them 959 uint32_t mpeg4Time = now + (66 * 365 + 17) * (24 * 60 * 60); 960 return mpeg4Time; 961} 962 963void MPEG4Writer::writeMvhdBox(int64_t durationUs) { 964 uint32_t now = getMpeg4Time(); 965 beginBox("mvhd"); 966 writeInt32(0); // version=0, flags=0 967 writeInt32(now); // creation time 968 writeInt32(now); // modification time 969 writeInt32(mTimeScale); // mvhd timescale 970 int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6; 971 writeInt32(duration); 972 writeInt32(0x10000); // rate: 1.0 973 writeInt16(0x100); // volume 974 writeInt16(0); // reserved 975 writeInt32(0); // reserved 976 writeInt32(0); // reserved 977 writeCompositionMatrix(0); // matrix 978 writeInt32(0); // predefined 979 writeInt32(0); // predefined 980 writeInt32(0); // predefined 981 writeInt32(0); // predefined 982 writeInt32(0); // predefined 983 writeInt32(0); // predefined 984 writeInt32(mTracks.size() + 1); // nextTrackID 985 endBox(); // mvhd 986} 987 988void MPEG4Writer::writeMoovBox(int64_t durationUs) { 989 beginBox("moov"); 990 writeMvhdBox(durationUs); 991 if (mAreGeoTagsAvailable) { 992 writeUdtaBox(); 993 } 994 writeMetaBox(); 995 int32_t id = 1; 996 for (List<Track *>::iterator it = mTracks.begin(); 997 it != mTracks.end(); ++it, ++id) { 998 (*it)->writeTrackHeader(mUse32BitOffset); 999 } 1000 endBox(); // moov 1001} 1002 1003void MPEG4Writer::writeFtypBox(MetaData *param) { 1004 beginBox("ftyp"); 1005 1006 int32_t fileType; 1007 if (param && param->findInt32(kKeyFileType, &fileType) && 1008 fileType != OUTPUT_FORMAT_MPEG_4) { 1009 writeFourcc("3gp4"); 1010 writeInt32(0); 1011 writeFourcc("isom"); 1012 writeFourcc("3gp4"); 1013 } else { 1014 writeFourcc("mp42"); 1015 writeInt32(0); 1016 writeFourcc("isom"); 1017 writeFourcc("mp42"); 1018 } 1019 1020 endBox(); 1021} 1022 1023static bool isTestModeEnabled() { 1024#if (PROPERTY_VALUE_MAX < 5) 1025#error "PROPERTY_VALUE_MAX must be at least 5" 1026#endif 1027 1028 // Test mode is enabled only if rw.media.record.test system 1029 // property is enabled. 1030 char value[PROPERTY_VALUE_MAX]; 1031 if (property_get("rw.media.record.test", value, NULL) && 1032 (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) { 1033 return true; 1034 } 1035 return false; 1036} 1037 1038void MPEG4Writer::sendSessionSummary() { 1039 // Send session summary only if test mode is enabled 1040 if (!isTestModeEnabled()) { 1041 return; 1042 } 1043 1044 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 1045 it != mChunkInfos.end(); ++it) { 1046 int trackNum = it->mTrack->getTrackId() << 28; 1047 notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 1048 trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS, 1049 it->mMaxInterChunkDurUs); 1050 } 1051} 1052 1053status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 1054 mInterleaveDurationUs = durationUs; 1055 return OK; 1056} 1057 1058void MPEG4Writer::lock() { 1059 mLock.lock(); 1060} 1061 1062void MPEG4Writer::unlock() { 1063 mLock.unlock(); 1064} 1065 1066off64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 1067 off64_t old_offset = mOffset; 1068 1069 ::write(mFd, 1070 (const uint8_t *)buffer->data() + buffer->range_offset(), 1071 buffer->range_length()); 1072 1073 mOffset += buffer->range_length(); 1074 1075 return old_offset; 1076} 1077 1078static void StripStartcode(MediaBuffer *buffer) { 1079 if (buffer->range_length() < 4) { 1080 return; 1081 } 1082 1083 const uint8_t *ptr = 1084 (const uint8_t *)buffer->data() + buffer->range_offset(); 1085 1086 if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 1087 buffer->set_range( 1088 buffer->range_offset() + 4, buffer->range_length() - 4); 1089 } 1090} 1091 1092off64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 1093 off64_t old_offset = mOffset; 1094 1095 size_t length = buffer->range_length(); 1096 1097 if (mUse4ByteNalLength) { 1098 uint8_t x = length >> 24; 1099 ::write(mFd, &x, 1); 1100 x = (length >> 16) & 0xff; 1101 ::write(mFd, &x, 1); 1102 x = (length >> 8) & 0xff; 1103 ::write(mFd, &x, 1); 1104 x = length & 0xff; 1105 ::write(mFd, &x, 1); 1106 1107 ::write(mFd, 1108 (const uint8_t *)buffer->data() + buffer->range_offset(), 1109 length); 1110 1111 mOffset += length + 4; 1112 } else { 1113 CHECK_LT(length, 65536); 1114 1115 uint8_t x = length >> 8; 1116 ::write(mFd, &x, 1); 1117 x = length & 0xff; 1118 ::write(mFd, &x, 1); 1119 ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length); 1120 mOffset += length + 2; 1121 } 1122 1123 return old_offset; 1124} 1125 1126size_t MPEG4Writer::write( 1127 const void *ptr, size_t size, size_t nmemb) { 1128 1129 const size_t bytes = size * nmemb; 1130 if (mWriteMoovBoxToMemory) { 1131 1132 off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 1133 if (moovBoxSize > mEstimatedMoovBoxSize) { 1134 // The reserved moov box at the beginning of the file 1135 // is not big enough. Moov box should be written to 1136 // the end of the file from now on, but not to the 1137 // in-memory cache. 1138 1139 // We write partial moov box that is in the memory to 1140 // the file first. 1141 for (List<off64_t>::iterator it = mBoxes.begin(); 1142 it != mBoxes.end(); ++it) { 1143 (*it) += mOffset; 1144 } 1145 lseek64(mFd, mOffset, SEEK_SET); 1146 ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset); 1147 ::write(mFd, ptr, bytes); 1148 mOffset += (bytes + mMoovBoxBufferOffset); 1149 1150 // All subsequent moov box content will be written 1151 // to the end of the file. 1152 mWriteMoovBoxToMemory = false; 1153 } else { 1154 memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 1155 mMoovBoxBufferOffset += bytes; 1156 } 1157 } else { 1158 ::write(mFd, ptr, size * nmemb); 1159 mOffset += bytes; 1160 } 1161 return bytes; 1162} 1163 1164void MPEG4Writer::beginBox(uint32_t id) { 1165 mBoxes.push_back(mWriteMoovBoxToMemory? 1166 mMoovBoxBufferOffset: mOffset); 1167 1168 writeInt32(0); 1169 writeInt32(id); 1170} 1171 1172void MPEG4Writer::beginBox(const char *fourcc) { 1173 CHECK_EQ(strlen(fourcc), 4); 1174 1175 mBoxes.push_back(mWriteMoovBoxToMemory? 1176 mMoovBoxBufferOffset: mOffset); 1177 1178 writeInt32(0); 1179 writeFourcc(fourcc); 1180} 1181 1182void MPEG4Writer::endBox() { 1183 CHECK(!mBoxes.empty()); 1184 1185 off64_t offset = *--mBoxes.end(); 1186 mBoxes.erase(--mBoxes.end()); 1187 1188 if (mWriteMoovBoxToMemory) { 1189 int32_t x = htonl(mMoovBoxBufferOffset - offset); 1190 memcpy(mMoovBoxBuffer + offset, &x, 4); 1191 } else { 1192 lseek64(mFd, offset, SEEK_SET); 1193 writeInt32(mOffset - offset); 1194 mOffset -= 4; 1195 lseek64(mFd, mOffset, SEEK_SET); 1196 } 1197} 1198 1199void MPEG4Writer::writeInt8(int8_t x) { 1200 write(&x, 1, 1); 1201} 1202 1203void MPEG4Writer::writeInt16(int16_t x) { 1204 x = htons(x); 1205 write(&x, 1, 2); 1206} 1207 1208void MPEG4Writer::writeInt32(int32_t x) { 1209 x = htonl(x); 1210 write(&x, 1, 4); 1211} 1212 1213void MPEG4Writer::writeInt64(int64_t x) { 1214 x = hton64(x); 1215 write(&x, 1, 8); 1216} 1217 1218void MPEG4Writer::writeCString(const char *s) { 1219 size_t n = strlen(s); 1220 write(s, 1, n + 1); 1221} 1222 1223void MPEG4Writer::writeFourcc(const char *s) { 1224 CHECK_EQ(strlen(s), 4); 1225 write(s, 1, 4); 1226} 1227 1228 1229// Written in +/-DD.DDDD format 1230void MPEG4Writer::writeLatitude(int degreex10000) { 1231 bool isNegative = (degreex10000 < 0); 1232 char sign = isNegative? '-': '+'; 1233 1234 // Handle the whole part 1235 char str[9]; 1236 int wholePart = degreex10000 / 10000; 1237 if (wholePart == 0) { 1238 snprintf(str, 5, "%c%.2d.", sign, wholePart); 1239 } else { 1240 snprintf(str, 5, "%+.2d.", wholePart); 1241 } 1242 1243 // Handle the fractional part 1244 int fractionalPart = degreex10000 - (wholePart * 10000); 1245 if (fractionalPart < 0) { 1246 fractionalPart = -fractionalPart; 1247 } 1248 snprintf(&str[4], 5, "%.4d", fractionalPart); 1249 1250 // Do not write the null terminator 1251 write(str, 1, 8); 1252} 1253 1254// Written in +/- DDD.DDDD format 1255void MPEG4Writer::writeLongitude(int degreex10000) { 1256 bool isNegative = (degreex10000 < 0); 1257 char sign = isNegative? '-': '+'; 1258 1259 // Handle the whole part 1260 char str[10]; 1261 int wholePart = degreex10000 / 10000; 1262 if (wholePart == 0) { 1263 snprintf(str, 6, "%c%.3d.", sign, wholePart); 1264 } else { 1265 snprintf(str, 6, "%+.3d.", wholePart); 1266 } 1267 1268 // Handle the fractional part 1269 int fractionalPart = degreex10000 - (wholePart * 10000); 1270 if (fractionalPart < 0) { 1271 fractionalPart = -fractionalPart; 1272 } 1273 snprintf(&str[5], 5, "%.4d", fractionalPart); 1274 1275 // Do not write the null terminator 1276 write(str, 1, 9); 1277} 1278 1279/* 1280 * Geodata is stored according to ISO-6709 standard. 1281 * latitudex10000 is latitude in degrees times 10000, and 1282 * longitudex10000 is longitude in degrees times 10000. 1283 * The range for the latitude is in [-90, +90], and 1284 * The range for the longitude is in [-180, +180] 1285 */ 1286status_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) { 1287 // Is latitude or longitude out of range? 1288 if (latitudex10000 < -900000 || latitudex10000 > 900000 || 1289 longitudex10000 < -1800000 || longitudex10000 > 1800000) { 1290 return BAD_VALUE; 1291 } 1292 1293 mLatitudex10000 = latitudex10000; 1294 mLongitudex10000 = longitudex10000; 1295 mAreGeoTagsAvailable = true; 1296 mMoovExtraSize += 30; 1297 return OK; 1298} 1299 1300status_t MPEG4Writer::setCaptureRate(float captureFps) { 1301 if (captureFps <= 0.0f) { 1302 return BAD_VALUE; 1303 } 1304 1305 mMetaKeys->setFloat(kMetaKey_CaptureFps, captureFps); 1306 mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32; 1307 1308 return OK; 1309} 1310 1311void MPEG4Writer::write(const void *data, size_t size) { 1312 write(data, 1, size); 1313} 1314 1315bool MPEG4Writer::isFileStreamable() const { 1316 return mStreamableFile; 1317} 1318 1319bool MPEG4Writer::exceedsFileSizeLimit() { 1320 // No limit 1321 if (mMaxFileSizeLimitBytes == 0) { 1322 return false; 1323 } 1324 1325 int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 1326 for (List<Track *>::iterator it = mTracks.begin(); 1327 it != mTracks.end(); ++it) { 1328 nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 1329 } 1330 1331 if (!mStreamableFile) { 1332 // Add 1024 bytes as error tolerance 1333 return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes; 1334 } 1335 // Be conservative in the estimate: do not exceed 95% of 1336 // the target file limit. For small target file size limit, though, 1337 // this will not help. 1338 return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100); 1339} 1340 1341bool MPEG4Writer::exceedsFileDurationLimit() { 1342 // No limit 1343 if (mMaxFileDurationLimitUs == 0) { 1344 return false; 1345 } 1346 1347 for (List<Track *>::iterator it = mTracks.begin(); 1348 it != mTracks.end(); ++it) { 1349 if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 1350 return true; 1351 } 1352 } 1353 return false; 1354} 1355 1356bool MPEG4Writer::reachedEOS() { 1357 bool allDone = true; 1358 for (List<Track *>::iterator it = mTracks.begin(); 1359 it != mTracks.end(); ++it) { 1360 if (!(*it)->reachedEOS()) { 1361 allDone = false; 1362 break; 1363 } 1364 } 1365 1366 return allDone; 1367} 1368 1369void MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 1370 ALOGI("setStartTimestampUs: %" PRId64, timeUs); 1371 CHECK_GE(timeUs, 0ll); 1372 Mutex::Autolock autoLock(mLock); 1373 if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 1374 mStartTimestampUs = timeUs; 1375 ALOGI("Earliest track starting time: %" PRId64, mStartTimestampUs); 1376 } 1377} 1378 1379int64_t MPEG4Writer::getStartTimestampUs() { 1380 Mutex::Autolock autoLock(mLock); 1381 return mStartTimestampUs; 1382} 1383 1384size_t MPEG4Writer::numTracks() { 1385 Mutex::Autolock autolock(mLock); 1386 return mTracks.size(); 1387} 1388 1389//////////////////////////////////////////////////////////////////////////////// 1390 1391MPEG4Writer::Track::Track( 1392 MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId) 1393 : mOwner(owner), 1394 mMeta(source->getFormat()), 1395 mSource(source), 1396 mDone(false), 1397 mPaused(false), 1398 mResumed(false), 1399 mStarted(false), 1400 mTrackId(trackId), 1401 mTrackDurationUs(0), 1402 mEstimatedTrackSizeBytes(0), 1403 mSamplesHaveSameSize(true), 1404 mStszTableEntries(new ListTableEntries<uint32_t>(1000, 1)), 1405 mStcoTableEntries(new ListTableEntries<uint32_t>(1000, 1)), 1406 mCo64TableEntries(new ListTableEntries<off64_t>(1000, 1)), 1407 mStscTableEntries(new ListTableEntries<uint32_t>(1000, 3)), 1408 mStssTableEntries(new ListTableEntries<uint32_t>(1000, 1)), 1409 mSttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)), 1410 mCttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)), 1411 mCodecSpecificData(NULL), 1412 mCodecSpecificDataSize(0), 1413 mGotAllCodecSpecificData(false), 1414 mReachedEOS(false), 1415 mRotation(0) { 1416 getCodecSpecificDataFromInputFormatIfPossible(); 1417 1418 const char *mime; 1419 mMeta->findCString(kKeyMIMEType, &mime); 1420 mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 1421 mIsAudio = !strncasecmp(mime, "audio/", 6); 1422 mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 1423 !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 1424 1425 setTimeScale(); 1426} 1427 1428void MPEG4Writer::Track::updateTrackSizeEstimate() { 1429 1430 uint32_t stcoBoxCount = (mOwner->use32BitFileOffset() 1431 ? mStcoTableEntries->count() 1432 : mCo64TableEntries->count()); 1433 int64_t stcoBoxSizeBytes = stcoBoxCount * 4; 1434 int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4); 1435 1436 mEstimatedTrackSizeBytes = mMdatSizeBytes; // media data size 1437 if (!mOwner->isFileStreamable()) { 1438 // Reserved free space is not large enough to hold 1439 // all meta data and thus wasted. 1440 mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 + // stsc box size 1441 mStssTableEntries->count() * 4 + // stss box size 1442 mSttsTableEntries->count() * 8 + // stts box size 1443 mCttsTableEntries->count() * 8 + // ctts box size 1444 stcoBoxSizeBytes + // stco box size 1445 stszBoxSizeBytes; // stsz box size 1446 } 1447} 1448 1449void MPEG4Writer::Track::addOneStscTableEntry( 1450 size_t chunkId, size_t sampleId) { 1451 1452 mStscTableEntries->add(htonl(chunkId)); 1453 mStscTableEntries->add(htonl(sampleId)); 1454 mStscTableEntries->add(htonl(1)); 1455} 1456 1457void MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) { 1458 mStssTableEntries->add(htonl(sampleId)); 1459} 1460 1461void MPEG4Writer::Track::addOneSttsTableEntry( 1462 size_t sampleCount, int32_t duration) { 1463 1464 if (duration == 0) { 1465 ALOGW("0-duration samples found: %zu", sampleCount); 1466 } 1467 mSttsTableEntries->add(htonl(sampleCount)); 1468 mSttsTableEntries->add(htonl(duration)); 1469} 1470 1471void MPEG4Writer::Track::addOneCttsTableEntry( 1472 size_t sampleCount, int32_t duration) { 1473 1474 if (mIsAudio) { 1475 return; 1476 } 1477 mCttsTableEntries->add(htonl(sampleCount)); 1478 mCttsTableEntries->add(htonl(duration)); 1479} 1480 1481void MPEG4Writer::Track::addChunkOffset(off64_t offset) { 1482 if (mOwner->use32BitFileOffset()) { 1483 uint32_t value = offset; 1484 mStcoTableEntries->add(htonl(value)); 1485 } else { 1486 mCo64TableEntries->add(hton64(offset)); 1487 } 1488} 1489 1490void MPEG4Writer::Track::setTimeScale() { 1491 ALOGV("setTimeScale"); 1492 // Default time scale 1493 mTimeScale = 90000; 1494 1495 if (mIsAudio) { 1496 // Use the sampling rate as the default time scale for audio track. 1497 int32_t sampleRate; 1498 bool success = mMeta->findInt32(kKeySampleRate, &sampleRate); 1499 CHECK(success); 1500 mTimeScale = sampleRate; 1501 } 1502 1503 // If someone would like to overwrite the timescale, use user-supplied value. 1504 int32_t timeScale; 1505 if (mMeta->findInt32(kKeyTimeScale, &timeScale)) { 1506 mTimeScale = timeScale; 1507 } 1508 1509 CHECK_GT(mTimeScale, 0); 1510} 1511 1512void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 1513 const char *mime; 1514 CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 1515 1516 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 1517 uint32_t type; 1518 const void *data; 1519 size_t size; 1520 if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { 1521 mCodecSpecificData = malloc(size); 1522 mCodecSpecificDataSize = size; 1523 memcpy(mCodecSpecificData, data, size); 1524 mGotAllCodecSpecificData = true; 1525 } 1526 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 1527 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 1528 uint32_t type; 1529 const void *data; 1530 size_t size; 1531 if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 1532 ESDS esds(data, size); 1533 if (esds.getCodecSpecificInfo(&data, &size) == OK) { 1534 mCodecSpecificData = malloc(size); 1535 mCodecSpecificDataSize = size; 1536 memcpy(mCodecSpecificData, data, size); 1537 mGotAllCodecSpecificData = true; 1538 } 1539 } 1540 } 1541} 1542 1543MPEG4Writer::Track::~Track() { 1544 stop(); 1545 1546 delete mStszTableEntries; 1547 delete mStcoTableEntries; 1548 delete mCo64TableEntries; 1549 delete mStscTableEntries; 1550 delete mSttsTableEntries; 1551 delete mStssTableEntries; 1552 delete mCttsTableEntries; 1553 1554 mStszTableEntries = NULL; 1555 mStcoTableEntries = NULL; 1556 mCo64TableEntries = NULL; 1557 mStscTableEntries = NULL; 1558 mSttsTableEntries = NULL; 1559 mStssTableEntries = NULL; 1560 mCttsTableEntries = NULL; 1561 1562 if (mCodecSpecificData != NULL) { 1563 free(mCodecSpecificData); 1564 mCodecSpecificData = NULL; 1565 } 1566} 1567 1568void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 1569 ALOGV("initTrackingProgressStatus"); 1570 mPreviousTrackTimeUs = -1; 1571 mTrackingProgressStatus = false; 1572 mTrackEveryTimeDurationUs = 0; 1573 { 1574 int64_t timeUs; 1575 if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 1576 ALOGV("Receive request to track progress status for every %" PRId64 " us", timeUs); 1577 mTrackEveryTimeDurationUs = timeUs; 1578 mTrackingProgressStatus = true; 1579 } 1580 } 1581} 1582 1583// static 1584void *MPEG4Writer::ThreadWrapper(void *me) { 1585 ALOGV("ThreadWrapper: %p", me); 1586 MPEG4Writer *writer = static_cast<MPEG4Writer *>(me); 1587 writer->threadFunc(); 1588 return NULL; 1589} 1590 1591void MPEG4Writer::bufferChunk(const Chunk& chunk) { 1592 ALOGV("bufferChunk: %p", chunk.mTrack); 1593 Mutex::Autolock autolock(mLock); 1594 CHECK_EQ(mDone, false); 1595 1596 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 1597 it != mChunkInfos.end(); ++it) { 1598 1599 if (chunk.mTrack == it->mTrack) { // Found owner 1600 it->mChunks.push_back(chunk); 1601 mChunkReadyCondition.signal(); 1602 return; 1603 } 1604 } 1605 1606 CHECK(!"Received a chunk for a unknown track"); 1607} 1608 1609void MPEG4Writer::writeChunkToFile(Chunk* chunk) { 1610 ALOGV("writeChunkToFile: %" PRId64 " from %s track", 1611 chunk->mTimeStampUs, chunk->mTrack->isAudio()? "audio": "video"); 1612 1613 int32_t isFirstSample = true; 1614 while (!chunk->mSamples.empty()) { 1615 List<MediaBuffer *>::iterator it = chunk->mSamples.begin(); 1616 1617 off64_t offset = chunk->mTrack->isAvc() 1618 ? addLengthPrefixedSample_l(*it) 1619 : addSample_l(*it); 1620 1621 if (isFirstSample) { 1622 chunk->mTrack->addChunkOffset(offset); 1623 isFirstSample = false; 1624 } 1625 1626 (*it)->release(); 1627 (*it) = NULL; 1628 chunk->mSamples.erase(it); 1629 } 1630 chunk->mSamples.clear(); 1631} 1632 1633void MPEG4Writer::writeAllChunks() { 1634 ALOGV("writeAllChunks"); 1635 size_t outstandingChunks = 0; 1636 Chunk chunk; 1637 while (findChunkToWrite(&chunk)) { 1638 writeChunkToFile(&chunk); 1639 ++outstandingChunks; 1640 } 1641 1642 sendSessionSummary(); 1643 1644 mChunkInfos.clear(); 1645 ALOGD("%zu chunks are written in the last batch", outstandingChunks); 1646} 1647 1648bool MPEG4Writer::findChunkToWrite(Chunk *chunk) { 1649 ALOGV("findChunkToWrite"); 1650 1651 int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL; 1652 Track *track = NULL; 1653 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 1654 it != mChunkInfos.end(); ++it) { 1655 if (!it->mChunks.empty()) { 1656 List<Chunk>::iterator chunkIt = it->mChunks.begin(); 1657 if (chunkIt->mTimeStampUs < minTimestampUs) { 1658 minTimestampUs = chunkIt->mTimeStampUs; 1659 track = it->mTrack; 1660 } 1661 } 1662 } 1663 1664 if (track == NULL) { 1665 ALOGV("Nothing to be written after all"); 1666 return false; 1667 } 1668 1669 if (mIsFirstChunk) { 1670 mIsFirstChunk = false; 1671 } 1672 1673 for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); 1674 it != mChunkInfos.end(); ++it) { 1675 if (it->mTrack == track) { 1676 *chunk = *(it->mChunks.begin()); 1677 it->mChunks.erase(it->mChunks.begin()); 1678 CHECK_EQ(chunk->mTrack, track); 1679 1680 int64_t interChunkTimeUs = 1681 chunk->mTimeStampUs - it->mPrevChunkTimestampUs; 1682 if (interChunkTimeUs > it->mPrevChunkTimestampUs) { 1683 it->mMaxInterChunkDurUs = interChunkTimeUs; 1684 } 1685 1686 return true; 1687 } 1688 } 1689 1690 return false; 1691} 1692 1693void MPEG4Writer::threadFunc() { 1694 ALOGV("threadFunc"); 1695 1696 prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0); 1697 1698 Mutex::Autolock autoLock(mLock); 1699 while (!mDone) { 1700 Chunk chunk; 1701 bool chunkFound = false; 1702 1703 while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) { 1704 mChunkReadyCondition.wait(mLock); 1705 } 1706 1707 // In real time recording mode, write without holding the lock in order 1708 // to reduce the blocking time for media track threads. 1709 // Otherwise, hold the lock until the existing chunks get written to the 1710 // file. 1711 if (chunkFound) { 1712 if (mIsRealTimeRecording) { 1713 mLock.unlock(); 1714 } 1715 writeChunkToFile(&chunk); 1716 if (mIsRealTimeRecording) { 1717 mLock.lock(); 1718 } 1719 } 1720 } 1721 1722 writeAllChunks(); 1723} 1724 1725status_t MPEG4Writer::startWriterThread() { 1726 ALOGV("startWriterThread"); 1727 1728 mDone = false; 1729 mIsFirstChunk = true; 1730 mDriftTimeUs = 0; 1731 for (List<Track *>::iterator it = mTracks.begin(); 1732 it != mTracks.end(); ++it) { 1733 ChunkInfo info; 1734 info.mTrack = *it; 1735 info.mPrevChunkTimestampUs = 0; 1736 info.mMaxInterChunkDurUs = 0; 1737 mChunkInfos.push_back(info); 1738 } 1739 1740 pthread_attr_t attr; 1741 pthread_attr_init(&attr); 1742 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 1743 pthread_create(&mThread, &attr, ThreadWrapper, this); 1744 pthread_attr_destroy(&attr); 1745 mWriterThreadStarted = true; 1746 return OK; 1747} 1748 1749 1750status_t MPEG4Writer::Track::start(MetaData *params) { 1751 if (!mDone && mPaused) { 1752 mPaused = false; 1753 mResumed = true; 1754 return OK; 1755 } 1756 1757 int64_t startTimeUs; 1758 if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 1759 startTimeUs = 0; 1760 } 1761 mStartTimeRealUs = startTimeUs; 1762 1763 int32_t rotationDegrees; 1764 if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) { 1765 mRotation = rotationDegrees; 1766 } 1767 1768 initTrackingProgressStatus(params); 1769 1770 sp<MetaData> meta = new MetaData; 1771 if (mOwner->isRealTimeRecording() && mOwner->numTracks() > 1) { 1772 /* 1773 * This extra delay of accepting incoming audio/video signals 1774 * helps to align a/v start time at the beginning of a recording 1775 * session, and it also helps eliminate the "recording" sound for 1776 * camcorder applications. 1777 * 1778 * If client does not set the start time offset, we fall back to 1779 * use the default initial delay value. 1780 */ 1781 int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 1782 if (startTimeOffsetUs < 0) { // Start time offset was not set 1783 startTimeOffsetUs = kInitialDelayTimeUs; 1784 } 1785 startTimeUs += startTimeOffsetUs; 1786 ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs); 1787 } 1788 1789 meta->setInt64(kKeyTime, startTimeUs); 1790 1791 status_t err = mSource->start(meta.get()); 1792 if (err != OK) { 1793 mDone = mReachedEOS = true; 1794 return err; 1795 } 1796 1797 pthread_attr_t attr; 1798 pthread_attr_init(&attr); 1799 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 1800 1801 mDone = false; 1802 mStarted = true; 1803 mTrackDurationUs = 0; 1804 mReachedEOS = false; 1805 mEstimatedTrackSizeBytes = 0; 1806 mMdatSizeBytes = 0; 1807 mMaxChunkDurationUs = 0; 1808 1809 pthread_create(&mThread, &attr, ThreadWrapper, this); 1810 pthread_attr_destroy(&attr); 1811 1812 return OK; 1813} 1814 1815status_t MPEG4Writer::Track::pause() { 1816 mPaused = true; 1817 return OK; 1818} 1819 1820status_t MPEG4Writer::Track::stop() { 1821 ALOGD("%s track stopping", mIsAudio? "Audio": "Video"); 1822 if (!mStarted) { 1823 ALOGE("Stop() called but track is not started"); 1824 return ERROR_END_OF_STREAM; 1825 } 1826 1827 if (mDone) { 1828 return OK; 1829 } 1830 mDone = true; 1831 1832 ALOGD("%s track source stopping", mIsAudio? "Audio": "Video"); 1833 mSource->stop(); 1834 ALOGD("%s track source stopped", mIsAudio? "Audio": "Video"); 1835 1836 void *dummy; 1837 pthread_join(mThread, &dummy); 1838 status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); 1839 1840 ALOGD("%s track stopped", mIsAudio? "Audio": "Video"); 1841 return err; 1842} 1843 1844bool MPEG4Writer::Track::reachedEOS() { 1845 return mReachedEOS; 1846} 1847 1848// static 1849void *MPEG4Writer::Track::ThreadWrapper(void *me) { 1850 Track *track = static_cast<Track *>(me); 1851 1852 status_t err = track->threadEntry(); 1853 return (void *)(uintptr_t)err; 1854} 1855 1856static void getNalUnitType(uint8_t byte, uint8_t* type) { 1857 ALOGV("getNalUnitType: %d", byte); 1858 1859 // nal_unit_type: 5-bit unsigned integer 1860 *type = (byte & 0x1F); 1861} 1862 1863static const uint8_t *findNextStartCode( 1864 const uint8_t *data, size_t length) { 1865 1866 ALOGV("findNextStartCode: %p %zu", data, length); 1867 1868 size_t bytesLeft = length; 1869 while (bytesLeft > 4 && 1870 memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) { 1871 --bytesLeft; 1872 } 1873 if (bytesLeft <= 4) { 1874 bytesLeft = 0; // Last parameter set 1875 } 1876 return &data[length - bytesLeft]; 1877} 1878 1879const uint8_t *MPEG4Writer::Track::parseParamSet( 1880 const uint8_t *data, size_t length, int type, size_t *paramSetLen) { 1881 1882 ALOGV("parseParamSet"); 1883 CHECK(type == kNalUnitTypeSeqParamSet || 1884 type == kNalUnitTypePicParamSet); 1885 1886 const uint8_t *nextStartCode = findNextStartCode(data, length); 1887 *paramSetLen = nextStartCode - data; 1888 if (*paramSetLen == 0) { 1889 ALOGE("Param set is malformed, since its length is 0"); 1890 return NULL; 1891 } 1892 1893 AVCParamSet paramSet(*paramSetLen, data); 1894 if (type == kNalUnitTypeSeqParamSet) { 1895 if (*paramSetLen < 4) { 1896 ALOGE("Seq parameter set malformed"); 1897 return NULL; 1898 } 1899 if (mSeqParamSets.empty()) { 1900 mProfileIdc = data[1]; 1901 mProfileCompatible = data[2]; 1902 mLevelIdc = data[3]; 1903 } else { 1904 if (mProfileIdc != data[1] || 1905 mProfileCompatible != data[2] || 1906 mLevelIdc != data[3]) { 1907 ALOGE("Inconsistent profile/level found in seq parameter sets"); 1908 return NULL; 1909 } 1910 } 1911 mSeqParamSets.push_back(paramSet); 1912 } else { 1913 mPicParamSets.push_back(paramSet); 1914 } 1915 return nextStartCode; 1916} 1917 1918status_t MPEG4Writer::Track::copyAVCCodecSpecificData( 1919 const uint8_t *data, size_t size) { 1920 ALOGV("copyAVCCodecSpecificData"); 1921 1922 // 2 bytes for each of the parameter set length field 1923 // plus the 7 bytes for the header 1924 if (size < 4 + 7) { 1925 ALOGE("Codec specific data length too short: %zu", size); 1926 return ERROR_MALFORMED; 1927 } 1928 1929 mCodecSpecificDataSize = size; 1930 mCodecSpecificData = malloc(size); 1931 memcpy(mCodecSpecificData, data, size); 1932 return OK; 1933} 1934 1935status_t MPEG4Writer::Track::parseAVCCodecSpecificData( 1936 const uint8_t *data, size_t size) { 1937 1938 ALOGV("parseAVCCodecSpecificData"); 1939 // Data starts with a start code. 1940 // SPS and PPS are separated with start codes. 1941 // Also, SPS must come before PPS 1942 uint8_t type = kNalUnitTypeSeqParamSet; 1943 bool gotSps = false; 1944 bool gotPps = false; 1945 const uint8_t *tmp = data; 1946 const uint8_t *nextStartCode = data; 1947 size_t bytesLeft = size; 1948 size_t paramSetLen = 0; 1949 mCodecSpecificDataSize = 0; 1950 while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { 1951 getNalUnitType(*(tmp + 4), &type); 1952 if (type == kNalUnitTypeSeqParamSet) { 1953 if (gotPps) { 1954 ALOGE("SPS must come before PPS"); 1955 return ERROR_MALFORMED; 1956 } 1957 if (!gotSps) { 1958 gotSps = true; 1959 } 1960 nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 1961 } else if (type == kNalUnitTypePicParamSet) { 1962 if (!gotSps) { 1963 ALOGE("SPS must come before PPS"); 1964 return ERROR_MALFORMED; 1965 } 1966 if (!gotPps) { 1967 gotPps = true; 1968 } 1969 nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, ¶mSetLen); 1970 } else { 1971 ALOGE("Only SPS and PPS Nal units are expected"); 1972 return ERROR_MALFORMED; 1973 } 1974 1975 if (nextStartCode == NULL) { 1976 return ERROR_MALFORMED; 1977 } 1978 1979 // Move on to find the next parameter set 1980 bytesLeft -= nextStartCode - tmp; 1981 tmp = nextStartCode; 1982 mCodecSpecificDataSize += (2 + paramSetLen); 1983 } 1984 1985 { 1986 // Check on the number of seq parameter sets 1987 size_t nSeqParamSets = mSeqParamSets.size(); 1988 if (nSeqParamSets == 0) { 1989 ALOGE("Cound not find sequence parameter set"); 1990 return ERROR_MALFORMED; 1991 } 1992 1993 if (nSeqParamSets > 0x1F) { 1994 ALOGE("Too many seq parameter sets (%zu) found", nSeqParamSets); 1995 return ERROR_MALFORMED; 1996 } 1997 } 1998 1999 { 2000 // Check on the number of pic parameter sets 2001 size_t nPicParamSets = mPicParamSets.size(); 2002 if (nPicParamSets == 0) { 2003 ALOGE("Cound not find picture parameter set"); 2004 return ERROR_MALFORMED; 2005 } 2006 if (nPicParamSets > 0xFF) { 2007 ALOGE("Too many pic parameter sets (%zd) found", nPicParamSets); 2008 return ERROR_MALFORMED; 2009 } 2010 } 2011// FIXME: 2012// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above 2013// and remove #if 0 2014#if 0 2015 { 2016 // Check on the profiles 2017 // These profiles requires additional parameter set extensions 2018 if (mProfileIdc == 100 || mProfileIdc == 110 || 2019 mProfileIdc == 122 || mProfileIdc == 144) { 2020 ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc); 2021 return BAD_VALUE; 2022 } 2023 } 2024#endif 2025 return OK; 2026} 2027 2028status_t MPEG4Writer::Track::makeAVCCodecSpecificData( 2029 const uint8_t *data, size_t size) { 2030 2031 if (mCodecSpecificData != NULL) { 2032 ALOGE("Already have codec specific data"); 2033 return ERROR_MALFORMED; 2034 } 2035 2036 if (size < 4) { 2037 ALOGE("Codec specific data length too short: %zu", size); 2038 return ERROR_MALFORMED; 2039 } 2040 2041 // Data is in the form of AVCCodecSpecificData 2042 if (memcmp("\x00\x00\x00\x01", data, 4)) { 2043 return copyAVCCodecSpecificData(data, size); 2044 } 2045 2046 if (parseAVCCodecSpecificData(data, size) != OK) { 2047 return ERROR_MALFORMED; 2048 } 2049 2050 // ISO 14496-15: AVC file format 2051 mCodecSpecificDataSize += 7; // 7 more bytes in the header 2052 mCodecSpecificData = malloc(mCodecSpecificDataSize); 2053 uint8_t *header = (uint8_t *)mCodecSpecificData; 2054 header[0] = 1; // version 2055 header[1] = mProfileIdc; // profile indication 2056 header[2] = mProfileCompatible; // profile compatibility 2057 header[3] = mLevelIdc; 2058 2059 // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne 2060 if (mOwner->useNalLengthFour()) { 2061 header[4] = 0xfc | 3; // length size == 4 bytes 2062 } else { 2063 header[4] = 0xfc | 1; // length size == 2 bytes 2064 } 2065 2066 // 3-bit '111' followed by 5-bit numSequenceParameterSets 2067 int nSequenceParamSets = mSeqParamSets.size(); 2068 header[5] = 0xe0 | nSequenceParamSets; 2069 header += 6; 2070 for (List<AVCParamSet>::iterator it = mSeqParamSets.begin(); 2071 it != mSeqParamSets.end(); ++it) { 2072 // 16-bit sequence parameter set length 2073 uint16_t seqParamSetLength = it->mLength; 2074 header[0] = seqParamSetLength >> 8; 2075 header[1] = seqParamSetLength & 0xff; 2076 2077 // SPS NAL unit (sequence parameter length bytes) 2078 memcpy(&header[2], it->mData, seqParamSetLength); 2079 header += (2 + seqParamSetLength); 2080 } 2081 2082 // 8-bit nPictureParameterSets 2083 int nPictureParamSets = mPicParamSets.size(); 2084 header[0] = nPictureParamSets; 2085 header += 1; 2086 for (List<AVCParamSet>::iterator it = mPicParamSets.begin(); 2087 it != mPicParamSets.end(); ++it) { 2088 // 16-bit picture parameter set length 2089 uint16_t picParamSetLength = it->mLength; 2090 header[0] = picParamSetLength >> 8; 2091 header[1] = picParamSetLength & 0xff; 2092 2093 // PPS Nal unit (picture parameter set length bytes) 2094 memcpy(&header[2], it->mData, picParamSetLength); 2095 header += (2 + picParamSetLength); 2096 } 2097 2098 return OK; 2099} 2100 2101/* 2102 * Updates the drift time from the audio track so that 2103 * the video track can get the updated drift time information 2104 * from the file writer. The fluctuation of the drift time of the audio 2105 * encoding path is smoothed out with a simple filter by giving a larger 2106 * weight to more recently drift time. The filter coefficients, 0.5 and 0.5, 2107 * are heuristically determined. 2108 */ 2109void MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) { 2110 int64_t driftTimeUs = 0; 2111 if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) { 2112 int64_t prevDriftTimeUs = mOwner->getDriftTimeUs(); 2113 int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1; 2114 mOwner->setDriftTimeUs(timeUs); 2115 } 2116} 2117 2118status_t MPEG4Writer::Track::threadEntry() { 2119 int32_t count = 0; 2120 const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 2121 const bool hasMultipleTracks = (mOwner->numTracks() > 1); 2122 int64_t chunkTimestampUs = 0; 2123 int32_t nChunks = 0; 2124 int32_t nZeroLengthFrames = 0; 2125 int64_t lastTimestampUs = 0; // Previous sample time stamp 2126 int64_t lastDurationUs = 0; // Between the previous two samples 2127 int64_t currDurationTicks = 0; // Timescale based ticks 2128 int64_t lastDurationTicks = 0; // Timescale based ticks 2129 int32_t sampleCount = 1; // Sample count in the current stts table entry 2130 uint32_t previousSampleSize = 0; // Size of the previous sample 2131 int64_t previousPausedDurationUs = 0; 2132 int64_t timestampUs = 0; 2133 int64_t cttsOffsetTimeUs = 0; 2134 int64_t currCttsOffsetTimeTicks = 0; // Timescale based ticks 2135 int64_t lastCttsOffsetTimeTicks = -1; // Timescale based ticks 2136 int32_t cttsSampleCount = 0; // Sample count in the current ctts table entry 2137 uint32_t lastSamplesPerChunk = 0; 2138 2139 if (mIsAudio) { 2140 prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0); 2141 } else { 2142 prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0); 2143 } 2144 2145 if (mOwner->isRealTimeRecording()) { 2146 androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO); 2147 } 2148 2149 sp<MetaData> meta_data; 2150 2151 status_t err = OK; 2152 MediaBuffer *buffer; 2153 const char *trackName = mIsAudio ? "Audio" : "Video"; 2154 while (!mDone && (err = mSource->read(&buffer)) == OK) { 2155 if (buffer->range_length() == 0) { 2156 buffer->release(); 2157 buffer = NULL; 2158 ++nZeroLengthFrames; 2159 continue; 2160 } 2161 2162 // If the codec specific data has not been received yet, delay pause. 2163 // After the codec specific data is received, discard what we received 2164 // when the track is to be paused. 2165 if (mPaused && !mResumed) { 2166 buffer->release(); 2167 buffer = NULL; 2168 continue; 2169 } 2170 2171 ++count; 2172 2173 int32_t isCodecConfig; 2174 if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 2175 && isCodecConfig) { 2176 CHECK(!mGotAllCodecSpecificData); 2177 2178 if (mIsAvc) { 2179 status_t err = makeAVCCodecSpecificData( 2180 (const uint8_t *)buffer->data() 2181 + buffer->range_offset(), 2182 buffer->range_length()); 2183 CHECK_EQ((status_t)OK, err); 2184 } else if (mIsMPEG4) { 2185 mCodecSpecificDataSize = buffer->range_length(); 2186 mCodecSpecificData = malloc(mCodecSpecificDataSize); 2187 memcpy(mCodecSpecificData, 2188 (const uint8_t *)buffer->data() 2189 + buffer->range_offset(), 2190 buffer->range_length()); 2191 } 2192 2193 buffer->release(); 2194 buffer = NULL; 2195 2196 mGotAllCodecSpecificData = true; 2197 continue; 2198 } 2199 2200 // Make a deep copy of the MediaBuffer and Metadata and release 2201 // the original as soon as we can 2202 MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 2203 memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 2204 buffer->range_length()); 2205 copy->set_range(0, buffer->range_length()); 2206 meta_data = new MetaData(*buffer->meta_data().get()); 2207 buffer->release(); 2208 buffer = NULL; 2209 2210 if (mIsAvc) StripStartcode(copy); 2211 2212 size_t sampleSize = copy->range_length(); 2213 if (mIsAvc) { 2214 if (mOwner->useNalLengthFour()) { 2215 sampleSize += 4; 2216 } else { 2217 sampleSize += 2; 2218 } 2219 } 2220 2221 // Max file size or duration handling 2222 mMdatSizeBytes += sampleSize; 2223 updateTrackSizeEstimate(); 2224 2225 if (mOwner->exceedsFileSizeLimit()) { 2226 mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 2227 break; 2228 } 2229 if (mOwner->exceedsFileDurationLimit()) { 2230 mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 2231 break; 2232 } 2233 2234 2235 int32_t isSync = false; 2236 meta_data->findInt32(kKeyIsSyncFrame, &isSync); 2237 CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 2238 2239//////////////////////////////////////////////////////////////////////////////// 2240 if (mStszTableEntries->count() == 0) { 2241 mFirstSampleTimeRealUs = systemTime() / 1000; 2242 mStartTimestampUs = timestampUs; 2243 mOwner->setStartTimestampUs(mStartTimestampUs); 2244 previousPausedDurationUs = mStartTimestampUs; 2245 } 2246 2247 if (mResumed) { 2248 int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 2249 if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) { 2250 copy->release(); 2251 return ERROR_MALFORMED; 2252 } 2253 2254 int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 2255 if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) { 2256 copy->release(); 2257 return ERROR_MALFORMED; 2258 } 2259 2260 previousPausedDurationUs += pausedDurationUs - lastDurationUs; 2261 mResumed = false; 2262 } 2263 2264 timestampUs -= previousPausedDurationUs; 2265 if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { 2266 copy->release(); 2267 return ERROR_MALFORMED; 2268 } 2269 2270 if (!mIsAudio) { 2271 /* 2272 * Composition time: timestampUs 2273 * Decoding time: decodingTimeUs 2274 * Composition time offset = composition time - decoding time 2275 */ 2276 int64_t decodingTimeUs; 2277 CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs)); 2278 decodingTimeUs -= previousPausedDurationUs; 2279 cttsOffsetTimeUs = 2280 timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs; 2281 if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) { 2282 copy->release(); 2283 return ERROR_MALFORMED; 2284 } 2285 2286 timestampUs = decodingTimeUs; 2287 ALOGV("decoding time: %" PRId64 " and ctts offset time: %" PRId64, 2288 timestampUs, cttsOffsetTimeUs); 2289 2290 // Update ctts box table if necessary 2291 currCttsOffsetTimeTicks = 2292 (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL; 2293 if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) { 2294 copy->release(); 2295 return ERROR_MALFORMED; 2296 } 2297 2298 if (mStszTableEntries->count() == 0) { 2299 // Force the first ctts table entry to have one single entry 2300 // so that we can do adjustment for the initial track start 2301 // time offset easily in writeCttsBox(). 2302 lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks; 2303 addOneCttsTableEntry(1, currCttsOffsetTimeTicks); 2304 cttsSampleCount = 0; // No sample in ctts box is pending 2305 } else { 2306 if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) { 2307 addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks); 2308 lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks; 2309 cttsSampleCount = 1; // One sample in ctts box is pending 2310 } else { 2311 ++cttsSampleCount; 2312 } 2313 } 2314 2315 // Update ctts time offset range 2316 if (mStszTableEntries->count() == 0) { 2317 mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2318 mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2319 } else { 2320 if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) { 2321 mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2322 } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) { 2323 mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks; 2324 } 2325 } 2326 2327 } 2328 2329 if (mOwner->isRealTimeRecording()) { 2330 if (mIsAudio) { 2331 updateDriftTime(meta_data); 2332 } 2333 } 2334 2335 if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { 2336 copy->release(); 2337 return ERROR_MALFORMED; 2338 } 2339 2340 ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64, 2341 trackName, timestampUs, previousPausedDurationUs); 2342 if (timestampUs > mTrackDurationUs) { 2343 mTrackDurationUs = timestampUs; 2344 } 2345 2346 // We need to use the time scale based ticks, rather than the 2347 // timestamp itself to determine whether we have to use a new 2348 // stts entry, since we may have rounding errors. 2349 // The calculation is intended to reduce the accumulated 2350 // rounding errors. 2351 currDurationTicks = 2352 ((timestampUs * mTimeScale + 500000LL) / 1000000LL - 2353 (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); 2354 if (currDurationTicks < 0ll) { 2355 ALOGE("timestampUs %" PRId64 " < lastTimestampUs %" PRId64 " for %s track", 2356 timestampUs, lastTimestampUs, trackName); 2357 copy->release(); 2358 return UNKNOWN_ERROR; 2359 } 2360 2361 // if the duration is different for this sample, see if it is close enough to the previous 2362 // duration that we can fudge it and use the same value, to avoid filling the stts table 2363 // with lots of near-identical entries. 2364 // "close enough" here means that the current duration needs to be adjusted by less 2365 // than 0.1 milliseconds 2366 if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) { 2367 int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL 2368 + (mTimeScale / 2)) / mTimeScale; 2369 if (deltaUs > -100 && deltaUs < 100) { 2370 // use previous ticks, and adjust timestamp as if it was actually that number 2371 // of ticks 2372 currDurationTicks = lastDurationTicks; 2373 timestampUs += deltaUs; 2374 } 2375 } 2376 2377 mStszTableEntries->add(htonl(sampleSize)); 2378 if (mStszTableEntries->count() > 2) { 2379 2380 // Force the first sample to have its own stts entry so that 2381 // we can adjust its value later to maintain the A/V sync. 2382 if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) { 2383 addOneSttsTableEntry(sampleCount, lastDurationTicks); 2384 sampleCount = 1; 2385 } else { 2386 ++sampleCount; 2387 } 2388 2389 } 2390 if (mSamplesHaveSameSize) { 2391 if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) { 2392 mSamplesHaveSameSize = false; 2393 } 2394 previousSampleSize = sampleSize; 2395 } 2396 ALOGV("%s timestampUs/lastTimestampUs: %" PRId64 "/%" PRId64, 2397 trackName, timestampUs, lastTimestampUs); 2398 lastDurationUs = timestampUs - lastTimestampUs; 2399 lastDurationTicks = currDurationTicks; 2400 lastTimestampUs = timestampUs; 2401 2402 if (isSync != 0) { 2403 addOneStssTableEntry(mStszTableEntries->count()); 2404 } 2405 2406 if (mTrackingProgressStatus) { 2407 if (mPreviousTrackTimeUs <= 0) { 2408 mPreviousTrackTimeUs = mStartTimestampUs; 2409 } 2410 trackProgressStatus(timestampUs); 2411 } 2412 if (!hasMultipleTracks) { 2413 off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy) 2414 : mOwner->addSample_l(copy); 2415 2416 uint32_t count = (mOwner->use32BitFileOffset() 2417 ? mStcoTableEntries->count() 2418 : mCo64TableEntries->count()); 2419 2420 if (count == 0) { 2421 addChunkOffset(offset); 2422 } 2423 copy->release(); 2424 copy = NULL; 2425 continue; 2426 } 2427 2428 mChunkSamples.push_back(copy); 2429 if (interleaveDurationUs == 0) { 2430 addOneStscTableEntry(++nChunks, 1); 2431 bufferChunk(timestampUs); 2432 } else { 2433 if (chunkTimestampUs == 0) { 2434 chunkTimestampUs = timestampUs; 2435 } else { 2436 int64_t chunkDurationUs = timestampUs - chunkTimestampUs; 2437 if (chunkDurationUs > interleaveDurationUs) { 2438 if (chunkDurationUs > mMaxChunkDurationUs) { 2439 mMaxChunkDurationUs = chunkDurationUs; 2440 } 2441 ++nChunks; 2442 if (nChunks == 1 || // First chunk 2443 lastSamplesPerChunk != mChunkSamples.size()) { 2444 lastSamplesPerChunk = mChunkSamples.size(); 2445 addOneStscTableEntry(nChunks, lastSamplesPerChunk); 2446 } 2447 bufferChunk(timestampUs); 2448 chunkTimestampUs = timestampUs; 2449 } 2450 } 2451 } 2452 2453 } 2454 2455 if (isTrackMalFormed()) { 2456 err = ERROR_MALFORMED; 2457 } 2458 2459 mOwner->trackProgressStatus(mTrackId, -1, err); 2460 2461 // Last chunk 2462 if (!hasMultipleTracks) { 2463 addOneStscTableEntry(1, mStszTableEntries->count()); 2464 } else if (!mChunkSamples.empty()) { 2465 addOneStscTableEntry(++nChunks, mChunkSamples.size()); 2466 bufferChunk(timestampUs); 2467 } 2468 2469 // We don't really know how long the last frame lasts, since 2470 // there is no frame time after it, just repeat the previous 2471 // frame's duration. 2472 if (mStszTableEntries->count() == 1) { 2473 lastDurationUs = 0; // A single sample's duration 2474 lastDurationTicks = 0; 2475 } else { 2476 ++sampleCount; // Count for the last sample 2477 } 2478 2479 if (mStszTableEntries->count() <= 2) { 2480 addOneSttsTableEntry(1, lastDurationTicks); 2481 if (sampleCount - 1 > 0) { 2482 addOneSttsTableEntry(sampleCount - 1, lastDurationTicks); 2483 } 2484 } else { 2485 addOneSttsTableEntry(sampleCount, lastDurationTicks); 2486 } 2487 2488 // The last ctts box may not have been written yet, and this 2489 // is to make sure that we write out the last ctts box. 2490 if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) { 2491 if (cttsSampleCount > 0) { 2492 addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks); 2493 } 2494 } 2495 2496 mTrackDurationUs += lastDurationUs; 2497 mReachedEOS = true; 2498 2499 sendTrackSummary(hasMultipleTracks); 2500 2501 ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", 2502 count, nZeroLengthFrames, mStszTableEntries->count(), trackName); 2503 if (mIsAudio) { 2504 ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs()); 2505 } 2506 2507 if (err == ERROR_END_OF_STREAM) { 2508 return OK; 2509 } 2510 return err; 2511} 2512 2513bool MPEG4Writer::Track::isTrackMalFormed() const { 2514 if (mStszTableEntries->count() == 0) { // no samples written 2515 ALOGE("The number of recorded samples is 0"); 2516 return true; 2517 } 2518 2519 if (!mIsAudio && mStssTableEntries->count() == 0) { // no sync frames for video 2520 ALOGE("There are no sync frames for video track"); 2521 return true; 2522 } 2523 2524 if (OK != checkCodecSpecificData()) { // no codec specific data 2525 return true; 2526 } 2527 2528 return false; 2529} 2530 2531void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { 2532 2533 // Send track summary only if test mode is enabled. 2534 if (!isTestModeEnabled()) { 2535 return; 2536 } 2537 2538 int trackNum = (mTrackId << 28); 2539 2540 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2541 trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE, 2542 mIsAudio? 0: 1); 2543 2544 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2545 trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS, 2546 mTrackDurationUs / 1000); 2547 2548 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2549 trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES, 2550 mStszTableEntries->count()); 2551 2552 { 2553 // The system delay time excluding the requested initial delay that 2554 // is used to eliminate the recording sound. 2555 int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL; 2556 if (startTimeOffsetUs < 0) { // Start time offset was not set 2557 startTimeOffsetUs = kInitialDelayTimeUs; 2558 } 2559 int64_t initialDelayUs = 2560 mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs; 2561 2562 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2563 trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS, 2564 (initialDelayUs) / 1000); 2565 } 2566 2567 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2568 trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES, 2569 mMdatSizeBytes / 1024); 2570 2571 if (hasMultipleTracks) { 2572 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2573 trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS, 2574 mMaxChunkDurationUs / 1000); 2575 2576 int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 2577 if (mStartTimestampUs != moovStartTimeUs) { 2578 int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 2579 mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2580 trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS, 2581 startTimeOffsetUs / 1000); 2582 } 2583 } 2584} 2585 2586void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 2587 ALOGV("trackProgressStatus: %" PRId64 " us", timeUs); 2588 2589 if (mTrackEveryTimeDurationUs > 0 && 2590 timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 2591 ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs); 2592 mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); 2593 mPreviousTrackTimeUs = timeUs; 2594 } 2595} 2596 2597void MPEG4Writer::trackProgressStatus( 2598 size_t trackId, int64_t timeUs, status_t err) { 2599 Mutex::Autolock lock(mLock); 2600 int32_t trackNum = (trackId << 28); 2601 2602 // Error notification 2603 // Do not consider ERROR_END_OF_STREAM an error 2604 if (err != OK && err != ERROR_END_OF_STREAM) { 2605 notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, 2606 trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL, 2607 err); 2608 return; 2609 } 2610 2611 if (timeUs == -1) { 2612 // Send completion notification 2613 notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2614 trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, 2615 err); 2616 } else { 2617 // Send progress status 2618 notify(MEDIA_RECORDER_TRACK_EVENT_INFO, 2619 trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME, 2620 timeUs / 1000); 2621 } 2622} 2623 2624void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { 2625 ALOGV("setDriftTimeUs: %" PRId64 " us", driftTimeUs); 2626 Mutex::Autolock autolock(mLock); 2627 mDriftTimeUs = driftTimeUs; 2628} 2629 2630int64_t MPEG4Writer::getDriftTimeUs() { 2631 ALOGV("getDriftTimeUs: %" PRId64 " us", mDriftTimeUs); 2632 Mutex::Autolock autolock(mLock); 2633 return mDriftTimeUs; 2634} 2635 2636bool MPEG4Writer::isRealTimeRecording() const { 2637 return mIsRealTimeRecording; 2638} 2639 2640bool MPEG4Writer::useNalLengthFour() { 2641 return mUse4ByteNalLength; 2642} 2643 2644void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) { 2645 ALOGV("bufferChunk"); 2646 2647 Chunk chunk(this, timestampUs, mChunkSamples); 2648 mOwner->bufferChunk(chunk); 2649 mChunkSamples.clear(); 2650} 2651 2652int64_t MPEG4Writer::Track::getDurationUs() const { 2653 return mTrackDurationUs; 2654} 2655 2656int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 2657 return mEstimatedTrackSizeBytes; 2658} 2659 2660status_t MPEG4Writer::Track::checkCodecSpecificData() const { 2661 const char *mime; 2662 CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 2663 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || 2664 !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || 2665 !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2666 if (!mCodecSpecificData || 2667 mCodecSpecificDataSize <= 0) { 2668 ALOGE("Missing codec specific data"); 2669 return ERROR_MALFORMED; 2670 } 2671 } else { 2672 if (mCodecSpecificData || 2673 mCodecSpecificDataSize > 0) { 2674 ALOGE("Unexepected codec specific data found"); 2675 return ERROR_MALFORMED; 2676 } 2677 } 2678 return OK; 2679} 2680 2681void MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) { 2682 2683 ALOGV("%s track time scale: %d", 2684 mIsAudio? "Audio": "Video", mTimeScale); 2685 2686 uint32_t now = getMpeg4Time(); 2687 mOwner->beginBox("trak"); 2688 writeTkhdBox(now); 2689 mOwner->beginBox("mdia"); 2690 writeMdhdBox(now); 2691 writeHdlrBox(); 2692 mOwner->beginBox("minf"); 2693 if (mIsAudio) { 2694 writeSmhdBox(); 2695 } else { 2696 writeVmhdBox(); 2697 } 2698 writeDinfBox(); 2699 writeStblBox(use32BitOffset); 2700 mOwner->endBox(); // minf 2701 mOwner->endBox(); // mdia 2702 mOwner->endBox(); // trak 2703} 2704 2705void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) { 2706 mOwner->beginBox("stbl"); 2707 mOwner->beginBox("stsd"); 2708 mOwner->writeInt32(0); // version=0, flags=0 2709 mOwner->writeInt32(1); // entry count 2710 if (mIsAudio) { 2711 writeAudioFourCCBox(); 2712 } else { 2713 writeVideoFourCCBox(); 2714 } 2715 mOwner->endBox(); // stsd 2716 writeSttsBox(); 2717 writeCttsBox(); 2718 if (!mIsAudio) { 2719 writeStssBox(); 2720 } 2721 writeStszBox(); 2722 writeStscBox(); 2723 writeStcoBox(use32BitOffset); 2724 mOwner->endBox(); // stbl 2725} 2726 2727void MPEG4Writer::Track::writeVideoFourCCBox() { 2728 const char *mime; 2729 bool success = mMeta->findCString(kKeyMIMEType, &mime); 2730 CHECK(success); 2731 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2732 mOwner->beginBox("mp4v"); 2733 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 2734 mOwner->beginBox("s263"); 2735 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2736 mOwner->beginBox("avc1"); 2737 } else { 2738 ALOGE("Unknown mime type '%s'.", mime); 2739 CHECK(!"should not be here, unknown mime type."); 2740 } 2741 2742 mOwner->writeInt32(0); // reserved 2743 mOwner->writeInt16(0); // reserved 2744 mOwner->writeInt16(1); // data ref index 2745 mOwner->writeInt16(0); // predefined 2746 mOwner->writeInt16(0); // reserved 2747 mOwner->writeInt32(0); // predefined 2748 mOwner->writeInt32(0); // predefined 2749 mOwner->writeInt32(0); // predefined 2750 2751 int32_t width, height; 2752 success = mMeta->findInt32(kKeyWidth, &width); 2753 success = success && mMeta->findInt32(kKeyHeight, &height); 2754 CHECK(success); 2755 2756 mOwner->writeInt16(width); 2757 mOwner->writeInt16(height); 2758 mOwner->writeInt32(0x480000); // horiz resolution 2759 mOwner->writeInt32(0x480000); // vert resolution 2760 mOwner->writeInt32(0); // reserved 2761 mOwner->writeInt16(1); // frame count 2762 mOwner->writeInt8(0); // compressor string length 2763 mOwner->write(" ", 31); 2764 mOwner->writeInt16(0x18); // depth 2765 mOwner->writeInt16(-1); // predefined 2766 2767 CHECK_LT(23 + mCodecSpecificDataSize, 128); 2768 2769 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 2770 writeMp4vEsdsBox(); 2771 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 2772 writeD263Box(); 2773 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 2774 writeAvccBox(); 2775 } 2776 2777 writePaspBox(); 2778 mOwner->endBox(); // mp4v, s263 or avc1 2779} 2780 2781void MPEG4Writer::Track::writeAudioFourCCBox() { 2782 const char *mime; 2783 bool success = mMeta->findCString(kKeyMIMEType, &mime); 2784 CHECK(success); 2785 const char *fourcc = NULL; 2786 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 2787 fourcc = "samr"; 2788 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 2789 fourcc = "sawb"; 2790 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2791 fourcc = "mp4a"; 2792 } else { 2793 ALOGE("Unknown mime type '%s'.", mime); 2794 CHECK(!"should not be here, unknown mime type."); 2795 } 2796 2797 mOwner->beginBox(fourcc); // audio format 2798 mOwner->writeInt32(0); // reserved 2799 mOwner->writeInt16(0); // reserved 2800 mOwner->writeInt16(0x1); // data ref index 2801 mOwner->writeInt32(0); // reserved 2802 mOwner->writeInt32(0); // reserved 2803 int32_t nChannels; 2804 CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 2805 mOwner->writeInt16(nChannels); // channel count 2806 mOwner->writeInt16(16); // sample size 2807 mOwner->writeInt16(0); // predefined 2808 mOwner->writeInt16(0); // reserved 2809 2810 int32_t samplerate; 2811 success = mMeta->findInt32(kKeySampleRate, &samplerate); 2812 CHECK(success); 2813 mOwner->writeInt32(samplerate << 16); 2814 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 2815 writeMp4aEsdsBox(); 2816 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 2817 !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 2818 writeDamrBox(); 2819 } 2820 mOwner->endBox(); 2821} 2822 2823void MPEG4Writer::Track::writeMp4aEsdsBox() { 2824 mOwner->beginBox("esds"); 2825 CHECK(mCodecSpecificData); 2826 CHECK_GT(mCodecSpecificDataSize, 0); 2827 2828 // Make sure all sizes encode to a single byte. 2829 CHECK_LT(mCodecSpecificDataSize + 23, 128); 2830 2831 mOwner->writeInt32(0); // version=0, flags=0 2832 mOwner->writeInt8(0x03); // ES_DescrTag 2833 mOwner->writeInt8(23 + mCodecSpecificDataSize); 2834 mOwner->writeInt16(0x0000);// ES_ID 2835 mOwner->writeInt8(0x00); 2836 2837 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2838 mOwner->writeInt8(15 + mCodecSpecificDataSize); 2839 mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 2840 mOwner->writeInt8(0x15); // streamType AudioStream 2841 2842 mOwner->writeInt16(0x03); // XXX 2843 mOwner->writeInt8(0x00); // buffer size 24-bit 2844 int32_t bitRate; 2845 bool success = mMeta->findInt32(kKeyBitRate, &bitRate); 2846 mOwner->writeInt32(success ? bitRate : 96000); // max bit rate 2847 mOwner->writeInt32(success ? bitRate : 96000); // avg bit rate 2848 2849 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2850 mOwner->writeInt8(mCodecSpecificDataSize); 2851 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2852 2853 static const uint8_t kData2[] = { 2854 0x06, // SLConfigDescriptorTag 2855 0x01, 2856 0x02 2857 }; 2858 mOwner->write(kData2, sizeof(kData2)); 2859 2860 mOwner->endBox(); // esds 2861} 2862 2863void MPEG4Writer::Track::writeMp4vEsdsBox() { 2864 CHECK(mCodecSpecificData); 2865 CHECK_GT(mCodecSpecificDataSize, 0); 2866 mOwner->beginBox("esds"); 2867 2868 mOwner->writeInt32(0); // version=0, flags=0 2869 2870 mOwner->writeInt8(0x03); // ES_DescrTag 2871 mOwner->writeInt8(23 + mCodecSpecificDataSize); 2872 mOwner->writeInt16(0x0000); // ES_ID 2873 mOwner->writeInt8(0x1f); 2874 2875 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 2876 mOwner->writeInt8(15 + mCodecSpecificDataSize); 2877 mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 2878 mOwner->writeInt8(0x11); // streamType VisualStream 2879 2880 static const uint8_t kData[] = { 2881 0x01, 0x77, 0x00, 2882 0x00, 0x03, 0xe8, 0x00, 2883 0x00, 0x03, 0xe8, 0x00 2884 }; 2885 mOwner->write(kData, sizeof(kData)); 2886 2887 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 2888 2889 mOwner->writeInt8(mCodecSpecificDataSize); 2890 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 2891 2892 static const uint8_t kData2[] = { 2893 0x06, // SLConfigDescriptorTag 2894 0x01, 2895 0x02 2896 }; 2897 mOwner->write(kData2, sizeof(kData2)); 2898 2899 mOwner->endBox(); // esds 2900} 2901 2902void MPEG4Writer::Track::writeTkhdBox(uint32_t now) { 2903 mOwner->beginBox("tkhd"); 2904 // Flags = 7 to indicate that the track is enabled, and 2905 // part of the presentation 2906 mOwner->writeInt32(0x07); // version=0, flags=7 2907 mOwner->writeInt32(now); // creation time 2908 mOwner->writeInt32(now); // modification time 2909 mOwner->writeInt32(mTrackId); // track id starts with 1 2910 mOwner->writeInt32(0); // reserved 2911 int64_t trakDurationUs = getDurationUs(); 2912 int32_t mvhdTimeScale = mOwner->getTimeScale(); 2913 int32_t tkhdDuration = 2914 (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 2915 mOwner->writeInt32(tkhdDuration); // in mvhd timescale 2916 mOwner->writeInt32(0); // reserved 2917 mOwner->writeInt32(0); // reserved 2918 mOwner->writeInt16(0); // layer 2919 mOwner->writeInt16(0); // alternate group 2920 mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume 2921 mOwner->writeInt16(0); // reserved 2922 2923 mOwner->writeCompositionMatrix(mRotation); // matrix 2924 2925 if (mIsAudio) { 2926 mOwner->writeInt32(0); 2927 mOwner->writeInt32(0); 2928 } else { 2929 int32_t width, height; 2930 bool success = mMeta->findInt32(kKeyWidth, &width); 2931 success = success && mMeta->findInt32(kKeyHeight, &height); 2932 CHECK(success); 2933 2934 mOwner->writeInt32(width << 16); // 32-bit fixed-point value 2935 mOwner->writeInt32(height << 16); // 32-bit fixed-point value 2936 } 2937 mOwner->endBox(); // tkhd 2938} 2939 2940void MPEG4Writer::Track::writeVmhdBox() { 2941 mOwner->beginBox("vmhd"); 2942 mOwner->writeInt32(0x01); // version=0, flags=1 2943 mOwner->writeInt16(0); // graphics mode 2944 mOwner->writeInt16(0); // opcolor 2945 mOwner->writeInt16(0); 2946 mOwner->writeInt16(0); 2947 mOwner->endBox(); 2948} 2949 2950void MPEG4Writer::Track::writeSmhdBox() { 2951 mOwner->beginBox("smhd"); 2952 mOwner->writeInt32(0); // version=0, flags=0 2953 mOwner->writeInt16(0); // balance 2954 mOwner->writeInt16(0); // reserved 2955 mOwner->endBox(); 2956} 2957 2958void MPEG4Writer::Track::writeHdlrBox() { 2959 mOwner->beginBox("hdlr"); 2960 mOwner->writeInt32(0); // version=0, flags=0 2961 mOwner->writeInt32(0); // component type: should be mhlr 2962 mOwner->writeFourcc(mIsAudio ? "soun" : "vide"); // component subtype 2963 mOwner->writeInt32(0); // reserved 2964 mOwner->writeInt32(0); // reserved 2965 mOwner->writeInt32(0); // reserved 2966 // Removing "r" for the name string just makes the string 4 byte aligned 2967 mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle"); // name 2968 mOwner->endBox(); 2969} 2970 2971void MPEG4Writer::Track::writeMdhdBox(uint32_t now) { 2972 int64_t trakDurationUs = getDurationUs(); 2973 mOwner->beginBox("mdhd"); 2974 mOwner->writeInt32(0); // version=0, flags=0 2975 mOwner->writeInt32(now); // creation time 2976 mOwner->writeInt32(now); // modification time 2977 mOwner->writeInt32(mTimeScale); // media timescale 2978 int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 2979 mOwner->writeInt32(mdhdDuration); // use media timescale 2980 // Language follows the three letter standard ISO-639-2/T 2981 // 'e', 'n', 'g' for "English", for instance. 2982 // Each character is packed as the difference between its ASCII value and 0x60. 2983 // For "English", these are 00101, 01110, 00111. 2984 // XXX: Where is the padding bit located: 0x15C7? 2985 mOwner->writeInt16(0); // language code 2986 mOwner->writeInt16(0); // predefined 2987 mOwner->endBox(); 2988} 2989 2990void MPEG4Writer::Track::writeDamrBox() { 2991 // 3gpp2 Spec AMRSampleEntry fields 2992 mOwner->beginBox("damr"); 2993 mOwner->writeCString(" "); // vendor: 4 bytes 2994 mOwner->writeInt8(0); // decoder version 2995 mOwner->writeInt16(0x83FF); // mode set: all enabled 2996 mOwner->writeInt8(0); // mode change period 2997 mOwner->writeInt8(1); // frames per sample 2998 mOwner->endBox(); 2999} 3000 3001void MPEG4Writer::Track::writeUrlBox() { 3002 // The table index here refers to the sample description index 3003 // in the sample table entries. 3004 mOwner->beginBox("url "); 3005 mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 3006 mOwner->endBox(); // url 3007} 3008 3009void MPEG4Writer::Track::writeDrefBox() { 3010 mOwner->beginBox("dref"); 3011 mOwner->writeInt32(0); // version=0, flags=0 3012 mOwner->writeInt32(1); // entry count (either url or urn) 3013 writeUrlBox(); 3014 mOwner->endBox(); // dref 3015} 3016 3017void MPEG4Writer::Track::writeDinfBox() { 3018 mOwner->beginBox("dinf"); 3019 writeDrefBox(); 3020 mOwner->endBox(); // dinf 3021} 3022 3023void MPEG4Writer::Track::writeAvccBox() { 3024 CHECK(mCodecSpecificData); 3025 CHECK_GE(mCodecSpecificDataSize, 5); 3026 3027 // Patch avcc's lengthSize field to match the number 3028 // of bytes we use to indicate the size of a nal unit. 3029 uint8_t *ptr = (uint8_t *)mCodecSpecificData; 3030 ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1); 3031 mOwner->beginBox("avcC"); 3032 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 3033 mOwner->endBox(); // avcC 3034} 3035 3036void MPEG4Writer::Track::writeD263Box() { 3037 mOwner->beginBox("d263"); 3038 mOwner->writeInt32(0); // vendor 3039 mOwner->writeInt8(0); // decoder version 3040 mOwner->writeInt8(10); // level: 10 3041 mOwner->writeInt8(0); // profile: 0 3042 mOwner->endBox(); // d263 3043} 3044 3045// This is useful if the pixel is not square 3046void MPEG4Writer::Track::writePaspBox() { 3047 mOwner->beginBox("pasp"); 3048 mOwner->writeInt32(1 << 16); // hspacing 3049 mOwner->writeInt32(1 << 16); // vspacing 3050 mOwner->endBox(); // pasp 3051} 3052 3053int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const { 3054 int64_t trackStartTimeOffsetUs = 0; 3055 int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 3056 if (mStartTimestampUs != moovStartTimeUs) { 3057 CHECK_GT(mStartTimestampUs, moovStartTimeUs); 3058 trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs; 3059 } 3060 return (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL; 3061} 3062 3063void MPEG4Writer::Track::writeSttsBox() { 3064 mOwner->beginBox("stts"); 3065 mOwner->writeInt32(0); // version=0, flags=0 3066 uint32_t duration; 3067 CHECK(mSttsTableEntries->get(duration, 1)); 3068 duration = htonl(duration); // Back to host byte order 3069 mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1); 3070 mSttsTableEntries->write(mOwner); 3071 mOwner->endBox(); // stts 3072} 3073 3074void MPEG4Writer::Track::writeCttsBox() { 3075 if (mIsAudio) { // ctts is not for audio 3076 return; 3077 } 3078 3079 // There is no B frame at all 3080 if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) { 3081 return; 3082 } 3083 3084 // Do not write ctts box when there is no need to have it. 3085 if (mCttsTableEntries->count() == 0) { 3086 return; 3087 } 3088 3089 ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]", 3090 mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs); 3091 3092 mOwner->beginBox("ctts"); 3093 mOwner->writeInt32(0); // version=0, flags=0 3094 uint32_t duration; 3095 CHECK(mCttsTableEntries->get(duration, 1)); 3096 duration = htonl(duration); // Back host byte order 3097 mCttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime() - mMinCttsOffsetTimeUs), 1); 3098 mCttsTableEntries->write(mOwner); 3099 mOwner->endBox(); // ctts 3100} 3101 3102void MPEG4Writer::Track::writeStssBox() { 3103 mOwner->beginBox("stss"); 3104 mOwner->writeInt32(0); // version=0, flags=0 3105 mStssTableEntries->write(mOwner); 3106 mOwner->endBox(); // stss 3107} 3108 3109void MPEG4Writer::Track::writeStszBox() { 3110 mOwner->beginBox("stsz"); 3111 mOwner->writeInt32(0); // version=0, flags=0 3112 mOwner->writeInt32(0); 3113 mStszTableEntries->write(mOwner); 3114 mOwner->endBox(); // stsz 3115} 3116 3117void MPEG4Writer::Track::writeStscBox() { 3118 mOwner->beginBox("stsc"); 3119 mOwner->writeInt32(0); // version=0, flags=0 3120 mStscTableEntries->write(mOwner); 3121 mOwner->endBox(); // stsc 3122} 3123 3124void MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) { 3125 mOwner->beginBox(use32BitOffset? "stco": "co64"); 3126 mOwner->writeInt32(0); // version=0, flags=0 3127 if (use32BitOffset) { 3128 mStcoTableEntries->write(mOwner); 3129 } else { 3130 mCo64TableEntries->write(mOwner); 3131 } 3132 mOwner->endBox(); // stco or co64 3133} 3134 3135void MPEG4Writer::writeUdtaBox() { 3136 beginBox("udta"); 3137 writeGeoDataBox(); 3138 endBox(); 3139} 3140 3141void MPEG4Writer::writeHdlr() { 3142 beginBox("hdlr"); 3143 writeInt32(0); // Version, Flags 3144 writeInt32(0); // Predefined 3145 writeFourcc("mdta"); 3146 writeInt32(0); // Reserved[0] 3147 writeInt32(0); // Reserved[1] 3148 writeInt32(0); // Reserved[2] 3149 writeInt8(0); // Name (empty) 3150 endBox(); 3151} 3152 3153void MPEG4Writer::writeKeys() { 3154 size_t count = mMetaKeys->countEntries(); 3155 3156 beginBox("keys"); 3157 writeInt32(0); // Version, Flags 3158 writeInt32(count); // Entry_count 3159 for (size_t i = 0; i < count; i++) { 3160 AMessage::Type type; 3161 const char *key = mMetaKeys->getEntryNameAt(i, &type); 3162 size_t n = strlen(key); 3163 writeInt32(n + 8); 3164 writeFourcc("mdta"); 3165 write(key, n); // write without the \0 3166 } 3167 endBox(); 3168} 3169 3170void MPEG4Writer::writeIlst() { 3171 size_t count = mMetaKeys->countEntries(); 3172 3173 beginBox("ilst"); 3174 for (size_t i = 0; i < count; i++) { 3175 beginBox(i + 1); // key id (1-based) 3176 beginBox("data"); 3177 AMessage::Type type; 3178 const char *key = mMetaKeys->getEntryNameAt(i, &type); 3179 switch (type) { 3180 case AMessage::kTypeString: 3181 { 3182 AString val; 3183 CHECK(mMetaKeys->findString(key, &val)); 3184 writeInt32(1); // type = UTF8 3185 writeInt32(0); // default country/language 3186 write(val.c_str(), strlen(val.c_str())); // write without \0 3187 break; 3188 } 3189 3190 case AMessage::kTypeFloat: 3191 { 3192 float val; 3193 CHECK(mMetaKeys->findFloat(key, &val)); 3194 writeInt32(23); // type = float32 3195 writeInt32(0); // default country/language 3196 writeInt32(*reinterpret_cast<int32_t *>(&val)); 3197 break; 3198 } 3199 3200 case AMessage::kTypeInt32: 3201 { 3202 int32_t val; 3203 CHECK(mMetaKeys->findInt32(key, &val)); 3204 writeInt32(67); // type = signed int32 3205 writeInt32(0); // default country/language 3206 writeInt32(val); 3207 break; 3208 } 3209 3210 default: 3211 { 3212 ALOGW("Unsupported key type, writing 0 instead"); 3213 writeInt32(77); // type = unsigned int32 3214 writeInt32(0); // default country/language 3215 writeInt32(0); 3216 break; 3217 } 3218 } 3219 endBox(); // data 3220 endBox(); // key id 3221 } 3222 endBox(); // ilst 3223} 3224 3225void MPEG4Writer::writeMetaBox() { 3226 size_t count = mMetaKeys->countEntries(); 3227 if (count == 0) { 3228 return; 3229 } 3230 3231 beginBox("meta"); 3232 writeHdlr(); 3233 writeKeys(); 3234 writeIlst(); 3235 endBox(); 3236} 3237 3238/* 3239 * Geodata is stored according to ISO-6709 standard. 3240 */ 3241void MPEG4Writer::writeGeoDataBox() { 3242 beginBox("\xA9xyz"); 3243 /* 3244 * For historical reasons, any user data start 3245 * with "\0xA9", must be followed by its assoicated 3246 * language code. 3247 * 0x0012: text string length 3248 * 0x15c7: lang (locale) code: en 3249 */ 3250 writeInt32(0x001215c7); 3251 writeLatitude(mLatitudex10000); 3252 writeLongitude(mLongitudex10000); 3253 writeInt8(0x2F); 3254 endBox(); 3255} 3256 3257} // namespace android 3258