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