WebmWriter.cpp revision b2487f03f12dcafdb801fc0007c8df8412397f44
1343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih/*
2343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * Copyright (C) 2014 The Android Open Source Project
3343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih *
4343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * Licensed under the Apache License, Version 2.0 (the "License");
5343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * you may not use this file except in compliance with the License.
6343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * You may obtain a copy of the License at
7343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih *
8343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih *      http://www.apache.org/licenses/LICENSE-2.0
9343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih *
10343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * Unless required by applicable law or agreed to in writing, software
11343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * distributed under the License is distributed on an "AS IS" BASIS,
12343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * See the License for the specific language governing permissions and
14343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * limitations under the License.
15343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih */
16343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
17343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// #define LOG_NDEBUG 0
18343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#define LOG_TAG "WebmWriter"
19343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
20343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include "EbmlUtil.h"
21343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include "WebmWriter.h"
22343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
23343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include <media/stagefright/MetaData.h>
24343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include <media/stagefright/MediaDefs.h>
25343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include <media/stagefright/foundation/ADebug.h>
26343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
27343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include <utils/Errors.h>
28343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
29343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include <unistd.h>
30343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include <fcntl.h>
31343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include <sys/stat.h>
32343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include <inttypes.h>
33343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
34343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihusing namespace webm;
35343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
36343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihnamespace {
37343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihsize_t XiphLaceCodeLen(size_t size) {
38343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return size / 0xff + 1;
39343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
40343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
41343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihsize_t XiphLaceEnc(uint8_t *buf, size_t size) {
42343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    size_t i;
43343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    for (i = 0; size >= 0xff; ++i, size -= 0xff) {
44343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        buf[i] = 0xff;
45343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
46343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    buf[i++] = size;
47343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return i;
48343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
49343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
50343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
51343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihnamespace android {
52343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
53343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatic const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024;
54343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
55343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert ShihWebmWriter::WebmWriter(int fd)
56343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    : mFd(dup(fd)),
57343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mInitCheck(mFd < 0 ? NO_INIT : OK),
58343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mTimeCodeScale(1000000),
59343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mStartTimestampUs(0),
60343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mStartTimeOffsetMs(0),
61343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mSegmentOffset(0),
62343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mSegmentDataStart(0),
63343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mInfoOffset(0),
64343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mInfoSize(0),
65343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mTracksOffset(0),
66343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mCuesOffset(0),
67343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mPaused(false),
68343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mStarted(false),
69343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mIsFileSizeLimitExplicitlyRequested(false),
70343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mIsRealTimeRecording(false),
71343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mStreamableFile(true),
72343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih      mEstimatedCuesSize(0) {
73343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[kAudioIndex] = WebmStream(kAudioType, "Audio", &WebmWriter::audioTrack);
74343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[kVideoIndex] = WebmStream(kVideoType, "Video", &WebmWriter::videoTrack);
75343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mSinkThread = new WebmFrameSinkThread(
76343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mFd,
77343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mSegmentDataStart,
78343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mStreams[kVideoIndex].mSink,
79343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mStreams[kAudioIndex].mSink,
80343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mCuePoints);
81343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
82343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
83343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// static
84343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihsp<WebmElement> WebmWriter::videoTrack(const sp<MetaData>& md) {
85343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    int32_t width, height;
86343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    CHECK(md->findInt32(kKeyWidth, &width));
87343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    CHECK(md->findInt32(kKeyHeight, &height));
88343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return WebmElement::VideoTrackEntry(width, height);
89343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
90343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
91343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// static
92343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihsp<WebmElement> WebmWriter::audioTrack(const sp<MetaData>& md) {
93343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    int32_t nChannels, samplerate;
94343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint32_t type;
95343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    const void *headerData1;
96343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    const char headerData2[] = { 3, 'v', 'o', 'r', 'b', 'i', 's', 7, 0, 0, 0,
97343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            'a', 'n', 'd', 'r', 'o', 'i', 'd', 0, 0, 0, 0, 1 };
98343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    const void *headerData3;
99343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    size_t headerSize1, headerSize2 = sizeof(headerData2), headerSize3;
100343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
101343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    CHECK(md->findInt32(kKeyChannelCount, &nChannels));
102343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    CHECK(md->findInt32(kKeySampleRate, &samplerate));
103343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    CHECK(md->findData(kKeyVorbisInfo, &type, &headerData1, &headerSize1));
104343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    CHECK(md->findData(kKeyVorbisBooks, &type, &headerData3, &headerSize3));
105343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
106343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    size_t codecPrivateSize = 1;
107343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    codecPrivateSize += XiphLaceCodeLen(headerSize1);
108343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    codecPrivateSize += XiphLaceCodeLen(headerSize2);
109343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    codecPrivateSize += headerSize1 + headerSize2 + headerSize3;
110343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
111343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    off_t off = 0;
112343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<ABuffer> codecPrivateBuf = new ABuffer(codecPrivateSize);
113343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint8_t *codecPrivateData = codecPrivateBuf->data();
114343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    codecPrivateData[off++] = 2;
115343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
116343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    off += XiphLaceEnc(codecPrivateData + off, headerSize1);
117343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    off += XiphLaceEnc(codecPrivateData + off, headerSize2);
118343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
119343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    memcpy(codecPrivateData + off, headerData1, headerSize1);
120343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    off += headerSize1;
121343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    memcpy(codecPrivateData + off, headerData2, headerSize2);
122343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    off += headerSize2;
123343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    memcpy(codecPrivateData + off, headerData3, headerSize3);
124343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
125343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> entry = WebmElement::AudioTrackEntry(
126343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            nChannels,
127343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            samplerate,
128343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            codecPrivateBuf);
129343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return entry;
130343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
131343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
132343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihsize_t WebmWriter::numTracks() {
133343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    Mutex::Autolock autolock(mLock);
134343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
135343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    size_t numTracks = 0;
136343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    for (size_t i = 0; i < kMaxStreams; ++i) {
137343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (mStreams[i].mTrackEntry != NULL) {
138343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            numTracks++;
139343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
140343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
141343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
142343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return numTracks;
143343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
144343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
145343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihuint64_t WebmWriter::estimateCuesSize(int32_t bitRate) {
146343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // This implementation is based on estimateMoovBoxSize in MPEG4Writer.
147343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    //
148343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // Statistical analysis shows that metadata usually accounts
149343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // for a small portion of the total file size, usually < 0.6%.
150343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
151343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
152343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // where 1MB is the common file size limit for MMS application.
153343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // The default MAX _MOOV_BOX_SIZE value is based on about 3
154343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // minute video recording with a bit rate about 3 Mbps, because
155343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // statistics also show that most of the video captured are going
156343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // to be less than 3 minutes.
157343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
158343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // If the estimation is wrong, we will pay the price of wasting
159343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // some reserved space. This should not happen so often statistically.
160343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    static const int32_t factor = 2;
161343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    static const int64_t MIN_CUES_SIZE = 3 * 1024;  // 3 KB
162343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    static const int64_t MAX_CUES_SIZE = (180 * 3000000 * 6LL / 8000);
163343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    int64_t size = MIN_CUES_SIZE;
164343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
165343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // Max file size limit is set
166343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
167343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        size = mMaxFileSizeLimitBytes * 6 / 1000;
168343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
169343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
170343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // Max file duration limit is set
171343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mMaxFileDurationLimitUs != 0) {
172343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (bitRate > 0) {
173343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            int64_t size2 = ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
174343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
175343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                // When both file size and duration limits are set,
176343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                // we use the smaller limit of the two.
177343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                if (size > size2) {
178343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                    size = size2;
179343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                }
180343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            } else {
181343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                // Only max file duration limit is set
182343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                size = size2;
183343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            }
184343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
185343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
186343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
187343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (size < MIN_CUES_SIZE) {
188343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        size = MIN_CUES_SIZE;
189343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
190343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
191343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // Any long duration recording will be probably end up with
192343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // non-streamable webm file.
193343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (size > MAX_CUES_SIZE) {
194343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        size = MAX_CUES_SIZE;
195343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
196343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
197343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ALOGV("limits: %" PRId64 "/%" PRId64 " bytes/us,"
198343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            " bit rate: %d bps and the estimated cues size %" PRId64 " bytes",
199343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
200343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return factor * size;
201343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
202343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
203343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihvoid WebmWriter::initStream(size_t idx) {
204343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStreams[idx].mThread != NULL) {
205343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return;
206343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
207343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStreams[idx].mSource == NULL) {
208343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGV("adding dummy source ... ");
209343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        mStreams[idx].mThread = new WebmFrameEmptySourceThread(
210343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mStreams[idx].mType, mStreams[idx].mSink);
211343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    } else {
212343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGV("adding source %p", mStreams[idx].mSource.get());
213343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        mStreams[idx].mThread = new WebmFrameMediaSourceThread(
214343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mStreams[idx].mSource,
215343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mStreams[idx].mType,
216343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mStreams[idx].mSink,
217343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mTimeCodeScale,
218343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mStartTimestampUs,
219343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mStartTimeOffsetMs,
220343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                numTracks(),
221343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mIsRealTimeRecording);
222343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
223343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
224343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
225343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihvoid WebmWriter::release() {
226343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    close(mFd);
227343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mFd = -1;
228343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mInitCheck = NO_INIT;
229343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStarted = false;
230343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
231343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
232343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmWriter::reset() {
233343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mInitCheck != OK) {
234343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return OK;
235343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    } else {
236343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (!mStarted) {
237343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            release();
238343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            return OK;
239343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
240343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
241343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
242343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    status_t err = OK;
243343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    int64_t maxDurationUs = 0;
244343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    int64_t minDurationUs = 0x7fffffffffffffffLL;
245343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    for (int i = 0; i < kMaxStreams; ++i) {
246343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (mStreams[i].mThread == NULL) {
247343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            continue;
248343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
249343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
250343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        status_t status = mStreams[i].mThread->stop();
251343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (err == OK && status != OK) {
252343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            err = status;
253343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
254343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
255343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        int64_t durationUs = mStreams[i].mThread->getDurationUs();
256343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (durationUs > maxDurationUs) {
257343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            maxDurationUs = durationUs;
258343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
259343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (durationUs < minDurationUs) {
260343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            minDurationUs = durationUs;
261343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
262343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
263343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
264343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (numTracks() > 1) {
265343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", minDurationUs, maxDurationUs);
266343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
267343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
268343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mSinkThread->stop();
269343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
270343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // Do not write out movie header on error.
271343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (err != OK) {
272343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        release();
273343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return err;
274343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
275343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
276343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> cues = new WebmMaster(kMkvCues, mCuePoints);
277343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t cuesSize = cues->totalSize();
278343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // TRICKY Even when the cues do fit in the space we reserved, if they do not fit
279343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // perfectly, we still need to check if there is enough "extra space" to write an
280343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // EBML void element.
281343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (cuesSize != mEstimatedCuesSize && cuesSize > mEstimatedCuesSize - kMinEbmlVoidSize) {
282343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        mCuesOffset = ::lseek(mFd, 0, SEEK_CUR);
283343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        cues->write(mFd, cuesSize);
284343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    } else {
285343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        uint64_t spaceSize;
286343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ::lseek(mFd, mCuesOffset, SEEK_SET);
287343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        cues->write(mFd, cuesSize);
288343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        sp<WebmElement> space = new EbmlVoid(mEstimatedCuesSize - cuesSize);
289343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        space->write(mFd, spaceSize);
290343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
291343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
292343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mCuePoints.clear();
293343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[kVideoIndex].mSink.clear();
294343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[kAudioIndex].mSink.clear();
295343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
296343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint8_t bary[sizeof(uint64_t)];
297343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t totalSize = ::lseek(mFd, 0, SEEK_END);
298343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t segmentSize = totalSize - mSegmentDataStart;
299343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ::lseek(mFd, mSegmentOffset + sizeOf(kMkvSegment), SEEK_SET);
300343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t segmentSizeCoded = encodeUnsigned(segmentSize, sizeOf(kMkvUnknownLength));
301343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    serializeCodedUnsigned(segmentSizeCoded, bary);
302343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ::write(mFd, bary, sizeOf(kMkvUnknownLength));
303343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
304343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t durationOffset = mInfoOffset + sizeOf(kMkvInfo) + sizeOf(mInfoSize)
305343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        + sizeOf(kMkvSegmentDuration) + sizeOf(sizeof(double));
306343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> duration = new WebmFloat(
307343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            kMkvSegmentDuration,
308343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            (double) (maxDurationUs * 1000 / mTimeCodeScale));
309343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    duration->serializePayload(bary);
310343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ::lseek(mFd, durationOffset, SEEK_SET);
311343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ::write(mFd, bary, sizeof(double));
312343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
313343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    List<sp<WebmElement> > seekEntries;
314343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    seekEntries.push_back(WebmElement::SeekEntry(kMkvInfo, mInfoOffset - mSegmentDataStart));
315343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    seekEntries.push_back(WebmElement::SeekEntry(kMkvTracks, mTracksOffset - mSegmentDataStart));
316343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    seekEntries.push_back(WebmElement::SeekEntry(kMkvCues, mCuesOffset - mSegmentDataStart));
317343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> seekHead = new WebmMaster(kMkvSeekHead, seekEntries);
318343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
319343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t metaSeekSize;
320343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ::lseek(mFd, mSegmentDataStart, SEEK_SET);
321343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    seekHead->write(mFd, metaSeekSize);
322343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
323343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t spaceSize;
324343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> space = new EbmlVoid(kMaxMetaSeekSize - metaSeekSize);
325343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    space->write(mFd, spaceSize);
326343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
327343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    release();
328343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return err;
329343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
330343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
331b2487f03f12dcafdb801fc0007c8df8412397f44Marco Nelissenstatus_t WebmWriter::addSource(const sp<IMediaSource> &source) {
332343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    Mutex::Autolock l(mLock);
333343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStarted) {
334343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGE("Attempt to add source AFTER recording is started");
335343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return UNKNOWN_ERROR;
336343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
337343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
338343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // At most 2 tracks can be supported.
339343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStreams[kVideoIndex].mTrackEntry != NULL
340343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            && mStreams[kAudioIndex].mTrackEntry != NULL) {
341343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGE("Too many tracks (2) to add");
342343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return ERROR_UNSUPPORTED;
343343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
344343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
345343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    CHECK(source != NULL);
346343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
347343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // A track of type other than video or audio is not supported.
348343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    const char *mime;
349343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    source->getFormat()->findCString(kKeyMIMEType, &mime);
350343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    const char *vp8 = MEDIA_MIMETYPE_VIDEO_VP8;
351343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    const char *vorbis = MEDIA_MIMETYPE_AUDIO_VORBIS;
352343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
353343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    size_t streamIndex;
354343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (!strncasecmp(mime, vp8, strlen(vp8))) {
355343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        streamIndex = kVideoIndex;
356343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    } else if (!strncasecmp(mime, vorbis, strlen(vorbis))) {
357343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        streamIndex = kAudioIndex;
358343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    } else {
359343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGE("Track (%s) other than %s or %s is not supported", mime, vp8, vorbis);
360343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return ERROR_UNSUPPORTED;
361343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
362343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
363343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // No more than one video or one audio track is supported.
364343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStreams[streamIndex].mTrackEntry != NULL) {
365343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGE("%s track already exists", mStreams[streamIndex].mName);
366343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return ERROR_UNSUPPORTED;
367343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
368343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
369343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // This is the first track of either audio or video.
370343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // Go ahead to add the track.
371343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[streamIndex].mSource = source;
372343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[streamIndex].mTrackEntry = mStreams[streamIndex].mMakeTrack(source->getFormat());
373343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
374343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return OK;
375343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
376343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
377343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmWriter::start(MetaData *params) {
378343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mInitCheck != OK) {
379343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return UNKNOWN_ERROR;
380343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
381343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
382343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStreams[kVideoIndex].mTrackEntry == NULL
383343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            && mStreams[kAudioIndex].mTrackEntry == NULL) {
384343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGE("No source added");
385343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return INVALID_OPERATION;
386343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
387343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
388343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mMaxFileSizeLimitBytes != 0) {
389343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        mIsFileSizeLimitExplicitlyRequested = true;
390343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
391343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
392343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (params) {
393343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        int32_t isRealTimeRecording;
394343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        params->findInt32(kKeyRealTimeRecording, &isRealTimeRecording);
395343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        mIsRealTimeRecording = isRealTimeRecording;
396343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
397343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
398343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStarted) {
399343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (mPaused) {
400343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mPaused = false;
401343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mStreams[kAudioIndex].mThread->resume();
402343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mStreams[kVideoIndex].mThread->resume();
403343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
404343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return OK;
405343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
406343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
407343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (params) {
408343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        int32_t tcsl;
409343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (params->findInt32(kKeyTimeScale, &tcsl)) {
410343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mTimeCodeScale = tcsl;
411343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
412343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
413343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    CHECK_GT(mTimeCodeScale, 0);
414343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ALOGV("movie time scale: %" PRIu64, mTimeCodeScale);
415343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
416343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    /*
417343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     * When the requested file size limit is small, the priority
418343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     * is to meet the file size limit requirement, rather than
419343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     * to make the file streamable. mStreamableFile does not tell
420343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     * whether the actual recorded file is streamable or not.
421343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     */
422343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreamableFile = (!mMaxFileSizeLimitBytes)
423343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        || (mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes);
424343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
425343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    /*
426343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     * Write various metadata.
427343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     */
428343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> ebml, segment, info, seekHead, tracks, cues;
429343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ebml = WebmElement::EbmlHeader();
430343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    segment = new WebmMaster(kMkvSegment);
431343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    seekHead = new EbmlVoid(kMaxMetaSeekSize);
432343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    info = WebmElement::SegmentInfo(mTimeCodeScale, 0);
433343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
434343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    List<sp<WebmElement> > children;
435343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    for (size_t i = 0; i < kMaxStreams; ++i) {
436343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (mStreams[i].mTrackEntry != NULL) {
437343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            children.push_back(mStreams[i].mTrackEntry);
438343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
439343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
440343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    tracks = new WebmMaster(kMkvTracks, children);
441343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
442343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (!mStreamableFile) {
443343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        cues = NULL;
444343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    } else {
445343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        int32_t bitRate = -1;
446343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (params) {
447343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            params->findInt32(kKeyBitRate, &bitRate);
448343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
449343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        mEstimatedCuesSize = estimateCuesSize(bitRate);
450343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        CHECK_GE(mEstimatedCuesSize, 8);
451343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        cues = new EbmlVoid(mEstimatedCuesSize);
452343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
453343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
454343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> elems[] = { ebml, segment, seekHead, info, tracks, cues };
455343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    size_t nElems = sizeof(elems) / sizeof(elems[0]);
456343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t offsets[nElems];
457343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t sizes[nElems];
458343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    for (uint32_t i = 0; i < nElems; i++) {
459343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        WebmElement *e = elems[i].get();
460343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (!e) {
461343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            continue;
462343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
463343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
464343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        uint64_t size;
465343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        offsets[i] = ::lseek(mFd, 0, SEEK_CUR);
466343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        sizes[i] = e->mSize;
467343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        e->write(mFd, size);
468343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
469343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
470343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mSegmentOffset = offsets[1];
471343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mSegmentDataStart = offsets[2];
472343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mInfoOffset = offsets[3];
473343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mInfoSize = sizes[3];
474343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mTracksOffset = offsets[4];
475343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mCuesOffset = offsets[5];
476343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
477343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // start threads
478343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (params) {
479343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        params->findInt64(kKeyTime, &mStartTimestampUs);
480343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
481343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
482343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    initStream(kAudioIndex);
483343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    initStream(kVideoIndex);
484343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
485343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[kAudioIndex].mThread->start();
486343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[kVideoIndex].mThread->start();
487343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mSinkThread->start();
488343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
489343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStarted = true;
490343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return OK;
491343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
492343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
493343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmWriter::pause() {
494343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mInitCheck != OK) {
495343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return OK;
496343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
497343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mPaused = true;
498343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    status_t err = OK;
499343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    for (int i = 0; i < kMaxStreams; ++i) {
500343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (mStreams[i].mThread == NULL) {
501343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            continue;
502343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
503343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        status_t status = mStreams[i].mThread->pause();
504343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (status != OK) {
505343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            err = status;
506343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
507343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
508343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return err;
509343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
510343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
511343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmWriter::stop() {
512343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return reset();
513343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
514343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
515343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihbool WebmWriter::reachedEOS() {
516343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return !mSinkThread->running();
517343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
518343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} /* namespace android */
519