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
13 namespace android {
14
RepeaterSource(const sp<MediaSource> & source,double rateHz)15 RepeaterSource::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
~RepeaterSource()26 RepeaterSource::~RepeaterSource() {
27 CHECK(!mStarted);
28 }
29
getFrameRate() const30 double RepeaterSource::getFrameRate() const {
31 return mRateHz;
32 }
33
setFrameRate(double rateHz)34 void 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
start(MetaData * params)49 status_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
stop()77 status_t RepeaterSource::stop() {
78 CHECK(mStarted);
79
80 ALOGV("stopping");
81
82 status_t err = mSource->stop();
83
84 if (mLooper != NULL) {
85 mLooper->stop();
86 mLooper.clear();
87
88 mReflector.clear();
89 }
90
91 if (mBuffer != NULL) {
92 ALOGV("releasing mbuf %p", mBuffer);
93 mBuffer->release();
94 mBuffer = NULL;
95 }
96
97
98 ALOGV("stopped");
99
100 mStarted = false;
101
102 return err;
103 }
104
getFormat()105 sp<MetaData> RepeaterSource::getFormat() {
106 return mSource->getFormat();
107 }
108
read(MediaBuffer ** buffer,const ReadOptions * options)109 status_t RepeaterSource::read(
110 MediaBuffer **buffer, const ReadOptions *options) {
111 int64_t seekTimeUs;
112 ReadOptions::SeekMode seekMode;
113 CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &seekMode));
114
115 for (;;) {
116 int64_t bufferTimeUs = -1ll;
117
118 if (mStartTimeUs < 0ll) {
119 Mutex::Autolock autoLock(mLock);
120 while ((mLastBufferUpdateUs < 0ll || mBuffer == NULL)
121 && mResult == OK) {
122 mCondition.wait(mLock);
123 }
124
125 ALOGV("now resuming.");
126 mStartTimeUs = ALooper::GetNowUs();
127 bufferTimeUs = mStartTimeUs;
128 } else {
129 bufferTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
130
131 int64_t nowUs = ALooper::GetNowUs();
132 int64_t delayUs = bufferTimeUs - nowUs;
133
134 if (delayUs > 0ll) {
135 usleep(delayUs);
136 }
137 }
138
139 bool stale = false;
140
141 {
142 Mutex::Autolock autoLock(mLock);
143 if (mResult != OK) {
144 CHECK(mBuffer == NULL);
145 return mResult;
146 }
147
148 #if SUSPEND_VIDEO_IF_IDLE
149 int64_t nowUs = ALooper::GetNowUs();
150 if (nowUs - mLastBufferUpdateUs > 1000000ll) {
151 mLastBufferUpdateUs = -1ll;
152 stale = true;
153 } else
154 #endif
155 {
156 mBuffer->add_ref();
157 *buffer = mBuffer;
158 (*buffer)->meta_data()->setInt64(kKeyTime, bufferTimeUs);
159 ++mFrameCount;
160 }
161 }
162
163 if (!stale) {
164 break;
165 }
166
167 mStartTimeUs = -1ll;
168 mFrameCount = 0;
169 ALOGV("now dormant");
170 }
171
172 return OK;
173 }
174
postRead()175 void RepeaterSource::postRead() {
176 (new AMessage(kWhatRead, mReflector))->post();
177 }
178
onMessageReceived(const sp<AMessage> & msg)179 void RepeaterSource::onMessageReceived(const sp<AMessage> &msg) {
180 switch (msg->what()) {
181 case kWhatRead:
182 {
183 MediaBuffer *buffer;
184 status_t err = mSource->read(&buffer);
185
186 ALOGV("read mbuf %p", buffer);
187
188 Mutex::Autolock autoLock(mLock);
189 if (mBuffer != NULL) {
190 mBuffer->release();
191 mBuffer = NULL;
192 }
193 mBuffer = buffer;
194 mResult = err;
195 mLastBufferUpdateUs = ALooper::GetNowUs();
196
197 mCondition.broadcast();
198
199 if (err == OK) {
200 postRead();
201 }
202 break;
203 }
204
205 default:
206 TRESPASS();
207 }
208 }
209
wakeUp()210 void RepeaterSource::wakeUp() {
211 ALOGV("wakeUp");
212 Mutex::Autolock autoLock(mLock);
213 if (mLastBufferUpdateUs < 0ll && mBuffer != NULL) {
214 mLastBufferUpdateUs = ALooper::GetNowUs();
215 mCondition.broadcast();
216 }
217 }
218
219 } // namespace android
220