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