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