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


相关推荐: Android中AutoCompleteTextView自动提示  Laravel如何与Inertia.js和Vue/React构建现代单页应用  消息称 OpenAI 正研发的神秘硬件设备或为智能笔,富士康代工  Laravel如何配置和使用队列处理异步任务_Laravel队列驱动与任务分发实例  如何基于云服务器快速搭建个人网站?  如何快速上传自定义模板至建站之星?  儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?  Laravel如何从数据库删除数据_Laravel destroy和delete方法区别  Laravel怎么实现API接口鉴权_Laravel Sanctum令牌生成与请求验证【教程】  Laravel如何使用Passport实现OAuth2?(完整配置步骤)  香港服务器网站测试全流程:性能评估、SEO加载与移动适配优化  Swift中swift中的switch 语句  php 三元运算符实例详细介绍  android nfc常用标签读取总结  Laravel如何记录自定义日志?(Log频道配置)  如何用PHP快速搭建高效网站?分步指南  Laravel如何实现文件上传和存储?(本地与S3配置)  清除minerd进程的简单方法  JavaScript Ajax实现异步通信  Python文件操作最佳实践_稳定性说明【指导】  安克发布新款氮化镓充电宝:体积缩小 30%,支持 200W 输出  JavaScript中如何操作剪贴板_ClipboardAPI怎么用  JS实现鼠标移上去显示图片或微信二维码  Python结构化数据采集_字段抽取解析【教程】  大连网站制作公司哪家好一点,大连买房网站哪个好?  Laravel如何实现用户密码重置功能?(完整流程代码)  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  html5如何实现懒加载图片_ intersectionobserver api用法【教程】  Laravel Facade的原理是什么_深入理解Laravel门面及其工作机制  Java遍历集合的三种方式  EditPlus 正则表达式 实战(3)  php后缀怎么变mp4格式错误_修改扩展名提示格式不对怎么办【技巧】  Laravel的路由模型绑定怎么用_Laravel Route Model Binding简化控制器逻辑  如何制作公司的网站链接,公司想做一个网站,一般需要花多少钱?  Laravel的HTTP客户端怎么用_Laravel HTTP Client发起API请求教程  网站制作大概多少钱一个,做一个平台网站大概多少钱?  网站制作壁纸教程视频,电脑壁纸网站?  如何用西部建站助手快速创建专业网站?  如何制作一个表白网站视频,关于勇敢表白的小标题?  如何快速生成高效建站系统源代码?  合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?  Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理  如何在橙子建站上传落地页?操作指南详解  如何将凡科建站内容保存为本地文件?  今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】  Win11怎么开启自动HDR画质_Windows11显示设置HDR选项  电视网站制作tvbox接口,云海电视怎样自定义添加电视源?  长沙企业网站制作哪家好,长沙水业集团官方网站?  油猴 教程,油猴搜脚本为什么会网页无法显示?  Laravel安装步骤详细教程_Laravel环境搭建指南