2017-10-29 119 views
0

我想在我的Android应用程序中实现Camera2 API。当我点击拍照按钮时,图像会在预览中冻结,错误消息将显示为“无法创建捕捉会话;配置失败”。该应用程序有最小的API为21和我已经设置的权限如下:Camera2 API错误未能创建捕获会话

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
<uses-permission android:name="android.permission.CAMERA"/> 
<uses-feature android:name="android.hardware.camera2.full"/> 

在MainActivity.java的代码如下:

package com.example.dioglgt.cameratest; 

import android.Manifest; 
import android.content.Context; 
import android.content.pm.PackageManager; 
import android.graphics.ImageFormat; 
import android.graphics.SurfaceTexture; 
import android.hardware.camera2.CameraAccessException; 
import android.hardware.camera2.CameraCaptureSession; 
import android.hardware.camera2.CameraCharacteristics; 
import android.hardware.camera2.CameraDevice; 
import android.hardware.camera2.CameraManager; 
import android.hardware.camera2.CameraMetadata; 
import android.hardware.camera2.CaptureRequest; 
import android.hardware.camera2.TotalCaptureResult; 
import android.hardware.camera2.params.StreamConfigurationMap; 
import android.media.Image; 
import android.media.ImageReader; 
import android.os.Bundle; 
import android.os.Environment; 
import android.os.Handler; 
import android.os.HandlerThread; 
import android.support.annotation.NonNull; 
import android.support.v4.app.ActivityCompat; 
import android.support.v7.app.AppCompatActivity; 
import android.util.Log; 
import android.util.Size; 
import android.util.SparseIntArray; 
import android.view.Surface; 
import android.view.TextureView; 
import android.view.View; 
import android.widget.Button; 
import android.widget.Toast; 

import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.OutputStream; 
import java.nio.ByteBuffer; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

public class MainActivity extends AppCompatActivity { 

    private static final int PERMISSION_REQUEST_CODE = 1; 
    private Button button; 
    private static final String TAG = "AndroidCameraApi"; 
    private Button takePictureButton; 
    private TextureView textureView; 
    private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); 
    static { 
     ORIENTATIONS.append(Surface.ROTATION_0, 90); 
     ORIENTATIONS.append(Surface.ROTATION_90, 0); 
     ORIENTATIONS.append(Surface.ROTATION_180, 270); 
     ORIENTATIONS.append(Surface.ROTATION_270, 180); 
    } 
    private String cameraId; 
    protected CameraDevice cameraDevice; 
    protected CameraCaptureSession cameraCaptureSessions; 
    protected CaptureRequest captureRequest; 
    protected CaptureRequest.Builder captureRequestBuilder; 
    private Size imageDimension; 
    private ImageReader imageReader; 
    private File file; 
    private static final int REQUEST_CAMERA_PERMISSION = 200; 
    private boolean mFlashSupported; 
    private Handler mBackgroundHandler; 
    private HandlerThread mBackgroundThread; 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.splash_page); 
     textureView = (TextureView) findViewById(R.id.texture); 
     assert textureView != null; 
     textureView.setSurfaceTextureListener(textureListener); 
     takePictureButton = (Button) findViewById(R.id.btn_takepicture); 
     assert takePictureButton != null; 
     takePictureButton.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       takePicture(); 
      } 
     }); 
    } 

    TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() { 
     @Override 
     public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 

      openCamera(); 
     } 
     @Override 
     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 

     } 
     @Override 
     public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 
      return false; 
     } 
     @Override 
     public void onSurfaceTextureUpdated(SurfaceTexture surface) { 
     } 
    }; 
    private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { 
     @Override 
     public void onOpened(CameraDevice camera) { 

      Log.e(TAG, "onOpened"); 
      cameraDevice = camera; 
      createCameraPreview(); 
     } 
     @Override 
     public void onDisconnected(CameraDevice camera) { 
      cameraDevice.close(); 
     } 
     @Override 
     public void onError(CameraDevice camera, int error) { 
      cameraDevice.close(); 
      cameraDevice = null; 
     } 
    }; 
    final CameraCaptureSession.CaptureCallback captureCallbackListener = new CameraCaptureSession.CaptureCallback() { 
     @Override 
     public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { 
      super.onCaptureCompleted(session, request, result); 
      Toast.makeText(MainActivity.this, "Saved:" + file, Toast.LENGTH_SHORT).show(); 
      createCameraPreview(); 
     } 
    }; 
    protected void startBackgroundThread() { 
     mBackgroundThread = new HandlerThread("Camera Background"); 
     mBackgroundThread.start(); 
     mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); 
    } 
    protected void stopBackgroundThread() { 
     mBackgroundThread.quitSafely(); 
     try { 
      mBackgroundThread.join(); 
      mBackgroundThread = null; 
      mBackgroundHandler = null; 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
    protected void takePicture() { 
     if(null == cameraDevice) { 
      Log.e(TAG, "cameraDevice is null"); 
      return; 
     } 
     CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); 
     try { 
      CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId()); 
      Size[] jpegSizes = null; 
      if (characteristics != null) { 
       jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG); 
      } 
      int width = 240; 
      int height = 180; 
      if (jpegSizes != null && 0 < jpegSizes.length) { 
       width = jpegSizes[0].getWidth(); 
       height = jpegSizes[0].getHeight(); 
      } 
      ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1); 
      List<Surface> outputSurfaces = new ArrayList<Surface>(2); 
      outputSurfaces.add(reader.getSurface()); 
      outputSurfaces.add(new Surface(textureView.getSurfaceTexture())); 
      final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 
      captureBuilder.addTarget(reader.getSurface()); 
      captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); 
      // Orientation 
      int rotation = getWindowManager().getDefaultDisplay().getRotation(); 
      captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)); 
      final File file = new File(Environment.getExternalStorageDirectory()+"/pic.jpg"); 
      ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() { 
       @Override 
       public void onImageAvailable(ImageReader reader) { 
        Image image = null; 
        try { 
         image = reader.acquireLatestImage(); 
         ByteBuffer buffer = image.getPlanes()[0].getBuffer(); 
         byte[] bytes = new byte[buffer.capacity()]; 
         buffer.get(bytes); 
         save(bytes); 
        } catch (FileNotFoundException e) { 
         e.printStackTrace(); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } finally { 
         if (image != null) { 
          image.close(); 
         } 
        } 
       } 
       private void save(byte[] bytes) throws IOException { 
        OutputStream output = null; 
        try { 
         output = new FileOutputStream(file); 
         output.write(bytes); 
        } finally { 
         if (null != output) { 
          output.close(); 
         } 
        } 
       } 
      }; 
      reader.setOnImageAvailableListener(readerListener, mBackgroundHandler); 
      final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() { 
       @Override 
       public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { 
        super.onCaptureCompleted(session, request, result); 
        Toast.makeText(MainActivity.this, "Saved:" + file, Toast.LENGTH_SHORT).show(); 
        createCameraPreview(); 
       } 
      }; 
      cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() { 
       @Override 
       public void onConfigured(CameraCaptureSession session) { 
        try { 
         session.capture(captureBuilder.build(), captureListener, mBackgroundHandler); 
        } catch (CameraAccessException e) { 
         e.printStackTrace(); 
        } 
       } 
       @Override 
       public void onConfigureFailed(CameraCaptureSession session) { 
       } 
      }, mBackgroundHandler); 
     } catch (CameraAccessException e) { 
      e.printStackTrace(); 
     } 
    } 
    protected void createCameraPreview() { 
     try { 
      SurfaceTexture texture = textureView.getSurfaceTexture(); 
      assert texture != null; 
      texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight()); 
      Surface surface = new Surface(texture); 
      captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 
      captureRequestBuilder.addTarget(surface); 
      cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback(){ 
       @Override 
       public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { 
        //The camera is already closed 
        if (null == cameraDevice) { 
         return; 
        } 
        // When the session is ready, we start displaying the preview. 
        cameraCaptureSessions = cameraCaptureSession; 
        Log.e(TAG, "so far good"); 
        updatePreview(); 
       } 
       @Override 
       public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { 
        Toast.makeText(MainActivity.this, "Configuration change", Toast.LENGTH_SHORT).show(); 
       } 
      }, null); 
     } catch (CameraAccessException e) { 
      e.printStackTrace(); 
     } 
    } 
    private void openCamera() { 
     CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); 
     Log.e(TAG, "is camera open"); 
     try { 
      cameraId = manager.getCameraIdList()[0]; 
      CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); 
      StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 
      assert map != null; 
      imageDimension = map.getOutputSizes(SurfaceTexture.class)[0]; 
      // Add permission for camera and let user grant the permission 
      if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { 
       ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CAMERA_PERMISSION); 
       return; 
      } 
      manager.openCamera(cameraId, stateCallback, null); 
     } catch (CameraAccessException e) { 
      e.printStackTrace(); 
     } 
     Log.e(TAG, "openCamera X"); 
    } 
    protected void updatePreview() { 
     if(null == cameraDevice) { 
      Log.e(TAG, "updatePreview error, return"); 
     } 
     captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); 
     try { 
      cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler); 
     } catch (CameraAccessException e) { 
      e.printStackTrace(); 
     } 
    } 
    private void closeCamera() { 
     if (null != cameraDevice) { 
      cameraDevice.close(); 
      cameraDevice = null; 
     } 
     if (null != imageReader) { 
      imageReader.close(); 
      imageReader = null; 
     } 
    } 
    @Override 
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 
     if (requestCode == REQUEST_CAMERA_PERMISSION) { 
      if (grantResults[0] == PackageManager.PERMISSION_DENIED) { 
       // close the app 
       Toast.makeText(MainActivity.this, "Sorry!!!, you can't use this app without granting permission", Toast.LENGTH_LONG).show(); 
       finish(); 
      } 
     } 
    } 
    @Override 
    protected void onResume() { 
     super.onResume(); 
     Log.e(TAG, "onResume"); 
     startBackgroundThread(); 
     if (textureView.isAvailable()) { 
      openCamera(); 
     } else { 
      textureView.setSurfaceTextureListener(textureListener); 
     } 
    } 
    @Override 
    protected void onPause() { 
     Log.e(TAG, "onPause"); 
     //closeCamera(); 
     stopBackgroundThread(); 
     super.onPause(); 
    } 


} 

我在具有牛轧糖的装置测试的应用程序请解决这个问题。我把下面的logcat中:

10-30 07:44:27.218 3060-3061/? E/ANDR-PERF-RESOURCEQS: Failed to apply optimization [4, 0] 
10-30 07:44:27.482 3067-5669/? E/mm-camera: <ISP ><ERROR> 1050: isp_handler_control_streamoff: stream_off 2 2 ide 20003 
10-30 07:44:27.482 3067-5669/? E/mm-camera: <ISP ><ERROR> 1050: isp_handler_control_streamoff: stream_off 2 2 ide 20003 

              [ 10-30 07:44:27.488 28733: 5783 D/   ] 
              cmdtype=MM_CAMERA_CMD_TYPE_EXIT 

              [ 10-30 07:44:27.528 28733: 5778 D/   ] 
              cmdtype=MM_CAMERA_CMD_TYPE_EXIT 

              [ 10-30 07:44:27.530 28733: 5777 D/   ] 
              cmdtype=MM_CAMERA_CMD_TYPE_EXIT 
10-30 07:44:27.547 642-656/? E/Sensors: sns_reg_la.c(194):reg write: offset 1792, num bytes: 24 
10-30 07:44:27.552 28733-28808/? E/QCamera3HWI: int qcamera::QCamera3HardwareInterface::configureStreamsPerfLocked(camera3_stream_configuration_t *): Blob size greater than 4k and multiple streams are on encoder output 
10-30 07:44:27.552 28733-28808/? E/Camera3-Device: Camera 0: configureStreamsLocked: Set of requested inputs/outputs not supported by HAL 
10-30 07:44:27.552 28733-28808/? E/CameraDeviceClient: endConfigure: Camera 0: Unsupported set of inputs/outputs provided 
10-30 07:44:27.558 4234-4234/com.example.dioglgt.cameratest E/CameraCaptureSession: Session 3: Failed to create capture session; configuration failed 
10-30 07:44:29.830 4810-4838/? E/radish: radish_send_nd_packet sent 72 bytes 
+0

ImageFormat.RAW_SENSOR可能不支持所有设备,可能是您首先尝试使用ImageFormat.JPEG作为所有设备支持。 – slee

+0

ImageFormat.JPEG不起作用。所以,我尝试使用ImageFormat.RAW_SENSOR。但似乎没有任何工作。有人能给我看一个有效的例子吗? – John

+0

我在我们以前的相机应用程序中尝试了几乎所有的项目代码,它没有错误。相反,我使用全局变化存储captureRequest = capturebuilder.build()。并在camerasession.setRepeatingRequest(captureRequest,capturecallback,null)中调用它; – slee

回答

1

(从评论移动作为一个答案):

错误从相机HAL建议你有输出组合不受支持。看起来你只是从列表中抓取纹理视图和JPEG的第一个大小;这可能会导致分辨率配对太高,具体取决于您的设备支持的硬件级别。如果您将预览分辨率降至< = 1080p,这是否有效?

针对硬编码的缓冲区大小为800,600:

这是不可能的600,800是一个实际的支持预览分辨率;您应该迭代列表以找到符合条件的大小(例如最大分辨率< = 1080p等)。除非你使用的是相对不寻常的android设备,否则相机分辨率将全部为横向 - (800,600)而不是(600,800)。相机API会将您提供给它的分辨率舍入到Surface/TextureView支持的大小,但在所有情况下都不会导致匹配的宽高比,所以没有明确选择支持的大小有点危险。

相关问题