Android Camera 预览镜像(使用 surfaceView 实现)
程序员文章站
2022-03-29 18:40:49
...
该方法是从opencv的java接口中学得
不知道为什么,最后显示出来的效果基本不能用(卡顿)
效果如下:
主要思想:
将Camera.PreviewCallback获得的 实时数据byte[] 数组,显示到Surfaceview上(双缓冲,子线程画图),这样就可以在即将预览的数据做镜像处理;
问题描述:
一般情况下 我们会直接使用
camera.setPreviewDisplay(this.getHolder());
将surfaceHolder 和 Camera的数据关联起来;但并没有提供这个接口直接实现镜像
Camera权限;activity注册等细节就不多说了,下面是
完整代码(1、CameraView ;2、Activity中使用 CameraView)
1、 重写 SurfaceView ,实现相关逻辑:
package com.yongyida.fastversion;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
/**
* @author Brandon on 2018/5/2
**/
public class CameraView extends SurfaceView implements Camera.PreviewCallback, SurfaceHolder.Callback {
private static final String TAG = CameraView.class.getSimpleName();
public static final int SURFACE_WIDTH = 640;
public static final int SURFACE_HIGH = 480;
SurfaceHolder mSurfaceHolder;
byte [] mData;
byte[] buffer;
Camera camera;
public CameraView(Context context) {
super(context);
mSurfaceHolder = this.getHolder();
mSurfaceHolder.addCallback(this);
cacheBitmap = Bitmap.createBitmap(SURFACE_WIDTH, SURFACE_HIGH, Bitmap.Config.ARGB_8888);
camera = Camera.open();
Camera.Parameters params = camera.getParameters();
int size = SURFACE_HIGH * SURFACE_WIDTH;
size = size * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
buffer = new byte[size];
camera.addCallbackBuffer(buffer);
camera.setPreviewCallbackWithBuffer(this);
// try {
//
// camera.setPreviewDisplay(this.getHolder());
// } catch (IOException e) {
// e.printStackTrace();
// }
camera.startPreview();
}
Bitmap cacheBitmap;
int mScale = 1;
//在子线程中绘制
private void drawFrame(byte[] data) {
cacheBitmap = TrackUtil.byte2Bitmap(data, SURFACE_WIDTH, SURFACE_HIGH);
Canvas canvas = mSurfaceHolder.lockCanvas();
canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
Matrix m = new Matrix();
m.postScale(-1, 1);
cacheBitmap = Bitmap.createBitmap(cacheBitmap, 0, 0, SURFACE_WIDTH, SURFACE_HIGH, m, true);
canvas.drawBitmap(cacheBitmap, new Rect(0,0,cacheBitmap.getWidth(), cacheBitmap.getHeight()),
new Rect((canvas.getWidth() - cacheBitmap.getWidth()) / 2,
(canvas.getHeight() - cacheBitmap.getHeight()) / 2,
(canvas.getWidth() - cacheBitmap.getWidth()) / 2 + cacheBitmap.getWidth(),
(canvas.getHeight() - cacheBitmap.getHeight()) / 2 + cacheBitmap.getHeight()), null);
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
synchronized (this) {
if (data!=null)
{
mData = data;
mCameraFrameReady = true;
Log.e(TAG, "preview ");
}
this.notify();
}
camera.addCallbackBuffer(buffer);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e(TAG, "onCreate");
Thread thread = new Thread(new SurfaceRunnable());
thread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.e(TAG, "onChangee");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e(TAG, "onDestory");
}
boolean mCameraFrameReady = false;
boolean mStopThread = false;
int mChainIdx = 0;
private class SurfaceRunnable implements Runnable {
@Override
public void run() {
do {
Log.e(TAG,"cameraReady " + mCameraFrameReady + " mStopThread " + mStopThread );
boolean hasFrame = false;
synchronized (CameraView.this) {
try {
while (!mCameraFrameReady && !mStopThread) {
CameraView.this.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
if (mCameraFrameReady) {
mChainIdx = 1 - mChainIdx;
mCameraFrameReady = false;
hasFrame = true;
}
}
if (!mStopThread && hasFrame) {
if (mData!=null){
drawFrame(mData);
Log.e(TAG,"frame been draw " + mData.length);
}
}
} while (!mStopThread);
}
}
}
2、Activity中显示
package com.yongyida.fastversion;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.yongyida.yydrobotcv.R;
/**
* create by Brandon 2018/5/2
* make it can mirror frame
*/
public class CanMirrorCameraActivity extends AppCompatActivity {
private static final String TAG = CanMirrorCameraActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG,"onCreate ");
setContentView(new CameraView(this));
}
}
下一篇: 如何在Git中合并特定的提交