mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-02-07 14:18:25 +00:00
Merge branch 'video' of git.linphone.org:linphone-android-private
Conflicts: libs/armeabi-v7a/liblinphone.so libs/armeabi/liblinphone.so src/org/linphone/core/LinphoneCallImpl.java src/org/linphone/core/LinphoneProxyConfigImpl.java src/org/linphone/core/tutorials/TutorialRegistrationActivity.java submodules/linphone
This commit is contained in:
commit
013e835343
14 changed files with 1247 additions and 66 deletions
217
AndroidCameraRecord.java
Normal file
217
AndroidCameraRecord.java
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
AndroidCameraRecordImpl.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 java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.ErrorCallback;
|
||||
import android.hardware.Camera.Parameters;
|
||||
import android.hardware.Camera.PreviewCallback;
|
||||
import android.hardware.Camera.Size;
|
||||
import android.util.Log;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
|
||||
public abstract class AndroidCameraRecord {
|
||||
|
||||
protected Camera camera;
|
||||
private RecorderParams params;
|
||||
|
||||
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) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public void startPreview() { // FIXME throws exception?
|
||||
if (previewStarted) {
|
||||
Log.w(tag, "Already started");
|
||||
throw new RuntimeException("Video recorder already started");
|
||||
// return
|
||||
}
|
||||
|
||||
if (params.surfaceView.getVisibility() != SurfaceView.VISIBLE) {
|
||||
// Illegal state
|
||||
Log.e(tag, "Illegal state: video capture surface view is not visible");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
camera=Camera.open();
|
||||
camera.setErrorCallback(new ErrorCallback() {
|
||||
public void onError(int error, Camera camera) {
|
||||
Log.e(tag, "Camera error : " + error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Camera.Parameters parameters=camera.getParameters();
|
||||
parameters.set("camera-id",params.cameraId);
|
||||
camera.setParameters(parameters);
|
||||
parameters = camera.getParameters();
|
||||
if (supportedVideoSizes == null) {
|
||||
supportedVideoSizes = new ArrayList<Size>(getSupportedPreviewSizes(parameters));
|
||||
}
|
||||
|
||||
|
||||
if (!params.videoDimensionsInverted) {
|
||||
parameters.setPreviewSize(params.width, params.height);
|
||||
} else {
|
||||
parameters.setPreviewSize(params.height, params.width);
|
||||
}
|
||||
parameters.setPreviewFrameRate(Math.round(params.fps));
|
||||
|
||||
|
||||
onSettingCameraParameters(parameters);
|
||||
camera.setParameters(parameters);
|
||||
|
||||
currentPreviewSize = camera.getParameters().getPreviewSize();
|
||||
|
||||
SurfaceHolder holder = params.surfaceView.getHolder();
|
||||
try {
|
||||
camera.setPreviewDisplay(holder);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
Log.e(tag, "Exception in Video capture setPreviewDisplay()", t);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
camera.startPreview();
|
||||
previewStarted = true;
|
||||
} catch (Throwable e) {
|
||||
Log.e(tag, "Can't start camera preview");
|
||||
}
|
||||
|
||||
previewStarted = true;
|
||||
|
||||
|
||||
// Register callback to get capture buffer
|
||||
lowLevelSetPreviewCallback(camera, storedPreviewCallback);
|
||||
|
||||
|
||||
onPreviewStarted(camera);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
protected void onSettingCameraParameters(Parameters parameters) {}
|
||||
|
||||
/**
|
||||
* Hook.
|
||||
* @param camera
|
||||
*/
|
||||
public void onPreviewStarted(Camera camera) {}
|
||||
|
||||
public void storePreviewCallBack(PreviewCallback cb) {
|
||||
this.storedPreviewCallback = cb;
|
||||
if (camera == null) {
|
||||
Log.w(tag, "Capture camera not ready, storing callback");
|
||||
return;
|
||||
}
|
||||
|
||||
lowLevelSetPreviewCallback(camera, cb);
|
||||
}
|
||||
|
||||
|
||||
public void stopPreview() {
|
||||
if (!previewStarted) return;
|
||||
lowLevelSetPreviewCallback(camera, null);
|
||||
camera.stopPreview();
|
||||
camera.release();
|
||||
camera=null;
|
||||
if (currentPreviewSize != null) currentPreviewSize = null;
|
||||
previewStarted = false;
|
||||
}
|
||||
|
||||
|
||||
public void stopCaptureCallback() {
|
||||
if (camera != null) {
|
||||
lowLevelSetPreviewCallback(camera, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb);
|
||||
|
||||
public void setDisplayOrientation(int rotation) {
|
||||
displayOrientation = rotation;
|
||||
}
|
||||
|
||||
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;
|
||||
public int width;
|
||||
|
||||
final long filterDataNativePtr;
|
||||
public int cameraId;
|
||||
public int rotation;
|
||||
public SurfaceView surfaceView;
|
||||
public boolean videoDimensionsInverted;
|
||||
|
||||
public RecorderParams(long ptr) {
|
||||
filterDataNativePtr = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public boolean isStarted() {
|
||||
return previewStarted;
|
||||
}
|
||||
|
||||
public List<Size> getSupportedVideoSizes() {
|
||||
return new ArrayList<Size>(supportedVideoSizes);
|
||||
}
|
||||
|
||||
|
||||
protected int getExpectedBufferLength() {
|
||||
if (currentPreviewSize == null) return -1;
|
||||
|
||||
return currentPreviewSize.width * currentPreviewSize.height * 3 /2;
|
||||
}
|
||||
}
|
||||
73
AndroidCameraRecordBufferedImpl.java
Normal file
73
AndroidCameraRecordBufferedImpl.java
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
AndroidCameraRecord8Impl.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;
|
||||
import android.hardware.Camera.Parameters;
|
||||
import android.hardware.Camera.PreviewCallback;
|
||||
import android.hardware.Camera.Size;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
*
|
||||
* Android >= 8 (2.2) version.
|
||||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
public class AndroidCameraRecordBufferedImpl extends AndroidCameraRecordImplAPI5 {
|
||||
|
||||
|
||||
public AndroidCameraRecordBufferedImpl(RecorderParams parameters) {
|
||||
super(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb) {
|
||||
if (cb != null) {
|
||||
Log.d("Linphone", "Setting optimized callback with buffer (Android >= 8). Remember to manage the pool of buffers!!!");
|
||||
}
|
||||
camera.setPreviewCallbackWithBuffer(cb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreviewStarted(Camera camera) {
|
||||
super.onPreviewStarted(camera);
|
||||
|
||||
Size s = camera.getParameters().getPreviewSize();
|
||||
int wishedBufferSize = s.height * s.width * 3 / 2;
|
||||
|
||||
camera.addCallbackBuffer(new byte[wishedBufferSize]);
|
||||
camera.addCallbackBuffer(new byte[wishedBufferSize]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
||||
super.onPreviewFrame(data, camera);
|
||||
camera.addCallbackBuffer(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSettingCameraParameters(Parameters parameters) {
|
||||
super.onSettingCameraParameters(parameters);
|
||||
// Only on v8 hardware
|
||||
camera.setDisplayOrientation(90 * rotateCapturedFrame());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
97
AndroidCameraRecordImpl.java
Normal file
97
AndroidCameraRecordImpl.java
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
AndroidCameraRecordImpl.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;
|
||||
import android.hardware.Camera.PreviewCallback;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Record from Android camera.
|
||||
*
|
||||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
public class AndroidCameraRecordImpl extends AndroidCameraRecord implements PreviewCallback {
|
||||
|
||||
private long filterCtxPtr;
|
||||
private double timeElapsedBetweenFrames = 0;
|
||||
private long lastFrameTime = 0;
|
||||
private final double expectedTimeBetweenFrames;
|
||||
private boolean sizesInverted;
|
||||
|
||||
public AndroidCameraRecordImpl(RecorderParams parameters) {
|
||||
super(parameters);
|
||||
expectedTimeBetweenFrames = 1d / Math.round(parameters.fps);
|
||||
filterCtxPtr = parameters.filterDataNativePtr;
|
||||
sizesInverted = parameters.videoDimensionsInverted;
|
||||
|
||||
storePreviewCallBack(this);
|
||||
}
|
||||
|
||||
|
||||
private native void putImage(long filterCtxPtr, byte[] buffer, int rotate, boolean sizesInverted);
|
||||
|
||||
|
||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
||||
if (data == null) {
|
||||
Log.e("Linphone", "onPreviewFrame Called with null buffer");
|
||||
return;
|
||||
}
|
||||
if (filterCtxPtr == 0l) {
|
||||
Log.e("Linphone", "onPreviewFrame Called with no filterCtxPtr set");
|
||||
return;
|
||||
}
|
||||
|
||||
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");
|
||||
return;
|
||||
}
|
||||
|
||||
long curTime = System.currentTimeMillis();
|
||||
if (lastFrameTime == 0) {
|
||||
lastFrameTime = curTime;
|
||||
putImage(filterCtxPtr, data, rotateCapturedFrame(), sizesInverted);
|
||||
return;
|
||||
}
|
||||
|
||||
double currentTimeElapsed = 0.8 * (curTime - lastFrameTime) / 1000 + 0.2 * timeElapsedBetweenFrames;
|
||||
if (currentTimeElapsed < expectedTimeBetweenFrames) {
|
||||
// Log.d("Linphone", "Clipping frame " + Math.round(1 / currentTimeElapsed) + " > " + fps);
|
||||
return;
|
||||
}
|
||||
lastFrameTime = curTime;
|
||||
timeElapsedBetweenFrames = currentTimeElapsed;
|
||||
|
||||
// Log.d("onPreviewFrame: ", Integer.toString(data.length));
|
||||
putImage(filterCtxPtr, data, rotateCapturedFrame(), sizesInverted);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb) {
|
||||
camera.setPreviewCallback(cb);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
64
AndroidCameraRecordImplAPI5.java
Normal file
64
AndroidCameraRecordImplAPI5.java
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
AndroidCameraRecordImplAPI5.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 java.util.List;
|
||||
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.Parameters;
|
||||
import android.hardware.Camera.Size;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
public class AndroidCameraRecordImplAPI5 extends AndroidCameraRecordImpl {
|
||||
|
||||
public AndroidCameraRecordImplAPI5(RecorderParams parameters) {
|
||||
super(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSettingCameraParameters(Parameters parameters) {
|
||||
super.onSettingCameraParameters(parameters);
|
||||
|
||||
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
|
||||
Log.w(tag, "Auto Focus supported by camera device");
|
||||
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
|
||||
} else {
|
||||
Log.w(tag, "Auto Focus not supported by camera device");
|
||||
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
|
||||
Log.w(tag, "Infinity Focus supported by camera device");
|
||||
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
|
||||
} else {
|
||||
Log.w(tag, "Infinity Focus not supported by camera device");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Size> oneShotSupportedVideoSizes() {
|
||||
Camera camera = Camera.open();
|
||||
List<Size> supportedVideoSizes =camera.getParameters().getSupportedPreviewSizes();
|
||||
camera.release();
|
||||
return supportedVideoSizes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Size> getSupportedPreviewSizes(Parameters parameters) {
|
||||
return parameters.getSupportedPreviewSizes();
|
||||
}
|
||||
}
|
||||
245
AndroidCameraRecordManager.java
Normal file
245
AndroidCameraRecordManager.java
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
AndroidCameraRecordManager.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 java.util.List;
|
||||
|
||||
import org.linphone.core.AndroidCameraRecord.RecorderParams;
|
||||
|
||||
import android.hardware.Camera.Size;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.SurfaceHolder.Callback;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Manage the video capture, only on for all cameras.
|
||||
*
|
||||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public static final synchronized AndroidCameraRecordManager getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new AndroidCameraRecordManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private AndroidCameraRecord.RecorderParams parameters;
|
||||
private SurfaceView surfaceView;
|
||||
private boolean muted;
|
||||
|
||||
|
||||
private AndroidCameraRecord recorder;
|
||||
|
||||
|
||||
private List<Size> supportedVideoSizes;
|
||||
private int rotation;
|
||||
|
||||
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 boolean toggleUseFrontCamera() {
|
||||
setUseFrontCamera(!useFrontCamera);
|
||||
return useFrontCamera;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setParametersFromFilter(long filterDataPtr, int height, int width, float fps) {
|
||||
stopVideoRecording();
|
||||
RecorderParams p = new RecorderParams(filterDataPtr);
|
||||
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
|
||||
parameters = p;
|
||||
tryToStartVideoRecording();
|
||||
}
|
||||
|
||||
|
||||
public final void setSurfaceView(final SurfaceView sv, final int rotation) {
|
||||
this.rotation = useFrontCamera ? 1 : rotation;
|
||||
SurfaceHolder holder = sv.getHolder();
|
||||
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||||
|
||||
holder.addCallback(new Callback() {
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
surfaceView = null;
|
||||
Log.d(tag , "Video capture surface destroyed");
|
||||
stopVideoRecording();
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
surfaceView = sv;
|
||||
Log.d(tag , "Video capture surface created");
|
||||
tryToStartVideoRecording();
|
||||
}
|
||||
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width,
|
||||
int height) {
|
||||
Log.d(tag , "Video capture surface changed");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setMuted(boolean muteState) {
|
||||
if (muteState == muted) return;
|
||||
muted = muteState;
|
||||
if (muted) {
|
||||
stopVideoRecording();
|
||||
} else {
|
||||
tryToStartVideoRecording();
|
||||
}
|
||||
}
|
||||
public boolean toggleMute() {
|
||||
setMuted(!muted);
|
||||
return muted;
|
||||
}
|
||||
public boolean isMuted() {
|
||||
return muted;
|
||||
}
|
||||
|
||||
public void tryResumingVideoRecording() {
|
||||
if (isRecording()) return;
|
||||
tryToStartVideoRecording();
|
||||
}
|
||||
|
||||
private void tryToStartVideoRecording() {
|
||||
if (muted || surfaceView == null || parameters == null) return;
|
||||
|
||||
parameters.rotation = rotation;
|
||||
parameters.surfaceView = surfaceView;
|
||||
if (version >= 8) {
|
||||
recorder = new AndroidCameraRecordBufferedImpl(parameters);
|
||||
} else if (version >= 5) {
|
||||
recorder = new AndroidCameraRecordImplAPI5(parameters);
|
||||
} else {
|
||||
recorder = new AndroidCameraRecordImpl(parameters);
|
||||
}
|
||||
|
||||
recorder.startPreview();
|
||||
}
|
||||
|
||||
public void stopVideoRecording() {
|
||||
if (recorder != null) {
|
||||
recorder.stopPreview();
|
||||
recorder = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FIXME select right camera
|
||||
/**
|
||||
* Eventually null if API < 5.
|
||||
*
|
||||
*/
|
||||
public List<Size> supportedVideoSizes() {
|
||||
if (supportedVideoSizes != null) {
|
||||
return supportedVideoSizes;
|
||||
}
|
||||
|
||||
if (recorder != null) {
|
||||
supportedVideoSizes = recorder.getSupportedVideoSizes();
|
||||
if (supportedVideoSizes != null) return supportedVideoSizes;
|
||||
}
|
||||
|
||||
if (version >= 5) {
|
||||
supportedVideoSizes = AndroidCameraRecordImplAPI5.oneShotSupportedVideoSizes();
|
||||
}
|
||||
|
||||
// eventually null
|
||||
|
||||
return supportedVideoSizes;
|
||||
}
|
||||
|
||||
|
||||
public boolean isRecording() {
|
||||
if (recorder != null) {
|
||||
return recorder.isStarted();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void invalidateParameters() {
|
||||
stopVideoRecording();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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.getHeight() && s.width == testSize.getWidth()) {
|
||||
return vSize;
|
||||
}
|
||||
}
|
||||
|
||||
return VideoSize.createStandard(defaultSizeCode, defaultIsPortrait);
|
||||
}
|
||||
|
||||
private static final int rearCamId() {return 1;}
|
||||
private static final int frontCamId() {return 2;}
|
||||
private final int cameraId() {return useFrontCamera? frontCamId() : rearCamId(); }
|
||||
}
|
||||
89
AndroidVideoWindowImpl.java
Normal file
89
AndroidVideoWindowImpl.java
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
package org.linphone.core;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.Surface.OutOfResourcesException;
|
||||
import android.view.SurfaceHolder.Callback;
|
||||
|
||||
public class AndroidVideoWindowImpl {
|
||||
private Bitmap mBitmap;
|
||||
private SurfaceView mView;
|
||||
private Surface mSurface;
|
||||
private VideoWindowListener mListener;
|
||||
static private String TAG = "Linphone";
|
||||
public static interface VideoWindowListener{
|
||||
void onSurfaceReady(AndroidVideoWindowImpl vw);
|
||||
void onSurfaceDestroyed(AndroidVideoWindowImpl vw);
|
||||
};
|
||||
public AndroidVideoWindowImpl(SurfaceView view){
|
||||
mView=view;
|
||||
mBitmap=null;
|
||||
mSurface=null;
|
||||
mListener=null;
|
||||
view.getHolder().addCallback(new Callback(){
|
||||
public void surfaceChanged(SurfaceHolder holder, int format,
|
||||
int width, int height) {
|
||||
Log.i(TAG,"Surface is being changed.");
|
||||
synchronized(AndroidVideoWindowImpl.this){
|
||||
mBitmap=Bitmap.createBitmap(width,height,Config.RGB_565);
|
||||
mSurface=holder.getSurface();
|
||||
}
|
||||
if (mListener!=null) mListener.onSurfaceReady(AndroidVideoWindowImpl.this);
|
||||
Log.w("Linphone", "Video display surface changed");
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
Log.w("Linphone", "Video display surface created");
|
||||
}
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
synchronized(AndroidVideoWindowImpl.this){
|
||||
mSurface=null;
|
||||
mBitmap=null;
|
||||
}
|
||||
if (mListener!=null)
|
||||
mListener.onSurfaceDestroyed(AndroidVideoWindowImpl.this);
|
||||
Log.d("Linphone", "Video display surface destroyed");
|
||||
}
|
||||
});
|
||||
}
|
||||
static final int LANDSCAPE=0;
|
||||
static final int PORTRAIT=1;
|
||||
public void requestOrientation(int orientation){
|
||||
//Surface.setOrientation(0, orientation==LANDSCAPE ? 1 : 0);
|
||||
//Log.d("Linphone", "Orientation changed.");
|
||||
}
|
||||
public void setListener(VideoWindowListener l){
|
||||
mListener=l;
|
||||
}
|
||||
public Surface getSurface(){
|
||||
return mView.getHolder().getSurface();
|
||||
}
|
||||
public Bitmap getBitmap(){
|
||||
return mBitmap;
|
||||
}
|
||||
//Called by the mediastreamer2 android display filter
|
||||
public synchronized void update(){
|
||||
if (mSurface!=null){
|
||||
try {
|
||||
Canvas canvas=mSurface.lockCanvas(null);
|
||||
canvas.drawBitmap(mBitmap, 0, 0, null);
|
||||
mSurface.unlockCanvasAndPost(canvas);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (OutOfResourcesException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -29,6 +29,9 @@ class LinphoneCallImpl implements LinphoneCall {
|
|||
private native boolean isIncoming(long nativePtr);
|
||||
native private long getRemoteAddress(long nativePtr);
|
||||
native private int getState(long nativePtr);
|
||||
private native long getCurrentParamsCopy(long nativePtr);
|
||||
private native void enableCamera(long nativePtr, boolean enabled);
|
||||
|
||||
protected LinphoneCallImpl(long aNativePtr) {
|
||||
nativePtr = aNativePtr;
|
||||
ref(nativePtr);
|
||||
|
|
@ -58,12 +61,11 @@ class LinphoneCallImpl implements LinphoneCall {
|
|||
public State getState() {
|
||||
return LinphoneCall.State.fromInt(getState(nativePtr));
|
||||
}
|
||||
public LinphoneCallParams getCurrentParamsReadOnly() {
|
||||
throw new RuntimeException("Not Implemenetd yet");
|
||||
public LinphoneCallParams getCurrentParamsCopy() {
|
||||
return new LinphoneCallParamsImpl(getCurrentParamsCopy(nativePtr));
|
||||
}
|
||||
|
||||
public void enableCamera(boolean enabled) {
|
||||
throw new RuntimeException("Not Implemenetd yet");
|
||||
enableCamera(nativePtr, enabled);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,8 +43,7 @@ class LinphoneCallLogImpl implements LinphoneCallLog {
|
|||
return new LinphoneAddressImpl(getTo(nativePtr));
|
||||
}
|
||||
public CallStatus getStatus() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
throw new RuntimeException("not implemented yet");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
51
LinphoneCallParamsImpl.java
Normal file
51
LinphoneCallParamsImpl.java
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
LinphoneCallParamsImpl.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;
|
||||
|
||||
public class LinphoneCallParamsImpl implements LinphoneCallParams {
|
||||
protected final long nativePtr;
|
||||
|
||||
public LinphoneCallParamsImpl(long nativePtr) {
|
||||
this.nativePtr = nativePtr;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
public boolean getVideoEnabled() {
|
||||
return getVideoEnabled(nativePtr);
|
||||
}
|
||||
|
||||
public void setVideoEnabled(boolean b) {
|
||||
enableVideo(nativePtr, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
destroy(nativePtr);
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public void setAudioBandwidth(int value) {
|
||||
audioBandwidth(nativePtr, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,8 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
import java.util.Vector;
|
||||
|
||||
import android.view.SurfaceView;
|
||||
|
||||
|
||||
class LinphoneCoreImpl implements LinphoneCore {
|
||||
|
||||
|
|
@ -53,6 +55,7 @@ class LinphoneCoreImpl implements LinphoneCore {
|
|||
private native void muteMic(long nativePtr,boolean isMuted);
|
||||
private native long interpretUrl(long nativePtr,String destination);
|
||||
private native long inviteAddress(long nativePtr,long to);
|
||||
private native long inviteAddressWithParams(long nativePtrLc,long to, long nativePtrParam);
|
||||
private native void sendDtmf(long nativePtr,char dtmf);
|
||||
private native void clearCallLogs(long nativePtr);
|
||||
private native boolean isMicMuted(long nativePtr);
|
||||
|
|
@ -63,12 +66,31 @@ class LinphoneCoreImpl implements LinphoneCore {
|
|||
private native long getCurrentCall(long nativePtr) ;
|
||||
private native void playDtmf(long nativePtr,char dtmf,int duration);
|
||||
private native void stopDtmf(long nativePtr);
|
||||
|
||||
private native void setVideoWindowId(long nativePtr, Object wid);
|
||||
private native void setPreviewWindowId(long nativePtr, Object wid);
|
||||
private AndroidVideoWindowImpl mVideoWindow;
|
||||
private AndroidVideoWindowImpl mPreviewWindow;
|
||||
private native void addFriend(long nativePtr,long friend);
|
||||
private native void setPresenceInfo(long nativePtr,int minute_away, String alternative_contact,int status);
|
||||
private native long createChatRoom(long nativePtr,String to);
|
||||
private native void enableVideo(long nativePtr,boolean vcap_enabled,boolean display_enabled);
|
||||
private native boolean isVideoEnabled(long nativePtr);
|
||||
private native void setFirewallPolicy(long nativePtr, int enum_value);
|
||||
private native int getFirewallPolicy(long nativePtr);
|
||||
private native void setStunServer(long nativePtr, String stun_server);
|
||||
private native String getStunServer(long nativePtr);
|
||||
private native long createDefaultCallParams(long nativePtr);
|
||||
private native int updateCall(long ptrLc, long ptrCall, long ptrParams);
|
||||
private native void setUploadBandwidth(long nativePtr, int bw);
|
||||
private native void setDownloadBandwidth(long nativePtr, int bw);
|
||||
private native void setPreferredVideoSize(long nativePtr, int width, int heigth);
|
||||
private native int[] getPreferredVideoSize(long nativePtr);
|
||||
private native void setRing(long nativePtr, String path);
|
||||
private native String getRing(long nativePtr);
|
||||
private native long[] listVideoPayloadTypes(long nativePtr);
|
||||
|
||||
|
||||
private static final String TAG = "LinphoneCore";
|
||||
|
||||
LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException {
|
||||
mListener=listener;
|
||||
|
|
@ -200,14 +222,15 @@ class LinphoneCoreImpl implements LinphoneCore {
|
|||
throw new LinphoneCoreException("Cannot interpret ["+destination+"]");
|
||||
}
|
||||
}
|
||||
public LinphoneCall invite(LinphoneAddress to) {
|
||||
public LinphoneCall invite(LinphoneAddress to) throws LinphoneCoreException {
|
||||
long lNativePtr = inviteAddress(nativePtr,((LinphoneAddressImpl)to).nativePtr);
|
||||
if (lNativePtr!=0) {
|
||||
return new LinphoneCallImpl(lNativePtr);
|
||||
} else {
|
||||
return null;
|
||||
throw new LinphoneCoreException("Unable to invite address " + to.asString());
|
||||
}
|
||||
}
|
||||
|
||||
public void sendDtmf(char number) {
|
||||
sendDtmf(nativePtr,number);
|
||||
}
|
||||
|
|
@ -295,73 +318,114 @@ class LinphoneCoreImpl implements LinphoneCore {
|
|||
return new LinphoneChatRoomImpl(createChatRoom(nativePtr,to));
|
||||
}
|
||||
public void setPreviewWindow(Object w) {
|
||||
throw new RuntimeException("not implemented yet");
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
if (mPreviewWindow!=null)
|
||||
mPreviewWindow.setListener(null);
|
||||
mPreviewWindow=new AndroidVideoWindowImpl((SurfaceView)w);
|
||||
mPreviewWindow.setListener(new AndroidVideoWindowImpl.VideoWindowListener(){
|
||||
public void onSurfaceDestroyed(AndroidVideoWindowImpl vw) {
|
||||
setPreviewWindowId(nativePtr,null);
|
||||
}
|
||||
|
||||
public void onSurfaceReady(AndroidVideoWindowImpl vw) {
|
||||
setPreviewWindowId(nativePtr,vw);
|
||||
}
|
||||
});
|
||||
}
|
||||
public void setVideoWindow(Object w) {
|
||||
throw new RuntimeException("not implemented yet");
|
||||
// TODO Auto-generated method stub
|
||||
if (mVideoWindow!=null)
|
||||
mVideoWindow.setListener(null);
|
||||
mVideoWindow=new AndroidVideoWindowImpl((SurfaceView) w);
|
||||
mVideoWindow.setListener(new AndroidVideoWindowImpl.VideoWindowListener(){
|
||||
public void onSurfaceDestroyed(AndroidVideoWindowImpl vw) {
|
||||
setVideoWindowId(nativePtr,null);
|
||||
}
|
||||
|
||||
public void onSurfaceReady(AndroidVideoWindowImpl vw) {
|
||||
setVideoWindowId(nativePtr,vw);
|
||||
}
|
||||
});
|
||||
}
|
||||
public void enableVideo(boolean vcap_enabled, boolean display_enabled) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
enableVideo(nativePtr,vcap_enabled, display_enabled);
|
||||
}
|
||||
public boolean isVideoEnabled() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
public void setStunServer(String stun_server) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
public String getStunServer() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
public void setFirewallPolicy(FirewallPolicy pol) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
return isVideoEnabled(nativePtr);
|
||||
}
|
||||
public FirewallPolicy getFirewallPolicy() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
return FirewallPolicy.fromInt(getFirewallPolicy(nativePtr));
|
||||
}
|
||||
public String getStunServer() {
|
||||
return getStunServer(nativePtr);
|
||||
}
|
||||
public void setFirewallPolicy(FirewallPolicy pol) {
|
||||
setFirewallPolicy(nativePtr,pol.value());
|
||||
}
|
||||
public void setStunServer(String stunServer) {
|
||||
setStunServer(nativePtr,stunServer);
|
||||
}
|
||||
|
||||
public LinphoneCallParams createDefaultCallParameters() {
|
||||
return new LinphoneCallParamsImpl(createDefaultCallParams(nativePtr));
|
||||
}
|
||||
|
||||
public LinphoneCall inviteAddressWithParams(LinphoneAddress to, LinphoneCallParams params) throws LinphoneCoreException {
|
||||
long ptrDestination = ((LinphoneAddressImpl)to).nativePtr;
|
||||
long ptrParams =((LinphoneCallParamsImpl)params).nativePtr;
|
||||
|
||||
long lcNativePtr = inviteAddressWithParams(nativePtr, ptrDestination, ptrParams);
|
||||
if (lcNativePtr!=0) {
|
||||
return new LinphoneCallImpl(lcNativePtr);
|
||||
} else {
|
||||
throw new LinphoneCoreException("Unable to invite with params " + to.asString());
|
||||
}
|
||||
}
|
||||
|
||||
public int updateCall(LinphoneCall call, LinphoneCallParams params) {
|
||||
long ptrCall = ((LinphoneCallImpl) call).nativePtr;
|
||||
long ptrParams = ((LinphoneCallParamsImpl)params).nativePtr;
|
||||
|
||||
return updateCall(nativePtr, ptrCall, ptrParams);
|
||||
}
|
||||
public void setUploadBandwidth(int bw) {
|
||||
setUploadBandwidth(nativePtr, bw);
|
||||
}
|
||||
|
||||
public void setDownloadBandwidth(int bw) {
|
||||
setDownloadBandwidth(nativePtr, bw);
|
||||
}
|
||||
|
||||
public void setPreferredVideoSize(VideoSize vSize) {
|
||||
setPreferredVideoSize(nativePtr, vSize.getWidth(), vSize.getHeight());
|
||||
}
|
||||
|
||||
public VideoSize getPreferredVideoSize() {
|
||||
int[] nativeSize = getPreferredVideoSize(nativePtr);
|
||||
|
||||
VideoSize vSize = new VideoSize();
|
||||
vSize.setWidth(nativeSize[0]);
|
||||
vSize.setHeight(nativeSize[1]);
|
||||
return vSize;
|
||||
}
|
||||
public void setRing(String path) {
|
||||
setRing(nativePtr,path);
|
||||
|
||||
setRing(nativePtr, path);
|
||||
}
|
||||
public String getRing() {
|
||||
return getRing(nativePtr);
|
||||
}
|
||||
public LinphoneCall inviteAddressWithParams(LinphoneAddress destination,
|
||||
LinphoneCallParams params) throws LinphoneCoreException {
|
||||
throw new RuntimeException("Not Implemenetd yet");
|
||||
}
|
||||
public int updateCall(LinphoneCall call, LinphoneCallParams params) {
|
||||
throw new RuntimeException("Not Implemenetd yet");
|
||||
}
|
||||
public LinphoneCallParams createDefaultCallParameters() {
|
||||
throw new RuntimeException("Not Implemenetd yet");
|
||||
|
||||
public PayloadType[] listVideoCodecs() {
|
||||
long[] typesPtr = listVideoPayloadTypes(nativePtr);
|
||||
if (typesPtr == null) return null;
|
||||
|
||||
PayloadType[] codecs = new PayloadType[typesPtr.length];
|
||||
|
||||
for (int i=0; i < codecs.length; i++) {
|
||||
codecs[i] = new PayloadTypeImpl(typesPtr[i]);
|
||||
}
|
||||
|
||||
return codecs;
|
||||
}
|
||||
public boolean isNetworkReachable() {
|
||||
throw new RuntimeException("Not Implemenetd yet");
|
||||
throw new RuntimeException("Not implemented");
|
||||
}
|
||||
public void setUploadBandwidth(int bw) {
|
||||
throw new RuntimeException("Not Implemenetd yet");
|
||||
}
|
||||
public void setDownloadBandwidth(int bw) {
|
||||
throw new RuntimeException("Not Implemenetd yet");
|
||||
}
|
||||
public void setPreferredVideoSize(VideoSize vSize) {
|
||||
throw new RuntimeException("Not Implemenetd yet");
|
||||
}
|
||||
public VideoSize getPreferredVideoSize() {
|
||||
throw new RuntimeException("Not Implemenetd yet");
|
||||
}
|
||||
public PayloadType[] listVideoCodecs() {
|
||||
throw new RuntimeException("Not Implemenetd yet");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,15 +24,22 @@ class PayloadTypeImpl implements PayloadType {
|
|||
protected final long nativePtr;
|
||||
|
||||
private native String toString(long ptr);
|
||||
|
||||
private native String getMime(long ptr);
|
||||
private native int getRate(long ptr);
|
||||
|
||||
protected PayloadTypeImpl(long aNativePtr) {
|
||||
nativePtr = aNativePtr;
|
||||
}
|
||||
public String toString() {
|
||||
return toString(nativePtr);
|
||||
|
||||
public int getRate() {
|
||||
return getRate(nativePtr);
|
||||
}
|
||||
|
||||
public String getMime() {
|
||||
throw new RuntimeException("Not Implemenetd yet");
|
||||
return getMime(nativePtr);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return toString(nativePtr);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
81
tutorials/JavaCameraRecordImpl.java
Normal file
81
tutorials/JavaCameraRecordImpl.java
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
JavaCameraRecordImpl.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.tutorials;
|
||||
|
||||
import org.linphone.core.AndroidCameraRecord;
|
||||
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.PreviewCallback;
|
||||
import android.hardware.Camera.Size;
|
||||
import android.util.Log;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class JavaCameraRecordImpl extends AndroidCameraRecord implements PreviewCallback {
|
||||
|
||||
private TextView debug;
|
||||
private long count = 0;
|
||||
private float averageCalledRate;
|
||||
|
||||
private long startTime;
|
||||
private long endTime;
|
||||
private int fps;
|
||||
|
||||
|
||||
public JavaCameraRecordImpl(AndroidCameraRecord.RecorderParams parameters) {
|
||||
super(parameters);
|
||||
storePreviewCallBack(this);
|
||||
fps = Math.round(parameters.fps);
|
||||
}
|
||||
|
||||
|
||||
public void setDebug(TextView debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
||||
|
||||
Size s = camera.getParameters().getPreviewSize();
|
||||
int expectedBuffLength = s.width * s.height * 3 /2;
|
||||
if (expectedBuffLength != data.length) {
|
||||
Log.e("Linphone", "onPreviewFrame called with bad buffer length " + data.length
|
||||
+ " whereas expected is " + expectedBuffLength + " don't calling putImage");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((count % 2 * fps) == 0) {
|
||||
endTime = System.currentTimeMillis();
|
||||
averageCalledRate = (100000 * 2 * fps) / (endTime - startTime);
|
||||
averageCalledRate /= 100f;
|
||||
startTime = endTime;
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
String msg = "Frame " + count + ": " + data.length + "bytes (avg="+averageCalledRate+"frames/s)";
|
||||
if (debug != null) debug.setText(msg);
|
||||
Log.d("onPreviewFrame:", msg);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb) {
|
||||
camera.setPreviewCallback(cb);
|
||||
}
|
||||
|
||||
}
|
||||
191
tutorials/TestVideoActivity.java
Normal file
191
tutorials/TestVideoActivity.java
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
TutorialHelloWorldActivity.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.tutorials;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
import org.linphone.R;
|
||||
import org.linphone.core.AndroidCameraRecord;
|
||||
import org.linphone.core.VideoSize;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.SurfaceHolder.Callback;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import static org.linphone.core.VideoSize.*;
|
||||
|
||||
/**
|
||||
* Activity for displaying and starting the HelloWorld example on Android phone.
|
||||
*
|
||||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
public class TestVideoActivity extends Activity implements Callback, OnClickListener {
|
||||
|
||||
private SurfaceView surfaceView;
|
||||
private static final int rate = 7;
|
||||
private JavaCameraRecordImpl recorder;
|
||||
private static String tag = "Linphone";
|
||||
private TextView debugView;
|
||||
private Button nextSize;
|
||||
private Button changeCamera;
|
||||
private Button changeOrientation;
|
||||
private AndroidCameraRecord.RecorderParams params;
|
||||
|
||||
private Stack<VideoSize> videoSizes = createSizesToTest();
|
||||
private int currentCameraId = 2;
|
||||
private boolean currentOrientationIsPortrait = false;
|
||||
private int width;
|
||||
private int height;
|
||||
private boolean started;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.videotest);
|
||||
|
||||
surfaceView=(SurfaceView)findViewById(R.id.videotest_surfaceView);
|
||||
|
||||
nextSize = (Button) findViewById(R.id.test_video_size);
|
||||
nextSize.setOnClickListener(this);
|
||||
|
||||
changeCamera = (Button) findViewById(R.id.test_video_camera);
|
||||
changeCamera.setText("Cam"+otherCameraId(currentCameraId));
|
||||
changeCamera.setOnClickListener(new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
changeCamera.setText("Cam"+currentCameraId);
|
||||
currentCameraId = otherCameraId(currentCameraId);
|
||||
updateRecording();
|
||||
}
|
||||
});
|
||||
|
||||
changeOrientation = (Button) findViewById(R.id.test_video_orientation);
|
||||
changeOrientation.setText(orientationToString(!currentOrientationIsPortrait));
|
||||
changeOrientation.setOnClickListener(new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
currentOrientationIsPortrait = !currentOrientationIsPortrait;
|
||||
changeOrientation.setText(orientationToString(!currentOrientationIsPortrait));
|
||||
|
||||
if (width == 0 || height == 0) return;
|
||||
int newWidth = currentOrientationIsPortrait? Math.min(height, width) : Math.max(height, width);
|
||||
int newHeight = currentOrientationIsPortrait? Math.max(height, width) : Math.min(height, width);
|
||||
changeSurfaceViewLayout(newWidth, newHeight); // will change width and height on surfaceChanged
|
||||
}
|
||||
});
|
||||
|
||||
SurfaceHolder holder = surfaceView.getHolder();
|
||||
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||||
holder.addCallback(this);
|
||||
|
||||
|
||||
debugView = (TextView) findViewById(R.id.videotest_debug);
|
||||
}
|
||||
|
||||
protected void updateRecording() {
|
||||
if (width == 0 || height == 0) return;
|
||||
if (recorder != null) recorder.stopPreview();
|
||||
|
||||
params = new AndroidCameraRecord.RecorderParams(0);
|
||||
params.surfaceView = surfaceView;
|
||||
params.width = width;
|
||||
params.height = height;
|
||||
params.fps = rate;
|
||||
params.cameraId = currentCameraId;
|
||||
|
||||
recorder = new JavaCameraRecordImpl(params);
|
||||
// recorder.setDebug(debugView);
|
||||
debugView.setText(orientationToString(currentOrientationIsPortrait)
|
||||
+ " w="+width + " h="+height+ " cam"+currentCameraId);
|
||||
recorder.startPreview();
|
||||
|
||||
}
|
||||
|
||||
private String orientationToString(boolean orientationIsPortrait) {
|
||||
return orientationIsPortrait? "Por" : "Lan";
|
||||
}
|
||||
private int otherCameraId(int currentId) {
|
||||
return (currentId == 2) ? 1 : 2;
|
||||
}
|
||||
public void onClick(View v) {
|
||||
nextSize.setText("Next");
|
||||
started=true;
|
||||
if (videoSizes.isEmpty()) {
|
||||
videoSizes = createSizesToTest();
|
||||
}
|
||||
|
||||
VideoSize size = videoSizes.pop();
|
||||
changeSurfaceViewLayout(size.getWidth(), size.getHeight());
|
||||
|
||||
// on surface changed the recorder will be restarted with new values
|
||||
// and the surface will be resized
|
||||
}
|
||||
|
||||
|
||||
private void changeSurfaceViewLayout(int width, int height) {
|
||||
LayoutParams params = surfaceView.getLayoutParams();
|
||||
params.height = height;
|
||||
params.width = width;
|
||||
surfaceView.setLayoutParams(params);
|
||||
|
||||
}
|
||||
|
||||
private Stack<VideoSize> createSizesToTest() {
|
||||
Stack<VideoSize> stack = new Stack<VideoSize>();
|
||||
|
||||
stack.push(VideoSize.createStandard(QCIF, false));
|
||||
stack.push(VideoSize.createStandard(CIF, false));
|
||||
stack.push(VideoSize.createStandard(QVGA, false));
|
||||
stack.push(VideoSize.createStandard(HVGA, false));
|
||||
stack.push(new VideoSize(640,480));
|
||||
stack.push(new VideoSize(800,480));
|
||||
return stack;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
surfaceView = null;
|
||||
Log.d(tag , "Video capture surface destroyed");
|
||||
if (recorder != null) recorder.stopPreview();
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
Log.d(tag , "Video capture surface created");
|
||||
}
|
||||
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
if (!started) return;
|
||||
if (recorder != null) recorder.stopPreview();
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
updateRecording();
|
||||
}
|
||||
}
|
||||
|
|
@ -76,6 +76,7 @@ public class TutorialRegistrationActivity extends TutorialHelloWorldActivity {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
Button buttonStop = (Button) findViewById(R.id.ButtonStop);
|
||||
buttonStop.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue