有时需要使用Android原生的camera无预览采集YUV数据,用于生成图片与h.264编码。要实现该功能,只需要调用setPreviewTexture即可。
1、相机CameraHelper
public class CameraHelper implements Camera.PreviewCallback {
private static final String TAG = "CameraHelper";
public static final int WIDTH = 640;
public static final int HEIGHT = 480;
private int mCameraId;
private Camera mCamera;
private byte[] buffer;
private SurfaceTexture surfaceTexture = new SurfaceTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
private boolean shut = false;
private OnPictureRawCapture pictureRawCaptureListener;
public void setPictureRawCaptureListener(OnPictureRawCapture pictureRawCaptureListener) {
this.pictureRawCaptureListener = pictureRawCaptureListener;
}
public CameraHelper(int cameraId){
mCameraId = cameraId;
}
public void switchCamera(){
if (mCameraId == Camera.CameraInfo.CAMERA_FACING_BACK){
mCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
}else{
mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
stopPreview();
startPreview();
}
public void startPreview() {
try {
mCamera = Camera.open(mCameraId);
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewFormat(ImageFormat.NV21);
parameters.setPreviewSize(WIDTH, HEIGHT);
mCamera.setParameters(parameters);
buffer = new byte[WIDTH * HEIGHT *3/2];
mCamera.addCallbackBuffer(buffer);
mCamera.setPreviewCallbackWithBuffer(this);
mCamera.setPreviewTexture(surfaceTexture);//
mCamera.startPreview();
} catch (IOException e) {
Log.e(TAG, "start preview failed");
e.printStackTrace();
}
}
public void stopPreview() {
if (mCamera == null){
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if(shut){
shut = false;
if(pictureRawCaptureListener != null){
pictureRawCaptureListener.onCapture(data);//生成图片
}
}
//to do
//h.264编码、模式识别等
camera.addCallbackBuffer(buffer);
}
public void takePicture(){//拍照
shut = true;
}
public interface OnPictureRawCapture{
void onCapture(byte[] data);
}
public Camera.Size getPreviewSize(){
Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
return previewSize;
}
}
2、相机启动线程
public class CameraRunnable implements Runnable{
private CameraHelper cameraHelper;
public CameraRunnable(CameraHelper cameraHelper) {
this.cameraHelper = cameraHelper;
}
@Override
public void run() {
cameraHelper.startPreview();
}
}
3、生成图片文件线程
public class PictureRunnable implements Runnable{
private static final String CAPTRUE_PATH = "sdcard/img/";
private static final String TEMPLATE = "yyyy_MM_dd_HH_mm_ss";
private SimpleDateFormat sdf = new SimpleDateFormat("", Locale.SIMPLIFIED_CHINESE);
private Camera.Size previewSize;
private byte[] imgRaw;
public PictureRunnable(byte[] data,Camera.Size size){
this.imgRaw = data;
this.previewSize = size;
}
@Override
public void run() {
createBmpAndSaveFile(imgRaw);
}
private void createBmpAndSaveFile(byte[] data) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
newOpts.inJustDecodeBounds = true;
YuvImage yuvimage = new YuvImage(
data,
ImageFormat.NV21,
previewSize.width,
previewSize.height,
null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
yuvimage.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 100, baos);
byte[] rawImage = baos.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length);
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
if (bitmap == null)
return;
else {
try {
saveFile(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void saveFile(Bitmap bm) throws IOException {
String fileName = getFileName()+".jpeg";
File dirFile = new File(CAPTRUE_PATH);
if(!dirFile.exists()){
dirFile.mkdir();
}
File myCaptureFile = new File(CAPTRUE_PATH + fileName);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));
bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);
bos.flush();
bos.close();
bm.recycle();
bm=null;
Log.d("CameraHelper","new img:"+myCaptureFile.getAbsolutePath());
EventBus.getDefault().post(myCaptureFile.getAbsolutePath());
}
private String getFileName() {
long time = System.currentTimeMillis();
sdf.applyPattern(TEMPLATE);
return sdf.format(time);
}
}
4、程序入口
4.1 开启相机
private CameraHelper myCamera;
private ExecutorService executorService;
private CameraRunnable cameraRunnable;
executorService = new ThreadPoolExecutor(2,4,0, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(10));
myCamera = new CameraHelper( Camera.CameraInfo.CAMERA_FACING_BACK);
myCamera.setPictureRawCaptureListener(this);
cameraRunnable = new CameraRunnable(myCamera);
executorService.execute(cameraRunnable);
4.2 拍照
myCamera.takePicture();
4.2.1 保存图片
@Override
public void onCapture(byte[] data) {
Log.d("CameraHelper","onCapture "+data.length);
Camera.Size previewSize = myCamera.getPreviewSize();
executorService.execute(new PictureRunnable(data,previewSize));
}
4.3 关闭相机
executorService.shutdownNow();
myCamera.stopPreview();