mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-19 20:18:09 +00:00
New Mediastreamer Android Camera filter integration
android: new mediastreamer integration android: new ms2 integration Video calls minor corrections
This commit is contained in:
parent
b923fd19d6
commit
b0357a9ddd
15 changed files with 31 additions and 1790 deletions
|
|
@ -1,162 +0,0 @@
|
|||
package org.linphone.core;
|
||||
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
import org.linphone.OpenGLESDisplay;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.opengl.GLSurfaceView;
|
||||
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 boolean useGLrendering;
|
||||
private Bitmap mBitmap;
|
||||
private SurfaceView mView;
|
||||
private Surface mSurface;
|
||||
private VideoWindowListener mListener;
|
||||
private Renderer renderer;
|
||||
public static interface VideoWindowListener{
|
||||
void onSurfaceReady(AndroidVideoWindowImpl vw);
|
||||
void onSurfaceDestroyed(AndroidVideoWindowImpl vw);
|
||||
};
|
||||
public AndroidVideoWindowImpl(SurfaceView view){
|
||||
useGLrendering = (view instanceof GLSurfaceView);
|
||||
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("Surface is being changed.");
|
||||
if (!useGLrendering) {
|
||||
synchronized(AndroidVideoWindowImpl.this){
|
||||
mBitmap=Bitmap.createBitmap(width,height,Config.RGB_565);
|
||||
mSurface=holder.getSurface();
|
||||
}
|
||||
}
|
||||
if (mListener!=null) mListener.onSurfaceReady(AndroidVideoWindowImpl.this);
|
||||
Log.w("Video display surface changed");
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
Log.w("Video display surface created");
|
||||
}
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
if (!useGLrendering) {
|
||||
synchronized(AndroidVideoWindowImpl.this){
|
||||
mSurface=null;
|
||||
mBitmap=null;
|
||||
}
|
||||
}
|
||||
if (mListener!=null)
|
||||
mListener.onSurfaceDestroyed(AndroidVideoWindowImpl.this);
|
||||
Log.d("Video display surface destroyed");
|
||||
}
|
||||
});
|
||||
|
||||
if (useGLrendering) {
|
||||
renderer = new Renderer();
|
||||
((GLSurfaceView)mView).setRenderer(renderer);
|
||||
((GLSurfaceView)mView).setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
|
||||
}
|
||||
}
|
||||
static final int LANDSCAPE=0;
|
||||
static final int PORTRAIT=1;
|
||||
public void requestOrientation(int orientation){
|
||||
//Surface.setOrientation(0, orientation==LANDSCAPE ? 1 : 0);
|
||||
//Log.d("Orientation changed.");
|
||||
}
|
||||
public void setListener(VideoWindowListener l){
|
||||
mListener=l;
|
||||
}
|
||||
public Surface getSurface(){
|
||||
if (useGLrendering)
|
||||
Log.e("View class does not match Video display filter used (you must use a non-GL View)");
|
||||
return mView.getHolder().getSurface();
|
||||
}
|
||||
public Bitmap getBitmap(){
|
||||
if (useGLrendering)
|
||||
Log.e("View class does not match Video display filter used (you must use a non-GL View)");
|
||||
return mBitmap;
|
||||
}
|
||||
|
||||
public void setOpenGLESDisplay(int ptr) {
|
||||
if (!useGLrendering)
|
||||
Log.e("View class does not match Video display filter used (you must use a GL View)");
|
||||
renderer.setOpenGLESDisplay(ptr);
|
||||
}
|
||||
|
||||
public void requestRender() {
|
||||
((GLSurfaceView)mView).requestRender();
|
||||
}
|
||||
|
||||
//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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Renderer implements GLSurfaceView.Renderer {
|
||||
int ptr;
|
||||
boolean initPending;
|
||||
int width=-1, height=-1;
|
||||
|
||||
public Renderer() {
|
||||
ptr = 0;
|
||||
initPending = false;
|
||||
}
|
||||
|
||||
public void setOpenGLESDisplay(int ptr) {
|
||||
this.ptr = ptr;
|
||||
// if dimension are set, we are recreating MS2 graph without
|
||||
// recreating the surface => need to force init
|
||||
if (width > 0 && height > 0) {
|
||||
initPending = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void onDrawFrame(GL10 gl) {
|
||||
if (ptr == 0)
|
||||
return;
|
||||
if (initPending) {
|
||||
OpenGLESDisplay.init(ptr, width, height);
|
||||
initPending = false;
|
||||
}
|
||||
OpenGLESDisplay.render(ptr);
|
||||
}
|
||||
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||
/* delay init until ptr is set */
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
initPending = true;
|
||||
}
|
||||
|
||||
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
146
Hacks.java
146
Hacks.java
|
|
@ -1,146 +0,0 @@
|
|||
/*
|
||||
Hacks.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.media.AudioManager;
|
||||
import android.os.Build;
|
||||
|
||||
public final class Hacks {
|
||||
|
||||
private Hacks() {}
|
||||
|
||||
|
||||
public static boolean isGalaxySOrTabWithFrontCamera() {
|
||||
return isGalaxySOrTab() && !isGalaxySOrTabWithoutFrontCamera();
|
||||
}
|
||||
private static boolean isGalaxySOrTabWithoutFrontCamera() {
|
||||
return isSC02B() || isSGHI896();
|
||||
}
|
||||
|
||||
|
||||
public static boolean isGalaxySOrTab() {
|
||||
return isGalaxyS() || isGalaxyTab();
|
||||
}
|
||||
|
||||
public static boolean isGalaxyTab() {
|
||||
return isGTP1000();
|
||||
}
|
||||
private static boolean isGalaxyS() {
|
||||
return isGT9000() || isSC02B() || isSGHI896() || isSPHD700();
|
||||
}
|
||||
|
||||
public static final boolean hasTwoCamerasRear0Front1() {
|
||||
return isSPHD700() || isADR6400();
|
||||
}
|
||||
|
||||
// HTC
|
||||
private static final boolean isADR6400() {
|
||||
return Build.MODEL.startsWith("ADR6400") || Build.DEVICE.startsWith("ADR6400");
|
||||
} // HTC Thunderbolt
|
||||
|
||||
// Galaxy S variants
|
||||
private static final boolean isSPHD700() {return Build.DEVICE.startsWith("SPH-D700");} // Epic
|
||||
private static boolean isSGHI896() {return Build.DEVICE.startsWith("SGH-I896");} // Captivate
|
||||
private static boolean isGT9000() {return Build.DEVICE.startsWith("GT-I9000");} // Galaxy S
|
||||
private static boolean isSC02B() {return Build.DEVICE.startsWith("SC-02B");} // Docomo
|
||||
private static boolean isGTP1000() {return Build.DEVICE.startsWith("GT-P1000");} // Tab
|
||||
|
||||
|
||||
/* private static final boolean log(final String msg) {
|
||||
Log.d(msg);
|
||||
return true;
|
||||
}*/
|
||||
|
||||
/* Not working as now
|
||||
* Calling from Galaxy S to PC is "usable" even with no hack; other side is not even with this one*/
|
||||
public static void galaxySSwitchToCallStreamUnMuteLowerVolume(AudioManager am) {
|
||||
// Switch to call audio channel (Galaxy S)
|
||||
am.setSpeakerphoneOn(false);
|
||||
sleep(200);
|
||||
|
||||
// Lower volume
|
||||
am.setStreamVolume(AudioManager.STREAM_VOICE_CALL, 1, 0);
|
||||
|
||||
// Another way to select call channel
|
||||
am.setMode(AudioManager.MODE_NORMAL);
|
||||
sleep(200);
|
||||
|
||||
// Mic is muted if not doing this
|
||||
am.setMicrophoneMute(true);
|
||||
sleep(200);
|
||||
am.setMicrophoneMute(false);
|
||||
sleep(200);
|
||||
}
|
||||
|
||||
public static final void sleep(int time) {
|
||||
try {
|
||||
Thread.sleep(time);
|
||||
} catch(InterruptedException ie){}
|
||||
}
|
||||
|
||||
public static void dumpDeviceInformation() {
|
||||
StringBuilder sb = new StringBuilder(" ==== Phone information dump ====\n");
|
||||
sb.append("DEVICE=").append(Build.DEVICE).append("\n");
|
||||
sb.append("MODEL=").append(Build.MODEL).append("\n");
|
||||
//MANUFACTURER doesn't exist in android 1.5.
|
||||
//sb.append("MANUFACTURER=").append(Build.MANUFACTURER).append("\n");
|
||||
sb.append("SDK=").append(Build.VERSION.SDK);
|
||||
|
||||
Log.i(sb.toString());
|
||||
}
|
||||
|
||||
public static boolean needSoftvolume() {
|
||||
return isGalaxySOrTab();
|
||||
}
|
||||
|
||||
public static boolean needRoutingAPI() {
|
||||
return Version.sdkStrictlyBelow(5) /*<donut*/;
|
||||
}
|
||||
|
||||
public static boolean needGalaxySAudioHack() {
|
||||
return isGalaxySOrTab() && !isSC02B();
|
||||
}
|
||||
|
||||
public static boolean needPausingCallForSpeakers() {
|
||||
// return false;
|
||||
return isGalaxySOrTab() && !isSC02B();
|
||||
}
|
||||
|
||||
public static boolean hasTwoCameras() {
|
||||
return isSPHD700() || isGalaxySOrTabWithFrontCamera();
|
||||
}
|
||||
|
||||
public static boolean hasCamera() {
|
||||
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
|
||||
int nb = 0;
|
||||
try {
|
||||
nb = (Integer) Camera.class.getMethod("getNumberOfCameras", (Class[])null).invoke(null);
|
||||
} catch (Exception e) {
|
||||
Log.e("Error getting number of cameras");
|
||||
}
|
||||
return nb > 0;
|
||||
}
|
||||
|
||||
Log.i("Hack: considering there IS a camera.\n"
|
||||
+ "If it is not the case, report DEVICE and MODEL to linphone-users@nongnu.org");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ package org.linphone.core;
|
|||
|
||||
|
||||
class LinphoneCallImpl implements LinphoneCall {
|
||||
|
||||
|
||||
protected final long nativePtr;
|
||||
boolean ownPtr = false;
|
||||
native private void ref(long ownPtr);
|
||||
|
|
@ -31,6 +31,7 @@ class LinphoneCallImpl implements LinphoneCall {
|
|||
native private int getState(long nativePtr);
|
||||
private native long getCurrentParamsCopy(long nativePtr);
|
||||
private native void enableCamera(long nativePtr, boolean enabled);
|
||||
private native boolean cameraEnabled(long nativePtr);
|
||||
private native void enableEchoCancellation(long nativePtr,boolean enable);
|
||||
private native boolean isEchoCancellationEnabled(long nativePtr) ;
|
||||
private native void enableEchoLimiter(long nativePtr,boolean enable);
|
||||
|
|
@ -48,7 +49,7 @@ class LinphoneCallImpl implements LinphoneCall {
|
|||
ref(nativePtr);
|
||||
}
|
||||
protected void finalize() throws Throwable {
|
||||
unref(nativePtr);
|
||||
unref(nativePtr);
|
||||
}
|
||||
public LinphoneCallLog getCallLog() {
|
||||
long lNativePtr = getCallLog(nativePtr);
|
||||
|
|
@ -79,6 +80,10 @@ class LinphoneCallImpl implements LinphoneCall {
|
|||
public void enableCamera(boolean enabled) {
|
||||
enableCamera(nativePtr, enabled);
|
||||
}
|
||||
@Override
|
||||
public boolean cameraEnabled() {
|
||||
return cameraEnabled(nativePtr);
|
||||
}
|
||||
public boolean equals(Object call) {
|
||||
return nativePtr == ((LinphoneCallImpl)call).nativePtr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
import java.util.Vector;
|
||||
|
||||
import android.view.SurfaceView;
|
||||
import org.linphone.LinphoneManager;
|
||||
import org.linphone.mediastream.video.AndroidVideoWindowImpl;
|
||||
|
||||
|
||||
class LinphoneCoreImpl implements LinphoneCore {
|
||||
|
|
@ -68,8 +69,7 @@ class LinphoneCoreImpl implements LinphoneCore {
|
|||
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 setDeviceRotation(long nativePtr, int rotation);
|
||||
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);
|
||||
|
|
@ -104,6 +104,8 @@ class LinphoneCoreImpl implements LinphoneCore {
|
|||
private native void setDownloadPtime(long nativePtr, int ptime);
|
||||
private native void setZrtpSecretsCache(long nativePtr, String file);
|
||||
private native void enableEchoLimiter(long nativePtr2, boolean val);
|
||||
private native int setVideoDevice(long nativePtr2, int id);
|
||||
private native int getVideoDevice(long nativePtr2);
|
||||
|
||||
LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException {
|
||||
mListener=listener;
|
||||
|
|
@ -327,33 +329,15 @@ class LinphoneCoreImpl implements LinphoneCore {
|
|||
return new LinphoneChatRoomImpl(createChatRoom(nativePtr,to));
|
||||
}
|
||||
public synchronized void setPreviewWindow(Object w) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
setPreviewWindowId(nativePtr,w);
|
||||
}
|
||||
public synchronized void setVideoWindow(Object w) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
setVideoWindowId(nativePtr, w);
|
||||
}
|
||||
public synchronized void setDeviceRotation(int rotation) {
|
||||
setDeviceRotation(nativePtr, rotation);
|
||||
}
|
||||
|
||||
public synchronized void enableVideo(boolean vcap_enabled, boolean display_enabled) {
|
||||
enableVideo(nativePtr,vcap_enabled, display_enabled);
|
||||
}
|
||||
|
|
@ -507,5 +491,16 @@ class LinphoneCoreImpl implements LinphoneCore {
|
|||
public void enableEchoLimiter(boolean val) {
|
||||
enableEchoLimiter(nativePtr,val);
|
||||
}
|
||||
@Override
|
||||
public void setVideoDevice(int id) {
|
||||
Log.i("Setting camera id :", id);
|
||||
if (setVideoDevice(nativePtr, id) != 0) {
|
||||
Log.e("Failed to set video device to id:", id);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int getVideoDevice() {
|
||||
return getVideoDevice(nativePtr);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
*/
|
||||
package org.linphone.core;
|
||||
|
||||
import org.linphone.mediastream.video.capture.hwconf.Hacks;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
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.Log;
|
||||
import org.linphone.core.video.AndroidCameraRecord;
|
||||
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.PreviewCallback;
|
||||
import android.hardware.Camera.Size;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* This is an helper class, not a test activity.
|
||||
*
|
||||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
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("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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,194 +0,0 @@
|
|||
/*
|
||||
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 static org.linphone.core.VideoSize.CIF;
|
||||
import static org.linphone.core.VideoSize.HVGA;
|
||||
import static org.linphone.core.VideoSize.QCIF;
|
||||
import static org.linphone.core.VideoSize.QVGA;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
import org.linphone.R;
|
||||
import org.linphone.core.Log;
|
||||
import org.linphone.core.VideoSize;
|
||||
import org.linphone.core.video.AndroidCameraRecord;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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 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.width, size.height);
|
||||
|
||||
// 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("Video capture surface destroyed");
|
||||
if (recorder != null) recorder.stopPreview();
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
Log.d("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();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
AndroidCameraConf.java
|
||||
Copyright (C) 2011 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.video;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.linphone.core.VideoSize;
|
||||
|
||||
|
||||
/**
|
||||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
interface AndroidCameraConf {
|
||||
|
||||
AndroidCameras getFoundCameras();
|
||||
|
||||
int getNumberOfCameras();
|
||||
|
||||
int getCameraOrientation(int cameraId);
|
||||
|
||||
boolean isFrontCamera(int cameraId);
|
||||
|
||||
List<VideoSize> getSupportedPreviewSizes(int cameraId);
|
||||
|
||||
/**
|
||||
* Default: no front; rear=0; default=rear
|
||||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
class AndroidCameras {
|
||||
Integer front;
|
||||
Integer rear = 0;
|
||||
Integer defaultC = rear;
|
||||
|
||||
boolean hasFrontCamera() { return front != null; }
|
||||
boolean hasRearCamera() { return rear != null; }
|
||||
boolean hasSeveralCameras() { return front != rear && front != null; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Cameras :");
|
||||
if (rear != null) sb.append(" rear=").append(rear);
|
||||
if (front != null) sb.append(" front=").append(front);
|
||||
if (defaultC != null) sb.append(" default=").append(defaultC);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
AndroidCameraConf.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.video;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.linphone.core.Hacks;
|
||||
import org.linphone.core.Log;
|
||||
import org.linphone.core.VideoSize;
|
||||
|
||||
import android.hardware.Camera;
|
||||
|
||||
|
||||
class AndroidCameraConf5 implements AndroidCameraConf {
|
||||
private AndroidCameras foundCameras;
|
||||
public AndroidCameras getFoundCameras() {return foundCameras;}
|
||||
|
||||
public AndroidCameraConf5() {
|
||||
// Defaults
|
||||
foundCameras = new AndroidCameras();
|
||||
|
||||
if (Hacks.isGalaxySOrTab()) {
|
||||
Log.d("Hack Galaxy S : has one or more cameras");
|
||||
if (Hacks.isGalaxySOrTabWithFrontCamera()) {
|
||||
Log.d("Hack Galaxy S : HAS a front camera with id=2");
|
||||
foundCameras.front = 2;
|
||||
} else {
|
||||
Log.d("Hack Galaxy S : NO front camera");
|
||||
}
|
||||
Log.d("Hack Galaxy S : HAS a rear camera with id=1");
|
||||
foundCameras.rear = 1;
|
||||
foundCameras.defaultC = foundCameras.rear;
|
||||
} else if (Hacks.hasTwoCamerasRear0Front1()) {
|
||||
Log.d("Hack SPHD700 has 2 cameras a rear with id=0 and a front with id=1");
|
||||
foundCameras.front = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int getNumberOfCameras() {
|
||||
Log.i("Detecting the number of cameras");
|
||||
if (Hacks.hasTwoCamerasRear0Front1() || Hacks.isGalaxySOrTabWithFrontCamera()) {
|
||||
Log.d("Hack: we know this model has 2 cameras");
|
||||
return 2;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int getCameraOrientation(int cameraId) {
|
||||
// Use hacks to guess orientation of the camera
|
||||
if (Hacks.isGalaxySOrTab() && isFrontCamera(cameraId)) {
|
||||
Log.d("Hack Galaxy S : front camera mounted landscape");
|
||||
// mounted in landscape for a portrait phone orientation
|
||||
// |^^^^^^^^|
|
||||
// | ____ |
|
||||
// | |____| |
|
||||
// | |
|
||||
// | |
|
||||
// | Phone |
|
||||
// |________|
|
||||
return 180;
|
||||
}
|
||||
return 90;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean isFrontCamera(int cameraId) {
|
||||
// Use hacks to guess facing of the camera
|
||||
if (cameraId == 2 && Hacks.isGalaxySOrTab()) {
|
||||
Log.d("Hack Galaxy S : front camera has id=2");
|
||||
return true;
|
||||
} else if (cameraId == 1 && Hacks.hasTwoCamerasRear0Front1()) {
|
||||
Log.d("Hack SPHD700 : front camera has id=1");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<VideoSize> getSupportedPreviewSizes(int cameraId) {
|
||||
if (getNumberOfCameras() >1) {
|
||||
Log.w("Hack: on older devices, using video formats supported by default camera");
|
||||
}
|
||||
Log.i("Opening camera to retrieve supported video sizes");
|
||||
Camera c = Camera.open();
|
||||
List<VideoSize> sizes=VideoUtil.createList(c.getParameters().getSupportedPreviewSizes());
|
||||
c.release();
|
||||
Log.i("Camera opened to retrieve supported video sizes released");
|
||||
return sizes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
AndroidCameraConf9.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.video;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.linphone.core.Log;
|
||||
import org.linphone.core.VideoSize;
|
||||
|
||||
import android.hardware.Camera;
|
||||
|
||||
class AndroidCameraConf9 implements AndroidCameraConf {
|
||||
private AndroidCameras foundCameras;
|
||||
private Map<Integer,List<VideoSize>> supportedSizes = new HashMap<Integer, List<VideoSize>>();
|
||||
public AndroidCameras getFoundCameras() {return foundCameras;}
|
||||
|
||||
public AndroidCameraConf9() {
|
||||
foundCameras = new AndroidCameras();
|
||||
|
||||
for (int id=0; id < getNumberOfCameras(); id++) {
|
||||
if (foundCameras.defaultC == null)
|
||||
foundCameras.defaultC = id;
|
||||
|
||||
if (isFrontCamera(id)) {
|
||||
foundCameras.front = id;
|
||||
} else {
|
||||
foundCameras.rear = id;
|
||||
}
|
||||
supportedSizes.put(id, findSupportedVideoSizes(id));
|
||||
}
|
||||
}
|
||||
|
||||
private List<VideoSize> findSupportedVideoSizes(int id) {
|
||||
Log.i("Opening camera ",id," to retrieve supported video sizes");
|
||||
Camera c = Camera.open(id);
|
||||
List<VideoSize> sizes=VideoUtil.createList(c.getParameters().getSupportedPreviewSizes());
|
||||
c.release();
|
||||
Log.i("Camera ",id," opened to retrieve supported video sizes released");
|
||||
return sizes;
|
||||
}
|
||||
|
||||
public int getNumberOfCameras() {
|
||||
return Camera.getNumberOfCameras();
|
||||
}
|
||||
|
||||
public int getCameraOrientation(int cameraId) {
|
||||
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
|
||||
Camera.getCameraInfo(cameraId, info);
|
||||
Log.d("Camera info for ",cameraId,": orientation=",info.orientation);
|
||||
return info.orientation;
|
||||
}
|
||||
|
||||
public boolean isFrontCamera(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;
|
||||
}
|
||||
|
||||
public List<VideoSize> getSupportedPreviewSizes(int cameraId) {
|
||||
return supportedSizes.get(cameraId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,279 +0,0 @@
|
|||
/*
|
||||
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.video;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.linphone.core.Log;
|
||||
import org.linphone.core.Version;
|
||||
import org.linphone.core.VideoSize;
|
||||
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.AutoFocusCallback;
|
||||
import android.hardware.Camera.ErrorCallback;
|
||||
import android.hardware.Camera.Parameters;
|
||||
import android.hardware.Camera.PreviewCallback;
|
||||
import android.hardware.Camera.Size;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
|
||||
|
||||
public abstract class AndroidCameraRecord implements AutoFocusCallback {
|
||||
|
||||
protected Camera camera;
|
||||
private RecorderParams params;
|
||||
|
||||
private PreviewCallback storedPreviewCallback;
|
||||
private boolean previewStarted;
|
||||
private List <VideoSize> supportedVideoSizes;
|
||||
private Size currentPreviewSize;
|
||||
|
||||
public AndroidCameraRecord(RecorderParams parameters) {
|
||||
this.params = parameters;
|
||||
}
|
||||
|
||||
protected List<Size> getSupportedPreviewSizes(Camera.Parameters parameters) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private int[] findClosestEnclosingFpsRange(int expectedFps, List<int[]> fpsRanges) {
|
||||
Log.d("Searching for closest fps range from ",expectedFps);
|
||||
int measure = Integer.MAX_VALUE;
|
||||
int[] closestRange = fpsRanges.get(0);
|
||||
for (int[] curRange : fpsRanges) {
|
||||
if (curRange[0] > expectedFps || curRange[1] < expectedFps) continue;
|
||||
int curMeasure = Math.abs(curRange[0] - expectedFps)
|
||||
+ Math.abs(curRange[1] - expectedFps);
|
||||
if (curMeasure < measure) {
|
||||
closestRange=curRange;
|
||||
Log.d("a better range has been found: w=",closestRange[0],",h=",closestRange[1]);
|
||||
}
|
||||
}
|
||||
Log.d("The closest fps range is w=",closestRange[0],",h=",closestRange[1]);
|
||||
return closestRange;
|
||||
}
|
||||
|
||||
public synchronized void startPreview() { // FIXME throws exception?
|
||||
if (previewStarted) {
|
||||
Log.w("Already started");
|
||||
throw new RuntimeException("Video recorder already started");
|
||||
// return
|
||||
}
|
||||
|
||||
if (params.surfaceView.getVisibility() != SurfaceView.VISIBLE) {
|
||||
// Illegal state
|
||||
Log.e("Illegal state: video capture surface view is not visible");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Log.d("Trying to open camera with id ", params.cameraId);
|
||||
if (camera != null) {
|
||||
Log.e("Camera is not null, ?already open? : aborting");
|
||||
return;
|
||||
}
|
||||
camera = openCamera(params.cameraId);
|
||||
camera.setErrorCallback(new ErrorCallback() {
|
||||
public void onError(int error, Camera camera) {
|
||||
Log.e("Camera error : ", error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Camera.Parameters parameters=camera.getParameters();
|
||||
if (Version.sdkStrictlyBelow(Version.API09_GINGERBREAD_23)) {
|
||||
parameters.set("camera-id",params.cameraId);
|
||||
}
|
||||
|
||||
if (supportedVideoSizes == null) {
|
||||
supportedVideoSizes = VideoUtil.createList(getSupportedPreviewSizes(parameters));
|
||||
}
|
||||
|
||||
|
||||
if (params.width >= params.height) {
|
||||
parameters.setPreviewSize(params.width, params.height);
|
||||
} else {
|
||||
// invert height and width
|
||||
parameters.setPreviewSize(params.height, params.width);
|
||||
}
|
||||
// should setParameters and get again to have the real one??
|
||||
currentPreviewSize = parameters.getPreviewSize();
|
||||
|
||||
// Frame rate
|
||||
if (Version.sdkStrictlyBelow(Version.API09_GINGERBREAD_23)) {
|
||||
// Select the supported fps just faster than the target rate
|
||||
List<Integer> supportedFrameRates=parameters.getSupportedPreviewFrameRates();
|
||||
if (supportedFrameRates != null && supportedFrameRates.size() > 0) {
|
||||
Collections.sort(supportedFrameRates);
|
||||
int selectedRate = -1;
|
||||
for (Integer rate : supportedFrameRates) {
|
||||
selectedRate=rate;
|
||||
if (rate >= params.fps) break;
|
||||
}
|
||||
parameters.setPreviewFrameRate(selectedRate);
|
||||
}
|
||||
} else {
|
||||
List<int[]> supportedRanges = parameters.getSupportedPreviewFpsRange();
|
||||
int[] range=findClosestEnclosingFpsRange((int)(1000*params.fps), supportedRanges);
|
||||
parameters.setPreviewFpsRange(range[0], range[1]);
|
||||
}
|
||||
|
||||
|
||||
onSettingCameraParameters(parameters);
|
||||
camera.setParameters(parameters);
|
||||
|
||||
SurfaceHolder holder = params.surfaceView.getHolder();
|
||||
try {
|
||||
camera.setPreviewDisplay(holder);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
Log.e(t,"Exception in Video capture setPreviewDisplay()");
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
camera.startPreview();
|
||||
} catch (Throwable e) {
|
||||
Log.e("Error, can't start camera preview. Releasing camera!");
|
||||
camera.release();
|
||||
camera = null;
|
||||
return;
|
||||
}
|
||||
|
||||
previewStarted = true;
|
||||
|
||||
// Activate autofocus
|
||||
if (Camera.Parameters.FOCUS_MODE_AUTO.equals(parameters.getFocusMode())) {
|
||||
OnClickListener svClickListener = new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
Log.i("Auto focus requested");
|
||||
camera.autoFocus(AndroidCameraRecord.this);
|
||||
}
|
||||
};
|
||||
params.surfaceView.setOnClickListener(svClickListener);
|
||||
// svClickListener.onClick(null);
|
||||
} else {
|
||||
params.surfaceView.setOnClickListener(null);
|
||||
}
|
||||
|
||||
// Register callback to get capture buffer
|
||||
lowLevelSetPreviewCallback(camera, storedPreviewCallback);
|
||||
|
||||
|
||||
onPreviewStarted(camera);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
protected Camera openCamera(int cameraId) {
|
||||
return Camera.open();
|
||||
}
|
||||
|
||||
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("Capture camera not ready, storing preview callback");
|
||||
return;
|
||||
}
|
||||
|
||||
lowLevelSetPreviewCallback(camera, cb);
|
||||
}
|
||||
|
||||
|
||||
public void stopPreview() {
|
||||
if (!previewStarted) return;
|
||||
lowLevelSetPreviewCallback(camera, null);
|
||||
camera.stopPreview();
|
||||
camera.release();
|
||||
camera=null;
|
||||
Log.d("Camera released");
|
||||
currentPreviewSize = null;
|
||||
previewStarted = false;
|
||||
}
|
||||
|
||||
|
||||
public void stopCaptureCallback() {
|
||||
if (camera != null) {
|
||||
lowLevelSetPreviewCallback(camera, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb);
|
||||
|
||||
|
||||
|
||||
public static class RecorderParams {
|
||||
public static enum MirrorType {NO, HORIZONTAL, CENTRAL, VERTICAL};
|
||||
|
||||
public float fps;
|
||||
public int height;
|
||||
public int width;
|
||||
|
||||
final long filterDataNativePtr;
|
||||
public int cameraId;
|
||||
public boolean isFrontCamera;
|
||||
public int rotation;
|
||||
public SurfaceView surfaceView;
|
||||
|
||||
public MirrorType mirror = MirrorType.NO;
|
||||
public int phoneOrientation;
|
||||
|
||||
public RecorderParams(long ptr) {
|
||||
filterDataNativePtr = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean isStarted() {
|
||||
return previewStarted;
|
||||
}
|
||||
|
||||
public List<VideoSize> getSupportedVideoSizes() {
|
||||
return supportedVideoSizes;
|
||||
}
|
||||
|
||||
|
||||
protected int getExpectedBufferLength() {
|
||||
if (currentPreviewSize == null) return -1;
|
||||
|
||||
return currentPreviewSize.width * currentPreviewSize.height * 3 /2;
|
||||
}
|
||||
|
||||
public void onAutoFocus(boolean success, Camera camera) {
|
||||
if (success) Log.i("Autofocus success");
|
||||
else Log.i("Autofocus failure");
|
||||
}
|
||||
|
||||
public int getStoredPhoneOrientation() {
|
||||
return params.phoneOrientation;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
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.video;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.linphone.core.Log;
|
||||
import org.linphone.core.video.AndroidCameraRecord.RecorderParams.MirrorType;
|
||||
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.Parameters;
|
||||
import android.hardware.Camera.PreviewCallback;
|
||||
import android.hardware.Camera.Size;
|
||||
|
||||
/**
|
||||
* Record from Android camera.
|
||||
* Android >= 5 (2.0) version.
|
||||
*
|
||||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
class AndroidCameraRecord5 extends AndroidCameraRecord implements PreviewCallback {
|
||||
|
||||
private long filterCtxPtr;
|
||||
private double timeElapsedBetweenFrames = 0;
|
||||
private long lastFrameTime = 0;
|
||||
private final double expectedTimeBetweenFrames;
|
||||
protected final int rotation;
|
||||
private MirrorType mirror;
|
||||
// private boolean isUsingFrontCamera;
|
||||
|
||||
public AndroidCameraRecord5(RecorderParams parameters) {
|
||||
super(parameters);
|
||||
expectedTimeBetweenFrames = 1d / Math.round(parameters.fps);
|
||||
filterCtxPtr = parameters.filterDataNativePtr;
|
||||
rotation = parameters.rotation;
|
||||
mirror = parameters.mirror;
|
||||
// isUsingFrontCamera = parameters.isFrontCamera;
|
||||
|
||||
storePreviewCallBack(this);
|
||||
}
|
||||
|
||||
|
||||
private native void putImage(long filterCtxPtr, byte[] buffer, int rotate, int mirror);
|
||||
|
||||
|
||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
||||
if (data == null) {
|
||||
Log.e("onPreviewFrame Called with null buffer");
|
||||
return;
|
||||
}
|
||||
if (filterCtxPtr == 0l) {
|
||||
Log.e("onPreviewFrame Called with no filterCtxPtr set");
|
||||
return;
|
||||
}
|
||||
|
||||
int expectedBuffLength = getExpectedBufferLength();
|
||||
if (expectedBuffLength != data.length) {
|
||||
Log.e("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, rotation, mirror.ordinal());
|
||||
return;
|
||||
}
|
||||
|
||||
double currentTimeElapsed = 0.8 * (curTime - lastFrameTime) / 1000 + 0.2 * timeElapsedBetweenFrames;
|
||||
if (currentTimeElapsed < expectedTimeBetweenFrames) {
|
||||
// Log.d("Clipping frame ", Math.round(1 / currentTimeElapsed), " > ", fps);
|
||||
return;
|
||||
}
|
||||
lastFrameTime = curTime;
|
||||
timeElapsedBetweenFrames = currentTimeElapsed;
|
||||
|
||||
// Log.d("onPreviewFrame: ", Integer.toString(data.length));
|
||||
putImage(filterCtxPtr, data, rotation, mirror.ordinal());
|
||||
}
|
||||
|
||||
protected String selectFocusMode(final List<String> supportedFocusModes) {/*
|
||||
if (isUsingFrontCamera && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
|
||||
return Camera.Parameters.FOCUS_MODE_FIXED;
|
||||
}
|
||||
if (!isUsingFrontCamera && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
|
||||
return Camera.Parameters.FOCUS_MODE_INFINITY;
|
||||
}*/
|
||||
|
||||
if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
|
||||
return Camera.Parameters.FOCUS_MODE_AUTO;
|
||||
}
|
||||
|
||||
return null; // Should not occur?
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSettingCameraParameters(Parameters parameters) {
|
||||
super.onSettingCameraParameters(parameters);
|
||||
List<String> supportedFocusModes = parameters.getSupportedFocusModes();
|
||||
String focusMode = selectFocusMode(supportedFocusModes);
|
||||
if (focusMode != null) {
|
||||
Log.w("Selected focus mode: ", focusMode);
|
||||
parameters.setFocusMode(focusMode);
|
||||
} else {
|
||||
Log.i("No suitable focus mode found in : ", Arrays.toString(supportedFocusModes.toArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Size> getSupportedPreviewSizes(Parameters parameters) {
|
||||
return parameters.getSupportedPreviewSizes();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb) {
|
||||
camera.setPreviewCallback(cb);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
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.video;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.linphone.core.Log;
|
||||
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.Parameters;
|
||||
import android.hardware.Camera.PreviewCallback;
|
||||
import android.hardware.Camera.Size;
|
||||
|
||||
/**
|
||||
*
|
||||
* Android >= 8 (2.2) version.
|
||||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
class AndroidCameraRecord8 extends AndroidCameraRecord5 {
|
||||
|
||||
|
||||
public AndroidCameraRecord8(RecorderParams parameters) {
|
||||
super(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void lowLevelSetPreviewCallback(Camera camera, PreviewCallback cb) {
|
||||
if (cb != null) {
|
||||
Log.d("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(rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String selectFocusMode(final List<String> supportedFocusModes) {
|
||||
if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_EDOF)) {
|
||||
return Camera.Parameters.FOCUS_MODE_EDOF;
|
||||
} else
|
||||
return super.selectFocusMode(supportedFocusModes);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
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.video;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.hardware.Camera;
|
||||
|
||||
/**
|
||||
*
|
||||
* Android >= 9 (2.3) version.
|
||||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
class AndroidCameraRecord9 extends AndroidCameraRecord8 {
|
||||
|
||||
|
||||
public AndroidCameraRecord9(RecorderParams parameters) {
|
||||
super(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Camera openCamera(int cameraId) {
|
||||
return Camera.open(cameraId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String selectFocusMode(final List<String> supportedFocusModes) {
|
||||
if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
|
||||
return Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
|
||||
} else
|
||||
return super.selectFocusMode(supportedFocusModes);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,362 +0,0 @@
|
|||
/*
|
||||
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.video;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.linphone.core.LinphoneCore;
|
||||
import org.linphone.core.Log;
|
||||
import org.linphone.core.Version;
|
||||
import org.linphone.core.VideoSize;
|
||||
import org.linphone.core.video.AndroidCameraRecord.RecorderParams;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.OrientationEventListener;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.SurfaceHolder.Callback;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Manage the video capture, only one for all cameras.
|
||||
*
|
||||
* @author Guillaume Beraudo
|
||||
*
|
||||
*/
|
||||
public class AndroidCameraRecordManager {
|
||||
private static AndroidCameraRecordManager instance;
|
||||
private OrientationEventListener orientationEventListener;
|
||||
private OnCapturingStateChangedListener capturingStateChangedListener;
|
||||
|
||||
/**
|
||||
* @return instance
|
||||
*/
|
||||
public static final synchronized AndroidCameraRecordManager getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new AndroidCameraRecordManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private AndroidCameraRecord.RecorderParams parameters;
|
||||
private final AndroidCameraConf cc;
|
||||
private SurfaceView surfaceView;
|
||||
private boolean muted;
|
||||
private int cameraId;
|
||||
|
||||
private AndroidCameraRecord recorder;
|
||||
private int mAlwaysChangingPhoneOrientation=0;
|
||||
|
||||
|
||||
// singleton
|
||||
private AndroidCameraRecordManager() {
|
||||
if (!Version.isVideoCapable()) { // imply sdk>=5
|
||||
throw new RuntimeException("AndroidCameraRecordManager: hardware is not video capable");
|
||||
}
|
||||
cc = Version.sdkAboveOrEqual(9) ? new AndroidCameraConf9() : new AndroidCameraConf5();
|
||||
Log.i("=== Detected " + cc.getFoundCameras()+ " ===");
|
||||
cameraId = cc.getFoundCameras().defaultC;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public boolean hasSeveralCameras() {
|
||||
return cc.getFoundCameras().hasSeveralCameras();
|
||||
}
|
||||
public boolean hasFrontCamera() {
|
||||
return cc.getFoundCameras().front != null;
|
||||
}
|
||||
|
||||
|
||||
public void setUseFrontCamera(boolean value) {
|
||||
if (!hasFrontCamera()) {
|
||||
Log.e("setUseFrontCamera(true) while no front camera detected on device: using rear");
|
||||
value = false;
|
||||
}
|
||||
if (cc.isFrontCamera(cameraId) == value) return; // already OK
|
||||
toggleUseFrontCamera();
|
||||
}
|
||||
|
||||
public boolean isUseFrontCamera() {return cc.isFrontCamera(cameraId);}
|
||||
public boolean toggleUseFrontCamera() {
|
||||
boolean previousUseFront = cc.isFrontCamera(cameraId);
|
||||
|
||||
cameraId = previousUseFront ? cc.getFoundCameras().rear : cc.getFoundCameras().front;
|
||||
|
||||
if (parameters != null) {
|
||||
parameters.cameraId = cameraId;
|
||||
parameters.isFrontCamera = !previousUseFront;
|
||||
if (isRecording()) {
|
||||
stopVideoRecording();
|
||||
tryToStartVideoRecording();
|
||||
}
|
||||
}
|
||||
|
||||
return !previousUseFront;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setParametersFromFilter(long filterDataPtr, int height, int width, float fps) {
|
||||
if (recorder != null) {
|
||||
Log.w("Recorder should not be running");
|
||||
stopVideoRecording();
|
||||
}
|
||||
RecorderParams p = new RecorderParams(filterDataPtr);
|
||||
p.fps = fps;
|
||||
p.width = width;
|
||||
p.height = height;
|
||||
p.cameraId = cameraId;
|
||||
p.isFrontCamera = isUseFrontCamera();
|
||||
parameters = p;
|
||||
|
||||
// Mirror the sent frames in order to make them readable
|
||||
// (otherwise it is mirrored and thus unreadable)
|
||||
if (p.isFrontCamera) {
|
||||
if (!isCameraMountedPortrait()) {
|
||||
// Code for Nexus S
|
||||
if (isFrameToBeShownPortrait())
|
||||
p.mirror = RecorderParams.MirrorType.CENTRAL;
|
||||
} else {
|
||||
// Code for Galaxy S like: camera mounted landscape when phone hold portrait
|
||||
p.mirror = RecorderParams.MirrorType.HORIZONTAL;
|
||||
}
|
||||
}
|
||||
|
||||
tryToStartVideoRecording();
|
||||
}
|
||||
|
||||
|
||||
public final void setSurfaceView(final SurfaceView sv) {
|
||||
SurfaceHolder holder = sv.getHolder();
|
||||
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||||
|
||||
holder.addCallback(new Callback() {
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
surfaceView = null;
|
||||
Log.d("Video capture surface destroyed");
|
||||
stopVideoRecording();
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
surfaceView = sv;
|
||||
Log.d("Video capture surface created");
|
||||
tryToStartVideoRecording();
|
||||
}
|
||||
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width,
|
||||
int height) {
|
||||
Log.d("Video capture surface changed");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param muteState
|
||||
* @return true if mute state changed
|
||||
*/
|
||||
public boolean setMuted(boolean muteState) {
|
||||
if (muteState == muted) return false;
|
||||
muted = muteState;
|
||||
if (muted) {
|
||||
stopVideoRecording();
|
||||
} else {
|
||||
tryToStartVideoRecording();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public boolean toggleMute() {
|
||||
setMuted(!muted);
|
||||
return muted;
|
||||
}
|
||||
public boolean isMuted() {
|
||||
return muted;
|
||||
}
|
||||
|
||||
public void tryResumingVideoRecording() {
|
||||
if (isRecording()) return;
|
||||
tryToStartVideoRecording();
|
||||
}
|
||||
|
||||
private synchronized void tryToStartVideoRecording() {
|
||||
if (orientationEventListener == null) {
|
||||
throw new RuntimeException("startOrientationSensor was not called");
|
||||
}
|
||||
|
||||
if (muted || surfaceView == null || parameters == null) return;
|
||||
|
||||
if (recorder != null) {
|
||||
Log.e("Recorder already present");
|
||||
stopVideoRecording();
|
||||
}
|
||||
|
||||
parameters.rotation = bufferRotationToCompensateCameraAndPhoneOrientations();
|
||||
|
||||
parameters.surfaceView = surfaceView;
|
||||
if (Version.sdkAboveOrEqual(9)) {
|
||||
recorder = new AndroidCameraRecord9(parameters);
|
||||
} else if (Version.sdkAboveOrEqual(8)) {
|
||||
recorder = new AndroidCameraRecord8(parameters);
|
||||
} else if (Version.sdkAboveOrEqual(5)) {
|
||||
recorder = new AndroidCameraRecord5(parameters);
|
||||
} else {
|
||||
throw new RuntimeException("SDK version unsupported " + Version.sdk());
|
||||
}
|
||||
|
||||
recorder.startPreview();
|
||||
|
||||
if (capturingStateChangedListener != null) {
|
||||
capturingStateChangedListener.captureStarted();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stopVideoRecording() {
|
||||
if (recorder != null) {
|
||||
recorder.stopPreview();
|
||||
recorder = null;
|
||||
if (capturingStateChangedListener != null) {
|
||||
capturingStateChangedListener.captureStopped();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<VideoSize> supportedVideoSizes() {
|
||||
Log.d("Using supportedVideoSizes of camera ",cameraId);
|
||||
return cc.getSupportedPreviewSizes(cameraId);
|
||||
}
|
||||
|
||||
|
||||
public boolean isRecording() {
|
||||
if (recorder != null) {
|
||||
return recorder.isStarted();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void invalidateParameters() {
|
||||
stopVideoRecording();
|
||||
parameters = null;
|
||||
}
|
||||
|
||||
/** Depends on currently selected camera, camera mounted portrait/landscape, current phone orientation */
|
||||
public boolean isFrameToBeShownPortrait() {
|
||||
final int rotation = bufferRotationToCompensateCameraAndPhoneOrientations();
|
||||
|
||||
boolean isPortrait;
|
||||
if (isCameraMountedPortrait()) {
|
||||
// Nexus S
|
||||
isPortrait = (rotation % 180) == 0;
|
||||
} else {
|
||||
isPortrait = (rotation % 180) == 90;
|
||||
}
|
||||
|
||||
Log.d("The frame to be shown and sent to remote is ", isPortrait? "portrait":"landscape"," orientation.");
|
||||
return isPortrait;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public boolean isCameraMountedPortrait() {
|
||||
return (cc.getCameraOrientation(cameraId) % 180) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private int bufferRotationToCompensateCameraAndPhoneOrientations() {
|
||||
if (Version.sdkStrictlyBelow(Version.API08_FROYO_22)) {
|
||||
// Don't perform any rotation
|
||||
// Phone screen should use fitting orientation
|
||||
return 0;
|
||||
}
|
||||
|
||||
final int phoneOrientation = mAlwaysChangingPhoneOrientation;
|
||||
final int cameraOrientation = cc.getCameraOrientation(cameraId);
|
||||
int frontCameraCorrection = 0;
|
||||
if (cc.isFrontCamera(cameraId)) {
|
||||
frontCameraCorrection=180; // hack that "just works" on Galaxy S and Nexus S.
|
||||
// See also magic with mirrors in setParametersFromFilter
|
||||
}
|
||||
final int rotation = (cameraOrientation + phoneOrientation + frontCameraCorrection) % 360;
|
||||
Log.d("Capture video buffer of cameraId=",cameraId,
|
||||
" will need a rotation of ",rotation,
|
||||
" degrees: camera_orientation=",cameraOrientation,
|
||||
" phone_orientation=", phoneOrientation);
|
||||
return rotation;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register a sensor to track phoneOrientation changes
|
||||
*/
|
||||
public void startOrientationSensor(Context c) {
|
||||
if (orientationEventListener == null) {
|
||||
orientationEventListener = new LocalOrientationEventListener(c);
|
||||
orientationEventListener.enable();
|
||||
}
|
||||
}
|
||||
|
||||
private class LocalOrientationEventListener extends OrientationEventListener {
|
||||
public LocalOrientationEventListener(Context context) {
|
||||
super(context);
|
||||
}
|
||||
@Override
|
||||
public void onOrientationChanged(final int o) {
|
||||
if (o == OrientationEventListener.ORIENTATION_UNKNOWN) return;
|
||||
|
||||
int degrees=270;
|
||||
if (o < 45 || o >315) degrees=0;
|
||||
else if (o<135) degrees=90;
|
||||
else if (o<225) degrees=180;
|
||||
|
||||
if (mAlwaysChangingPhoneOrientation == degrees) return;
|
||||
|
||||
Log.i("Phone orientation changed to ", degrees);
|
||||
mAlwaysChangingPhoneOrientation = degrees;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if linphone core configured to send a A buffer while phone orientation induces !A buffer (A=landscape or portrait)
|
||||
*/
|
||||
public boolean isOutputOrientationMismatch(LinphoneCore lc) {
|
||||
final boolean currentlyPortrait = lc.getPreferredVideoSize().isPortrait();
|
||||
final boolean shouldBePortrait = isFrameToBeShownPortrait();
|
||||
return currentlyPortrait ^ shouldBePortrait;
|
||||
}
|
||||
|
||||
public void setOnCapturingStateChanged(OnCapturingStateChangedListener listener) {
|
||||
this.capturingStateChangedListener=listener;
|
||||
}
|
||||
|
||||
public static interface OnCapturingStateChangedListener {
|
||||
void captureStarted();
|
||||
void captureStopped();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue