blob: af6b66337db85a88c95f60c8daedf0aa7921d7d0 [file] [log] [blame]
//#define LOG_NDEBUG 0
#define LOG_TAG "RepeaterSource"
#include <utils/Log.h>
#include "RepeaterSource.h"
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
namespace android {
RepeaterSource::RepeaterSource(const sp<MediaSource> &source, double rateHz)
: mStarted(false),
mSource(source),
mRateHz(rateHz),
mBuffer(NULL),
mResult(OK),
mLastBufferUpdateUs(-1ll),
mStartTimeUs(-1ll),
mFrameCount(0) {
}
RepeaterSource::~RepeaterSource() {
CHECK(!mStarted);
}
double RepeaterSource::getFrameRate() const {
return mRateHz;
}
void RepeaterSource::setFrameRate(double rateHz) {
Mutex::Autolock autoLock(mLock);
if (rateHz == mRateHz) {
return;
}
if (mStartTimeUs >= 0ll) {
int64_t nextTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
mStartTimeUs = nextTimeUs;
mFrameCount = 0;
}
mRateHz = rateHz;
}
status_t RepeaterSource::start(MetaData *params) {
CHECK(!mStarted);
status_t err = mSource->start(params);
if (err != OK) {
return err;
}
mBuffer = NULL;
mResult = OK;
mStartTimeUs = -1ll;
mFrameCount = 0;
mLooper = new ALooper;
mLooper->setName("repeater_looper");
mLooper->start();
mReflector = new AHandlerReflector<RepeaterSource>(this);
mLooper->registerHandler(mReflector);
postRead();
mStarted = true;
return OK;
}
status_t RepeaterSource::stop() {
CHECK(mStarted);
ALOGV("stopping");
status_t err = mSource->stop();
if (mLooper != NULL) {
mLooper->stop();
mLooper.clear();
mReflector.clear();
}
if (mBuffer != NULL) {
ALOGV("releasing mbuf %p", mBuffer);
mBuffer->release();
mBuffer = NULL;
}
ALOGV("stopped");
mStarted = false;
return err;
}
sp<MetaData> RepeaterSource::getFormat() {
return mSource->getFormat();
}
status_t RepeaterSource::read(
MediaBuffer **buffer, const ReadOptions *options) {
int64_t seekTimeUs;
ReadOptions::SeekMode seekMode;
CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &seekMode));
for (;;) {
int64_t bufferTimeUs = -1ll;
if (mStartTimeUs < 0ll) {
Mutex::Autolock autoLock(mLock);
while ((mLastBufferUpdateUs < 0ll || mBuffer == NULL)
&& mResult == OK) {
mCondition.wait(mLock);
}
ALOGV("now resuming.");
mStartTimeUs = ALooper::GetNowUs();
bufferTimeUs = mStartTimeUs;
} else {
bufferTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
int64_t nowUs = ALooper::GetNowUs();
int64_t delayUs = bufferTimeUs - nowUs;
if (delayUs > 0ll) {
usleep(delayUs);
}
}
bool stale = false;
{
Mutex::Autolock autoLock(mLock);
if (mResult != OK) {
CHECK(mBuffer == NULL);
return mResult;
}
#if SUSPEND_VIDEO_IF_IDLE
int64_t nowUs = ALooper::GetNowUs();
if (nowUs - mLastBufferUpdateUs > 1000000ll) {
mLastBufferUpdateUs = -1ll;
stale = true;
} else
#endif
{
mBuffer->add_ref();
*buffer = mBuffer;
(*buffer)->meta_data()->setInt64(kKeyTime, bufferTimeUs);
++mFrameCount;
}
}
if (!stale) {
break;
}
mStartTimeUs = -1ll;
mFrameCount = 0;
ALOGV("now dormant");
}
return OK;
}
void RepeaterSource::postRead() {
(new AMessage(kWhatRead, mReflector))->post();
}
void RepeaterSource::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatRead:
{
MediaBuffer *buffer;
status_t err = mSource->read(&buffer);
ALOGV("read mbuf %p", buffer);
Mutex::Autolock autoLock(mLock);
if (mBuffer != NULL) {
mBuffer->release();
mBuffer = NULL;
}
mBuffer = buffer;
mResult = err;
mLastBufferUpdateUs = ALooper::GetNowUs();
mCondition.broadcast();
if (err == OK) {
postRead();
}
break;
}
default:
TRESPASS();
}
}
void RepeaterSource::wakeUp() {
ALOGV("wakeUp");
Mutex::Autolock autoLock(mLock);
if (mLastBufferUpdateUs < 0ll && mBuffer != NULL) {
mLastBufferUpdateUs = ALooper::GetNowUs();
mCondition.broadcast();
}
}
} // namespace android