我给你一段代码,你看看能不能帮我优化一下。

2023-04-15by@richyeohx-ax4MO&@ChatGPT.Model: gpt-3.5
richyeohx-ax4MO

我给你一段代码,你看看能不能帮我优化一下。

Avatar
Avatar

很抱歉,我需要看到你的代码才能为你提供优化建议。请将代码复制粘贴到这里,我会尽力帮助你优化。

richyeohx-ax4MO

public static byte[] convertYUV420888ToNV21(Image image) {
byte[] nv21;
ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();
int yRowStride = image.getPlanes()[0].getRowStride();
int uRowStride = image.getPlanes()[1].getRowStride();
int vRowStride = image.getPlanes()[2].getRowStride();
int yPixelStride = image.getPlanes()[0].getPixelStride();
int vPixelStride = image.getPlanes()[2].getPixelStride();

int ySize = yBuffer.remaining();
int uSize = uBuffer.remaining();
int vSize = vBuffer.remaining();

nv21 = new byte[ySize + uSize + vSize];

int nv21Index = 0;
int yIndex = 0;
int uIndex = 0;
int vIndex = 0;

int w = image.getWidth();
int h = image.getHeight();
int halfH = h / 2;
int halfW = w / 2;
int uvRowStride = vRowStride;
int uvPixelStride = vPixelStride;

if (uRowStride != vRowStride || uPixelStride != vPixelStride) {
    // if the resolution is odd, the last pixel column of the U/V plane is dropped
    uvRowStride = (w % 2 == 0 ? uRowStride : uRowStride - 1);
    uvPixelStride = (w % 2 == 0 ? uPixelStride : vPixelStride * 2);
}

for (int i = 0; i < h; i++) {
    int yOffset = i * yRowStride;
    if (i % 2 == 0) {
        int uvOffset = (i >> 1) * uvRowStride;
        for (int j = 0; j < w; j += 2) {
            int uvIndex = uvOffset + j * uvPixelStride;
            nv21[nv21Index++] = yBuffer.get(yIndex + yOffset + j * yPixelStride);
            nv21[nv21Index++] = vBuffer.get(vIndex + uvIndex + vPixelStride);
            nv21[nv21Index++] = uBuffer.get(uIndex + uvIndex + uPixelStride);
            nv21[nv21Index++] = yBuffer.get(yIndex + yOffset + (j + 1) * yPixelStride);
        }
    } else {
        for (int j = 0; j < w; j++) {
            nv21[nv21Index++] = yBuffer.get(yIndex + yOffset + j * yPixelStride);
        }
    }
}

return nv21;

}

Avatar
Avatar

这段代码看起来已经比较简洁了,但仍有一些优化的空间:

  1. 可以将变量声明和初始化合并在一起,减少代码行数。

  2. 可以使用 System.arraycopy() 方法来替代循环,提高效率。

  3. 可以使用多线程或者并行流来加速处理。

以下是一个可能的优化版本:

public static byte[] convertYUV420888ToNV21(Image image) {
    ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
    ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
    ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();
    int yRowStride = image.getPlanes()[0].getRowStride();
    int uRowStride = image.getPlanes()[1].getRowStride();
    int vRowStride = image.getPlanes()[2].getRowStride();
    int yPixelStride = image.getPlanes()[0].getPixelStride();
    int vPixelStride = image.getPlanes()[2].getPixelStride();

    int ySize = yBuffer.remaining();
    int uSize = uBuffer.remaining();
    int vSize = vBuffer.remaining();

    byte[] nv21 = new byte[ySize + uSize + vSize];

    int w = image.getWidth();
    int h = image.getHeight();
    int halfH = h / 2;
    int halfW = w / 2;
    int uvRowStride = vRowStride;
    int uvPixelStride = vPixelStride;

    if (uRowStride != vRowStride || uPixelStride != vPixelStride) {
        uvRowStride = (w % 2 == 0) ? uRowStride : uRowStride - 1;
        uvPixelStride = (w % 2 == 0) ? uPixelStride : vPixelStride * 2;
    }

    int yOffset = 0, uvOffset = 0, nv21Index = 0;
    byte[] yRow = new byte[w * yPixelStride];
    byte[] uvRow = new byte[w * 2];
    for (int i = 0; i < h; i++) {
        yBuffer.position(yOffset);
        yBuffer.get(yRow, 0, Math.min(w * yPixelStride, yRowStride));
        yOffset += yRowStride;

        if (i % 2 == 0) {
            uBuffer.position(uvOffset);
            vBuffer.position(uvOffset);
            uBuffer.get(uvRow, 0, Math.min(w * 2, uvRowStride));
            uvOffset += uvRowStride;

            for (int j = 0; j < w; j += 2) {
                nv21[nv21Index++] = yRow[j * yPixelStride];
                nv21[nv21Index++] = uvRow[j * 2 + vPixelStride];
                nv21[nv21Index++] = uvRow[j * 2 + uPixelStride];
                nv21[nv21Index++] = yRow[(j + 1) * yPixelStride];
            }
        } else {
            for (int j = 0; j < w; j++) {
                nv21[nv21Index++] = yRow[j * yPixelStride];
            }
        }
    }

    return nv21;
}

这个优化版本主要是将循环中的操作改为了数组拷贝和位置操作,同时减少了一些重复代码。

richyeohx-ax4MO

可否能进一步优化呢。

Avatar
Avatar

这个方法已经非常简单了,但还有一些小的优化可以做:

  1. 可以通过使用 direct ByteBuffer 来避免数据拷贝,提高效率。

  2. 可以将循环中的操作写入一个 lambda 表达式,然后使用 parallelStream() 方法来并行处理。

以下是一个进一步优化的版本:

public static byte[] convertYUV420888ToNV21(Image image) {
    ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
    ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
    ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();
    int yRowStride = image.getPlanes()[0].getRowStride();
    int uRowStride = image.getPlanes()[1].getRowStride();
    int vRowStride = image.getPlanes()[2].getRowStride();
    int yPixelStride = image.getPlanes()[0].getPixelStride();
    int vPixelStride = image.getPlanes()[2].getPixelStride();
    int w = image.getWidth();
    int h = image.getHeight();

    byte[] nv21 = new byte[yRowStride * h + (uvRowStride = (w + 1) / 2 * 2) * (h + 1) / 2];

    ByteBuffer yDirectBuffer = ByteBuffer.allocateDirect(yBuffer.remaining());
    yDirectBuffer.put(yBuffer);
    yDirectBuffer.rewind();

    ByteBuffer uDirectBuffer = ByteBuffer.allocateDirect(uBuffer.remaining());
    uDirectBuffer.put(uBuffer);
    uDirectBuffer.rewind();

    ByteBuffer vDirectBuffer = ByteBuffer.allocateDirect(vBuffer.remaining());
    vDirectBuffer.put(vBuffer);
    vDirectBuffer.rewind();

    IntStream.range(0, h).parallel().forEach(i -> {
        int yOffset = i * yRowStride;
        int uvOffset = uvRowStride * (i / 2);
        int nv21Offset = i * yRowStride;

        byte[] yRow = new byte[w * yPixelStride];
        yDirectBuffer.position(yOffset);
        yDirectBuffer.get(yRow, 0, w * yPixelStride);

        byte[] uvRow = new byte[uvRowStride];
        uDirectBuffer.position(uvOffset);
        uDirectBuffer.get(uvRow, 0, uvRowStride);
        vDirectBuffer.position(uvOffset);
        vDirectBuffer.get(uvRow, 1, uvRowStride - 1);

        for (int j = 0; j < w; j += 2) {
            nv21[nv21Offset + j * yPixelStride] = yRow[j * yPixelStride];
            nv21[nv21Offset + (j + 1) * yPixelStride] = yRow[(j + 1) * yPixelStride];
            nv21[nv21Offset + w * yPixelStride + j] = uvRow[j];
            nv21[nv21Offset + w * yPixelStride + j + 1] = uvRow[j + 1];
        }
    });

    return nv21;
}

这个版本使用了 direct ByteBuffer,并且使用了 parallelStream() 方法来并行处理循环,提高了处理效率。

richyeohx-ax4MO

有没有内存使用上的优化建议呢。

Avatar
Avatar

当然,还有一些内存使用上的优化建议:

  1. 可以使用 direct ByteBuffer,并且在使用完之后及时调用 clear() 方法来释放内存。

  2. 可以在循环中使用 byte 数组来避免不必要的内存分配。

  3. 可以将循环中的操作写入一个 lambda 表达式,然后使用 parallel() 方法来并行处理,减少内存占用。

以下是一个内存使用上的优化版本:

public static byte[] convertYUV420888ToNV21(Image image) {
    ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
    ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
    ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();
    int yRowStride = image.getPlanes()[0].getRowStride();
    int uRowStride = image.getPlanes()[1].getRowStride();
    int vRowStride = image.getPlanes()[2].getRowStride();
    int yPixelStride = image.getPlanes()[0].getPixelStride();
    int vPixelStride = image.getPlanes()[2].getPixelStride();
    int w = image.getWidth();
    int h = image.getHeight();

    ByteBuffer nv21Buffer = ByteBuffer.allocateDirect(yRowStride * h + (w + 1) / 2 * 2 * (h + 1) / 2)
            .order(ByteOrder.nativeOrder());

    ByteBuffer yDirectBuffer = ByteBuffer.allocateDirect(yBuffer.remaining())
            .order(ByteOrder.nativeOrder());
    yDirectBuffer.put(yBuffer);
    yDirectBuffer.rewind();

    ByteBuffer uDirectBuffer = ByteBuffer.allocateDirect(uBuffer.remaining())
            .order(ByteOrder.nativeOrder());
    uDirectBuffer.put(uBuffer);
    uDirectBuffer.rewind();

    ByteBuffer vDirectBuffer = ByteBuffer.allocateDirect(vBuffer.remaining())
            .order(ByteOrder.nativeOrder());
    vDirectBuffer.put(vBuffer);
    vDirectBuffer.rewind();

    byte[] yRow = new byte[w * yPixelStride];
    byte[] uvRow = new byte[(w + 1) / 2 * 2];
    IntStream.range(0, h).parallel().forEach(i -> {
        int yOffset = i * yRowStride;
        int uvOffset = (i / 2) * uRowStride;
        int nv21Offset = i * yRowStride;

        yDirectBuffer.position(yOffset);
        yDirectBuffer.get(yRow, 0, w * yPixelStride);

        uDirectBuffer.position(uvOffset);
        uDirectBuffer.get(uvRow, 0, (w + 1) / 2);
        vDirectBuffer.position(uvOffset);
        vDirectBuffer.get(uvRow, 1, (w + 1) / 2 - 1);

        for (int j = 0; j < w; j += 2) {
            nv21Buffer.put(nv21Offset + j * yPixelStride, yRow[j * yPixelStride]);
            nv21Buffer.put(nv21Offset + (j + 1) * yPixelStride, yRow[(j + 1) * yPixelStride]);
            nv21Buffer.put(yRowStride * h + (i / 2) * uvRow.length + j, uvRow[j]);
            nv21Buffer.put(yRowStride * h + (i / 2) * uvRow.length + j + 1, uvRow[j + 1]);
        }
    });

    yDirectBuffer.clear();
    uDirectBuffer.clear();
    vDirectBuffer.clear();

    byte[] nv21 = new byte[nv21Buffer.remaining()];
    nv21Buffer.rewind();
    nv21Buffer.get(nv21);
    nv21Buffer.clear();

    return nv21;
}

这个版本使用了 direct ByteBuffer 并及时调用了 clear() 方法来释放内存,同时在循环中使用了 byte 数组来减少内存分配。此外,使用 parallel() 方法来并行处理循环,减少内存占用。

richyeohx-ax4MO

内存分配和释放呢。

Avatar