mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1030007 - Throttle updating the preview window when CPU low and/or encoder falls behind. r=mikeh, r=cpearce
This commit is contained in:
parent
9213c02ced
commit
072944be8a
@ -66,15 +66,22 @@ nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void MediaOmxReader::Shutdown()
|
||||
void MediaOmxReader::ReleaseDecoder()
|
||||
{
|
||||
ReleaseMediaResources();
|
||||
if (mOmxDecoder.get()) {
|
||||
mOmxDecoder->ReleaseDecoder();
|
||||
}
|
||||
mOmxDecoder.clear();
|
||||
}
|
||||
|
||||
void MediaOmxReader::Shutdown()
|
||||
{
|
||||
ReleaseMediaResources();
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &MediaOmxReader::ReleaseDecoder);
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
||||
bool MediaOmxReader::IsWaitingMediaResources()
|
||||
{
|
||||
if (!mOmxDecoder.get()) {
|
||||
|
@ -104,6 +104,8 @@ public:
|
||||
// ANDROID_VERSION < 19
|
||||
void CheckAudioOffload();
|
||||
#endif
|
||||
|
||||
void ReleaseDecoder();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -248,6 +248,20 @@ CameraControlImpl::OnPreviewStateChange(CameraControlListener::PreviewState aNew
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CameraControlImpl::OnRateLimitPreview(bool aLimit)
|
||||
{
|
||||
// This function runs on neither the Main Thread nor the Camera Thread.
|
||||
RwLockAutoEnterRead lock(mListenerLock);
|
||||
|
||||
DOM_CAMERA_LOGI("OnRateLimitPreview: %d\n", aLimit);
|
||||
|
||||
for (uint32_t i = 0; i < mListeners.Length(); ++i) {
|
||||
CameraControlListener* l = mListeners[i];
|
||||
l->OnRateLimitPreview(aLimit);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CameraControlImpl::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight)
|
||||
{
|
||||
|
@ -67,6 +67,7 @@ protected:
|
||||
void OnFacesDetected(const nsTArray<Face>& aFaces);
|
||||
void OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType);
|
||||
|
||||
void OnRateLimitPreview(bool aLimit);
|
||||
bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight);
|
||||
void OnRecorderStateChange(CameraControlListener::RecorderState aState,
|
||||
int32_t aStatus = -1, int32_t aTrackNumber = -1);
|
||||
|
@ -64,6 +64,7 @@ public:
|
||||
virtual void OnRecorderStateChange(RecorderState aState, int32_t aStatus, int32_t aTrackNum) { }
|
||||
|
||||
virtual void OnShutter() { }
|
||||
virtual void OnRateLimitPreview(bool aLimit) { }
|
||||
virtual bool OnNewPreviewFrame(layers::Image* aFrame, uint32_t aWidth, uint32_t aHeight)
|
||||
{
|
||||
return false;
|
||||
|
@ -4,6 +4,15 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CameraPreviewMediaStream.h"
|
||||
#include "CameraCommon.h"
|
||||
|
||||
/**
|
||||
* Maximum number of outstanding invalidates before we start to drop frames;
|
||||
* if we hit this threshold, it is an indicator that the main thread is
|
||||
* either very busy or the device is busy elsewhere (e.g. encoding or
|
||||
* persisting video data).
|
||||
*/
|
||||
#define MAX_INVALIDATE_PENDING 4
|
||||
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::dom;
|
||||
@ -13,7 +22,9 @@ namespace mozilla {
|
||||
CameraPreviewMediaStream::CameraPreviewMediaStream(DOMMediaStream* aWrapper)
|
||||
: MediaStream(aWrapper)
|
||||
, mMutex("mozilla::camera::CameraPreviewMediaStream")
|
||||
, mFrameCallback(nullptr)
|
||||
, mInvalidatePending(0)
|
||||
, mDiscardedFrames(0)
|
||||
, mRateLimit(false)
|
||||
{
|
||||
SetGraphImpl(MediaStreamGraph::GetInstance());
|
||||
mIsConsumed = false;
|
||||
@ -103,22 +114,53 @@ CameraPreviewMediaStream::Destroy()
|
||||
}
|
||||
|
||||
void
|
||||
CameraPreviewMediaStream::SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage)
|
||||
CameraPreviewMediaStream::Invalidate()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
for (uint32_t i = 0; i < mVideoOutputs.Length(); ++i) {
|
||||
--mInvalidatePending;
|
||||
for (nsTArray<nsRefPtr<VideoFrameContainer> >::size_type i = 0; i < mVideoOutputs.Length(); ++i) {
|
||||
VideoFrameContainer* output = mVideoOutputs[i];
|
||||
output->SetCurrentFrame(aIntrinsicSize, aImage, now);
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(output, &VideoFrameContainer::Invalidate);
|
||||
NS_DispatchToMainThread(event);
|
||||
output->Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CameraPreviewMediaStream::RateLimit(bool aLimit)
|
||||
{
|
||||
mRateLimit = aLimit;
|
||||
}
|
||||
|
||||
void
|
||||
CameraPreviewMediaStream::SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage)
|
||||
{
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (mInvalidatePending > 0) {
|
||||
if (mRateLimit || mInvalidatePending > MAX_INVALIDATE_PENDING) {
|
||||
++mDiscardedFrames;
|
||||
DOM_CAMERA_LOGW("Discard preview frame %d, %d invalidation(s) pending",
|
||||
mDiscardedFrames, mInvalidatePending);
|
||||
return;
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGI("Update preview frame, %d invalidation(s) pending",
|
||||
mInvalidatePending);
|
||||
}
|
||||
mDiscardedFrames = 0;
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
for (nsTArray<nsRefPtr<VideoFrameContainer> >::size_type i = 0; i < mVideoOutputs.Length(); ++i) {
|
||||
VideoFrameContainer* output = mVideoOutputs[i];
|
||||
output->SetCurrentFrame(aIntrinsicSize, aImage, now);
|
||||
}
|
||||
|
||||
++mInvalidatePending;
|
||||
}
|
||||
|
||||
if (mFrameCallback) {
|
||||
mFrameCallback->OnNewFrame(aIntrinsicSize, aImage);
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &CameraPreviewMediaStream::Invalidate);
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
||||
void
|
||||
@ -126,7 +168,7 @@ CameraPreviewMediaStream::ClearCurrentFrame()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
for (uint32_t i = 0; i < mVideoOutputs.Length(); ++i) {
|
||||
for (nsTArray<nsRefPtr<VideoFrameContainer> >::size_type i = 0; i < mVideoOutputs.Length(); ++i) {
|
||||
VideoFrameContainer* output = mVideoOutputs[i];
|
||||
output->ClearCurrentFrame();
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
|
@ -11,13 +11,8 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CameraPreviewFrameCallback {
|
||||
public:
|
||||
virtual void OnNewFrame(const gfxIntSize& aIntrinsicSize, layers::Image* aImage) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a stream for camere preview.
|
||||
* This is a stream for camera preview.
|
||||
*
|
||||
* XXX It is a temporary fix of SourceMediaStream.
|
||||
* A camera preview requests no delay and no buffering stream.
|
||||
@ -40,20 +35,21 @@ public:
|
||||
virtual void RemoveListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
|
||||
virtual void Destroy();
|
||||
|
||||
void Invalidate();
|
||||
|
||||
// Call these on any thread.
|
||||
void SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage);
|
||||
void ClearCurrentFrame();
|
||||
|
||||
void SetFrameCallback(CameraPreviewFrameCallback* aCallback) {
|
||||
mFrameCallback = aCallback;
|
||||
}
|
||||
void RateLimit(bool aLimit);
|
||||
|
||||
protected:
|
||||
// mMutex protects all the class' fields.
|
||||
// This class is not registered to MediaStreamGraph.
|
||||
// It needs to protect all the fields.
|
||||
Mutex mMutex;
|
||||
CameraPreviewFrameCallback* mFrameCallback;
|
||||
int32_t mInvalidatePending;
|
||||
uint32_t mDiscardedFrames;
|
||||
bool mRateLimit;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ protected:
|
||||
DOMCameraControlListener* mListener;
|
||||
|
||||
// our viewfinder stream
|
||||
CameraPreviewMediaStream* mInput;
|
||||
nsRefPtr<CameraPreviewMediaStream> mInput;
|
||||
|
||||
// set once when this object is created
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
@ -287,6 +287,12 @@ DOMCameraControlListener::OnShutter()
|
||||
NS_DispatchToMainThread(new Callback(mDOMCameraControl));
|
||||
}
|
||||
|
||||
void
|
||||
DOMCameraControlListener::OnRateLimitPreview(bool aLimit)
|
||||
{
|
||||
mStream->RateLimit(aLimit);
|
||||
}
|
||||
|
||||
bool
|
||||
DOMCameraControlListener::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight)
|
||||
{
|
||||
|
@ -28,6 +28,7 @@ public:
|
||||
virtual void OnRecorderStateChange(RecorderState aState, int32_t aStatus, int32_t aTrackNum) MOZ_OVERRIDE;
|
||||
virtual void OnConfigurationChange(const CameraListenerConfiguration& aConfiguration) MOZ_OVERRIDE;
|
||||
virtual void OnShutter() MOZ_OVERRIDE;
|
||||
virtual void OnRateLimitPreview(bool aLimit) MOZ_OVERRIDE;
|
||||
virtual bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) MOZ_OVERRIDE;
|
||||
virtual void OnUserError(UserContext aContext, nsresult aError) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -1682,6 +1682,12 @@ nsGonkCameraControl::GetRecorderProfileManagerImpl()
|
||||
return profileMgr.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsGonkCameraControl::OnRateLimitPreview(bool aLimit)
|
||||
{
|
||||
CameraControlImpl::OnRateLimitPreview(aLimit);
|
||||
}
|
||||
|
||||
void
|
||||
nsGonkCameraControl::OnNewPreviewFrame(layers::TextureClient* aBuffer)
|
||||
{
|
||||
@ -1744,6 +1750,12 @@ OnFacesDetected(nsGonkCameraControl* gc, camera_frame_metadata_t* aMetaData)
|
||||
gc->OnFacesDetected(aMetaData);
|
||||
}
|
||||
|
||||
void
|
||||
OnRateLimitPreview(nsGonkCameraControl* gc, bool aLimit)
|
||||
{
|
||||
gc->OnRateLimitPreview(aLimit);
|
||||
}
|
||||
|
||||
void
|
||||
OnNewPreviewFrame(nsGonkCameraControl* gc, layers::TextureClient* aBuffer)
|
||||
{
|
||||
|
@ -52,10 +52,11 @@ public:
|
||||
void OnFacesDetected(camera_frame_metadata_t* aMetaData);
|
||||
void OnTakePictureComplete(uint8_t* aData, uint32_t aLength);
|
||||
void OnTakePictureError();
|
||||
void OnRateLimitPreview(bool aLimit);
|
||||
void OnNewPreviewFrame(layers::TextureClient* aBuffer);
|
||||
void OnRecorderEvent(int msg, int ext1, int ext2);
|
||||
void OnSystemError(CameraControlListener::SystemContext aWhere, nsresult aError);
|
||||
|
||||
|
||||
// See ICameraControl.h for getter/setter return values.
|
||||
virtual nsresult Set(uint32_t aKey, const nsAString& aValue) MOZ_OVERRIDE;
|
||||
virtual nsresult Get(uint32_t aKey, nsAString& aValue) MOZ_OVERRIDE;
|
||||
@ -84,6 +85,7 @@ public:
|
||||
protected:
|
||||
~nsGonkCameraControl();
|
||||
|
||||
using CameraControlImpl::OnRateLimitPreview;
|
||||
using CameraControlImpl::OnNewPreviewFrame;
|
||||
using CameraControlImpl::OnAutoFocusComplete;
|
||||
using CameraControlImpl::OnFacesDetected;
|
||||
@ -178,6 +180,7 @@ private:
|
||||
};
|
||||
|
||||
// camera driver callbacks
|
||||
void OnRateLimitPreview(nsGonkCameraControl* gc, bool aLimit);
|
||||
void OnTakePictureComplete(nsGonkCameraControl* gc, uint8_t* aData, uint32_t aLength);
|
||||
void OnTakePictureError(nsGonkCameraControl* gc);
|
||||
void OnAutoFocusComplete(nsGonkCameraControl* gc, bool aSuccess);
|
||||
|
@ -44,6 +44,12 @@ GonkCameraHardware::GonkCameraHardware(mozilla::nsGonkCameraControl* aTarget, ui
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n", __func__, __LINE__, (void*)this, (void*)aTarget);
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraHardware::OnRateLimitPreview(bool aLimit)
|
||||
{
|
||||
::OnRateLimitPreview(mTarget, aLimit);
|
||||
}
|
||||
|
||||
void
|
||||
GonkCameraHardware::OnNewFrame()
|
||||
{
|
||||
|
@ -55,6 +55,8 @@ public:
|
||||
static sp<GonkCameraHardware> Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId);
|
||||
virtual void Close();
|
||||
|
||||
virtual void OnRateLimitPreview(bool aLimit);
|
||||
|
||||
// derived from GonkNativeWindowNewFrameCallback
|
||||
virtual void OnNewFrame() MOZ_OVERRIDE;
|
||||
|
||||
|
@ -170,6 +170,7 @@ GonkCameraSource::GonkCameraSource(
|
||||
mStarted(false),
|
||||
mNumFramesEncoded(0),
|
||||
mTimeBetweenFrameCaptureUs(0),
|
||||
mRateLimit(false),
|
||||
mFirstFrameTimeUs(0),
|
||||
mNumFramesDropped(0),
|
||||
mNumGlitches(0),
|
||||
@ -589,6 +590,10 @@ status_t GonkCameraSource::reset() {
|
||||
}
|
||||
}
|
||||
stopCameraRecording();
|
||||
if (mRateLimit) {
|
||||
mRateLimit = false;
|
||||
mCameraHw->OnRateLimitPreview(false);
|
||||
}
|
||||
releaseCamera();
|
||||
|
||||
if (mCollectStats) {
|
||||
@ -692,51 +697,65 @@ status_t GonkCameraSource::read(
|
||||
|
||||
void GonkCameraSource::dataCallbackTimestamp(int64_t timestampUs,
|
||||
int32_t msgType, const sp<IMemory> &data) {
|
||||
bool rateLimit;
|
||||
bool prevRateLimit;
|
||||
CS_LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
|
||||
CS_LOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs);
|
||||
releaseOneRecordingFrame(data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mNumFramesReceived > 0) {
|
||||
CHECK(timestampUs > mLastFrameTimestampUs);
|
||||
if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
|
||||
++mNumGlitches;
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
|
||||
CS_LOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs);
|
||||
releaseOneRecordingFrame(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// May need to skip frame or modify timestamp. Currently implemented
|
||||
// by the subclass CameraSourceTimeLapse.
|
||||
if (skipCurrentFrame(timestampUs)) {
|
||||
releaseOneRecordingFrame(data);
|
||||
return;
|
||||
}
|
||||
|
||||
mLastFrameTimestampUs = timestampUs;
|
||||
if (mNumFramesReceived == 0) {
|
||||
mFirstFrameTimeUs = timestampUs;
|
||||
// Initial delay
|
||||
if (mStartTimeUs > 0) {
|
||||
if (timestampUs < mStartTimeUs) {
|
||||
// Frame was captured before recording was started
|
||||
// Drop it without updating the statistical data.
|
||||
releaseOneRecordingFrame(data);
|
||||
return;
|
||||
if (mNumFramesReceived > 0) {
|
||||
CHECK(timestampUs > mLastFrameTimestampUs);
|
||||
if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
|
||||
++mNumGlitches;
|
||||
}
|
||||
mStartTimeUs = timestampUs - mStartTimeUs;
|
||||
}
|
||||
}
|
||||
++mNumFramesReceived;
|
||||
|
||||
CHECK(data != NULL && data->size() > 0);
|
||||
mFramesReceived.push_back(data);
|
||||
int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
|
||||
mFrameTimes.push_back(timeUs);
|
||||
CS_LOGV("initial delay: %lld, current time stamp: %lld",
|
||||
mStartTimeUs, timeUs);
|
||||
mFrameAvailableCondition.signal();
|
||||
// May need to skip frame or modify timestamp. Currently implemented
|
||||
// by the subclass CameraSourceTimeLapse.
|
||||
if (skipCurrentFrame(timestampUs)) {
|
||||
releaseOneRecordingFrame(data);
|
||||
return;
|
||||
}
|
||||
|
||||
mLastFrameTimestampUs = timestampUs;
|
||||
if (mNumFramesReceived == 0) {
|
||||
mFirstFrameTimeUs = timestampUs;
|
||||
// Initial delay
|
||||
if (mStartTimeUs > 0) {
|
||||
if (timestampUs < mStartTimeUs) {
|
||||
// Frame was captured before recording was started
|
||||
// Drop it without updating the statistical data.
|
||||
releaseOneRecordingFrame(data);
|
||||
return;
|
||||
}
|
||||
mStartTimeUs = timestampUs - mStartTimeUs;
|
||||
}
|
||||
}
|
||||
++mNumFramesReceived;
|
||||
|
||||
// If a backlog is building up in the receive queue, we are likely
|
||||
// resource constrained and we need to throttle
|
||||
prevRateLimit = mRateLimit;
|
||||
rateLimit = mFramesReceived.empty();
|
||||
mRateLimit = rateLimit;
|
||||
|
||||
CHECK(data != NULL && data->size() > 0);
|
||||
mFramesReceived.push_back(data);
|
||||
int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
|
||||
mFrameTimes.push_back(timeUs);
|
||||
CS_LOGV("initial delay: %lld, current time stamp: %lld",
|
||||
mStartTimeUs, timeUs);
|
||||
mFrameAvailableCondition.signal();
|
||||
}
|
||||
|
||||
if(prevRateLimit != rateLimit) {
|
||||
mCameraHw->OnRateLimitPreview(rateLimit);
|
||||
}
|
||||
}
|
||||
|
||||
bool GonkCameraSource::isMetaDataStoredInVideoBuffers() const {
|
||||
|
@ -127,6 +127,7 @@ private:
|
||||
List<sp<IMemory> > mFramesReceived;
|
||||
List<sp<IMemory> > mFramesBeingEncoded;
|
||||
List<int64_t> mFrameTimes;
|
||||
bool mRateLimit;
|
||||
|
||||
int64_t mFirstFrameTimeUs;
|
||||
int32_t mNumFramesDropped;
|
||||
|
Loading…
Reference in New Issue
Block a user