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