/**
* 打开相机 如果只有一个UsbDevice就不用加设备判断
*/
fun open(activity: Activity, surfaceView: AspectRatioSurfaceView) {
mActivity = activity
try {
mCameraHelper = CameraHelper()
//UVC摄像头状态回调
mStateListener = object : ICameraHelper.StateCallback {
//插入UVC设备
override fun onAttach(device: UsbDevice) {
//设置为当前设备(如果没有权限,会显示授权对话框)
if (mUsbDevice != null && device == mUsbDevice) {
mCameraHelper?.selectDevice(device)
}
}
//打开UVC设备成功(也就是已经获取到UVC设备的权限)
override fun onDeviceOpen(device: UsbDevice, isFirstOpen: Boolean) {
//打开UVC摄像头
if (mUsbDevice != null && device == mUsbDevice) {
mCameraHelper?.openCamera()
}
}
//打开摄像头成功
override fun onCameraOpen(device: UsbDevice) {
if (mUsbDevice != null && device == mUsbDevice) {
//开始预览
mCameraHelper?.startPreview()
// //需要自适应摄像头分辨率的话,设置新的宽高比
// surfaceView.setAspectRatio(640, 480)
//获取预览使用的Size(包括帧格式、宽度、高度、FPS)
val size = mCameraHelper?.getPreviewSize()
if (size != null) {
val width = size.width
val height = size.height
//需要自适应摄像头分辨率的话,设置新的宽高比
surfaceView.setAspectRatio(width, height)
}
//添加预览Surface
mCameraHelper?.addSurface(surfaceView.holder.surface, false)
mCameraHelper?.setFrameCallback(IFrameCallback {
var mFrame = bytebuffer2ByteArray(it)
//这是成像代码。可以在需要的地方调用
nv21ToBitmap(activity,mFrame,width,height)
//如果是YUV格式请看最下面的一个java方法,参数为PIXEL_FORMAT_YUV
}, UVCCamera.PIXEL_FORMAT_NV21)
}
}
//关闭摄像头成功
override fun onCameraClose(device: UsbDevice) {
//移除预览Surface 已经在surfaceView的surfaceDestroyed方法里调用过了
//官方的案例这里会再次removeSurface导致了再次打开相机会出现异常
}
//关闭UVC设备成功
override fun onDeviceClose(device: UsbDevice) {
Timber.d("USB相机关闭成功")
}
//断开UVC设备
override fun onDetach(device: UsbDevice) {
Timber.d("USB相机断开连接:${device.productName}")
}
//用户没有授予访问UVC设备的权限
override fun onCancel(device: UsbDevice) {}
}
//设置SurfaceView的Surface监听回调
surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
//创建了新的Surface
override fun surfaceCreated(holder: SurfaceHolder) {
//添加预览Surface
mCameraHelper?.addSurface(holder.surface, false)
}
//Surface发生了改变
override fun surfaceChanged(
holder: SurfaceHolder,
format: Int,
width: Int,
height: Int
) {
}
//销毁了原来的Surface
override fun surfaceDestroyed(holder: SurfaceHolder) {
//移除预览Surface
try {
mCameraHelper?.removeSurface(holder.surface)
} catch (_: Exception) {
}
}
})
//设置UVC摄像头状态回调
mCameraHelper?.setStateCallback(mStateListener)
} catch (e: Exception) {
//普通相机通信异常
}
}
fun bytebuffer2ByteArray(buffer: ByteBuffer): ByteArray? {
//重置 limit 和postion 值
// buffer.flip();
//获取buffer中有效大小
val len: Int = buffer.limit() - buffer.position()
val bytes = ByteArray(len)
for (i in bytes.indices) {
bytes[i] = buffer.get()
}
return bytes
}
//2毫秒左右转换完成
fun nv21ToBitmap(context: Context, nv21: ByteArray, width: Int, height: Int): Bitmap? {
val rs = RenderScript.create(context)
val yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs))
var yuvType: Type.Builder? = null
yuvType = Type.Builder(rs, Element.U8(rs)).setX(nv21.size)
val `in` = Allocation.createTyped(rs, yuvType.create(), 1)
val rgbaType = Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height)
val out = Allocation.createTyped(rs, rgbaType.create(), 1)
`in`.copyFrom(nv21)
yuvToRgbIntrinsic.setInput(`in`)
yuvToRgbIntrinsic.forEach(out)
val bmpout = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
out.copyTo(bmpout)
return bmpout
}
public Bitmap yuv2Bmp(byte[] data, int width, int height) {
ByteArrayOutputStream baos;
byte[] rawImage;
Bitmap bitmap;
BitmapFactory.Options newOpts = new BitmapFactory.Options();
newOpts.inJustDecodeBounds = true;
YuvImage yuvimage = new YuvImage(
data,
ImageFormat.NV21,
width,
height,
null);
baos = new ByteArrayOutputStream();
yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, baos);
rawImage = baos.toByteArray();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
bitmap = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length, options);
return bitmap;
}
以上注意setFrameCallback只能在startPreview、addSurface之后调用,不按顺序调用就接受不到回调!