android采集相机视频,Android音视频之使用Camera采集视频

在 Android 平台预览相机画面主要用到的是 SurfaceView、TextureView 这两个类。那么它们的区别是什么呢?

SurfaceView 可以在独立的线程中进行绘制,不会影响主线程。它使用双缓冲机制,播放视频时画面更流畅。不足之处是,SurfaceView 的内容不再应用窗口上,它的显示不受 View 的属性控制,所以不能进行平移、缩放等变换,也不能嵌套在其它 ViewGroup 中使用。

TextureView 支持移动、旋转、缩放等变换,可以使用 View 控件的一些特性,比如设置透明度。然而它必须在硬件加速的窗口中使用,占用内存比 SurfaceView 高,还会有 1-3 s 的延迟。在 Android 5.0 以前在主线程渲染,5.0 以后有单独的渲染线程。

接下来,我们使用 SurfaceView 和 TextureView 实现相机预览的功能。

使用 SurfaceView

添加相机权限

实现 SurfaceHolder.Callback,在 surfaceCreated 方法中打开相机预览,在 surfaceDestroy 方法中关闭相机预览就可以了。Camera 的 open 方法有些耗时,为了避免阻塞 UI 线程,可以创建子线程打开相机。

public class CameraSurfacePreview extends SurfaceView implements SurfaceHolder.Callback {

private static final int MAX_PREVIEW_WIDTH = 1280;

private static final int MAX_PREVIEW_HEIGHT = 720;

private SurfaceHolder mSurfaceHolder;

private Camera mCamera;

private Activity mActivity;

public CameraSurfacePreview(Context context) {

super(context);

init();

}

private void init() {

mSurfaceHolder = getHolder();

mSurfaceHolder.addCallback(this);

mActivity = (Activity) getContext();

}

@Override

public void surfaceCreated(SurfaceHolder holder) {

logger.debug("surfaceCreated");

openCamera();

startPreviewDisplay();

}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

logger.debug("surfaceChanged: format:{}, width:{}, height:{}", format, width, height);

}

@Override

public void surfaceDestroyed(SurfaceHolder holder) {

logger.debug("surfaceDestroyed");

releaseCamera();

}

// 打开相机

private void openCamera() {

Camera.CameraInfo cameraInfo = new Camera.CameraInfo();

int number = Camera.getNumberOfCameras();

for (int i = 0; i < number; i++) {

Camera.getCameraInfo(i, cameraInfo);

if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {

try {

mCamera = Camera.open(i);

CameraUtils.setCameraDisplayOrientation(mActivity, i, mCamera);

Camera.Parameters params = mCamera.getParameters();

params.setPreviewSize(MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT);

mCamera.setParameters(params);

} catch (Exception e) {

logger.error("openCamera error", e);

mActivity.onBackPressed();

}

break;

}

}

}

// 开启预览

private void startPreviewDisplay() {

if (mCamera != null) {

try {

// 设置预览回调,取得 NV21 数据,进一步处理

mCamera.setPreviewCallback(new Camera.PreviewCallback() {

@Override

public void onPreviewFrame(byte[] data, Camera camera) {

}

});

mCamera.setPreviewDisplay(mSurfaceHolder);

mCamera.startPreview();

} catch (IOException e) {

logger.error("startPreviewDisplay error", e);

}

}

}

// 关闭相机

private void releaseCamera() {

if (mCamera != null) {

try {

mCamera.stopPreview();

mCamera.setPreviewDisplay(null);

mCamera.release();

} catch (IOException e) {

logger.error("releaseCamera error", e);

}

mCamera = null;

}

}

}

使用 TextureView

实现 TextureView.SurfaceTextureListener 接口,在 SurfaceTexture 可用时,打开相机预览,使用 SurfaceTexture 呈现画面。在 SurfaceTexture 销毁时,释放相机资源。Textureview 必须在硬件加速开启的窗口中使用,应用默认开启。

public class CameraTexturePreview extends TextureView implements TextureView.SurfaceTextureListener {

private Camera mCamera;

private Activity mActivity;

public CameraTexturePreview(Context context) {

super(context);

init();

}

private void init() {

setSurfaceTextureListener(this);

mActivity = (Activity) getContext();

}

@Override

public void onSurfaceTextureAvailable(final SurfaceTexture surface, int width, int height) {

logger.debug("onSurfaceTextureAvailable. width:{}, height:{}", width, height);

openCamera();

startPreviewDisplay(surface);

}

@Override

public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

logger.debug("onSurfaceTextureSizeChanged. width:{}, height:{}", width, height);

// Ignored, Camera does all the work for us

}

@Override

public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {

logger.debug("onSurfaceTextureDestroyed");

releaseCamera();

return true;

}

@Override

public void onSurfaceTextureUpdated(SurfaceTexture surface) {

// Invoked every time there's a new Camera preview frame

}

// 开始预览

private void startPreviewDisplay(SurfaceTexture surfaceTexture) {

if (mCamera != null) {

try {

mCamera.setPreviewTexture(surfaceTexture);

mCamera.startPreview();

} catch (IOException e) {

logger.error("startPreviewDisplay error", e);

}

}

}

// 关闭相机

private void releaseCamera() {

if (mCamera != null) {

try {

mCamera.stopPreview();

mCamera.setPreviewTexture(null);

mCamera.release();

} catch (IOException e) {

logger.error("releaseCamera error", e);

}

mCamera = null;

}

}

}

// 设置相机预览方向

public static void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {

Camera.CameraInfo info = new Camera.CameraInfo();

Camera.getCameraInfo(cameraId, info);

int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();

int degrees = 0;

switch (rotation) {

case Surface.ROTATION_0:

degrees = 0;

break;

case Surface.ROTATION_90:

degrees = 90;

break;

case Surface.ROTATION_180:

degrees = 180;

break;

case Surface.ROTATION_270:

degrees = 270;

break;

default:

}

int result;

if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {

result = (info.orientation + degrees) % 360;

result = (360 - result) % 360; // compensate the mirror

} else { // back-facing

result = (info.orientation - degrees + 360) % 360;

}

camera.setDisplayOrientation(result);

}

详细的代码在 GitHub 上,欢迎提出意见和评论。

参考文章:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值