Как ускорить конверсию YUV для быстрого предварительного просмотра камеры SkiaSharp? - PullRequest
0 голосов
/ 25 января 2019

Я пишу некоторый код для рендеринга камеры с помощью SkiaSharp.Это кросс-платформенный, но я столкнулся с проблемой при написании реализации для Android.

Мне нужно было конвертировать YUV_420_888 в RGB8888, потому что это то, что поддерживает SkiaSharp и с помощью этот поток ,Каким-то образом удалось показать изображения достойного качества на моем холсте SkiaSharp.Проблема в скорости.В лучшем случае я могу получить около 8 кадров в секунду, но обычно это всего 4 или 5 кадров в секунду.Оказалось, что самым большим фактором является конверсия.Теперь у меня есть около 3 версий моего конвертера ToRGB.Я даже закончил тем, что попробовал "небезопасный" код и параллельные циклы.Я покажу вам только мой лучший.

private unsafe byte[] ToRgb(byte[] yValuesArr, byte[] uValuesArr,
        byte[] vValuesArr, int uvPixelStride, int uvRowStride)
    {
        var width = PixelSize.Width;
        var height = PixelSize.Height;
        var rgb = new byte[width * height * 4];

        var partitions = Partitioner.Create(0, height);
        Parallel.ForEach(partitions, range =>
        {
            var (item1, item2) = range;
            Parallel.For(item1, item2, y =>
            {
                for (var x = 0; x < width; x++)
                {
                    var yIndex = x + width * y;
                    var currentPosition = yIndex * 4;
                    var uvIndex = uvPixelStride * (x / 2) + uvRowStride * (y / 2);

                    fixed (byte* rgbFixed = rgb)
                    fixed (byte* yValuesFixed = yValuesArr)
                    fixed (byte* uValuesFixed = uValuesArr)
                    fixed (byte* vValuesFixed = vValuesArr)
                    {
                        var rgbPtr = rgbFixed;
                        var yValues = yValuesFixed;
                        var uValues = uValuesFixed;
                        var vValues = vValuesFixed;

                        var yy = *(yValues + yIndex);
                        var uu = *(uValues + uvIndex);
                        var vv = *(vValues + uvIndex);

                        var rTmp = yy + vv * 1436 / 1024 - 179;
                        var gTmp = yy - uu * 46549 / 131072 + 44 - vv * 93604 / 131072 + 91;
                        var bTmp = yy + uu * 1814 / 1024 - 227;

                        rgbPtr = rgbPtr + currentPosition;
                        *rgbPtr = (byte) (rTmp < 0 ? 0 : rTmp > 255 ? 255 : rTmp);
                        rgbPtr++;

                        *rgbPtr = (byte) (gTmp < 0 ? 0 : gTmp > 255 ? 255 : gTmp);
                        rgbPtr++;

                        *rgbPtr = (byte) (bTmp < 0 ? 0 : bTmp > 255 ? 255 : bTmp);
                        rgbPtr++;

                        *rgbPtr = 255;
                    }
                }
            });
        });

        return rgb;
}

Вы также можете найти его в моем репо .Вы можете также найти в этом же репо ту часть, где Я отрисовал вывод в SkiaSharp

Для размера предварительного просмотра 1440x1080, работающего на моем телефоне, этот код занимает около 120 мс для завершения.Даже если все остальные части оптимизированы, максимум, что я могу получить, это 8fps.И нет, это не мое оборудование, потому что встроенная камера работает без сбоев.Кстати, 1440x1080 - это результат моего ChooseOptimalSize алгоритма, который я получил из примеров монодроидов API-интерфейса Camera2 для Android.Я не знаю, является ли это лучшим способом или ему не хватает логики для определения fps и определения размера предварительного просмотра, чтобы сделать его быстрее.

1 Ответ

0 голосов
/ 26 января 2019

SkiaSharp поддерживает отрисовку графического процессора? Если вы подключите камеру к SurfaceTexture, вы можете использовать кадры предварительного просмотра в качестве текстур GL и эффективно визуализировать их в сцену OpenGL.

Даже если нет, вы все равно можете получить более быстрые результаты, отправляя кадры в GPU и считывая их обратно в CPU с помощью чего-то вроде glReadPixels, поскольку это будет выполнять преобразование RGB внутри GPU.

...