所以我有一个对话,我想按顺序显示前后摄像头预览,比如延迟2秒后。问题是,我总是可以设置1个摄像机视图到框架,如何在运行中自动更改它?
这是我想要动态更改的地方:
public class CameraExample extends AnimatedViewContainer {
private final static String TAG = "CameraExample";
private Camera mCamera;
private CameraPreview mPreview;
private Context mContext;
public CameraExample(Context context, int i) {
super(context, i);
mPreview = null;
mContext = context;
initCamera(mContext);
}
// A safe way to get an instance of the Camera object.
public static Camera getCameraInstance(int cameraId) {
Camera c = null;
try {
// attempt to get a Camera instance
c = Camera.open(cameraId);
} catch (Exception e) {
// Camera is not available (in use or does not exist)
Log.e(TAG, "CameraExample: " + "camera not available (in use or does not exist); " + e.getMessage());
}
return c; // returns null if camera is unavailable
}
private void initCamera(Context context) {
// Check if this device has a camera
if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
// no camera on this device
Log.e(TAG, "CameraExample: " + "this device has no camera");
} else {
// this device has a camera
int numCameras = Camera.getNumberOfCameras();
if (numCameras >= 0) {
for (int cameraId = 0; cameraId < numCameras; cameraId++) {
mCamera = getCameraInstance(cameraId);
if (mCamera != null) {
CameraInfo cameraInfo = new CameraInfo();
Camera.getCameraInfo(cameraId, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
try {
//Create our Preview view and set it as the content of this LinearLayout View
mPreview = new CameraPreview(context, mCamera, cameraId);
} catch (RuntimeException e) {
Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
}
}
if (createView() == false) {
break;
}
}
}
}
}
}
@Override
public void onCreateViewContent(LayoutInflater layoutInflater, ViewGroup parentGroup, View[] containerViews, int index) {
containerViews[index] = layoutInflater.inflate(R.layout.example_camera, parentGroup, false);
FrameLayout previewFrame = (FrameLayout) containerViews[index].findViewById(R.id.preview);
// Add preview for inflation
previewFrame.addView(mPreview);
}
@Override
public void cleanup() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
}
CameraPreview
类:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private int mCameraId;
public CameraPreview(Context context, Camera camera, int cameraId) {
super(context);
mContext = context;
mCamera = camera;
mCameraId = cameraId;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.e(TAG, "CameraExample: " + "Error setting camera preview: " + e.getMessage());
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
}
}
我在这里设定了我的观点:
@Override
public void onCreateViewContent(LayoutInflater layoutInflater, ViewGroup parentGroup, View[] containerViews, int index) {
containerViews[index] = layoutInflater.inflate(R.layout.example_camera, parentGroup, false);
FrameLayout previewFrame = (FrameLayout) containerViews[index].findViewById(R.id.preview);
previewFrame.addView(mPreview);
}
问题是,我不知道如何在设备通常具有2个不同摄像头的2个实例并在一定秒后自动更改它们,以便我的框架一个接一个地显示前后摄像头预览经过一定的秒数。任何解决方案都非常感谢!我想我必须用surfaceChanged()
方法处理它,但我真的不知道怎么做!
如所问,这是AnimatedViewContainer
类:
public abstract class AnimatedViewContainer extends Example {
Context mContext;
int mAnimationDuration;
int mAnimationDurationShort;
LayoutInflater mLayoutInflater;
ViewGroup mParentGroup;
View[] mContainerViews;
boolean hasBeenClicked = false;
int mCurrentIndex;
int mMaxNumItems;
int mIndexVisibleItem;
public AnimatedViewContainer(Context context, int maxNumItems) {
super(context);
mContext = context;
mMaxNumItems = maxNumItems;
mContainerViews = new View[mMaxNumItems];
// Retrieve and cache the system's default "medium" animation time
mAnimationDuration = getResources().getInteger(android.R.integer.config_mediumAnimTime);
// and "short"
mAnimationDurationShort = getResources().getInteger(android.R.integer.config_shortAnimTime);
mCurrentIndex = 0;
mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//TODO: shouldn't be null, should be any ViewGroup with the right LayoutParams
mParentGroup = null;
}
public abstract void onCreateViewContent(LayoutInflater layoutInflater, ViewGroup parentGroup, View[] containerViews, int index);
public boolean createView() {
if (mCurrentIndex >= mMaxNumItems) {
return false; // indicates to terminate the loop
}
// handle/execute the concrete definition of the view content defined by the child class
onCreateViewContent(mLayoutInflater, mParentGroup, mContainerViews, mCurrentIndex);
// only the first container view should be visible
if (mCurrentIndex == 0) {
mContainerViews[mCurrentIndex].setVisibility(View.VISIBLE);
mIndexVisibleItem = mCurrentIndex;
} else {
mContainerViews[mCurrentIndex].setVisibility(View.GONE);
}
// if you click on the container view, show next container view with a crossfade animation
mContainerViews[mCurrentIndex].setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
crossfade(true);
hasBeenClicked = true;
}
});
// add the container view to the FrameLayout
addView(mContainerViews[mCurrentIndex]);
mCurrentIndex++;
return true;
}
public void crossfade(boolean manuallyClicked) {
//only rotate when example is actually shown and at least one content item was created. This may also prevent NPEs due to incompletely loaded views.
if(!this.isShown() || mCurrentIndex == 0)
return;
//when example was previously clicked, don't do anything
if(!manuallyClicked && hasBeenClicked){
hasBeenClicked = false;
return;
}
int numTotalItems = mCurrentIndex;
final int indexVisibleItem = mIndexVisibleItem;
int nextIndex = indexVisibleItem + 1;
if (nextIndex >= numTotalItems) {
nextIndex = 0;
}
final boolean hasOnlyOneItem;
if (numTotalItems == 1) {
hasOnlyOneItem = true;
} else {
hasOnlyOneItem = false;
}
if (hasOnlyOneItem) { //there is only one item in the mContainerViews
mContainerViews[indexVisibleItem].animate().alpha(0.5f).setDuration(mAnimationDurationShort).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mContainerViews[indexVisibleItem].animate().alpha(1f).setDuration(mAnimationDurationShort).setListener(null);
}
});
} else {
// Set the next view to 0% opacity but visible, so that it is visible (but fully transparent) during the animation.
mContainerViews[nextIndex].setAlpha(0f);
mContainerViews[nextIndex].setVisibility(View.VISIBLE);
// Animate the next view to 100% opacity, and clear any animation
// listener set on the view.
mContainerViews[nextIndex].animate().alpha(1f).setDuration(mAnimationDuration).setListener(null);
// Animate the current view to 0% opacity. After the animation ends,
// set its visibility to GONE as an optimization step (it won't participate in layout passes, etc.)
mContainerViews[indexVisibleItem].animate().alpha(0f).setDuration(mAnimationDuration).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mContainerViews[indexVisibleItem].setVisibility(View.GONE);
}
});
}
mIndexVisibleItem = nextIndex;
}
@Override
public void cleanup() {
}
}
答案 0 :(得分:2)
我可以在几秒钟内找到改变相机的解决方案(但请记住,因为Alex Cohn说你不能在2秒内更换相机,因为通常需要2秒以上才能开始预览,这取决于在设备上)通过稍微改变您的代码。请使用以下代码并检查。
注意:我没有实现任何方向更改和拍照功能,我希望您已经开发了这些功能,实际上您只需要在几秒钟内自动更换相机。
我使用对话框片段在对话框中显示预览。这是CameraExample的代码
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.v4.app.DialogFragment;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
/**
* Created by Admin on 6/26/2017.
*/
public class CameraExample extends DialogFragment {
private final static String TAG = "CameraExample";
private Camera mCamera;
private CameraPreview mPreview;
private Context mContext;
private View view;
private int mCamId = 0;
public CameraExample() {
mPreview = null;
mContext = getContext();
}
// A safe way to get an instance of the Camera object.
public static Camera getCameraInstance(int cameraId) {
Camera c = null;
try {
// attempt to get a Camera instance
c = Camera.open(cameraId);
} catch (Exception e) {
// Camera is not available (in use or does not exist)
Log.e(TAG, "CameraExample: " + "camera not available (in use or does not exist); " + e.getMessage());
}
return c; // returns null if camera is unavailable
}
private void initCamera(Context context, int cameraId) {
// Check if this device has a camera
if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
// no camera on this device
Log.e(TAG, "CameraExample: " + "this device has no camera");
} else {
// this device has a camera
int numCameras = Camera.getNumberOfCameras();
if (numCameras >= 0) {
mCamera = getCameraInstance(cameraId);
if (mCamera != null) {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, cameraInfo);
try {
//Create our Preview view and set it as the content of this LinearLayout View
mPreview = new CameraPreview(context, mCamera, cameraId);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mPreview.setLayoutParams(layoutParams);
} catch (RuntimeException e) {
Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
}
}
}
}
}
private CountDownTimer countDownTimer;
private void switchCam() {
//10 seconds
countDownTimer = new CountDownTimer(10000, 1000) {
@Override
public void onTick(long l) {
System.out.println(l + " left");
}
@Override
public void onFinish() {
cleanup();
startCam();
}
}.start();
}
private void startCam() {
initCamera(getContext(), mCamId);
FrameLayout previewFrame = (FrameLayout) view.findViewById(R.id.preview);
previewFrame.removeAllViews();
// Add preview for inflation
previewFrame.addView(mPreview);
mCamId = mCamId == 0 ? 1 : 0;
switchCam();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
getDialog().getWindow().setGravity(Gravity.CENTER);
// getDialog().getWindow().setBackgroundDrawableResource(android.R.color.transparent);
view = inflater.inflate(R.layout.camera_fragment, container, false);
startCam();
return view;
}
@Override
public void onPause() {
super.onPause();
cleanup();
if (countDownTimer != null)
countDownTimer.cancel();
}
@Override
public void onStart() {
super.onStart();
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
public void cleanup() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
}
而且我还必须更改预览课程。请参阅下面的代码。
import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
/**
* Created by Admin on 6/26/2017.
*/
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private int mCameraId;
public CameraPreview(Context context, Camera camera, int cameraId) {
super(context);
mContext = context;
mCamera = camera;
mCameraId = cameraId;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.e(TAG, "CameraExample: " + "Error setting camera preview: " + e.getMessage());
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
}
}
答案 1 :(得分:1)
您的课程中存在双重初始化错误。我可以让它运行并看到相机从0到1切换,并在10秒后返回以下修复:
我从 CameraExample 构造函数中删除了对 initCamera()的调用。相反,我把它调用 CreateView()。或者,您可以从创建新CameraExample(上下文,i)的地方调用 CreateView(),这是一种公共方法。
请注意,这指的是dropbox中的代码,而不是问题中发布的代码。
答案 2 :(得分:0)
您必须停止相机,切换面板然后再次启动:
使用计时器并每2秒定期调用switchFacing()
。
但要注意:
此类在API级别21中已弃用。 我们建议使用新的android.hardware.camera2 API 应用
edit2:这是可以使用的完整课程。
//This class uses Camera1 API to be backwards compatible.
private static String TAG = "CameraManager";
private Context mContext = null;
private SurfaceView mPreview = null;
private SurfaceHolder mHolder = null;
private Camera mCamera = null;
private int mFrontFaceID = -1;
private int mBackFaceID = -1;
private int mActualFacingID = -1;
public CameraManager(Context context, SurfaceView preview) {
mContext = context;
mPreview = preview;
mHolder = mPreview.getHolder();
mHolder.addCallback(this);
}
//called in onCreate
public void init() {
Camera.CameraInfo info = new Camera.CameraInfo();
for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
mFrontFaceID = i;
}
if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
mBackFaceID = i;
}
}
if (mActualFacingID == -1) {
if (mFrontFaceID != -1) {
mActualFacingID = mFrontFaceID;
} else {
mActualFacingID = mBackFaceID;
}
}
//At least one one camera will be available because of manifest declaration
}
//called first on surface created
public void start() {
Log.i(TAG, "startCamera()");
if (mCamera == null) {
mCamera = getCameraInstance(mActualFacingID);
}
if (mCamera == null) {
Log.i(TAG, "can't get camera instance");
return;
}
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
setCameraDisplayOrientation();
setBestSupportedSizes();
mCamera.startPreview();
}
public void stop() {
Log.i(TAG, "stopCamera()");
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
public void switchFacing() {
if (mFrontFaceID == -1 || mBackFaceID == -1) {
return;
}
stop();
if (mActualFacingID == mFrontFaceID) {
mActualFacingID = mBackFaceID;
} else {
mActualFacingID = mFrontFaceID;
}
start();
}
public Camera getCameraInstance(int cameraID) {
Camera c = null;
if (cameraID != -1) {
try {
c = Camera.open(cameraID);
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "error opening camera: " + cameraID);
}
}
return c;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i(TAG, "surfaceCreated()");
start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i(TAG, "surfaceChanged()");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i(TAG, "surfaceDestroyed()");
stop();
}
private void setBestSupportedSizes() {
if (mCamera == null) {
return;
}
Camera.Parameters parameters = mCamera.getParameters();
List<Point> pictureSizes=getSortedSizes(parameters.getSupportedPictureSizes());
List<Point> previewSizes=getSortedSizes(parameters.getSupportedPreviewSizes());
Point previewResult=null;
for (Point size:previewSizes){
float ratio = (float) size.y / size.x;
if(Math.abs(ratio-4/(float)3)<0.05){ //Aspect ratio of 4/3 because otherwise the image scales to much.
previewResult=size;
break;
}
}
Log.i(TAG,"preview: "+previewResult.x+"x"+previewResult.y);
Point pictureResult=null;
if(previewResult!=null){
float previewRatio=(float)previewResult.y/previewResult.x;
for (Point size:pictureSizes){
float ratio = (float) size.y / size.x;
if(Math.abs(previewRatio-ratio)<0.05){
pictureResult=size;
break;
}
}
}
Log.i(TAG,"preview: "+pictureResult.x+"x"+pictureResult.y);
if(previewResult!=null && pictureResult!=null){
Log.i(TAG,"best preview: "+previewResult.x+"x"+previewResult.y);
Log.i(TAG, "best picture: " + pictureResult.x + "x" + pictureResult.y);
parameters.setPreviewSize(previewResult.y, previewResult.x);
parameters.setPictureSize(pictureResult.y, pictureResult.x);
mCamera.setParameters(parameters);
mPreview.setBackgroundColor(Color.TRANSPARENT); //in the case of errors needed
}else{
mCamera.stopPreview();
mPreview.setBackgroundColor(Color.BLACK);
}
}
private List<Point> getSortedSizes(List<Camera.Size> sizes) {
ArrayList<Point> list = new ArrayList<>();
for (Camera.Size size : sizes) {
int height;
int width;
if (size.width > size.height) {
height = size.width;
width = size.height;
} else {
height = size.height;
width = size.width;
}
list.add(new Point(width, height));
}
Collections.sort(list, new Comparator<Point>() {
@Override
public int compare(Point lhs, Point rhs) {
long lhsCount = lhs.x * (long) lhs.y;
long rhsCount = rhs.x * (long) rhs.y;
if (lhsCount < rhsCount) {
return 1;
}
if (lhsCount > rhsCount) {
return -1;
}
return 0;
}
});
return list;
}
//TAKE PICTURE
public void takePhoto() {
if (mCamera != null) {
mCamera.takePicture(null, null, this);
}
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
//do something with your picture
}
//ROTATION
private void setCameraDisplayOrientation() {
if (mCamera != null) {
mCamera.setDisplayOrientation(getRotation());
}
}
public int getRotation() {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(mActualFacingID, info);
int rotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
在某些课堂电话中:
SurfaceView preview = (SurfaceView) findViewById(R.id.surfaceView);
CameraManager mgr = new CameraManager(MainActivity.this, MainActivity.this, preview);
mgr.init();
...
mgr.takePhoto(); //surface must already be created
mgr.switchFacing();
mgr.takePhoto();
此代码应支持几乎所有设备。最支持的宽高比是4:3,代码负责这一点。
edit3:surface view must be in the xml of course
<SurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/surfaceView" />
答案 3 :(得分:0)
无法快速切换相机。停止摄像机,关闭摄像机,打开另一台摄像机以及开始预览所需的时间取决于设备,但在许多情况下(有时在强大的现代设备上),您将超过2秒作为目标。
另一方面,某些Android设备支持同时操作两台摄像头,请参阅 Is it possible to use front and back Camera at same time in Android 和 Android, Open Front and Back Cameras Simultaneously 。因此,在某些基于Snapdragon 801的设备上,您可以保持两个摄像头准备就绪。并且每秒最多切换30次视频流。
答案 4 :(得分:0)
我认为你应该使用这个
mCamera = Camera.open(cameraId);
0表示CAMERA_FACING_BACK
1表示CAMERA_FACING_FRONT
更多参考流程: -
https://developer.android.com/reference/android/hardware/Camera.html#open(int)
https://developer.android.com/reference/android/hardware/Camera.CameraInfo.html#CAMERA_FACING_BACK
答案 5 :(得分:0)
我们可以使用线程来保持一台摄像机处于活动状态并让它停留一段时间。交换相机并在无限时间内保修。
var bookingSchema = new Schema({
booking_id_customer: {
type: Number
}
}
bookingSchema.reIndex();
答案 6 :(得分:-1)
我想这就是你要找的东西:
ImageButton useOtherCamera = (ImageButton) findViewById(R.id.useOtherCamera);
//if phone has only one camera, hide "switch camera" button
if(Camera.getNumberOfCameras() == 1){
useOtherCamera.setVisibility(View.INVISIBLE);
}
else {
useOtherCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (inPreview) {
camera.stopPreview();
}
//NB: if you don't release the current camera before switching, you app will crash
camera.release();
//swap the id of the camera to be used
if(currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK){
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
}
else {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
camera = Camera.open(currentCameraId);
//Code snippet for this method from somewhere on android developers, i forget where
setCameraDisplayOrientation(CameraActivity.this, currentCameraId, camera);
try {
//this step is critical or preview on new camera will no know where to render to
camera.setPreviewDisplay(previewHolder);
} catch (IOException e) {
e.printStackTrace();
}
camera.startPreview();
}
这是一个示例代码,我可以动态地在前后摄像头之间切换。希望它会有所帮助。