在某些设备上未调用相机 onPreviewFrame
Camera onPreviewFrame not called on some devices
我希望 LogCat 记录 #onPreviewFrame()
多次,但它只适用于选定的设备,例如:
- 三星 Galaxy S6 (7.0)
- 三星 Galaxy S6 (6.0.1)
- LG 莱昂 (5.0.1)
但不适用于以下设备:
- LG G4 (6.0)
- 华为6X (7.0)
- 连结 6P (7.0)
下面是代码片段:
public CameraSurfaceView(Context context, AttributeSet set) {
super(context, set);
Log.d(TAG, "CameraSurfaceView(context, set)");
// Get the Surface Holder
this.holder = this.getHolder();
this.holder.addCallback(this);
this.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
// Turn on the Camera
this.camera = Camera.open();
} catch (Exception ex) {
Log.e(TAG, "#surfaceCreated() error=" + ex.getMessage(), ex);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d(TAG, "#surfaceChanged()");
if (holder.getSurface() == null) {
// preview surface does not exist
return;
}
if (camera == null) {
// camera does not exist
return;
}
// This allows us to make our own draw calls to this canvas
this.setWillNotDraw(false);
// Initialize canvas variables
previewPaint = new Paint();
// Initialize preview variables
deviceWidth = width;
deviceHeight = height;
Camera.Size previewSize = this.camera.getParameters().getPreviewSize();
previewWidth = previewSize.width;
previewHeight = previewSize.height;
previewBitmap = Bitmap.createBitmap(previewWidth, previewHeight, Bitmap.Config.ARGB_8888);
// Initialize Scale Variables
previewScaleMatrix = new Matrix();
previewScaleMatrix.setScale(deviceWidth / (float) previewWidth,
deviceHeight / (float) previewHeight, deviceWidth / 2.0f, deviceHeight / 2.0f);
// Initialize RenderScript variables
rs = RenderScript.create(getContext());
// RenderScript YUV to RGB
yuvToRgbScript = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
Type.Builder previewRgbaType =
new Type.Builder(rs, Element.RGBA_8888(rs)).setX(previewWidth).setY(previewHeight);
yuvToRgbOut = Allocation.createTyped(rs, previewRgbaType.create(), Allocation.USAGE_SCRIPT);
// RenderScript Invert
invertScript = new ScriptC_invert(rs);
invertOut = Allocation.createTyped(rs, yuvToRgbOut.getType(), Allocation.USAGE_SCRIPT);
// Set color effect to none
parameters.setColorEffect(Camera.Parameters.EFFECT_NONE);
camera.setParameters(parameters);
// Set the preview callback
Log.d(TAG, "#surfaceChanged() camera.setPreviewCallback()");
camera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Log.d(TAG, "#onPreviewFrame()");
}
});
// Start the camera preview
Log.d(TAG, "#surfaceChanged() camera.startPreview()");
camera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when replaced with a new screen
// Always make sure to release the Camera instance
if (camera != null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera = null;
}
}
我的LogCat显示如下:
D/CameraSurfaceView: #surfaceChanged()
D/CameraSurfaceView: #surfaceChanged() camera.setPreviewCallback()
D/CameraSurfaceView: #surfaceChanged() camera.startPreview()
ScriptC_invert
来自 https://developer.android.com/guide/topics/renderscript/compute.html#writing-an-rs-kernel
中的 RenderScript
样本
即使我删除了所有 RenderScript 的东西,同样的问题。
我也试过以下方法:
- Camera onPreviewFrame not called
- Android onPreviewFrame is not called
注意:
一个修复需要在我的 surfaceChanged()
方法中使用 camera.setPreviewDisplay(holder)
。但这会给我带来另一个问题,因为我需要在 onPreviewFrame()
中执行 holder.lockCanvas()
并遇到以下异常:
E/SurfaceHolder: Exception locking surface
java.lang.IllegalArgumentException
at android.view.Surface.nativeLockCanvas(Native Method)
at android.view.Surface.lockCanvas(Surface.java:264)
at android.view.SurfaceView.internalLockCanvas(SurfaceView.java:842)
at android.view.SurfaceView.lockCanvas(SurfaceView.java:830)
at com.arcanys.ar.CameraSurfaceView.onPreviewFrame(CameraSurfaceView.java:204)
可能有一些我遗漏或配置错误的东西。
至于暂时,我还没有找到解决这个问题的方法,但我有一个解决方法。
由于我们不能同时使用camera.setPreviewDisplay(surfaceHolder)
和camera.setPreviewCallback(previewCallback)
希望在某些设备上使用onPreviewFrame()
中的surfaceHolder.lockCanvas()
,我已将预览转移到另一个 SurfaceView
并从那里处理 onPreviewFrame()
并使用它自己的 SufraceHolder
.
我希望 LogCat 记录 #onPreviewFrame()
多次,但它只适用于选定的设备,例如:
- 三星 Galaxy S6 (7.0)
- 三星 Galaxy S6 (6.0.1)
- LG 莱昂 (5.0.1)
但不适用于以下设备:
- LG G4 (6.0)
- 华为6X (7.0)
- 连结 6P (7.0)
下面是代码片段:
public CameraSurfaceView(Context context, AttributeSet set) {
super(context, set);
Log.d(TAG, "CameraSurfaceView(context, set)");
// Get the Surface Holder
this.holder = this.getHolder();
this.holder.addCallback(this);
this.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
// Turn on the Camera
this.camera = Camera.open();
} catch (Exception ex) {
Log.e(TAG, "#surfaceCreated() error=" + ex.getMessage(), ex);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d(TAG, "#surfaceChanged()");
if (holder.getSurface() == null) {
// preview surface does not exist
return;
}
if (camera == null) {
// camera does not exist
return;
}
// This allows us to make our own draw calls to this canvas
this.setWillNotDraw(false);
// Initialize canvas variables
previewPaint = new Paint();
// Initialize preview variables
deviceWidth = width;
deviceHeight = height;
Camera.Size previewSize = this.camera.getParameters().getPreviewSize();
previewWidth = previewSize.width;
previewHeight = previewSize.height;
previewBitmap = Bitmap.createBitmap(previewWidth, previewHeight, Bitmap.Config.ARGB_8888);
// Initialize Scale Variables
previewScaleMatrix = new Matrix();
previewScaleMatrix.setScale(deviceWidth / (float) previewWidth,
deviceHeight / (float) previewHeight, deviceWidth / 2.0f, deviceHeight / 2.0f);
// Initialize RenderScript variables
rs = RenderScript.create(getContext());
// RenderScript YUV to RGB
yuvToRgbScript = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
Type.Builder previewRgbaType =
new Type.Builder(rs, Element.RGBA_8888(rs)).setX(previewWidth).setY(previewHeight);
yuvToRgbOut = Allocation.createTyped(rs, previewRgbaType.create(), Allocation.USAGE_SCRIPT);
// RenderScript Invert
invertScript = new ScriptC_invert(rs);
invertOut = Allocation.createTyped(rs, yuvToRgbOut.getType(), Allocation.USAGE_SCRIPT);
// Set color effect to none
parameters.setColorEffect(Camera.Parameters.EFFECT_NONE);
camera.setParameters(parameters);
// Set the preview callback
Log.d(TAG, "#surfaceChanged() camera.setPreviewCallback()");
camera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Log.d(TAG, "#onPreviewFrame()");
}
});
// Start the camera preview
Log.d(TAG, "#surfaceChanged() camera.startPreview()");
camera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when replaced with a new screen
// Always make sure to release the Camera instance
if (camera != null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera = null;
}
}
我的LogCat显示如下:
D/CameraSurfaceView: #surfaceChanged()
D/CameraSurfaceView: #surfaceChanged() camera.setPreviewCallback()
D/CameraSurfaceView: #surfaceChanged() camera.startPreview()
ScriptC_invert
来自 https://developer.android.com/guide/topics/renderscript/compute.html#writing-an-rs-kernel
RenderScript
样本
即使我删除了所有 RenderScript 的东西,同样的问题。
我也试过以下方法:
- Camera onPreviewFrame not called
- Android onPreviewFrame is not called
注意:
一个修复需要在我的 surfaceChanged()
方法中使用 camera.setPreviewDisplay(holder)
。但这会给我带来另一个问题,因为我需要在 onPreviewFrame()
中执行 holder.lockCanvas()
并遇到以下异常:
E/SurfaceHolder: Exception locking surface
java.lang.IllegalArgumentException
at android.view.Surface.nativeLockCanvas(Native Method)
at android.view.Surface.lockCanvas(Surface.java:264)
at android.view.SurfaceView.internalLockCanvas(SurfaceView.java:842)
at android.view.SurfaceView.lockCanvas(SurfaceView.java:830)
at com.arcanys.ar.CameraSurfaceView.onPreviewFrame(CameraSurfaceView.java:204)
可能有一些我遗漏或配置错误的东西。
至于暂时,我还没有找到解决这个问题的方法,但我有一个解决方法。
由于我们不能同时使用camera.setPreviewDisplay(surfaceHolder)
和camera.setPreviewCallback(previewCallback)
希望在某些设备上使用onPreviewFrame()
中的surfaceHolder.lockCanvas()
,我已将预览转移到另一个 SurfaceView
并从那里处理 onPreviewFrame()
并使用它自己的 SufraceHolder
.