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