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