//#define LOG_NDEBUG 0 #define LOG_TAG "RepeaterSource" #include #include "RepeaterSource.h" #include #include #include #include #include namespace android { RepeaterSource::RepeaterSource(const sp &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(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 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 &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