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