本文介绍了如何在三星Galaxy设备上同时打开前置和后置摄像头?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个问题,因为我已经解决了SO中的所有问题.

This is a question that is still left unanswered as i have gone through all the questions in SO.

  • access both front and back camera simultaneously on samsung galaxy devices
  • How to capture both front and back cameras in Galaxy S4 simultaneously?

...等等,但是真正的问题是我有一个在多种设备上经过测试的完美双摄像头,这些设备包括:Google Pixel XL,LETV 1S,Elephone S7,LG设备,实际上大多数设备都有两个图像信号处理器,三星设备除外,后者在测试时仅显示1个摄像机预览.

...and so on but the real problem is that i have a perfectly working dual camera tested on multiple devices like: Google Pixel XL, LETV 1S, Elephone S7, LG Devices, practically most devices that have two Image Signal Processors, except for Samsung Devices, which show only 1 camera preview when tested.

到目前为止,我已经尝试使用OpenGL,Deprecated Camera API,Camera2 API,最后是自己的Samsung Camera Api打开这两个相机,结果仍然相同.

I have tried so far opening both cameras with OpenGL, Deprecated Camera API, Camera2 API, and lastly the very own Samsung Camera Api and still the same results.

下面是Samsung API CameraPreview

Below is the Samsung API CameraPreview

public class SCamera {
private SCamera mSCamera;
  private SCameraManager mSCameraManager;
  private SCameraDevice mSCameraDevice;
  private SCameraCaptureSession mSCameraSession;
  private SCameraCharacteristics mCharacteristics;
  private SCaptureRequest.Builder mPreviewBuilder;
  /**
   * Current Preview Size.
   */
  private Size mPreviewSize;
  /**
   * Current Picture Size.
   */
  private Size mPictureSize;
  /**
   * ID of the current {@link com.samsung.android.sdk.camera.SCameraDevice}.
   */
  private String mCameraId;
  /**
   * for camera preview.
   */
  private TextureView mTextureView;
  /**
   * A camera related listener/callback will be posted in this handler.
   */
  private Handler mBackgroundHandler;
  private HandlerThread mBackgroundHandlerThread;
  /**
   * A image saving worker Runnable will be posted to this handler.
   */
  private HandlerThread mImageSavingHandlerThread;
  /**
   * An orientation listener for jpeg orientation
   */
  private int mLastOrientation = 0;
  private Semaphore mCameraOpenCloseLock = new Semaphore(1);
  /**
   * Lens facing. Camera with this facing will be opened
   */
  private int mLensFacing;
  private List<Integer> mLensFacingList;
  private Activity context;

  public SamsungApiManager(Activity context, TextureView textureView, int cameraId) {
    this.context = context;
    this.mTextureView = textureView;
    startBackgroundThread();

    // initialize SCamera
    mSCamera = new SCamera();
    try {
      mSCamera.initialize(context);
    } catch (SsdkUnsupportedException e) {
      e.printStackTrace();
      return;
    }
    createUI();
    checkRequiredFeatures(cameraId);
    openCamera(mLensFacing);
  }

  private void checkRequiredFeatures(int cameraId) {
    try {
      // Find available lens facing value for this device
      Set<Integer> lensFacings = new HashSet<>();
      for (String id : mSCamera.getSCameraManager().getCameraIdList()) {
        SCameraCharacteristics cameraCharacteristics =
            mSCamera.getSCameraManager().getCameraCharacteristics(id);
        lensFacings.add(cameraCharacteristics.get(SCameraCharacteristics.LENS_FACING));
      }
      mLensFacingList = new ArrayList<>(lensFacings);

      mLensFacing = mLensFacingList.get(cameraId);

      setDefaultJpegSize(mSCamera.getSCameraManager(), mLensFacing);
    } catch (CameraAccessException e) {
      e.printStackTrace();
      Log.e("Camera", "Cannot access the camera.", e);
    }
  }

  /**
   * Starts back ground thread that callback from camera will posted.
   */
  private void startBackgroundThread() {
    mBackgroundHandlerThread = new HandlerThread("Background Thread");
    mBackgroundHandlerThread.start();
    mBackgroundHandler = new Handler(mBackgroundHandlerThread.getLooper());

    mImageSavingHandlerThread = new HandlerThread("Saving Thread");
    mImageSavingHandlerThread.start();
  }

  /**
   * Starts a preview.
   */
  synchronized private void startPreview() {
    if (mSCameraSession == null) return;
    try {
      // Starts displaying the preview.
      mSCameraSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);
    } catch (CameraAccessException e) {
      Log.e("Error", e.getMessage());
      e.printStackTrace();
    }
  }

  /**
   * Stops back ground thread.
   */
  private void stopBackgroundThread() {
    if (mBackgroundHandlerThread != null) {
      mBackgroundHandlerThread.quitSafely();
      try {
        mBackgroundHandlerThread.join();
        mBackgroundHandlerThread = null;
        mBackgroundHandler = null;
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }

    if (mImageSavingHandlerThread != null) {
      mImageSavingHandlerThread.quitSafely();
      try {
        mImageSavingHandlerThread.join();
        mImageSavingHandlerThread = null;
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  private void setDefaultJpegSize(SCameraManager manager, int facing) {
    try {
      for (String id : manager.getCameraIdList()) {
        SCameraCharacteristics cameraCharacteristics = manager.getCameraCharacteristics(id);
        if (cameraCharacteristics.get(SCameraCharacteristics.LENS_FACING) == facing) {
          List<Size> jpegSizeList = new ArrayList<>();

          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
              && cameraCharacteristics.get(SCameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
              .getHighResolutionOutputSizes(ImageFormat.JPEG) != null) {
            jpegSizeList.addAll(Arrays.asList(
                cameraCharacteristics.get(SCameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
                    .getHighResolutionOutputSizes(ImageFormat.JPEG)));
          }
          jpegSizeList.addAll(Arrays.asList(
              cameraCharacteristics.get(SCameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
                  .getOutputSizes(ImageFormat.JPEG)));
          mPictureSize = jpegSizeList.get(0);
        }
      }
    } catch (CameraAccessException e) {
      Log.e("Camera", "Cannot access the camera.", e);
    }
  }

  /**
   * Opens a {@link com.samsung.android.sdk.camera.SCameraDevice}.
   */
  synchronized public void openCamera(int facing) {
    try {
      if (!mCameraOpenCloseLock.tryAcquire(3000, TimeUnit.MILLISECONDS)) {
        Log.e("Error", "time out");
      }

      mSCameraManager = mSCamera.getSCameraManager();

      mCameraId = null;

      // Find camera device that facing to given facing parameter.
      for (String id : mSCamera.getSCameraManager().getCameraIdList()) {
        SCameraCharacteristics cameraCharacteristics =
            mSCamera.getSCameraManager().getCameraCharacteristics(id);
        if (cameraCharacteristics.get(SCameraCharacteristics.LENS_FACING) == facing) {
          mCameraId = id;
          break;
        }
      }

      if (mCameraId == null) {
        Log.e("Error", "no id found");
        return;
      }

      // acquires camera characteristics
      mCharacteristics = mSCamera.getSCameraManager().getCameraCharacteristics(mCameraId);

      StreamConfigurationMap streamConfigurationMap =
          mCharacteristics.get(SCameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

      // Acquires supported preview size list that supports SurfaceTexture
      mPreviewSize =
          getOptimalPreviewSize(streamConfigurationMap.getOutputSizes(SurfaceTexture.class),
              (double) mPictureSize.getWidth() / mPictureSize.getHeight());

      Log.d("Camera",
          "Picture Size: " + mPictureSize.toString() + " Preview Size: " + mPreviewSize.toString());

      if (contains(mCharacteristics.get(SCameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES),
          SCameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
        List<Size> rawSizeList = new ArrayList<>();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
            && streamConfigurationMap.getHighResolutionOutputSizes(ImageFormat.RAW_SENSOR)
            != null) {
          rawSizeList.addAll(Arrays.asList(
              streamConfigurationMap.getHighResolutionOutputSizes(ImageFormat.RAW_SENSOR)));
        }
        rawSizeList.addAll(
            Arrays.asList(streamConfigurationMap.getOutputSizes(ImageFormat.RAW_SENSOR)));
      }

      // Opening the camera device here
      mSCameraManager.openCamera(mCameraId, new SCameraDevice.StateCallback() {
        @Override
        public void onDisconnected(SCameraDevice sCameraDevice) {
          mCameraOpenCloseLock.release();
        }

        @Override
        public void onError(SCameraDevice sCameraDevice, int i) {
          mCameraOpenCloseLock.release();
        }

        public void onOpened(SCameraDevice sCameraDevice) {
          mCameraOpenCloseLock.release();
          mSCameraDevice = sCameraDevice;
          createPreviewSession();
        }
      }, mBackgroundHandler);
    } catch (CameraAccessException e) {
      e.printStackTrace();
      Log.e("Camera", "Cannot open the camera.", e);
    } catch (InterruptedException e) {
      throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
    }
  }

  /**
   * Closes a camera and release resources.
   */
  synchronized private void closeCamera() {
    try {
      mCameraOpenCloseLock.acquire();

      if (mSCameraSession != null) {
        mSCameraSession.close();
        mSCameraSession = null;
      }

      if (mSCameraDevice != null) {
        mSCameraDevice.close();
        mSCameraDevice = null;
      }

      mSCameraManager = null;
    } catch (InterruptedException e) {
      Log.e("Camera", "Interrupted while trying to lock camera closing.", e);
    } finally {
      mCameraOpenCloseLock.release();
    }
  }

  /**
   * Configures requires transform {@link android.graphics.Matrix} to TextureView.
   */
  private void configureTransform(int viewWidth, int viewHeight) {
    if (null == mTextureView || null == mPreviewSize) {
      return;
    }

    int rotation = context.getWindowManager().getDefaultDisplay().getRotation();
    Matrix matrix = new Matrix();
    RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
    RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
    float centerX = viewRect.centerX();
    float centerY = viewRect.centerY();
    if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
      bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
      matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
      float scale = Math.max((float) viewHeight / mPreviewSize.getHeight(),
          (float) viewWidth / mPreviewSize.getWidth());
      matrix.postScale(scale, scale, centerX, centerY);
      matrix.postRotate(90 * (rotation - 2), centerX, centerY);
    } else {
      matrix.postRotate(90 * rotation, centerX, centerY);
    }

    mTextureView.setTransform(matrix);
    mTextureView.getSurfaceTexture()
        .setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
  }

  private boolean contains(final int[] array, final int key) {
    for (final int i : array) {
      if (i == key) {
        return true;
      }
    }
    return false;
  }

  /**
   * Create a {@link com.samsung.android.sdk.camera.SCameraCaptureSession} for preview.
   */
  synchronized private void createPreviewSession() {

    if (null == mSCamera
        || null == mSCameraDevice
        || null == mSCameraManager
        || null == mPreviewSize
        || !mTextureView.isAvailable()) {
      return;
    }

    try {
      SurfaceTexture texture = mTextureView.getSurfaceTexture();

      // Set default buffer size to camera preview size.
      texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());

      Surface surface = new Surface(texture);

      // Creates SCaptureRequest.Builder for preview with output target.
      mPreviewBuilder = mSCameraDevice.createCaptureRequest(SCameraDevice.TEMPLATE_PREVIEW);
      mPreviewBuilder.addTarget(surface);

      // Creates SCaptureRequest.Builder for still capture with output target.
      //mCaptureBuilder = mSCameraDevice.createCaptureRequest(SCameraDevice.TEMPLATE_STILL_CAPTURE);

      // Creates a SCameraCaptureSession here.
      List<Surface> outputSurface = new ArrayList<Surface>();
      outputSurface.add(surface);
      //outputSurface.add(mJpegReader.getSurface());

      mSCameraDevice.createCaptureSession(outputSurface, new SCameraCaptureSession.StateCallback() {
        @Override
        public void onConfigureFailed(SCameraCaptureSession sCameraCaptureSession) {

        }

        @Override
        public void onConfigured(SCameraCaptureSession sCameraCaptureSession) {
          mSCameraSession = sCameraCaptureSession;
          startPreview();
        }
      }, mBackgroundHandler);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }

  /**
   * Prepares an UI, like button, dialog, etc.
   */
  private void createUI() {
    // Set SurfaceTextureListener that handle life cycle of TextureView
    mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
      @Override
      public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        // "onSurfaceTextureAvailable" is called, which means that SCameraCaptureSession is not created.
        // We need to configure transform for TextureView and crate SCameraCaptureSession.
        configureTransform(width, height);
        createPreviewSession();
      }

      @Override
      public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        return true;
      }

      @Override
      public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        // SurfaceTexture size changed, we need to configure transform for TextureView, again.
        configureTransform(width, height);
      }

      @Override
      public void onSurfaceTextureUpdated(SurfaceTexture surface) {
      }
    });
  }

  /**
   * Returns required orientation that the jpeg picture needs to be rotated to be displayed upright.
   */
  private int getJpegOrientation() {
    int degrees = mLastOrientation;

    if (mCharacteristics.get(SCameraCharacteristics.LENS_FACING)
        == SCameraCharacteristics.LENS_FACING_FRONT) {
      degrees = -degrees;
    }

    return (mCharacteristics.get(SCameraCharacteristics.SENSOR_ORIENTATION) + degrees + 360) % 360;
  }

  /**
   * find optimal preview size for given targetRatio
   */
  private Size getOptimalPreviewSize(Size[] sizes, double targetRatio) {
    final double ASPECT_TOLERANCE = 0.001;

    Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    Display display = context.getWindowManager().getDefaultDisplay();
    Point displaySize = new Point();
    display.getSize(displaySize);
    int targetHeight = Math.min(displaySize.y, displaySize.x);

    // Try to find an size match aspect ratio and size
    for (Size size : sizes) {
      double ratio = (double) size.getWidth() / size.getHeight();
      if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
      if (Math.abs(size.getHeight() - targetHeight) < minDiff) {
        optimalSize = size;
        minDiff = Math.abs(size.getHeight() - targetHeight);
      }
    }

    // Cannot find the one match the aspect ratio. This should not happen.
    // Ignore the requirement.
    if (optimalSize == null) {
      Log.w("Camera", "No preview size match the aspect ratio");
      minDiff = Double.MAX_VALUE;
      for (Size size : sizes) {
        if (Math.abs(size.getHeight() - targetHeight) < minDiff) {
          optimalSize = size;
          minDiff = Math.abs(size.getHeight() - targetHeight);
        }
      }
    }

    return optimalSize;
  }
}

以下是我同时访问两个摄像机的方式:

Below is how i access both cameras simultaneously:

  private void openFrontCam() {

        textureFront.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
          @Override
          public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
            sCamera =
                new SCamera(DualCamera.this, textureFront, 0);
          }

          @Override
          public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {

          }

          @Override
          public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
            return false;
          }

          @Override
          public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

          }
        });
      }



   private void openBackCam() {

        textureBack.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
          @Override
          public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
            sCamera =
                new SCamera(DualCamera.this, textureBack, 1);
          }

          @Override
          public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {

          }

          @Override
          public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
            return false;
          }

          @Override
          public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

          }
        });
      }

现在我的理解是,有人声称他们在三星设备上使用了双摄像头功能.,除非三星已锁定该功能仅供自己使用.

Now my understanding is that some claim that they got the dual camera feature working on Samsung Devices like in this detailed answer, unless Samsung has locked the feature for their own use only.

到目前为止,我已经用尽了所有选项,不知道还有什么可以尝试的.

I have exhausted every option to date and don't know what is there left to try.

谢谢.

推荐答案

我仅使用三星的内部SemCamera.jar和OpenGL以及glsl着色器,设法在Samsung galaxy S8,S8 +和Note 8设备上解锁了此功能.但是,它与较旧的Samsung设备或最新的S9设备不兼容.对他们的库存相机应用程序进行反向工程以查看该功能是否存在之后,我发现该功能已从其代码中完全删除.因此,他们的框架阻止了第三方应用程序使用此功能,并且显然不是出于安全原因.我们希望在不久的将来,他们将在下一个Camera SDK中共享双摄像头功能.

I managed to unlock this feature only on Samsung galaxy S8, S8+ and Note 8 devices, using their internal library SemCamera.jar and OpenGL with glsl shaders. However it is not compatible with older Samsung devices nor with the newest S9 devices. After reverse engineering their stock camera app to see if the feature exists, i saw that it was erased completely from their code. So their framework blocks 3rd party apps from using this feature and clearly not for security reasons. We hope that in the near future they will share the dual camera feature in the next Camera SDK.

这篇关于如何在三星Galaxy设备上同时打开前置和后置摄像头?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!