android - 将相机预览安装到比显示器大的 SurfaceView

标签 android android-layout android-camera surfaceview

我有一个 Android 应用程序需要全屏预览相机预览,而不管 getSupportedPreviewSizes() 给出的预览大小如何,并且不会失真。我希望这会在高度或宽度上裁剪预览,但这与我无关。我寻求这样做的原因是因为某些 android 相机(例如三星 Galaxy SII 前置摄像头)不会返回与显示器具有相同纵横比的任何预览,因此需要拉伸(stretch)和剪裁。

是否可以将相机预览完全放大到大于显示尺寸的 View ? 可以通过简单地设置表面 View 的布局参数将 SurfaceView 放大到大于返回的预览像素尺寸match_parent,但这会导致某些方向的失真,并且只有在预览填满显示之前才有可能。这似乎表明在显示器之外进行预览是不可能的,并且硬件(或操作系统)限制了这种行为。

another question关于该主题,但该问题声称无法创建大于屏幕尺寸的 SurfaceView,这是错误的,正如我在日志记录中发现的那样。然而,似乎情况是相机预览无法增长到巨大的 SurfaceView 的全尺寸。

我的尝试:

我有一个相对布局,其中有一个 FrameLayout,并在其中创建了一个 SurfaceView。整个相对布局的宽度设置为 635dp,大约是设备屏幕尺寸的两倍。 FrameLayout 与此大小匹配,SurfaceView 也是如此(稍后以编程方式添加)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/camera_activity_layout"
    android:layout_width="635dp"
    android:layout_height="match_parent" >

    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </FrameLayout>

</RelativeLayout>

以下是获取和设置预览大小的代码。在这里,我想让相机预览扩大以填充整个 FrameLayout(屏幕宽度的两倍)。 View 完全正常显示和破坏,因此我删除了与此特定问题无关的代码,因为它分散了基本问题的注意力,并且我尝试轻松简单地将 View 扩大到大于显示的大小。

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    ...

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        Camera.Parameters parameters = mCamera.getParameters();
        final DisplayMetrics dm = this.getResources().getDisplayMetrics();
            //getBestPreviewSize returns the best preview size, don't worry
            //but some devices do not return one for all camera matching the aspect ratio
        cameraSize = getBestPreviewSize(parameters, dm.heightPixels, dm.widthPixels);

        if (cameraSize!=null) {
            parameters.setPreviewSize(cameraSize.width, cameraSize.height);
            mCamera.setParameters(parameters);
        }

        FrameLayout.LayoutParams frameParams = (FrameLayout.LayoutParams) this.getLayoutParams();

        frameParams.width = 800; //For argument's sake making this ~double the width of the display. Same result occurs if I use MATCH_PARENT
        frameParams.height = LayoutParams.MATCH_PARENT;
        this.setLayoutParams(frameParams);

        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

            Log.d("surfChange","W/H of CamPreview (child) is "+this.getWidth()+"/"+this.getHeight()+" while parent is ");
            Log.d("surfChange","W/H of holder (child) is "+mHolder.getSurfaceFrame().width()+"/"+mHolder.getSurfaceFrame().height()+" while parent is ");
        } catch (Exception e){
        }
    }
};

我担心在这项工作中取得成功的唯一方法是以某种方式渲染到 openGL 表面,但是这 apparently全彩可能太慢了。如果可以简单地拉伸(stretch)和剪切相机预览,那也是一种痛苦。

在此先感谢您对解决方案的任何尝试。

最佳答案

好的,我知道这是一个很晚的答案,但这是可能的。下面是来自 Android SDK 示例的代码。要查看实现此代码的其余代码,请下载 android sdk 示例并转到 Samples/android-10(one I used, could try whichever you want to target)/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.java

class PreviewSurface extends ViewGroup implements SurfaceHolder.Callback {
...
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    if (changed && getChildCount() > 0) {
        final View child = getChildAt(0);

        final int width = r - l;
        final int height = b - t;

        int previewWidth = width;
        int previewHeight = height;
        if (mPreviewSize != null) {
            previewWidth = mPreviewSize.width;
            previewHeight = mPreviewSize.height;
        }

        // Center the child SurfaceView within the parent.
        if (width * previewHeight > height * previewWidth) {
            final int scaledChildWidth = previewWidth * height / previewHeight;
            child.layout((width - scaledChildWidth) / 2, 0,
                    (width + scaledChildWidth) / 2, height);
        } else {
            final int scaledChildHeight = previewHeight * width / previewWidth;
            child.layout(0, (height - scaledChildHeight) / 2,
                    width, (height + scaledChildHeight) / 2);
        }
    }
}
}

此代码旨在使预览适合最小尺寸(不会弄乱纵横比)并居中以在其他尺寸上有黑条。但是如果你翻转 >成为 <相反,您将实现您想要的。例如:

if (width * previewHeight < height * previewWidth) {...

关于android - 将相机预览安装到比显示器大的 SurfaceView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11321251/

相关文章:

android - Camera.open() 阻塞 UI 线程

java - 根据其他TextView更改TextView值

android - 如何告诉用户哪个角色使用手势素描?

android - 谷歌眼镜 : menu and card font size styling

Android-布局的正确定位

android - 我如何从 Intent 中获取 Uri?

java - 向 Whatsapp 用户发送图像

android - 如何在Constraint Layout中实现如下动态宽度的布局?

Android:以编程方式更改布局的 Root View 的高度

android - Android 中某些相机分辨率的不同捕获输出大小