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 "WebmFrameThread" 19343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 20343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include "WebmConstants.h" 21343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include "WebmFrameThread.h" 22343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 23343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include <media/stagefright/MetaData.h> 24343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include <media/stagefright/foundation/ADebug.h> 25343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 26343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include <utils/Log.h> 27343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih#include <inttypes.h> 28343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 29343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihusing namespace webm; 30343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 31343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihnamespace android { 32343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 33343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihvoid *WebmFrameThread::wrap(void *arg) { 34343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih WebmFrameThread *worker = reinterpret_cast<WebmFrameThread*>(arg); 35343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih worker->run(); 36343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih return NULL; 37343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 38343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 39343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmFrameThread::start() { 40606e71cfb90e9646230d37a52b1b43c62c85292cWonsik Kim status_t err = OK; 41343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih pthread_attr_t attr; 42343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih pthread_attr_init(&attr); 43343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 44606e71cfb90e9646230d37a52b1b43c62c85292cWonsik Kim if ((err = pthread_create(&mThread, &attr, WebmFrameThread::wrap, this))) { 45606e71cfb90e9646230d37a52b1b43c62c85292cWonsik Kim mThread = 0; 46606e71cfb90e9646230d37a52b1b43c62c85292cWonsik Kim } 47343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih pthread_attr_destroy(&attr); 48606e71cfb90e9646230d37a52b1b43c62c85292cWonsik Kim return err; 49343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 50343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 51343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmFrameThread::stop() { 52606e71cfb90e9646230d37a52b1b43c62c85292cWonsik Kim void *status = nullptr; 53606e71cfb90e9646230d37a52b1b43c62c85292cWonsik Kim if (mThread) { 54606e71cfb90e9646230d37a52b1b43c62c85292cWonsik Kim pthread_join(mThread, &status); 55606e71cfb90e9646230d37a52b1b43c62c85292cWonsik Kim mThread = 0; 56606e71cfb90e9646230d37a52b1b43c62c85292cWonsik Kim } 57b4a7a2df4c28c3f32b5d877b54831d2cc5d78f81Colin Cross return (status_t)(intptr_t)status; 58343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 59343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 60343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih//================================================================================================= 61343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 62343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert ShihWebmFrameSourceThread::WebmFrameSourceThread( 63343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int type, 64343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih LinkedBlockingQueue<const sp<WebmFrame> >& sink) 65343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih : mType(type), mSink(sink) { 66343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 67343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 68343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih//================================================================================================= 69343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 70343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert ShihWebmFrameSinkThread::WebmFrameSinkThread( 71343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih const int& fd, 72343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih const uint64_t& off, 73343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih sp<WebmFrameSourceThread> videoThread, 74343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih sp<WebmFrameSourceThread> audioThread, 75343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih List<sp<WebmElement> >& cues) 76343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih : mFd(fd), 77343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mSegmentDataStart(off), 78343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mVideoFrames(videoThread->mSink), 79343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mAudioFrames(audioThread->mSink), 80343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mCues(cues), 81343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mDone(true) { 82343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 83343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 84343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert ShihWebmFrameSinkThread::WebmFrameSinkThread( 85343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih const int& fd, 86343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih const uint64_t& off, 87343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih LinkedBlockingQueue<const sp<WebmFrame> >& videoSource, 88343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih LinkedBlockingQueue<const sp<WebmFrame> >& audioSource, 89343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih List<sp<WebmElement> >& cues) 90343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih : mFd(fd), 91343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mSegmentDataStart(off), 92343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mVideoFrames(videoSource), 93343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mAudioFrames(audioSource), 94343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mCues(cues), 95343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mDone(true) { 96343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 97343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 98343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// Initializes a webm cluster with its starting timecode. 99343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// 100343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// frames: 101343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// sequence of input audio/video frames received from the source. 102343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// 103343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// clusterTimecodeL: 104343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// the starting timecode of the cluster; this is the timecode of the first 105343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// frame since frames are ordered by timestamp. 106343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// 107343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// children: 108343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// list to hold child elements in a webm cluster (start timecode and 109343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// simple blocks). 110343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// 111343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// static 112343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihvoid WebmFrameSinkThread::initCluster( 113343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih List<const sp<WebmFrame> >& frames, 114343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih uint64_t& clusterTimecodeL, 115343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih List<sp<WebmElement> >& children) { 116343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih CHECK(!frames.empty() && children.empty()); 117343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 118343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih const sp<WebmFrame> f = *(frames.begin()); 119343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih clusterTimecodeL = f->mAbsTimecode; 120343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih WebmUnsigned *clusterTimecode = new WebmUnsigned(kMkvTimecode, clusterTimecodeL); 121343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih children.clear(); 122343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih children.push_back(clusterTimecode); 123343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 124343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 125343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihvoid WebmFrameSinkThread::writeCluster(List<sp<WebmElement> >& children) { 126343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih // children must contain at least one simpleblock and its timecode 127b8c35f94470d1518e2def0582aaec4e038c92af0Colin Cross CHECK_GE(children.size(), 2u); 128343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 129343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih uint64_t size; 130343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih sp<WebmElement> cluster = new WebmMaster(kMkvCluster, children); 131343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih cluster->write(mFd, size); 132343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih children.clear(); 133343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 134343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 135343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// Write out (possibly multiple) webm cluster(s) from frames split on video key frames. 136343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// 137343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// last: 138343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih// current flush is triggered by EOS instead of a second outstanding video key frame. 139343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihvoid WebmFrameSinkThread::flushFrames(List<const sp<WebmFrame> >& frames, bool last) { 140343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (frames.empty()) { 141343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih return; 142343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 143343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 144343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih uint64_t clusterTimecodeL; 145343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih List<sp<WebmElement> > children; 146343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih initCluster(frames, clusterTimecodeL, children); 147343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 148343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih uint64_t cueTime = clusterTimecodeL; 149343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih off_t fpos = ::lseek(mFd, 0, SEEK_CUR); 150343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih size_t n = frames.size(); 151343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (!last) { 152343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih // If we are not flushing the last sequence of outstanding frames, flushFrames 153343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih // must have been called right after we have pushed a second outstanding video key 154343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih // frame (the last frame), which belongs to the next cluster; also hold back on 155343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih // flushing the second to last frame before we check its type. A audio frame 156343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih // should precede the aforementioned video key frame in the next sequence, a video 157343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih // frame should be the last frame in the current (to-be-flushed) sequence. 158b8c35f94470d1518e2def0582aaec4e038c92af0Colin Cross CHECK_GE(n, 2u); 159343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih n -= 2; 160343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 161343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 162343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih for (size_t i = 0; i < n; i++) { 163343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih const sp<WebmFrame> f = *(frames.begin()); 164343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (f->mType == kVideoType && f->mKey) { 165343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih cueTime = f->mAbsTimecode; 166343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 167343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 168343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (f->mAbsTimecode - clusterTimecodeL > INT16_MAX) { 169343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih writeCluster(children); 170343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih initCluster(frames, clusterTimecodeL, children); 171343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 172343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 173343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih frames.erase(frames.begin()); 174343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih children.push_back(f->SimpleBlock(clusterTimecodeL)); 175343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 176343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 177343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih // equivalent to last==false 178343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (!frames.empty()) { 179343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih // decide whether to write out the second to last frame. 180343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih const sp<WebmFrame> secondLastFrame = *(frames.begin()); 181343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (secondLastFrame->mType == kVideoType) { 182343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih frames.erase(frames.begin()); 183343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih children.push_back(secondLastFrame->SimpleBlock(clusterTimecodeL)); 184343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 185343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 186343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 187343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih writeCluster(children); 188343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih sp<WebmElement> cuePoint = WebmElement::CuePointEntry(cueTime, 1, fpos - mSegmentDataStart); 189343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mCues.push_back(cuePoint); 190343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 191343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 192343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmFrameSinkThread::start() { 193343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mDone = false; 194343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih return WebmFrameThread::start(); 195343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 196343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 197343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmFrameSinkThread::stop() { 198343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mDone = true; 199343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mVideoFrames.push(WebmFrame::EOS); 200343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mAudioFrames.push(WebmFrame::EOS); 201343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih return WebmFrameThread::stop(); 202343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 203343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 204343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihvoid WebmFrameSinkThread::run() { 205343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int numVideoKeyFrames = 0; 206343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih List<const sp<WebmFrame> > outstandingFrames; 207343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih while (!mDone) { 208343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih ALOGV("wait v frame"); 209343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih const sp<WebmFrame> videoFrame = mVideoFrames.peek(); 210343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih ALOGV("v frame: %p", videoFrame.get()); 211343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 212343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih ALOGV("wait a frame"); 213343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih const sp<WebmFrame> audioFrame = mAudioFrames.peek(); 214343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih ALOGV("a frame: %p", audioFrame.get()); 215343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 216343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (videoFrame->mEos && audioFrame->mEos) { 217343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih break; 218343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 219343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 220343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (*audioFrame < *videoFrame) { 221343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih ALOGV("take a frame"); 222343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mAudioFrames.take(); 223343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih outstandingFrames.push_back(audioFrame); 224343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } else { 225343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih ALOGV("take v frame"); 226343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mVideoFrames.take(); 227343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih outstandingFrames.push_back(videoFrame); 228343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (videoFrame->mKey) 229343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih numVideoKeyFrames++; 230343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 231343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 232343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (numVideoKeyFrames == 2) { 233343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih flushFrames(outstandingFrames, /* last = */ false); 234343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih numVideoKeyFrames--; 235343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 236343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 237343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih ALOGV("flushing last cluster (size %zu)", outstandingFrames.size()); 238343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih flushFrames(outstandingFrames, /* last = */ true); 239343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mDone = true; 240343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 241343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 242343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih//================================================================================================= 243343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 244343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatic const int64_t kInitialDelayTimeUs = 700000LL; 245343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 246343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihvoid WebmFrameMediaSourceThread::clearFlags() { 247343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mDone = false; 248343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mPaused = false; 249343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mResumed = false; 250343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mStarted = false; 251343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mReachedEOS = false; 252343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 253343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 254343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert ShihWebmFrameMediaSourceThread::WebmFrameMediaSourceThread( 255ba8128f9db82da66f28c6e6740d4721d80da954eDongwon Kang const sp<MediaSource>& source, 256343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int type, 257343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih LinkedBlockingQueue<const sp<WebmFrame> >& sink, 258343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih uint64_t timeCodeScale, 259343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int64_t startTimeRealUs, 260343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int32_t startTimeOffsetMs, 261343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int numTracks, 262343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih bool realTimeRecording) 263343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih : WebmFrameSourceThread(type, sink), 264343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mSource(source), 265343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mTimeCodeScale(timeCodeScale), 266343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mTrackDurationUs(0) { 267343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih clearFlags(); 268343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mStartTimeUs = startTimeRealUs; 269343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (realTimeRecording && numTracks > 1) { 270343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih /* 271343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * Copied from MPEG4Writer 272343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * 273343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * This extra delay of accepting incoming audio/video signals 274343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * helps to align a/v start time at the beginning of a recording 275343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * session, and it also helps eliminate the "recording" sound for 276343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * camcorder applications. 277343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * 278343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * If client does not set the start time offset, we fall back to 279343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih * use the default initial delay value. 280343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih */ 281343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int64_t startTimeOffsetUs = startTimeOffsetMs * 1000LL; 282343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (startTimeOffsetUs < 0) { // Start time offset was not set 283343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih startTimeOffsetUs = kInitialDelayTimeUs; 284343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 285343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mStartTimeUs += startTimeOffsetUs; 286343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs); 287343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 288343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 289343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 290343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmFrameMediaSourceThread::start() { 291343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih sp<MetaData> meta = new MetaData; 292343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih meta->setInt64(kKeyTime, mStartTimeUs); 293343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih status_t err = mSource->start(meta.get()); 294343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (err != OK) { 295343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mDone = true; 296343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mReachedEOS = true; 297343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih return err; 298343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } else { 299343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mStarted = true; 300343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih return WebmFrameThread::start(); 301343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 302343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 303343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 304343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmFrameMediaSourceThread::resume() { 305343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (!mDone && mPaused) { 306343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mPaused = false; 307343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mResumed = true; 308343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 309343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih return OK; 310343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 311343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 312343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmFrameMediaSourceThread::pause() { 313343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (mStarted) { 314343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mPaused = true; 315343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 316343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih return OK; 317343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 318343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 319343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihstatus_t WebmFrameMediaSourceThread::stop() { 320343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (mStarted) { 321343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mStarted = false; 322343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mDone = true; 323343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mSource->stop(); 324343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih return WebmFrameThread::stop(); 325343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 326343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih return OK; 327343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 328343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 329343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shihvoid WebmFrameMediaSourceThread::run() { 330343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int32_t count = 0; 331343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int64_t timestampUs = 0xdeadbeef; 332343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int64_t lastTimestampUs = 0; // Previous sample time stamp 333343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int64_t lastDurationUs = 0; // Previous sample duration 334343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int64_t previousPausedDurationUs = 0; 335343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 336343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih const uint64_t kUninitialized = 0xffffffffffffffffL; 337343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mStartTimeUs = kUninitialized; 338343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 339343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih status_t err = OK; 3401889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang MediaBufferBase *buffer; 341343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih while (!mDone && (err = mSource->read(&buffer, NULL)) == OK) { 342343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (buffer->range_length() == 0) { 343343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih buffer->release(); 344343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih buffer = NULL; 345343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih continue; 346343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 347343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 3483d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen MetaDataBase &md = buffer->meta_data(); 3493d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen CHECK(md.findInt64(kKeyTime, ×tampUs)); 350343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (mStartTimeUs == kUninitialized) { 351343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mStartTimeUs = timestampUs; 352343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 353343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih timestampUs -= mStartTimeUs; 354343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 355343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (mPaused && !mResumed) { 356343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih lastDurationUs = timestampUs - lastTimestampUs; 357343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih lastTimestampUs = timestampUs; 358343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih buffer->release(); 359343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih buffer = NULL; 360343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih continue; 361343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 362343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih ++count; 363343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 364343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih // adjust time-stamps after pause/resume 365343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (mResumed) { 366343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 367343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih CHECK_GE(durExcludingEarlierPausesUs, 0ll); 368343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 369343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih CHECK_GE(pausedDurationUs, lastDurationUs); 370343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih previousPausedDurationUs += pausedDurationUs - lastDurationUs; 371343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mResumed = false; 372343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 373343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih timestampUs -= previousPausedDurationUs; 374343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih CHECK_GE(timestampUs, 0ll); 375343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 376343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih int32_t isSync = false; 3773d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen md.findInt32(kKeyIsSyncFrame, &isSync); 378343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih const sp<WebmFrame> f = new WebmFrame( 379343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mType, 380343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih isSync, 381343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih timestampUs * 1000 / mTimeCodeScale, 382343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih buffer); 383343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mSink.push(f); 384343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 385343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih ALOGV( 386343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih "%s %s frame at %" PRId64 " size %zu\n", 387343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mType == kVideoType ? "video" : "audio", 388343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih isSync ? "I" : "P", 389343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih timestampUs * 1000 / mTimeCodeScale, 390343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih buffer->range_length()); 391343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 392343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih buffer->release(); 393343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih buffer = NULL; 394343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 395343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih if (timestampUs > mTrackDurationUs) { 396343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mTrackDurationUs = timestampUs; 397343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 398343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih lastDurationUs = timestampUs - lastTimestampUs; 399343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih lastTimestampUs = timestampUs; 400343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih } 401343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih 402343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mTrackDurationUs += lastDurationUs; 403343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih mSink.push(WebmFrame::EOS); 404343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 405343947abc8b7c126f966fd32a0b18bff6c2cecd1Robert Shih} 406