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