草庐IT

Android音视频开发:MediaRecorder录制视频

音视频开发老舅 2025-04-16 原文

简介

安卓api提供了Camera类控制相机捕获图像,在api21以后,安卓也提供了Camera2,Camera变得过时了,但为了兼容性,这里还是使用Camera。

对于录制视频,可以使用MediaRecorder,这个可看安卓官方api文档

使用

使用Camera进行拍照摄像前,你得先申请权限:

<!-- 相机权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 录音权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 相机模块 -->
<uses-feature android:name="android.hardware.camera"/>
<!-- 自动对焦模块 -->
<uses-feature android:name="android.hardware.camera.autofocus"/>

接着,是相机预览流程:

  1. Camera.open(int)获取Camera实例

  2. setParameters设置相机参数

  3. setDisplayOrientation设置正确预览方向

  4. 关联SurfaceView,用于展示预览画面

  5. startPreview开始预览,stopPreview停止预览

  6. release释放相机资源

录像流程:

  1. 创建MediaRecorder对象,用于录制音频视频

  2. 关联MediaRecorder和Camera,捕获从Camera传来的画面

  3. 设置MediaRecorder相关参数,视频格式、编码、大小等等

  4. setOrientationHint可设置视频最终旋转角度

  5. start开始录制,stop停止录制

  6. release释放资源

为了防止篇幅过长,我这里就不展示全部代码了,详细代码请可以留言

接下来我会就其中一些关键点列举出来:

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

视频质量

视频质量直接影响视频清晰度和文件大小,这个可以根据个人需求调整,码率不宜过小也不宜过大。

/**
     * 获取适合的视频质量配置
     * 影响视频清晰度和文件大小,根据自身需要调整
     * @param cameraID 摄像头ID
     */
    fun getBestCamcorderProfile(cameraID: Int): CamcorderProfile? {
        var profile: CamcorderProfile? = null
        when {
            CamcorderProfile.hasProfile(cameraID, CamcorderProfile.QUALITY_1080P) -> { //1080P,优先
                profile = CamcorderProfile.get(cameraID, CamcorderProfile.QUALITY_1080P)
            }
            CamcorderProfile.hasProfile(cameraID, CamcorderProfile.QUALITY_720P) -> { //720P
                profile = CamcorderProfile.get(cameraID, CamcorderProfile.QUALITY_720P)
            }
            CamcorderProfile.hasProfile(cameraID, CamcorderProfile.QUALITY_480P) -> { //480P
                profile = CamcorderProfile.get(cameraID, CamcorderProfile.QUALITY_480P)
            }
            CamcorderProfile.hasProfile(cameraID, CamcorderProfile.QUALITY_HIGH) -> {//高品质
                profile = CamcorderProfile.get(cameraID, CamcorderProfile.QUALITY_HIGH)
                profile.videoBitRate /= 8
                return profile
            }
            CamcorderProfile.hasProfile(cameraID, CamcorderProfile.QUALITY_CIF) -> {
                profile = CamcorderProfile.get(cameraID, CamcorderProfile.QUALITY_CIF)
                return profile
            }
            CamcorderProfile.hasProfile(cameraID, CamcorderProfile.QUALITY_QVGA) -> {
                profile = CamcorderProfile.get(cameraID, CamcorderProfile.QUALITY_QVGA)
            }
            CamcorderProfile.hasProfile(cameraID, CamcorderProfile.QUALITY_LOW) -> {
                profile = CamcorderProfile.get(cameraID, CamcorderProfile.QUALITY_LOW)
            }
        }
        if (profile != null) {
            //视频码率
            profile.videoBitRate = 6000000
        }
        return profile
    }

视频预览角度 

 /**
     * 根据屏幕方向获取对应预览角度
     * setDisplayOrientation只能改变预览的角度,与视频最终结果角度无关
     * @param cameraID 相机ID
     */
    fun getCameraPreviewOrientation(cameraID: Int, activity: Activity): Int {
        val info = Camera.CameraInfo();
        Camera.getCameraInfo(cameraID, info);
        //屏幕选择角度
        val rotation = activity.windowManager.defaultDisplay.rotation
        var degrees = 0
        when (rotation) {
            Surface.ROTATION_0 ->
                degrees = 0
            Surface.ROTATION_90 ->
                degrees = 90
            Surface.ROTATION_180 ->
                degrees = 180
            Surface.ROTATION_270 ->
                degrees = 270
        }
        var result = 90
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360
            result = (360 - result) % 360
        } else {
            result = (info.orientation - degrees + 360) % 360
        }
        return result;
    }

相机预览 

 /**
     * 初始化相机设置并开启预览
     */
    private fun startPreview() {
        try {
            //开启后置摄像头
            camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK)
              //设置预览角度
            val rotation = CameraUtil.getCameraPreviewOrientation(Camera.CameraInfo.CAMERA_FACING_BACK,this)
            camera?.setDisplayOrientation(rotation)
            // 在SurfaceView上预览
            camera?.setPreviewDisplay(sv_camera.holder)
            val parameters = camera?.getParameters()
              //获取支持的预览大小,注意这里获取的宽高是根据横屏的
            val sizes = parameters?.supportedPreviewSizes
            //宽高建议根据横竖屏切换
            val previewSize =
                CameraUtil.findFitPreviewSize(sv_camera.height,sv_camera.width,sizes)
            if (previewSize != null) {
                //设置预览大小
                parameters?.setPreviewSize(previewSize.width, previewSize.height)
            }
            //设置自动对焦模式
            CameraUtil.setAutoFocusMode(parameters)
            camera?.setParameters(parameters)
            //开始预览
            camera?.startPreview()
        } catch (e: Exception) {
            Log.e("Test", "出错了", e)
        }
    }

视频录制 

    /**
     * 开始录制
     * 注意方法调用的先后顺序
     */
    private fun startRecorder() {
        if (camera == null) {
            return
        }
        if (recorder != null) {
            stopRecord()
        }
        try {
            val videoSize = CameraUtil.findFitVideoSize(camera!!.parameters,
                sv_camera.height / sv_camera.width.toFloat()
            )
            //先停止camera预览,释放camera
            camera?.stopPreview()
            camera?.unlock()
            //创建MediaRecorder对象
            recorder = MediaRecorder()
            //关联camera
            recorder?.setCamera(camera)
            //设置视频角度;
            val rotation =
                CameraUtil.getCameraPreviewOrientation(Camera.CameraInfo.CAMERA_FACING_BACK, this)
            recorder?.setOrientationHint(rotation)
            //设置预览区域
            recorder?.setPreviewDisplay(sv_camera.holder.surface)
            //设置音频来源
            recorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
            //设置视频来源,来自摄像头
            recorder?.setVideoSource(MediaRecorder.VideoSource.CAMERA)

            //设置输出格式
//            recorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
            val profile = CameraUtil.getBestCamcorderProfile(Camera.CameraInfo.CAMERA_FACING_BACK)
            if (profile != null) {
                //设置视频码率
                recorder?.setProfile(profile)
            }
            //设置视频帧率,注意设备支持
            recorder?.setVideoFrameRate(30)
            //设置视频宽高
            recorder?.setVideoSize(videoSize.width, videoSize.height)
            val file =
                File(getExternalFilesDir(Environment.DIRECTORY_MOVIES)?.absolutePath, "test.mp4")
            //设置音频文件的存储位置 {
            recorder?.setOutputFile(file.absolutePath)
            //准备
            recorder?.prepare()
            //开始录制
            recorder?.start()
            ct_time.start()
        } catch (e: Exception) {
            Log.e("Test", e.message, e)
        }
    }

以上就是Camera+MediaRecord录制视频的方法!有问题大家提出来讨论一下。

 如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

有关Android音视频开发:MediaRecorder录制视频的更多相关文章

  1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  2. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  3. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  4. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  5. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  6. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  7. 屏幕录制为什么没声音?检查这2项,轻松解决 - 2

    相信很多人在录制视频的时候都会遇到各种各样的问题,比如录制的视频没有声音。屏幕录制为什么没声音?今天小编就和大家分享一下如何录制音画同步视频的具体操作方法。如果你有录制的视频没有声音,你可以试试这个方法。 一、检查是否打开电脑系统声音相信很多小伙伴在录制视频后会发现录制的视频没有声音,屏幕录制为什么没声音?如果当时没有打开音频录制,则录制好的视频是没有声音的。因此,建议在录制前进行检查。屏幕上没有声音,很可能是因为你的电脑系统的声音被禁止了。您只需打开电脑系统的声音,即可录制音频和图画同步视频。操作方法:步骤1:点击电脑屏幕右下侧的“小喇叭”图案,在上方的选项中,选择“声音”。 步骤2:在“声

  8. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  9. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  10. 动漫制作技巧如何制作动漫视频 - 2

    动漫制作技巧是很多新人想了解的问题,今天小编就来解答与大家分享一下动漫制作流程,为了帮助有兴趣的同学理解,大多数人会选择动漫培训机构,那么今天小编就带大家来看看动漫制作要掌握哪些技巧?一、动漫作品首先完成草图设计和原型制作。设计草图要有目的、有对象、有步骤、要形象、要简单、符合实际。设计图要一致性,以保证制作的顺利进行。二、原型制作是根据设计图纸和制作材料,可以是手绘也可以是3d软件创建。在此步骤中,要注意的问题是色彩和平面布局。三、动漫制作制作完成后,加工成型。完成不同的表现形式后,就要对设计稿进行加工处理,使加工的难易度降低,并得到一些基本准确的概念,以便于后续的大样、准确的尺寸制定。四、

随机推荐