web-dev-qa-db-ja.com

SurfaceViewを備えたCamera2

新しいCamera2を単純なSurfaceViewで動作させようとしていますが、ライブプレビューで問題が発生しています。一部のデバイスでは、画像が不均衡に引き伸ばされ、他のデバイスでは見栄えがします。

プレビューストリームサイズのサイズに合うようにプログラムで調整するSurfaceViewをセットアップしました。

Nexus 5ではこれは問題ないように見えますが、1台のSamsungデバイスがうまく機能していません。また、Samsungデバイスには、プレビューの右側に黒い境界線があります。

SurfaceViewを操作することは本当に不可能ですか、それとも今回はTextureViewに切り替えるときですか?

10
slott

はい、それは確かに可能です。 SurfaceViewとそれに関連するSurfaceは2つの異なるものであり、それぞれにサイズを割り当てることができます。

Surfaceは、カメラの出力を保持する実際のメモリバッファであるため、そのサイズを設定すると、各フレームから取得する実際の画像のサイズが決まります。カメラから利用できるフォーマットごとに、このバッファーを作成できる可能な(正確な)サイズの小さなセットがあります。

SurfaceViewは、この画像が利用可能な場合に表示するものであり、基本的にはレイアウト内の任意のサイズにすることができます。基になる関連画像データをレイアウトサイズに合わせて拡大しますが、この表示サイズはデータのサイズとは異なることに注意してください-Androidは、表示用に画像データのサイズを自動的に変更します。これがおそらくあなたのストレッチを引き起こしています。

たとえば、次のように、camera2basicのAutoFitTextureViewに似たSurfaceViewベースのautofitビューを作成できます(これが私が使用しているものです)。

import Android.content.Context;
import Android.util.AttributeSet;
import Android.view.SurfaceView;

public class AutoFitSurfaceView extends SurfaceView {

    private int mRatioWidth = 0;
    private int mRatioHeight = 0;

    public AutoFitSurfaceView(Context context) {
        this(context, null);
    }

    public AutoFitSurfaceView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AutoFitSurfaceView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
     * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
     * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
     *
     * @param width  Relative horizontal size
     * @param height Relative vertical size
     */
    public void setAspectRatio(int width, int height) {
        if (width < 0 || height < 0) {
            throw new IllegalArgumentException("Size cannot be negative.");
        }
        mRatioWidth = width;
        mRatioHeight = height;
        requestLayout();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        if (0 == mRatioWidth || 0 == mRatioHeight) {
            setMeasuredDimension(width, height);
        } else {
            if (width < height * mRatioWidth / mRatioHeight) {
                setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
            } else {
                setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
            }
        }
    }
}
3
rcsumner

createCaptureSession のドキュメントには

SurfaceViewに描画する場合:SurfaceViewのSurfaceが作成されたら、setFixedSize(int、int)を使用してSurfaceのサイズをgetOutputSizes(SurfaceHolder.class)によって返されるサイズの1つに設定します。

1
paleozogt

私はCamera2を使ったことがありません(しかし、新しいテクノロジーでは非常に興味深いです)。私が提案できるのは、サンプルに従うことだけです。また、注意深くチェックすると、サンプルはカスタムTextureViewを使用しているので、プロジェクトにコピーしてみてください。

http://developer.Android.com/samples/Camera2Basic/src/com.example.Android.camera2basic/AutoFitTextureView.html

/**
 * A {@link TextureView} that can be adjusted to a specified aspect ratio.
 */
public class AutoFitTextureView extends TextureView {

また、SurfaceViewとTextureViewの違いは(理論的には)、レイアウトで通常のビューとして使用でき、他のビュー階層を通じて「全体をパンチ」できることと、Camera2はAPI21 +でのみ使用できることを考慮しています... TextureViewへの移行に害はありません

0
Budius