ОК, есть несколько способов сделать это.Но есть существенная проблема с производительностью.Байт [] от камеры имеет формат YUV , который должен быть преобразован в некоторый формат RGB, если вы хотите отобразить его.Это преобразование является довольно дорогой операцией и значительно снижает выходную частоту кадров.
Это зависит от того, что вы на самом деле хотите сделать с предварительным просмотром камеры.Потому что лучшее решение - нарисовать предварительный просмотр камеры без обратного вызова и сделать некоторые эффекты поверх предварительного просмотра камеры.Это обычный способ делать аргументированную реальность.
Но если вам действительно нужно отображать вывод вручную, есть несколько способов сделать это.Ваш пример не работает по нескольким причинам.Во-первых, вы вообще не отображаете изображение.Если вы называете это:
mCamera.setPreviewCallback(new CameraGreenFilter());
mCamera.setPreviewDisplay(null);
, то ваша камера вообще не отображает предварительный просмотр, вы должны отобразить его вручную.И вы не можете выполнять дорогостоящие операции в методе onPreviewFrame, поскольку время жизни данных ограничено, они перезаписываются в следующем кадре.Один совет, используйте setPreviewCallbackWithBuffer , это быстрее, потому что он использует один буфер и не должен выделять новую память в каждом кадре.
Итак, вы должны сделать что-то вроде этого:
private byte[] cameraFrame;
private byte[] buffer;
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
cameraFrame = data;
addCallbackBuffer(data); //actually, addCallbackBuffer(buffer) has to be called once sowhere before you call mCamera.startPreview();
}
private ByteOutputStream baos;
private YuvImage yuvimage;
private byte[] jdata;
private Bitmap bmp;
private Paint paint;
@Override //from SurfaceView
public void onDraw(Canvas canvas) {
baos = new ByteOutputStream();
yuvimage=new YuvImage(cameraFrame, ImageFormat.NV21, prevX, prevY, null);
yuvimage.compressToJpeg(new Rect(0, 0, width, height), 80, baos); //width and height of the screen
jdata = baos.toByteArray();
bmp = BitmapFactory.decodeByteArray(jdata, 0, jdata.length);
canvas.drawBitmap(bmp , 0, 0, paint);
invalidate(); //to call ondraw again
}
Чтобы сделать эту работу, вам нужно вызвать setWillNotDraw (false) в конструкторе класса или где-то еще.
В onDraw вы можете, например, применить paint.setColorFilter (filter) , если вы хотите изменить цвета.Я могу опубликовать некоторый пример этого, если хотите.
Так что это будет работать, но производительность будет низкой (менее 8 кадров в секунду), потому что BitmapFactory.decodeByteArray работает медленно.Вы можете попытаться преобразовать данные из YUV в RGB с помощью собственного кода и Android NDK, но это довольно сложно.
Другой вариант - использовать openGL ES.Вам нужен GLSurfaceView, где вы привязываете кадр камеры как текстуру (в GLSurfaceView реализует Camera.previewCallback, поэтому вы используете onPreviewFrame так же, как и на обычной поверхности).Но есть та же проблема, вам нужно конвертировать данные YUV.Есть один шанс - вы можете отображать только данные яркости из предварительного просмотра (изображение в оттенках серого) довольно быстро, потому что первая половина байтового массива в YUV - это только данные яркости без цветов.Поэтому в onPreviewFrame вы используете arraycopy для копирования первой половины массива, а затем привязываете текстуру следующим образом:
gl.glGenTextures(1, cameraTexture, 0);
int tex = cameraTexture[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, tex);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_LUMINANCE,
this.prevX, this.prevY, 0, GL10.GL_LUMINANCE,
GL10.GL_UNSIGNED_BYTE, ByteBuffer.wrap(this.cameraFrame)); //cameraFrame is the first half od byte[] from onPreviewFrame
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
Таким образом, вы не можете получить 16-18 кадров в секунду, и вы можете использовать openGL, чтобы сделатьнекоторые фильтры.Я могу прислать вам еще немного кода, если вы хотите, но это слишком долго, чтобы вставить сюда ...
Для получения дополнительной информации, вы можете увидеть мой simillar вопрос , но тамтоже не хорошее решение ...