MPEG4Writer.cpp revision 25b130939339d57789a86fac837a2a8cedbcb7d8
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/MediaSource.h> 27#include <media/stagefright/Utils.h> 28 29namespace android { 30 31class MPEG4Writer::Track { 32public: 33 Track(MPEG4Writer *owner, const sp<MediaSource> &source); 34 ~Track(); 35 36 status_t start(); 37 void stop(); 38 bool reachedEOS(); 39 40 int64_t getDuration() const; 41 void writeTrackHeader(int32_t trackID); 42 43private: 44 MPEG4Writer *mOwner; 45 sp<MetaData> mMeta; 46 sp<MediaSource> mSource; 47 volatile bool mDone; 48 49 pthread_t mThread; 50 51 struct SampleInfo { 52 size_t size; 53 off_t offset; 54 int64_t timestamp; 55 }; 56 List<SampleInfo> mSampleInfos; 57 58 void *mCodecSpecificData; 59 size_t mCodecSpecificDataSize; 60 61 bool mReachedEOS; 62 63 static void *ThreadWrapper(void *me); 64 void threadEntry(); 65 66 Track(const Track &); 67 Track &operator=(const Track &); 68}; 69 70MPEG4Writer::MPEG4Writer(const char *filename) 71 : mFile(fopen(filename, "wb")), 72 mOffset(0), 73 mMdatOffset(0) { 74 CHECK(mFile != NULL); 75} 76 77MPEG4Writer::~MPEG4Writer() { 78 stop(); 79 80 for (List<Track *>::iterator it = mTracks.begin(); 81 it != mTracks.end(); ++it) { 82 delete *it; 83 } 84 mTracks.clear(); 85} 86 87void MPEG4Writer::addSource(const sp<MediaSource> &source) { 88 Track *track = new Track(this, source); 89 mTracks.push_back(track); 90} 91 92status_t MPEG4Writer::start() { 93 if (mFile == NULL) { 94 return UNKNOWN_ERROR; 95 } 96 97 beginBox("ftyp"); 98 writeFourcc("isom"); 99 writeInt32(0); 100 writeFourcc("isom"); 101 endBox(); 102 103 mMdatOffset = mOffset; 104 write("\x00\x00\x00\x01mdat????????", 16); 105 106 for (List<Track *>::iterator it = mTracks.begin(); 107 it != mTracks.end(); ++it) { 108 status_t err = (*it)->start(); 109 110 if (err != OK) { 111 for (List<Track *>::iterator it2 = mTracks.begin(); 112 it2 != it; ++it2) { 113 (*it2)->stop(); 114 } 115 116 return err; 117 } 118 } 119 120 return OK; 121} 122 123void MPEG4Writer::stop() { 124 if (mFile == NULL) { 125 return; 126 } 127 128 int64_t max_duration = 0; 129 for (List<Track *>::iterator it = mTracks.begin(); 130 it != mTracks.end(); ++it) { 131 (*it)->stop(); 132 133 int64_t duration = (*it)->getDuration(); 134 if (duration > max_duration) { 135 max_duration = duration; 136 } 137 } 138 139 // Fix up the size of the 'mdat' chunk. 140 fseek(mFile, mMdatOffset + 8, SEEK_SET); 141 int64_t size = mOffset - mMdatOffset; 142 size = hton64(size); 143 fwrite(&size, 1, 8, mFile); 144 fseek(mFile, mOffset, SEEK_SET); 145 146 time_t now = time(NULL); 147 148 beginBox("moov"); 149 150 beginBox("mvhd"); 151 writeInt32(0); // version=0, flags=0 152 writeInt32(now); // creation time 153 writeInt32(now); // modification time 154 writeInt32(1000); // timescale 155 writeInt32(max_duration); 156 writeInt32(0x10000); // rate 157 writeInt16(0x100); // volume 158 writeInt16(0); // reserved 159 writeInt32(0); // reserved 160 writeInt32(0); // reserved 161 writeInt32(0x10000); // matrix 162 writeInt32(0); 163 writeInt32(0); 164 writeInt32(0); 165 writeInt32(0x10000); 166 writeInt32(0); 167 writeInt32(0); 168 writeInt32(0); 169 writeInt32(0x40000000); 170 writeInt32(0); // predefined 171 writeInt32(0); // predefined 172 writeInt32(0); // predefined 173 writeInt32(0); // predefined 174 writeInt32(0); // predefined 175 writeInt32(0); // predefined 176 writeInt32(mTracks.size() + 1); // nextTrackID 177 endBox(); // mvhd 178 179 int32_t id = 1; 180 for (List<Track *>::iterator it = mTracks.begin(); 181 it != mTracks.end(); ++it, ++id) { 182 (*it)->writeTrackHeader(id); 183 } 184 endBox(); // moov 185 186 CHECK(mBoxes.empty()); 187 188 fclose(mFile); 189 mFile = NULL; 190} 191 192off_t MPEG4Writer::addSample(MediaBuffer *buffer) { 193 Mutex::Autolock autoLock(mLock); 194 195 off_t old_offset = mOffset; 196 197 fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), 198 1, buffer->range_length(), mFile); 199 200 mOffset += buffer->range_length(); 201 202 return old_offset; 203} 204 205void MPEG4Writer::beginBox(const char *fourcc) { 206 CHECK_EQ(strlen(fourcc), 4); 207 208 mBoxes.push_back(mOffset); 209 210 writeInt32(0); 211 writeFourcc(fourcc); 212} 213 214void MPEG4Writer::endBox() { 215 CHECK(!mBoxes.empty()); 216 217 off_t offset = *--mBoxes.end(); 218 mBoxes.erase(--mBoxes.end()); 219 220 fseek(mFile, offset, SEEK_SET); 221 writeInt32(mOffset - offset); 222 mOffset -= 4; 223 fseek(mFile, mOffset, SEEK_SET); 224} 225 226void MPEG4Writer::writeInt8(int8_t x) { 227 fwrite(&x, 1, 1, mFile); 228 ++mOffset; 229} 230 231void MPEG4Writer::writeInt16(int16_t x) { 232 x = htons(x); 233 fwrite(&x, 1, 2, mFile); 234 mOffset += 2; 235} 236 237void MPEG4Writer::writeInt32(int32_t x) { 238 x = htonl(x); 239 fwrite(&x, 1, 4, mFile); 240 mOffset += 4; 241} 242 243void MPEG4Writer::writeInt64(int64_t x) { 244 x = hton64(x); 245 fwrite(&x, 1, 8, mFile); 246 mOffset += 8; 247} 248 249void MPEG4Writer::writeCString(const char *s) { 250 size_t n = strlen(s); 251 252 fwrite(s, 1, n + 1, mFile); 253 mOffset += n + 1; 254} 255 256void MPEG4Writer::writeFourcc(const char *s) { 257 CHECK_EQ(strlen(s), 4); 258 fwrite(s, 1, 4, mFile); 259 mOffset += 4; 260} 261 262void MPEG4Writer::write(const void *data, size_t size) { 263 fwrite(data, 1, size, mFile); 264 mOffset += size; 265} 266 267bool MPEG4Writer::reachedEOS() { 268 bool allDone = true; 269 for (List<Track *>::iterator it = mTracks.begin(); 270 it != mTracks.end(); ++it) { 271 if (!(*it)->reachedEOS()) { 272 allDone = false; 273 break; 274 } 275 } 276 277 return allDone; 278} 279 280//////////////////////////////////////////////////////////////////////////////// 281 282MPEG4Writer::Track::Track( 283 MPEG4Writer *owner, const sp<MediaSource> &source) 284 : mOwner(owner), 285 mMeta(source->getFormat()), 286 mSource(source), 287 mDone(false), 288 mCodecSpecificData(NULL), 289 mCodecSpecificDataSize(0), 290 mReachedEOS(false) { 291} 292 293MPEG4Writer::Track::~Track() { 294 stop(); 295 296 if (mCodecSpecificData != NULL) { 297 free(mCodecSpecificData); 298 mCodecSpecificData = NULL; 299 } 300} 301 302status_t MPEG4Writer::Track::start() { 303 status_t err = mSource->start(); 304 305 if (err != OK) { 306 mDone = mReachedEOS = true; 307 return err; 308 } 309 310 pthread_attr_t attr; 311 pthread_attr_init(&attr); 312 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 313 314 mDone = false; 315 mReachedEOS = false; 316 317 pthread_create(&mThread, &attr, ThreadWrapper, this); 318 pthread_attr_destroy(&attr); 319 320 return OK; 321} 322 323void MPEG4Writer::Track::stop() { 324 if (mDone) { 325 return; 326 } 327 328 mDone = true; 329 330 void *dummy; 331 pthread_join(mThread, &dummy); 332 333 mSource->stop(); 334} 335 336bool MPEG4Writer::Track::reachedEOS() { 337 return mReachedEOS; 338} 339 340// static 341void *MPEG4Writer::Track::ThreadWrapper(void *me) { 342 Track *track = static_cast<Track *>(me); 343 344 track->threadEntry(); 345 346 return NULL; 347} 348 349void MPEG4Writer::Track::threadEntry() { 350 bool is_mpeg4 = false; 351 sp<MetaData> meta = mSource->getFormat(); 352 const char *mime; 353 meta->findCString(kKeyMIMEType, &mime); 354 is_mpeg4 = !strcasecmp(mime, "video/mp4v-es"); 355 356 MediaBuffer *buffer; 357 while (!mDone && mSource->read(&buffer) == OK) { 358 if (buffer->range_length() == 0) { 359 buffer->release(); 360 buffer = NULL; 361 362 continue; 363 } 364 365 if (mCodecSpecificData == NULL && is_mpeg4) { 366 const uint8_t *data = 367 (const uint8_t *)buffer->data() + buffer->range_offset(); 368 369 const size_t size = buffer->range_length(); 370 371 size_t offset = 0; 372 while (offset + 3 < size) { 373 if (data[offset] == 0x00 && data[offset + 1] == 0x00 374 && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) { 375 break; 376 } 377 378 ++offset; 379 } 380 381 // CHECK(offset + 3 < size); 382 if (offset + 3 >= size) { 383 // XXX assume the entire first chunk of data is the codec specific 384 // data. 385 offset = size; 386 } 387 388 mCodecSpecificDataSize = offset; 389 mCodecSpecificData = malloc(offset); 390 memcpy(mCodecSpecificData, data, offset); 391 392 buffer->set_range(buffer->range_offset() + offset, size - offset); 393 } 394 395 off_t offset = mOwner->addSample(buffer); 396 397 SampleInfo info; 398 info.size = buffer->range_length(); 399 info.offset = offset; 400 401 int32_t units, scale; 402 bool success = 403 buffer->meta_data()->findInt32(kKeyTimeUnits, &units); 404 CHECK(success); 405 success = 406 buffer->meta_data()->findInt32(kKeyTimeScale, &scale); 407 CHECK(success); 408 409 info.timestamp = (int64_t)units * 1000 / scale; 410 411 mSampleInfos.push_back(info); 412 413 buffer->release(); 414 buffer = NULL; 415 } 416 417 mReachedEOS = true; 418} 419 420int64_t MPEG4Writer::Track::getDuration() const { 421 return 10000; // XXX 422} 423 424void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { 425 const char *mime; 426 bool success = mMeta->findCString(kKeyMIMEType, &mime); 427 CHECK(success); 428 429 bool is_audio = !strncasecmp(mime, "audio/", 6); 430 431 time_t now = time(NULL); 432 433 mOwner->beginBox("trak"); 434 435 mOwner->beginBox("tkhd"); 436 mOwner->writeInt32(0); // version=0, flags=0 437 mOwner->writeInt32(now); // creation time 438 mOwner->writeInt32(now); // modification time 439 mOwner->writeInt32(trackID); 440 mOwner->writeInt32(0); // reserved 441 mOwner->writeInt32(getDuration()); 442 mOwner->writeInt32(0); // reserved 443 mOwner->writeInt32(0); // reserved 444 mOwner->writeInt16(0); // layer 445 mOwner->writeInt16(0); // alternate group 446 mOwner->writeInt16(is_audio ? 0x100 : 0); // volume 447 mOwner->writeInt16(0); // reserved 448 449 mOwner->writeInt32(0x10000); // matrix 450 mOwner->writeInt32(0); 451 mOwner->writeInt32(0); 452 mOwner->writeInt32(0); 453 mOwner->writeInt32(0x10000); 454 mOwner->writeInt32(0); 455 mOwner->writeInt32(0); 456 mOwner->writeInt32(0); 457 mOwner->writeInt32(0x40000000); 458 459 if (is_audio) { 460 mOwner->writeInt32(0); 461 mOwner->writeInt32(0); 462 } else { 463 int32_t width, height; 464 bool success = mMeta->findInt32(kKeyWidth, &width); 465 success = success && mMeta->findInt32(kKeyHeight, &height); 466 CHECK(success); 467 468 mOwner->writeInt32(width); 469 mOwner->writeInt32(height); 470 } 471 mOwner->endBox(); // tkhd 472 473 mOwner->beginBox("mdia"); 474 475 mOwner->beginBox("mdhd"); 476 mOwner->writeInt32(0); // version=0, flags=0 477 mOwner->writeInt32(now); // creation time 478 mOwner->writeInt32(now); // modification time 479 mOwner->writeInt32(1000); // timescale 480 mOwner->writeInt32(getDuration()); 481 mOwner->writeInt16(0); // language code XXX 482 mOwner->writeInt16(0); // predefined 483 mOwner->endBox(); 484 485 mOwner->beginBox("hdlr"); 486 mOwner->writeInt32(0); // version=0, flags=0 487 mOwner->writeInt32(0); // predefined 488 mOwner->writeFourcc(is_audio ? "soun" : "vide"); 489 mOwner->writeInt32(0); // reserved 490 mOwner->writeInt32(0); // reserved 491 mOwner->writeInt32(0); // reserved 492 mOwner->writeCString(""); // name 493 mOwner->endBox(); 494 495 mOwner->beginBox("minf"); 496 497 mOwner->beginBox("dinf"); 498 mOwner->beginBox("dref"); 499 mOwner->writeInt32(0); // version=0, flags=0 500 mOwner->writeInt32(1); 501 mOwner->beginBox("url "); 502 mOwner->writeInt32(1); // version=0, flags=1 503 mOwner->endBox(); // url 504 mOwner->endBox(); // dref 505 mOwner->endBox(); // dinf 506 507 if (is_audio) { 508 mOwner->beginBox("smhd"); 509 mOwner->writeInt32(0); // version=0, flags=0 510 mOwner->writeInt16(0); // balance 511 mOwner->writeInt16(0); // reserved 512 mOwner->endBox(); 513 } else { 514 mOwner->beginBox("vmhd"); 515 mOwner->writeInt32(0x00000001); // version=0, flags=1 516 mOwner->writeInt16(0); // graphics mode 517 mOwner->writeInt16(0); // opcolor 518 mOwner->writeInt16(0); 519 mOwner->writeInt16(0); 520 mOwner->endBox(); 521 } 522 mOwner->endBox(); // minf 523 524 mOwner->beginBox("stbl"); 525 526 mOwner->beginBox("stsd"); 527 mOwner->writeInt32(0); // version=0, flags=0 528 mOwner->writeInt32(1); // entry count 529 if (is_audio) { 530 const char *fourcc = NULL; 531 if (!strcasecmp("audio/3gpp", mime)) { 532 fourcc = "samr"; 533 } else if (!strcasecmp("audio/amr-wb", mime)) { 534 fourcc = "sawb"; 535 } else { 536 LOGE("Unknown mime type '%s'.", mime); 537 CHECK(!"should not be here, unknown mime type."); 538 } 539 540 mOwner->beginBox(fourcc); // audio format 541 mOwner->writeInt32(0); // reserved 542 mOwner->writeInt16(0); // reserved 543 mOwner->writeInt16(0); // data ref index 544 mOwner->writeInt32(0); // reserved 545 mOwner->writeInt32(0); // reserved 546 mOwner->writeInt16(2); // channel count 547 mOwner->writeInt16(16); // sample size 548 mOwner->writeInt16(0); // predefined 549 mOwner->writeInt16(0); // reserved 550 551 int32_t samplerate; 552 bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 553 CHECK(success); 554 555 mOwner->writeInt32(samplerate << 16); 556 mOwner->endBox(); 557 } else { 558 if (!strcasecmp("video/mp4v-es", mime)) { 559 mOwner->beginBox("mp4v"); 560 } else if (!strcasecmp("video/3gpp", mime)) { 561 mOwner->beginBox("s263"); 562 } else { 563 LOGE("Unknown mime type '%s'.", mime); 564 CHECK(!"should not be here, unknown mime type."); 565 } 566 567 mOwner->writeInt32(0); // reserved 568 mOwner->writeInt16(0); // reserved 569 mOwner->writeInt16(0); // data ref index 570 mOwner->writeInt16(0); // predefined 571 mOwner->writeInt16(0); // reserved 572 mOwner->writeInt32(0); // predefined 573 mOwner->writeInt32(0); // predefined 574 mOwner->writeInt32(0); // predefined 575 576 int32_t width, height; 577 bool success = mMeta->findInt32(kKeyWidth, &width); 578 success = success && mMeta->findInt32(kKeyHeight, &height); 579 CHECK(success); 580 581 mOwner->writeInt16(width); 582 mOwner->writeInt16(height); 583 mOwner->writeInt32(0x480000); // horiz resolution 584 mOwner->writeInt32(0x480000); // vert resolution 585 mOwner->writeInt32(0); // reserved 586 mOwner->writeInt16(1); // frame count 587 mOwner->write(" ", 32); 588 mOwner->writeInt16(0x18); // depth 589 mOwner->writeInt16(-1); // predefined 590 591 CHECK(23 + mCodecSpecificDataSize < 128); 592 593 if (!strcasecmp("video/mp4v-es", mime)) { 594 mOwner->beginBox("esds"); 595 596 mOwner->writeInt32(0); // version=0, flags=0 597 598 mOwner->writeInt8(0x03); // ES_DescrTag 599 mOwner->writeInt8(23 + mCodecSpecificDataSize); 600 mOwner->writeInt16(0x0000); // ES_ID 601 mOwner->writeInt8(0x1f); 602 603 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 604 mOwner->writeInt8(15 + mCodecSpecificDataSize); 605 mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 606 mOwner->writeInt8(0x11); // streamType VisualStream 607 608 static const uint8_t kData[] = { 609 0x01, 0x77, 0x00, 610 0x00, 0x03, 0xe8, 0x00, 611 0x00, 0x03, 0xe8, 0x00 612 }; 613 mOwner->write(kData, sizeof(kData)); 614 615 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 616 617 mOwner->writeInt8(mCodecSpecificDataSize); 618 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 619 620 static const uint8_t kData2[] = { 621 0x06, // SLConfigDescriptorTag 622 0x01, 623 0x02 624 }; 625 mOwner->write(kData2, sizeof(kData2)); 626 627 mOwner->endBox(); // esds 628 } else if (!strcasecmp("video/3gpp", mime)) { 629 mOwner->beginBox("d263"); 630 631 mOwner->writeInt32(0); // vendor 632 mOwner->writeInt8(0); // decoder version 633 mOwner->writeInt8(10); // level: 10 634 mOwner->writeInt8(0); // profile: 0 635 636 mOwner->endBox(); // d263 637 } 638 mOwner->endBox(); // mp4v or s263 639 } 640 mOwner->endBox(); // stsd 641 642 mOwner->beginBox("stts"); 643 mOwner->writeInt32(0); // version=0, flags=0 644 mOwner->writeInt32(mSampleInfos.size() - 1); 645 646 List<SampleInfo>::iterator it = mSampleInfos.begin(); 647 int64_t last = (*it).timestamp; 648 ++it; 649 while (it != mSampleInfos.end()) { 650 mOwner->writeInt32(1); 651 mOwner->writeInt32((*it).timestamp - last); 652 653 last = (*it).timestamp; 654 655 ++it; 656 } 657 mOwner->endBox(); // stts 658 659 mOwner->beginBox("stsz"); 660 mOwner->writeInt32(0); // version=0, flags=0 661 mOwner->writeInt32(0); // default sample size 662 mOwner->writeInt32(mSampleInfos.size()); 663 for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 664 it != mSampleInfos.end(); ++it) { 665 mOwner->writeInt32((*it).size); 666 } 667 mOwner->endBox(); // stsz 668 669 mOwner->beginBox("stsc"); 670 mOwner->writeInt32(0); // version=0, flags=0 671 mOwner->writeInt32(mSampleInfos.size()); 672 int32_t n = 1; 673 for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 674 it != mSampleInfos.end(); ++it, ++n) { 675 mOwner->writeInt32(n); 676 mOwner->writeInt32(1); 677 mOwner->writeInt32(1); 678 } 679 mOwner->endBox(); // stsc 680 681 mOwner->beginBox("co64"); 682 mOwner->writeInt32(0); // version=0, flags=0 683 mOwner->writeInt32(mSampleInfos.size()); 684 for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 685 it != mSampleInfos.end(); ++it, ++n) { 686 mOwner->writeInt64((*it).offset); 687 } 688 mOwner->endBox(); // co64 689 690 mOwner->endBox(); // stbl 691 mOwner->endBox(); // mdia 692 mOwner->endBox(); // trak 693} 694 695} // namespace android 696