1. Да.Чтобы понять, почему, давайте взглянем на байт-код, который Android Studio создает для вашего вложенного цикла «влево / вправо от центра»:
(аннотированная выдержка из сборки выпуска blackNonROI
, AS 3.2.1):
:goto_27
sub-int v2, p2, p4 ;for(int y=verMargin; y<height-verMargin; y++)
if-ge v1, v2, :cond_45
const/4 v2, 0x0
:goto_2c
if-ge v2, p3, :cond_36 ;for (int x = 0; x < hozMargin; x++)
mul-int v3, v1, p1
add-int/2addr v3, v2
.line 759
aput-byte v0, p0, v3
add-int/lit8 v2, v2, 0x1
goto :goto_2c
:cond_36
sub-int v2, p1, p3
:goto_38
if-ge v2, p1, :cond_42 ;for (int x = width-hozMargin; x < width; x++)
mul-int v3, v1, p1
add-int/2addr v3, v2
.line 761
aput-byte v0, p0, v3
add-int/lit8 v2, v2, 0x1
goto :goto_38
:cond_42
add-int/lit8 v1, v1, 0x1
goto :goto_27
.line 764
:cond_45 ;all done with the for loops!
Не потрудившись расшифровать всю эту вещь построчно, ясно, что каждый из ваших маленьких внутренних циклов выполняет:
- 1 сравнение
- 1 целочисленное умножение
- 1 сложение
- 1 магазин
- 1 goto
Это много, если учесть, что все, что выдействительно нужно, чтобы этот внутренний цикл устанавливал определенное количество последовательных элементов массива на 0.
Более того, некоторые из этих байт-кодов требуют реализации нескольких машинных инструкций, поэтому я не удивлюсь, если вы ищетев течение более 20 циклов, просто чтобы сделать одну итерацию одного из внутренних циклов.(Я не проверял, как выглядит этот код после его компиляции виртуальной машиной Dalvik, но я искренне сомневаюсь, что он достаточно умен, чтобы оптимизировать умножения из этих циклов.)
ВОЗМОЖНЫЕ ИСПРАВЛЕНИЯ
Вы можете улучшить производительность, исключив некоторые избыточные вычисления.Например, каждый внутренний цикл пересчитывает y * width
каждый раз .Вместо этого вы можете предварительно рассчитать это смещение, сохранить его в локальной переменной (во внешнем цикле) и использовать его при расчете индексов.
Когда производительность абсолютно критична, я иногда буду делать такого родаманипулирование буфером в нативном коде.Если вы можете быть достаточно уверены, что mPendingFrameData
является DirectByteBuffer
, это еще более привлекательный вариант.Недостатки: 1.) более высокая сложность и 2.) меньшая «сетка безопасности», если что-то пойдет не так / вылетит.
САМОЕ СООТВЕТСТВУЮЩЕЕ ИСПРАВЛЕНИЕ
В этом случае наиболее подходящим решением, вероятно, является просто использование Arrays.fill()
, которое, скорее всего, будет реализовано оптимизированным способом.
Обратите внимание, что верхний и нижний блоки представляют собой большие непрерывные куски памяти и могутобрабатывается по одному Arrays.fill()
каждому:
Arrays.fill(yuvData, 0, verMargin * width, 0); //top
Arrays.fill(yuvData, width * height - verMargin * width, width * height, 0); //bottom
И тогда стороны могут обрабатываться примерно так:
for(int y=verMargin; y<height-verMargin; y++){
int offset = y * width;
Arrays.fill(yuvData, offset, offset + hozMargin, 0); //left
Arrays.fill(yuvData, offset + width, offset + width - hozMargin, 0); //right
}
Здесь есть больше возможностей для оптимизации, но мыуже на грани убывающей отдачи.Например, поскольку конец каждой строки смежен с началом следующей (в памяти), вы можете фактически объединить два меньших вызова fill()
в один больший, который охватывает как правую часть строки N, так и левую.сторона ряда N + 1. И пр.
2. Не уверен.Если ваш предварительный просмотр отображается без каких-либо повреждений / разрывов, то это, вероятно, безопасное место для вызова функции (с точки зрения безопасности потока), и поэтому оно, вероятно, такое же хорошее место, как и любое другое.
3 и 4. Могут быть библиотеки для выполнения этой задачи;Я не знаю ничего лишнего, для основанных на Java фреймов NV21.Вы должны будете сделать некоторые преобразования формата, и я не думаю, что это того стоит.Использование графического процессора для выполнения этой работы, на мой взгляд, является чрезмерной чрезмерной оптимизацией, но может быть целесообразным для некоторых специализированных приложений.Я хотел бы подумать о переходе на JNI (собственный код), прежде чем когда-либо подумать об использовании графического процессора.
Я думаю, что ваш выбор - выполнять манипуляции непосредственно с NV21 вместо преобразования в растровое изображение - это хорошийодин (учитывая ваши потребности и тот факт, что задача достаточно проста, чтобы избежать необходимости в графической библиотеке).