第一部分:
由于Android下摄像头预览数据只能 ImageFormat.NV21 格式的,所以解码时要经过一翻周折.
Camera mCamera = Camera.open();
Camera.Parameters p = mCamera.getParameters();
p.setPreviewFormat(ImageFormat.NV21);
mCamera.setParameters(p);
mCamera.startPreview();
下面是解码核心部分:
@Override
publicvoidonPreviewFrame(byte[] data, Camera camera) {
Size size = camera.getParameters().getPreviewSize();
try{
YuvImage image = newYuvImage(data, ImageFormat.NV21, size.width, size.height,null);
if(image!=null){
ByteArrayOutputStream stream = newByteArrayOutputStream();
image.compressToJpeg(newRect(0,0, size.width, size.height),80, stream);
Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
stream.close();
}
}catch(Exception ex){
Log.e("Sys","Error:"+ex.getMessage());
}
}
代码很简单。就是把YUV数据转成 Bitmap 就行了,系统提供
YuvImage 类。
第二部分:
原理是利用手机的摄像头取景,然后解码视频流
拆分成位图,然后对位图进行处理和识别
要在android手机里面捕获视频流
当然,手机必须得有摄像头
然后嘛,第一步是在AndroidManifest.xml加入如下权限声明
<permission android:name="android.permission.CAMERA">permission>
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
摄像头的预览和捕获只能通过surfaceview..
而且他的工作模式必须是SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS
不然不能在surfaceview里面显示出预览的图像
然后在surfaceCreated方法里面加入我们的摄像头初始化
public void surfaceCreated(SurfaceHolder arg0) {
//启动相机服务
mCamera = Camera.open();
Log.i("Camera", "surface open");
try {
//设置预览 这个holder是 SurfaceView的getHolder()方法得到的
mCamera.setPreviewDisplay(holder);
Camera.Parameters parameters = mCamera.getParameters();
//设置图片格式
parameters.setPictureFormat(PixelFormat.JPEG);
//设置预览的帧数,受硬件影响.
parameters.setPreviewFrameRate(10);
//设置尺寸
parameters.setPreviewSize(preV.getWidth(), preV.getHeight());
mCamera.setParameters(parameters);
//设置回调的类
mCamera.setPreviewCallback(new ViewCallback(preV, this));
//开始预览
mCamera.startPreview();
} catch (Exception e) {
//释放相机
mCamera.release();
mCamera = null;
return;
}
}
然后看看我们的ViewCallback类
在这个类里面要实现PreviewCallback
主要是里面的 public void onPreviewFrame(byte[] data, Camera arg1)
{}
data就是返回的数据流了, 不过麻烦的是这个流并不是rgb编码的,是YUV420SP编码的,
Camera.Parameters
里面有个setPreviewFormat() 这个虽然可以设置
但是具体能不能编码成JPEG是受你的手机影响的
其中的data是yuv格式的,需要对其解码:
static public void decodeYUV420SP(byte[]
rgbBuf, byte[] yuv420sp, int width, int height) {
final int
frameSize = width * height;
if (rgbBuf
== null)
throw new
NullPointerException("buffer 'rgbBuf' is null");
if
(rgbBuf.length < frameSize * 3)
throw new
IllegalArgumentException("buffer 'rgbBuf' size "
+ rgbBuf.length + " < minimum " + frameSize * 3);
if (yuv420sp
== null)
throw new NullPointerException("buffer
'yuv420sp' is null");
if
(yuv420sp.length < frameSize * 3 / 2)
throw new
IllegalArgumentException("buffer 'yuv420sp' size " +
yuv420sp.length
+ " < minimum " + frameSize * 3 / 2);
int i = 0, y = 0;
int uvp = 0, u = 0, v = 0;
int y1192 = 0, r = 0, g = 0, b = 0;
for (int j = 0, yp = 0; j < height; j++) {
uvp = frameSize + (j >> 1) * width;
u = 0;
v = 0;
for (i = 0; i < width; i++, yp++) {
y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
y1192 = 1192 * y;