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, &timestampUs));
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