mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-05-02 02:16:24 +00:00
Captured video always sent in correct orientation.
Temporarily blocked rotation of phone in video call activity.
This commit is contained in:
parent
02ac3962b9
commit
6dad6a3154
7 changed files with 249 additions and 94 deletions
|
|
@ -39,14 +39,12 @@ public abstract class AndroidCameraRecord {
|
|||
|
||||
private PreviewCallback storedPreviewCallback;
|
||||
private boolean previewStarted;
|
||||
protected int displayOrientation;
|
||||
protected static final String tag="Linphone";
|
||||
private List <Size> supportedVideoSizes;
|
||||
private Size currentPreviewSize;
|
||||
|
||||
public AndroidCameraRecord(RecorderParams parameters) {
|
||||
this.params = parameters;
|
||||
setDisplayOrientation(parameters.rotation);
|
||||
}
|
||||
|
||||
protected List<Size> getSupportedPreviewSizes(Camera.Parameters parameters) {
|
||||
|
|
@ -67,7 +65,7 @@ public abstract class AndroidCameraRecord {
|
|||
}
|
||||
|
||||
|
||||
camera=Camera.open();
|
||||
camera = openCamera(params.cameraId);
|
||||
camera.setErrorCallback(new ErrorCallback() {
|
||||
public void onError(int error, Camera camera) {
|
||||
Log.e(tag, "Camera error : " + error);
|
||||
|
|
@ -84,9 +82,10 @@ public abstract class AndroidCameraRecord {
|
|||
}
|
||||
|
||||
|
||||
if (!params.videoDimensionsInverted) {
|
||||
if (params.width >= params.height) {
|
||||
parameters.setPreviewSize(params.width, params.height);
|
||||
} else {
|
||||
// invert height and width
|
||||
parameters.setPreviewSize(params.height, params.width);
|
||||
}
|
||||
parameters.setPreviewFrameRate(Math.round(params.fps));
|
||||
|
|
@ -126,6 +125,10 @@ public abstract class AndroidCameraRecord {
|
|||
|
||||
|
||||
|
||||
protected Camera openCamera(int cameraId) {
|
||||
return Camera.open();
|
||||
}
|
||||
|
||||
protected void onSettingCameraParameters(Parameters parameters) {}
|
||||
|
||||
/**
|
||||
|
|
@ -164,24 +167,8 @@ public abstract class AndroidCameraRecord {
|
|||
|
||||
protected abstract void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb);
|
||||
|
||||
public void setDisplayOrientation(int rotation) {
|
||||
displayOrientation = rotation;
|
||||
}
|
||||
protected int getDisplayOrientation() {return displayOrientation;}
|
||||
|
||||
protected int rotateCapturedFrame() {
|
||||
if (params.videoDimensionsInverted) {
|
||||
return 1; // always rotate 90°
|
||||
} else if (params.cameraId == 2) {
|
||||
return 0;
|
||||
} else {
|
||||
return (4 + 1 - displayOrientation) % 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static class RecorderParams {
|
||||
public float fps;
|
||||
public int height;
|
||||
|
|
@ -191,7 +178,6 @@ public abstract class AndroidCameraRecord {
|
|||
public int cameraId;
|
||||
public int rotation;
|
||||
public SurfaceView surfaceView;
|
||||
public boolean videoDimensionsInverted;
|
||||
|
||||
public RecorderParams(long ptr) {
|
||||
filterDataNativePtr = ptr;
|
||||
|
|
@ -200,7 +186,6 @@ public abstract class AndroidCameraRecord {
|
|||
|
||||
|
||||
|
||||
|
||||
public boolean isStarted() {
|
||||
return previewStarted;
|
||||
}
|
||||
|
|
@ -215,4 +200,5 @@ public abstract class AndroidCameraRecord {
|
|||
|
||||
return currentPreviewSize.width * currentPreviewSize.height * 3 /2;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ import android.hardware.Camera.Size;
|
|||
import android.util.Log;
|
||||
|
||||
|
||||
public class AndroidCameraRecordImplAPI5 extends AndroidCameraRecordImpl {
|
||||
public class AndroidCameraRecord5Impl extends AndroidCameraRecordImpl {
|
||||
|
||||
public AndroidCameraRecordImplAPI5(RecorderParams parameters) {
|
||||
public AndroidCameraRecord5Impl(RecorderParams parameters) {
|
||||
super(parameters);
|
||||
}
|
||||
|
||||
|
|
@ -30,10 +30,10 @@ import android.util.Log;
|
|||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
public class AndroidCameraRecordAPI8Impl extends AndroidCameraRecordImplAPI5 {
|
||||
public class AndroidCameraRecord8Impl extends AndroidCameraRecord5Impl {
|
||||
|
||||
|
||||
public AndroidCameraRecordAPI8Impl(RecorderParams parameters) {
|
||||
public AndroidCameraRecord8Impl(RecorderParams parameters) {
|
||||
super(parameters);
|
||||
}
|
||||
|
||||
|
|
@ -66,10 +66,6 @@ public class AndroidCameraRecordAPI8Impl extends AndroidCameraRecordImplAPI5 {
|
|||
protected void onSettingCameraParameters(Parameters parameters) {
|
||||
super.onSettingCameraParameters(parameters);
|
||||
// Only on v8 hardware
|
||||
camera.setDisplayOrientation(90 * getPreviewCaptureRotation());
|
||||
}
|
||||
|
||||
private int getPreviewCaptureRotation() {
|
||||
return (4 + 1 - displayOrientation) % 4;
|
||||
camera.setDisplayOrientation(rotation);
|
||||
}
|
||||
}
|
||||
40
AndroidCameraRecord9Impl.java
Normal file
40
AndroidCameraRecord9Impl.java
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
AndroidCameraRecord9Impl.java
|
||||
Copyright (C) 2010 Belledonne Communications, Grenoble, France
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package org.linphone.core;
|
||||
|
||||
import android.hardware.Camera;
|
||||
|
||||
/**
|
||||
*
|
||||
* Android >= 9 (2.3) version.
|
||||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
public class AndroidCameraRecord9Impl extends AndroidCameraRecord8Impl {
|
||||
|
||||
|
||||
public AndroidCameraRecord9Impl(RecorderParams parameters) {
|
||||
super(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Camera openCamera(int cameraId) {
|
||||
return Camera.open(cameraId);
|
||||
}
|
||||
}
|
||||
|
|
@ -34,19 +34,19 @@ public class AndroidCameraRecordImpl extends AndroidCameraRecord implements Prev
|
|||
private double timeElapsedBetweenFrames = 0;
|
||||
private long lastFrameTime = 0;
|
||||
private final double expectedTimeBetweenFrames;
|
||||
private boolean sizesInverted;
|
||||
protected final int rotation;
|
||||
|
||||
public AndroidCameraRecordImpl(RecorderParams parameters) {
|
||||
super(parameters);
|
||||
expectedTimeBetweenFrames = 1d / Math.round(parameters.fps);
|
||||
filterCtxPtr = parameters.filterDataNativePtr;
|
||||
sizesInverted = parameters.videoDimensionsInverted;
|
||||
rotation = parameters.rotation;
|
||||
|
||||
storePreviewCallBack(this);
|
||||
}
|
||||
|
||||
|
||||
private native void putImage(long filterCtxPtr, byte[] buffer, int rotate, boolean sizesInverted);
|
||||
private native void putImage(long filterCtxPtr, byte[] buffer, int rotate);
|
||||
|
||||
|
||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
||||
|
|
@ -69,7 +69,7 @@ public class AndroidCameraRecordImpl extends AndroidCameraRecord implements Prev
|
|||
long curTime = System.currentTimeMillis();
|
||||
if (lastFrameTime == 0) {
|
||||
lastFrameTime = curTime;
|
||||
putImage(filterCtxPtr, data, rotateCapturedFrame(), sizesInverted);
|
||||
putImage(filterCtxPtr, data, rotation);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ public class AndroidCameraRecordImpl extends AndroidCameraRecord implements Prev
|
|||
timeElapsedBetweenFrames = currentTimeElapsed;
|
||||
|
||||
// Log.d("onPreviewFrame: ", Integer.toString(data.length));
|
||||
putImage(filterCtxPtr, data, rotateCapturedFrame(), sizesInverted);
|
||||
putImage(filterCtxPtr, data, rotation);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -92,6 +92,4 @@ public class AndroidCameraRecordImpl extends AndroidCameraRecord implements Prev
|
|||
camera.setPreviewCallback(cb);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.List;
|
|||
|
||||
import org.linphone.core.AndroidCameraRecord.RecorderParams;
|
||||
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.Size;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
|
@ -38,14 +39,9 @@ import android.view.SurfaceHolder.Callback;
|
|||
*
|
||||
*/
|
||||
public class AndroidCameraRecordManager {
|
||||
private static final int version = Integer.parseInt(Build.VERSION.SDK);
|
||||
private static final String tag = "Linphone";
|
||||
private static AndroidCameraRecordManager instance;
|
||||
|
||||
// singleton
|
||||
private AndroidCameraRecordManager() {}
|
||||
|
||||
|
||||
/**
|
||||
* @return instance
|
||||
*/
|
||||
|
|
@ -59,31 +55,76 @@ public class AndroidCameraRecordManager {
|
|||
private AndroidCameraRecord.RecorderParams parameters;
|
||||
private SurfaceView surfaceView;
|
||||
private boolean muted;
|
||||
|
||||
private int cameraId;
|
||||
|
||||
private AndroidCameraRecord recorder;
|
||||
|
||||
|
||||
private List<Size> supportedVideoSizes;
|
||||
private int rotation;
|
||||
private int phoneOrientation;
|
||||
public int getPhoneOrientation() {return phoneOrientation;}
|
||||
public void setPhoneOrientation(int degrees) {this.phoneOrientation = degrees;}
|
||||
|
||||
private boolean useFrontCamera;
|
||||
private int frontCameraId;
|
||||
private int rearCameraId;
|
||||
|
||||
// singleton
|
||||
private AndroidCameraRecordManager() {
|
||||
findFrontAndRearCameraIds();
|
||||
}
|
||||
|
||||
|
||||
private void findFrontAndRearCameraIds() {
|
||||
if (Version.sdkAbove(9)) {
|
||||
findFrontAndRearCameraIds9();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Build.DEVICE.startsWith("GT-I9000")) {
|
||||
// Galaxy S has 2 cameras
|
||||
frontCameraId = 2;
|
||||
rearCameraId = 1;
|
||||
cameraId = rearCameraId;
|
||||
return;
|
||||
}
|
||||
|
||||
// default to 0/0
|
||||
}
|
||||
|
||||
private void findFrontAndRearCameraIds9() {
|
||||
for (int id=0; id < getNumberOfCameras9(); id++) {
|
||||
if (isFrontCamera9(id)) {
|
||||
frontCameraId = id;
|
||||
} else {
|
||||
rearCameraId = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasSeveralCameras() {
|
||||
return frontCameraId != rearCameraId;
|
||||
}
|
||||
|
||||
|
||||
public void setUseFrontCamera(boolean value) {
|
||||
if (useFrontCamera == value) return;
|
||||
this.useFrontCamera = value;
|
||||
|
||||
if (isFrontCamera() == value) return; // already OK
|
||||
|
||||
toggleUseFrontCamera();
|
||||
}
|
||||
|
||||
public boolean isUseFrontCamera() {return isFrontCamera();}
|
||||
public boolean toggleUseFrontCamera() {
|
||||
boolean previousUseFront = isFrontCamera();
|
||||
|
||||
cameraId = previousUseFront ? rearCameraId : frontCameraId;
|
||||
|
||||
if (parameters != null) {
|
||||
parameters.cameraId = cameraId();
|
||||
parameters.cameraId = cameraId;
|
||||
if (isRecording()) {
|
||||
stopVideoRecording();
|
||||
tryToStartVideoRecording();
|
||||
}
|
||||
}
|
||||
}
|
||||
public boolean isUseFrontCamera() {return useFrontCamera;}
|
||||
public boolean toggleUseFrontCamera() {
|
||||
setUseFrontCamera(!useFrontCamera);
|
||||
return useFrontCamera;
|
||||
|
||||
return !previousUseFront;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -94,16 +135,14 @@ public class AndroidCameraRecordManager {
|
|||
p.fps = fps;
|
||||
p.width = width;
|
||||
p.height = height;
|
||||
p.cameraId = cameraId();
|
||||
p.videoDimensionsInverted = width < height;
|
||||
// width and height will be inverted in Recorder on startPreview
|
||||
p.cameraId = cameraId;
|
||||
parameters = p;
|
||||
tryToStartVideoRecording();
|
||||
}
|
||||
|
||||
|
||||
public final void setSurfaceView(final SurfaceView sv, final int rotation) {
|
||||
this.rotation = useFrontCamera ? 1 : rotation;
|
||||
public final void setSurfaceView(final SurfaceView sv, final int phoneOrientation) {
|
||||
this.phoneOrientation = phoneOrientation;
|
||||
SurfaceHolder holder = sv.getHolder();
|
||||
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||||
|
||||
|
|
@ -152,12 +191,15 @@ public class AndroidCameraRecordManager {
|
|||
private void tryToStartVideoRecording() {
|
||||
if (muted || surfaceView == null || parameters == null) return;
|
||||
|
||||
parameters.rotation = rotation;
|
||||
parameters.rotation = bufferRotationForCorrectImageOrientation();
|
||||
|
||||
parameters.surfaceView = surfaceView;
|
||||
if (version >= 8) {
|
||||
recorder = new AndroidCameraRecordAPI8Impl(parameters);
|
||||
} else if (version >= 5) {
|
||||
recorder = new AndroidCameraRecordImplAPI5(parameters);
|
||||
if (Version.sdkAbove(9)) {
|
||||
recorder = new AndroidCameraRecord9Impl(parameters);
|
||||
} else if (Version.sdkAbove(8)) {
|
||||
recorder = new AndroidCameraRecord8Impl(parameters);
|
||||
} else if (Version.sdkAbove(5)) {
|
||||
recorder = new AndroidCameraRecord5Impl(parameters);
|
||||
} else {
|
||||
recorder = new AndroidCameraRecordImpl(parameters);
|
||||
}
|
||||
|
|
@ -188,8 +230,8 @@ public class AndroidCameraRecordManager {
|
|||
if (supportedVideoSizes != null) return supportedVideoSizes;
|
||||
}
|
||||
|
||||
if (version >= 5) {
|
||||
supportedVideoSizes = AndroidCameraRecordImplAPI5.oneShotSupportedVideoSizes();
|
||||
if (Version.sdkAbove(5)) {
|
||||
supportedVideoSizes = AndroidCameraRecord5Impl.oneShotSupportedVideoSizes();
|
||||
}
|
||||
|
||||
// eventually null
|
||||
|
|
@ -212,34 +254,86 @@ public class AndroidCameraRecordManager {
|
|||
parameters = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Naive simple version.
|
||||
* @param askedSize
|
||||
* @return
|
||||
*/
|
||||
public VideoSize doYouSupportThisVideoSize(VideoSize askedSize) {
|
||||
Log.d(tag, "Asking camera if it supports size "+askedSize);
|
||||
if (useFrontCamera && askedSize.isPortrait()) {
|
||||
return askedSize.createInverted(); // only landscape supported
|
||||
} else {
|
||||
return askedSize;
|
||||
}
|
||||
public boolean outputIsPortrait() {
|
||||
final int rotation = bufferRotationForCorrectImageOrientation();
|
||||
final boolean isPortrait = (rotation % 180) == 90;
|
||||
|
||||
Log.d(tag, "Camera sensor in portrait orientation ?" + isPortrait);
|
||||
return isPortrait;
|
||||
}
|
||||
|
||||
|
||||
private VideoSize closestVideoSize(VideoSize vSize, int defaultSizeCode, boolean defaultIsPortrait) {
|
||||
VideoSize testSize = vSize.isPortrait() ? vSize.createInverted() : vSize;
|
||||
|
||||
for (Size s : AndroidCameraRecordManager.getInstance().supportedVideoSizes()) {
|
||||
if (s.height == testSize.height && s.width == testSize.width) {
|
||||
return vSize;
|
||||
}
|
||||
}
|
||||
|
||||
return VideoSize.createStandard(defaultSizeCode, defaultIsPortrait);
|
||||
|
||||
|
||||
public static int getNumberOfCameras() {
|
||||
if (Version.sdkAbove(9)) return getNumberOfCameras9();
|
||||
|
||||
// Use hacks to guess the number of cameras
|
||||
if (Build.DEVICE.startsWith("GT-I9000")) {
|
||||
// Galaxy S has 2 cameras
|
||||
return 2;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static final int rearCamId() {return 1;}
|
||||
private static final int frontCamId() {return 2;}
|
||||
private final int cameraId() {return useFrontCamera? frontCamId() : rearCamId(); }
|
||||
private static int getNumberOfCameras9() {
|
||||
return Camera.getNumberOfCameras();
|
||||
}
|
||||
|
||||
public boolean isCameraOrientationPortrait() {
|
||||
return (getCameraOrientation() % 180) == 90;
|
||||
}
|
||||
|
||||
public int getCameraOrientation() {
|
||||
if (Version.sdkAbove(9)) return getCameraOrientation9();
|
||||
|
||||
// Use hacks to guess orientation of the camera
|
||||
if (cameraId == 2 && Build.DEVICE.startsWith("GT-I9000")) {
|
||||
// Galaxy S rear camera
|
||||
// mounted in landscape for a portrait phone orientation
|
||||
return 90;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
private int getCameraOrientation9() {
|
||||
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
|
||||
Camera.getCameraInfo(cameraId, info);
|
||||
return info.orientation;
|
||||
}
|
||||
|
||||
public boolean isFrontCamera() {
|
||||
if (Version.sdkAbove(9)) return isFrontCamera9();
|
||||
|
||||
// Use hacks to guess facing of the camera
|
||||
|
||||
if (cameraId == 2 && Build.DEVICE.startsWith("GT-I9000")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isFrontCamera9() {
|
||||
return isFrontCamera9(cameraId);
|
||||
}
|
||||
|
||||
|
||||
private boolean isFrontCamera9(int cameraId) {
|
||||
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
|
||||
Camera.getCameraInfo(cameraId, info);
|
||||
return info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT ? true : false;
|
||||
}
|
||||
|
||||
private int bufferRotationForCorrectImageOrientation() {
|
||||
final int cameraOrientation = getCameraOrientation();
|
||||
final int rotation = Version.sdkAbove(8) ?
|
||||
(360 - cameraOrientation + 90 - phoneOrientation) % 360
|
||||
: 0;
|
||||
Log.d(tag, "Capture video buffer will need a rotation of " + rotation
|
||||
+ " degrees : camera " + cameraOrientation
|
||||
+ ", phone " + phoneOrientation);
|
||||
return rotation;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
41
Version.java
Normal file
41
Version.java
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Version.java
|
||||
Copyright (C) 2010 Belledonne Communications, Grenoble, France
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package org.linphone.core;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
/**
|
||||
* Centralize version access and allow simulation of lower versions.
|
||||
* @author Guillaume Beraudo
|
||||
*/
|
||||
public class Version {
|
||||
|
||||
private static final int buildVersion =
|
||||
// Integer.parseInt(Build.VERSION.SDK);
|
||||
7; // 2.1
|
||||
|
||||
public static final boolean sdkAbove(int value) {
|
||||
return buildVersion >= value;
|
||||
}
|
||||
|
||||
public static final boolean sdkBelow(int value) {
|
||||
return buildVersion < value;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue