Preliminary support for front camera.

This commit is contained in:
Guillaume Beraudo 2010-12-09 09:13:12 +01:00
parent 36efd26291
commit 1c113d3074
12 changed files with 119 additions and 58 deletions

View file

@ -8,4 +8,5 @@
<item android:id="@+id/videocall_menu_terminate_call" android:title="@string/menu_videocall_terminate_call_title"></item>
<item android:id="@+id/videocall_menu_change_resolution" android:title="@string/menu_videocall_change_resolution_title"></item>
<item android:id="@+id/videocall_menu_back_to_dialer" android:title="@string/menu_videocall_back_to_dialer_title"></item>
<item android:title="@string/menu_videocall_switch_camera_title" android:id="@+id/videocall_menu_switch_camera"></item>
</menu>

View file

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pref_video_use_front_camera_title">Use front camera (if any)</string>
<string name="pref_video_use_front_camera_key">pref_video_use_front_camera_key</string>
<string name="pref_video">Video</string>
<string name="pref_preferences">Preferences</string>
<string name="pref_video_codec_h263_title">H263</string>
@ -11,6 +13,7 @@
<string name="pref_video_codecs_title">Video codecs</string>
<string name="pref_video_codecs_key">pref_video_codecs_key</string>
<string name="menu_videocall_back_to_dialer_title">Display dialer</string>
<string name="menu_videocall_switch_camera_title">Front/Rear Camera</string>
<string name="menu_videocall_change_resolution_when_low_resolution">Try High resolution</string>
<string name="menu_videocall_change_resolution_when_high_resolution">Low resolution</string>
<string name="menu_videocall_change_resolution_title">Change resolution</string>

View file

@ -83,6 +83,7 @@
android:defaultValue="false" android:selectable="false"></CheckBoxPreference>
</PreferenceScreen>
<PreferenceScreen android:title="@string/pref_video_settings_title"
android:dependency="@string/pref_video_enable_key"
android:shouldDisableView="true">
@ -98,7 +99,8 @@
android:summary="@string/pref_video_automatically_share_my_video"
android:dependency="@string/pref_video_enable_key"></CheckBoxPreference>
</PreferenceScreen>
</PreferenceCategory>
<CheckBoxPreference android:key="@string/pref_video_use_front_camera_key" android:title="@string/pref_video_use_front_camera_title"></CheckBoxPreference>
</PreferenceCategory>

View file

@ -91,10 +91,12 @@ public class BandwidthManager {
LinphoneCallParams params = lCall.getCurrentParamsCopy();
// Update video parm if
if (newProfile == LOW_BANDWIDTH) {
if (newProfile == LOW_BANDWIDTH) { // NO VIDEO
params.setVideoEnabled(false);
params.setAudioBandwidth(40);
} else {
params.setVideoEnabled(true);
params.setAudioBandwidth(0); // disable limitation
}

View file

@ -485,7 +485,7 @@ public class DialerActivity extends Activity implements LinphoneCoreListener {
}
private void enterIncalMode(LinphoneCore lc) {
resetCameraFromPreferences();
mCallControlRow.setVisibility(View.GONE);
mInCallControlRow.setVisibility(View.VISIBLE);
mAddressLayout.setVisibility(View.GONE);
@ -522,6 +522,12 @@ public class DialerActivity extends Activity implements LinphoneCoreListener {
mSpeaker.setChecked(false);
}
}
private void resetCameraFromPreferences() {
boolean useFrontCam = mPref.getBoolean(getString(R.string.pref_video_use_front_camera_key), false);
AndroidCameraRecordManager.getInstance().setUseFrontCamera(useFrontCam);
}
private void exitCallMode() {
mCallControlRow.setVisibility(View.VISIBLE);
mInCallControlRow.setVisibility(View.GONE);
@ -539,6 +545,7 @@ public class DialerActivity extends Activity implements LinphoneCoreListener {
mSpeaker.setChecked(false);
routeAudioToReceiver();
BandwidthManager.getInstance().setUserRestriction(false);
resetCameraFromPreferences();
}
private void routeAudioToSpeaker() {
if (Integer.parseInt(Build.VERSION.SDK) <= 4 /*<donut*/) {

View file

@ -21,6 +21,8 @@ package org.linphone;
import org.linphone.core.AndroidCameraRecordManager;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCallParams;
import org.linphone.core.LinphoneCore;
import android.app.Activity;
@ -52,8 +54,8 @@ public class VideoCallActivity extends Activity {
LinphoneService.instance().getLinphoneCore().setVideoWindow(mVideoView);
mVideoCaptureView = (SurfaceView) findViewById(R.id.video_capture_surface);
final int rotation = getWindowManager().getDefaultDisplay().getRotation();
final int rotation = getWindowManager().getDefaultDisplay().getOrientation();
recordManager = AndroidCameraRecordManager.getInstance();
recordManager.setSurfaceView(mVideoCaptureView, rotation);
mVideoCaptureView.setZOrderOnTop(true);
@ -126,6 +128,14 @@ public class VideoCallActivity extends Activity {
sendStaticImage(recordManager.isMuted());
rewriteToggleCameraItem(item);
break;
case R.id.videocall_menu_switch_camera:
recordManager.stopVideoRecording();
recordManager.setUseFrontCamera(!recordManager.isUseFrontCamera());
LinphoneCore lc = LinphoneService.instance().getLinphoneCore();
LinphoneCall lCall = lc.getCurrentCall();
LinphoneCallParams params = lCall.getCurrentParamsCopy();
lc.updateCall(lCall, params);
break;
default:
Log.e(LinphoneService.TAG, "Unknown menu item ["+item+"]");
break;

View file

@ -39,13 +39,14 @@ public abstract class AndroidCameraRecord {
private PreviewCallback storedPreviewCallback;
private boolean previewStarted;
protected int orientationCode;
protected int displayOrientation;
protected static final String tag="Linphone";
private List <Size> supportedVideoSizes;
private Size currentPreviewSize;
public AndroidCameraRecord(RecorderParams parameters) {
this.params = parameters;
setRotation(parameters.rotation);
setDisplayOrientation(parameters.rotation);
}
protected List<Size> getSupportedPreviewSizes(Camera.Parameters parameters) {
@ -75,11 +76,14 @@ public abstract class AndroidCameraRecord {
Camera.Parameters parameters=camera.getParameters();
parameters.set("camera-id",params.cameraId);
camera.setParameters(parameters);
parameters = camera.getParameters();
if (supportedVideoSizes == null) {
supportedVideoSizes = getSupportedPreviewSizes(camera.getParameters());
supportedVideoSizes = new ArrayList<Size>(getSupportedPreviewSizes(parameters));
}
parameters.set("camera-id", params.cameraId);
if (!params.videoDimensionsInverted) {
parameters.setPreviewSize(params.width, params.height);
} else {
@ -91,6 +95,7 @@ public abstract class AndroidCameraRecord {
onSettingCameraParameters(parameters);
camera.setParameters(parameters);
currentPreviewSize = camera.getParameters().getPreviewSize();
SurfaceHolder holder = params.surfaceView.getHolder();
try {
@ -140,12 +145,13 @@ public abstract class AndroidCameraRecord {
}
void stopPreview() {
public void stopPreview() {
if (!previewStarted) return;
lowLevelSetPreviewCallback(camera, null);
camera.stopPreview();
camera.release();
camera=null;
if (currentPreviewSize != null) currentPreviewSize = null;
previewStarted = false;
}
@ -158,12 +164,16 @@ public abstract class AndroidCameraRecord {
protected abstract void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb);
public void setRotation(int rotation) {
orientationCode = (4 + 1 - rotation) % 4;
public void setDisplayOrientation(int rotation) {
displayOrientation = rotation;
}
protected int getOrientationCode() {
return orientationCode;
protected int rotateCapturedFrame() {
if (params.cameraId == 2) {
return 0;
} else {
return (4 + 1 - displayOrientation) % 4;
}
}
@ -175,10 +185,10 @@ public abstract class AndroidCameraRecord {
public int width;
final long filterDataNativePtr;
int cameraId;
int rotation;
public int cameraId;
public int rotation;
public SurfaceView surfaceView;
boolean videoDimensionsInverted;
public boolean videoDimensionsInverted;
public RecorderParams(long ptr) {
filterDataNativePtr = ptr;
@ -195,4 +205,11 @@ public abstract class AndroidCameraRecord {
public List<Size> getSupportedVideoSizes() {
return new ArrayList<Size>(supportedVideoSizes);
}
protected int getExpectedBufferLength() {
if (currentPreviewSize == null) return -1;
return currentPreviewSize.width * currentPreviewSize.height * 3 /2;
}
}

View file

@ -66,7 +66,7 @@ public class AndroidCameraRecordBufferedImpl extends AndroidCameraRecordImplAPI5
protected void onSettingCameraParameters(Parameters parameters) {
super.onSettingCameraParameters(parameters);
// Only on v8 hardware
camera.setDisplayOrientation(90 * orientationCode);
camera.setDisplayOrientation(90 * displayOrientation);
}

View file

@ -20,7 +20,6 @@ package org.linphone.core;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.util.Log;
/**
@ -35,19 +34,19 @@ public class AndroidCameraRecordImpl extends AndroidCameraRecord implements Prev
private double timeElapsedBetweenFrames = 0;
private long lastFrameTime = 0;
private final double expectedTimeBetweenFrames;
private boolean videoDimensionsInverted;
private boolean sizesInverted;
public AndroidCameraRecordImpl(RecorderParams parameters) {
super(parameters);
expectedTimeBetweenFrames = 1d / Math.round(parameters.fps);
filterCtxPtr = parameters.filterDataNativePtr;
videoDimensionsInverted = parameters.videoDimensionsInverted;
sizesInverted = parameters.videoDimensionsInverted;
storePreviewCallBack(this);
}
private native void putImage(long filterCtxPtr, byte[] buffer, int orientation, boolean videoDimensionsInverted);
private native void putImage(long filterCtxPtr, byte[] buffer, int rotate, boolean sizesInverted);
public void onPreviewFrame(byte[] data, Camera camera) {
@ -60,8 +59,7 @@ public class AndroidCameraRecordImpl extends AndroidCameraRecord implements Prev
return;
}
Size s = camera.getParameters().getPreviewSize();
int expectedBuffLength = s.width * s.height * 3 /2;
int expectedBuffLength = getExpectedBufferLength();
if (expectedBuffLength != data.length) {
Log.e("Linphone", "onPreviewFrame called with bad buffer length " + data.length
+ " whereas expected is " + expectedBuffLength + " don't calling putImage");
@ -71,7 +69,7 @@ public class AndroidCameraRecordImpl extends AndroidCameraRecord implements Prev
long curTime = System.currentTimeMillis();
if (lastFrameTime == 0) {
lastFrameTime = curTime;
putImage(filterCtxPtr, data, getOrientationCode(), videoDimensionsInverted);
putImage(filterCtxPtr, data, rotateCapturedFrame(), sizesInverted);
return;
}
@ -84,10 +82,11 @@ public class AndroidCameraRecordImpl extends AndroidCameraRecord implements Prev
timeElapsedBetweenFrames = currentTimeElapsed;
// Log.d("onPreviewFrame: ", Integer.toString(data.length));
putImage(filterCtxPtr, data, getOrientationCode(), videoDimensionsInverted);
putImage(filterCtxPtr, data, rotateCapturedFrame(), sizesInverted);
}
@Override
protected void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb) {
camera.setPreviewCallback(cb);

View file

@ -18,9 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone.core;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.linphone.core.AndroidCameraRecord.RecorderParams;
@ -41,38 +39,21 @@ import android.view.SurfaceHolder.Callback;
*/
public class AndroidCameraRecordManager {
private static final int version = Integer.parseInt(Build.VERSION.SDK);
private static Map<Integer, AndroidCameraRecordManager> instances = new HashMap<Integer, AndroidCameraRecordManager>();
private static final String tag = "Linphone";
private static AndroidCameraRecordManager instance;
// singleton
private AndroidCameraRecordManager(int cameraId) {
this.cameraId = cameraId;
}
private AndroidCameraRecordManager() {}
/**
* Instance for a given camera
* @param cameraId : starting from 0
* @return
*/
public static final synchronized AndroidCameraRecordManager getInstance(int cameraId) {
if (cameraId < 0) {
Log.e("Linphone", "Asking unmanageable camera " + cameraId);
return null;
}
AndroidCameraRecordManager m = instances.get(cameraId);
if (m == null) {
m = new AndroidCameraRecordManager(cameraId);
instances.put(cameraId, m);
}
return m;
}
/**
* @return instance for the default camera
* @return instance
*/
public static final synchronized AndroidCameraRecordManager getInstance() {
return getInstance(0);
if (instance == null) {
instance = new AndroidCameraRecordManager();
}
return instance;
}
private AndroidCameraRecord.RecorderParams parameters;
@ -81,11 +62,26 @@ public class AndroidCameraRecordManager {
private AndroidCameraRecord recorder;
private final Integer cameraId;
private List<Size> supportedVideoSizes;
private int rotation;
private static final String tag = "Linphone";
private boolean useFrontCamera;
public void setUseFrontCamera(boolean value) {
if (useFrontCamera == value) return;
this.useFrontCamera = value;
if (parameters != null) {
parameters.cameraId = cameraId();
if (isRecording()) {
stopVideoRecording();
tryToStartVideoRecording();
}
}
}
public boolean isUseFrontCamera() {return useFrontCamera;}
public void setParametersFromFilter(long filterDataPtr, int height, int width, float fps) {
@ -94,15 +90,16 @@ public class AndroidCameraRecordManager {
p.fps = fps;
p.width = width;
p.height = height;
p.cameraId = cameraId;
p.cameraId = cameraId();
p.videoDimensionsInverted = width < height;
// width and height will be inverted in Recorder on startPreview
parameters = p;
tryToStartVideoRecording();
}
public final void setSurfaceView(final SurfaceView sv, final int rotation) {
this.rotation = rotation;
this.rotation = useFrontCamera ? 1 : rotation;
SurfaceHolder holder = sv.getHolder();
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
@ -206,4 +203,22 @@ public class AndroidCameraRecordManager {
parameters = null;
}
public int[] doYouSupportThisVideoSize(int[] askedSize) {
final int askedW = askedSize[0];
final int askedH = askedSize[1];
Log.d(tag, "w"+askedW);
Log.d(tag, "h"+askedH);
if (useFrontCamera && isPortraitSize(askedW, askedH)) {
return new int[] {askedH, askedW}; // only landscape supported
} else {
return askedSize;
}
}
private boolean isPortraitSize(int width, int height) {
return width < height;
}
private static final int rearCamId() {return 1;}
private static final int frontCamId() {return 2;}
private final int cameraId() {return useFrontCamera? frontCamId() : rearCamId(); }
}

View file

@ -27,6 +27,7 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams {
private native void enableVideo(long nativePtr, boolean b);
private native boolean getVideoEnabled(long nativePtr);
private native void audioBandwidth(long nativePtr, int bw);
private native void destroy(long nativePtr);
@ -43,4 +44,8 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams {
destroy(nativePtr);
super.finalize();
}
public void setAudioBandwidth(int value) {
audioBandwidth(nativePtr, value);
}
}

@ -1 +1 @@
Subproject commit 9fc45b990045768c65a346e5b41a37ab8087d0b5
Subproject commit 684c6fa545f0875b943b6d6741cd01ef05febfe4