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