我试图在不使用Camera API(使用意图)的情况下在Android中构建自定义相机。我有一个MainActivity.java,我需要调用CameraPreview
类来查看相机预览,但我不知道如何调用该类。
我试过了
public CameraPreview cameraPreview;
以后
mPreview = new CameraPreview(this, mCamera);
if(hasCamera) {
// Create an instance of Camera
mCamera = getCameraInstance();
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
它不起作用。请指教! 我的代码编译但我在屏幕上看不到预览。
public class MainActivity extends AppCompatActivity implements SensorEventListener{
public CameraPreview cameraPreview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
hasCamera = checkCameraHardware(this);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
// Success! There's a accelerometer.
mAccel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Toast.makeText(MainActivity.this, "Accelerometer Found!", Toast.LENGTH_SHORT).show();
}
else {
// Failure! No accelerometer.
Toast.makeText(MainActivity.this, "Accelerometer Not Found!", Toast.LENGTH_SHORT).show();
}
if(hasCamera) {
// Create an instance of Camera
mCamera = getCameraInstance();
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
/* Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
}
); */
}
//Accelerometer Handling
mAccel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mAccel, SensorManager.SENSOR_DELAY_NORMAL);
if(safeToTakePicture) {
// cameraPreview.surfaceCreated(mHolder);
mCamera.takePicture(null, null, mPicture);
safeToTakePicture = false;
}
}
@Override
public void onSensorChanged(SensorEvent event) {
long currentTime = System.currentTimeMillis();
// update every 1 sec
if((currentTime - prevTime) > 10000){
mDiff = currentTime - prevTime;
mX = event.values[0];
mY = event.values[1];
mZ = event.values[2];
float speed = Math.abs(mX + mY + mZ - mPrev_x - mPrev_y - mPrev_z) / mDiff;
if (speed > SHAKE_THRESHOLD) {
Log.d("sensor", "Shake detected with speed: " + speed);
mCamera.takePicture(null, null, mPicture);
safeToTakePicture = false;
Toast.makeText(this, "Shake detected with speed: " + speed, Toast.LENGTH_SHORT).show();
}
}
mPrev_x = mX;
mPrev_y = mY;
mPrev_z = mZ;
prevTime = currentTime;
// mCamera.takePicture(null, null, mPicture);
// Toast.makeText(MainActivity.this, "SensorChanged Event! x:" + event.values[0], Toast.LENGTH_SHORT).show();
}
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
/** A safe way to get an instance of the Camera object. */
//Deprecated Camera instance, but ok
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
// receive data in a JPEG format,
// you must implement an Camera.PictureCallback interface to receive the image data and write it to a file
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d(TAG, "Error creating media file, check storage permissions: " /* +
e.getMessage()*/);
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
};
private static File getOutputMediaFile(int type){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MyCameraApp");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.
// Create the storage directory if it does not exist
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else if(type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"VID_"+ timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
public final void onAccuracyChanged(Sensor sensor, int accuracy){
//mCamera.takePicture(null, null, mPicture);
//Toast.makeText(this, "Taking a picture now", Toast.LENGTH_SHORT).show();
}
@Override
protected void onPause() {
super.onPause();
letGo();
}
@Override
protected void onDestroy() {
super.onDestroy();
letGo();
}
private void letGo(){
if(mCamera != null){
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
// Call stopPreview() to stop updating the preview surface.
mCamera.stopPreview();
}
}
/**
* When this function returns, mCamera will be null.
*/
private void stopPreviewAndFreeCamera() {
if (mCamera != null) {
// Call stopPreview() to stop updating the preview surface.
mCamera.stopPreview();
// Important: Call release() to release the camera for use by other
// applications. Applications should release the camera immediately
// during onPause() and re-open() it during onResume()).
mCamera.release();
mCamera = null;
}
}
}
CameraPreview
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private static final String TAG = MainActivity.class.getSimpleName();
SurfaceView mSurfaceView;
private Camera mCamera;
private boolean safeToTakePicture = false;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mSurfaceView = new SurfaceView(context);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
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.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// 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
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
safeToTakePicture = true;
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
答案 0 :(得分:0)
好的伙计们,分享我的稳定版本, 这是改进的自定义相机预览类(注意!预览大小设置为800x600,图像大小约为5mpx以获得更好的性能,这可以删除,查看代码):
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private Context mContext;
private Camera.PreviewCallback previewCallback;
private Camera.AutoFocusCallback autoFocusCallback;
private static final String TAG = "CameraPreview";
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
public CameraPreview(Context context, Camera camera,
Camera.PreviewCallback previewCb,
Camera.AutoFocusCallback autoFocusCb) {
super(context);
mContext = context;
mCamera = camera;
previewCallback = previewCb;
autoFocusCallback = autoFocusCb;
// supported preview sizes
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
// for(Camera.Size str: mSupportedPreviewSizes)
// Log.e(TAG, str.width + "/" + str.height);
// for(Camera.Size str: mCamera.getParameters().getSupportedPictureSizes())
// Log.e(TAG, str.width + "/" + str.height);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
// // deprecated setting, but required on Android versions prior to 3.0
// mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
/*
* Set camera to continuous focus if supported, otherwise use
* software auto-focus. Only works for API level >=9.
*/
/*
Camera.Parameters parameters = camera.getParameters();
for (String f : parameters.getSupportedFocusModes()) {
if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {
mCamera.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
autoFocusCallback = null;
break;
}
}
*/
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
Log.d("DBG", "Error setting camera preview: " + e.getMessage());
}
}
@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
}
try {
// Hard code camera surface rotation 90 degs to match Activity view in portrait
// Camera.Parameters parameters = mCamera.getParameters();
// parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
// mCamera.setParameters(parameters);
Camera.Parameters params = mCamera.getParameters();
for(Camera.Size str: params.getSupportedPictureSizes()) {
if (str.width >= 2400 && str.width <= 2600 && str.height >= 1800 && str.height <= 2000) {
params.setPictureSize(str.width, str.height);
Log.e("Picture size: ", str.width + "/" + str.height);
}
}
for(Camera.Size str: params.getSupportedPreviewSizes())
if(str.width == 800 && str.height == 600){
params.setPreviewSize(str.width, str.height);
Log.e("Preview size: ", str.width + "/" + str.height);
}
mCamera.setParameters(params);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.setPreviewCallback(previewCallback);
mCamera.startPreview();
mCamera.autoFocus(autoFocusCallback);
if(!(SettingsService.settings.autofocusOn))
mCamera.cancelAutoFocus();
} catch (Exception e) {
Log.d("DBG", "Error starting camera preview: " + e.getMessage());
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
this.getHolder().removeCallback(this);
try {
mCamera.stopPreview();
mCamera.release();
}catch(Exception e){
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
float ratio;
if(mPreviewSize.height >= mPreviewSize.width)
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
else
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
// One of these methods should be used, second method squishes preview slightly
setMeasuredDimension(width, (int) (width * ratio));
// setMeasuredDimension((int) (width * ratio), height);
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) h / w;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.height / size.width;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
这里是活动或片段中的用法:
public class ScanFragment extends Fragment {
private View mFragmentView;
private static Camera mCamera;
private CameraPreview mPreview;
private Handler autoFocusHandler;
private Context mContext;
public boolean previewing = true;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mContext = (MainActivity)getActivity();
// Inflate the layout for this fragment
mFragmentView = inflater.inflate(R.layout.fragment_scan, container, false);
}
public void cameraPreviewStop(){
previewing = false;
if(mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
}
}
public void cameraPreviewStart(){
try {
if (mCamera != null) {
mCamera.setPreviewCallback(previewCb);
mCamera.startPreview();
previewing = true;
mCamera.autoFocus(autoFocusCB);
}else{
initControls();
cameraPreviewStart();
}
}catch (Exception e){
releaseCamera();
initControls();
cameraPreviewStart();
}
}
public void initControls() {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
autoFocusHandler = new Handler();
try{
mCamera = getCameraInstance();
}catch(Exception e){
}
// Instance barcode scanner
initPreviewCamera();
}
public void initPreviewCamera(){
autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
autoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
mPreview = new CameraPreview(mContext, mCamera, previewCb,
autoFocusCB);
FrameLayout preview = (FrameLayout) mFragmentView.findViewById(R.id.cameraPreview);
preview.removeAllViews();
preview.addView(mPreview);
}
/**
* A safe way to get an instance of the Camera object.
*/
public static Camera getCameraInstance() {
Camera c = null;
try {
c = Camera.open();
} catch (Exception e) {
}
return c;
}
public void releaseCamera() {
if (mCamera != null) {
previewing = false;
try {
mCamera.setPreviewCallback(null);
mCamera.release();
}catch (Exception e){
}
mCamera = null;
}
}
private Runnable doAutoFocus = new Runnable() {
public void run() {
if (previewing)
mCamera.autoFocus(autoFocusCB);
}
};
Camera.PreviewCallback previewCb = new Camera.PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
Image imageFromCamera = new Image(size.width, size.height, "Y800");
// Do something...
}
};
// Mimic continuous auto-focusing
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
autoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
}
如果在活动中,则覆盖一些内容:
@Override
protected void onResume() {
super.onResume();
if(previewing) {
initControls();
cameraPreviewStart();
}
}
@Override
protected void onStop() {
super.onStop();
releaseCamera();
}
带有相机片段的片段视图(您可以在这里添加自定义视图和任何您想要自定义的内容,预览大小,绝对您想要的任何内容):
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:local="http://schemas.android.com/apk/res-auto">
<FrameLayout
android:id="@+id/cameraPreview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
最后请注意,这非常重要!特别是对于Android api 23+设备,从Android 6.0开始,如果你在相机对象上获得null,那么你必须只使用一个相机实例,然后你试图打开已经打开的相机。祝你有愉快的一天;)