「音视频直播技术」Android视频采集(Camera1)
前言
今天为大家介绍一下使用Camera1进行视频采集。之前我写过一篇文章介绍的是Camera2进行视频采集。那么有人会问,为什么有了Camera2还要介绍Camera1呢?这里最主要的原因是因为Android版本众多,Camera2是Google新推出的视频采集架构,但很多老的机型还不支持,所以为了兼容性的问题,我们还不能放弃使用Camera1进行视频的采集。
下面我们来详细介绍一下 Camera1 的使用步骤。
Camera1 使用步骤
如图所示,使用 Camera1 的步骤包括下面几大步:
- 设置Camera权限
- 检查Camera是否可用
- 打开摄像头
- 设置摄像头参数
- 设置预览
- 采集数据过程
详细介绍
1. 申请Camera权限
第一步,在 AndroidManifast.xml中添加下面设置权限的语句。
<uses-permission android:name="android.permission.CAMERA" />
第二步,动态申请Camera权限。
Android在Android 6.0后,对根限的管理更严格了,除了上面要静态申请权限外,还要通过调用 requestPermissions 函数动态申请Camera权限。requestPermissions函数如下:
void requestPermissions(String[] permissions, int requestCode);
2. 检查Camera是否可用
为了程序的建壮性,在使用Camera之前我们最好检测一下设备是否可用。检测代码中下:
public static void checkCameraService(Context context)
throws CameraDisabledException, NoCameraException {
//Check if device policy has disabled the camera.
DevicePolicyManager dpm = (DevicePolicyManager)context.getSystemService(Context.DEVICE_POLICY_SERVICE);
if (dpm.getCameraDisabled(null)) {
throw new CameraDisabledException();
}
......
}
如果Camera服务可用,则还要检查一下Camera的个数是否为 0 ? 如果为0 ,说明Camera也是不可用的。代码如下:
......
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
int numberOfCameras = Camera.getNumberOfCameras();
......
3. 打开摄像头
private Camera mCamera;
......
Camera.CameraInfo info = new Camera.CameraInfo();
// Try to find a front-facing camera (e.g. for videoconferencing).
int numCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numCameras; i++) {
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
mCamera = Camera.open(i);
break;
}
}
if (mCamera == null) {
Log.d(TAG, "No front-facing camera found; opening default");
mCamera = Camera.open(); // opens first back-facing camera
}
if (mCamera == null) {
throw new RuntimeException("Unable to open camera");
}
......
我们在打开Camera判断是否打开成功,是通过Camera对象是否为null来判断的。因为通过捕获异常有时候是不准确的。
4. 设置摄像头参数
设置摄像头参数主要是设置图像的宽、高、帧率。设置的基本步骤为:1. 从摄像头取出现有参数。2. 修改参数。3. 设置参数。
......
Camera.Parameters parms = mCamera.getParameters();
CameraUtils.choosePreviewSize(parms, desiredWidth, desiredHeight);
// Try to set the frame rate to a constant value.
CameraUtils.chooseFixedPreviewFps(parms, desiredFps * 1000);
// Give the camera a hint that we're recording video. This can have a big
// impact on frame rate.
parms.setRecordingHint(true);
mCamera.setParameters(parms);
......
5. 设置预览
开启预览的步骤如下:1. 通过 OpenGL ES生成外部纹理。 2. 通过纹理ID行成SurfaceTexture。 3. 将生成的纹理设置到Camera中。 4. 开启预览。5. 当有视频帧到达后,使用OpengGL ES绘制图片。
......
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
GlUtil.checkGlError("glGenTextures");
int texId = textures[0];
GLES20.glBindTexture(mTextureTarget, texId);
......
mCameraTexture = new SurfaceTexture(textureId);
......
// Ready to go, start the camera.
Log.d(TAG, "starting camera preview");
try {
mCamera.setPreviewTexture(mCameraTexture);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
mCamera.startPreview();
......
绘制图片
private void frameAvailable() {
mCameraTexture.updateTexImage();
draw();
}
通过上面的步骤,就将 OpenGL ES 、EGL、NativeWindow以及Camera之间建立起了联接。
6.采集数据过程
- 打开Camera后,Camera开始采集数据。
- Camera会将数据存放到 mCameraTexture 中,也就是SurfaceTexture中。
- Camera完成一帧数据的采集后,通知应用程序有一帧数据已经准备好了。
- 应用程序收到通知后,调用mCameraTexture.updateTexImage(); 将SurfaceTexture中的数据输出到外部纹理(也就是GLES20.glGenTextures函数产生的纹理中)。
- 通过 OpenGL ES 程序将外部纹理渲染到 EGL 的 EGLSurface中。
- 并最终调用 EGL14.eglSwapBuffers(mEGLDisplay, eglSurface); 将 EGLSurface中的内容输出到 NativeWindow,最终显示出来。
- 循环执行 1-6 步。
参考
推荐阅读
-
Android音视频之视频采集(系统API预览)
-
Android 音视频深入 十六 FFmpeg 推流手机摄像头,实现直播 (附源码下载)
-
Android多媒体技术(一)Camera实时视频采集预览、拍照、JPEG图片方向的处理
-
RTSP播放器网页web无插件直播流媒体音视频播放器EasyPlayer-RTSP-Android解码获取视频帧的方法
-
「音视频直播技术」Android下H264解码
-
直播软件搭建音视频开发中的视频采集
-
Android音视频点/直播模块开发
-
直播间搭建Android 音视频开发的音视频基础知识
-
「音视频直播技术」Android下视频H264编码
-
Android直播软件搭建从入门到精通之视频编码技术概述