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