1 功能需求
(1)手机端打开摄像头实时预览;
(2)手机端作为服务端,PC端作为客户端连接;
(3)连接成功后PC端可以同时预览手机端的摄像头采集的图像;
(4)PC端点击拍照可以控制手机端拍摄一张照片,并将照片传给PC端。
2 功能模块
(1)安卓手机打开摄像头并实现预览和拍照功能;
(2)手机端开启监听,并在连接成功后将摄像头采集的数据传给PC;
(3)手机端读取PC发送的命令指令,执行相应的操作。
3 开发流程
3.1 开启摄像头实现预览
(1) 获取摄像头权限,并添加自动对焦属性。
在应用程序的manifest.xml文件中添加使用手机摄像头权限。由于程序需要使用socket的通信过程,将手机作为服务端,因此需要添加网络权限。
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission Android:name="android.permission.INTERNET"/>
2)实现相机的实时预览。
安卓系统使用SurfaceView即可完成预览功能。在布局文件中添加SurfaceView。activity_main.xml布局文件如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/gray_light"
android:orientation="vertical" >
<SurfaceView
android:id="@+id/surview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitCenter" />
</LinearLayout>
(3)在MainActivity 的onCreate中初始化SurfceView。初始化方法如下:
private void initSurfaceView() {
surfaceView = (SurfaceView) findViewById(R.id.surview);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceHolder.setKeepScreenOn(true);
surfaceHolder.addCallback(new Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
// 开启摄像头
startCamera(curCameraIndex);
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
}
});
surfaceView.setFocusable(true);
surfaceView.setBackgroundColor(TRIM_MEMORY_BACKGROUND);
}
4)SurfceView创建完成时调用开启摄像头的方法startCamera()。startCamera方法如下,其中代码含义已在注释程序中注明。
// 根据索引初始化摄像头
@SuppressLint("NewApi")
public void startCamera(int cameraIndex) {
// 先停止摄像头
stopCamera();
// 再初始化并打开摄像头
if (camera == null) {
//打开手机摄像头,cameraIndex为摄像头索引,0代表后置摄像头,1代表前置摄像头。
camera = Camera.open(cameraIndex);
//创建摄像头操作工具类
cameraUtil = new CameraUtil(camera, callback);
//开启预览
cameraUtil.initCamera(srcFrameHeight, srcFrameWidth, surfaceHolder);
Log.e(TAG, "打开相机");
}
}
// 停止并释放摄像头
public void stopCamera() {
if (camera != null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera = null;
}
}
//摄像头开启预览后采集到的数据回调接口
PreviewCallback callback = new PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Size size = camera.getParameters().getPreviewSize();
try {
if (times == 0) {
YuvImage image = new YuvImage(data, ImageFormat.NV21,
size.width, size.height, null);
if (image != null) {
// 将YuvImage对象转为字节数组
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, size.width,
size.height), 100, outputStream);
byte[] srcData = outputStream.toByteArray();
int len = srcData.length;
// 字节数组转为Bitmap
Bitmap src = BitmapFactory.decodeByteArray(srcData, 0,
len);
src = BitmapUtil.rotate(src, 90);
// 压缩Bitmap,并获取压缩后的字节数组,即可获取预览数据文件
// outdata数据即是待发送给PC端的数据
byte[] outdata = BitmapUtil.transImage(src,
srcFrameWidth / 4, srcFrameHeight / 4);
int datalen = outdata.length;
if (isOpen) {
// 写入头
sendData(new byte[] {
(byte) 0xA0 });
// 写入数组长度
sendData(intToByteArray(datalen));
// 写入数据值
sendData(outdata);
}
// 回收Bitmap
if (!src.isRecycled()) {
src.recycle();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
(5)CameraUtil为设置摄像头的辅助类,代码如下:
public class CameraUtil {
//摄像头类
Camera camera;
int cameraIndex;
//预览视图宽和高
int srcFrameWidth;
int srcFrameHeight;
SurfaceHolder surfaceHolder;
PreviewCallback callback;
public CameraUtil(Camera camera, PreviewCallback callback) {
this.camera = camera;
this.callback = callback;
}
//摄像头预览初始化
public void initCamera(final int srcFrameWidth, final int srcFrameHeight, final SurfaceHolder surfaceHolder) {
this.srcFrameHeight = srcFrameHeight;
this.srcFrameWidth = srcFrameWidth;
this.surfaceHolder = surfaceHolder;
Camera.Parameters params = camera.getParameters();
//params.setPreviewSize(srcFrameWidth / 4, srcFrameHeight / 4);
//设置预览格式
params.setPreviewFormat(ImageFormat.NV21);
params.setPreviewFrameRate(30);
//设置图像质量
params.setJpegQuality(100);
params.setPictureFormat(ImageFormat.JPEG);
//设置预览方向
params.set("orientation", "portrait");
params.set("rotation", 90);
//设置对焦模式为自动连续对焦
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 1连续对焦
camera.setParameters(params);
camera.setDisplayOrientation(90);
// 设置显示图像的SurfaceView
try {
camera.setPreviewDisplay<