用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

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

通过React实现页面的无限滚动效果

《通过React实现页面的无限滚动效果》今天我们来聊聊无限滚动这个现代Web开发中不可或缺的技术,无论你是刷微博、逛知乎还是看脚本,无限滚动都已经渗透到我们日常的浏览体验中,那么,如何优雅地实现它呢?... 目录1. 早期的解决方案2. 交叉观察者:IntersectionObserver2.1 Inter

Spring Gateway动态路由实现方案

《SpringGateway动态路由实现方案》本文主要介绍了SpringGateway动态路由实现方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录前沿何为路由RouteDefinitionRouteLocator工作流程动态路由实现尾巴前沿S