Android使用MediaRecorder实现录像功能
发布时间 - 2026-01-11 01:55:15 点击率:次用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" > <SurfaceView android:id="@+id/camera_preview" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:orientation="horizontal"> <TextView android:id="@+id/timestamp_minute_prefix" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#7F00FF" android:textSize="30sp" android:text="0"/> <TextView android:id="@+id/timestamp_minute_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#7F00FF" android:textSize="30sp" android:text="0"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#7F00FF" android:textSize="30sp" android:text=":"/> <TextView android:id="@+id/timestamp_second_prefix" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#7F00FF" android:textSize="30sp" android:text="0"/> <TextView android: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> <ImageButton android: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();
@Override
protected 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);
}
@Override
protected void onPause() {
super.onPause();
if (mIsRecording) {
stopRecording();
}
stopPreview();
}
private SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsSufaceCreated = false;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsSufaceCreated = true;
}
@Override
public 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;
}
@Override
public 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); // 设置视频的输出格式 为MP4
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); // 设置音频的编码格式
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // 设置视频的编码格式
mRecorder.setVideoSize(176, 144); // 设置视频大小
mRecorder.setVideoFrameRate(20); // 设置帧率
// mRecorder.setMaxDuration(10000); //设置最大录像时间为10s
mRecorder.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() {
@Override
public 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);
}
}
}
效果例如以下:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# Android
# MediaRecorder
# 录像
# android开发之调用手机的摄像头使用MediaRecorder录像并播放
# 视频文件
# 仅仅是
# 时间为
# 不加
# 重新启动
# 这句
# 每隔
# 回调
# 大家多多
# 有一个
# 实现了
# Size
# media
# os
# app
# Activity
# Parameters
# Environment
# Handler
# Log
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?
php做exe能调用系统命令吗_执行cmd指令实现方式【详解】
b2c电商网站制作流程,b2c水平综合的电商平台?
Laravel如何安装Breeze扩展包_Laravel用户注册登录功能快速实现【流程】
php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】
PHP怎么接收前端传的文件路径_处理文件路径参数接收方法【汇总】
ChatGPT 4.0官网入口地址 ChatGPT在线体验官网
怎样使用JSON进行数据交换_它有什么限制
EditPlus中的正则表达式实战(5)
如何快速查询网址的建站时间与历史轨迹?
网站建设整体流程解析,建站其实很容易!
JS中对数组元素进行增删改移的方法总结
电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?
Laravel怎么定时执行任务_Laravel任务调度器Schedule配置与Cron设置【教程】
Win11怎么关闭资讯和兴趣_Windows11任务栏设置隐藏小组件
在centOS 7安装mysql 5.7的详细教程
如何用花生壳三步快速搭建专属网站?
网易LOFTER官网链接 老福特网页版登录地址
Laravel Eloquent性能优化技巧_Laravel N+1查询问题解决
如何快速使用云服务器搭建个人网站?
Python正则表达式进阶教程_复杂匹配与分组替换解析
如何用景安虚拟主机手机版绑定域名建站?
linux写shell需要注意的问题(必看)
Laravel如何为API生成Swagger或OpenAPI文档
Laravel怎么设置路由分组Prefix_Laravel多级路由嵌套与命名空间隔离【步骤】
潮流网站制作头像软件下载,适合母子的网名有哪些?
米侠浏览器网页背景异常怎么办 米侠显示修复
Bootstrap整体框架之JavaScript插件架构
高防服务器如何保障网站安全无虞?
Laravel如何使用查询构建器?(Query Builder高级用法)
Laravel如何使用缓存系统提升性能_Laravel缓存驱动和应用优化方案
Laravel怎么实现观察者模式Observer_Laravel模型事件监听与解耦开发【指南】
Edge浏览器提示“由你的组织管理”怎么解决_去除浏览器托管提示【修复】
JavaScript Ajax实现异步通信
如何快速生成高效建站系统源代码?
C语言设计一个闪闪的圣诞树
iOS UIView常见属性方法小结
Linux系统命令中screen命令详解
怎么用AI帮你设计一套个性化的手机App图标?
如何挑选高效建站主机与优质域名?
Python文本处理实践_日志清洗解析【指导】
如何快速上传自定义模板至建站之星?
Windows10怎样连接蓝牙设备_Windows10蓝牙连接步骤【教程】
如何快速搭建高效香港服务器网站?
如何在景安云服务器上绑定域名并配置虚拟主机?
香港服务器网站搭建教程-电商部署、配置优化与安全稳定指南
Android GridView 滑动条设置一直显示状态(推荐)
JavaScript如何实现类型判断_typeof和instanceof有什么区别
教学论文网站制作软件有哪些,写论文用什么软件
?
Laravel怎么导出Excel文件_Laravel Excel插件使用教程

