MPEG4Writer.cpp revision be83c9e8c71ce16c0d0e9ed9df525510a49a541b
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 35namespace android { 36 37class MPEG4Writer::Track { 38public: 39 Track(MPEG4Writer *owner, const sp<MediaSource> &source); 40 ~Track(); 41 42 status_t start(); 43 void stop(); 44 bool reachedEOS(); 45 46 int64_t getDurationUs() const; 47 void writeTrackHeader(int32_t trackID); 48 49private: 50 MPEG4Writer *mOwner; 51 sp<MetaData> mMeta; 52 sp<MediaSource> mSource; 53 volatile bool mDone; 54 int64_t mMaxTimeStampUs; 55 56 pthread_t mThread; 57 58 struct SampleInfo { 59 size_t size; 60 int64_t timestamp; 61 }; 62 List<SampleInfo> mSampleInfos; 63 bool mSamplesHaveSameSize; 64 65 List<MediaBuffer *> mChunkSamples; 66 List<off_t> mChunkOffsets; 67 68 struct StscTableEntry { 69 70 StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id) 71 : firstChunk(chunk), 72 samplesPerChunk(samples), 73 sampleDescriptionId(id) {} 74 75 uint32_t firstChunk; 76 uint32_t samplesPerChunk; 77 uint32_t sampleDescriptionId; 78 }; 79 List<StscTableEntry> mStscTableEntries; 80 81 List<int32_t> mStssTableEntries; 82 83 struct SttsTableEntry { 84 85 SttsTableEntry(uint32_t count, uint32_t duration) 86 : sampleCount(count), sampleDuration(duration) {} 87 88 uint32_t sampleCount; 89 uint32_t sampleDuration; 90 }; 91 List<SttsTableEntry> mSttsTableEntries; 92 93 void *mCodecSpecificData; 94 size_t mCodecSpecificDataSize; 95 bool mGotAllCodecSpecificData; 96 97 bool mReachedEOS; 98 99 static void *ThreadWrapper(void *me); 100 void threadEntry(); 101 102 status_t makeAVCCodecSpecificData( 103 const uint8_t *data, size_t size); 104 void writeOneChunk(bool isAvc); 105 106 Track(const Track &); 107 Track &operator=(const Track &); 108}; 109 110#define USE_NALLEN_FOUR 1 111 112MPEG4Writer::MPEG4Writer(const char *filename) 113 : mFile(fopen(filename, "wb")), 114 mOffset(0), 115 mMdatOffset(0), 116 mInterleaveDurationUs(500000) { 117 CHECK(mFile != NULL); 118} 119 120MPEG4Writer::MPEG4Writer(int fd) 121 : mFile(fdopen(fd, "wb")), 122 mOffset(0), 123 mMdatOffset(0), 124 mInterleaveDurationUs(500000) { 125 CHECK(mFile != NULL); 126} 127 128MPEG4Writer::~MPEG4Writer() { 129 stop(); 130 131 for (List<Track *>::iterator it = mTracks.begin(); 132 it != mTracks.end(); ++it) { 133 delete *it; 134 } 135 mTracks.clear(); 136} 137 138status_t MPEG4Writer::addSource(const sp<MediaSource> &source) { 139 Track *track = new Track(this, source); 140 mTracks.push_back(track); 141 142 return OK; 143} 144 145status_t MPEG4Writer::start() { 146 if (mFile == NULL) { 147 return UNKNOWN_ERROR; 148 } 149 150 beginBox("ftyp"); 151 writeFourcc("isom"); 152 writeInt32(0); 153 writeFourcc("isom"); 154 endBox(); 155 156 mMdatOffset = mOffset; 157 write("\x00\x00\x00\x01mdat????????", 16); 158 159 for (List<Track *>::iterator it = mTracks.begin(); 160 it != mTracks.end(); ++it) { 161 status_t err = (*it)->start(); 162 163 if (err != OK) { 164 for (List<Track *>::iterator it2 = mTracks.begin(); 165 it2 != it; ++it2) { 166 (*it2)->stop(); 167 } 168 169 return err; 170 } 171 } 172 173 return OK; 174} 175 176void MPEG4Writer::stop() { 177 if (mFile == NULL) { 178 return; 179 } 180 181 int64_t max_duration = 0; 182 for (List<Track *>::iterator it = mTracks.begin(); 183 it != mTracks.end(); ++it) { 184 (*it)->stop(); 185 186 int64_t duration = (*it)->getDurationUs(); 187 if (duration > max_duration) { 188 max_duration = duration; 189 } 190 } 191 192 // Fix up the size of the 'mdat' chunk. 193 fseek(mFile, mMdatOffset + 8, SEEK_SET); 194 int64_t size = mOffset - mMdatOffset; 195 size = hton64(size); 196 fwrite(&size, 1, 8, mFile); 197 fseek(mFile, mOffset, SEEK_SET); 198 199 time_t now = time(NULL); 200 201 beginBox("moov"); 202 203 beginBox("mvhd"); 204 writeInt32(0); // version=0, flags=0 205 writeInt32(now); // creation time 206 writeInt32(now); // modification time 207 writeInt32(1000); // timescale 208 writeInt32(max_duration / 1000); 209 writeInt32(0x10000); // rate 210 writeInt16(0x100); // volume 211 writeInt16(0); // reserved 212 writeInt32(0); // reserved 213 writeInt32(0); // reserved 214 writeInt32(0x10000); // matrix 215 writeInt32(0); 216 writeInt32(0); 217 writeInt32(0); 218 writeInt32(0x10000); 219 writeInt32(0); 220 writeInt32(0); 221 writeInt32(0); 222 writeInt32(0x40000000); 223 writeInt32(0); // predefined 224 writeInt32(0); // predefined 225 writeInt32(0); // predefined 226 writeInt32(0); // predefined 227 writeInt32(0); // predefined 228 writeInt32(0); // predefined 229 writeInt32(mTracks.size() + 1); // nextTrackID 230 endBox(); // mvhd 231 232 int32_t id = 1; 233 for (List<Track *>::iterator it = mTracks.begin(); 234 it != mTracks.end(); ++it, ++id) { 235 (*it)->writeTrackHeader(id); 236 } 237 endBox(); // moov 238 239 CHECK(mBoxes.empty()); 240 241 fclose(mFile); 242 mFile = NULL; 243} 244 245status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { 246 mInterleaveDurationUs = durationUs; 247 return OK; 248} 249 250void MPEG4Writer::lock() { 251 mLock.lock(); 252} 253 254void MPEG4Writer::unlock() { 255 mLock.unlock(); 256} 257 258off_t MPEG4Writer::addSample_l(MediaBuffer *buffer) { 259 off_t old_offset = mOffset; 260 261 fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 262 1, buffer->range_length(), mFile); 263 264 mOffset += buffer->range_length(); 265 266 return old_offset; 267} 268 269static void StripStartcode(MediaBuffer *buffer) { 270 if (buffer->range_length() < 4) { 271 return; 272 } 273 274 const uint8_t *ptr = 275 (const uint8_t *)buffer->data() + buffer->range_offset(); 276 277 if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) { 278 buffer->set_range( 279 buffer->range_offset() + 4, buffer->range_length() - 4); 280 } 281} 282 283off_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) { 284 StripStartcode(buffer); 285 286 off_t old_offset = mOffset; 287 288 size_t length = buffer->range_length(); 289 290#if USE_NALLEN_FOUR 291 uint8_t x = length >> 24; 292 fwrite(&x, 1, 1, mFile); 293 x = (length >> 16) & 0xff; 294 fwrite(&x, 1, 1, mFile); 295 x = (length >> 8) & 0xff; 296 fwrite(&x, 1, 1, mFile); 297 x = length & 0xff; 298 fwrite(&x, 1, 1, mFile); 299#else 300 CHECK(length < 65536); 301 302 uint8_t x = length >> 8; 303 fwrite(&x, 1, 1, mFile); 304 x = length & 0xff; 305 fwrite(&x, 1, 1, mFile); 306#endif 307 308 fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 309 1, length, mFile); 310 311#if USE_NALLEN_FOUR 312 mOffset += length + 4; 313#else 314 mOffset += length + 2; 315#endif 316 317 return old_offset; 318} 319 320void MPEG4Writer::beginBox(const char *fourcc) { 321 CHECK_EQ(strlen(fourcc), 4); 322 323 mBoxes.push_back(mOffset); 324 325 writeInt32(0); 326 writeFourcc(fourcc); 327} 328 329void MPEG4Writer::endBox() { 330 CHECK(!mBoxes.empty()); 331 332 off_t offset = *--mBoxes.end(); 333 mBoxes.erase(--mBoxes.end()); 334 335 fseek(mFile, offset, SEEK_SET); 336 writeInt32(mOffset - offset); 337 mOffset -= 4; 338 fseek(mFile, mOffset, SEEK_SET); 339} 340 341void MPEG4Writer::writeInt8(int8_t x) { 342 fwrite(&x, 1, 1, mFile); 343 ++mOffset; 344} 345 346void MPEG4Writer::writeInt16(int16_t x) { 347 x = htons(x); 348 fwrite(&x, 1, 2, mFile); 349 mOffset += 2; 350} 351 352void MPEG4Writer::writeInt32(int32_t x) { 353 x = htonl(x); 354 fwrite(&x, 1, 4, mFile); 355 mOffset += 4; 356} 357 358void MPEG4Writer::writeInt64(int64_t x) { 359 x = hton64(x); 360 fwrite(&x, 1, 8, mFile); 361 mOffset += 8; 362} 363 364void MPEG4Writer::writeCString(const char *s) { 365 size_t n = strlen(s); 366 367 fwrite(s, 1, n + 1, mFile); 368 mOffset += n + 1; 369} 370 371void MPEG4Writer::writeFourcc(const char *s) { 372 CHECK_EQ(strlen(s), 4); 373 fwrite(s, 1, 4, mFile); 374 mOffset += 4; 375} 376 377void MPEG4Writer::write(const void *data, size_t size) { 378 fwrite(data, 1, size, mFile); 379 mOffset += size; 380} 381 382bool MPEG4Writer::reachedEOS() { 383 bool allDone = true; 384 for (List<Track *>::iterator it = mTracks.begin(); 385 it != mTracks.end(); ++it) { 386 if (!(*it)->reachedEOS()) { 387 allDone = false; 388 break; 389 } 390 } 391 392 return allDone; 393} 394 395//////////////////////////////////////////////////////////////////////////////// 396 397MPEG4Writer::Track::Track( 398 MPEG4Writer *owner, const sp<MediaSource> &source) 399 : mOwner(owner), 400 mMeta(source->getFormat()), 401 mSource(source), 402 mDone(false), 403 mMaxTimeStampUs(0), 404 mSamplesHaveSameSize(true), 405 mCodecSpecificData(NULL), 406 mCodecSpecificDataSize(0), 407 mGotAllCodecSpecificData(false), 408 mReachedEOS(false) { 409} 410 411MPEG4Writer::Track::~Track() { 412 stop(); 413 414 if (mCodecSpecificData != NULL) { 415 free(mCodecSpecificData); 416 mCodecSpecificData = NULL; 417 } 418} 419 420status_t MPEG4Writer::Track::start() { 421 status_t err = mSource->start(); 422 423 if (err != OK) { 424 mDone = mReachedEOS = true; 425 return err; 426 } 427 428 pthread_attr_t attr; 429 pthread_attr_init(&attr); 430 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 431 432 mDone = false; 433 mMaxTimeStampUs = 0; 434 mReachedEOS = false; 435 436 pthread_create(&mThread, &attr, ThreadWrapper, this); 437 pthread_attr_destroy(&attr); 438 439 return OK; 440} 441 442void MPEG4Writer::Track::stop() { 443 if (mDone) { 444 return; 445 } 446 447 mDone = true; 448 449 void *dummy; 450 pthread_join(mThread, &dummy); 451 452 mSource->stop(); 453} 454 455bool MPEG4Writer::Track::reachedEOS() { 456 return mReachedEOS; 457} 458 459// static 460void *MPEG4Writer::Track::ThreadWrapper(void *me) { 461 Track *track = static_cast<Track *>(me); 462 463 track->threadEntry(); 464 465 return NULL; 466} 467 468#include <ctype.h> 469static void hexdump(const void *_data, size_t size) { 470 const uint8_t *data = (const uint8_t *)_data; 471 size_t offset = 0; 472 while (offset < size) { 473 printf("0x%04x ", offset); 474 475 size_t n = size - offset; 476 if (n > 16) { 477 n = 16; 478 } 479 480 for (size_t i = 0; i < 16; ++i) { 481 if (i == 8) { 482 printf(" "); 483 } 484 485 if (offset + i < size) { 486 printf("%02x ", data[offset + i]); 487 } else { 488 printf(" "); 489 } 490 } 491 492 printf(" "); 493 494 for (size_t i = 0; i < n; ++i) { 495 if (isprint(data[offset + i])) { 496 printf("%c", data[offset + i]); 497 } else { 498 printf("."); 499 } 500 } 501 502 printf("\n"); 503 504 offset += 16; 505 } 506} 507 508 509status_t MPEG4Writer::Track::makeAVCCodecSpecificData( 510 const uint8_t *data, size_t size) { 511 // hexdump(data, size); 512 513 if (mCodecSpecificData != NULL) { 514 LOGE("Already have codec specific data"); 515 return ERROR_MALFORMED; 516 } 517 518 if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) { 519 LOGE("Must start with a start code"); 520 return ERROR_MALFORMED; 521 } 522 523 size_t picParamOffset = 4; 524 while (picParamOffset + 3 < size 525 && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) { 526 ++picParamOffset; 527 } 528 529 if (picParamOffset + 3 >= size) { 530 LOGE("Could not find start-code for pictureParameterSet"); 531 return ERROR_MALFORMED; 532 } 533 534 size_t seqParamSetLength = picParamOffset - 4; 535 size_t picParamSetLength = size - picParamOffset - 4; 536 537 mCodecSpecificDataSize = 538 6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2; 539 540 mCodecSpecificData = malloc(mCodecSpecificDataSize); 541 uint8_t *header = (uint8_t *)mCodecSpecificData; 542 header[0] = 1; 543 header[1] = 0x42; // profile 544 header[2] = 0x80; 545 header[3] = 0x1e; // level 546 547#if USE_NALLEN_FOUR 548 header[4] = 0xfc | 3; // length size == 4 bytes 549#else 550 header[4] = 0xfc | 1; // length size == 2 bytes 551#endif 552 553 header[5] = 0xe0 | 1; 554 header[6] = seqParamSetLength >> 8; 555 header[7] = seqParamSetLength & 0xff; 556 memcpy(&header[8], &data[4], seqParamSetLength); 557 header += 8 + seqParamSetLength; 558 header[0] = 1; 559 header[1] = picParamSetLength >> 8; 560 header[2] = picParamSetLength & 0xff; 561 memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength); 562 563 return OK; 564} 565 566void MPEG4Writer::Track::threadEntry() { 567 sp<MetaData> meta = mSource->getFormat(); 568 const char *mime; 569 meta->findCString(kKeyMIMEType, &mime); 570 bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 571 !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); 572 bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); 573 int32_t count = 0; 574 const int64_t interleaveDurationUs = mOwner->interleaveDuration(); 575 int64_t chunkTimestampUs = 0; 576 int32_t nChunks = 0; 577 int32_t nZeroLengthFrames = 0; 578 int64_t lastTimestamp = 0; // Timestamp of the previous sample 579 int64_t lastDuration = 0; // Time spacing between the previous two samples 580 int32_t sampleCount = 1; // Sample count in the current stts table entry 581 uint32_t previousSampleSize = 0; // Size of the previous sample 582 583 MediaBuffer *buffer; 584 while (!mDone && mSource->read(&buffer) == OK) { 585 if (buffer->range_length() == 0) { 586 buffer->release(); 587 buffer = NULL; 588 ++nZeroLengthFrames; 589 continue; 590 } 591 592 ++count; 593 594 int32_t isCodecConfig; 595 if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig) 596 && isCodecConfig) { 597 CHECK(!mGotAllCodecSpecificData); 598 599 if (is_avc) { 600 status_t err = makeAVCCodecSpecificData( 601 (const uint8_t *)buffer->data() 602 + buffer->range_offset(), 603 buffer->range_length()); 604 CHECK_EQ(OK, err); 605 } else if (is_mpeg4) { 606 mCodecSpecificDataSize = buffer->range_length(); 607 mCodecSpecificData = malloc(mCodecSpecificDataSize); 608 memcpy(mCodecSpecificData, 609 (const uint8_t *)buffer->data() 610 + buffer->range_offset(), 611 buffer->range_length()); 612 } 613 614 buffer->release(); 615 buffer = NULL; 616 617 mGotAllCodecSpecificData = true; 618 continue; 619 } else if (!mGotAllCodecSpecificData && 620 count == 1 && is_mpeg4 && mCodecSpecificData == NULL) { 621 // The TI mpeg4 encoder does not properly set the 622 // codec-specific-data flag. 623 624 const uint8_t *data = 625 (const uint8_t *)buffer->data() + buffer->range_offset(); 626 627 const size_t size = buffer->range_length(); 628 629 size_t offset = 0; 630 while (offset + 3 < size) { 631 if (data[offset] == 0x00 && data[offset + 1] == 0x00 632 && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) { 633 break; 634 } 635 636 ++offset; 637 } 638 639 // CHECK(offset + 3 < size); 640 if (offset + 3 >= size) { 641 // XXX assume the entire first chunk of data is the codec specific 642 // data. 643 offset = size; 644 } 645 646 mCodecSpecificDataSize = offset; 647 mCodecSpecificData = malloc(offset); 648 memcpy(mCodecSpecificData, data, offset); 649 650 buffer->set_range(buffer->range_offset() + offset, size - offset); 651 652 if (size == offset) { 653 buffer->release(); 654 buffer = NULL; 655 656 continue; 657 } 658 659 mGotAllCodecSpecificData = true; 660 } else if (!mGotAllCodecSpecificData && is_avc && count < 3) { 661 // The TI video encoder does not flag codec specific data 662 // as such and also splits up SPS and PPS across two buffers. 663 664 const uint8_t *data = 665 (const uint8_t *)buffer->data() + buffer->range_offset(); 666 667 size_t size = buffer->range_length(); 668 669 CHECK(count == 2 || mCodecSpecificData == NULL); 670 671 size_t offset = mCodecSpecificDataSize; 672 mCodecSpecificDataSize += size + 4; 673 mCodecSpecificData = 674 realloc(mCodecSpecificData, mCodecSpecificDataSize); 675 676 memcpy((uint8_t *)mCodecSpecificData + offset, 677 "\x00\x00\x00\x01", 4); 678 679 memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size); 680 681 buffer->release(); 682 buffer = NULL; 683 684 if (count == 2) { 685 void *tmp = mCodecSpecificData; 686 size = mCodecSpecificDataSize; 687 mCodecSpecificData = NULL; 688 mCodecSpecificDataSize = 0; 689 690 status_t err = makeAVCCodecSpecificData( 691 (const uint8_t *)tmp, size); 692 free(tmp); 693 tmp = NULL; 694 CHECK_EQ(OK, err); 695 696 mGotAllCodecSpecificData = true; 697 } 698 699 continue; 700 } 701 702 SampleInfo info; 703 info.size = is_avc 704#if USE_NALLEN_FOUR 705 ? buffer->range_length() + 4 706#else 707 ? buffer->range_length() + 2 708#endif 709 : buffer->range_length(); 710 711 bool is_audio = !strncasecmp(mime, "audio/", 6); 712 713 int64_t timestampUs; 714 CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs)); 715 716 if (timestampUs > mMaxTimeStampUs) { 717 mMaxTimeStampUs = timestampUs; 718 } 719 720 // Our timestamp is in ms. 721 info.timestamp = (timestampUs + 500) / 1000; 722 mSampleInfos.push_back(info); 723 if (mSampleInfos.size() > 2) { 724 if (lastDuration != info.timestamp - lastTimestamp) { 725 SttsTableEntry sttsEntry(sampleCount, lastDuration); 726 mSttsTableEntries.push_back(sttsEntry); 727 sampleCount = 1; 728 } else { 729 ++sampleCount; 730 } 731 } 732 if (mSamplesHaveSameSize) { 733 if (mSampleInfos.size() >= 2 && previousSampleSize != info.size) { 734 mSamplesHaveSameSize = false; 735 } 736 previousSampleSize = info.size; 737 } 738 lastDuration = info.timestamp - lastTimestamp; 739 lastTimestamp = info.timestamp; 740 741//////////////////////////////////////////////////////////////////////////////// 742 // Make a deep copy of the MediaBuffer less Metadata 743 MediaBuffer *copy = new MediaBuffer(buffer->range_length()); 744 memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), 745 buffer->range_length()); 746 copy->set_range(0, buffer->range_length()); 747 748 mChunkSamples.push_back(copy); 749 if (interleaveDurationUs == 0) { 750 StscTableEntry stscEntry(++nChunks, 1, 1); 751 mStscTableEntries.push_back(stscEntry); 752 writeOneChunk(is_avc); 753 } else { 754 if (chunkTimestampUs == 0) { 755 chunkTimestampUs = timestampUs; 756 } else { 757 if (timestampUs - chunkTimestampUs > interleaveDurationUs) { 758 ++nChunks; 759 if (nChunks == 1 || // First chunk 760 (--(mStscTableEntries.end()))->samplesPerChunk != 761 mChunkSamples.size()) { 762 StscTableEntry stscEntry(nChunks, 763 mChunkSamples.size(), 1); 764 mStscTableEntries.push_back(stscEntry); 765 } 766 writeOneChunk(is_avc); 767 chunkTimestampUs = timestampUs; 768 } 769 } 770 } 771 772 int32_t isSync = false; 773 if (buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync) && 774 isSync != 0) { 775 mStssTableEntries.push_back(mSampleInfos.size()); 776 } 777 778 buffer->release(); 779 buffer = NULL; 780 } 781 782 CHECK(!mSampleInfos.empty()); 783 784 // Last chunk 785 if (!mChunkSamples.empty()) { 786 ++nChunks; 787 StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1); 788 mStscTableEntries.push_back(stscEntry); 789 writeOneChunk(is_avc); 790 } 791 792 // We don't really know how long the last frame lasts, since 793 // there is no frame time after it, just repeat the previous 794 // frame's duration. 795 if (mSampleInfos.size() == 1) { 796 lastDuration = 0; // A single sample's duration 797 } else { 798 ++sampleCount; // Count for the last sample 799 } 800 SttsTableEntry sttsEntry(sampleCount, lastDuration); 801 mSttsTableEntries.push_back(sttsEntry); 802 mReachedEOS = true; 803 LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames", 804 count, nZeroLengthFrames, mSampleInfos.size()); 805} 806 807void MPEG4Writer::Track::writeOneChunk(bool isAvc) { 808 mOwner->lock(); 809 for (List<MediaBuffer *>::iterator it = mChunkSamples.begin(); 810 it != mChunkSamples.end(); ++it) { 811 off_t offset = isAvc? mOwner->addLengthPrefixedSample_l(*it) 812 : mOwner->addSample_l(*it); 813 if (it == mChunkSamples.begin()) { 814 mChunkOffsets.push_back(offset); 815 } 816 } 817 mOwner->unlock(); 818 while (!mChunkSamples.empty()) { 819 List<MediaBuffer *>::iterator it = mChunkSamples.begin(); 820 (*it)->release(); 821 (*it) = NULL; 822 mChunkSamples.erase(it); 823 } 824 mChunkSamples.clear(); 825} 826 827int64_t MPEG4Writer::Track::getDurationUs() const { 828 return mMaxTimeStampUs; 829} 830 831void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { 832 const char *mime; 833 bool success = mMeta->findCString(kKeyMIMEType, &mime); 834 CHECK(success); 835 836 bool is_audio = !strncasecmp(mime, "audio/", 6); 837 838 time_t now = time(NULL); 839 840 mOwner->beginBox("trak"); 841 842 mOwner->beginBox("tkhd"); 843 mOwner->writeInt32(0); // version=0, flags=0 844 mOwner->writeInt32(now); // creation time 845 mOwner->writeInt32(now); // modification time 846 mOwner->writeInt32(trackID); 847 mOwner->writeInt32(0); // reserved 848 mOwner->writeInt32(getDurationUs() / 1000); 849 mOwner->writeInt32(0); // reserved 850 mOwner->writeInt32(0); // reserved 851 mOwner->writeInt16(0); // layer 852 mOwner->writeInt16(0); // alternate group 853 mOwner->writeInt16(is_audio ? 0x100 : 0); // volume 854 mOwner->writeInt16(0); // reserved 855 856 mOwner->writeInt32(0x10000); // matrix 857 mOwner->writeInt32(0); 858 mOwner->writeInt32(0); 859 mOwner->writeInt32(0); 860 mOwner->writeInt32(0x10000); 861 mOwner->writeInt32(0); 862 mOwner->writeInt32(0); 863 mOwner->writeInt32(0); 864 mOwner->writeInt32(0x40000000); 865 866 if (is_audio) { 867 mOwner->writeInt32(0); 868 mOwner->writeInt32(0); 869 } else { 870 int32_t width, height; 871 bool success = mMeta->findInt32(kKeyWidth, &width); 872 success = success && mMeta->findInt32(kKeyHeight, &height); 873 CHECK(success); 874 875 mOwner->writeInt32(width << 16); // 32-bit fixed-point value 876 mOwner->writeInt32(height << 16); // 32-bit fixed-point value 877 } 878 mOwner->endBox(); // tkhd 879 880 mOwner->beginBox("mdia"); 881 882 mOwner->beginBox("mdhd"); 883 mOwner->writeInt32(0); // version=0, flags=0 884 mOwner->writeInt32(now); // creation time 885 mOwner->writeInt32(now); // modification time 886 mOwner->writeInt32(1000); // timescale 887 mOwner->writeInt32(getDurationUs() / 1000); 888 mOwner->writeInt16(0); // language code XXX 889 mOwner->writeInt16(0); // predefined 890 mOwner->endBox(); 891 892 mOwner->beginBox("hdlr"); 893 mOwner->writeInt32(0); // version=0, flags=0 894 mOwner->writeInt32(0); // component type: should be mhlr 895 mOwner->writeFourcc(is_audio ? "soun" : "vide"); // component subtype 896 mOwner->writeInt32(0); // reserved 897 mOwner->writeInt32(0); // reserved 898 mOwner->writeInt32(0); // reserved 899 mOwner->writeCString("SoundHandler"); // name 900 mOwner->endBox(); 901 902 mOwner->beginBox("minf"); 903 if (is_audio) { 904 mOwner->beginBox("smhd"); 905 mOwner->writeInt32(0); // version=0, flags=0 906 mOwner->writeInt16(0); // balance 907 mOwner->writeInt16(0); // reserved 908 mOwner->endBox(); 909 } else { 910 mOwner->beginBox("vmhd"); 911 mOwner->writeInt32(0x00000001); // version=0, flags=1 912 mOwner->writeInt16(0); // graphics mode 913 mOwner->writeInt16(0); // opcolor 914 mOwner->writeInt16(0); 915 mOwner->writeInt16(0); 916 mOwner->endBox(); 917 } 918 919 mOwner->beginBox("dinf"); 920 mOwner->beginBox("dref"); 921 mOwner->writeInt32(0); // version=0, flags=0 922 mOwner->writeInt32(1); 923 mOwner->beginBox("url "); 924 mOwner->writeInt32(1); // version=0, flags=1 925 mOwner->endBox(); // url 926 mOwner->endBox(); // dref 927 mOwner->endBox(); // dinf 928 929 mOwner->endBox(); // minf 930 931 mOwner->beginBox("stbl"); 932 933 mOwner->beginBox("stsd"); 934 mOwner->writeInt32(0); // version=0, flags=0 935 mOwner->writeInt32(1); // entry count 936 if (is_audio) { 937 const char *fourcc = NULL; 938 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) { 939 fourcc = "samr"; 940 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { 941 fourcc = "sawb"; 942 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 943 fourcc = "mp4a"; 944 } else { 945 LOGE("Unknown mime type '%s'.", mime); 946 CHECK(!"should not be here, unknown mime type."); 947 } 948 949 mOwner->beginBox(fourcc); // audio format 950 mOwner->writeInt32(0); // reserved 951 mOwner->writeInt16(0); // reserved 952 mOwner->writeInt16(0x1); // data ref index 953 mOwner->writeInt32(0); // reserved 954 mOwner->writeInt32(0); // reserved 955 int32_t nChannels; 956 CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels)); 957 mOwner->writeInt16(nChannels); // channel count 958 mOwner->writeInt16(16); // sample size 959 mOwner->writeInt16(0); // predefined 960 mOwner->writeInt16(0); // reserved 961 962 int32_t samplerate; 963 bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 964 CHECK(success); 965 966 mOwner->writeInt32(samplerate << 16); 967 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) { 968 mOwner->beginBox("esds"); 969 970 mOwner->writeInt32(0); // version=0, flags=0 971 mOwner->writeInt8(0x03); // ES_DescrTag 972 mOwner->writeInt8(23 + mCodecSpecificDataSize); 973 mOwner->writeInt16(0x0000);// ES_ID 974 mOwner->writeInt8(0x00); 975 976 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 977 mOwner->writeInt8(15 + mCodecSpecificDataSize); 978 mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2 979 mOwner->writeInt8(0x15); // streamType AudioStream 980 981 mOwner->writeInt16(0x03); // XXX 982 mOwner->writeInt8(0x00); // buffer size 24-bit 983 mOwner->writeInt32(96000); // max bit rate 984 mOwner->writeInt32(96000); // avg bit rate 985 986 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 987 mOwner->writeInt8(mCodecSpecificDataSize); 988 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 989 990 static const uint8_t kData2[] = { 991 0x06, // SLConfigDescriptorTag 992 0x01, 993 0x02 994 }; 995 mOwner->write(kData2, sizeof(kData2)); 996 997 mOwner->endBox(); // esds 998 } 999 mOwner->endBox(); 1000 } else { 1001 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 1002 mOwner->beginBox("mp4v"); 1003 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 1004 mOwner->beginBox("s263"); 1005 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 1006 mOwner->beginBox("avc1"); 1007 } else { 1008 LOGE("Unknown mime type '%s'.", mime); 1009 CHECK(!"should not be here, unknown mime type."); 1010 } 1011 1012 mOwner->writeInt32(0); // reserved 1013 mOwner->writeInt16(0); // reserved 1014 mOwner->writeInt16(0); // data ref index 1015 mOwner->writeInt16(0); // predefined 1016 mOwner->writeInt16(0); // reserved 1017 mOwner->writeInt32(0); // predefined 1018 mOwner->writeInt32(0); // predefined 1019 mOwner->writeInt32(0); // predefined 1020 1021 int32_t width, height; 1022 bool success = mMeta->findInt32(kKeyWidth, &width); 1023 success = success && mMeta->findInt32(kKeyHeight, &height); 1024 CHECK(success); 1025 1026 mOwner->writeInt16(width); 1027 mOwner->writeInt16(height); 1028 mOwner->writeInt32(0x480000); // horiz resolution 1029 mOwner->writeInt32(0x480000); // vert resolution 1030 mOwner->writeInt32(0); // reserved 1031 mOwner->writeInt16(1); // frame count 1032 mOwner->write(" ", 32); 1033 mOwner->writeInt16(0x18); // depth 1034 mOwner->writeInt16(-1); // predefined 1035 1036 CHECK(23 + mCodecSpecificDataSize < 128); 1037 1038 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { 1039 mOwner->beginBox("esds"); 1040 1041 mOwner->writeInt32(0); // version=0, flags=0 1042 1043 mOwner->writeInt8(0x03); // ES_DescrTag 1044 mOwner->writeInt8(23 + mCodecSpecificDataSize); 1045 mOwner->writeInt16(0x0000); // ES_ID 1046 mOwner->writeInt8(0x1f); 1047 1048 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 1049 mOwner->writeInt8(15 + mCodecSpecificDataSize); 1050 mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 1051 mOwner->writeInt8(0x11); // streamType VisualStream 1052 1053 static const uint8_t kData[] = { 1054 0x01, 0x77, 0x00, 1055 0x00, 0x03, 0xe8, 0x00, 1056 0x00, 0x03, 0xe8, 0x00 1057 }; 1058 mOwner->write(kData, sizeof(kData)); 1059 1060 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 1061 1062 mOwner->writeInt8(mCodecSpecificDataSize); 1063 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 1064 1065 static const uint8_t kData2[] = { 1066 0x06, // SLConfigDescriptorTag 1067 0x01, 1068 0x02 1069 }; 1070 mOwner->write(kData2, sizeof(kData2)); 1071 1072 mOwner->endBox(); // esds 1073 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { 1074 mOwner->beginBox("d263"); 1075 1076 mOwner->writeInt32(0); // vendor 1077 mOwner->writeInt8(0); // decoder version 1078 mOwner->writeInt8(10); // level: 10 1079 mOwner->writeInt8(0); // profile: 0 1080 1081 mOwner->endBox(); // d263 1082 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { 1083 mOwner->beginBox("avcC"); 1084 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 1085 mOwner->endBox(); // avcC 1086 } 1087 1088 mOwner->endBox(); // mp4v, s263 or avc1 1089 } 1090 mOwner->endBox(); // stsd 1091 1092 mOwner->beginBox("stts"); 1093 mOwner->writeInt32(0); // version=0, flags=0 1094 mOwner->writeInt32(mSttsTableEntries.size()); 1095 for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); 1096 it != mSttsTableEntries.end(); ++it) { 1097 mOwner->writeInt32(it->sampleCount); 1098 mOwner->writeInt32(it->sampleDuration); 1099 } 1100 mOwner->endBox(); // stts 1101 1102 if (!is_audio) { 1103 mOwner->beginBox("stss"); 1104 mOwner->writeInt32(0); // version=0, flags=0 1105 mOwner->writeInt32(mStssTableEntries.size()); // number of sync frames 1106 for (List<int32_t>::iterator it = mStssTableEntries.begin(); 1107 it != mStssTableEntries.end(); ++it) { 1108 mOwner->writeInt32(*it); 1109 } 1110 mOwner->endBox(); // stss 1111 } 1112 1113 mOwner->beginBox("stsz"); 1114 mOwner->writeInt32(0); // version=0, flags=0 1115 if (mSamplesHaveSameSize) { 1116 List<SampleInfo>::iterator it = mSampleInfos.begin(); 1117 mOwner->writeInt32(it->size); // default sample size 1118 } else { 1119 mOwner->writeInt32(0); 1120 } 1121 mOwner->writeInt32(mSampleInfos.size()); 1122 if (!mSamplesHaveSameSize) { 1123 for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 1124 it != mSampleInfos.end(); ++it) { 1125 mOwner->writeInt32((*it).size); 1126 } 1127 } 1128 mOwner->endBox(); // stsz 1129 1130 mOwner->beginBox("stsc"); 1131 mOwner->writeInt32(0); // version=0, flags=0 1132 mOwner->writeInt32(mStscTableEntries.size()); 1133 for (List<StscTableEntry>::iterator it = mStscTableEntries.begin(); 1134 it != mStscTableEntries.end(); ++it) { 1135 mOwner->writeInt32(it->firstChunk); 1136 mOwner->writeInt32(it->samplesPerChunk); 1137 mOwner->writeInt32(it->sampleDescriptionId); 1138 } 1139 mOwner->endBox(); // stsc 1140 1141 mOwner->beginBox("co64"); 1142 mOwner->writeInt32(0); // version=0, flags=0 1143 mOwner->writeInt32(mChunkOffsets.size()); 1144 for (List<off_t>::iterator it = mChunkOffsets.begin(); 1145 it != mChunkOffsets.end(); ++it) { 1146 mOwner->writeInt64((*it)); 1147 } 1148 mOwner->endBox(); // co64 1149 1150 mOwner->endBox(); // stbl 1151 mOwner->endBox(); // mdia 1152 mOwner->endBox(); // trak 1153} 1154 1155} // namespace android 1156