MPEG4Writer.cpp revision 5aff464f67322cd13dc8ed165806971cfff2e4d5
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#include <utils/Log.h> 20 21#include <arpa/inet.h> 22 23#include <ctype.h> 24#include <pthread.h> 25 26#include <media/stagefright/MPEG4Writer.h> 27#include <media/stagefright/MediaBuffer.h> 28#include <media/stagefright/MetaData.h> 29#include <media/stagefright/MediaDebug.h> 30#include <media/stagefright/MediaDefs.h> 31#include <media/stagefright/MediaErrors.h> 32#include <media/stagefright/MediaSource.h> 33#include <media/stagefright/Utils.h> 34#include <media/mediarecorder.h> 35#include <cutils/properties.h> 36 37#include "include/ESDS.h" 38 39namespace android { 40 41class MPEG4Writer::Track { 42public: 43 Track(MPEG4Writer *owner, const sp<MediaSource> &source); 44 45 ~Track(); 46 47 status_t start(MetaData *params); 48 void stop(); 49 void pause(); 50 bool reachedEOS(); 51 52 int64_t getDurationUs() const; 53 int64_t getEstimatedTrackSizeBytes() const; 54 void writeTrackHeader(int32_t trackID, bool use32BitOffset = true); 55 56private: 57 MPEG4Writer *mOwner; 58 sp<MetaData> mMeta; 59 sp<MediaSource> mSource; 60 volatile bool mDone; 61 volatile bool mPaused; 62 volatile bool mResumed; 63 int64_t mMaxTimeStampUs; 64 int64_t mEstimatedTrackSizeBytes; 65 int32_t mTimeScale; 66 67 pthread_t mThread; 68 69 // mNumSamples is used to track how many samples in mSampleSizes List. 70 // This is to reduce the cost associated with mSampleSizes.size() call, 71 // since it is O(n). Ideally, the fix should be in List class. 72 size_t mNumSamples; 73 List<size_t> mSampleSizes; 74 bool mSamplesHaveSameSize; 75 76 List<MediaBuffer *> mChunkSamples; 77 List<off_t> mChunkOffsets; 78 79 struct StscTableEntry { 80 81 StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id) 82 : firstChunk(chunk), 83 samplesPerChunk(samples), 84 sampleDescriptionId(id) {} 85 86 uint32_t firstChunk; 87 uint32_t samplesPerChunk; 88 uint32_t sampleDescriptionId; 89 }; 90 List<StscTableEntry> mStscTableEntries; 91 92 List<int32_t> mStssTableEntries; 93 List<int64_t> mChunkDurations; 94 95 struct SttsTableEntry { 96 97 SttsTableEntry(uint32_t count, uint32_t durationUs) 98 : sampleCount(count), sampleDurationUs(durationUs) {} 99 100 uint32_t sampleCount; 101 uint32_t sampleDurationUs; 102 }; 103 List<SttsTableEntry> mSttsTableEntries; 104 105 void *mCodecSpecificData; 106 size_t mCodecSpecificDataSize; 107 bool mGotAllCodecSpecificData; 108 bool mTrackingProgressStatus; 109 110 bool mReachedEOS; 111 int64_t mStartTimestampUs; 112 int64_t mPreviousTrackTimeUs; 113 int64_t mTrackEveryTimeDurationUs; 114 115 static void *ThreadWrapper(void *me); 116 void threadEntry(); 117 118 status_t makeAVCCodecSpecificData( 119 const uint8_t *data, size_t size); 120 void writeOneChunk(bool isAvc); 121 122 // Track authoring progress status 123 void trackProgressStatus(int64_t timeUs, status_t err = OK); 124 void initTrackingProgressStatus(MetaData *params); 125 126 // Utilities for collecting statistical data 127 void logStatisticalData(bool isAudio); 128 void findMinAvgMaxSampleDurationMs( 129 int32_t *min, int32_t *avg, int32_t *max); 130 void findMinMaxChunkDurations(int64_t *min, int64_t *max); 131 132 void getCodecSpecificDataFromInputFormatIfPossible(); 133 134 Track(const Track &); 135 Track &operator=(const Track &); 136}; 137 138#define USE_NALLEN_FOUR 1 139 140MPEG4Writer::MPEG4Writer(const char *filename) 141 : mFile(fopen(filename, "wb")), 142 mUse32BitOffset(true), 143 mPaused(false), 144 mStarted(false), 145 mOffset(0), 146 mMdatOffset(0), 147 mEstimatedMoovBoxSize(0), 148 mInterleaveDurationUs(1000000) { 149 CHECK(mFile != NULL); 150} 151 152MPEG4Writer::MPEG4Writer(int fd) 153 : mFile(fdopen(fd, "wb")), 154 mUse32BitOffset(true), 155 mPaused(false), 156 mStarted(false), 157 mOffset(0), 158 mMdatOffset(0), 159 mEstimatedMoovBoxSize(0), 160 mInterleaveDurationUs(1000000) { 161 CHECK(mFile != NULL); 162} 163 164MPEG4Writer::~MPEG4Writer() { 165 stop(); 166 167 for (List<Track *>::iterator it = mTracks.begin(); 168 it != mTracks.end(); ++it) { 169 delete *it; 170 } 171 mTracks.clear(); 172} 173 174status_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 175 Track *track = new Track(this, source); 176 mTracks.push_back(track); 177 178 return OK; 179} 180 181status_t MPEG4Writer::startTracks(MetaData *params) { 182 for (List<Track *>::iterator it = mTracks.begin(); 183 it != mTracks.end(); ++it) { 184 status_t err = (*it)->start(params); 185 186 if (err != OK) { 187 for (List<Track *>::iterator it2 = mTracks.begin(); 188 it2 != it; ++it2) { 189 (*it2)->stop(); 190 } 191 192 return err; 193 } 194 } 195 return OK; 196} 197 198int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { 199 // This implementation is highly experimental/heurisitic. 200 // 201 // Statistical analysis shows that metadata usually accounts 202 // for a small portion of the total file size, usually < 0.6%. 203 // Currently, lets set to 0.4% for now. 204 205 // The default MIN_MOOV_BOX_SIZE is set to 0.4% x 1MB, 206 // where 1MB is the common file size limit for MMS application. 207 // The default MAX _MOOV_BOX_SIZE value is based on about 4 208 // minute video recording with a bit rate about 3 Mbps, because 209 // statistics also show that most of the video captured are going 210 // to be less than 3 minutes. 211 212 // If the estimation is wrong, we will pay the price of wasting 213 // some reserved space. This should not happen so often statistically. 214 static const int32_t factor = mUse32BitOffset? 1: 2; 215 static const int64_t MIN_MOOV_BOX_SIZE = 4 * 1024; // 4 KB 216 static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); 217 int64_t size = MIN_MOOV_BOX_SIZE; 218 219 if (mMaxFileSizeLimitBytes != 0) { 220 size = mMaxFileSizeLimitBytes * 4 / 1000; 221 } else if (mMaxFileDurationLimitUs != 0) { 222 if (bitRate <= 0) { 223 // We could not estimate the file size since bitRate is not set. 224 size = MIN_MOOV_BOX_SIZE; 225 } else { 226 size = ((mMaxFileDurationLimitUs * bitRate * 4) / 1000 / 8000000); 227 } 228 } 229 if (size < MIN_MOOV_BOX_SIZE) { 230 size = MIN_MOOV_BOX_SIZE; 231 } 232 233 // Any long duration recording will be probably end up with 234 // non-streamable mp4 file. 235 if (size > MAX_MOOV_BOX_SIZE) { 236 size = MAX_MOOV_BOX_SIZE; 237 } 238 239 LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" 240 " moov size %lld bytes", 241 mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); 242 return factor * size; 243} 244 245status_t MPEG4Writer::start(MetaData *param) { 246 if (mFile == NULL) { 247 return UNKNOWN_ERROR; 248 } 249 250 int32_t use64BitOffset; 251 if (param && 252 param->findInt32(kKey64BitFileOffset, &use64BitOffset) && 253 use64BitOffset) { 254 mUse32BitOffset = false; 255 } 256 257 // System property can overwrite the file offset bits parameter 258 char value[PROPERTY_VALUE_MAX]; 259 if (property_get("media.stagefright.record-64bits", value, NULL) 260 && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 261 mUse32BitOffset = false; 262 } 263 264 mStartTimestampUs = -1; 265 266 if (mStarted) { 267 if (mPaused) { 268 mPaused = false; 269 return startTracks(param); 270 } 271 return OK; 272 } 273 274 if (!param || 275 !param->findInt32(kKeyTimeScale, &mTimeScale)) { 276 mTimeScale = 1000; 277 } 278 CHECK(mTimeScale > 0); 279 LOGV("movie time scale: %d", mTimeScale); 280 281 mStreamableFile = true; 282 mWriteMoovBoxToMemory = false; 283 mMoovBoxBuffer = NULL; 284 mMoovBoxBufferOffset = 0; 285 286 beginBox("ftyp"); 287 { 288 int32_t fileType; 289 if (param && param->findInt32(kKeyFileType, &fileType) && 290 fileType != OUTPUT_FORMAT_MPEG_4) { 291 writeFourcc("3gp4"); 292 } else { 293 writeFourcc("isom"); 294 } 295 } 296 writeInt32(0); 297 writeFourcc("isom"); 298 writeFourcc("3gp4"); 299 endBox(); 300 301 mFreeBoxOffset = mOffset; 302 303 if (mEstimatedMoovBoxSize == 0) { 304 int32_t bitRate = -1; 305 if (param) { 306 param->findInt32(kKeyBitRate, &bitRate); 307 } 308 mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); 309 } 310 CHECK(mEstimatedMoovBoxSize >= 8); 311 fseeko(mFile, mFreeBoxOffset, SEEK_SET); 312 writeInt32(mEstimatedMoovBoxSize); 313 write("free", 4); 314 315 mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; 316 mOffset = mMdatOffset; 317 fseeko(mFile, mMdatOffset, SEEK_SET); 318 if (mUse32BitOffset) { 319 write("????mdat", 8); 320 } else { 321 write("\x00\x00\x00\x01mdat????????", 16); 322 } 323 status_t err = startTracks(param); 324 if (err != OK) { 325 return err; 326 } 327 mStarted = true; 328 return OK; 329} 330 331void MPEG4Writer::pause() { 332 if (mFile == NULL) { 333 return; 334 } 335 mPaused = true; 336 for (List<Track *>::iterator it = mTracks.begin(); 337 it != mTracks.end(); ++it) { 338 (*it)->pause(); 339 } 340} 341 342void MPEG4Writer::stop() { 343 if (mFile == NULL) { 344 return; 345 } 346 347 int64_t maxDurationUs = 0; 348 for (List<Track *>::iterator it = mTracks.begin(); 349 it != mTracks.end(); ++it) { 350 (*it)->stop(); 351 352 int64_t durationUs = (*it)->getDurationUs(); 353 if (durationUs > maxDurationUs) { 354 maxDurationUs = durationUs; 355 } 356 } 357 358 359 // Fix up the size of the 'mdat' chunk. 360 if (mUse32BitOffset) { 361 fseeko(mFile, mMdatOffset, SEEK_SET); 362 int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset)); 363 fwrite(&size, 1, 4, mFile); 364 } else { 365 fseeko(mFile, mMdatOffset + 8, SEEK_SET); 366 int64_t size = mOffset - mMdatOffset; 367 size = hton64(size); 368 fwrite(&size, 1, 8, mFile); 369 } 370 fseeko(mFile, mOffset, SEEK_SET); 371 372 time_t now = time(NULL); 373 const off_t moovOffset = mOffset; 374 mWriteMoovBoxToMemory = true; 375 mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); 376 mMoovBoxBufferOffset = 0; 377 CHECK(mMoovBoxBuffer != NULL); 378 int32_t duration = (maxDurationUs * mTimeScale) / 1E6; 379 380 beginBox("moov"); 381 382 beginBox("mvhd"); 383 writeInt32(0); // version=0, flags=0 384 writeInt32(now); // creation time 385 writeInt32(now); // modification time 386 writeInt32(mTimeScale); // mvhd timescale 387 writeInt32(duration); 388 writeInt32(0x10000); // rate: 1.0 389 writeInt16(0x100); // volume 390 writeInt16(0); // reserved 391 writeInt32(0); // reserved 392 writeInt32(0); // reserved 393 writeInt32(0x10000); // matrix 394 writeInt32(0); 395 writeInt32(0); 396 writeInt32(0); 397 writeInt32(0x10000); 398 writeInt32(0); 399 writeInt32(0); 400 writeInt32(0); 401 writeInt32(0x40000000); 402 writeInt32(0); // predefined 403 writeInt32(0); // predefined 404 writeInt32(0); // predefined 405 writeInt32(0); // predefined 406 writeInt32(0); // predefined 407 writeInt32(0); // predefined 408 writeInt32(mTracks.size() + 1); // nextTrackID 409 endBox(); // mvhd 410 411 int32_t id = 1; 412 for (List<Track *>::iterator it = mTracks.begin(); 413 it != mTracks.end(); ++it, ++id) { 414 (*it)->writeTrackHeader(id, mUse32BitOffset); 415 } 416 endBox(); // moov 417 418 mWriteMoovBoxToMemory = false; 419 if (mStreamableFile) { 420 CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize); 421 422 // Moov box 423 fseeko(mFile, mFreeBoxOffset, SEEK_SET); 424 mOffset = mFreeBoxOffset; 425 write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, mFile); 426 427 // Free box 428 fseeko(mFile, mOffset, SEEK_SET); 429 writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); 430 write("free", 4); 431 432 // Free temp memory 433 free(mMoovBoxBuffer); 434 mMoovBoxBuffer = NULL; 435 mMoovBoxBufferOffset = 0; 436 } else { 437 LOGI("The mp4 file will not be streamable."); 438 } 439 440 CHECK(mBoxes.empty()); 441 442 fflush(mFile); 443 fclose(mFile); 444 mFile = NULL; 445 mStarted = false; 446} 447 448status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 449 mInterleaveDurationUs = durationUs; 450 return OK; 451} 452 453void MPEG4Writer::lock() { 454 mLock.lock(); 455} 456 457void MPEG4Writer::unlock() { 458 mLock.unlock(); 459} 460 461off_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 462 off_t old_offset = mOffset; 463 464 fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 465 1, buffer->range_length(), mFile); 466 467 mOffset += buffer->range_length(); 468 469 return old_offset; 470} 471 472static void StripStartcode(MediaBuffer *buffer) { 473 if (buffer->range_length() < 4) { 474 return; 475 } 476 477 const uint8_t *ptr = 478 (const uint8_t *)buffer->data() + buffer->range_offset(); 479 480 if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 481 buffer->set_range( 482 buffer->range_offset() + 4, buffer->range_length() - 4); 483 } 484} 485 486off_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 487 off_t old_offset = mOffset; 488 489 size_t length = buffer->range_length(); 490 491#if USE_NALLEN_FOUR 492 uint8_t x = length >> 24; 493 fwrite(&x, 1, 1, mFile); 494 x = (length >> 16) & 0xff; 495 fwrite(&x, 1, 1, mFile); 496 x = (length >> 8) & 0xff; 497 fwrite(&x, 1, 1, mFile); 498 x = length & 0xff; 499 fwrite(&x, 1, 1, mFile); 500#else 501 CHECK(length < 65536); 502 503 uint8_t x = length >> 8; 504 fwrite(&x, 1, 1, mFile); 505 x = length & 0xff; 506 fwrite(&x, 1, 1, mFile); 507#endif 508 509 fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 510 1, length, mFile); 511 512#if USE_NALLEN_FOUR 513 mOffset += length + 4; 514#else 515 mOffset += length + 2; 516#endif 517 518 return old_offset; 519} 520 521size_t MPEG4Writer::write( 522 const void *ptr, size_t size, size_t nmemb, FILE *stream) { 523 524 const size_t bytes = size * nmemb; 525 if (mWriteMoovBoxToMemory) { 526 off_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; 527 if (moovBoxSize > mEstimatedMoovBoxSize) { 528 for (List<off_t>::iterator it = mBoxes.begin(); 529 it != mBoxes.end(); ++it) { 530 (*it) += mOffset; 531 } 532 fseeko(mFile, mOffset, SEEK_SET); 533 fwrite(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, stream); 534 fwrite(ptr, size, nmemb, stream); 535 mOffset += (bytes + mMoovBoxBufferOffset); 536 free(mMoovBoxBuffer); 537 mMoovBoxBuffer = NULL; 538 mMoovBoxBufferOffset = 0; 539 mWriteMoovBoxToMemory = false; 540 mStreamableFile = false; 541 } else { 542 memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes); 543 mMoovBoxBufferOffset += bytes; 544 } 545 } else { 546 fwrite(ptr, size, nmemb, stream); 547 mOffset += bytes; 548 } 549 return bytes; 550} 551 552void MPEG4Writer::beginBox(const char *fourcc) { 553 CHECK_EQ(strlen(fourcc), 4); 554 555 mBoxes.push_back(mWriteMoovBoxToMemory? 556 mMoovBoxBufferOffset: mOffset); 557 558 writeInt32(0); 559 writeFourcc(fourcc); 560} 561 562void MPEG4Writer::endBox() { 563 CHECK(!mBoxes.empty()); 564 565 off_t offset = *--mBoxes.end(); 566 mBoxes.erase(--mBoxes.end()); 567 568 if (mWriteMoovBoxToMemory) { 569 int32_t x = htonl(mMoovBoxBufferOffset - offset); 570 memcpy(mMoovBoxBuffer + offset, &x, 4); 571 } else { 572 fseeko(mFile, offset, SEEK_SET); 573 writeInt32(mOffset - offset); 574 mOffset -= 4; 575 fseeko(mFile, mOffset, SEEK_SET); 576 } 577} 578 579void MPEG4Writer::writeInt8(int8_t x) { 580 write(&x, 1, 1, mFile); 581} 582 583void MPEG4Writer::writeInt16(int16_t x) { 584 x = htons(x); 585 write(&x, 1, 2, mFile); 586} 587 588void MPEG4Writer::writeInt32(int32_t x) { 589 x = htonl(x); 590 write(&x, 1, 4, mFile); 591} 592 593void MPEG4Writer::writeInt64(int64_t x) { 594 x = hton64(x); 595 write(&x, 1, 8, mFile); 596} 597 598void MPEG4Writer::writeCString(const char *s) { 599 size_t n = strlen(s); 600 write(s, 1, n + 1, mFile); 601} 602 603void MPEG4Writer::writeFourcc(const char *s) { 604 CHECK_EQ(strlen(s), 4); 605 write(s, 1, 4, mFile); 606} 607 608void MPEG4Writer::write(const void *data, size_t size) { 609 write(data, 1, size, mFile); 610} 611 612bool MPEG4Writer::exceedsFileSizeLimit() { 613 // No limit 614 if (mMaxFileSizeLimitBytes == 0) { 615 return false; 616 } 617 618 int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize); 619 for (List<Track *>::iterator it = mTracks.begin(); 620 it != mTracks.end(); ++it) { 621 nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes(); 622 } 623 return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes); 624} 625 626bool MPEG4Writer::exceedsFileDurationLimit() { 627 // No limit 628 if (mMaxFileDurationLimitUs == 0) { 629 return false; 630 } 631 632 for (List<Track *>::iterator it = mTracks.begin(); 633 it != mTracks.end(); ++it) { 634 if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) { 635 return true; 636 } 637 } 638 return false; 639} 640 641bool MPEG4Writer::reachedEOS() { 642 bool allDone = true; 643 for (List<Track *>::iterator it = mTracks.begin(); 644 it != mTracks.end(); ++it) { 645 if (!(*it)->reachedEOS()) { 646 allDone = false; 647 break; 648 } 649 } 650 651 return allDone; 652} 653 654void MPEG4Writer::setStartTimestampUs(int64_t timeUs) { 655 LOGI("setStartTimestampUs: %lld", timeUs); 656 CHECK(timeUs >= 0); 657 Mutex::Autolock autoLock(mLock); 658 if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { 659 mStartTimestampUs = timeUs; 660 LOGI("Earliest track starting time: %lld", mStartTimestampUs); 661 } 662} 663 664int64_t MPEG4Writer::getStartTimestampUs() { 665 Mutex::Autolock autoLock(mLock); 666 return mStartTimestampUs; 667} 668 669size_t MPEG4Writer::numTracks() { 670 Mutex::Autolock autolock(mLock); 671 return mTracks.size(); 672} 673 674//////////////////////////////////////////////////////////////////////////////// 675 676MPEG4Writer::Track::Track( 677 MPEG4Writer *owner, const sp<MediaSource> &source) 678 : mOwner(owner), 679 mMeta(source->getFormat()), 680 mSource(source), 681 mDone(false), 682 mPaused(false), 683 mResumed(false), 684 mMaxTimeStampUs(0), 685 mEstimatedTrackSizeBytes(0), 686 mSamplesHaveSameSize(true), 687 mCodecSpecificData(NULL), 688 mCodecSpecificDataSize(0), 689 mGotAllCodecSpecificData(false), 690 mReachedEOS(false) { 691 getCodecSpecificDataFromInputFormatIfPossible(); 692 693 if (!mMeta->findInt32(kKeyTimeScale, &mTimeScale)) { 694 mTimeScale = 1000; 695 } 696 CHECK(mTimeScale > 0); 697} 698 699void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { 700 const char *mime; 701 CHECK(mMeta->findCString(kKeyMIMEType, &mime)); 702 703 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 704 uint32_t type; 705 const void *data; 706 size_t size; 707 if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { 708 mCodecSpecificData = malloc(size); 709 mCodecSpecificDataSize = size; 710 memcpy(mCodecSpecificData, data, size); 711 mGotAllCodecSpecificData = true; 712 } 713 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) 714 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 715 uint32_t type; 716 const void *data; 717 size_t size; 718 if (mMeta->findData(kKeyESDS, &type, &data, &size)) { 719 ESDS esds(data, size); 720 if (esds.getCodecSpecificInfo(&data, &size) == OK) { 721 mCodecSpecificData = malloc(size); 722 mCodecSpecificDataSize = size; 723 memcpy(mCodecSpecificData, data, size); 724 mGotAllCodecSpecificData = true; 725 } 726 } 727 } 728} 729 730MPEG4Writer::Track::~Track() { 731 stop(); 732 733 if (mCodecSpecificData != NULL) { 734 free(mCodecSpecificData); 735 mCodecSpecificData = NULL; 736 } 737} 738 739void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { 740 LOGV("initTrackingProgressStatus"); 741 mPreviousTrackTimeUs = -1; 742 mTrackingProgressStatus = false; 743 mTrackEveryTimeDurationUs = 0; 744 { 745 int64_t timeUs; 746 if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { 747 LOGV("Receive request to track progress status for every %lld us", timeUs); 748 mTrackEveryTimeDurationUs = timeUs; 749 mTrackingProgressStatus = true; 750 } 751 } 752} 753 754status_t MPEG4Writer::Track::start(MetaData *params) { 755 if (!mDone && mPaused) { 756 mPaused = false; 757 mResumed = true; 758 return OK; 759 } 760 761 int64_t startTimeUs; 762 if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) { 763 startTimeUs = 0; 764 } 765 766 initTrackingProgressStatus(params); 767 768 sp<MetaData> meta = new MetaData; 769 meta->setInt64(kKeyTime, startTimeUs); 770 status_t err = mSource->start(meta.get()); 771 if (err != OK) { 772 mDone = mReachedEOS = true; 773 return err; 774 } 775 776 pthread_attr_t attr; 777 pthread_attr_init(&attr); 778 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 779 780 mDone = false; 781 mMaxTimeStampUs = 0; 782 mReachedEOS = false; 783 mEstimatedTrackSizeBytes = 0; 784 785 pthread_create(&mThread, &attr, ThreadWrapper, this); 786 pthread_attr_destroy(&attr); 787 788 return OK; 789} 790 791void MPEG4Writer::Track::pause() { 792 mPaused = true; 793} 794 795void MPEG4Writer::Track::stop() { 796 if (mDone) { 797 return; 798 } 799 800 mDone = true; 801 802 void *dummy; 803 pthread_join(mThread, &dummy); 804 805 mSource->stop(); 806} 807 808bool MPEG4Writer::Track::reachedEOS() { 809 return mReachedEOS; 810} 811 812// static 813void *MPEG4Writer::Track::ThreadWrapper(void *me) { 814 Track *track = static_cast<Track *>(me); 815 816 track->threadEntry(); 817 818 return NULL; 819} 820 821#include <ctype.h> 822static void hexdump(const void *_data, size_t size) { 823 const uint8_t *data = (const uint8_t *)_data; 824 size_t offset = 0; 825 while (offset < size) { 826 printf("0x%04x ", offset); 827 828 size_t n = size - offset; 829 if (n > 16) { 830 n = 16; 831 } 832 833 for (size_t i = 0; i < 16; ++i) { 834 if (i == 8) { 835 printf(" "); 836 } 837 838 if (offset + i < size) { 839 printf("%02x ", data[offset + i]); 840 } else { 841 printf(" "); 842 } 843 } 844 845 printf(" "); 846 847 for (size_t i = 0; i < n; ++i) { 848 if (isprint(data[offset + i])) { 849 printf("%c", data[offset + i]); 850 } else { 851 printf("."); 852 } 853 } 854 855 printf("\n"); 856 857 offset += 16; 858 } 859} 860 861 862status_t MPEG4Writer::Track::makeAVCCodecSpecificData( 863 const uint8_t *data, size_t size) { 864 // hexdump(data, size); 865 866 if (mCodecSpecificData != NULL) { 867 LOGE("Already have codec specific data"); 868 return ERROR_MALFORMED; 869 } 870 871 if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) { 872 LOGE("Must start with a start code"); 873 return ERROR_MALFORMED; 874 } 875 876 size_t picParamOffset = 4; 877 while (picParamOffset + 3 < size 878 && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) { 879 ++picParamOffset; 880 } 881 882 if (picParamOffset + 3 >= size) { 883 LOGE("Could not find start-code for pictureParameterSet"); 884 return ERROR_MALFORMED; 885 } 886 887 size_t seqParamSetLength = picParamOffset - 4; 888 size_t picParamSetLength = size - picParamOffset - 4; 889 890 mCodecSpecificDataSize = 891 6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2; 892 893 mCodecSpecificData = malloc(mCodecSpecificDataSize); 894 uint8_t *header = (uint8_t *)mCodecSpecificData; 895 header[0] = 1; 896 header[1] = 0x42; // profile 897 header[2] = 0x80; 898 header[3] = 0x1e; // level 899 900#if USE_NALLEN_FOUR 901 header[4] = 0xfc | 3; // length size == 4 bytes 902#else 903 header[4] = 0xfc | 1; // length size == 2 bytes 904#endif 905 906 header[5] = 0xe0 | 1; 907 header[6] = seqParamSetLength >> 8; 908 header[7] = seqParamSetLength & 0xff; 909 memcpy(&header[8], &data[4], seqParamSetLength); 910 header += 8 + seqParamSetLength; 911 header[0] = 1; 912 header[1] = picParamSetLength >> 8; 913 header[2] = picParamSetLength & 0xff; 914 memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength); 915 916 return OK; 917} 918 919static bool collectStatisticalData() { 920 char value[PROPERTY_VALUE_MAX]; 921 if (property_get("media.stagefright.record-stats", value, NULL) 922 && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 923 return true; 924 } 925 return false; 926} 927 928void MPEG4Writer::Track::threadEntry() { 929 sp<MetaData> meta = mSource->getFormat(); 930 const char *mime; 931 meta->findCString(kKeyMIMEType, &mime); 932 bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 933 !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 934 bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 935 bool is_audio = !strncasecmp(mime, "audio/", 6); 936 int32_t count = 0; 937 const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 938 int64_t chunkTimestampUs = 0; 939 int32_t nChunks = 0; 940 int32_t nZeroLengthFrames = 0; 941 int64_t lastTimestampUs = 0; // Previous sample time stamp in ms 942 int64_t lastDurationUs = 0; // Between the previous two samples in ms 943 int32_t sampleCount = 1; // Sample count in the current stts table entry 944 uint32_t previousSampleSize = 0; // Size of the previous sample 945 int64_t previousPausedDurationUs = 0; 946 sp<MetaData> meta_data; 947 bool collectStats = collectStatisticalData(); 948 949 mNumSamples = 0; 950 status_t err = OK; 951 MediaBuffer *buffer; 952 while (!mDone && (err = mSource->read(&buffer)) == OK) { 953 if (buffer->range_length() == 0) { 954 buffer->release(); 955 buffer = NULL; 956 ++nZeroLengthFrames; 957 continue; 958 } 959 960 // If the codec specific data has not been received yet, delay pause. 961 // After the codec specific data is received, discard what we received 962 // when the track is to be paused. 963 if (mPaused && !mResumed) { 964 buffer->release(); 965 buffer = NULL; 966 continue; 967 } 968 969 ++count; 970 971 int32_t isCodecConfig; 972 if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 973 && isCodecConfig) { 974 CHECK(!mGotAllCodecSpecificData); 975 976 if (is_avc) { 977 status_t err = makeAVCCodecSpecificData( 978 (const uint8_t *)buffer->data() 979 + buffer->range_offset(), 980 buffer->range_length()); 981 CHECK_EQ(OK, err); 982 } else if (is_mpeg4) { 983 mCodecSpecificDataSize = buffer->range_length(); 984 mCodecSpecificData = malloc(mCodecSpecificDataSize); 985 memcpy(mCodecSpecificData, 986 (const uint8_t *)buffer->data() 987 + buffer->range_offset(), 988 buffer->range_length()); 989 } 990 991 buffer->release(); 992 buffer = NULL; 993 994 mGotAllCodecSpecificData = true; 995 continue; 996 } else if (!mGotAllCodecSpecificData && 997 count == 1 && is_mpeg4 && mCodecSpecificData == NULL) { 998 // The TI mpeg4 encoder does not properly set the 999 // codec-specific-data flag. 1000 1001 const uint8_t *data = 1002 (const uint8_t *)buffer->data() + buffer->range_offset(); 1003 1004 const size_t size = buffer->range_length(); 1005 1006 size_t offset = 0; 1007 while (offset + 3 < size) { 1008 if (data[offset] == 0x00 && data[offset + 1] == 0x00 1009 && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) { 1010 break; 1011 } 1012 1013 ++offset; 1014 } 1015 1016 // CHECK(offset + 3 < size); 1017 if (offset + 3 >= size) { 1018 // XXX assume the entire first chunk of data is the codec specific 1019 // data. 1020 offset = size; 1021 } 1022 1023 mCodecSpecificDataSize = offset; 1024 mCodecSpecificData = malloc(offset); 1025 memcpy(mCodecSpecificData, data, offset); 1026 1027 buffer->set_range(buffer->range_offset() + offset, size - offset); 1028 1029 if (size == offset) { 1030 buffer->release(); 1031 buffer = NULL; 1032 1033 continue; 1034 } 1035 1036 mGotAllCodecSpecificData = true; 1037 } else if (!mGotAllCodecSpecificData && is_avc && count < 3) { 1038 // The TI video encoder does not flag codec specific data 1039 // as such and also splits up SPS and PPS across two buffers. 1040 1041 const uint8_t *data = 1042 (const uint8_t *)buffer->data() + buffer->range_offset(); 1043 1044 size_t size = buffer->range_length(); 1045 1046 CHECK(count == 2 || mCodecSpecificData == NULL); 1047 1048 size_t offset = mCodecSpecificDataSize; 1049 mCodecSpecificDataSize += size + 4; 1050 mCodecSpecificData = 1051 realloc(mCodecSpecificData, mCodecSpecificDataSize); 1052 1053 memcpy((uint8_t *)mCodecSpecificData + offset, 1054 "\x00\x00\x00\x01", 4); 1055 1056 memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size); 1057 1058 buffer->release(); 1059 buffer = NULL; 1060 1061 if (count == 2) { 1062 void *tmp = mCodecSpecificData; 1063 size = mCodecSpecificDataSize; 1064 mCodecSpecificData = NULL; 1065 mCodecSpecificDataSize = 0; 1066 1067 status_t err = makeAVCCodecSpecificData( 1068 (const uint8_t *)tmp, size); 1069 free(tmp); 1070 tmp = NULL; 1071 CHECK_EQ(OK, err); 1072 1073 mGotAllCodecSpecificData = true; 1074 } 1075 1076 continue; 1077 } 1078 1079 if (!mGotAllCodecSpecificData) { 1080 mGotAllCodecSpecificData = true; 1081 } 1082 1083 // Make a deep copy of the MediaBuffer and Metadata and release 1084 // the original as soon as we can 1085 MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 1086 memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 1087 buffer->range_length()); 1088 copy->set_range(0, buffer->range_length()); 1089 meta_data = new MetaData(*buffer->meta_data().get()); 1090 buffer->release(); 1091 buffer = NULL; 1092 1093 if (is_avc) StripStartcode(copy); 1094 1095 size_t sampleSize; 1096 sampleSize = is_avc 1097#if USE_NALLEN_FOUR 1098 ? copy->range_length() + 4 1099#else 1100 ? copy->range_length() + 2 1101#endif 1102 : copy->range_length(); 1103 1104 // Max file size or duration handling 1105 mEstimatedTrackSizeBytes += sampleSize; 1106 if (mOwner->exceedsFileSizeLimit()) { 1107 mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 1108 break; 1109 } 1110 if (mOwner->exceedsFileDurationLimit()) { 1111 mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 1112 break; 1113 } 1114 1115 1116 int32_t isSync = false; 1117 meta_data->findInt32(kKeyIsSyncFrame, &isSync); 1118 1119 int64_t timestampUs; 1120 CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); 1121 1122//////////////////////////////////////////////////////////////////////////////// 1123 if (mSampleSizes.empty()) { 1124 mStartTimestampUs = timestampUs; 1125 mOwner->setStartTimestampUs(mStartTimestampUs); 1126 } 1127 1128 if (mResumed) { 1129 previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - lastDurationUs); 1130 mResumed = false; 1131 } 1132 1133 timestampUs -= previousPausedDurationUs; 1134 LOGV("time stamp: %lld and previous paused duration %lld", 1135 timestampUs, previousPausedDurationUs); 1136 if (timestampUs > mMaxTimeStampUs) { 1137 mMaxTimeStampUs = timestampUs; 1138 } 1139 1140 mSampleSizes.push_back(sampleSize); 1141 ++mNumSamples; 1142 if (mNumSamples > 2) { 1143 if (lastDurationUs != timestampUs - lastTimestampUs) { 1144 SttsTableEntry sttsEntry(sampleCount, lastDurationUs); 1145 mSttsTableEntries.push_back(sttsEntry); 1146 sampleCount = 1; 1147 } else { 1148 ++sampleCount; 1149 } 1150 } 1151 if (mSamplesHaveSameSize) { 1152 if (mNumSamples >= 2 && previousSampleSize != sampleSize) { 1153 mSamplesHaveSameSize = false; 1154 } 1155 previousSampleSize = sampleSize; 1156 } 1157 lastDurationUs = timestampUs - lastTimestampUs; 1158 lastTimestampUs = timestampUs; 1159 1160 if (isSync != 0) { 1161 mStssTableEntries.push_back(mNumSamples); 1162 } 1163 1164 if (mTrackingProgressStatus) { 1165 if (mPreviousTrackTimeUs <= 0) { 1166 mPreviousTrackTimeUs = mStartTimestampUs; 1167 } 1168 trackProgressStatus(timestampUs); 1169 } 1170 if (mOwner->numTracks() == 1) { 1171 off_t offset = is_avc? mOwner->addLengthPrefixedSample_l(copy) 1172 : mOwner->addSample_l(copy); 1173 if (mChunkOffsets.empty()) { 1174 mChunkOffsets.push_back(offset); 1175 } 1176 copy->release(); 1177 copy = NULL; 1178 continue; 1179 } 1180 1181 mChunkSamples.push_back(copy); 1182 if (interleaveDurationUs == 0) { 1183 StscTableEntry stscEntry(++nChunks, 1, 1); 1184 mStscTableEntries.push_back(stscEntry); 1185 writeOneChunk(is_avc); 1186 } else { 1187 if (chunkTimestampUs == 0) { 1188 chunkTimestampUs = timestampUs; 1189 } else { 1190 if (timestampUs - chunkTimestampUs > interleaveDurationUs) { 1191 ++nChunks; 1192 if (collectStats) { 1193 mChunkDurations.push_back(timestampUs - chunkTimestampUs); 1194 } 1195 if (nChunks == 1 || // First chunk 1196 (--(mStscTableEntries.end()))->samplesPerChunk != 1197 mChunkSamples.size()) { 1198 StscTableEntry stscEntry(nChunks, 1199 mChunkSamples.size(), 1); 1200 mStscTableEntries.push_back(stscEntry); 1201 } 1202 writeOneChunk(is_avc); 1203 chunkTimestampUs = timestampUs; 1204 } 1205 } 1206 } 1207 1208 } 1209 1210 if (mSampleSizes.empty()) { 1211 err = UNKNOWN_ERROR; 1212 } 1213 mOwner->trackProgressStatus(this, -1, err); 1214 1215 // Last chunk 1216 if (mOwner->numTracks() == 1) { 1217 StscTableEntry stscEntry(1, mNumSamples, 1); 1218 mStscTableEntries.push_back(stscEntry); 1219 } else if (!mChunkSamples.empty()) { 1220 ++nChunks; 1221 StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1); 1222 mStscTableEntries.push_back(stscEntry); 1223 writeOneChunk(is_avc); 1224 } 1225 1226 // We don't really know how long the last frame lasts, since 1227 // there is no frame time after it, just repeat the previous 1228 // frame's duration. 1229 if (mNumSamples == 1) { 1230 lastDurationUs = 0; // A single sample's duration 1231 } else { 1232 ++sampleCount; // Count for the last sample 1233 } 1234 SttsTableEntry sttsEntry(sampleCount, lastDurationUs); 1235 mSttsTableEntries.push_back(sttsEntry); 1236 mReachedEOS = true; 1237 LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s", 1238 count, nZeroLengthFrames, mNumSamples, is_audio? "audio": "video"); 1239 1240 logStatisticalData(is_audio); 1241} 1242 1243void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { 1244 LOGV("trackProgressStatus: %lld us", timeUs); 1245 if (mTrackEveryTimeDurationUs > 0 && 1246 timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { 1247 LOGV("Fire time tracking progress status at %lld us", timeUs); 1248 mOwner->trackProgressStatus(this, timeUs - mPreviousTrackTimeUs, err); 1249 mPreviousTrackTimeUs = timeUs; 1250 } 1251} 1252 1253void MPEG4Writer::trackProgressStatus( 1254 const MPEG4Writer::Track* track, int64_t timeUs, status_t err) { 1255 Mutex::Autolock lock(mLock); 1256 int32_t nTracks = mTracks.size(); 1257 CHECK(nTracks >= 1); 1258 CHECK(nTracks < 64); // Arbitrary number 1259 1260 int32_t trackNum = 0; 1261#if 0 1262 // In the worst case, we can put the trackNum 1263 // along with MEDIA_RECORDER_INFO_COMPLETION_STATUS 1264 // to report the progress. 1265 for (List<Track *>::iterator it = mTracks.begin(); 1266 it != mTracks.end(); ++it, ++trackNum) { 1267 if (track == (*it)) { 1268 break; 1269 } 1270 } 1271#endif 1272 CHECK(trackNum < nTracks); 1273 trackNum <<= 16; 1274 1275 // Error notification 1276 // Do not consider ERROR_END_OF_STREAM an error 1277 if (err != OK && err != ERROR_END_OF_STREAM) { 1278 notify(MEDIA_RECORDER_EVENT_ERROR, 1279 trackNum | MEDIA_RECORDER_ERROR_UNKNOWN, 1280 err); 1281 return; 1282 } 1283 1284 if (timeUs == -1) { 1285 // Send completion notification 1286 notify(MEDIA_RECORDER_EVENT_INFO, 1287 trackNum | MEDIA_RECORDER_INFO_COMPLETION_STATUS, 1288 err); 1289 return; 1290 } else { 1291 // Send progress status 1292 notify(MEDIA_RECORDER_EVENT_INFO, 1293 trackNum | MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS, 1294 timeUs / 1000); 1295 } 1296} 1297 1298void MPEG4Writer::Track::findMinAvgMaxSampleDurationMs( 1299 int32_t *min, int32_t *avg, int32_t *max) { 1300 CHECK(!mSampleSizes.empty()); 1301 int32_t avgSampleDurationMs = mMaxTimeStampUs / 1000 / mNumSamples; 1302 int32_t minSampleDurationMs = 0x7FFFFFFF; 1303 int32_t maxSampleDurationMs = 0; 1304 for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 1305 it != mSttsTableEntries.end(); ++it) { 1306 int32_t sampleDurationMs = 1307 (static_cast<int32_t>(it->sampleDurationUs) + 500) / 1000; 1308 if (sampleDurationMs > maxSampleDurationMs) { 1309 maxSampleDurationMs = sampleDurationMs; 1310 } else if (sampleDurationMs < minSampleDurationMs) { 1311 minSampleDurationMs = sampleDurationMs; 1312 } 1313 LOGI("sample duration: %d ms", sampleDurationMs); 1314 } 1315 CHECK(minSampleDurationMs != 0); 1316 CHECK(avgSampleDurationMs != 0); 1317 CHECK(maxSampleDurationMs != 0); 1318 *min = minSampleDurationMs; 1319 *avg = avgSampleDurationMs; 1320 *max = maxSampleDurationMs; 1321} 1322 1323// Don't count the last duration 1324void MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) { 1325 int64_t duration = mOwner->interleaveDuration(); 1326 int64_t minChunkDuration = duration; 1327 int64_t maxChunkDuration = duration; 1328 if (mChunkDurations.size() > 1) { 1329 for (List<int64_t>::iterator it = mChunkDurations.begin(); 1330 it != --mChunkDurations.end(); ++it) { 1331 if (minChunkDuration > (*it)) { 1332 minChunkDuration = (*it); 1333 } else if (maxChunkDuration < (*it)) { 1334 maxChunkDuration = (*it); 1335 } 1336 } 1337 } 1338 *min = minChunkDuration; 1339 *max = maxChunkDuration; 1340} 1341 1342void MPEG4Writer::Track::logStatisticalData(bool isAudio) { 1343 if (mMaxTimeStampUs <= 0 || mSampleSizes.empty()) { 1344 LOGI("nothing is recorded"); 1345 return; 1346 } 1347 1348 bool collectStats = collectStatisticalData(); 1349 1350 if (collectStats) { 1351 LOGI("%s track - duration %lld us, total %d frames", 1352 isAudio? "audio": "video", mMaxTimeStampUs, 1353 mNumSamples); 1354 int32_t min, avg, max; 1355 findMinAvgMaxSampleDurationMs(&min, &avg, &max); 1356 LOGI("min/avg/max sample duration (ms): %d/%d/%d", min, avg, max); 1357 if (!isAudio) { 1358 float avgFps = 1000.0 / avg; 1359 float minFps = 1000.0 / max; 1360 float maxFps = 1000.0 / min; 1361 LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f", 1362 minFps, avgFps, maxFps); 1363 } 1364 1365 int64_t totalBytes = 0; 1366 for (List<size_t>::iterator it = mSampleSizes.begin(); 1367 it != mSampleSizes.end(); ++it) { 1368 totalBytes += (*it); 1369 } 1370 float bitRate = (totalBytes * 8000000.0) / mMaxTimeStampUs; 1371 LOGI("avg bit rate (bps): %.2f", bitRate); 1372 1373 int64_t duration = mOwner->interleaveDuration(); 1374 if (duration != 0) { // If interleaving is enabled 1375 int64_t minChunk, maxChunk; 1376 findMinMaxChunkDurations(&minChunk, &maxChunk); 1377 LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld", 1378 minChunk, duration, maxChunk); 1379 } 1380 } 1381} 1382 1383void MPEG4Writer::Track::writeOneChunk(bool isAvc) { 1384 mOwner->lock(); 1385 for (List<MediaBuffer *>::iterator it = mChunkSamples.begin(); 1386 it != mChunkSamples.end(); ++it) { 1387 off_t offset = isAvc? mOwner->addLengthPrefixedSample_l(*it) 1388 : mOwner->addSample_l(*it); 1389 if (it == mChunkSamples.begin()) { 1390 mChunkOffsets.push_back(offset); 1391 } 1392 } 1393 mOwner->unlock(); 1394 while (!mChunkSamples.empty()) { 1395 List<MediaBuffer *>::iterator it = mChunkSamples.begin(); 1396 (*it)->release(); 1397 (*it) = NULL; 1398 mChunkSamples.erase(it); 1399 } 1400 mChunkSamples.clear(); 1401} 1402 1403int64_t MPEG4Writer::Track::getDurationUs() const { 1404 return mMaxTimeStampUs; 1405} 1406 1407int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { 1408 return mEstimatedTrackSizeBytes; 1409} 1410 1411void MPEG4Writer::Track::writeTrackHeader( 1412 int32_t trackID, bool use32BitOffset) { 1413 const char *mime; 1414 bool success = mMeta->findCString(kKeyMIMEType, &mime); 1415 CHECK(success); 1416 1417 bool is_audio = !strncasecmp(mime, "audio/", 6); 1418 LOGV("%s track time scale: %d", 1419 is_audio? "Audio": "Video", mTimeScale); 1420 1421 1422 time_t now = time(NULL); 1423 int32_t mvhdTimeScale = mOwner->getTimeScale(); 1424 int64_t trakDurationUs = getDurationUs(); 1425 1426 mOwner->beginBox("trak"); 1427 1428 mOwner->beginBox("tkhd"); 1429 // Flags = 7 to indicate that the track is enabled, and 1430 // part of the presentation 1431 mOwner->writeInt32(0x07); // version=0, flags=7 1432 mOwner->writeInt32(now); // creation time 1433 mOwner->writeInt32(now); // modification time 1434 mOwner->writeInt32(trackID); 1435 mOwner->writeInt32(0); // reserved 1436 int32_t tkhdDuration = 1437 (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 1438 mOwner->writeInt32(tkhdDuration); // in mvhd timescale 1439 mOwner->writeInt32(0); // reserved 1440 mOwner->writeInt32(0); // reserved 1441 mOwner->writeInt16(0); // layer 1442 mOwner->writeInt16(0); // alternate group 1443 mOwner->writeInt16(is_audio ? 0x100 : 0); // volume 1444 mOwner->writeInt16(0); // reserved 1445 1446 mOwner->writeInt32(0x10000); // matrix 1447 mOwner->writeInt32(0); 1448 mOwner->writeInt32(0); 1449 mOwner->writeInt32(0); 1450 mOwner->writeInt32(0x10000); 1451 mOwner->writeInt32(0); 1452 mOwner->writeInt32(0); 1453 mOwner->writeInt32(0); 1454 mOwner->writeInt32(0x40000000); 1455 1456 if (is_audio) { 1457 mOwner->writeInt32(0); 1458 mOwner->writeInt32(0); 1459 } else { 1460 int32_t width, height; 1461 bool success = mMeta->findInt32(kKeyWidth, &width); 1462 success = success && mMeta->findInt32(kKeyHeight, &height); 1463 CHECK(success); 1464 1465 mOwner->writeInt32(width << 16); // 32-bit fixed-point value 1466 mOwner->writeInt32(height << 16); // 32-bit fixed-point value 1467 } 1468 mOwner->endBox(); // tkhd 1469 1470 int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); 1471 if (mStartTimestampUs != moovStartTimeUs) { 1472 mOwner->beginBox("edts"); 1473 mOwner->beginBox("elst"); 1474 mOwner->writeInt32(0); // version=0, flags=0: 32-bit time 1475 mOwner->writeInt32(2); // never ends with an empty list 1476 1477 // First elst entry: specify the starting time offset 1478 int64_t offsetUs = mStartTimestampUs - moovStartTimeUs; 1479 int32_t seg = (offsetUs * mvhdTimeScale + 5E5) / 1E6; 1480 mOwner->writeInt32(seg); // in mvhd timecale 1481 mOwner->writeInt32(-1); // starting time offset 1482 mOwner->writeInt32(1 << 16); // rate = 1.0 1483 1484 // Second elst entry: specify the track duration 1485 seg = (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; 1486 mOwner->writeInt32(seg); // in mvhd timescale 1487 mOwner->writeInt32(0); 1488 mOwner->writeInt32(1 << 16); 1489 mOwner->endBox(); 1490 mOwner->endBox(); 1491 } 1492 1493 mOwner->beginBox("mdia"); 1494 1495 mOwner->beginBox("mdhd"); 1496 mOwner->writeInt32(0); // version=0, flags=0 1497 mOwner->writeInt32(now); // creation time 1498 mOwner->writeInt32(now); // modification time 1499 mOwner->writeInt32(mTimeScale); // media timescale 1500 int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; 1501 mOwner->writeInt32(mdhdDuration); // use media timescale 1502 // Language follows the three letter standard ISO-639-2/T 1503 // 'e', 'n', 'g' for "English", for instance. 1504 // Each character is packed as the difference between its ASCII value and 0x60. 1505 // For "English", these are 00101, 01110, 00111. 1506 // XXX: Where is the padding bit located: 0x15C7? 1507 mOwner->writeInt16(0); // language code 1508 mOwner->writeInt16(0); // predefined 1509 mOwner->endBox(); 1510 1511 mOwner->beginBox("hdlr"); 1512 mOwner->writeInt32(0); // version=0, flags=0 1513 mOwner->writeInt32(0); // component type: should be mhlr 1514 mOwner->writeFourcc(is_audio ? "soun" : "vide"); // component subtype 1515 mOwner->writeInt32(0); // reserved 1516 mOwner->writeInt32(0); // reserved 1517 mOwner->writeInt32(0); // reserved 1518 // Removing "r" for the name string just makes the string 4 byte aligned 1519 mOwner->writeCString(is_audio ? "SoundHandle": "VideoHandle"); // name 1520 mOwner->endBox(); 1521 1522 mOwner->beginBox("minf"); 1523 if (is_audio) { 1524 mOwner->beginBox("smhd"); 1525 mOwner->writeInt32(0); // version=0, flags=0 1526 mOwner->writeInt16(0); // balance 1527 mOwner->writeInt16(0); // reserved 1528 mOwner->endBox(); 1529 } else { 1530 mOwner->beginBox("vmhd"); 1531 mOwner->writeInt32(0x01); // version=0, flags=1 1532 mOwner->writeInt16(0); // graphics mode 1533 mOwner->writeInt16(0); // opcolor 1534 mOwner->writeInt16(0); 1535 mOwner->writeInt16(0); 1536 mOwner->endBox(); 1537 } 1538 1539 mOwner->beginBox("dinf"); 1540 mOwner->beginBox("dref"); 1541 mOwner->writeInt32(0); // version=0, flags=0 1542 mOwner->writeInt32(1); // entry count (either url or urn) 1543 // The table index here refers to the sample description index 1544 // in the sample table entries. 1545 mOwner->beginBox("url "); 1546 mOwner->writeInt32(1); // version=0, flags=1 (self-contained) 1547 mOwner->endBox(); // url 1548 mOwner->endBox(); // dref 1549 mOwner->endBox(); // dinf 1550 1551 mOwner->beginBox("stbl"); 1552 1553 mOwner->beginBox("stsd"); 1554 mOwner->writeInt32(0); // version=0, flags=0 1555 mOwner->writeInt32(1); // entry count 1556 if (is_audio) { 1557 const char *fourcc = NULL; 1558 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 1559 fourcc = "samr"; 1560 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 1561 fourcc = "sawb"; 1562 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 1563 fourcc = "mp4a"; 1564 } else { 1565 LOGE("Unknown mime type '%s'.", mime); 1566 CHECK(!"should not be here, unknown mime type."); 1567 } 1568 1569 mOwner->beginBox(fourcc); // audio format 1570 mOwner->writeInt32(0); // reserved 1571 mOwner->writeInt16(0); // reserved 1572 mOwner->writeInt16(0x1); // data ref index 1573 mOwner->writeInt32(0); // reserved 1574 mOwner->writeInt32(0); // reserved 1575 int32_t nChannels; 1576 CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 1577 mOwner->writeInt16(nChannels); // channel count 1578 mOwner->writeInt16(16); // sample size 1579 mOwner->writeInt16(0); // predefined 1580 mOwner->writeInt16(0); // reserved 1581 1582 int32_t samplerate; 1583 bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 1584 CHECK(success); 1585 1586 mOwner->writeInt32(samplerate << 16); 1587 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 1588 mOwner->beginBox("esds"); 1589 1590 mOwner->writeInt32(0); // version=0, flags=0 1591 mOwner->writeInt8(0x03); // ES_DescrTag 1592 mOwner->writeInt8(23 + mCodecSpecificDataSize); 1593 mOwner->writeInt16(0x0000);// ES_ID 1594 mOwner->writeInt8(0x00); 1595 1596 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 1597 mOwner->writeInt8(15 + mCodecSpecificDataSize); 1598 mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 1599 mOwner->writeInt8(0x15); // streamType AudioStream 1600 1601 mOwner->writeInt16(0x03); // XXX 1602 mOwner->writeInt8(0x00); // buffer size 24-bit 1603 mOwner->writeInt32(96000); // max bit rate 1604 mOwner->writeInt32(96000); // avg bit rate 1605 1606 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 1607 mOwner->writeInt8(mCodecSpecificDataSize); 1608 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 1609 1610 static const uint8_t kData2[] = { 1611 0x06, // SLConfigDescriptorTag 1612 0x01, 1613 0x02 1614 }; 1615 mOwner->write(kData2, sizeof(kData2)); 1616 1617 mOwner->endBox(); // esds 1618 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || 1619 !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 1620 // 3gpp2 Spec AMRSampleEntry fields 1621 mOwner->beginBox("damr"); 1622 mOwner->writeCString(" "); // vendor: 4 bytes 1623 mOwner->writeInt8(0); // decoder version 1624 mOwner->writeInt16(0x83FF); // mode set: all enabled 1625 mOwner->writeInt8(0); // mode change period 1626 mOwner->writeInt8(1); // frames per sample 1627 mOwner->endBox(); 1628 } 1629 mOwner->endBox(); 1630 } else { 1631 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 1632 mOwner->beginBox("mp4v"); 1633 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 1634 mOwner->beginBox("s263"); 1635 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 1636 mOwner->beginBox("avc1"); 1637 } else { 1638 LOGE("Unknown mime type '%s'.", mime); 1639 CHECK(!"should not be here, unknown mime type."); 1640 } 1641 1642 mOwner->writeInt32(0); // reserved 1643 mOwner->writeInt16(0); // reserved 1644 mOwner->writeInt16(1); // data ref index 1645 mOwner->writeInt16(0); // predefined 1646 mOwner->writeInt16(0); // reserved 1647 mOwner->writeInt32(0); // predefined 1648 mOwner->writeInt32(0); // predefined 1649 mOwner->writeInt32(0); // predefined 1650 1651 int32_t width, height; 1652 bool success = mMeta->findInt32(kKeyWidth, &width); 1653 success = success && mMeta->findInt32(kKeyHeight, &height); 1654 CHECK(success); 1655 1656 mOwner->writeInt16(width); 1657 mOwner->writeInt16(height); 1658 mOwner->writeInt32(0x480000); // horiz resolution 1659 mOwner->writeInt32(0x480000); // vert resolution 1660 mOwner->writeInt32(0); // reserved 1661 mOwner->writeInt16(1); // frame count 1662 mOwner->write(" ", 32); 1663 mOwner->writeInt16(0x18); // depth 1664 mOwner->writeInt16(-1); // predefined 1665 1666 CHECK(23 + mCodecSpecificDataSize < 128); 1667 1668 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 1669 mOwner->beginBox("esds"); 1670 1671 mOwner->writeInt32(0); // version=0, flags=0 1672 1673 mOwner->writeInt8(0x03); // ES_DescrTag 1674 mOwner->writeInt8(23 + mCodecSpecificDataSize); 1675 mOwner->writeInt16(0x0000); // ES_ID 1676 mOwner->writeInt8(0x1f); 1677 1678 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 1679 mOwner->writeInt8(15 + mCodecSpecificDataSize); 1680 mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 1681 mOwner->writeInt8(0x11); // streamType VisualStream 1682 1683 static const uint8_t kData[] = { 1684 0x01, 0x77, 0x00, 1685 0x00, 0x03, 0xe8, 0x00, 1686 0x00, 0x03, 0xe8, 0x00 1687 }; 1688 mOwner->write(kData, sizeof(kData)); 1689 1690 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 1691 1692 mOwner->writeInt8(mCodecSpecificDataSize); 1693 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 1694 1695 static const uint8_t kData2[] = { 1696 0x06, // SLConfigDescriptorTag 1697 0x01, 1698 0x02 1699 }; 1700 mOwner->write(kData2, sizeof(kData2)); 1701 1702 mOwner->endBox(); // esds 1703 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 1704 mOwner->beginBox("d263"); 1705 1706 mOwner->writeInt32(0); // vendor 1707 mOwner->writeInt8(0); // decoder version 1708 mOwner->writeInt8(10); // level: 10 1709 mOwner->writeInt8(0); // profile: 0 1710 1711 mOwner->endBox(); // d263 1712 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 1713 mOwner->beginBox("avcC"); 1714 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 1715 mOwner->endBox(); // avcC 1716 } 1717 1718 mOwner->beginBox("pasp"); 1719 // This is useful if the pixel is not square 1720 mOwner->writeInt32(1 << 16); // hspacing 1721 mOwner->writeInt32(1 << 16); // vspacing 1722 mOwner->endBox(); // pasp 1723 mOwner->endBox(); // mp4v, s263 or avc1 1724 } 1725 mOwner->endBox(); // stsd 1726 1727 mOwner->beginBox("stts"); 1728 mOwner->writeInt32(0); // version=0, flags=0 1729 mOwner->writeInt32(mSttsTableEntries.size()); 1730 for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 1731 it != mSttsTableEntries.end(); ++it) { 1732 mOwner->writeInt32(it->sampleCount); 1733 int32_t dur = (it->sampleDurationUs * mTimeScale + 5E5) / 1E6; 1734 mOwner->writeInt32(dur); 1735 } 1736 mOwner->endBox(); // stts 1737 1738 if (!is_audio) { 1739 mOwner->beginBox("stss"); 1740 mOwner->writeInt32(0); // version=0, flags=0 1741 mOwner->writeInt32(mStssTableEntries.size()); // number of sync frames 1742 for (List<int32_t>::iterator it = mStssTableEntries.begin(); 1743 it != mStssTableEntries.end(); ++it) { 1744 mOwner->writeInt32(*it); 1745 } 1746 mOwner->endBox(); // stss 1747 } 1748 1749 mOwner->beginBox("stsz"); 1750 mOwner->writeInt32(0); // version=0, flags=0 1751 if (mSamplesHaveSameSize) { 1752 List<size_t>::iterator it = mSampleSizes.begin(); 1753 mOwner->writeInt32(*it); // default sample size 1754 } else { 1755 mOwner->writeInt32(0); 1756 } 1757 mOwner->writeInt32(mNumSamples); 1758 if (!mSamplesHaveSameSize) { 1759 for (List<size_t>::iterator it = mSampleSizes.begin(); 1760 it != mSampleSizes.end(); ++it) { 1761 mOwner->writeInt32(*it); 1762 } 1763 } 1764 mOwner->endBox(); // stsz 1765 1766 mOwner->beginBox("stsc"); 1767 mOwner->writeInt32(0); // version=0, flags=0 1768 mOwner->writeInt32(mStscTableEntries.size()); 1769 for (List<StscTableEntry>::iterator it = mStscTableEntries.begin(); 1770 it != mStscTableEntries.end(); ++it) { 1771 mOwner->writeInt32(it->firstChunk); 1772 mOwner->writeInt32(it->samplesPerChunk); 1773 mOwner->writeInt32(it->sampleDescriptionId); 1774 } 1775 mOwner->endBox(); // stsc 1776 mOwner->beginBox(use32BitOffset? "stco": "co64"); 1777 mOwner->writeInt32(0); // version=0, flags=0 1778 mOwner->writeInt32(mChunkOffsets.size()); 1779 for (List<off_t>::iterator it = mChunkOffsets.begin(); 1780 it != mChunkOffsets.end(); ++it) { 1781 if (use32BitOffset) { 1782 mOwner->writeInt32(static_cast<int32_t>(*it)); 1783 } else { 1784 mOwner->writeInt64((*it)); 1785 } 1786 } 1787 mOwner->endBox(); // stco or co64 1788 1789 mOwner->endBox(); // stbl 1790 mOwner->endBox(); // minf 1791 mOwner->endBox(); // mdia 1792 mOwner->endBox(); // trak 1793} 1794 1795} // namespace android 1796