用MediaRecorder实现简单的录像功能

2023-12-05 06:58

本文主要是介绍用MediaRecorder实现简单的录像功能,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

思路:定义一个SurfaceView用来显示预览,在SurfaceHolder的回调中用Camera对象启动预览,然后调用MediaRecorder来录像。只是实现了简单的录像开始和停止功能,顶部能显示显示录像的时间,还有待完善。

代码如下:

在AndroidManifest.xml添加下面的权限:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 硬件支持 -->
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent" ><SurfaceViewandroid:id="@+id/camera_preview"android:layout_width="match_parent"android:layout_height="match_parent" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentTop="true"android:layout_centerHorizontal="true"android:orientation="horizontal"><TextViewandroid:id="@+id/timestamp_minute_prefix"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#7F00FF"android:textSize="30sp"android:text="0"/><TextViewandroid:id="@+id/timestamp_minute_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#7F00FF"android:textSize="30sp"android:text="0"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#7F00FF"android:textSize="30sp"android:text=":"/><TextViewandroid:id="@+id/timestamp_second_prefix"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#7F00FF"android:textSize="30sp"android:text="0"/><TextViewandroid:id="@+id/timestamp_second_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#7F00FF"android:textSize="30sp"android:text="0"/></LinearLayout><ImageButtonandroid:id="@+id/record_shutter"android:layout_width="64dp"android:layout_height="64dp"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true"android:layout_marginBottom="15dp"android:background="@android:color/transparent"android:scaleType="centerCrop"android:src="@drawable/recording_shutter" /></RelativeLayout>
MainActivity.java
package com.jackie.videorecorder;import java.io.File;import android.app.Activity;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.TextView;import org.w3c.dom.Text;public class MainActivity extends Activity implements OnClickListener {private SurfaceView mCameraPreview;private SurfaceHolder mSurfaceHolder;private ImageButton mShutter;private TextView mMinutePrefix;private TextView mMinuteText;private TextView mSecondPrefix;private TextView mSecondText;private Camera mCamera;private MediaRecorder mRecorder;private final static int CAMERA_ID = 0;private boolean mIsRecording = false;private boolean mIsSufaceCreated = false;private static final String TAG = "Jackie";private Handler mHandler = new Handler();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mCameraPreview = (SurfaceView) findViewById(R.id.camera_preview);mMinutePrefix = (TextView) findViewById(R.id.timestamp_minute_prefix);mMinuteText = (TextView) findViewById(R.id.timestamp_minute_text);mSecondPrefix = (TextView) findViewById(R.id.timestamp_second_prefix);mSecondText = (TextView) findViewById(R.id.timestamp_second_text);mSurfaceHolder = mCameraPreview.getHolder();mSurfaceHolder.addCallback(mSurfaceCallback);mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);mShutter = (ImageButton) findViewById(R.id.record_shutter);mShutter.setOnClickListener(this);}@Overrideprotected void onPause() {super.onPause();if (mIsRecording) {stopRecording();}stopPreview();}private  SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mIsSufaceCreated = false;}@Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsSufaceCreated = true;}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {startPreview();}};//启动预览private void startPreview() {//保证只有一个Camera对象if (mCamera != null || !mIsSufaceCreated) {Log.d(TAG, "startPreview will return");return;}mCamera = Camera.open(CAMERA_ID);Parameters parameters = mCamera.getParameters();Size size = getBestPreviewSize(CameraUtils.PREVIEW_WIDTH, CameraUtils.PREVIEW_HEIGHT, parameters);if (size != null) {parameters.setPreviewSize(size.width, size.height);}parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);parameters.setPreviewFrameRate(20);//设置相机预览方向mCamera.setDisplayOrientation(90);mCamera.setParameters(parameters);try {mCamera.setPreviewDisplay(mSurfaceHolder);
//			mCamera.setPreviewCallback(mPreviewCallback);} catch (Exception e) {Log.d(TAG, e.getMessage());}mCamera.startPreview();}private void stopPreview() {//释放Camera对象if (mCamera != null) {try {mCamera.setPreviewDisplay(null);} catch (Exception e) {Log.e(TAG, e.getMessage());}mCamera.stopPreview();mCamera.release();mCamera = null;}}private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {Camera.Size result = null;for (Camera.Size size : parameters.getSupportedPreviewSizes()) {if (size.width <= width && size.height <= height) {if (result == null) {result = size;} else {int resultArea = result.width * result.height;int newArea = size.width * size.height;if (newArea > resultArea) {result = size;}}}}return result;}@Overridepublic void onClick(View v) {if (mIsRecording) {stopRecording();} else {initMediaRecorder();startRecording();//开始录像后,每隔1s去更新录像的时间戳mHandler.postDelayed(mTimestampRunnable, 1000);}}private void initMediaRecorder() {mRecorder = new MediaRecorder();//实例化mCamera.unlock();//给Recorder设置Camera对象,保证录像跟预览的方向保持一致mRecorder.setCamera(mCamera);mRecorder.setOrientationHint(90);  //改变保存后的视频文件播放时是否横屏(不加这句,视频文件播放的时候角度是反的)mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置从麦克风采集声音mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // 设置从摄像头采集图像mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);  // 设置视频的输出格式 为MP4mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); // 设置音频的编码格式mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // 设置视频的编码格式mRecorder.setVideoSize(176, 144);  // 设置视频大小mRecorder.setVideoFrameRate(20); // 设置帧率
//        mRecorder.setMaxDuration(10000); //设置最大录像时间为10smRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());//设置视频存储路径File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + File.separator + "VideoRecorder");if (!file.exists()) {//多级文件夹的创建file.mkdirs();}mRecorder.setOutputFile(file.getPath() + File.separator + "VID_" + System.currentTimeMillis() + ".mp4");}private void startRecording() {if (mRecorder != null) {try {mRecorder.prepare();mRecorder.start();} catch (Exception e) {mIsRecording = false;Log.e(TAG, e.getMessage());}}mShutter.setImageDrawable(getResources().getDrawable(R.drawable.recording_shutter_hl));mIsRecording = true;}private void stopRecording() {if (mCamera != null) {mCamera.lock();}if (mRecorder != null) {mRecorder.stop();mRecorder.release();mRecorder = null;}mShutter.setImageDrawable(getResources().getDrawable(R.drawable.recording_shutter));mIsRecording = false;mHandler.removeCallbacks(mTimestampRunnable);//将录像时间还原mMinutePrefix.setVisibility(View.VISIBLE);mMinuteText.setText("0");mSecondPrefix.setVisibility(View.VISIBLE);mSecondText.setText("0");//重启预览startPreview();}private Runnable mTimestampRunnable = new Runnable() {@Overridepublic void run() {updateTimestamp();mHandler.postDelayed(this, 1000);}};private void updateTimestamp() {int second = Integer.parseInt(mSecondText.getText().toString());int minute = Integer.parseInt(mMinuteText.getText().toString());second++;Log.d(TAG, "second: " + second);if (second < 10) {mSecondText.setText(String.valueOf(second));} else if (second >= 10 && second < 60) {mSecondPrefix.setVisibility(View.GONE);mSecondText.setText(String.valueOf(second));} else if (second >= 60) {mSecondPrefix.setVisibility(View.VISIBLE);mSecondText.setText("0");minute++;mMinuteText.setText(String.valueOf(minute));} else if (minute >= 60) {mMinutePrefix.setVisibility(View.GONE);}}
}

效果如下:



这篇关于用MediaRecorder实现简单的录像功能的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/456597

相关文章

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Nginx部署HTTP/3的实现步骤

《Nginx部署HTTP/3的实现步骤》本文介绍了在Nginx中部署HTTP/3的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前提条件第一步:安装必要的依赖库第二步:获取并构建 BoringSSL第三步:获取 Nginx

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja