Как конвертировать YUV_420_888 в YUV422 (UYVY) - PullRequest
0 голосов
/ 28 марта 2019

Как вы знаете, мы можем получить изображение из Android Camera2 API (ImageReader.OnImageAvailableListener), и формат изображения - YUV_420_888, и мне нужно преобразовать формат в YUV422 (UYVY).

Информация оизображение с моей камеры.

получить данные с 3-х плоскостей

pixelStride 1
rowStride 720
width 720
height 480
buffer size 345600

Завершено считывание данных с плоскости 0

pixelStride 2
rowStride 720
width 720
height 480
buffer size 172799

Завершено считывание данных с плоскости 1

pixelStride 2
rowStride 720
width 720
height 480
buffer size 172799

Завершено чтение данных из плоскости 2

Моя функция преобразования выглядит следующим образом:

private static byte[] getDataFromImage(Image image, int colorFormat) {
    if (colorFormat != COLOR_FormatI420 && colorFormat != COLOR_FormatNV21 && colorFormat != COLOR_FormatYUYV422_UYVY) {
        throw new IllegalArgumentException("only support COLOR_FormatI420 " + "and COLOR_FormatNV21"  + "and COLOR_FormatYUYV422_UYVY");
    }
    if (!isImageFormatSupported(image)) {
        throw new RuntimeException("can't convert Image to byte array, format " + image.getFormat());
    }
    Rect crop = image.getCropRect();
    int format = image.getFormat();
    int width = crop.width();
    int height = crop.height();
    Image.Plane[] planes = image.getPlanes();
    byte[] data = new byte[width * height * 2];
    byte[] rowData = new byte[planes[0].getRowStride()];
    Log.e(TAG, "get data from " + planes.length + " planes" + "format is " + format);
    int channelOffset = 0;
    int outputStride = 1;
    for (int i = 0; i < planes.length; i++) {
        switch (i) {
            case 0:
                if(false) {
                    channelOffset = 0;
                    outputStride = 1;
                } else { //for YUV422 UYVY
                    channelOffset = 1;
                    outputStride = 2;
                }
                break;
            case 1:
                if (colorFormat == COLOR_FormatI420) {
                    channelOffset = width * height;
                    outputStride = 1;
                } else if (colorFormat == COLOR_FormatNV21) {
                    channelOffset = width * height + 1;
                    outputStride = 2;
                } else { //for YUV422 UYVY
                    channelOffset = 0;
                    outputStride = 4;
                }
                break;
            case 2:
                if (colorFormat == COLOR_FormatI420) {
                    channelOffset = (int) (width * height * 1.25);
                    outputStride = 1;
                } else if (colorFormat == COLOR_FormatNV21) {
                    channelOffset = width * height;
                    outputStride = 2;
                } else { //for YUV422 UYVY
                    channelOffset = 2;
                    outputStride = 4;
                }
                break;
        }
        ByteBuffer buffer = planes[i].getBuffer();
        int rowStride = planes[i].getRowStride();
        int pixelStride = planes[i].getPixelStride();
        Log.e(TAG, "pixelStride " + pixelStride);
        Log.e(TAG, "rowStride " + rowStride);
        Log.e(TAG, "width " + width);
        Log.e(TAG, "height " + height);
        Log.e(TAG, "buffer size " + buffer.remaining());
        int shift = (i == 0) ? 0 : 1;
        int w = width; // >> shift;
        int h = height;// >> shift;
        buffer.position(rowStride * (crop.top >> shift) + pixelStride * (crop.left >> shift));
        Log.e(TAG, "buffer position " + buffer.position());
        for (int row = 0; row < h; row++) {
            int length;
            if (pixelStride == 1 && outputStride == 1) {
                length = w;
                buffer.get(data, channelOffset, length);
                channelOffset += length;
            } else {
                if (i == 0) {
                    length = w;
                    buffer.get(rowData, 0, length);
                } else {
                    if(row == h - 2) {
                        length = w - 1;
                    } else {
                        length = w;
                    }
                    if( row % 2 == 0) {
                       // Log.e(TAG, "row is " + row + "length " + length);
                        buffer.get(rowData, 0, length);
                    }
                }

                if(colorFormat != COLOR_FormatYUYV422_UYVY) {
                    for (int col = 0; col < w; col++) {
                        data[channelOffset] = rowData[col * pixelStride];
                        channelOffset += outputStride;
                    }
                } else {
                    if(i == 0) {
                        for (int col = 0; col < w; col++) {
                            data[channelOffset] = rowData[col * pixelStride];
                            channelOffset += outputStride;
                        }
                    } else {
                        for (int col = 0; col < w-1;) {
                            data[channelOffset] = rowData[col];
                            col = col + 2;
                            channelOffset += outputStride;
                        }
                    }
                }
            }
//                if (row < h - 1) {
//                    buffer.position(buffer.position() + rowStride - length);
//                }
        }
        Log.e(TAG, "Finished reading data from plane " + i);
    }
    Log.e(TAG, "data length is " + data.length);
    return data;
}

Когда я устанавливаю второй параметр colorFormat в качестве COLOR_FormatYUYV422_UYVY, функция getDataFromImage является ответом на преобразование.От YUV420_888 до YUV422_UYVY.Однако цвет изображения не правильный.Кто может просмотреть функцию getDataFromImage для преобразования (YUV420_888-> YUV422 (UYVY))?

...