MPEG2TSWriter.cpp revision 0da4dab0a45a2bc1d95cbc6ef6a4850ed2569584
1/*
2 * Copyright (C) 2010 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//#define LOG_NDEBUG 0
18#define LOG_TAG "MPEG2TSWriter"
19#include <media/stagefright/foundation/ADebug.h>
20
21#include <media/stagefright/foundation/hexdump.h>
22#include <media/stagefright/foundation/ABuffer.h>
23#include <media/stagefright/foundation/AMessage.h>
24#include <media/stagefright/MPEG2TSWriter.h>
25#include <media/stagefright/MediaBuffer.h>
26#include <media/stagefright/MediaDefs.h>
27#include <media/stagefright/MediaErrors.h>
28#include <media/stagefright/MediaSource.h>
29#include <media/stagefright/MetaData.h>
30#include <media/stagefright/Utils.h>
31
32#include "include/ESDS.h"
33
34namespace android {
35
36struct MPEG2TSWriter::SourceInfo : public AHandler {
37    SourceInfo(const sp<MediaSource> &source);
38
39    void start(const sp<AMessage> &notify);
40    void stop();
41
42    unsigned streamType() const;
43    unsigned incrementContinuityCounter();
44
45    enum {
46        kNotifyStartFailed,
47        kNotifyBuffer,
48        kNotifyReachedEOS,
49    };
50
51protected:
52    virtual void onMessageReceived(const sp<AMessage> &msg);
53
54    virtual ~SourceInfo();
55
56private:
57    enum {
58        kWhatStart = 'strt',
59        kWhatRead  = 'read',
60    };
61
62    sp<MediaSource> mSource;
63    sp<ALooper> mLooper;
64    sp<AMessage> mNotify;
65
66    sp<ABuffer> mAACBuffer;
67
68    unsigned mStreamType;
69    unsigned mContinuityCounter;
70
71    void extractCodecSpecificData();
72
73    void appendAACFrames(MediaBuffer *buffer);
74    void flushAACFrames();
75
76    void postAVCFrame(MediaBuffer *buffer);
77
78    DISALLOW_EVIL_CONSTRUCTORS(SourceInfo);
79};
80
81MPEG2TSWriter::SourceInfo::SourceInfo(const sp<MediaSource> &source)
82    : mSource(source),
83      mLooper(new ALooper),
84      mStreamType(0),
85      mContinuityCounter(0) {
86    mLooper->setName("MPEG2TSWriter source");
87
88    sp<MetaData> meta = mSource->getFormat();
89    const char *mime;
90    CHECK(meta->findCString(kKeyMIMEType, &mime));
91
92    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
93        mStreamType = 0x0f;
94    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
95        mStreamType = 0x1b;
96    } else {
97        TRESPASS();
98    }
99}
100
101MPEG2TSWriter::SourceInfo::~SourceInfo() {
102}
103
104unsigned MPEG2TSWriter::SourceInfo::streamType() const {
105    return mStreamType;
106}
107
108unsigned MPEG2TSWriter::SourceInfo::incrementContinuityCounter() {
109    if (++mContinuityCounter == 16) {
110        mContinuityCounter = 0;
111    }
112
113    return mContinuityCounter;
114}
115
116void MPEG2TSWriter::SourceInfo::start(const sp<AMessage> &notify) {
117    mLooper->registerHandler(this);
118    mLooper->start();
119
120    mNotify = notify;
121
122    (new AMessage(kWhatStart, id()))->post();
123}
124
125void MPEG2TSWriter::SourceInfo::stop() {
126    mLooper->unregisterHandler(id());
127    mLooper->stop();
128}
129
130void MPEG2TSWriter::SourceInfo::extractCodecSpecificData() {
131    sp<MetaData> meta = mSource->getFormat();
132
133    const char *mime;
134    CHECK(meta->findCString(kKeyMIMEType, &mime));
135
136    if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
137        return;
138    }
139
140    sp<ABuffer> out = new ABuffer(1024);
141    out->setRange(0, 0);
142
143    uint32_t type;
144    const void *data;
145    size_t size;
146    CHECK(meta->findData(kKeyAVCC, &type, &data, &size));
147
148    const uint8_t *ptr = (const uint8_t *)data;
149
150    size_t numSeqParameterSets = ptr[5] & 31;
151
152    ptr += 6;
153    size -= 6;
154
155    for (size_t i = 0; i < numSeqParameterSets; ++i) {
156        CHECK(size >= 2);
157        size_t length = U16_AT(ptr);
158
159        ptr += 2;
160        size -= 2;
161
162        CHECK(size >= length);
163
164        CHECK_LE(out->size() + 4 + length, out->capacity());
165        memcpy(out->data() + out->size(), "\x00\x00\x00\x01", 4);
166        memcpy(out->data() + out->size() + 4, ptr, length);
167        out->setRange(0, out->size() + length + 4);
168
169        ptr += length;
170        size -= length;
171    }
172
173    CHECK(size >= 1);
174    size_t numPictureParameterSets = *ptr;
175    ++ptr;
176    --size;
177
178    for (size_t i = 0; i < numPictureParameterSets; ++i) {
179        CHECK(size >= 2);
180        size_t length = U16_AT(ptr);
181
182        ptr += 2;
183        size -= 2;
184
185        CHECK(size >= length);
186
187        CHECK_LE(out->size() + 4 + length, out->capacity());
188        memcpy(out->data() + out->size(), "\x00\x00\x00\x01", 4);
189        memcpy(out->data() + out->size() + 4, ptr, length);
190        out->setRange(0, out->size() + length + 4);
191
192        ptr += length;
193        size -= length;
194    }
195
196    out->meta()->setInt64("timeUs", 0ll);
197
198    sp<AMessage> notify = mNotify->dup();
199    notify->setInt32("what", kNotifyBuffer);
200    notify->setObject("buffer", out);
201    notify->post();
202}
203
204void MPEG2TSWriter::SourceInfo::postAVCFrame(MediaBuffer *buffer) {
205    sp<AMessage> notify = mNotify->dup();
206    notify->setInt32("what", kNotifyBuffer);
207
208    sp<ABuffer> copy =
209        new ABuffer(buffer->range_length());
210    memcpy(copy->data(),
211           (const uint8_t *)buffer->data()
212            + buffer->range_offset(),
213           buffer->range_length());
214
215    int64_t timeUs;
216    CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
217    copy->meta()->setInt64("timeUs", timeUs);
218
219    int32_t isSync;
220    if (buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)
221            && isSync != 0) {
222        copy->meta()->setInt32("isSync", true);
223    }
224
225    notify->setObject("buffer", copy);
226    notify->post();
227}
228
229void MPEG2TSWriter::SourceInfo::appendAACFrames(MediaBuffer *buffer) {
230    if (mAACBuffer != NULL
231            && mAACBuffer->size() + 7 + buffer->range_length()
232                    > mAACBuffer->capacity()) {
233        flushAACFrames();
234    }
235
236    if (mAACBuffer == NULL) {
237        size_t alloc = 4096;
238        if (buffer->range_length() + 7 > alloc) {
239            alloc = 7 + buffer->range_length();
240        }
241
242        mAACBuffer = new ABuffer(alloc);
243
244        int64_t timeUs;
245        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
246
247        mAACBuffer->meta()->setInt64("timeUs", timeUs);
248        mAACBuffer->meta()->setInt32("isSync", true);
249
250        mAACBuffer->setRange(0, 0);
251    }
252
253    sp<MetaData> meta = mSource->getFormat();
254    uint32_t type;
255    const void *data;
256    size_t size;
257    CHECK(meta->findData(kKeyESDS, &type, &data, &size));
258
259    ESDS esds((const char *)data, size);
260    CHECK_EQ(esds.InitCheck(), (status_t)OK);
261
262    const uint8_t *codec_specific_data;
263    size_t codec_specific_data_size;
264    esds.getCodecSpecificInfo(
265            (const void **)&codec_specific_data, &codec_specific_data_size);
266
267    CHECK_GE(codec_specific_data_size, 2u);
268
269    unsigned profile = (codec_specific_data[0] >> 3) - 1;
270
271    unsigned sampling_freq_index =
272        ((codec_specific_data[0] & 7) << 1)
273        | (codec_specific_data[1] >> 7);
274
275    unsigned channel_configuration =
276        (codec_specific_data[1] >> 3) & 0x0f;
277
278    uint8_t *ptr = mAACBuffer->data() + mAACBuffer->size();
279
280    const uint32_t aac_frame_length = buffer->range_length() + 7;
281
282    *ptr++ = 0xff;
283    *ptr++ = 0xf1;  // b11110001, ID=0, layer=0, protection_absent=1
284
285    *ptr++ =
286        profile << 6
287        | sampling_freq_index << 2
288        | ((channel_configuration >> 2) & 1);  // private_bit=0
289
290    // original_copy=0, home=0, copyright_id_bit=0, copyright_id_start=0
291    *ptr++ =
292        (channel_configuration & 3) << 6
293        | aac_frame_length >> 11;
294    *ptr++ = (aac_frame_length >> 3) & 0xff;
295    *ptr++ = (aac_frame_length & 7) << 5;
296
297    // adts_buffer_fullness=0, number_of_raw_data_blocks_in_frame=0
298    *ptr++ = 0;
299
300    memcpy(ptr,
301           (const uint8_t *)buffer->data() + buffer->range_offset(),
302           buffer->range_length());
303
304    ptr += buffer->range_length();
305
306    mAACBuffer->setRange(0, ptr - mAACBuffer->data());
307}
308
309void MPEG2TSWriter::SourceInfo::flushAACFrames() {
310    if (mAACBuffer == NULL) {
311        return;
312    }
313
314    sp<AMessage> notify = mNotify->dup();
315    notify->setInt32("what", kNotifyBuffer);
316    notify->setObject("buffer", mAACBuffer);
317    notify->post();
318
319    mAACBuffer.clear();
320}
321
322void MPEG2TSWriter::SourceInfo::onMessageReceived(const sp<AMessage> &msg) {
323    switch (msg->what()) {
324        case kWhatStart:
325        {
326            status_t err = mSource->start();
327            if (err != OK) {
328                sp<AMessage> notify = mNotify->dup();
329                notify->setInt32("what", kNotifyStartFailed);
330                notify->post();
331                break;
332            }
333
334            extractCodecSpecificData();
335
336            (new AMessage(kWhatRead, id()))->post();
337            break;
338        }
339
340        case kWhatRead:
341        {
342            MediaBuffer *buffer;
343            status_t err = mSource->read(&buffer);
344
345            if (err != OK && err != INFO_FORMAT_CHANGED) {
346                if (mStreamType == 0x0f) {
347                    flushAACFrames();
348                }
349
350                sp<AMessage> notify = mNotify->dup();
351                notify->setInt32("what", kNotifyReachedEOS);
352                notify->setInt32("status", err);
353                notify->post();
354                break;
355            }
356
357            if (err == OK) {
358                if (buffer->range_length() > 0) {
359                    if (mStreamType == 0x0f) {
360                        appendAACFrames(buffer);
361                    } else {
362                        postAVCFrame(buffer);
363                    }
364                }
365
366                buffer->release();
367                buffer = NULL;
368            }
369
370            msg->post();
371            break;
372        }
373
374        default:
375            TRESPASS();
376    }
377}
378
379////////////////////////////////////////////////////////////////////////////////
380
381MPEG2TSWriter::MPEG2TSWriter(const char *filename)
382    : mFile(fopen(filename, "wb")),
383      mStarted(false),
384      mNumSourcesDone(0),
385      mNumTSPacketsWritten(0),
386      mNumTSPacketsBeforeMeta(0) {
387    CHECK(mFile != NULL);
388
389    mLooper = new ALooper;
390    mLooper->setName("MPEG2TSWriter");
391
392    mReflector = new AHandlerReflector<MPEG2TSWriter>(this);
393
394    mLooper->registerHandler(mReflector);
395    mLooper->start();
396}
397
398MPEG2TSWriter::~MPEG2TSWriter() {
399    mLooper->unregisterHandler(mReflector->id());
400    mLooper->stop();
401
402    fclose(mFile);
403    mFile = NULL;
404}
405
406status_t MPEG2TSWriter::addSource(const sp<MediaSource> &source) {
407    CHECK(!mStarted);
408
409    sp<MetaData> meta = source->getFormat();
410    const char *mime;
411    CHECK(meta->findCString(kKeyMIMEType, &mime));
412
413    if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
414            && strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
415        return ERROR_UNSUPPORTED;
416    }
417
418    sp<SourceInfo> info = new SourceInfo(source);
419
420    mSources.push(info);
421
422    return OK;
423}
424
425status_t MPEG2TSWriter::start(MetaData *param) {
426    CHECK(!mStarted);
427
428    mStarted = true;
429    mNumSourcesDone = 0;
430    mNumTSPacketsWritten = 0;
431    mNumTSPacketsBeforeMeta = 0;
432
433    for (size_t i = 0; i < mSources.size(); ++i) {
434        sp<AMessage> notify =
435            new AMessage(kWhatSourceNotify, mReflector->id());
436
437        notify->setInt32("source-index", i);
438
439        mSources.editItemAt(i)->start(notify);
440    }
441
442    return OK;
443}
444
445status_t MPEG2TSWriter::stop() {
446    CHECK(mStarted);
447
448    for (size_t i = 0; i < mSources.size(); ++i) {
449        mSources.editItemAt(i)->stop();
450    }
451    mStarted = false;
452
453    return OK;
454}
455
456status_t MPEG2TSWriter::pause() {
457    CHECK(mStarted);
458
459    return OK;
460}
461
462bool MPEG2TSWriter::reachedEOS() {
463    return !mStarted || (mNumSourcesDone == mSources.size() ? true : false);
464}
465
466status_t MPEG2TSWriter::dump(int fd, const Vector<String16> &args) {
467    return OK;
468}
469
470void MPEG2TSWriter::onMessageReceived(const sp<AMessage> &msg) {
471    switch (msg->what()) {
472        case kWhatSourceNotify:
473        {
474            int32_t sourceIndex;
475            CHECK(msg->findInt32("source-index", &sourceIndex));
476
477            int32_t what;
478            CHECK(msg->findInt32("what", &what));
479
480            if (what == SourceInfo::kNotifyReachedEOS
481                    || what == SourceInfo::kNotifyStartFailed) {
482                ++mNumSourcesDone;
483            } else if (what == SourceInfo::kNotifyBuffer) {
484                sp<RefBase> obj;
485                CHECK(msg->findObject("buffer", &obj));
486
487                writeTS();
488
489                sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
490                writeAccessUnit(sourceIndex, buffer);
491            }
492            break;
493        }
494
495        default:
496            TRESPASS();
497    }
498}
499
500void MPEG2TSWriter::writeProgramAssociationTable() {
501    // 0x47
502    // transport_error_indicator = b0
503    // payload_unit_start_indicator = b1
504    // transport_priority = b0
505    // PID = b0000000000000 (13 bits)
506    // transport_scrambling_control = b00
507    // adaptation_field_control = b01 (no adaptation field, payload only)
508    // continuity_counter = b????
509    // skip = 0x00
510    // --- payload follows
511    // table_id = 0x00
512    // section_syntax_indicator = b1
513    // must_be_zero = b0
514    // reserved = b11
515    // section_length = 0x00d
516    // transport_stream_id = 0x0000
517    // reserved = b11
518    // version_number = b00001
519    // current_next_indicator = b1
520    // section_number = 0x00
521    // last_section_number = 0x00
522    //   one program follows:
523    //   program_number = 0x0001
524    //   reserved = b111
525    //   program_map_PID = 0x01e0 (13 bits!)
526    // CRC = 0x????????
527
528    static const uint8_t kData[] = {
529        0x47,
530        0x40, 0x00, 0x10, 0x00,  // b0100 0000 0000 0000 0001 ???? 0000 0000
531        0x00, 0xb0, 0x0d, 0x00,  // b0000 0000 1011 0000 0000 1101 0000 0000
532        0x00, 0xc3, 0x00, 0x00,  // b0000 0000 1100 0011 0000 0000 0000 0000
533        0x00, 0x01, 0xe1, 0xe0,  // b0000 0000 0000 0001 1110 0001 1110 0000
534        0x00, 0x00, 0x00, 0x00   // b???? ???? ???? ???? ???? ???? ???? ????
535    };
536
537    sp<ABuffer> buffer = new ABuffer(188);
538    memset(buffer->data(), 0, buffer->size());
539    memcpy(buffer->data(), kData, sizeof(kData));
540
541    static const unsigned kContinuityCounter = 5;
542    buffer->data()[3] |= kContinuityCounter;
543
544    CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), buffer->size());
545}
546
547void MPEG2TSWriter::writeProgramMap() {
548    // 0x47
549    // transport_error_indicator = b0
550    // payload_unit_start_indicator = b1
551    // transport_priority = b0
552    // PID = b0 0001 1110 0000 (13 bits) [0x1e0]
553    // transport_scrambling_control = b00
554    // adaptation_field_control = b01 (no adaptation field, payload only)
555    // continuity_counter = b????
556    // skip = 0x00
557    // -- payload follows
558    // table_id = 0x02
559    // section_syntax_indicator = b1
560    // must_be_zero = b0
561    // reserved = b11
562    // section_length = 0x???
563    // program_number = 0x0001
564    // reserved = b11
565    // version_number = b00001
566    // current_next_indicator = b1
567    // section_number = 0x00
568    // last_section_number = 0x00
569    // reserved = b111
570    // PCR_PID = b? ???? ???? ???? (13 bits)
571    // reserved = b1111
572    // program_info_length = 0x000
573    //   one or more elementary stream descriptions follow:
574    //   stream_type = 0x??
575    //   reserved = b111
576    //   elementary_PID = b? ???? ???? ???? (13 bits)
577    //   reserved = b1111
578    //   ES_info_length = 0x000
579    // CRC = 0x????????
580
581    static const uint8_t kData[] = {
582        0x47,
583        0x41, 0xe0, 0x10, 0x00,  // b0100 0001 1110 0000 0001 ???? 0000 0000
584        0x02, 0xb0, 0x00, 0x00,  // b0000 0010 1011 ???? ???? ???? 0000 0000
585        0x01, 0xc3, 0x00, 0x00,  // b0000 0001 1100 0011 0000 0000 0000 0000
586        0xe0, 0x00, 0xf0, 0x00   // b111? ???? ???? ???? 1111 0000 0000 0000
587    };
588
589    sp<ABuffer> buffer = new ABuffer(188);
590    memset(buffer->data(), 0, buffer->size());
591    memcpy(buffer->data(), kData, sizeof(kData));
592
593    static const unsigned kContinuityCounter = 5;
594    buffer->data()[3] |= kContinuityCounter;
595
596    size_t section_length = 5 * mSources.size() + 4 + 9;
597    buffer->data()[6] |= section_length >> 8;
598    buffer->data()[7] = section_length & 0xff;
599
600    static const unsigned kPCR_PID = 0x1e1;
601    buffer->data()[13] |= (kPCR_PID >> 8) & 0x1f;
602    buffer->data()[14] = kPCR_PID & 0xff;
603
604    uint8_t *ptr = &buffer->data()[sizeof(kData)];
605    for (size_t i = 0; i < mSources.size(); ++i) {
606        *ptr++ = mSources.editItemAt(i)->streamType();
607
608        const unsigned ES_PID = 0x1e0 + i + 1;
609        *ptr++ = 0xe0 | (ES_PID >> 8);
610        *ptr++ = ES_PID & 0xff;
611        *ptr++ = 0xf0;
612        *ptr++ = 0x00;
613    }
614
615    *ptr++ = 0x00;
616    *ptr++ = 0x00;
617    *ptr++ = 0x00;
618    *ptr++ = 0x00;
619
620    CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), buffer->size());
621}
622
623void MPEG2TSWriter::writeAccessUnit(
624        int32_t sourceIndex, const sp<ABuffer> &accessUnit) {
625    // 0x47
626    // transport_error_indicator = b0
627    // payload_unit_start_indicator = b1
628    // transport_priority = b0
629    // PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex]
630    // transport_scrambling_control = b00
631    // adaptation_field_control = b01 (no adaptation field, payload only)
632    // continuity_counter = b????
633    // -- payload follows
634    // packet_startcode_prefix = 0x000001
635    // stream_id = 0x?? (0xe0 for avc video, 0xc0 for aac audio)
636    // PES_packet_length = 0x????
637    // reserved = b10
638    // PES_scrambling_control = b00
639    // PES_priority = b0
640    // data_alignment_indicator = b1
641    // copyright = b0
642    // original_or_copy = b0
643    // PTS_DTS_flags = b10  (PTS only)
644    // ESCR_flag = b0
645    // ES_rate_flag = b0
646    // DSM_trick_mode_flag = b0
647    // additional_copy_info_flag = b0
648    // PES_CRC_flag = b0
649    // PES_extension_flag = b0
650    // PES_header_data_length = 0x05
651    // reserved = b0010 (PTS)
652    // PTS[32..30] = b???
653    // reserved = b1
654    // PTS[29..15] = b??? ???? ???? ???? (15 bits)
655    // reserved = b1
656    // PTS[14..0] = b??? ???? ???? ???? (15 bits)
657    // reserved = b1
658    // the first fragment of "buffer" follows
659
660    sp<ABuffer> buffer = new ABuffer(188);
661    memset(buffer->data(), 0, buffer->size());
662
663    const unsigned PID = 0x1e0 + sourceIndex + 1;
664
665    const unsigned continuity_counter =
666        mSources.editItemAt(sourceIndex)->incrementContinuityCounter();
667
668    // XXX if there are multiple streams of a kind (more than 1 audio or
669    // more than 1 video) they need distinct stream_ids.
670    const unsigned stream_id =
671        mSources.editItemAt(sourceIndex)->streamType() == 0x0f ? 0xc0 : 0xe0;
672
673    int64_t timeUs;
674    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
675
676    uint32_t PTS = (timeUs * 9ll) / 100ll;
677
678    size_t PES_packet_length = accessUnit->size() + 8;
679
680    uint8_t *ptr = buffer->data();
681    *ptr++ = 0x47;
682    *ptr++ = 0x40 | (PID >> 8);
683    *ptr++ = PID & 0xff;
684    *ptr++ = 0x10 | continuity_counter;
685    *ptr++ = 0x00;
686    *ptr++ = 0x00;
687    *ptr++ = 0x01;
688    *ptr++ = stream_id;
689    *ptr++ = PES_packet_length >> 8;
690    *ptr++ = PES_packet_length & 0xff;
691    *ptr++ = 0x84;
692    *ptr++ = 0x80;
693    *ptr++ = 0x05;
694    *ptr++ = 0x20 | (((PTS >> 30) & 7) << 1) | 1;
695    *ptr++ = (PTS >> 22) & 0xff;
696    *ptr++ = (((PTS >> 15) & 0x7f) << 1) | 1;
697    *ptr++ = (PTS >> 7) & 0xff;
698    *ptr++ = ((PTS & 0x7f) << 1) | 1;
699
700    size_t sizeLeft = buffer->data() + buffer->size() - ptr;
701    size_t copy = accessUnit->size();
702    if (copy > sizeLeft) {
703        copy = sizeLeft;
704    }
705
706    memcpy(ptr, accessUnit->data(), copy);
707
708    CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), buffer->size());
709
710    size_t offset = copy;
711    while (offset < accessUnit->size()) {
712        // for subsequent fragments of "buffer":
713        // 0x47
714        // transport_error_indicator = b0
715        // payload_unit_start_indicator = b0
716        // transport_priority = b0
717        // PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex]
718        // transport_scrambling_control = b00
719        // adaptation_field_control = b01 (no adaptation field, payload only)
720        // continuity_counter = b????
721        // the fragment of "buffer" follows.
722
723        memset(buffer->data(), 0, buffer->size());
724
725        const unsigned continuity_counter =
726            mSources.editItemAt(sourceIndex)->incrementContinuityCounter();
727
728        ptr = buffer->data();
729        *ptr++ = 0x47;
730        *ptr++ = 0x00 | (PID >> 8);
731        *ptr++ = PID & 0xff;
732        *ptr++ = 0x10 | continuity_counter;
733
734        size_t sizeLeft = buffer->data() + buffer->size() - ptr;
735        size_t copy = accessUnit->size() - offset;
736        if (copy > sizeLeft) {
737            copy = sizeLeft;
738        }
739
740        memcpy(ptr, accessUnit->data() + offset, copy);
741        CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile),
742                 buffer->size());
743
744        offset += copy;
745    }
746}
747
748void MPEG2TSWriter::writeTS() {
749    if (mNumTSPacketsWritten >= mNumTSPacketsBeforeMeta) {
750        writeProgramAssociationTable();
751        writeProgramMap();
752
753        mNumTSPacketsBeforeMeta = mNumTSPacketsWritten + 2500;
754    }
755}
756
757}  // namespace android
758
759