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;
8670b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian    const char *mimeType;
879c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar    if (!md->findInt32(kKeyWidth, &width)
889c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar            || !md->findInt32(kKeyHeight, &height)
899c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar            || !md->findCString(kKeyMIMEType, &mimeType)) {
909c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar        ALOGE("Missing format keys for video track");
919c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar        md->dumpToLog();
929c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar        return NULL;
939c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar    }
9470b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian    const char *codec;
9570b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian    if (!strncasecmp(
9670b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian            mimeType,
9770b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian            MEDIA_MIMETYPE_VIDEO_VP8,
9870b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian            strlen(MEDIA_MIMETYPE_VIDEO_VP8))) {
9970b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian        codec = "V_VP8";
10070b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian    } else if (!strncasecmp(
10170b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian            mimeType,
10270b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian            MEDIA_MIMETYPE_VIDEO_VP9,
10370b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian            strlen(MEDIA_MIMETYPE_VIDEO_VP9))) {
10470b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian        codec = "V_VP9";
10570b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian    } else {
1069c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar        ALOGE("Unsupported codec: %s", mimeType);
1079c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar        return NULL;
10870b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian    }
109d637d296bb0954756d3d231633fad73fadd70316Lajos Molnar    return WebmElement::VideoTrackEntry(codec, width, height, md);
110343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
111343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
112343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// static
113343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihsp<WebmElement> WebmWriter::audioTrack(const sp<MetaData>& md) {
114343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    int32_t nChannels, samplerate;
115343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint32_t type;
116343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    const void *headerData1;
117343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    const char headerData2[] = { 3, 'v', 'o', 'r', 'b', 'i', 's', 7, 0, 0, 0,
118343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            'a', 'n', 'd', 'r', 'o', 'i', 'd', 0, 0, 0, 0, 1 };
119343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    const void *headerData3;
120343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    size_t headerSize1, headerSize2 = sizeof(headerData2), headerSize3;
121343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
1229c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar    if (!md->findInt32(kKeyChannelCount, &nChannels)
1239c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar            || !md->findInt32(kKeySampleRate, &samplerate)
1249c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar            || !md->findData(kKeyVorbisInfo, &type, &headerData1, &headerSize1)
1259c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar            || !md->findData(kKeyVorbisBooks, &type, &headerData3, &headerSize3)) {
1269c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar        ALOGE("Missing format keys for audio track");
1279c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar        md->dumpToLog();
1289c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar        return NULL;
1299c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar    }
130343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
131343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    size_t codecPrivateSize = 1;
132343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    codecPrivateSize += XiphLaceCodeLen(headerSize1);
133343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    codecPrivateSize += XiphLaceCodeLen(headerSize2);
134343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    codecPrivateSize += headerSize1 + headerSize2 + headerSize3;
135343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
136343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    off_t off = 0;
137343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<ABuffer> codecPrivateBuf = new ABuffer(codecPrivateSize);
138343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint8_t *codecPrivateData = codecPrivateBuf->data();
139343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    codecPrivateData[off++] = 2;
140343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
141343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    off += XiphLaceEnc(codecPrivateData + off, headerSize1);
142343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    off += XiphLaceEnc(codecPrivateData + off, headerSize2);
143343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
144343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    memcpy(codecPrivateData + off, headerData1, headerSize1);
145343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    off += headerSize1;
146343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    memcpy(codecPrivateData + off, headerData2, headerSize2);
147343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    off += headerSize2;
148343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    memcpy(codecPrivateData + off, headerData3, headerSize3);
149343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
150343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> entry = WebmElement::AudioTrackEntry(
151343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            nChannels,
152343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            samplerate,
153343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            codecPrivateBuf);
154343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return entry;
155343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
156343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
157343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihsize_t WebmWriter::numTracks() {
158343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    Mutex::Autolock autolock(mLock);
159343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
160343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    size_t numTracks = 0;
161343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    for (size_t i = 0; i < kMaxStreams; ++i) {
162343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (mStreams[i].mTrackEntry != NULL) {
163343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            numTracks++;
164343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
165343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
166343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
167343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return numTracks;
168343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
169343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
170343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihuint64_t WebmWriter::estimateCuesSize(int32_t bitRate) {
171343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // This implementation is based on estimateMoovBoxSize in MPEG4Writer.
172343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    //
173343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // Statistical analysis shows that metadata usually accounts
174343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // for a small portion of the total file size, usually < 0.6%.
175343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
176343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
177343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // where 1MB is the common file size limit for MMS application.
178343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // The default MAX _MOOV_BOX_SIZE value is based on about 3
179343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // minute video recording with a bit rate about 3 Mbps, because
180343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // statistics also show that most of the video captured are going
181343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // to be less than 3 minutes.
182343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
183343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // If the estimation is wrong, we will pay the price of wasting
184343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // some reserved space. This should not happen so often statistically.
185343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    static const int32_t factor = 2;
186343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    static const int64_t MIN_CUES_SIZE = 3 * 1024;  // 3 KB
187343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    static const int64_t MAX_CUES_SIZE = (180 * 3000000 * 6LL / 8000);
188343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    int64_t size = MIN_CUES_SIZE;
189343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
190343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // Max file size limit is set
191343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
192343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        size = mMaxFileSizeLimitBytes * 6 / 1000;
193343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
194343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
195343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // Max file duration limit is set
196343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mMaxFileDurationLimitUs != 0) {
197343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (bitRate > 0) {
198343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            int64_t size2 = ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
199343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
200343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                // When both file size and duration limits are set,
201343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                // we use the smaller limit of the two.
202343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                if (size > size2) {
203343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                    size = size2;
204343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                }
205343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            } else {
206343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                // Only max file duration limit is set
207343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                size = size2;
208343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            }
209343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
210343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
211343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
212343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (size < MIN_CUES_SIZE) {
213343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        size = MIN_CUES_SIZE;
214343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
215343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
216343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // Any long duration recording will be probably end up with
217343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // non-streamable webm file.
218343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (size > MAX_CUES_SIZE) {
219343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        size = MAX_CUES_SIZE;
220343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
221343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
222343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ALOGV("limits: %" PRId64 "/%" PRId64 " bytes/us,"
223343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            " bit rate: %d bps and the estimated cues size %" PRId64 " bytes",
224343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
225343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return factor * size;
226343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
227343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
228343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihvoid WebmWriter::initStream(size_t idx) {
229343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStreams[idx].mThread != NULL) {
230343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return;
231343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
232343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStreams[idx].mSource == NULL) {
233343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGV("adding dummy source ... ");
234343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        mStreams[idx].mThread = new WebmFrameEmptySourceThread(
235343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mStreams[idx].mType, mStreams[idx].mSink);
236343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    } else {
237343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGV("adding source %p", mStreams[idx].mSource.get());
238343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        mStreams[idx].mThread = new WebmFrameMediaSourceThread(
239343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mStreams[idx].mSource,
240343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mStreams[idx].mType,
241343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mStreams[idx].mSink,
242343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mTimeCodeScale,
243343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mStartTimestampUs,
244343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mStartTimeOffsetMs,
245343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                numTracks(),
246343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih                mIsRealTimeRecording);
247343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
248343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
249343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
250343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihvoid WebmWriter::release() {
251343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    close(mFd);
252343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mFd = -1;
253343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mInitCheck = NO_INIT;
254343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStarted = false;
2552bae6deec84016b9caaffcb536534820c47b12d2Lajos Molnar    for (size_t ix = 0; ix < kMaxStreams; ++ix) {
2562bae6deec84016b9caaffcb536534820c47b12d2Lajos Molnar        mStreams[ix].mTrackEntry.clear();
2572bae6deec84016b9caaffcb536534820c47b12d2Lajos Molnar        mStreams[ix].mSource.clear();
2582bae6deec84016b9caaffcb536534820c47b12d2Lajos Molnar    }
2592bae6deec84016b9caaffcb536534820c47b12d2Lajos Molnar    mStreamsInOrder.clear();
260343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
261343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
262343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmWriter::reset() {
263343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mInitCheck != OK) {
264343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return OK;
265343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    } else {
266343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (!mStarted) {
267343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            release();
268343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            return OK;
269343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
270343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
271343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
272343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    status_t err = OK;
273343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    int64_t maxDurationUs = 0;
274343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    int64_t minDurationUs = 0x7fffffffffffffffLL;
275343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    for (int i = 0; i < kMaxStreams; ++i) {
276343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (mStreams[i].mThread == NULL) {
277343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            continue;
278343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
279343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
280343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        status_t status = mStreams[i].mThread->stop();
281343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (err == OK && status != OK) {
282343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            err = status;
283343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
284343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
285343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        int64_t durationUs = mStreams[i].mThread->getDurationUs();
286343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (durationUs > maxDurationUs) {
287343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            maxDurationUs = durationUs;
288343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
289343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (durationUs < minDurationUs) {
290343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            minDurationUs = durationUs;
291343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
2922bae6deec84016b9caaffcb536534820c47b12d2Lajos Molnar
2932bae6deec84016b9caaffcb536534820c47b12d2Lajos Molnar        mStreams[i].mThread.clear();
294343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
295343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
296343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (numTracks() > 1) {
297343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", minDurationUs, maxDurationUs);
298343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
299343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
300343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mSinkThread->stop();
301343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
302343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // Do not write out movie header on error.
303343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (err != OK) {
304343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        release();
305343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return err;
306343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
307343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
308343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> cues = new WebmMaster(kMkvCues, mCuePoints);
309343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t cuesSize = cues->totalSize();
310343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // TRICKY Even when the cues do fit in the space we reserved, if they do not fit
311343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // perfectly, we still need to check if there is enough "extra space" to write an
312343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // EBML void element.
313343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (cuesSize != mEstimatedCuesSize && cuesSize > mEstimatedCuesSize - kMinEbmlVoidSize) {
314343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        mCuesOffset = ::lseek(mFd, 0, SEEK_CUR);
315343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        cues->write(mFd, cuesSize);
316343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    } else {
317343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        uint64_t spaceSize;
318343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ::lseek(mFd, mCuesOffset, SEEK_SET);
319343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        cues->write(mFd, cuesSize);
320343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        sp<WebmElement> space = new EbmlVoid(mEstimatedCuesSize - cuesSize);
321343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        space->write(mFd, spaceSize);
322343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
323343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
324343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mCuePoints.clear();
325343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[kVideoIndex].mSink.clear();
326343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[kAudioIndex].mSink.clear();
327343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
328343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint8_t bary[sizeof(uint64_t)];
329343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t totalSize = ::lseek(mFd, 0, SEEK_END);
330343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t segmentSize = totalSize - mSegmentDataStart;
331343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ::lseek(mFd, mSegmentOffset + sizeOf(kMkvSegment), SEEK_SET);
332343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t segmentSizeCoded = encodeUnsigned(segmentSize, sizeOf(kMkvUnknownLength));
333343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    serializeCodedUnsigned(segmentSizeCoded, bary);
334343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ::write(mFd, bary, sizeOf(kMkvUnknownLength));
335343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
336343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t durationOffset = mInfoOffset + sizeOf(kMkvInfo) + sizeOf(mInfoSize)
337343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        + sizeOf(kMkvSegmentDuration) + sizeOf(sizeof(double));
338343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> duration = new WebmFloat(
339343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            kMkvSegmentDuration,
340343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            (double) (maxDurationUs * 1000 / mTimeCodeScale));
341343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    duration->serializePayload(bary);
342343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ::lseek(mFd, durationOffset, SEEK_SET);
343343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ::write(mFd, bary, sizeof(double));
344343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
345343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    List<sp<WebmElement> > seekEntries;
346343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    seekEntries.push_back(WebmElement::SeekEntry(kMkvInfo, mInfoOffset - mSegmentDataStart));
347343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    seekEntries.push_back(WebmElement::SeekEntry(kMkvTracks, mTracksOffset - mSegmentDataStart));
348343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    seekEntries.push_back(WebmElement::SeekEntry(kMkvCues, mCuesOffset - mSegmentDataStart));
349343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> seekHead = new WebmMaster(kMkvSeekHead, seekEntries);
350343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
351343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t metaSeekSize;
352343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ::lseek(mFd, mSegmentDataStart, SEEK_SET);
353343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    seekHead->write(mFd, metaSeekSize);
354343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
355343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t spaceSize;
356343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> space = new EbmlVoid(kMaxMetaSeekSize - metaSeekSize);
357343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    space->write(mFd, spaceSize);
358343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
359343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    release();
360343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return err;
361343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
362343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
363b2487f03f12dcafdb801fc0007c8df8412397f44Marco Nelissenstatus_t WebmWriter::addSource(const sp<IMediaSource> &source) {
364343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    Mutex::Autolock l(mLock);
365343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStarted) {
366343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGE("Attempt to add source AFTER recording is started");
367343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return UNKNOWN_ERROR;
368343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
369343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
370343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // At most 2 tracks can be supported.
371343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStreams[kVideoIndex].mTrackEntry != NULL
372343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            && mStreams[kAudioIndex].mTrackEntry != NULL) {
373343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGE("Too many tracks (2) to add");
374343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return ERROR_UNSUPPORTED;
375343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
376343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
377343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    CHECK(source != NULL);
378343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
379343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // A track of type other than video or audio is not supported.
380343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    const char *mime;
381343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    source->getFormat()->findCString(kKeyMIMEType, &mime);
382343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    const char *vp8 = MEDIA_MIMETYPE_VIDEO_VP8;
38370b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian    const char *vp9 = MEDIA_MIMETYPE_VIDEO_VP9;
384343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    const char *vorbis = MEDIA_MIMETYPE_AUDIO_VORBIS;
385343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
386343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    size_t streamIndex;
38770b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian    if (!strncasecmp(mime, vp8, strlen(vp8)) ||
38870b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian        !strncasecmp(mime, vp9, strlen(vp9))) {
389343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        streamIndex = kVideoIndex;
390343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    } else if (!strncasecmp(mime, vorbis, strlen(vorbis))) {
391343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        streamIndex = kAudioIndex;
392343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    } else {
39370b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian        ALOGE("Track (%s) other than %s, %s or %s is not supported",
39470b22a024d75bce04575c16ed49fc7991c8544a6Vignesh Venkatasubramanian              mime, vp8, vp9, vorbis);
395343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return ERROR_UNSUPPORTED;
396343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
397343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
398343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // No more than one video or one audio track is supported.
399343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStreams[streamIndex].mTrackEntry != NULL) {
400343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGE("%s track already exists", mStreams[streamIndex].mName);
401343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return ERROR_UNSUPPORTED;
402343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
403343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
404343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // This is the first track of either audio or video.
405343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // Go ahead to add the track.
406343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[streamIndex].mSource = source;
407343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[streamIndex].mTrackEntry = mStreams[streamIndex].mMakeTrack(source->getFormat());
4089c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar    if (mStreams[streamIndex].mTrackEntry == NULL) {
4092bae6deec84016b9caaffcb536534820c47b12d2Lajos Molnar        mStreams[streamIndex].mSource.clear();
4109c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar        return BAD_VALUE;
4119c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar    }
4122bae6deec84016b9caaffcb536534820c47b12d2Lajos Molnar    mStreamsInOrder.push_back(mStreams[streamIndex].mTrackEntry);
413343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
414343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return OK;
415343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
416343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
417343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmWriter::start(MetaData *params) {
418343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mInitCheck != OK) {
419343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return UNKNOWN_ERROR;
420343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
421343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
422343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStreams[kVideoIndex].mTrackEntry == NULL
423343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            && mStreams[kAudioIndex].mTrackEntry == NULL) {
424343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        ALOGE("No source added");
425343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return INVALID_OPERATION;
426343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
427343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
428343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mMaxFileSizeLimitBytes != 0) {
429343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        mIsFileSizeLimitExplicitlyRequested = true;
430343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
431343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
432343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (params) {
433343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        int32_t isRealTimeRecording;
434343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        params->findInt32(kKeyRealTimeRecording, &isRealTimeRecording);
435343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        mIsRealTimeRecording = isRealTimeRecording;
436343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
437343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
438343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mStarted) {
439343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (mPaused) {
440343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mPaused = false;
441343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mStreams[kAudioIndex].mThread->resume();
442343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mStreams[kVideoIndex].mThread->resume();
443343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
444343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return OK;
445343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
446343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
447343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (params) {
448343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        int32_t tcsl;
449343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (params->findInt32(kKeyTimeScale, &tcsl)) {
450343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            mTimeCodeScale = tcsl;
451343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
452343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
4539c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar    if (mTimeCodeScale == 0) {
4549c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar        ALOGE("movie time scale is 0");
4559c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar        return BAD_VALUE;
4569c876499f869af4010b8fcdca2d9f316a8a91123Lajos Molnar    }
457343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ALOGV("movie time scale: %" PRIu64, mTimeCodeScale);
458343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
459343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    /*
460343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     * When the requested file size limit is small, the priority
461343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     * is to meet the file size limit requirement, rather than
462343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     * to make the file streamable. mStreamableFile does not tell
463343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     * whether the actual recorded file is streamable or not.
464343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     */
465343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreamableFile = (!mMaxFileSizeLimitBytes)
466343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        || (mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes);
467343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
468343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    /*
469343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     * Write various metadata.
470343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih     */
471343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> ebml, segment, info, seekHead, tracks, cues;
472343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    ebml = WebmElement::EbmlHeader();
473343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    segment = new WebmMaster(kMkvSegment);
474343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    seekHead = new EbmlVoid(kMaxMetaSeekSize);
475343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    info = WebmElement::SegmentInfo(mTimeCodeScale, 0);
476343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
477343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    List<sp<WebmElement> > children;
4782bae6deec84016b9caaffcb536534820c47b12d2Lajos Molnar    for (size_t i = 0; i < mStreamsInOrder.size(); ++i) {
4792bae6deec84016b9caaffcb536534820c47b12d2Lajos Molnar        children.push_back(mStreamsInOrder[i]);
480343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
481343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    tracks = new WebmMaster(kMkvTracks, children);
482343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
483343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (!mStreamableFile) {
484343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        cues = NULL;
485343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    } else {
486343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        int32_t bitRate = -1;
487343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (params) {
488343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            params->findInt32(kKeyBitRate, &bitRate);
489343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
490343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        mEstimatedCuesSize = estimateCuesSize(bitRate);
491343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        CHECK_GE(mEstimatedCuesSize, 8);
492343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        cues = new EbmlVoid(mEstimatedCuesSize);
493343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
494343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
495343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    sp<WebmElement> elems[] = { ebml, segment, seekHead, info, tracks, cues };
496343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    size_t nElems = sizeof(elems) / sizeof(elems[0]);
497343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t offsets[nElems];
498343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    uint64_t sizes[nElems];
499343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    for (uint32_t i = 0; i < nElems; i++) {
500343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        WebmElement *e = elems[i].get();
501343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (!e) {
502343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            continue;
503343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
504343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
505343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        uint64_t size;
506343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        offsets[i] = ::lseek(mFd, 0, SEEK_CUR);
507343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        sizes[i] = e->mSize;
508343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        e->write(mFd, size);
509343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
510343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
511343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mSegmentOffset = offsets[1];
512343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mSegmentDataStart = offsets[2];
513343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mInfoOffset = offsets[3];
514343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mInfoSize = sizes[3];
515343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mTracksOffset = offsets[4];
516343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mCuesOffset = offsets[5];
517343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
518343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    // start threads
519343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (params) {
520343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        params->findInt64(kKeyTime, &mStartTimestampUs);
521343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
522343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
523343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    initStream(kAudioIndex);
524343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    initStream(kVideoIndex);
525343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
526343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[kAudioIndex].mThread->start();
527343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStreams[kVideoIndex].mThread->start();
528343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mSinkThread->start();
529343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
530343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mStarted = true;
531343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return OK;
532343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
533343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
534343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmWriter::pause() {
535343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    if (mInitCheck != OK) {
536343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        return OK;
537343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
538343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    mPaused = true;
539343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    status_t err = OK;
540343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    for (int i = 0; i < kMaxStreams; ++i) {
541343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (mStreams[i].mThread == NULL) {
542343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            continue;
543343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
544343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        status_t status = mStreams[i].mThread->pause();
545343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        if (status != OK) {
546343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih            err = status;
547343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih        }
548343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    }
549343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return err;
550343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
551343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
552343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmWriter::stop() {
553343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return reset();
554343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
555343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih
556343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihbool WebmWriter::reachedEOS() {
557343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih    return !mSinkThread->running();
558343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih}
559343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} /* namespace android */
560