1//#define LOG_NDEBUG 0
2#define LOG_TAG "RepeaterSource"
3#include <utils/Log.h>
4
5#include "RepeaterSource.h"
6
7#include <media/stagefright/foundation/ADebug.h>
8#include <media/stagefright/foundation/ALooper.h>
9#include <media/stagefright/foundation/AMessage.h>
10#include <media/stagefright/MediaBuffer.h>
11#include <media/stagefright/MetaData.h>
12
13namespace android {
14
15RepeaterSource::RepeaterSource(const sp<MediaSource> &source, double rateHz)
16    : mStarted(false),
17      mSource(source),
18      mRateHz(rateHz),
19      mBuffer(NULL),
20      mResult(OK),
21      mLastBufferUpdateUs(-1ll),
22      mStartTimeUs(-1ll),
23      mFrameCount(0) {
24}
25
26RepeaterSource::~RepeaterSource() {
27    CHECK(!mStarted);
28}
29
30double RepeaterSource::getFrameRate() const {
31    return mRateHz;
32}
33
34void RepeaterSource::setFrameRate(double rateHz) {
35    Mutex::Autolock autoLock(mLock);
36
37    if (rateHz == mRateHz) {
38        return;
39    }
40
41    if (mStartTimeUs >= 0ll) {
42        int64_t nextTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
43        mStartTimeUs = nextTimeUs;
44        mFrameCount = 0;
45    }
46    mRateHz = rateHz;
47}
48
49status_t RepeaterSource::start(MetaData *params) {
50    CHECK(!mStarted);
51
52    status_t err = mSource->start(params);
53
54    if (err != OK) {
55        return err;
56    }
57
58    mBuffer = NULL;
59    mResult = OK;
60    mStartTimeUs = -1ll;
61    mFrameCount = 0;
62
63    mLooper = new ALooper;
64    mLooper->setName("repeater_looper");
65    mLooper->start();
66
67    mReflector = new AHandlerReflector<RepeaterSource>(this);
68    mLooper->registerHandler(mReflector);
69
70    postRead();
71
72    mStarted = true;
73
74    return OK;
75}
76
77status_t RepeaterSource::stop() {
78    CHECK(mStarted);
79
80    ALOGV("stopping");
81
82    if (mLooper != NULL) {
83        mLooper->stop();
84        mLooper.clear();
85
86        mReflector.clear();
87    }
88
89    if (mBuffer != NULL) {
90        ALOGV("releasing mbuf %p", mBuffer);
91        mBuffer->release();
92        mBuffer = NULL;
93    }
94
95    status_t err = mSource->stop();
96
97    ALOGV("stopped");
98
99    mStarted = false;
100
101    return err;
102}
103
104sp<MetaData> RepeaterSource::getFormat() {
105    return mSource->getFormat();
106}
107
108status_t RepeaterSource::read(
109        MediaBuffer **buffer, const ReadOptions *options) {
110    int64_t seekTimeUs;
111    ReadOptions::SeekMode seekMode;
112    CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &seekMode));
113
114    for (;;) {
115        int64_t bufferTimeUs = -1ll;
116
117        if (mStartTimeUs < 0ll) {
118            Mutex::Autolock autoLock(mLock);
119            while ((mLastBufferUpdateUs < 0ll || mBuffer == NULL)
120                    && mResult == OK) {
121                mCondition.wait(mLock);
122            }
123
124            ALOGV("now resuming.");
125            mStartTimeUs = ALooper::GetNowUs();
126            bufferTimeUs = mStartTimeUs;
127        } else {
128            bufferTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
129
130            int64_t nowUs = ALooper::GetNowUs();
131            int64_t delayUs = bufferTimeUs - nowUs;
132
133            if (delayUs > 0ll) {
134                usleep(delayUs);
135            }
136        }
137
138        bool stale = false;
139
140        {
141            Mutex::Autolock autoLock(mLock);
142            if (mResult != OK) {
143                CHECK(mBuffer == NULL);
144                return mResult;
145            }
146
147#if SUSPEND_VIDEO_IF_IDLE
148            int64_t nowUs = ALooper::GetNowUs();
149            if (nowUs - mLastBufferUpdateUs > 1000000ll) {
150                mLastBufferUpdateUs = -1ll;
151                stale = true;
152            } else
153#endif
154            {
155                mBuffer->add_ref();
156                *buffer = mBuffer;
157                (*buffer)->meta_data()->setInt64(kKeyTime, bufferTimeUs);
158                ++mFrameCount;
159            }
160        }
161
162        if (!stale) {
163            break;
164        }
165
166        mStartTimeUs = -1ll;
167        mFrameCount = 0;
168        ALOGV("now dormant");
169    }
170
171    return OK;
172}
173
174void RepeaterSource::postRead() {
175    (new AMessage(kWhatRead, mReflector->id()))->post();
176}
177
178void RepeaterSource::onMessageReceived(const sp<AMessage> &msg) {
179    switch (msg->what()) {
180        case kWhatRead:
181        {
182            MediaBuffer *buffer;
183            status_t err = mSource->read(&buffer);
184
185            ALOGV("read mbuf %p", buffer);
186
187            Mutex::Autolock autoLock(mLock);
188            if (mBuffer != NULL) {
189                mBuffer->release();
190                mBuffer = NULL;
191            }
192            mBuffer = buffer;
193            mResult = err;
194            mLastBufferUpdateUs = ALooper::GetNowUs();
195
196            mCondition.broadcast();
197
198            if (err == OK) {
199                postRead();
200            }
201            break;
202        }
203
204        default:
205            TRESPASS();
206    }
207}
208
209void RepeaterSource::wakeUp() {
210    ALOGV("wakeUp");
211    Mutex::Autolock autoLock(mLock);
212    if (mLastBufferUpdateUs < 0ll && mBuffer != NULL) {
213        mLastBufferUpdateUs = ALooper::GetNowUs();
214        mCondition.broadcast();
215    }
216}
217
218}  // namespace android
219