Bug 970183: Support phone rotation in gUM at start of capture r=slee,cjku,jesup

This commit is contained in:
Steven Lee 2014-02-25 02:22:36 -05:00
Родитель e3b7eb3c59
Коммит 4ebfd597ee
2 изменённых файлов: 100 добавлений и 21 удалений

Просмотреть файл

@ -51,6 +51,7 @@
#include "ImageContainer.h"
#include "nsGlobalWindow.h"
#include "prprf.h"
#include "mozilla/Hal.h"
#endif
#include "NullTransport.h"
@ -83,6 +84,7 @@ class MediaEngineWebRTCVideoSource : public MediaEngineVideoSource
, public nsRunnable
#ifdef MOZ_B2G_CAMERA
, public CameraControlListener
, public mozilla::hal::ScreenConfigurationObserver
#else
, public webrtc::ExternalRenderer
#endif
@ -92,7 +94,8 @@ public:
MediaEngineWebRTCVideoSource(int aIndex)
: mCameraControl(nullptr)
, mCallbackMonitor("WebRTCCamera.CallbackMonitor")
, mSensorAngle(0)
, mRotation(0)
, mBackCamera(false)
, mCaptureIndex(aIndex)
, mMonitor("WebRTCCamera.Monitor")
, mWidth(0)
@ -172,7 +175,8 @@ public:
void StartImpl(webrtc::CaptureCapability aCapability);
void StopImpl();
void SnapshotImpl();
void RotateImage(layers::Image* aImage);
void RotateImage(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight);
void Notify(const mozilla::hal::ScreenConfiguration& aConfiguration);
#endif
// This runnable is for creating a temporary file on the main thread.
@ -207,7 +211,9 @@ private:
nsRefPtr<ICameraControl> mCameraControl;
mozilla::ReentrantMonitor mCallbackMonitor; // Monitor for camera callback handling
nsRefPtr<nsIDOMFile> mLastCapture;
int mSensorAngle;
int mRotation;
int mCameraAngle; // See dom/base/ScreenOrientation.h
bool mBackCamera;
#else
webrtc::VideoEngine* mVideoEngine; // Weak reference, don't free.
webrtc::ViEBase* mViEBase;

Просмотреть файл

@ -12,6 +12,9 @@
#ifdef MOZ_B2G_CAMERA
#include "GrallocImages.h"
#include "libyuv.h"
#include "mozilla/Hal.h"
#include "ScreenOrientation.h"
using namespace mozilla::dom;
#endif
namespace mozilla {
@ -137,7 +140,7 @@ MediaEngineWebRTCVideoSource::NotifyPull(MediaStreamGraph* aGraph,
nsRefPtr<layers::Image> image = mImage;
TrackTicks target = TimeToTicksRoundUp(USECS_PER_S, aDesiredTime);
TrackTicks delta = target - aLastEndTime;
LOGFRAME(("NotifyPull, desired = %ld, target = %ld, delta = %ld %s", (int64_t) aDesiredTime,
LOGFRAME(("NotifyPull, desired = %ld, target = %ld, delta = %ld %s", (int64_t) aDesiredTime,
(int64_t) target, (int64_t) delta, image ? "" : "<null>"));
// Bug 846188 We may want to limit incoming frames to the requested frame rate
@ -512,6 +515,7 @@ MediaEngineWebRTCVideoSource::AllocImpl() {
// in DeallocImpl() will do that for us.
mCameraControl->AddListener(this);
}
mCallbackMonitor.Notify();
}
@ -522,6 +526,54 @@ MediaEngineWebRTCVideoSource::DeallocImpl() {
mCameraControl = nullptr;
}
// The same algorithm from bug 840244
static int
GetRotateAmount(ScreenOrientation aScreen, int aCameraMountAngle, bool aBackCamera) {
int screenAngle = 0;
switch (aScreen) {
case eScreenOrientation_PortraitPrimary:
screenAngle = 0;
break;
case eScreenOrientation_PortraitSecondary:
screenAngle = 180;
break;
case eScreenOrientation_LandscapePrimary:
screenAngle = 90;
break;
case eScreenOrientation_LandscapeSecondary:
screenAngle = 270;
break;
default:
MOZ_ASSERT(false);
break;
}
int result;
if (aBackCamera) {
//back camera
result = (aCameraMountAngle - screenAngle + 360) % 360;
} else {
//front camera
result = (aCameraMountAngle + screenAngle) % 360;
}
return result;
}
// undefine to remove on-the-fly rotation support
// #define DYNAMIC_GUM_ROTATION
void
MediaEngineWebRTCVideoSource::Notify(const hal::ScreenConfiguration& aConfiguration) {
#ifdef DYNAMIC_GUM_ROTATION
MonitorAutoLock enter(mMonitor);
mRotation = GetRotateAmount(aConfiguration.orientation(), mCameraAngle, mBackCamera);
LOG(("*** New orientation: %d (Camera %d Back %d MountAngle: %d)",
mRotation, mCaptureIndex, mBackCamera, mCameraAngle));
#endif
}
void
MediaEngineWebRTCVideoSource::StartImpl(webrtc::CaptureCapability aCapability) {
MOZ_ASSERT(NS_IsMainThread());
@ -532,14 +584,15 @@ MediaEngineWebRTCVideoSource::StartImpl(webrtc::CaptureCapability aCapability) {
config.mPreviewSize.height = aCapability.height;
mCameraControl->Start(&config);
mCameraControl->Set(CAMERA_PARAM_PICTURESIZE, config.mPreviewSize);
mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, mSensorAngle);
MOZ_ASSERT(mSensorAngle >= 0 && mSensorAngle < 360);
hal::RegisterScreenConfigurationObserver(this);
}
void
MediaEngineWebRTCVideoSource::StopImpl() {
MOZ_ASSERT(NS_IsMainThread());
hal::UnregisterScreenConfigurationObserver(this);
mCameraControl->Stop();
}
@ -563,6 +616,21 @@ MediaEngineWebRTCVideoSource::OnHardwareStateChange(HardwareState aState)
mCallbackMonitor.Notify();
}
} else {
mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, mCameraAngle);
MOZ_ASSERT(mCameraAngle == 0 || mCameraAngle == 90 || mCameraAngle == 180 ||
mCameraAngle == 270);
hal::ScreenConfiguration aConfig;
hal::GetCurrentScreenConfiguration(&aConfig);
nsCString deviceName;
ICameraControl::GetCameraName(mCaptureIndex, deviceName);
if (deviceName.EqualsASCII("back")) {
mBackCamera = true;
}
mRotation = GetRotateAmount(aConfig.orientation(), mCameraAngle, mBackCamera);
LOG(("*** Initial orientation: %d (Camera %d Back %d MountAngle: %d)",
mRotation, mCaptureIndex, mBackCamera, mCameraAngle));
mState = kStarted;
mCallbackMonitor.Notify();
}
@ -587,13 +655,13 @@ MediaEngineWebRTCVideoSource::OnTakePictureComplete(uint8_t* aData, uint32_t aLe
}
void
MediaEngineWebRTCVideoSource::RotateImage(layers::Image* aImage) {
MediaEngineWebRTCVideoSource::RotateImage(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) {
layers::GrallocImage *nativeImage = static_cast<layers::GrallocImage*>(aImage);
layers::SurfaceDescriptor handle = nativeImage->GetSurfaceDescriptor();
layers::SurfaceDescriptorGralloc grallocHandle = handle.get_SurfaceDescriptorGralloc();
android::sp<android::GraphicBuffer> graphicBuffer = layers::GrallocBufferActor::GetFrom(grallocHandle);
void *pMem = nullptr;
uint32_t size = mWidth * mHeight * 3 / 2;
uint32_t size = aWidth * aHeight * 3 / 2;
graphicBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_MASK, &pMem);
@ -602,12 +670,15 @@ MediaEngineWebRTCVideoSource::RotateImage(layers::Image* aImage) {
nsRefPtr<layers::Image> image = mImageContainer->CreateImage(ImageFormat::PLANAR_YCBCR);
layers::PlanarYCbCrImage* videoImage = static_cast<layers::PlanarYCbCrImage*>(image.get());
uint32_t dstWidth = mWidth;
uint32_t dstHeight = mHeight;
uint32_t dstWidth;
uint32_t dstHeight;
if (mSensorAngle == 90 || mSensorAngle == 270) {
dstWidth = mHeight;
dstHeight = mWidth;
if (mRotation == 90 || mRotation == 270) {
dstWidth = aHeight;
dstHeight = aWidth;
} else {
dstWidth = aWidth;
dstHeight = aHeight;
}
uint32_t half_width = dstWidth / 2;
@ -617,9 +688,9 @@ MediaEngineWebRTCVideoSource::RotateImage(layers::Image* aImage) {
dstPtr + (dstWidth * dstHeight), half_width,
dstPtr + (dstWidth * dstHeight * 5 / 4), half_width,
0, 0,
mWidth, mHeight,
mWidth, mHeight,
static_cast<libyuv::RotationMode>(mSensorAngle),
aWidth, aHeight,
aWidth, aHeight,
static_cast<libyuv::RotationMode>(mRotation),
libyuv::FOURCC_NV21);
graphicBuffer->unlock();
@ -651,17 +722,19 @@ MediaEngineWebRTCVideoSource::OnNewPreviewFrame(layers::Image* aImage, uint32_t
if (mState == kStopped) {
return false;
}
// Bug XXX we'd prefer to avoid converting if mRotation == 0, but that causes problems in UpdateImage()
RotateImage(aImage, aWidth, aHeight);
if (mRotation != 0 && mRotation != 180) {
uint32_t temp = aWidth;
aWidth = aHeight;
aHeight = temp;
}
if (mWidth != static_cast<int>(aWidth) || mHeight != static_cast<int>(aHeight)) {
mWidth = aWidth;
mHeight = aHeight;
LOG(("Video FrameSizeChange: %ux%u", mWidth, mHeight));
}
if (mSensorAngle == 0) {
mImage = aImage;
} else {
RotateImage(aImage);
}
return true; // return true because we're accepting the frame
}
#endif