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