公众号回复:666,领取学习资源大礼包

来源:svvvvvvvL

地址:https://www.jianshu.com/p/0d2f200ab374

Android的相机 Camera2 在 6.0M 的时候,出了一个支持高帧率预览和录像的功能。

就是创建一个新的 session,叫做 mCameraDevice.createConstrainedHighSpeedCaptureSession,通过这个,可以实现相机的高帧率(>120fps)的预览和录像(需要相机本身支持)。

根据相机的不同,实现的帧率也不同, 比如我手上这个华为v10的手机就是下图这个样子:

下面说一下大概步骤.

第一步, 获取权限

相机部分肯定得请求相关权限才能操作的,这里需要3个,分别为

  • 相机 Manifest.permission.CAMERA

  • 录音 Manifest.permission.RECORD_AUDIO 这个是为了录视频的时候录音用的

  • 写入文件 Manifest.permission.WRITE_EXTERNAL_STORAGE 这个是拍好了视屏,存入到手机相册用的

除了运行时请求这些权限之外, 还需要在AndroidManifest.xml文件里面加入这3个权限的注册,否则请求权限的时候,不能触发Dialog提示

    <uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.RECORD_AUDIO" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

第二步,打开相机

正确获取到权限了之后,按照常规方式打开相机.

先获取到

CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);

然后用这个manager打开相机,即

manager.openCamera(cameraId, mStateCallback, mBackgroundHandler);

在这中间,我们可以获取到相机的支持的各种参数信息, 也就是在这里才可以知道,当前的相机支不支持高帧率录制

读取到的支持预览高帧率

使用 manager.getCameraCharacteristics(cameraId) 获取 CameraCharacteristics

然后使用 characteristics .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) 这个值可以获取到向前摄像头支持的参数 StreamConfigurationMap

最后用 map 调用 map.getHighSpeedVideoFpsRanges() 来获取支持搞帧率预览范围,代码部分为

            CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);if (map == null) {ErrorDialog.newInstance(getString(R.string.open_failed_of_map_null)).show(getFragmentManager(), "TAG");return;}for (Range<Integer> fpsRange : map.getHighSpeedVideoFpsRanges()) {Log.d(TAG, "openCamera: [width, height] = "+ fpsRange.toString());}

比如我手上的这个华为V10测试机,获取到的参数就是

openCamera: [width, height] = [120, 120]
openCamera: [width, height] = [30, 120]

帧率范围Range的 LowerUpper一致才认为支持,所以这个log结果说明它支持120fps的预览.

支持高帧率的视频录制的条件

  • 高帧率的视频录制和普通的camera.createCaptureSession要求不同,高帧率session的预览preview大小和设置的MediaRecorder的大小必须一致

  • 上文获取出来的支持120fps,说明他支持预览,但是不意味着它支持录制视频。

  • 是否支持视频录制,需要用另一个方法来查询, 就是 CamcorderProfilepublic static boolean hasProfile(int cameraId, int quality) 方法,只有他返回true才意味着当前预览的帧率支持被录制视频。

为什么一定要用CamcorderProfile来判断是否支持?

直接在MediaRecorder的方法里set设置各个属性是否可行?

答案是不行, 虽然我也不知道为什么, 我用手边的机器坚果Pro 2s测试, 查询到支持的预览帧率支持1080p的240fps,但是在给MediaRecorder设置好各种参数后,比如mMediaRecorder.setVideoFrameRate(240),点击录制直接crash.

配置MediaRecorder

在得出手机支持高帧率录制后, 就需要配置MediaRecorder给下一步打开预览使用了. 具体的步骤如下:

        CamcorderProfile profile = mVideoSize.getCamcorderProfile();mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);mMediaRecorder.setProfile(profile);mNextVideoFilePath = getVideoFile();mMediaRecorder.setOutputFile(mNextVideoFilePath);int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();int orientation = ORIENTATIONS.get(rotation);mMediaRecorder.setOrientationHint(orientation);mMediaRecorder.prepare();

这里面的关键就是setVideoFrameRate这一个属性, 这个只能由CamcorderProfile.videoFrameRate来设置, 如果CamcorderProfile说你不支持, 那么你手动设置了这个数值, 也不能正常录制.

其他的只需要将CamcorderProfile不包含的配置设置进去就好了. 其他的比如setOutputFile输出文件路径,setOrientationHint旋转方向这些, 根据需要配置就好了.

第三步, 开启预览

使用CameraDevice的如下方法开启预览

    /** @param outputs The new set of Surfaces that should be made available as*                targets for captured high speed image data.* @param callback The callback to notify about the status of the new capture session.* @param handler The handler on which the callback should be invoked, or {@code null} to use*                the current thread's {@link android.os.Looper looper}.** @throws IllegalArgumentException if the set of output Surfaces do not meet the requirements,*                                  the callback is null, or the handler is null but the current*                                  thread has no looper, or the camera device doesn't support*                                  high speed video capability.* @throws CameraAccessException if the camera device is no longer connected or has*                               encountered a fatal error* @throws IllegalStateException if the camera device has been closed** @see #createCaptureSession* @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE* @see StreamConfigurationMap#getHighSpeedVideoSizes* @see StreamConfigurationMap#getHighSpeedVideoFpsRangesFor* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES* @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO* @see CameraCaptureSession#captureBurst* @see CameraCaptureSession#setRepeatingBurst* @see CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList*/public abstract void createConstrainedHighSpeedCaptureSession(@NonNull List<Surface> outputs,@NonNull CameraCaptureSession.StateCallback callback,@Nullable Handler handler)throws CameraAccessException;

可以看到, 第一个参数是一个surface的List,代表着相机摄像头拍得到画面要输出到哪里去, 这里我们有2个目的地:

第一个是preview,需要输出到预览, 这样我们在屏幕上才看得到画面 第二个是mMediaRecorder.getSurface(), 这个是输出到MediaRecorder里面去,用来录制视频

所以这个地方的代码就类似

            Surface previewSurface = new Surface(texture);//添加预览输出surfaces.add(previewSurface);mPreviewBuilder.addTarget(previewSurface);//配置MediaRecordersetUpMediaRecorder();//添加MediaRecorder输出surfaces.add(mMediaRecorder.getSurface());mPreviewBuilder.addTarget(mMediaRecorder.getSurface());//开启预览mCameraDevice.createConstrainedHighSpeedCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {//保存引用mPreviewSessionHighSpeed = (CameraConstrainedHighSpeedCaptureSession) cameraCaptureSession;//刷新预览, 使屏幕动起来updatePreview();}@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {Activity activity = getActivity();if (null != activity) {Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();}}}, mBackgroundHandler);

没什么错误的话,这样就可以启动预览了.

第四步, 开始录像和结束录像

因为MediaRecorder在之前已经准备就绪了, 所以开启录像只需要调用一下开始录像就好了

mMediaRecorder.start();

其他的一些UI操作看着办.

结束录制也是几句话:

//停止录制
mMediaRecorder.stop();
//重置状态,便于重用, 不需要每次都new MediaRecorder了
mMediaRecorder.reset();
//因为MediaRecorder被销毁了, 所以需要重新配置MediaRecorder,重新打开预览
startPreview();

第五步, 验证视频的帧率

对于录制生成的视频, 需要查看他的具体参数是不是真的是我们所设置的值. 我这里是macos环境, 就只演示我自己的操作:

  1. 用USB线连接手机和电脑,点击右下角的 Device File Explorer

  1. 在文件列表中找到自己录制的视频文件, 并把它保存到本地,比如Downloads

保存到本地的视频文件

  1. 打开终端Terminal,然后运行命令ffmpeg -i 视频文件名, 如果提示ffmpeg命令不存在或者找不到,就先安装这个东西

红线处是查询视频信息的命令,绿线是该视频的fps帧率信息. 虽然我们预览的是120fps,但是录制出来的不一定可以达到那么高, 比如图里面的就只有74.54fps.这是系统自己决定的.

最后

关键就是2点:

  1. 预览尺寸和录制尺寸要一直

  2. CamcorderProfile 说你支持你才支持.

所有Demo代码提交到Github.可以访问

https://github.com/ZhengShang/HighSpeedVideoDemo/tree/master

如果运行apk后发现crash,ANR或者黑屏等杂七杂八的问题, 这都很正常, Android相机开发受制于各种不同的手机和rom的差异化,确实挺难做到完美兼容的, 尤其是这随便写的Demo,就更难保证了.

但是大体流程是这个样子, 具体解决Bug那都是后事了.

推荐阅读:

音视频开发入门必备之基础知识

移动端技术交流喊你入群啦~~~

推荐几个堪称教科书级别的 Android 音视频入门项目

Android OpenGL ES 实现 3D 阿凡达效果

没想到,快手成了“生产力”

觉得不错,点个在看呗~

Android Camera2 实现高帧率预览录制(附源码)相关推荐

  1. android camera2 帧数,Android Camera2 HighSpeedCaptureSession高帧率预览录像

    ❗️底部有示例Apk和Github代码 Android的相机Camera2在6.0M的时候,出了一个支持高帧率预览和录像的功能,就是创建一个新的session,叫做mCameraDevice.crea ...

  2. 富文本生成word并在线预览(附源码)

    记录富文本内容生成word并在线预览碰到的问题,以及最终的解决方案. 一.需求 当前项目需要将页面富文本中的内容,生成word并在线预览. 二.解决方案1(未解决) 1. openoffice wor ...

  3. Android AR开发实践之七:OpenGLES相机预览背景绘制源码详解

    Android AR开发实践之七:OpenGLES相机预览背景绘制源码详解 目录 Android AR开发实践之七:OpenGLES相机预览背景绘制源码详解 一.OpenGL ES渲染管线 1.基本处 ...

  4. Android悬浮窗开启 适配所有机型(附源码)

    Android悬浮窗开启 适配所有机型(附源码) 1.开启悬浮窗权限 清单文件中添加: <uses-permission android:name="android.permissio ...

  5. pyTorch入门(六)——实战Android Minist OpenCV手写数字识别(附源码地址)

    学更好的别人, 做更好的自己. --<微卡智享> 本文长度为4239字,预计阅读12分钟 前言 前面几篇文章实现了pyTorch训练模型,然后在Windows平台用C++ OpenCV D ...

  6. 集成Android 科大讯飞免费在线语音合成播报功能(附源码)

    概述 开篇先介绍一下'科大讯飞',毕竟是我家乡合肥的科技公司,我感到骄傲,更重要的是它在语音识别行业也是佼佼者,在如今人工智能横飞的时代,依然能够保持着较高水准的技术优势.在此,希望科大在AI之战中能 ...

  7. android SQLite数据库用法图文详解(附源码)

    (转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景 SQLite是嵌入式设备使用的一种轻量型数据库.可以通过执行sql语句对数据库进行操作,android ...

  8. Android 高级编程【6个实战案例(附源码):刮刮卡、补间动画、逐帧动画、Fragment、RecyclerView、下拉刷新】

    目   录 刮刮卡案例[ScratchCard] 结构图 activity_main.xml MainActivity.java 运行效果图 补间动画(Tween Animation) 逐帧动画(Fr ...

  9. Android开发之自定义控件的基本介绍(附源码)

    老套路先看效果图: 一个特别简单的字母排序列表如上图: 先看下有哪些属性: <com.xiayiye.honorfirst.custom.CustomNumViewandroid:id=&quo ...

最新文章

  1. 1145 Hashing - Average Search Time
  2. 百万奖池,鹅厂offer,2020腾讯广告算法大赛等你来战!
  3. reid2019-2021
  4. memkind版本查看_QQ 20周年来啦!扫码查看你的回忆
  5. Ocelot 集成Butterfly 实现分布式跟踪
  6. 【Linux】一步一步学Linux——bg命令(131)
  7. mysql 5.5 外键_MySQL 5.5添加外键失败,错误[HY000] [150]和[HY000] [1005]
  8. 干货:科大讯飞最新语音识别系统和框架深度剖析
  9. Ubuntu下 sqlitebrowser 查看 Android Sqlite数据库
  10. MyCat分片规则之枚举分片
  11. 自考 02333 软件工程 思维导图 结构化方法
  12. 数据结构——线性表的链式存储
  13. CNKI知网如何批量下载论文
  14. TIM_SetCompare1(TIM14,625); 但是这个办法对TIM4行不通。TIM4使用TIM_OCInitStructure.TIM_Pulse = dutyCycle;
  15. 操作系统实验——进程控制
  16. 关于win10激活工具KMSpico安装失败,卡住不动!
  17. 一仓库失窃,四管理员被传讯_如何找到丢失或失窃的Android手机
  18. 阿里云函数计算快速入门
  19. 影视处理计算机配置,影视后期制作需要什么样的电脑配置
  20. 思岚科技邀你2017日本东京国际机器人展

热门文章

  1. 学生成绩管理系统(通过学号,班级,姓名查询以及其他方法的实现)
  2. make all和make有什么不同?
  3. 2022数维杯国际赛C题思路(思路已更完)
  4. AutoDock, AutoDock-vina等对接工具安装
  5. 十年的成长历程!十年的回顾!
  6. 非常简单的animation动画
  7. 删除隧道适配器 本地连接
  8. 《跟我一起学爬虫系列》3-一个简单爬虫示例
  9. ygo游戏王卡组_游戏王 WCS游戏王世界大会前三强卡组,淘气仙星成为比赛冠军卡组...
  10. 基于Volcano 3D游戏引擎开发一个类似魔兽世界的场景