【问题标题】:Camera onPreviewFrame not called on some devices某些设备上未调用相机 onPreviewFrame
【发布时间】:2017-09-05 11:27:28
【问题描述】:

我希望 LogCat 能够多次记录 #onPreviewFrame(),但它仅适用于选定的设备,例如:

  • 三星 Galaxy S6 (7.0)
  • 三星 Galaxy S6 (6.0.1)
  • LG 莱昂 (5.0.1)

但不适用于以下设备:

  • LG G4 (6.0)
  • 华为6X (7.0)
  • Nexus 6P (7.0)

下面是sn-p的代码:

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 内容,同样的问题。

我还尝试了以下方法:

注意:

在我的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$4.internalLockCanvas(SurfaceView.java:842)
                     at android.view.SurfaceView$4.lockCanvas(SurfaceView.java:830)
                     at com.arcanys.ar.CameraSurfaceView.onPreviewFrame(CameraSurfaceView.java:204)

我可能遗漏了一些东西或配置错误。

【问题讨论】:

    标签: android android-camera android-canvas


    【解决方案1】:

    就目前而言,我还没有找到解决此问题的方法,而是有一个解决方法。

    由于我们不能同时使用camera.setPreviewDisplay(surfaceHolder)camera.setPreviewCallback(previewCallback),希望在某些设备上使用onPreviewFrame() 中的surfaceHolder.lockCanvas(),我已将我的预览转移到另一个SurfaceView 并处理onPreviewFrame()从那里使用它自己的SufraceHolder

    【讨论】:

    • 这是一个正确的解决方法。 setPreviewDisplay or setPreviewTexture 在 Android 中是强制性的,但有些设备不强制执行。
    • 顺便说一句,除非您的大多数目标设备都低于 Lollipop,否则请考虑切换到 camera2 API。如果您决定继续使用 已弃用 Camera API,请确保在单独的 Handler 线程中打开相机(以便 Camera.open() 和回调不会导致 UI 线程拥塞)。
    • @AlexCohn 谢谢你的建议。是的,我还针对棒棒糖之前的设备,这就是我仍在使用已弃用的相机 API 的原因。
    • 你可以同时使用camera.setPreviewDisplay(surfaceHolder)camera.setPreviewCallback(previewCallback),在说什么?..你不能同时使用camera.setPreviewTexture(mSurfaceTexture);camera.setPreviewDisplay(getHolder());
    猜你喜欢
    • 2011-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-17
    相关资源
    最近更新 更多