web-dev-qa-db-ja.com

ディスプレイよりも大きいSurfaceViewにカメラプレビューを合わせる

Androidアプリケーションは、getSupportedPreviewSizes()で指定されたプレビューサイズに関係なく、歪みなしでカメラプレビューをフルスクリーンで表示する必要があります。これにより、いずれかのプレビューがある程度トリミングされると思います。高さや幅ですが、これは私には関係ありません。これを実行しようとする理由は、特定のAndroidカメラ(Samsung Galaxy SII前面カメラなど)が同じプレビューを返さないためです。ディスプレイとしてのアスペクト比。したがって、引き伸ばしてクリップする必要があります。

カメラのプレビューを表示サイズよりも大きいビューに完全に拡大することは可能ですか?返されるプレビューピクセルの寸法よりも大きくSurfaceViewを拡大することは可能ですか?サーフェスビューのレイアウトパラメータをmatch_parentに設定するだけですが、これにより、ある方向に歪みが生じ、プレビューが表示いっぱいになるまでしか可能ではありません。これは、ディスプレイの外部でのプレビューが不可能であり、ハードウェア(またはOS)がそのような動作を制限していることを示しているようです。

このトピックには 別の質問 がありますが、その質問では、ログで見つけたように、画面のサイズよりも大きいSurfaceViewを作成することはできません。これは誤りです。ただし、カメラのプレビューを巨大なSurfaceViewのフルサイズに拡大することはできません。

私の試み:

相対レイアウトがあり、その中にFrameLayoutがあり、その中にSurfaceViewを作成します。相対レイアウト全体の幅は、デバイスの画面サイズの約2倍である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全体(画面幅の2倍)を埋めたいと思います。ビューは完全に正常に表示および破棄されるため、この特定の質問に関係のないコードは、本質的な質問の邪魔になるため削除し、ビューを表示サイズよりも簡単かつ単純に拡大しようとしています。

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サーフェスにレンダリングすることだと私は心配していますが、これは どうやら フルカラーでは遅すぎるかもしれません。カメラのプレビューを単純に引き伸ばしてクリップできるのも面倒です。

解決策を試みてくれたことに感謝します。

23
Daniel Smith

わかりました、これは答えとして非常に遅いことを私は知っていますが、それは可能です。以下は、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);
        }
    }
}
}

このコードは、プレビューを最小の寸法(aspcect比を台無しにしない)に合わせ、中央に他の寸法に黒いバーを配置することを目的としています。しかし、代わりに><に反転すると、目的の結果が得られます。例:

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