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