MPEG4Writer.cpp revision 20111aa043c5f404472bc63b90bc5aad906b1101
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#undef NDEBUG 20#include <assert.h> 21 22#include <ctype.h> 23#include <pthread.h> 24 25#include <media/stagefright/MPEG4Writer.h> 26#include <media/stagefright/MediaBuffer.h> 27#include <media/stagefright/MetaData.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<MetaData> &meta, MediaSource *source); 36 ~Track(); 37 38 void start(); 39 void stop(); 40 41 int64_t getDuration() const; 42 void writeTrackHeader(int32_t trackID); 43 44private: 45 MPEG4Writer *mOwner; 46 sp<MetaData> mMeta; 47 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 static void *ThreadWrapper(void *me); 63 void threadEntry(); 64 65 Track(const Track &); 66 Track &operator=(const Track &); 67}; 68 69MPEG4Writer::MPEG4Writer(const char *filename) 70 : mFile(fopen(filename, "wb")), 71 mOffset(0), 72 mMdatOffset(0) { 73 assert(mFile != NULL); 74} 75 76MPEG4Writer::~MPEG4Writer() { 77 stop(); 78 79 for (List<Track *>::iterator it = mTracks.begin(); 80 it != mTracks.end(); ++it) { 81 delete *it; 82 } 83 mTracks.clear(); 84} 85 86void MPEG4Writer::addSource(const sp<MetaData> &meta, 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 assert(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 assert(strlen(fourcc) == 4); 195 196 mBoxes.push_back(mOffset); 197 198 writeInt32(0); 199 writeFourcc(fourcc); 200} 201 202void MPEG4Writer::endBox() { 203 assert(!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 assert(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, const sp<MetaData> &meta, MediaSource *source) 259 : mOwner(owner), 260 mMeta(meta), 261 mSource(source), 262 mDone(false), 263 mCodecSpecificData(NULL), 264 mCodecSpecificDataSize(0) { 265} 266 267MPEG4Writer::Track::~Track() { 268 stop(); 269 270 if (mCodecSpecificData != NULL) { 271 free(mCodecSpecificData); 272 mCodecSpecificData = NULL; 273 } 274} 275 276void MPEG4Writer::Track::start() { 277 mSource->start(); 278 279 pthread_attr_t attr; 280 pthread_attr_init(&attr); 281 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 282 283 mDone = false; 284 285 int err = pthread_create(&mThread, &attr, ThreadWrapper, this); 286 assert(err == 0); 287 288 pthread_attr_destroy(&attr); 289} 290 291void MPEG4Writer::Track::stop() { 292 if (mDone) { 293 return; 294 } 295 296 mDone = true; 297 298 void *dummy; 299 pthread_join(mThread, &dummy); 300 301 mSource->stop(); 302} 303 304// static 305void *MPEG4Writer::Track::ThreadWrapper(void *me) { 306 Track *track = static_cast<Track *>(me); 307 308 track->threadEntry(); 309 310 return NULL; 311} 312 313void MPEG4Writer::Track::threadEntry() { 314 bool is_mpeg4 = false; 315 sp<MetaData> meta = mSource->getFormat(); 316 const char *mime; 317 meta->findCString(kKeyMIMEType, &mime); 318 is_mpeg4 = !strcasecmp(mime, "video/mp4v-es"); 319 320 MediaBuffer *buffer; 321 while (!mDone && mSource->read(&buffer) == OK) { 322 if (buffer->range_length() == 0) { 323 buffer->release(); 324 buffer = NULL; 325 326 continue; 327 } 328 329 if (mCodecSpecificData == NULL && is_mpeg4) { 330 const uint8_t *data = 331 (const uint8_t *)buffer->data() + buffer->range_offset(); 332 333 const size_t size = buffer->range_length(); 334 335 size_t offset = 0; 336 while (offset + 3 < size) { 337 if (data[offset] == 0x00 && data[offset + 1] == 0x00 338 && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) { 339 break; 340 } 341 342 ++offset; 343 } 344 345 assert(offset + 3 < size); 346 347 mCodecSpecificDataSize = offset; 348 mCodecSpecificData = malloc(offset); 349 memcpy(mCodecSpecificData, data, offset); 350 351 buffer->set_range(buffer->range_offset() + offset, size - offset); 352 } 353 354 off_t offset = mOwner->addSample(buffer); 355 356 SampleInfo info; 357 info.size = buffer->range_length(); 358 info.offset = offset; 359 360 int32_t units, scale; 361 bool success = 362 buffer->meta_data()->findInt32(kKeyTimeUnits, &units); 363 assert(success); 364 success = 365 buffer->meta_data()->findInt32(kKeyTimeScale, &scale); 366 assert(success); 367 368 info.timestamp = (int64_t)units * 1000 / scale; 369 370 mSampleInfos.push_back(info); 371 372 buffer->release(); 373 buffer = NULL; 374 } 375} 376 377int64_t MPEG4Writer::Track::getDuration() const { 378 return 10000; // XXX 379} 380 381void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { 382 const char *mime; 383 bool success = mMeta->findCString(kKeyMIMEType, &mime); 384 assert(success); 385 386 bool is_audio = !strncasecmp(mime, "audio/", 6); 387 388 time_t now = time(NULL); 389 390 mOwner->beginBox("trak"); 391 392 mOwner->beginBox("tkhd"); 393 mOwner->writeInt32(0); // version=0, flags=0 394 mOwner->writeInt32(now); // creation time 395 mOwner->writeInt32(now); // modification time 396 mOwner->writeInt32(trackID); 397 mOwner->writeInt32(0); // reserved 398 mOwner->writeInt32(getDuration()); 399 mOwner->writeInt32(0); // reserved 400 mOwner->writeInt32(0); // reserved 401 mOwner->writeInt16(0); // layer 402 mOwner->writeInt16(0); // alternate group 403 mOwner->writeInt16(is_audio ? 0x100 : 0); // volume 404 mOwner->writeInt16(0); // reserved 405 406 mOwner->writeInt32(0x10000); // matrix 407 mOwner->writeInt32(0); 408 mOwner->writeInt32(0); 409 mOwner->writeInt32(0); 410 mOwner->writeInt32(0x10000); 411 mOwner->writeInt32(0); 412 mOwner->writeInt32(0); 413 mOwner->writeInt32(0); 414 mOwner->writeInt32(0x40000000); 415 416 if (is_audio) { 417 mOwner->writeInt32(0); 418 mOwner->writeInt32(0); 419 } else { 420 int32_t width, height; 421 bool success = mMeta->findInt32(kKeyWidth, &width); 422 success = success && mMeta->findInt32(kKeyHeight, &height); 423 assert(success); 424 425 mOwner->writeInt32(width); 426 mOwner->writeInt32(height); 427 } 428 mOwner->endBox(); // tkhd 429 430 mOwner->beginBox("mdia"); 431 432 mOwner->beginBox("mdhd"); 433 mOwner->writeInt32(0); // version=0, flags=0 434 mOwner->writeInt32(now); // creation time 435 mOwner->writeInt32(now); // modification time 436 mOwner->writeInt32(1000); // timescale 437 mOwner->writeInt32(getDuration()); 438 mOwner->writeInt16(0); // language code XXX 439 mOwner->writeInt16(0); // predefined 440 mOwner->endBox(); 441 442 mOwner->beginBox("hdlr"); 443 mOwner->writeInt32(0); // version=0, flags=0 444 mOwner->writeInt32(0); // predefined 445 mOwner->writeFourcc(is_audio ? "soun" : "vide"); 446 mOwner->writeInt32(0); // reserved 447 mOwner->writeInt32(0); // reserved 448 mOwner->writeInt32(0); // reserved 449 mOwner->writeCString(""); // name 450 mOwner->endBox(); 451 452 mOwner->beginBox("minf"); 453 454 mOwner->beginBox("dinf"); 455 mOwner->beginBox("dref"); 456 mOwner->writeInt32(0); // version=0, flags=0 457 mOwner->writeInt32(1); 458 mOwner->beginBox("url "); 459 mOwner->writeInt32(1); // version=0, flags=1 460 mOwner->endBox(); // url 461 mOwner->endBox(); // dref 462 mOwner->endBox(); // dinf 463 464 if (is_audio) { 465 mOwner->beginBox("smhd"); 466 mOwner->writeInt32(0); // version=0, flags=0 467 mOwner->writeInt16(0); // balance 468 mOwner->writeInt16(0); // reserved 469 mOwner->endBox(); 470 } else { 471 mOwner->beginBox("vmhd"); 472 mOwner->writeInt32(0x00000001); // version=0, flags=1 473 mOwner->writeInt16(0); // graphics mode 474 mOwner->writeInt16(0); // opcolor 475 mOwner->writeInt16(0); 476 mOwner->writeInt16(0); 477 mOwner->endBox(); 478 } 479 mOwner->endBox(); // minf 480 481 mOwner->beginBox("stbl"); 482 483 mOwner->beginBox("stsd"); 484 mOwner->writeInt32(0); // version=0, flags=0 485 mOwner->writeInt32(1); // entry count 486 if (is_audio) { 487 mOwner->beginBox("xxxx"); // audio format XXX 488 mOwner->writeInt32(0); // reserved 489 mOwner->writeInt16(0); // reserved 490 mOwner->writeInt16(0); // data ref index 491 mOwner->writeInt32(0); // reserved 492 mOwner->writeInt32(0); // reserved 493 mOwner->writeInt16(2); // channel count 494 mOwner->writeInt16(16); // sample size 495 mOwner->writeInt16(0); // predefined 496 mOwner->writeInt16(0); // reserved 497 498 int32_t samplerate; 499 bool success = mMeta->findInt32(kKeySampleRate, &samplerate); 500 assert(success); 501 502 mOwner->writeInt32(samplerate << 16); 503 mOwner->endBox(); 504 } else { 505 if (!strcasecmp("video/mp4v-es", mime)) { 506 mOwner->beginBox("mp4v"); 507 } else if (!strcasecmp("video/3gpp", mime)) { 508 mOwner->beginBox("s263"); 509 } else { 510 assert(!"should not be here, unknown mime type."); 511 } 512 513 mOwner->writeInt32(0); // reserved 514 mOwner->writeInt16(0); // reserved 515 mOwner->writeInt16(0); // data ref index 516 mOwner->writeInt16(0); // predefined 517 mOwner->writeInt16(0); // reserved 518 mOwner->writeInt32(0); // predefined 519 mOwner->writeInt32(0); // predefined 520 mOwner->writeInt32(0); // predefined 521 522 int32_t width, height; 523 bool success = mMeta->findInt32(kKeyWidth, &width); 524 success = success && mMeta->findInt32(kKeyHeight, &height); 525 assert(success); 526 527 mOwner->writeInt16(width); 528 mOwner->writeInt16(height); 529 mOwner->writeInt32(0x480000); // horiz resolution 530 mOwner->writeInt32(0x480000); // vert resolution 531 mOwner->writeInt32(0); // reserved 532 mOwner->writeInt16(1); // frame count 533 mOwner->write(" ", 32); 534 mOwner->writeInt16(0x18); // depth 535 mOwner->writeInt16(-1); // predefined 536 537 assert(23 + mCodecSpecificDataSize < 128); 538 539 if (!strcasecmp("video/mp4v-es", mime)) { 540 mOwner->beginBox("esds"); 541 542 mOwner->writeInt32(0); // version=0, flags=0 543 544 mOwner->writeInt8(0x03); // ES_DescrTag 545 mOwner->writeInt8(23 + mCodecSpecificDataSize); 546 mOwner->writeInt16(0x0000); // ES_ID 547 mOwner->writeInt8(0x1f); 548 549 mOwner->writeInt8(0x04); // DecoderConfigDescrTag 550 mOwner->writeInt8(15 + mCodecSpecificDataSize); 551 mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2 552 mOwner->writeInt8(0x11); // streamType VisualStream 553 554 static const uint8_t kData[] = { 555 0x01, 0x77, 0x00, 556 0x00, 0x03, 0xe8, 0x00, 557 0x00, 0x03, 0xe8, 0x00 558 }; 559 mOwner->write(kData, sizeof(kData)); 560 561 mOwner->writeInt8(0x05); // DecoderSpecificInfoTag 562 563 mOwner->writeInt8(mCodecSpecificDataSize); 564 mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); 565 566 static const uint8_t kData2[] = { 567 0x06, // SLConfigDescriptorTag 568 0x01, 569 0x02 570 }; 571 mOwner->write(kData2, sizeof(kData2)); 572 573 mOwner->endBox(); // esds 574 } else if (!strcasecmp("video/3gpp", mime)) { 575 mOwner->beginBox("d263"); 576 577 mOwner->writeInt32(0); // vendor 578 mOwner->writeInt8(0); // decoder version 579 mOwner->writeInt8(10); // level: 10 580 mOwner->writeInt8(0); // profile: 0 581 582 mOwner->endBox(); // d263 583 } 584 mOwner->endBox(); // mp4v or s263 585 } 586 mOwner->endBox(); // stsd 587 588 mOwner->beginBox("stts"); 589 mOwner->writeInt32(0); // version=0, flags=0 590 mOwner->writeInt32(mSampleInfos.size() - 1); 591 592 List<SampleInfo>::iterator it = mSampleInfos.begin(); 593 int64_t last = (*it).timestamp; 594 ++it; 595 while (it != mSampleInfos.end()) { 596 mOwner->writeInt32(1); 597 mOwner->writeInt32((*it).timestamp - last); 598 599 last = (*it).timestamp; 600 601 ++it; 602 } 603 mOwner->endBox(); // stts 604 605 mOwner->beginBox("stsz"); 606 mOwner->writeInt32(0); // version=0, flags=0 607 mOwner->writeInt32(0); // default sample size 608 mOwner->writeInt32(mSampleInfos.size()); 609 for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 610 it != mSampleInfos.end(); ++it) { 611 mOwner->writeInt32((*it).size); 612 } 613 mOwner->endBox(); // stsz 614 615 mOwner->beginBox("stsc"); 616 mOwner->writeInt32(0); // version=0, flags=0 617 mOwner->writeInt32(mSampleInfos.size()); 618 int32_t n = 1; 619 for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 620 it != mSampleInfos.end(); ++it, ++n) { 621 mOwner->writeInt32(n); 622 mOwner->writeInt32(1); 623 mOwner->writeInt32(1); 624 } 625 mOwner->endBox(); // stsc 626 627 mOwner->beginBox("co64"); 628 mOwner->writeInt32(0); // version=0, flags=0 629 mOwner->writeInt32(mSampleInfos.size()); 630 for (List<SampleInfo>::iterator it = mSampleInfos.begin(); 631 it != mSampleInfos.end(); ++it, ++n) { 632 mOwner->writeInt64((*it).offset); 633 } 634 mOwner->endBox(); // co64 635 636 mOwner->endBox(); // stbl 637 mOwner->endBox(); // mdia 638 mOwner->endBox(); // trak 639} 640 641} // namespace android 642