在一些安卓设备上,相机预览视图被拉伸了。

4
我正在使用Google的API2相机,并在我的代码中遇到了一些问题。我有两个不同的CameraSessions,一个用于视频,另一个用于图像。为了更有效率,我更改了代码以使用唯一的Session并使应用程序更高效。
但是,我更改后发现我的相机预览不正常。当我使用4:3宽高比时,我的预览会在高度上被拉伸。而当我使用16:9比例时,它看起来很好。在这两种情况下,我的图片看起来都很好,我的预览不正确,但我拍摄的照片具有正确的宽高比。
我已经检查了不同的帖子,有相同的问题: Camera Preview Stretched on Few Android Devices Camera display / preview in full screen does not maintain aspect ratio - image is skewed, stretched in order to fit on the screen

但是不同的答案并没有帮助我。我知道问题在我的onMeasure()setTransformMatrix()OnLayoutChangeListener()方法内,但我不知道哪里出了问题。

现在请忽略有关旋转的代码,因为它是动态的。它总是进入else条件。

这是我的代码:

private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View v, int left, int top, int right,
                               int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {

        Log.d(TAG, "[onLayoutChange] " + mCameraUI.getTextureView().getMeasuredWidth() + "x" + mCameraUI.getTextureView().getMeasuredHeight());

        int width = right - left;
        int height = bottom - top;
        if (mPreviewWidth != width || mPreviewHeight != height
                || (mOrientationResize != mPrevOrientationResize)
                || mAspectRatioResize || mOrientationChanged) {

            Log.i(TAG, "[onLayoutChange] Layout changed");
            mPreviewWidth = width;
            mPreviewHeight = height;
            Log.i(TAG, "[onLayoutChange] Preview size: "+ mPreviewWidth + "x" + mPreviewHeight);
            setTransformMatrix(width, height);
            mController.onScreenSizeChanged((int) mSurfaceTextureUncroppedWidth,
                    (int) mSurfaceTextureUncroppedHeight);
            mAspectRatioResize = false;
            mOrientationChanged = true;
        }
    }
};

setTransform

 private void setTransformMatrix(int width, int height) {


    Log.i(TAG, "Screen: " + mPreviewWidth + "x" + mPreviewHeight);

    mMatrix = new Matrix();
    //mCameraUI.getTextureView().getTransform(mMatrix);
    float scaleX = 1f, scaleY = 1f;
    float scaledTextureWidth, scaledTextureHeight;

     mAspectRatio= (float)height/(float)width;
    if (mAspectRatio==(4f / 3f)){

            scaledTextureWidth = Math.max(width,
                    (int) (height / mAspectRatio));
            scaledTextureHeight = Math.max(height,
                    (int) (width * mAspectRatio));
        Log.i(TAG, "[PhotoUIManager]: Aspect Ratio 4:3=" + scaledTextureWidth + "x" + scaledTextureHeight );
    }
    else{
        scaledTextureWidth = Math.max(width,
                (int) (height / mAspectRatio));
        scaledTextureHeight = Math.max(height,
                (int) (width * mAspectRatio));
        Log.i(TAG, "[PhotoUIManager]: Aspect Ratio 16:9=" + scaledTextureWidth + "x" + scaledTextureHeight );
    }       


    if (mSurfaceTextureUncroppedWidth != scaledTextureWidth || mSurfaceTextureUncroppedHeight != scaledTextureHeight) {
        Log.e(TAG,"mi SurfaceWidth = " + mSurfaceTextureUncroppedWidth + "and mi scaledWidth=" + scaledTextureWidth);
        Log.e(TAG,"mi SurfaceHeigh = " + mSurfaceTextureUncroppedHeight + "and mi scaledHeight=" + scaledTextureHeight);
        mSurfaceTextureUncroppedWidth = scaledTextureWidth;
        mSurfaceTextureUncroppedHeight = scaledTextureHeight;
        Log.e(TAG,"Surfaces: " + mSurfaceTextureUncroppedWidth + "x" + mSurfaceTextureUncroppedHeight);
        if (mSurfaceTextureSizeListener != null) {
            mSurfaceTextureSizeListener.onSurfaceTextureSizeChanged(
                    (int) mSurfaceTextureUncroppedWidth, (int) mSurfaceTextureUncroppedHeight);
        }
    }
    scaleX = scaledTextureWidth / width;
    scaleY = scaledTextureHeight / height;
    mMatrix.setScale(scaleX, scaleY, scaledTextureWidth/2, scaledTextureHeight/2);
    Log.e(TAG, "scale: X= " + scaleX + " Y=" + scaleY + "Width= " + scaledTextureWidth + "Height= " + scaledTextureHeight);

    // init the position (this seems to be necessary too when the ratio is 16/9
    mCameraUI.getTextureView().setX(0);
    mCameraUI.getTextureView().setY(0);

    // Translate the preview with the rotation is aspect ration is 4/3
    if (mAspectRatio == 4f / 3f) {
        Log.e(TAG, "aspect ratio standard");
        float verticalTranslateOffset = (mCameraUI.getTextureView().getMeasuredHeight() - scaledTextureHeight) / 2;
        float horizontalTranslateOffset = (mCameraUI.getTextureView().getMeasuredWidth() - scaledTextureWidth) / 2;
        int rotation = CameraUtil.getDisplayRotation(mActivity);
        switch (rotation) {
            case 0:
                // phone portrait; translate the preview up
                mCameraUI.getTextureView().setY(-verticalTranslateOffset);
                mFaceView.setStandardPreviewTranslationOffset(-verticalTranslateOffset);
                mFocusView.setStandardPreviewTranslationOffset(-verticalTranslateOffset);
                break;
            case 90:
                // phone landscape: translate the preview left
                mCameraUI.getTextureView().setX(-horizontalTranslateOffset);
                mFaceView.setStandardPreviewTranslationOffset(-horizontalTranslateOffset);
                mFocusView.setStandardPreviewTranslationOffset(-horizontalTranslateOffset);
                break;
            case 180:
                // phone upside down: translate the preview bottom
                mCameraUI.getTextureView().setY(verticalTranslateOffset);
                mFaceView.setStandardPreviewTranslationOffset(verticalTranslateOffset);
                mFocusView.setStandardPreviewTranslationOffset(verticalTranslateOffset);
                break;
            case 270:
                // reverse landscape: translate the preview right
                mCameraUI.getTextureView().setX(horizontalTranslateOffset);
                mFaceView.setStandardPreviewTranslationOffset(horizontalTranslateOffset);
                mFocusView.setStandardPreviewTranslationOffset(horizontalTranslateOffset);
                break;
        }

    } else {
        Log.e(TAG, "aspect ratio full");
        mFaceView.setStandardPreviewTranslationOffset(0);
        mFocusView.setStandardPreviewTranslationOffset(0);
    }

    mRenderOverlay.updateLayout();
    mCameraUI.getTextureView().setTransform(mMatrix);

    RectF previewRect = new RectF(0, 0, width, height);

    mController.onPreviewRectChanged(CameraUtil.rectFToRect(previewRect));

}

onMeasure

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    Log.d(TAG, "onMeasure PREVIOUS. Width x Height [" + widthMeasureSpec + " = " + width + "x" + heightMeasureSpec + " = " + height + "]");

    int rotation = ((Activity) getContext()).getWindowManager().getDefaultDisplay().getRotation();
    boolean isInHorizontal = Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation;

    int newWidth;
    int newHeight;

    if (isInHorizontal) {

        newHeight = getMeasuredHeight();
        newWidth = (int) (newHeight * mAspectRatio);
    } else {

        newWidth = getMeasuredWidth();
        newHeight = (int) (newWidth * mAspectRatio);
    }

    setMeasuredDimension(newWidth, newHeight);
    Log.d(TAG, "onMeasure. Width x Height [" + newWidth + "x" + newHeight + "]");

}
1个回答

1

已解决!

我的纹理缓冲区大小有默认值,当我初始化新会话或更改纵横比之后,它们就会被重置。但是纹理的宽度和高度值没有随着纵横比的变化而更新,因此它一遍又一遍地被拉伸。

我通过将默认缓冲区大小更改为预览大小来解决这个问题,每次更改纵横比时我都会更新它。

   public void createCameraPreviewSession(Size previewsize, Surface recordingSurface) {
    try {
        if (mCaptureSession != null) {
            mCaptureSession.stopRepeating();
            mCaptureSession.close();
            mCaptureSession = null;
        }

        SurfaceTexture texture = mTextureView.getSurfaceTexture();
        assert texture != null;

        List<Surface> surfaces = new ArrayList<Surface>();

        // We configure the size of default buffer to be the size of camera preview we want.
        texture.setDefaultBufferSize(previewsize.getWidth(),previewsize.getHeight());
        ;
        // This is the output Surface we need to start preview.
        Surface surface = new Surface(texture);
.......

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接