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

如何从YUV420 ByteBuffer创建org.webrtc.JavaI420Buffer修复视频帧失真

问题根源

你当前代码的核心问题是:调用ByteBuffer.slice()时没有为每个平面设置正确的读取上限(limit),仅指定了起始位置,WebRTC底层读取平面数据时可能会读到超出当前平面的冗余数据,进而导致色彩或画面失真。

你给出的参数中所有平面的rowStride等于对应平面的宽度、pixelStride为1,符合I420格式的标准对齐要求,偏移量计算也正确,格式本身没有问题。

修复后的代码

public static I420Buffer convert(ImageProcessResult result) {
    int frameWidth = result.getWidth();
    int frameHeight = result.getHeight();

    int rowStrideY = result.getRowStride(0);
    int rowStrideU = result.getRowStride(1);
    int rowStrideV = result.getRowStride(2);

    int offsetY = result.getPlaneOffset(0);
    int offsetU = result.getPlaneOffset(1);
    int offsetV = result.getPlaneOffset(2);
    
    // 计算每个平面的实际数据长度
    int planeSizeY = rowStrideY * result.getPlaneHeight(0);
    int planeSizeU = rowStrideU * result.getPlaneHeight(1);
    int planeSizeV = rowStrideV * result.getPlaneHeight(2);

    ByteBuffer i420ByteBuffer = result.getBuffer();
    // 先重置原Buffer的状态,避免之前的操作遗留的position/limit影响
    i420ByteBuffer.clear();

    // 切Y平面:指定起始位置和结束位置
    i420ByteBuffer.position(offsetY);
    i420ByteBuffer.limit(offsetY + planeSizeY);
    final ByteBuffer dataY = i420ByteBuffer.slice();

    // 切U平面
    i420ByteBuffer.position(offsetU);
    i420ByteBuffer.limit(offsetU + planeSizeU);
    final ByteBuffer dataU = i420ByteBuffer.slice();

    // 切V平面
    i420ByteBuffer.position(offsetV);
    i420ByteBuffer.limit(offsetV + planeSizeV);
    final ByteBuffer dataV = i420ByteBuffer.slice();

    // 重置原Buffer的状态,避免释放时出问题
    i420ByteBuffer.clear();

    JavaI420Buffer frame = JavaI420Buffer.wrap(frameWidth, frameHeight, dataY, rowStrideY, dataU, rowStrideU, dataV, rowStrideV,
            () -> {
                JniCommon.nativeFreeByteBuffer(i420ByteBuffer);
            });
    return frame;
}

其他排查点

如果修改后仍有失真,可按以下顺序排查:

  • 确认视频处理引擎返回的确实是I420平面格式,而非NV12/NV21半平面格式,半平面格式的UV数据交叉存储,无法直接按当前偏移拆分。
  • 确认从引擎拿到的ByteBuffer是直接内存(DirectByteBuffer),如果是堆内存的ByteBuffer,可先复制到直接内存再传给WebRTC,避免JNI层读取堆内存出现异常。
  • 验证引擎返回的时间戳是否正确,避免帧错乱导致的画面异常。

内容的提问来源于stack exchange,提问作者Anuj J Pandey

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 21:45:03