25

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

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

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

私の試み:

相対レイアウトがあり、その中に FrameLayout があり、その中に SurfaceView を作成します。以下では、相対レイアウト全体の幅を 635 dp に設定しています。これは、デバイスの画面サイズの約 2 倍です。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 サーフェスにレンダリングすることではないかと心配していますが、これは明らかにフル カラーでは遅すぎる可能性があります。カメラのプレビューが単純に引き伸ばされたり、切り取られたりするのも面倒です。

解決策の試みに感謝します。

4

1 に答える 1

14

わかりました、これは答えとして非常に遅いことを知っていますが、可能です。以下は、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) {...
于 2013-01-18T20:16:21.433 に答える