限时福利领取


在Android开发中,处理YUV图像数据是视频和相机应用开发中的常见需求。但很多开发者初次接触时,往往会遇到格式混乱、性能瓶颈和内存占用高等问题。今天我们就来聊聊如何高效处理YUV图像数据。

YUV图像处理示意图

一、背景痛点分析

在使用Camera2 API或MediaCodec时,我们经常会遇到YUV数据处理的问题:

  1. 格式转换CPU开销大:YUV转RGB的纯CPU计算会消耗大量资源
  2. 内存拷贝导致GC压力:频繁创建中间ByteBuffer会触发垃圾回收
  3. 格式混乱:YUV420P/NV21/NV12等格式容易混淆

二、YUV格式对比

Android平台主要使用三种YUV格式:

  1. YUV420P:平面存储,Y、U、V三个平面完全分开
  2. NV21:Y平面连续存储,VU交错存储(Android默认格式)
  3. NV12:Y平面连续存储,UV交错存储

Android首选NV21的原因:

  • 硬件编解码器普遍支持
  • 内存访问效率更高
  • Camera2 API默认输出格式

三、核心实现方案

1. 使用ImageReader获取NV21数据

ImageReader reader = ImageReader.newInstance(
    width, height, 
    ImageFormat.YUV_420_888, 2);

reader.setOnImageAvailableListener(reader -> {
    Image image = reader.acquireLatestImage();
    // 获取三个Plane
    Image.Plane[] planes = image.getPlanes();

    // Y分量(亮度)
    ByteBuffer yBuffer = planes[0].getBuffer();
    // UV分量(色度)
    ByteBuffer uvBuffer = planes[1].getBuffer();

    // 处理数据...
    image.close();
}, handler);

2. OpenGL ES着色器转换

// 片段着色器
uniform sampler2D yTexture;
uniform sampler2D uvTexture;

void main() {
    float y = texture2D(yTexture, vTexCoord).r;
    float u = texture2D(uvTexture, vTexCoord).r - 0.5;
    float v = texture2D(uvTexture, vTexCoord).g - 0.5;

    // YUV转RGB矩阵运算
    float r = y + 1.402 * v;
    float g = y - 0.344 * u - 0.714 * v;
    float b = y + 1.772 * u;

    gl_FragColor = vec4(r, g, b, 1.0);
}

四、性能优化技巧

性能优化流程图

  1. 对象池技术:避免重复分配ByteBuffer
public class BufferPool {
    private Queue<ByteBuffer> pool = new ArrayDeque<>();

    public synchronized ByteBuffer get(int size) {
        ByteBuffer buffer = pool.poll();
        if (buffer == null || buffer.capacity() < size) {
            buffer = ByteBuffer.allocateDirect(size);
        }
        return buffer;
    }

    public synchronized void put(ByteBuffer buffer) {
        buffer.clear();
        pool.offer(buffer);
    }
}
  1. SurfaceTexture设置
surfaceTexture.setDefaultBufferSize(width, height);

五、常见问题解决

  1. 色偏问题
  2. 根据视频标准选择BT.601或BT.709转换矩阵
  3. 移动端通常使用BT.601

  4. 低端设备问题

  5. 在GLSL中使用mediump代替highp
  6. 简化着色器计算

六、思考与拓展

现在我们已经掌握了基本的YUV处理技术,那么如何实现4K YUV数据的零拷贝处理呢?这里有几个思路方向:

  1. 使用AHardwareBuffer直接访问硬件缓冲区
  2. 通过EGLImageKHR实现GPU直接访问
  3. 利用RenderScript进行并行处理

希望这篇笔记能帮助你更好地理解Android中的YUV图像处理。在实际开发中,记得根据具体场景选择合适的优化方案。

Logo

音视频技术社区,一个全球开发者共同探讨、分享、学习音视频技术的平台,加入我们,与全球开发者一起创造更加优秀的音视频产品!

更多推荐