前言
Android除了支持播放多媒體文件之外,還可以從對應的硬件中捕獲多媒體,比如從麥克風錄音、從攝像頭錄像等。本篇博客講解一下Android下如何通過MediaRecorder進行錄音以及錄像的步驟,最后將以簡單的Demo演示。
本篇博客的主要內容:
MediaRecorder主要用於記錄音頻與視頻,它位於"android.media.MediaRecorder"下。它為開發人員提供了詳盡的AIP以完成記錄音頻與視頻的工作,下面簡單介紹一些常用的。
- void prepar():准備錄制。
- void start():開始錄制。
- void stop():停止錄制。
- void reset():重置MediaRecorder。
- void release():釋放MediaRecorder占用的資源。
- void setAudioEncoder(int):設置音頻記錄的編碼格式。
- void setAudoSource(int):設置音頻記錄的音頻源。
- void setOutoutFormat(int):設置記錄的媒體文件的輸出轉換格式。
- void setPreviewDisplay(Surface):設置視頻的預覽界面。
- void setVideoEncoder(int):設置視頻記錄的編碼格式。
- void setVideoSource(int):設置視頻記錄的視頻源。
- void setOutputFile(String):媒體文件輸出路徑。
- void setMaxDuration(int):設置最大記錄時長,單位為毫秒。
上面僅僅列出了一些常用的方法,但是通過這個方法可以看出MediaRecorder是需要在多個狀態之間切換的,准備、開始、停止、重置等等。MediaRecorder也為我們提供了一套狀態切換的規則,只有在既定的狀態下,才能完成對應的操作,下圖是官方文檔提供的狀態圖。
上圖非常直觀的展示了MediaRecorder的狀態間的轉換,這里只說幾點需要注意的地方:
- 當為MediaRecorder設定媒體錄入源之后即初始化完成,這個時候才可以為其設定其他的參數。
- 在開始錄制前必須先調用prepare()准備錄制。
- 只有在Initial初始化狀態,才可以對MediaRecorder調用release()釋放資源,其他狀態必須先stop()或者reset()。
- 錯誤狀態是游離在所有狀態之外的,當發生錯誤的時候,只有進行reset()才會進入Initial初始狀態。
MediaRecorder錄制視頻必不可少的步驟:
- 調用new MediaRecorder()構造函數得到MediaRecorder的實例。
- 調用setOutputFormat()設定媒體文件的輸出格式,必須在設定音頻與視頻的編碼格式之前設定。
- 如果需要記錄音頻,則調用setAudioSource()設定音頻的錄入源以及調用setAudioEncoder()設定音頻的編碼方式。
- 如果需要記錄視頻,則調用setVideoSource()設定視頻的錄入員以及調用setVideoEncoder()設定視頻的編碼方式。
- 調用setOutputFile()設定記錄的媒體文件保存的路徑。
- 先調用prepare()准備錄制,准備完成之后調用start()開始錄制。
- 記錄完成后,調用stop()停止錄制。
上面介紹了使用MediaRecorder錄制視頻必不可少的步驟,因為錄制音頻無需捕獲圖像,所以更簡單一些。下面直接通過一個簡單的示例,演示如何錄制音頻,錄制的音頻文件保存在sd根目錄下,注釋很詳細,這里不在累述了。布局很簡單,只有兩個Button,開始錄音、結束錄音,就不提供布局代碼了。
實現代碼:
1 package cn.bgxt.mediarecorderdemo; 2 3 import java.io.File; 4 import android.app.Activity; 5 import android.media.MediaRecorder; 6 import android.media.MediaRecorder.OnErrorListener; 7 import android.os.Bundle; 8 import android.view.View; 9 import android.view.View.OnClickListener; 10 import android.widget.Button; 11 import android.widget.Toast; 12 13 public class RecordActivity extends Activity { 14 private Button btn_RecordStart, btn_RecordStop; 15 private MediaRecorder mediaRecorder; 16 private boolean isRecording; 17 @Override 18 protected void onCreate(Bundle savedInstanceState) { 19 // TODO Auto-generated method stub 20 super.onCreate(savedInstanceState); 21 setContentView(R.layout.activity_record); 22 23 btn_RecordStart = (Button) findViewById(R.id.btn_RecordStart); 24 btn_RecordStop = (Button) findViewById(R.id.btn_RecordStop); 25 26 btn_RecordStop.setEnabled(false); 27 28 btn_RecordStart.setOnClickListener(click); 29 btn_RecordStop.setOnClickListener(click); 30 } 31 32 private View.OnClickListener click = new OnClickListener() { 33 34 @Override 35 public void onClick(View v) { 36 switch (v.getId()) { 37 case R.id.btn_RecordStart: 38 start(); 39 break; 40 case R.id.btn_RecordStop: 41 stop(); 42 break; 43 default: 44 break; 45 } 46 } 47 }; 48 49 /** 50 * 開始錄音 51 */ 52 protected void start() { 53 try { 54 File file = new File("/sdcard/mediarecorder.amr"); 55 if (file.exists()) { 56 // 如果文件存在,刪除它,演示代碼保證設備上只有一個錄音文件 57 file.delete(); 58 } 59 mediaRecorder = new MediaRecorder(); 60 // 設置音頻錄入源 61 mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 62 // 設置錄制音頻的輸出格式 63 mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 64 // 設置音頻的編碼格式 65 mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 66 // 設置錄制音頻文件輸出文件路徑 67 mediaRecorder.setOutputFile(file.getAbsolutePath()); 68 69 mediaRecorder.setOnErrorListener(new OnErrorListener() { 70 71 @Override 72 public void onError(MediaRecorder mr, int what, int extra) { 73 // 發生錯誤,停止錄制 74 mediaRecorder.stop(); 75 mediaRecorder.release(); 76 mediaRecorder = null; 77 isRecording=false; 78 btn_RecordStart.setEnabled(true); 79 btn_RecordStop.setEnabled(false); 80 Toast.makeText(RecordActivity.this, "錄音發生錯誤", 0).show(); 81 } 82 }); 83 84 // 准備、開始 85 mediaRecorder.prepare(); 86 mediaRecorder.start(); 87 88 isRecording=true; 89 btn_RecordStart.setEnabled(false); 90 btn_RecordStop.setEnabled(true); 91 Toast.makeText(RecordActivity.this, "開始錄音", 0).show(); 92 } catch (Exception e) { 93 e.printStackTrace(); 94 } 95 } 96 97 /** 98 * 錄音結束 99 */ 100 protected void stop() { 101 if (isRecording) { 102 // 如果正在錄音,停止並釋放資源 103 mediaRecorder.stop(); 104 mediaRecorder.release(); 105 mediaRecorder = null; 106 isRecording=false; 107 btn_RecordStart.setEnabled(true); 108 btn_RecordStop.setEnabled(false); 109 Toast.makeText(RecordActivity.this, "錄音結束", 0).show(); 110 } 111 } 112 113 @Override 114 protected void onDestroy() { 115 if (isRecording) { 116 // 如果正在錄音,停止並釋放資源 117 mediaRecorder.stop(); 118 mediaRecorder.release(); 119 mediaRecorder = null; 120 } 121 super.onDestroy(); 122 } 123 124 }
錄制音頻需要訪問麥克風設備,訪問設備需要添加權限:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
效果展示:
上面已經介紹了使用MediaRecorder錄制視頻的步驟,這里依照步驟一步一步寫代碼就可以了。下面通過一個簡單的Demo演示如何使用MediaRecorder錄制一段從攝像頭捕獲到的視頻,錄制的視頻文件將保持在SD卡上。布局很簡單,兩個Button,開始、停止,然后還有一個SurfaceView顯示預覽效果,就不給出布局代碼了。
實現代碼:
1 package cn.bgxt.mediarecorderdemo; 2 3 import java.io.File; 4 import java.io.IOException; 5 6 import android.app.Activity; 7 import android.media.MediaRecorder; 8 import android.media.MediaRecorder.OnErrorListener; 9 import android.os.Bundle; 10 import android.view.SurfaceHolder; 11 import android.view.SurfaceView; 12 import android.view.View; 13 import android.view.View.OnClickListener; 14 import android.widget.Button; 15 import android.widget.Toast; 16 17 public class VideoActivity extends Activity { 18 private Button btn_VideoStart, btn_VideoStop; 19 private SurfaceView sv_view; 20 private boolean isRecording; 21 private MediaRecorder mediaRecorder; 22 23 @Override 24 protected void onCreate(Bundle savedInstanceState) { 25 super.onCreate(savedInstanceState); 26 setContentView(R.layout.activity_video); 27 28 btn_VideoStart = (Button) findViewById(R.id.btn_VideoStart); 29 btn_VideoStop = (Button) findViewById(R.id.btn_VideoStop); 30 sv_view = (SurfaceView) findViewById(R.id.sv_view); 31 32 btn_VideoStop.setEnabled(false); 33 34 btn_VideoStart.setOnClickListener(click); 35 btn_VideoStop.setOnClickListener(click); 36 37 // 聲明Surface不維護自己的緩沖區,針對Android3.0以下設備支持 38 sv_view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 39 } 40 41 private View.OnClickListener click = new OnClickListener() { 42 43 @Override 44 public void onClick(View v) { 45 switch (v.getId()) { 46 case R.id.btn_VideoStart: 47 start(); 48 break; 49 case R.id.btn_VideoStop: 50 stop(); 51 break; 52 default: 53 break; 54 } 55 } 56 }; 57 58 protected void start() { 59 try { 60 File file = new File("/sdcard/video.mp4"); 61 if (file.exists()) { 62 // 如果文件存在,刪除它,演示代碼保證設備上只有一個錄音文件 63 file.delete(); 64 } 65 66 mediaRecorder = new MediaRecorder(); 67 mediaRecorder.reset(); 68 // 設置音頻錄入源 69 mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 70 // 設置視頻圖像的錄入源 71 mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 72 // 設置錄入媒體的輸出格式 73 mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 74 // 設置音頻的編碼格式 75 mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); 76 // 設置視頻的編碼格式 77 mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP); 78 // 設置視頻的采樣率,每秒4幀 79 mediaRecorder.setVideoFrameRate(4); 80 // 設置錄制視頻文件的輸出路徑 81 mediaRecorder.setOutputFile(file.getAbsolutePath()); 82 // 設置捕獲視頻圖像的預覽界面 83 mediaRecorder.setPreviewDisplay(sv_view.getHolder().getSurface()); 84 85 mediaRecorder.setOnErrorListener(new OnErrorListener() { 86 87 @Override 88 public void onError(MediaRecorder mr, int what, int extra) { 89 // 發生錯誤,停止錄制 90 mediaRecorder.stop(); 91 mediaRecorder.release(); 92 mediaRecorder = null; 93 isRecording=false; 94 btn_VideoStart.setEnabled(true); 95 btn_VideoStop.setEnabled(false); 96 Toast.makeText(VideoActivity.this, "錄制出錯", 0).show(); 97 } 98 }); 99 100 // 准備、開始 101 mediaRecorder.prepare(); 102 mediaRecorder.start(); 103 104 btn_VideoStart.setEnabled(false); 105 btn_VideoStop.setEnabled(true); 106 isRecording = true; 107 Toast.makeText(VideoActivity.this, "開始錄像", 0).show(); 108 } catch (Exception e) { 109 e.printStackTrace(); 110 } 111 112 } 113 114 protected void stop() { 115 if (isRecording) { 116 // 如果正在錄制,停止並釋放資源 117 mediaRecorder.stop(); 118 mediaRecorder.release(); 119 mediaRecorder = null; 120 isRecording=false; 121 btn_VideoStart.setEnabled(true); 122 btn_VideoStop.setEnabled(false); 123 Toast.makeText(VideoActivity.this, "停止錄像,並保存文件", 0).show(); 124 } 125 } 126 127 @Override 128 protected void onDestroy() { 129 if (isRecording) { 130 mediaRecorder.stop(); 131 mediaRecorder.release(); 132 mediaRecorder = null; 133 } 134 super.onDestroy(); 135 } 136 137 }
錄制視頻需要用到麥克風和攝像頭硬件,還需要賦予一些相應的權限。
1 <uses-permission android:name="android.permission.RECORD_AUDIO"/> 2 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 3 <uses-permission android:name="android.permission.CAMERA"/> 4 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
效果展示:
通過上面錄制視頻的Demo可以看出,使用MediaRecorder錄制視頻,需要設置一些錄入源、編碼格式、輸出格式等。這些方法都是以int類型的參數設定的,它們其實都是在MediaRecorder的內部類中已經以常量的形式定義好了,直接適用場景進行選擇即可。
- MediaRecorder.AudioEncoder:音頻的編碼格式。
- MediaRecorder.AudioSource:錄制的音頻源。
- MediaRecorder.OutputFormat:媒體文件的輸出編碼格式。
- MediaRecorder.VideoEncoder:視頻的編碼格式。
- MediaRecorder.VideoSource:錄制的視頻源。