Я пишу некоторый код для рендеринга камеры с помощью 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 и определения размера предварительного просмотра, чтобы сделать его быстрее.