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