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