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