woshidan's loose leaf

ぼんやり勉強しています

アプリで決めたActivityの向きがLANDSCAPEの時、Camera2のCameraDeviceから受け取るカメラのプレビューの向きがずれる

昨日のImageReaderのメモで プレビューの向きがおかしいのが気になる、という話を書きました。

その件について調べると

https://stackoverflow.com/questions/34536798/android-camera2-preview-is-rotated-90deg-while-in-landscape

などどうもアプリの画面の向きがLANDSCAPEの場合、そういうことがあるらしい。

一つには、TextureView に画像変換用の Matrix をセットすることで、TextureViewにセットされる画像をいじることができて、例えば下記のように記述した場合、

        // https://stackoverflow.com/questions/34536798/android-camera2-preview-is-rotated-90deg-while-in-landscape
        Matrix rotate = new Matrix();
        rotate.postScale(0.5f, 0.5f);
        rotate.postTranslate(IMAGE_HEIGHT / 2, 0);
        rotate.postRotate(60);
        mTextureView.setTransform(rotate);

みたいな感じとなる。

これをもうちょっとうまくやる。

        // Landscapeのアプリの場合、カメラの向きとプレビューの向きがずれるっぽい
        // https://stackoverflow.com/questions/34536798/android-camera2-preview-is-rotated-90deg-while-in-landscape
        Matrix rotate = new Matrix();
        rotate.postRotate(270); // デバイスの向きとアプリの向きの差分から決めると良い 
        // 関連: https://github.com/googlesamples/android-Camera2Basic/blob/master/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java#L520-L541
        rotate.postTranslate(0, mTextureView.getWidth());
        rotate.postScale(1.0f * 1.15f, 0.56f * 1.15f); // とりあえず頑張ってうめた
        mTextureView.setTransform(rotate);

これでだいたいプレビューの向きとサイズがあってくる。

このMatrixでの操作手順は、前操作した結果にさらに次の操作が反映されるので実際紙などを使って考えた方が早い。

さて、さっきのコードについてScaleが手打ちだとちょっと困るのでもう少しだけ頑張って

    private void createCameraPreviewSession() {
        // Landscapeのアプリの場合、カメラの向きとプレビューの向きがずれるっぽい
        // https://stackoverflow.com/questions/34536798/android-camera2-preview-is-rotated-90deg-while-in-landscape
        Matrix rotate = new Matrix();
        rotate.postRotate(270); // デバイスの向きとアプリの向きの差分から決めると良い
        // 関連: https://github.com/googlesamples/android-Camera2Basic/blob/master/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java#L520-L541
        rotate.postTranslate(0, mTextureView.getWidth());
        rotate.postScale((1.0f * IMAGE_WIDTH / IMAGE_HEIGHT) * (mTextureView.getWidth() / mTextureView.getHeight()), (1.0f * IMAGE_HEIGHT / IMAGE_WIDTH) * (mTextureView.getWidth() / mTextureView.getHeight()));
        mTextureView.setTransform(rotate);
        SurfaceTexture texture = mTextureView.getSurfaceTexture();
        texture.setDefaultBufferSize(IMAGE_WIDTH, IMAGE_HEIGHT); // 自分の手元のデバイスで決めうちしてます

こう。

今日時点での全体のコードは https://gist.github.com/woshidan/5443e4d0d779ffff036862d7010e14ef

気になってることについては

  • [新しい気になること]デバイスの向きとアプリの向きの差分
  • [既存気になること]CameraDevice解放のタイミングについて
  • [既存気になること]CameraCaptureSession closeのタイミングについて