我正在尝试从相机预览中捕获帧,以便在用户看到相机预览时对背景中的帧进行一些图像处理。
为此,我最初使用addCallbackBuffer()
insurfaceChanged()
方法添加 60 个缓冲区SurfaceView
,然后在每次onPreviewFrame()
调用时,我重新添加使用过的缓冲区。
问题是重新添加缓冲区onPreviewFrame()
会减慢预览速度。
我还在计算onPreviewFrame()
每秒的呼叫次数。在第一秒内,我接到了超过 70 个电话,onPreviewFrame()
而在第二秒及以后的时间里,我接到了 25 个电话。
这是代码
public class MySurfaceView extends SurfaceView implements
SurfaceHolder.Callback, Camera.PreviewCallback {
private static final int BUFFER_COUNT = 60;
private SurfaceHolder mHolder;
private Camera mCamera;
private boolean isPreviewRunning;
private final FPSCounter fpscounter = new FPSCounter();
private int frameWidth, frameHeight;
private byte[] prevFrameByteArr, currFrameByteArr;
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
mHolder = getHolder();
mHolder.addCallback(this);
}
public byte[] getPrevFrameByteArray() {
return prevFrameByteArr;
}
public byte[] getCurrFrameByteArray() {
return currFrameByteArr;
}
public int getFrameRate() {
return fpscounter.getLastFrameCount();
}
public int getFrameWidth() {
return frameWidth;
}
public int getFrameHeight() {
return frameHeight;
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
synchronized (this) {
prevFrameByteArr = currFrameByteArr;
currFrameByteArr = data;
}
mCamera.addCallbackBuffer(data);
fpscounter.logFrame();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
synchronized (this) {
if (isPreviewRunning)
mCamera.stopPreview();
Camera.Parameters parameters = mCamera.getParameters();
parameters.setRecordingHint(true);
parameters.setPreviewFormat(ImageFormat.NV21);
/* To get better frame rate, get the least resolution that matches the current aspect ratio */
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size currPreviewSize = parameters.getPreviewSize();
float ar = (float) (Math.floor(((float) currPreviewSize.width / currPreviewSize.height) * 10) / 10);
for (Size s : sizes) {
int w = s.width, h = s.height;
float resAr = (float) (Math.floor(((float) w / h) * 10) / 10);
if (ar == resAr) {
this.frameWidth = w;
this.frameHeight = h;
parameters.setPreviewSize(w, h);
currPreviewSize = s;
for (int i = 0; i < BUFFER_COUNT; i++) {
byte[] buffer = new byte[w * h *
ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8];
mCamera.addCallbackBuffer(buffer);
}
break;
}
}
mCamera.setParameters(parameters);
try {
mCamera.setPreviewDisplay(holder);
mCamera.setPreviewCallbackWithBuffer(this);
mCamera.startPreview();
isPreviewRunning = true;
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
synchronized (this) {
setWillNotDraw(true);
mCamera = Camera.open();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
synchronized (this) {
try {
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
isPreviewRunning = false;
}
} catch (Exception e) {
Log.e("cam error", e.getMessage());
}
}
}
}
和FPSCounter
班级
private long startTime;
private int frames, lastFrameCount;
public void logFrame() {
frames++;
if (System.nanoTime() - startTime >= 1000000000) {
lastFrameCount = frames;
frames = 0;
startTime = System.nanoTime();
}
}
public int getLastFrameCount() {
return lastFrameCount;
}
有人知道如何解决这个问题吗?