Я провел некоторое исследование по этому вопросу и собрал рабочий (ish) пример.Вот что я нашел.Получить исходные данные с камеры довольно просто.Он возвращается как байтовый массив YUV.Вам нужно будет нарисовать его вручную на поверхности, чтобы иметь возможность изменить его.Для этого вам понадобится SurfaceView, с которым вы можете вручную запускать вызовы отрисовки.Для этого можно установить несколько флагов.
Для того, чтобы выполнить вызов отрисовки вручную, вам необходимо преобразовать массив байтов в какое-то растровое изображение.На этом этапе битовые карты и BitmapDecoder не очень хорошо обрабатывают байтовый массив YUV.Для этого была подана ошибка, но не надо знать, какой у нее статус.Поэтому люди пытаются самостоятельно декодировать байтовый массив в формат RGB.
Похоже, что ручное декодирование было довольно медленным, и люди имели разные степени успеха с ним.Нечто подобное должно, вероятно, действительно быть сделано с нативным кодом на уровне NDK.
Тем не менее, можно заставить его работать.Кроме того, моя небольшая демонстрация - это только то, как я провожу пару часов вместе, занимаясь хакерством (думаю, это слишком сильно поразило мое воображение;)).Таким образом, есть вероятность, что с некоторыми изменениями вы сможете значительно улучшить то, что мне удалось получить.
Этот небольшой фрагмент кода содержит пару других драгоценных камней, которые я также нашел.Если все, что вам нужно - это рисовать поверх поверхности, вы можете переопределить функцию onDraw поверхности - вы могли бы потенциально проанализировать возвращенное изображение с камеры и нарисовать наложение - это было бы намного быстрее, чем пытаться обрабатывать каждый кадр.Кроме того, я изменил SurfaceHolder.SURFACE_TYPE_NORMAL от того, что было бы необходимо, если вы хотите, чтобы отображался предварительный просмотр камеры.Итак, пара изменений в коде - закомментированный код:
//try { mCamera.setPreviewDisplay(holder); } catch (IOException e)
// { Log.e("Camera", "mCamera.setPreviewDisplay(holder);"); }
И:
SurfaceHolder.SURFACE_TYPE_NORMAL //SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS - for preview to work
Должно позволять накладывать кадры на основе предварительного просмотра камеры поверхреальный предварительный просмотр.
В любом случае, вот рабочий фрагмент кода. Должен дать вам кое-что для начала.
Просто поместите строку кода в один из ваших видов, например:
<pathtocustomview.MySurfaceView android:id="@+id/surface_camera"
android:layout_width="fill_parent" android:layout_height="10dip"
android:layout_weight="1">
</pathtocustomview.MySurfaceView>
И включите этот класс в ваш источник где-нибудь:
package pathtocustomview;
import java.io.IOException;
import java.nio.Buffer;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
public class MySurfaceView extends SurfaceView implements Callback,
Camera.PreviewCallback {
private SurfaceHolder mHolder;
private Camera mCamera;
private boolean isPreviewRunning = false;
private byte [] rgbbuffer = new byte[256 * 256];
private int [] rgbints = new int[256 * 256];
protected final Paint rectanglePaint = new Paint();
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
rectanglePaint.setARGB(100, 200, 0, 0);
rectanglePaint.setStyle(Paint.Style.FILL);
rectanglePaint.setStrokeWidth(2);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(new Rect((int) Math.random() * 100,
(int) Math.random() * 100, 200, 200), rectanglePaint);
Log.w(this.getClass().getName(), "On Draw Called");
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
synchronized (this) {
this.setWillNotDraw(false); // This allows us to make our own draw
// calls to this canvas
mCamera = Camera.open();
Camera.Parameters p = mCamera.getParameters();
p.setPreviewSize(240, 160);
mCamera.setParameters(p);
//try { mCamera.setPreviewDisplay(holder); } catch (IOException e)
// { Log.e("Camera", "mCamera.setPreviewDisplay(holder);"); }
mCamera.startPreview();
mCamera.setPreviewCallback(this);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
synchronized (this) {
try {
if (mCamera != null) {
mCamera.stopPreview();
isPreviewRunning = false;
mCamera.release();
}
} catch (Exception e) {
Log.e("Camera", e.getMessage());
}
}
}
public void onPreviewFrame(byte[] data, Camera camera) {
Log.d("Camera", "Got a camera frame");
Canvas c = null;
if(mHolder == null){
return;
}
try {
synchronized (mHolder) {
c = mHolder.lockCanvas(null);
// Do your drawing here
// So this data value you're getting back is formatted in YUV format and you can't do much
// with it until you convert it to rgb
int bwCounter=0;
int yuvsCounter=0;
for (int y=0;y<160;y++) {
System.arraycopy(data, yuvsCounter, rgbbuffer, bwCounter, 240);
yuvsCounter=yuvsCounter+240;
bwCounter=bwCounter+256;
}
for(int i = 0; i < rgbints.length; i++){
rgbints[i] = (int)rgbbuffer[i];
}
//decodeYUV(rgbbuffer, data, 100, 100);
c.drawBitmap(rgbints, 0, 256, 0, 0, 256, 256, false, new Paint());
Log.d("SOMETHING", "Got Bitmap");
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mHolder.unlockCanvasAndPost(c);
}
}
}
}