最近公司在VOIP视频上传的功能里加视频截图的功能。下面我来介绍一下我的实现思路和实现过程。
首先,简单说一下视频录制功能是调用的相机的自带的Camera类,用SurfaceView当容器,绘出摄像头采集的数据。要实现截取当前正在拍摄视频的截图主要有两种思路:1 获取当前屏幕的view,然后把view转换成Bitmap。之后再对Bitmap压缩然后上传。2 利用Camera类自带的takePicture()方法调用系统相机拍照,实际上相当于模拟相机拍照。
第一种方法看似简单,而且之前用过,我先试了一下,但是结果不如人意,图片是弄出来了,但是却是一片漆黑。好吧,经过查阅资料发现这和SurfaceView实现机制有关系,感觉这条路走不通,好,走第二条。
第二种方法可以使用正在上传录制的Camera对象,调用takePictiure方法
Camera.takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg)
这个方法有3个参数,需要实现一个callback,调用这个方法会回调这个callback,这里我用的是最常用的PictureCallback,自己新建一个类继承这个Callback,重载里面的onPictureTaken方法
onPictureTaken(byte[] data, Camera camera)
方法里有一个byte数组,这里面就是梦寐以求的照片数据了,之后对它怎么处理不就是很easy的了,还有一点要注意的,调用了takePicture方法以后在回调里要调用一下Camera.startPreview(); 因为照相以后会把视频预览卡住,这样要重新开启一下。以下是我的代码。
camera.takePicture(null, null, new MyPictureCallback());
private final class MyPictureCallback implements PictureCallback {
public void onPictureTaken(byte[] data, Camera camera) {
try {
TakePhotoThread takePhotoThread = new TakePhotoThread(data);//处理照片线程
new Thread(takePhotoThread).start();
camera.startPreview();//在这里设置重新开始预览
Toast.makeText(context, "截图成功", Toast.LENGTH_SHORT);
} catch (Exception e) {
e.printStackTrace();
}
}
}
我这里新建了一个线程来处理照片数据。具体如何处理照片就按照各自的需求了。
貌似一切都可以了,但是事与愿违,截图功能出来以后,在不同测试机下显示的效果不太一样,有的手机,好吧就是万恶的小米手机,照出的照片只有176*144,再加上我加了一些压缩的逻辑,出来的截图简直惨不忍睹,根本看不到是什么。研究了很久,才找到一些资料,发现这个拍照有默认值,不同的手机默认分辨率不同,而小米手机默认的是最小分辨率,好那么我们通过代码设置一个默认分辨率
parameters.setPictureSize(1024, 768);
然而还有问题,在有的手机上直接boom了,原来是这个手机硬件没有这个尺寸。后来我选择了照相机尺寸中的最中间的一个,暂时让照片不会那么小了。
//设置拍照大小,设置为支持拍照像素的一半大小
List<Size> list = parameters.getSupportedPictureSizes();
if(list.size() >2){
Size size = list.get(list.size()/2);
parameters.setPictureSize(size.width, size.height);
}else{
Size size = list.get(0);
parameters.setPictureSize(size.width, size.height);
}
好以上就是我的实现方法,暂时解决了这个问题,但是调用的系统照相功能还是会在预览时停顿一下的,这就有了我们的第三种方法。我试了一下也是可行的。我简单说一下,就是在Activity里继承PreviewCallback这个接口重载这个函数:
public void onPreviewFrame(byte[] data, Camera camera) {}