19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2014 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//#define LOG_NDEBUG 0
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "WebmFrameThread"
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "WebmConstants.h"
21000479f9e325b4e426a67033abd92d47da412725Mathias Agopian#include "WebmFrameThread.h"
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/MetaData.h>
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/foundation/ADebug.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h>
276158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian#include <inttypes.h>
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectusing namespace webm;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid *WebmFrameThread::wrap(void *arg) {
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    WebmFrameThread *worker = reinterpret_cast<WebmFrameThread*>(arg);
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    worker->run();
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NULL;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
38af1e11b849ea527f4b1b1695924ce42cc9d7f670Mathias Agopian
39af1e11b849ea527f4b1b1695924ce42cc9d7f670Mathias Agopianstatus_t WebmFrameThread::start() {
40af1e11b849ea527f4b1b1695924ce42cc9d7f670Mathias Agopian    pthread_attr_t attr;
41af1e11b849ea527f4b1b1695924ce42cc9d7f670Mathias Agopian    pthread_attr_init(&attr);
42af1e11b849ea527f4b1b1695924ce42cc9d7f670Mathias Agopian    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pthread_create(&mThread, &attr, WebmFrameThread::wrap, this);
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pthread_attr_destroy(&attr);
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return OK;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameThread::stop() {
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void *status;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pthread_join(mThread, &status);
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return (status_t)(intptr_t)status;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5417f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian//=================================================================================================
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectWebmFrameSourceThread::WebmFrameSourceThread(
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int type,
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    LinkedBlockingQueue<const sp<WebmFrame> >& sink)
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    : mType(type), mSink(sink) {
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//=================================================================================================
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectWebmFrameSinkThread::WebmFrameSinkThread(
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const int& fd,
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const uint64_t& off,
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sp<WebmFrameSourceThread> videoThread,
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sp<WebmFrameSourceThread> audioThread,
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        List<sp<WebmElement> >& cues)
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    : mFd(fd),
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mSegmentDataStart(off),
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mVideoFrames(videoThread->mSink),
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mAudioFrames(audioThread->mSink),
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mCues(cues),
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mDone(true) {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectWebmFrameSinkThread::WebmFrameSinkThread(
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const int& fd,
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const uint64_t& off,
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LinkedBlockingQueue<const sp<WebmFrame> >& videoSource,
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LinkedBlockingQueue<const sp<WebmFrame> >& audioSource,
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        List<sp<WebmElement> >& cues)
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    : mFd(fd),
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mSegmentDataStart(off),
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mVideoFrames(videoSource),
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mAudioFrames(audioSource),
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mCues(cues),
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mDone(true) {
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Initializes a webm cluster with its starting timecode.
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// frames:
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//   sequence of input audio/video frames received from the source.
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// clusterTimecodeL:
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//   the starting timecode of the cluster; this is the timecode of the first
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//   frame since frames are ordered by timestamp.
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// children:
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//   list to hold child elements in a webm cluster (start timecode and
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//   simple blocks).
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// static
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid WebmFrameSinkThread::initCluster(
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    List<const sp<WebmFrame> >& frames,
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uint64_t& clusterTimecodeL,
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    List<sp<WebmElement> >& children) {
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    CHECK(!frames.empty() && children.empty());
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const sp<WebmFrame> f = *(frames.begin());
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    clusterTimecodeL = f->mAbsTimecode;
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    WebmUnsigned *clusterTimecode = new WebmUnsigned(kMkvTimecode, clusterTimecodeL);
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    children.clear();
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    children.push_back(clusterTimecode);
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid WebmFrameSinkThread::writeCluster(List<sp<WebmElement> >& children) {
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // children must contain at least one simpleblock and its timecode
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    CHECK_GE(children.size(), 2);
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    uint64_t size;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sp<WebmElement> cluster = new WebmMaster(kMkvCluster, children);
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    cluster->write(mFd, size);
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    children.clear();
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Write out (possibly multiple) webm cluster(s) from frames split on video key frames.
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//
13117f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian// last:
13217f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian//   current flush is triggered by EOS instead of a second outstanding video key frame.
13317f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopianvoid WebmFrameSinkThread::flushFrames(List<const sp<WebmFrame> >& frames, bool last) {
13417f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    if (frames.empty()) {
13517f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian        return;
13617f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    }
13717f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian
13817f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    uint64_t clusterTimecodeL;
13917f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    List<sp<WebmElement> > children;
14017f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    initCluster(frames, clusterTimecodeL, children);
14117f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian
14217f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    uint64_t cueTime = clusterTimecodeL;
14317f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    off_t fpos = ::lseek(mFd, 0, SEEK_CUR);
14417f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    size_t n = frames.size();
14517f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    if (!last) {
14617f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian        // If we are not flushing the last sequence of outstanding frames, flushFrames
14717f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian        // must have been called right after we have pushed a second outstanding video key
14817f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian        // frame (the last frame), which belongs to the next cluster; also hold back on
14917f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian        // flushing the second to last frame before we check its type. A audio frame
15017f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian        // should precede the aforementioned video key frame in the next sequence, a video
15117f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian        // frame should be the last frame in the current (to-be-flushed) sequence.
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CHECK_GE(n, 2);
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        n -= 2;
15469d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian    }
15569d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian
15669d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian    for (size_t i = 0; i < n; i++) {
15769d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian        const sp<WebmFrame> f = *(frames.begin());
15869d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian        if (f->mType == kVideoType && f->mKey) {
15969d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian            cueTime = f->mAbsTimecode;
16069d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian        }
16169d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian
16269d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian        if (f->mAbsTimecode - clusterTimecodeL > INT16_MAX) {
16369d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian            writeCluster(children);
16469d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian            initCluster(frames, clusterTimecodeL, children);
16569d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian        }
16669d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian
16769d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian        frames.erase(frames.begin());
16869d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian        children.push_back(f->SimpleBlock(clusterTimecodeL));
16969d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian    }
17069d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian
17169d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian    // equivalent to last==false
17269d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian    if (!frames.empty()) {
17369d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian        // decide whether to write out the second to last frame.
17469d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian        const sp<WebmFrame> secondLastFrame = *(frames.begin());
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (secondLastFrame->mType == kVideoType) {
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            frames.erase(frames.begin());
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            children.push_back(secondLastFrame->SimpleBlock(clusterTimecodeL));
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    writeCluster(children);
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    sp<WebmElement> cuePoint = WebmElement::CuePointEntry(cueTime, 1, fpos - mSegmentDataStart);
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mCues.push_back(cuePoint);
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameSinkThread::start() {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mDone = false;
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return WebmFrameThread::start();
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameSinkThread::stop() {
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mDone = true;
1935d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian    mVideoFrames.push(WebmFrame::EOS);
1945d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian    mAudioFrames.push(WebmFrame::EOS);
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return WebmFrameThread::stop();
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid WebmFrameSinkThread::run() {
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int numVideoKeyFrames = 0;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    List<const sp<WebmFrame> > outstandingFrames;
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (!mDone) {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ALOGV("wait v frame");
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const sp<WebmFrame> videoFrame = mVideoFrames.peek();
2045d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian        ALOGV("v frame: %p", videoFrame.get());
2055d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian
2065d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian        ALOGV("wait a frame");
2075d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian        const sp<WebmFrame> audioFrame = mAudioFrames.peek();
2085d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian        ALOGV("a frame: %p", audioFrame.get());
2095d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian
2105d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian        if (videoFrame->mEos && audioFrame->mEos) {
2115d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian            break;
2125d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian        }
2135d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (*audioFrame < *videoFrame) {
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ALOGV("take a frame");
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAudioFrames.take();
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            outstandingFrames.push_back(audioFrame);
21817f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian        } else {
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ALOGV("take v frame");
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mVideoFrames.take();
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            outstandingFrames.push_back(videoFrame);
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (videoFrame->mKey)
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                numVideoKeyFrames++;
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (numVideoKeyFrames == 2) {
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flushFrames(outstandingFrames, /* last = */ false);
22817f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian            numVideoKeyFrames--;
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ALOGV("flushing last cluster (size %zu)", outstandingFrames.size());
2328138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen    flushFrames(outstandingFrames, /* last = */ true);
2338138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen    mDone = true;
2348138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen}
2358138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen
2368138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen//=================================================================================================
2378138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen
2388138cb49e47f9a9905a316a217757710185c66aaMarco Nelissenstatic const int64_t kInitialDelayTimeUs = 700000LL;
2398138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen
2408138cb49e47f9a9905a316a217757710185c66aaMarco Nelissenvoid WebmFrameMediaSourceThread::clearFlags() {
2410586a1b77a788a119166a37fccd909bf9ed65f23Dianne Hackborn    mDone = false;
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mPaused = false;
24317f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    mResumed = false;
24417f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    mStarted = false;
245402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian    mReachedEOS = false;
246402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian}
24717f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian
248402c34649f514669517c2208e35caa58ff8bb2b9Mathias AgopianWebmFrameMediaSourceThread::WebmFrameMediaSourceThread(
249402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian        const sp<MediaSource>& source,
250402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian        int type,
251402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian        LinkedBlockingQueue<const sp<WebmFrame> >& sink,
252402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian        uint64_t timeCodeScale,
25317f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian        int64_t startTimeRealUs,
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int32_t startTimeOffsetMs,
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numTracks,
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        bool realTimeRecording)
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    : WebmFrameSourceThread(type, sink),
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      mSource(source),
25917f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian      mTimeCodeScale(timeCodeScale),
26017f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian      mTrackDurationUs(0) {
26117f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    clearFlags();
26217f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    mStartTimeUs = startTimeRealUs;
26317f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    if (realTimeRecording && numTracks > 1) {
264402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian        /*
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Copied from MPEG4Writer
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This extra delay of accepting incoming audio/video signals
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * helps to align a/v start time at the beginning of a recording
269f1e5b0d4e5d0d2a78c234cd0cbd3005a74a79429Mathias Agopian         * session, and it also helps eliminate the "recording" sound for
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * camcorder applications.
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * If client does not set the start time offset, we fall back to
2738138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen         * use the default initial delay value.
2748138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen         */
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int64_t startTimeOffsetUs = startTimeOffsetMs * 1000LL;
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (startTimeOffsetUs < 0) {  // Start time offset was not set
2778138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen            startTimeOffsetUs = kInitialDelayTimeUs;
2788138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen        }
2798138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen        mStartTimeUs += startTimeOffsetUs;
2808138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen        ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs);
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameMediaSourceThread::start() {
28517f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian    sp<MetaData> meta = new MetaData;
286402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian    meta->setInt64(kKeyTime, mStartTimeUs);
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    status_t err = mSource->start(meta.get());
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err != OK) {
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDone = true;
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mReachedEOS = true;
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return err;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStarted = true;
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return WebmFrameThread::start();
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2976158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameMediaSourceThread::resume() {
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!mDone && mPaused) {
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPaused = false;
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mResumed = true;
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return OK;
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameMediaSourceThread::pause() {
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mStarted) {
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPaused = true;
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return OK;
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameMediaSourceThread::stop() {
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mStarted) {
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStarted = false;
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDone = true;
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSource->stop();
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return WebmFrameThread::stop();
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3201473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian    return OK;
3211473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian}
322f1e5b0d4e5d0d2a78c234cd0cbd3005a74a79429Mathias Agopian
323f1e5b0d4e5d0d2a78c234cd0cbd3005a74a79429Mathias Agopianvoid WebmFrameMediaSourceThread::run() {
324f1e5b0d4e5d0d2a78c234cd0cbd3005a74a79429Mathias Agopian    int32_t count = 0;
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int64_t timestampUs = 0xdeadbeef;
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int64_t lastTimestampUs = 0; // Previous sample time stamp
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int64_t lastDurationUs = 0; // Previous sample duration
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int64_t previousPausedDurationUs = 0;
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const uint64_t kUninitialized = 0xffffffffffffffffL;
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mStartTimeUs = kUninitialized;
3326158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian
3336158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian    status_t err = OK;
3346158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian    MediaBuffer *buffer;
3356158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian    while (!mDone && (err = mSource->read(&buffer, NULL)) == OK) {
3366158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian        if (buffer->range_length() == 0) {
3376158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian            buffer->release();
3386158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian            buffer = NULL;
3396158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian            continue;
3406158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian        }
3416158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian
3426158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian        sp<MetaData> md = buffer->meta_data();
3436158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian        CHECK(md->findInt64(kKeyTime, &timestampUs));
3446158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian        if (mStartTimeUs == kUninitialized) {
3456158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian            mStartTimeUs = timestampUs;
3466158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian        }
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        timestampUs -= mStartTimeUs;
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mPaused && !mResumed) {
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            lastDurationUs = timestampUs - lastTimestampUs;
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            lastTimestampUs = timestampUs;
3526158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian            buffer->release();
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            buffer = NULL;
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            continue;
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ++count;
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // adjust time-stamps after pause/resume
3598138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen        if (mResumed) {
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            CHECK_GE(durExcludingEarlierPausesUs, 0ll);
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            CHECK_GE(pausedDurationUs, lastDurationUs);
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mResumed = false;
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        timestampUs -= previousPausedDurationUs;
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CHECK_GE(timestampUs, 0ll);
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int32_t isSync = false;
37117f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian        md->findInt32(kKeyIsSyncFrame, &isSync);
372402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian        const sp<WebmFrame> f = new WebmFrame(
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mType,
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            isSync,
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            timestampUs * 1000 / mTimeCodeScale,
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            buffer);
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSink.push(f);
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ALOGV(
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            "%s %s frame at %" PRId64 " size %zu\n",
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mType == kVideoType ? "video" : "audio",
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            isSync ? "I" : "P",
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            timestampUs * 1000 / mTimeCodeScale,
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            buffer->range_length());
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        buffer->release();
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        buffer = NULL;
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (timestampUs > mTrackDurationUs) {
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTrackDurationUs = timestampUs;
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3921473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian        lastDurationUs = timestampUs - lastTimestampUs;
3931473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian        lastTimestampUs = timestampUs;
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mTrackDurationUs += lastDurationUs;
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mSink.push(WebmFrame::EOS);
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project