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

如何在Android RenderScript中旋转YUV_420_888数据至90度适配竖屏

Solution: 90-Degree YUV Rotation in RenderScript for Camera2 API

Got it, let's fix this rotation directly in your RenderScript YUV-to-RGBA converter—perfect for keeping performance high, which is critical for camera preview scenarios like your HdrViewfinder-style app.

Core Idea

When rotating 90 degrees clockwise, the output image swaps width and height (original width becomes new height, original height becomes new width). We need to adjust how we sample the Y, U, and V planes to map each output pixel back to the correct position in the original YUV buffer.

Modified RenderScript Code

Here's the updated script with rotation logic integrated:

// Needed directive for RS to work
#pragma version(1)
// The java_package_name directive needs to use your Activity's package path
#pragma rs java_package_name(net.hydex11.cameracaptureexample)

rs_allocation inputAllocation;
int wIn, hIn;
int numTotalPixels;

// Function to invoke before applying conversion
void setInputImageSize(int _w, int _h) {
    wIn = _w;
    hIn = _h;
    numTotalPixels = wIn * hIn;
}

// Kernel that converts a YUV element to a RGBA one, with 90-degree clockwise rotation
uchar4 __attribute__((kernel)) convert(uint32_t x, uint32_t y) {
    // 90-degree clockwise rotation: map output (x,y) to original YUV coordinates
    uint32_t srcX = y;          // Original X = output Y
    uint32_t srcY = hIn - 1 - x;// Original Y = (input height - 1) - output X

    // Sample Y component from planar Y plane
    int yIdx = srcX + srcY * wIn;
    uchar _y = rsGetElementAt_uchar(inputAllocation, yIdx);

    // Sample U/V components from interleaved chroma plane (4:2:0 subsampled)
    uint32_t srcX_uv = srcX >> 1; // Downscale X by 2 for chroma subsampling
    uint32_t srcY_uv = srcY >> 1; // Downscale Y by 2 for chroma subsampling
    int uvIdx = numTotalPixels + srcY_uv * wIn + (srcX_uv << 1);
    uchar _u = rsGetElementAt_uchar(inputAllocation, uvIdx);
    uchar _v = rsGetElementAt_uchar(inputAllocation, uvIdx + 1);

    // YUV to RGBA conversion (unchanged from your original logic)
    _y = _y < 16 ? 16 : _y;
    short Y = ((short)_y) - 16;
    short U = ((short)_u) - 128;
    short V = ((short)_v) - 128;

    uchar4 out;
    out.r = (uchar) clamp((float)( (Y * 298 + V * 409 + 128) >> 8), 0.f, 255.f);
    out.g = (uchar) clamp((float)( (Y * 298 - U * 100 - V * 208 + 128) >> 8), 0.f, 255.f);
    out.b = (uchar) clamp((float)( (Y * 298 + U * 516 + 128) >> 8), 0.f, 255.f);
    out.a = 255; // Ensure full opacity (uncommented for correct rendering)
    return out;
}

Key Changes Explained

  1. Coordinate Mapping for Rotation:

    • For each output pixel (x,y), we calculate the corresponding position in the original YUV buffer:
      • srcX = y: The X position in the original image matches the Y position of the output (since we're rotating clockwise, width and height swap).
      • srcY = hIn - 1 - x: The Y position in the original image is flipped along the vertical axis to maintain correct orientation after rotation.
  2. Chroma Plane Sampling Adjustment:

    • Since YUV_420_888 uses 2x2 subsampling for U/V, we downscale the original srcX and srcY by 2 (using bit shifts >>1) to get the correct chroma block position.
    • The UV index calculation is adjusted to use the rotated subsampled coordinates, ensuring we pick the right U/V pair for each output pixel.
  3. Opacity Fix:

    • Uncommented out.a = 255 to ensure the output image is fully opaque (critical for correct rendering in your preview Surface).

Java Layer Adjustment

Don't forget to update your Java code to create the output Allocation with swapped dimensions:

  • If your input YUV buffer is wIn x hIn, the output RGBA buffer should be hIn x wIn (since rotation swaps width and height). For example:
    // After calling setInputImageSize(w, h) on the RenderScript script
    Allocation outputAllocation = Allocation.createTyped(rs, 
        new Type.Builder(rs, Element.RGBA_8888(rs)).setX(h).setY(w).create());
    

Performance Note

By handling rotation directly in RenderScript, you leverage hardware acceleration (GPU or optimized CPU) which is far faster than doing this conversion/rotation in Java bytecode—perfect for real-time camera preview use cases like your HdrViewfinder project.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:26:00