c732d49e |
/* |
74ca6d11 |
* Copyright (C) 2020, University of the Basque Country (UPV/EHU) |
c732d49e |
* Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
*
* The original file was part of Open Source IMSDROID
* Copyright (C) 2010-2011, Mamadou Diop.
* Copyright (C) 2011, Doubango Telecom.
*
*
* Contact: Mamadou Diop <diopmamadou(at)doubango(dot)org>
*
* This file is part of Open Source Doubango Framework.
*
* This 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 3
* of the License, or (at your option) any later version.
*
* This 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.doubango.ngn.media;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.util.Log;
import android.view.SurfaceHolder;
|
175b478c |
import org.doubango.ngn.BuildConfig; |
c732d49e |
import org.doubango.ngn.NgnApplication;
import org.doubango.ngn.NgnEngine;
import org.doubango.ngn.utils.NgnConfigurationEntry;
import org.doubango.utils.Utils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class NgnCameraProducer {
private static final String TAG = Utils.getTAG(NgnCameraProducer.class.getCanonicalName());
private static Camera instance;
private static boolean useFrontFacingCamera;
// Default values
private static int fps = 15;
private static int width = 176;
private static int height = 144;
private static SurfaceHolder holder = null;
private static PreviewCallback callback = null;
private static final int MIN_SDKVERSION_addCallbackBuffer = 7;
private static final int MIN_SDKVERSION_setPreviewCallbackWithBuffer = 7;
private static final int MIN_SDKVERSION_setDisplayOrientation = 8;
//private static final int MIN_SDKVERSION_getSupportedPreviewSizes = 5;
private static Method addCallbackBufferMethod = null;
private static Method setDisplayOrientationMethod = null;
private static Method setPreviewCallbackWithBufferMethod = null;
static{
NgnCameraProducer.useFrontFacingCamera = NgnEngine
.getInstance().getConfigurationService().getBoolean(NgnConfigurationEntry.GENERAL_USE_FFC,
NgnConfigurationEntry.DEFAULT_GENERAL_USE_FFC);
}
static{
if(NgnApplication.getSDKVersion() >= NgnCameraProducer.MIN_SDKVERSION_addCallbackBuffer){
// According to http://developer.android.com/reference/android/hardware/Camera.html both addCallbackBuffer and setPreviewCallbackWithBuffer
// are only available starting API level 8. But it's not true as these functions exist in API level 7 but are hidden.
try {
NgnCameraProducer.addCallbackBufferMethod = Camera.class.getMethod("addCallbackBuffer", byte[].class);
} catch (Exception e) {
Log.e(NgnCameraProducer.TAG, e.toString());
}
}
if(NgnApplication.getSDKVersion() >= NgnCameraProducer.MIN_SDKVERSION_setPreviewCallbackWithBuffer){
try {
NgnCameraProducer.setPreviewCallbackWithBufferMethod = Camera.class.getMethod(
"setPreviewCallbackWithBuffer", PreviewCallback.class);
} catch (Exception e) {
Log.e(NgnCameraProducer.TAG, e.toString());
}
}
if(NgnApplication.getSDKVersion() >= NgnCameraProducer.MIN_SDKVERSION_setDisplayOrientation){
try {
NgnCameraProducer.setDisplayOrientationMethod = Camera.class.getMethod("setDisplayOrientation", int.class);
} catch (Exception e) {
Log.e(NgnCameraProducer.TAG, e.toString());
}
}
}
public static Camera getCamera(){
return NgnCameraProducer.instance;
}
public static Camera openCamera(int fps, int width, int height, SurfaceHolder holder, PreviewCallback callback){
if(NgnCameraProducer.instance == null){
try{
if(NgnCameraProducer.useFrontFacingCamera){
NgnCameraProducer.instance = NgnCameraProducer.openFrontFacingCamera();
}
else{
NgnCameraProducer.instance = Camera.open();
}
NgnCameraProducer.fps = fps;
NgnCameraProducer.width = width;
NgnCameraProducer.height = height;
NgnCameraProducer.holder = holder;
NgnCameraProducer.callback = callback;
Camera.Parameters parameters = NgnCameraProducer.instance.getParameters();
/*
* http://developer.android.com/reference/android/graphics/ImageFormat.html#NV21
* YCrCb format used for images, which uses the NV21 encoding format.
* This is the default format for camera preview images, when not otherwise set with setPreviewFormat(int).
*/
parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP);
parameters.setPreviewFrameRate(NgnCameraProducer.fps);
NgnCameraProducer.instance.setParameters(parameters);
try{
parameters.setPictureSize(NgnCameraProducer.width , NgnCameraProducer.height);
NgnCameraProducer.instance.setParameters(parameters);
}
catch(Exception e){
// FFMpeg converter will resize the video stream
Log.d(NgnCameraProducer.TAG, e.toString());
}
NgnCameraProducer.instance.setPreviewDisplay(NgnCameraProducer.holder);
NgnCameraProducer.initializeCallbacks(NgnCameraProducer.callback);
}
catch(Exception e){
NgnCameraProducer.releaseCamera();
Log.e(NgnCameraProducer.TAG, e.toString());
}
}
return NgnCameraProducer.instance;
}
public static void releaseCamera(Camera camera){
if(camera != null){
camera.stopPreview();
NgnCameraProducer.deInitializeCallbacks(camera);
camera.release();
if(camera == NgnCameraProducer.instance){
NgnCameraProducer.instance = null;
}
}
}
public static void releaseCamera(){
if(NgnCameraProducer.instance != null){
NgnCameraProducer.instance.stopPreview();
NgnCameraProducer.deInitializeCallbacks();
NgnCameraProducer.instance.release();
NgnCameraProducer.instance = null;
}
}
public static void setDisplayOrientation(int degrees){
if(NgnCameraProducer.instance != null && NgnCameraProducer.setDisplayOrientationMethod != null){
try {
NgnCameraProducer.setDisplayOrientationMethod.invoke(NgnCameraProducer.instance, degrees);
} catch (Exception e) {
Log.e(NgnCameraProducer.TAG, e.toString());
}
}
}
public static void setDisplayOrientation(Camera camera, int degrees){
if(camera != null && NgnCameraProducer.setDisplayOrientationMethod != null){
try {
NgnCameraProducer.setDisplayOrientationMethod.invoke(camera, degrees);
} catch (Exception e) {
Log.e(NgnCameraProducer.TAG, e.toString());
}
}
}
public static void addCallbackBuffer(Camera camera, byte[] buffer) {
try {
NgnCameraProducer.addCallbackBufferMethod.invoke(camera, buffer);
} catch (Exception e) {
Log.e(NgnCameraProducer.TAG, e.toString());
}
}
public static void addCallbackBuffer(byte[] buffer) {
try {
NgnCameraProducer.addCallbackBufferMethod.invoke(NgnCameraProducer.instance, buffer);
} catch (Exception e) {
Log.e(NgnCameraProducer.TAG, e.toString());
}
}
public static boolean isAddCallbackBufferSupported(){
return NgnCameraProducer.addCallbackBufferMethod != null;
}
public static boolean isFrontFacingCameraEnabled(){
return NgnCameraProducer.useFrontFacingCamera;
}
public static void useRearCamera(){
NgnCameraProducer.useFrontFacingCamera = false;
}
public static void useFrontFacingCamera(){
NgnCameraProducer.useFrontFacingCamera = true;
}
public static Camera toggleCamera(){
if(NgnCameraProducer.instance != null){
NgnCameraProducer.useFrontFacingCamera = !NgnCameraProducer.useFrontFacingCamera;
NgnCameraProducer.releaseCamera();
NgnCameraProducer.openCamera(NgnCameraProducer.fps,
NgnCameraProducer.width,
NgnCameraProducer.height,
NgnCameraProducer.holder,
NgnCameraProducer.callback);
}
return NgnCameraProducer.instance;
}
private static void initializeCallbacks(PreviewCallback callback){
initializeCallbacks(callback, NgnCameraProducer.instance);
}
private static void initializeCallbacks(PreviewCallback callback, Camera camera){ |
175b478c |
if(BuildConfig.DEBUG)Log.d(TAG,"initializeCallbacks"); |
c732d49e |
if(camera != null){
if(NgnCameraProducer.setPreviewCallbackWithBufferMethod != null){ |
175b478c |
if(BuildConfig.DEBUG)Log.w(TAG,"initializeCallbacks NgnCameraProducer.setPreviewCallbackWithBufferMethod!=null"); |
c732d49e |
try {
NgnCameraProducer.setPreviewCallbackWithBufferMethod.invoke(camera, callback);
} catch (Exception e) { |
175b478c |
if(BuildConfig.DEBUG)Log.e(NgnCameraProducer.TAG,"Error in initializeCallbacks"+ e.toString()); |
c732d49e |
}
}
else{ |
175b478c |
if(BuildConfig.DEBUG)Log.d(TAG,"initializeCallbacks NgnCameraProducer.setPreviewCallbackWithBufferMethod==null"); |
c732d49e |
camera.setPreviewCallback(callback);
} |
175b478c |
}else{
if(BuildConfig.DEBUG)Log.w(TAG,"Camera is null in initializeCallbacks"); |
c732d49e |
}
}
private static void deInitializeCallbacks(){
deInitializeCallbacks(NgnCameraProducer.instance);
}
private static void deInitializeCallbacks(Camera camera){
if(camera!= null){
if(NgnCameraProducer.setPreviewCallbackWithBufferMethod != null){
try {
NgnCameraProducer.setPreviewCallbackWithBufferMethod.invoke(camera, new Object[]{ null });
} catch (Exception e) {
Log.e(NgnCameraProducer.TAG, e.toString());
}
}
else{
camera.setPreviewCallback(null);
}
}
}
public static int getNumberOfCameras() {
// 1. Android 2.3 or later
if (NgnApplication.getSDKVersion() >= 9) {
try {
Method getNumberOfCamerasMethod = Camera.class.getDeclaredMethod("getNumberOfCameras");
if (getNumberOfCamerasMethod != null) {
return (Integer) getNumberOfCamerasMethod.invoke(null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return 1;
}
private static Camera openFrontFacingCamera() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{
Camera camera = null;
// 1. Android 2.3 or later
if(NgnApplication.getSDKVersion() >= 9){
try {
Method getNumberOfCamerasMethod = Camera.class.getDeclaredMethod("getNumberOfCameras");
if(getNumberOfCamerasMethod != null){
Integer numberOfCameras = (Integer)getNumberOfCamerasMethod.invoke(null);
if(numberOfCameras > 1){
Method openMethod = Camera.class.getDeclaredMethod("open", int.class);
if((camera = (Camera)openMethod.invoke(null, (numberOfCameras - 1))) != null){
return camera;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
//2. From mapper
if((camera = FrontFacingCameraMapper.getPreferredCamera()) != null){
return camera;
}
//3. Use switcher
if(FrontFacingCameraSwitcher.getSwitcher() != null){
camera = Camera.open();
FrontFacingCameraSwitcher.getSwitcher().invoke(camera, (int)1);
return camera;
}
//4. Use parameters
camera = Camera.open();
Camera.Parameters parameters = camera.getParameters();
parameters.set("camera-id", 2);
camera.setParameters(parameters);
return camera;
}
/***
* FrontFacingCameraSwitcher
* @author Mamadou Diop
*
*/
static class FrontFacingCameraSwitcher
{
private static Method DualCameraSwitchMethod;
static{
try{
FrontFacingCameraSwitcher.DualCameraSwitchMethod = Class.forName("android.hardware.Camera").getMethod("DualCameraSwitch",int.class);
}
catch(Exception e){
Log.d(NgnCameraProducer.TAG, e.toString());
}
}
static Method getSwitcher(){
return FrontFacingCameraSwitcher.DualCameraSwitchMethod;
}
}
static class FrontFacingCameraMapper
{
private static int preferredIndex = -1;
static FrontFacingCameraMapper Map[] = {
new FrontFacingCameraMapper("android.hardware.HtcFrontFacingCamera", "getCamera"),
// Sprint: HTC EVO 4G and Samsung Epic 4G
// DO not forget to change the manifest if you are using OS 1.6 and later
new FrontFacingCameraMapper("com.sprint.hardware.twinCamDevice.FrontFacingCamera", "getFrontFacingCamera"),
// Huawei U8230
new FrontFacingCameraMapper("android.hardware.CameraSlave", "open"),
// Default: Used for test reflection
// new FrontFacingCameraMapper("android.hardware.Camera", "open"),
};
static{
int index = 0;
for(FrontFacingCameraMapper ffc: FrontFacingCameraMapper.Map){
try{
Class.forName(ffc.className).getDeclaredMethod(ffc.methodName);
FrontFacingCameraMapper.preferredIndex = index;
break;
}
catch(Exception e){
Log.d(NgnCameraProducer.TAG, e.toString());
}
++index;
}
}
private final String className;
private final String methodName;
FrontFacingCameraMapper(String className, String methodName){
this.className = className;
this.methodName = methodName;
}
static Camera getPreferredCamera(){
if(FrontFacingCameraMapper.preferredIndex == -1){
return null;
}
try{
Method method = Class.forName(FrontFacingCameraMapper.Map[FrontFacingCameraMapper.preferredIndex].className)
.getDeclaredMethod(FrontFacingCameraMapper.Map[FrontFacingCameraMapper.preferredIndex].methodName);
return (Camera)method.invoke(null);
}
catch(Exception e){
Log.e(NgnCameraProducer.TAG, e.toString());
}
return null;
}
}
} |