You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android相机预览数据旋转异常求助(Unity插件开发)

Alright, let's tackle this rotation issue head-on. The core problem here is that setDisplayOrientation() only affects how the preview is displayed on screen—it doesn't change the pixel order of the raw byte data you get in onPreviewFrame(). And params.setRotation() only applies to JPEG photos taken with the camera, not the preview stream. Plus, your original AdjustOrientation method didn't account for the fact that front and rear cameras have different sensor orientations, which is why you saw opposite rotation directions on your Pixel XL.

Here's how to fix this while sticking to the old Camera API:


Step 1: Calculate the Correct Camera Rotation Angle

First, add this method to compute the proper rotation angle based on Android's official guidelines—it handles both screen rotation and front/rear camera sensor differences:

private int getCameraDisplayOrientation(int cameraId) {
    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(cameraId, info);
    int rotation = myActivity.getWindowManager().getDefaultDisplay().getRotation();
    int degrees = 0;
    switch (rotation) {
        case Surface.ROTATION_0: degrees = 0; break;
        case Surface.ROTATION_90: degrees = 90; break;
        case Surface.ROTATION_180: degrees = 180; break;
        case Surface.ROTATION_270: degrees = 270; break;
    }

    int result;
    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
        result = (info.orientation + degrees) % 360;
        result = (360 - result) % 360;  // Compensate for front camera mirroring
    } else {  // Rear camera
        result = (info.orientation - degrees + 360) % 360;
    }
    return result;
}

Step 2: Update Preview Parameter Setup

Replace the orientation-handling code in your setupCamera method with this logic. We'll adjust the preview dimensions based on the rotation angle (since rotating 90/270 degrees swaps width and height):

@SuppressLint("NewApi")
private void setupCamera(int cameraID, int width, int height) {
    Camera.Parameters params = mCamera.getParameters();
    params.setRecordingHint(true);
    params.setPreviewFormat(17); // NV21 format (your existing choice)
    params.setZoom(0);
    params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
    params.setExposureCompensation(0);

    // Calculate the correct rotation angle
    int displayOrientation = getCameraDisplayOrientation(cameraID);
    mCamera.setDisplayOrientation(displayOrientation);

    // Swap width/height if rotation is 90 or 270 degrees
    int targetPreviewWidth = width;
    int targetPreviewHeight = height;
    if (displayOrientation == 90 || displayOrientation == 270) {
        targetPreviewWidth = height;
        targetPreviewHeight = width;
    }

    // Get optimal preview size for the adjusted dimensions
    Camera.Size previewSize = getOptimalSize(targetPreviewWidth, targetPreviewHeight, mCamera.getParameters().getSupportedPreviewSizes());
    params.setPreviewSize(previewSize.width, previewSize.height);

    try{
        mCamera.setParameters(params);
    } catch (Exception e){
        Log.i("Unity", "ERROR: " + e.getMessage());
    }

    Camera.Size mCameraPreviewSize = params.getPreviewSize();
    prevWidth = mCameraPreviewSize.width;
    prevHeight = mCameraPreviewSize.height;

    // Log preview details (unchanged from your code)
    int[] fpsRange = new int[2];
    params.getPreviewFpsRange(fpsRange);
    String previewFacts = mCameraPreviewSize.width + "x" + mCameraPreviewSize.height;
    if (fpsRange[0] == fpsRange[1]) {
        previewFacts += " @" + (fpsRange[0] / 1000.0) + "fps";
    } else {
        previewFacts += " @[" + (fpsRange[0] / 1000.0) + " - " + (fpsRange[1] / 1000.0) + "] fps";
    }
    Log.i("Unity", "JAVA: previewFacts=" + previewFacts);
}

Step 3: Remove the Old AdjustOrientation Method

Your original AdjustOrientation method is now obsolete—delete it, and remove the call to it from your startCamera method.


Why This Works

  • The getCameraDisplayOrientation method correctly calculates the rotation needed for both front and rear cameras, fixing the opposite rotation issue on your Pixel XL.
  • By swapping width/height for 90/270 degree rotations, we ensure the preview data's dimensions match the rotated screen orientation. Unity can now render the onPreviewFrame data directly using the updated prevWidth and prevHeight values without extra rotation.
  • setDisplayOrientation ensures the preview looks correct on the Android side, while our dimension adjustment aligns the raw byte data with your Unity app's portrait layout.

Optional: Rotate Raw NV21 Data Directly

If you need the raw byte array in onPreviewFrame to be physically rotated (instead of just adjusting dimensions), you can add this NV21 rotation helper and call it in the preview callback (note: this adds performance overhead):

// Rotate NV21 data 90 degrees (add similar methods for 180/270 if needed)
private byte[] rotateNV21(byte[] data, int width, int height) {
    byte[] rotatedData = new byte[data.length];
    int ySize = width * height;
    int y = 0;
    int uvIndex = ySize;

    for (int x = 0; x < width; x++) {
        for (int yRow = height - 1; yRow >= 0; yRow--) {
            rotatedData[y] = data[yRow * width + x];
            y++;
        }
        for (int yRow = height - 1; yRow >= 0; yRow -= 2) {
            rotatedData[uvIndex] = data[ySize + yRow * width + x];
            rotatedData[uvIndex + 1] = data[ySize + (yRow + 1) * width + x];
            uvIndex += 2;
        }
    }
    return rotatedData;
}

Then update your preview callback:

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
    // Rotate data based on your calculated displayOrientation
    int displayOrientation = getCameraDisplayOrientation(mCamera.getCameraInfo().facing == Camera.CameraInfo.CAMERA_FACING_FRONT ? 1 : 0);
    byte[] rotatedData = rotateNV21(data, prevWidth, prevHeight);
    bytes = rotatedData;
    UnityPlayer.UnitySendMessage(gameObjectTargetName, "GetBuffer", "");
}

内容的提问来源于stack exchange,提问作者Dalanchoo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:57:56