iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >十分钟实现 Android Camera2 视频录制
  • 913
分享到

十分钟实现 Android Camera2 视频录制

android音视频相机Camera视频录制 2023-09-08 16:09:04 913人浏览 独家记忆
摘要

1. 前言 因为工作中要使用Android Camera2 api,但因为Camera2比较复杂,网上资料也比较乱,有一定入门门槛,所以花了几天时间系统研究了下,并在CSDN上记录了下,希望能帮助到更

1. 前言

因为工作中要使用Android Camera2 api,但因为Camera2比较复杂,网上资料也比较乱,有一定入门门槛,所以花了几天时间系统研究了下,并在CSDN上记录了下,希望能帮助到更多的小伙伴。
上两篇文章使用Camera2实现了相机预览和拍照的功能,这篇文章我们接着上文,来实现Camera2视频录制的功能。

2. 前置操作

2.1 声明相机参数和成员变量

首先还是声明相机参数和成员变量,比起前文增加了这些

private var mediaRecorder: MediaRecorder? = nullprivate var isRecordingVideo: Boolean = falseprivate val SENSOR_ORIENTATioN_DEFAULT_DEGREES = 90private val SENSOR_ORIENTATION_INVERSE_DEGREES = 270private val DEFAULT_ORIENTATIONS = SparseIntArray().apply {    append(Surface.ROTATION_0, 90)    append(Surface.ROTATION_90, 0)    append(Surface.ROTATION_180, 270)    append(Surface.ROTATION_270, 180)}private val INVERSE_ORIENTATIONS = SparseIntArray().apply {    append(Surface.ROTATION_0, 270)    append(Surface.ROTATION_90, 180)    append(Surface.ROTATION_180, 90)    append(Surface.ROTATION_270, 0)}

完整的需要声明的相机参数和成员变量如下

//后摄 : 0 ,前摄 : 1private val cameraid = "0"private val TAG = CameraActivity3::class.java.simpleNameprivate lateinit var cameraDevice: CameraDeviceprivate val cameraThread = HandlerThread("CameraThread").apply { start() }private val cameraHandler = Handler(cameraThread.looper)private val cameraManager: CameraManager by lazy {    getSystemService(Context.CAMERA_SERVICE) as CameraManager}private val characteristics: CameraCharacteristics by lazy {    cameraManager.getCameraCharacteristics(cameraId)}private lateinit var session: CameraCaptureSessionprivate lateinit var imageReader: ImageReader//JPEG格式,所有相机必须支持JPEG输出,因此不需要检查private val pixelFORMat = ImageFormat.JPEG//imageReader最大的图片缓存private val IMAGE_BUFFER_SIZE: Int = 3//线程池private val threadPool = Executors.newCachedThreadPool()private val imageReaderThread = HandlerThread("imageReaderThread").apply { start() }private val imageReaderHandler = Handler(imageReaderThread.looper)private lateinit var relativeOrientation: OrientationLiveDataprivate var mediaRecorder: MediaRecorder? = nullprivate var isRecordingVideo: Boolean = falseprivate val SENSOR_ORIENTATION_DEFAULT_DEGREES = 90private val SENSOR_ORIENTATION_INVERSE_DEGREES = 270private val DEFAULT_ORIENTATIONS = SparseIntArray().apply {    append(Surface.ROTATION_0, 90)    append(Surface.ROTATION_90, 0)    append(Surface.ROTATION_180, 270)    append(Surface.ROTATION_270, 180)}private val INVERSE_ORIENTATIONS = SparseIntArray().apply {    append(Surface.ROTATION_0, 270)    append(Surface.ROTATION_90, 180)    append(Surface.ROTATION_180, 90)    append(Surface.ROTATION_270, 0)}

2.2 添加布局

首先我们需要在XML中添加两个按钮,分别是录制按钮和停止录制按钮

<Button    android:id="@+id/btn_capture_video"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_gravity="bottom|center"    android:layout_marginRight="16dp"    android:text="录屏"    android:visibility="visible"    app:layout_constraintBottom_toBottomOf="parent"    app:layout_constraintLeft_toLeftOf="parent"    app:layout_constraintRight_toRightOf="parent" /><Button    android:id="@+id/btn_stop_capture"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_gravity="bottom|left"    android:text="停止录屏"    android:visibility="visible"    app:layout_constraintBottom_toBottomOf="parent"    app:layout_constraintLeft_toLeftOf="parent"    app:layout_constraintRight_toRightOf="parent" />

2.3 初始化MediaPlayer

我们需要在打开相机的时候,去初始化mediaRecorder

mediaRecorder = MediaRecorder()

完整代码如下

@SuppressLint("MissingPermission")private fun openCamera(cameraId: String) {    cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() {        override fun onOpened(camera: CameraDevice) {            cameraDevice = camera            mediaRecorder = MediaRecorder()            startPreview()        }        override fun onDisconnected(camera: CameraDevice) {            this@CameraActivity3.finish()        }        override fun onError(camera: CameraDevice, error: Int) {            Toast.makeText(application, "openCamera Failed:$error", Toast.LENGTH_SHORT).show()        }    }, cameraHandler)}

3. 实现视频录制功能

3.1 关闭原本的Session

因为拍照和录制视频功能不好一起使用,所以需要先调用closePreviewSession,来关闭原来的session

private fun closePreviewSession() {    session?.close()}

3.2 给MediaRecorder设置参数

接着,需要调用setUpMediaRecorder()来初始化MediaRecorder
setUpMediaRecorder中,会给mediaRecorder设置很多预置参数

首先获取目标路径

 val nextVideoAbsolutePath = getVideoFilePath(cameraActivity) fun getVideoFilePath(context: Context?): String {    val filename = "VIDEO_${System.currentTimeMillis()}.mp4"    val dir = context?.getExternalFilesDir("video")    return if (dir == null) {        filename    } else {        "${dir.absolutePath}/$filename"    }}

然后设置mediaRecorder方向

val sensorOrientation = characteristics?.get(SENSOR_ORIENTATION)val rotation = cameraActivity.windowManager.defaultDisplay.rotationwhen (sensorOrientation) {    SENSOR_ORIENTATION_DEFAULT_DEGREES ->        mediaRecorder?.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation))    SENSOR_ORIENTATION_INVERSE_DEGREES ->        mediaRecorder?.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation))}

最后给meidaRecorder设置若干参数项,这里我们默认给视频尺寸设置成了1920*1080,如果你的设备相机不支持这个分辨率,需要修改一下。

mediaRecorder?.apply {    setAudiOSource(MediaRecorder.AudioSource.MIC)    setVideoSource(MediaRecorder.VideoSource.SURFACE)    setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)    setOutputFile(nextVideoAbsolutePath)    setVideoEncodingBitRate(10000000)    setVideoFrameRate(30)    setVideoSize(1920,1080)    setVideoEncoder(MediaRecorder.VideoEncoder.H264)    setAudioEncoder(MediaRecorder.AudioEncoder.AAC)    prepare()}

再来看下完整的代码

private fun setUpMediaRecorder() {    val cameraActivity = this    val nextVideoAbsolutePath = getVideoFilePath(cameraActivity)    val sensorOrientation = characteristics?.get(SENSOR_ORIENTATION)    val rotation = cameraActivity.windowManager.defaultDisplay.rotation    when (sensorOrientation) {        SENSOR_ORIENTATION_DEFAULT_DEGREES ->            mediaRecorder?.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation))        SENSOR_ORIENTATION_INVERSE_DEGREES ->            mediaRecorder?.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation))    }    mediaRecorder?.apply {        setAudioSource(MediaRecorder.AudioSource.MIC)        setVideoSource(MediaRecorder.VideoSource.SURFACE)        setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)        setOutputFile(nextVideoAbsolutePath)        setVideoEncodingBitRate(10000000)        setVideoFrameRate(30)        setVideoSize(1920,1080) //FIXME 如果你的设备相机不支持这个分辨率,需要修改一下        setVideoEncoder(MediaRecorder.VideoEncoder.H264)        setAudioEncoder(MediaRecorder.AudioEncoder.AAC)        prepare()    }}fun getVideoFilePath(context: Context?): String {    val filename = "VIDEO_${System.currentTimeMillis()}.mp4"    val dir = context?.getExternalFilesDir("video")    return if (dir == null) {        filename    } else {        "${dir.absolutePath}/$filename"    }}

3.3 重新创建Session

接着就将binding.surfaceViewrecorderSurface添加到surfaces

val recorderSurface = mediaRecorder!!.surfaceval surfaces = ArrayList<Surface>().apply {    add(binding.surfaceView.holder.surface)    add(recorderSurface)}

重新调用cameraDevice?.createCaptureSession,将surfaces传入

cameraDevice?.createCaptureSession(surfaces,    object : CameraCaptureSession.StateCallback() {        override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {            //待实现        }        override fun onConfigureFailed(cameraCaptureSession: CameraCaptureSession) {            Toast.makeText(application, "onConfigureFailed", Toast.LENGTH_SHORT).show()        }    }, cameraHandler)

3.4 开始录制

onConfigured调用后,我们执行下面这些代码,主要执行了这些操作

  • cameraCaptureSession赋值给session
  • session?.setRepeatingRequest,这将不断地实时发送视频流,直到会话断开或调用session.stoprepeat()
  • 调用mediaRecorder?.start录制视频
session = cameraCaptureSessionval previewRequestBuilder = cameraDevice!!.createCaptureRequest(TEMPLATE_RECORD).apply {    addTarget(binding.surfaceView.holder.surface)    addTarget(recorderSurface)}session?.setRepeatingRequest(previewRequestBuilder!!.build(), null, cameraHandler)isRecordingVideo = truemediaRecorder?.start()

3.5 录制视频完整代码

binding.btnCaptureVideo.setOnClickListener {    startRecordingVideo()}private fun startRecordingVideo() {closePreviewSession()setUpMediaRecorder()val recorderSurface = mediaRecorder!!.surfaceval surfaces = ArrayList<Surface>().apply {    add(binding.surfaceView.holder.surface)    add(recorderSurface)}cameraDevice?.createCaptureSession(    surfaces,    object : CameraCaptureSession.StateCallback() {        override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {            session = cameraCaptureSession            val previewRequestBuilder =                cameraDevice!!.createCaptureRequest(TEMPLATE_RECORD).apply {                    addTarget(binding.surfaceView.holder.surface)                    addTarget(recorderSurface)                }            session?.setRepeatingRequest(                previewRequestBuilder!!.build(),                null,                cameraHandler            )            isRecordingVideo = true            mediaRecorder?.start()        }        override fun onConfigureFailed(cameraCaptureSession: CameraCaptureSession) {            Toast.makeText(application, "onConfigureFailed", Toast.LENGTH_SHORT).show()        }    }, cameraHandler)}private fun closePreviewSession() {    session?.close()}private fun setUpMediaRecorder() {    val cameraActivity = this    val nextVideoAbsolutePath = getVideoFilePath(cameraActivity)    val sensorOrientation = characteristics?.get(SENSOR_ORIENTATION)    val rotation = cameraActivity.windowManager.defaultDisplay.rotation    when (sensorOrientation) {        SENSOR_ORIENTATION_DEFAULT_DEGREES ->            mediaRecorder?.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation))        SENSOR_ORIENTATION_INVERSE_DEGREES ->            mediaRecorder?.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation))    }    mediaRecorder?.apply {        setAudioSource(MediaRecorder.AudioSource.MIC)        setVideoSource(MediaRecorder.VideoSource.SURFACE)        setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)        setOutputFile(nextVideoAbsolutePath)        setVideoEncodingBitRate(10000000)        setVideoFrameRate(30)        setVideoSize(1920, 1080) //FIXME 如果你的设备相机不支持这个分辨率,需要修改一下        setVideoEncoder(MediaRecorder.VideoEncoder.H264)        setAudioEncoder(MediaRecorder.AudioEncoder.AAC)        prepare()    }}

在这里插入图片描述

我们运行程序,点击录制视频,过几秒点击停止录制,然后打开文件管理器,在/sdcard/Android/data/包名/files/video文件夹下,可以看到这个视频了

在这里插入图片描述

4. 停止录制视频

停止录制视频比较简单,只需要释放mediaRecorder
然后再调用startPreview重新开始预览就可以了

private fun stopRecordingVideo() {    isRecordingVideo = false    mediaRecorder?.apply {        stop()        reset()    }    //重新开始预览    startPreview()}

5. 实现动态设置分辨率

之前我们这是录制分辨率是写死的1920*1080,这样是不够动态灵活的,接下来我们来实现下动态设置分辨率

首先通过characteristics获取到可用的分辨率列表

val characteristics = manager.getCameraCharacteristics(cameraId)val map = characteristics.get(SCALER_STREAM_CONFIGURATION_MAP) ?:        throw RuntimeException("Cannot get available preview/video sizes")

然后通过这个map来选择出最适合的分辨率,这里的选择规则是返回宽高比3:4的分辨率中最高的分辨率

 videoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder::class.java)) fun chooseVideoSize(choices: Array<Size>) = choices.firstOrNull {        it.width == it.height * 4 / 3 } ?: choices[choices.size - 1]

最后,将该分辨率设置到mediaRecorder中就行了

mediaRecorder?.apply {    setAudioSource(MediaRecorder.AudioSource.MIC)    setVideoSource(MediaRecorder.VideoSource.SURFACE)    setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)    setOutputFile(nextVideoAbsolutePath)    setVideoEncodingBitRate(10000000)    setVideoFrameRate(30)    //setVideoSize(1920, 1080)    setVideoSize(videoSize.width,videoSize.height)    setVideoEncoder(MediaRecorder.VideoEncoder.H264)    setAudioEncoder(MediaRecorder.AudioEncoder.AAC)    prepare()}

6. 其他

6.1 本文源码下载

下载地址 : Android Camera2 Demo - 实现相机预览、拍照、录制视频功能

6.2 Android Camera2 系列

更多Camera2相关文章,请看
十分钟实现 Android Camera2 相机预览_氦客的博客-CSDN博客
十分钟实现 Android Camera2 相机拍照_氦客的博客-CSDN博客
十分钟实现 Android Camera2 视频录制_氦客的博客-CSDN博客

6.3 Android 相机相关文章

Android 使用CameraX实现预览/拍照/录制视频/图片分析/对焦/缩放/切换摄像头等操作_氦客的博客-CSDN博客
Android 从零开发一个简易的相机App_android开发简易app_氦客的博客-CSDN博客

来源地址:https://blog.csdn.net/EthanCo/article/details/131418829

--结束END--

本文标题: 十分钟实现 Android Camera2 视频录制

本文链接: https://www.lsjlt.com/news/400274.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 十分钟实现 Android Camera2 视频录制
    1. 前言 因为工作中要使用Android Camera2 API,但因为Camera2比较复杂,网上资料也比较乱,有一定入门门槛,所以花了几天时间系统研究了下,并在CSDN上记录了下,希望能帮助到更...
    99+
    2023-09-08
    android 音视频 相机 Camera 视频录制
  • 十分钟实现 Android Camera2 相机预览
    1. 前言 因为工作中要使用Android Camera2 API,但因为Camera2比较复杂,网上资料也比较乱,有一定入门门槛,所以花了几天时间系统研究了下,并在CSDN上记录了下,希望能帮助到更...
    99+
    2023-10-26
    android 相机 Camera2 音视频 预览
  • Android视频录制功能的实现步骤
    官方使用指南请查看Google音频和视频指南 视频录制基本步骤 1.申明权限 <uses-permission android:name="android.permiss...
    99+
    2024-04-02
  • vue如何实现录制视频并压缩视频文件
    这篇“vue如何实现录制视频并压缩视频文件”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“vue如何实现录制视频并压缩视频文件...
    99+
    2023-07-04
  • C++ Opencv实现录制九宫格视频
    目录库的导入开启摄像头定义所需变量捕获图片并生成视频实现图片的抓取、转换与保存补充在项目开始之前,我的环境已配置完成,具体环境如何配置可参考网络教程。下面我们开始项目的实现 库的导入...
    99+
    2024-04-02
  • 使用AVFoundation实现视频录制详解
    目录一、前言二、AVCaptureSession + AVCaptureMovieFileOutput一、前言 AVCaptureSession 是 AVFoundation 的核心...
    99+
    2024-04-02
  • Android 录制音视频的完整代码
    打开camera private void openCamera(int position) { if (mCamera == null) { mCamera = Ca...
    99+
    2024-04-02
  • android如何实现视频截屏&手机录屏
    这篇文章主要介绍android如何实现视频截屏&手机录屏,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!问题在android中有时候我们需要对屏幕进行截屏操作,单一的截屏操作好解决可以通过activity的顶层...
    99+
    2023-05-30
    android
  • android实现播放网络视频
    本文实例为大家分享了android实现播放网络视频的具体代码,供大家参考,具体内容如下 PlayVideoActivity.java package cn.edu.zufe.a...
    99+
    2024-04-02
  • Android如何实现播放视频
    这篇文章将为大家详细讲解有关Android如何实现播放视频,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、通过intent的方式,调用系统自带的播放器  Uri uri&n...
    99+
    2023-05-31
    android
  • Android实现音乐视频播放
    本文实例为大家分享了Android实现音乐视频播放的具体代码,供大家参考,具体内容如下 步骤 1、新建一个安卓项目,再加一个assets包 2、在 assets中加入一段音频 3...
    99+
    2024-04-02
  • Golang与FFmpeg: 实现网络视频实时录制的技术实现
    要实现网络视频的实时录制,可以使用Golang和FFmpeg的组合来完成。下面是一种可能的技术实现方案:1. 使用Golang编写一...
    99+
    2023-10-08
    Golang
  • JavaScript如何实现控制视频
    这篇文章将为大家详细讲解有关JavaScript如何实现控制视频,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体代码如下所示:<html lang=&q...
    99+
    2024-04-02
  • Android应用中怎么实现一个录制视频生成GIF图片功能
    今天就跟大家聊聊有关Android应用中怎么实现一个录制视频生成GIF图片功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。首先打开AS,连接上手机,打开你要录制的程序或者视频打开A...
    99+
    2023-05-31
    android roi
  • Android仿微信长按录制视频并播放功能
    本文实例为大家分享了Android仿微信长按录制视频并播放功能的具体代码,供大家参考,具体内容如下 一、点击按钮进行录制 首先要获取摄像拍照的权限和读取权限 <uses-p...
    99+
    2024-04-02
  • Android实现短视频画心效果
    本文实例为大家分享了Android实现短视频画心效果的具体代码,供大家参考,具体内容如下 布局 主布局 <?xml version="1.0" encoding="...
    99+
    2024-04-02
  • Android怎么实现音乐视频播放
    这篇文章给大家分享的是有关Android怎么实现音乐视频播放的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。步骤新建一个安卓项目,再加一个assets包在 assets中加入一段音频在界面中加入音乐的“开始”按钮和...
    99+
    2023-06-15
  • Python如何实现视频分帧
    这篇文章主要介绍“Python如何实现视频分帧”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Python如何实现视频分帧”文章能帮助大家解决问题。下载依赖pip install ...
    99+
    2023-07-05
  • Android实现视频的画中画功能
    简介: Android 8.0(API 级别 26)允许以画中画 (PIP) 模式启动 Activity。画中画是一种特殊类型的多窗口模式,最常用于视频播放。使用该模式,用户可以通过...
    99+
    2024-04-02
  • android怎么实现视频播放功能
    Android可以使用MediaPlayer或ExoPlayer等库来实现视频播放功能。以下是一种常见的实现方法:1. 添加权限和依...
    99+
    2023-08-23
    android
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作