使用MediaRecorder
進行錄影,要注意再設定MediaRecorder的引數的時候設定,這裡也是查了網上很多程式碼都沒有一個完整能實現的,或多或少都有點問題。
還有再暫停/繼續錄製的時候要注意將Camera
的預覽關閉camera.stopPreview()
不然預覽的介面還是會繼續動給人暫停了還在錄製的錯覺。
還有camera再使用之前記得要unlock
一下。至於設定MediaRecorder的引數,也是嘗試了好多次,最後選擇了使用profile
選擇影片質量來進行配置,這樣最簡單,可以考慮到影片大小的要求選擇預設的 720P等,但是注意要硬體適配的大小。
所以如果出現media start failed,那麼可以嘗試降低影片錄製引數來重新嘗試。
完整的VideoUtils
程式碼如下:
import android.hardware.Camera
import android.media.CamcorderProfile
import android.media.MediaRecorder
import android.os.Build
import android.view.Surface
import android.view.TextureView
import com.blankj.utilcode.util.PathUtils
import com.blankj.utilcode.util.PermissionUtils
import com.blankj.utilcode.util.ToastUtils
import java.io.File
import java.io.IOException
import java.lang.Exception
// 簽署時候,錄製影片的工具,包含錄製和播放
class VideoUtils {
companion object {
private var instance: VideoUtils ?= null
fun getInstance(): VideoUtils {
if (instance == null) {
instance = VideoUtils()
}
return instance!!
}
}
private var camera: Camera? = null
// 是否正在錄製
var isRecording: Boolean = false
// 是否開啟了錄製,初始化並開啟錄製,之後是暫停
var started: Boolean = false
private var mMediaRecorder: MediaRecorder ?= null
init {
mMediaRecorder = MediaRecorder()
}
private fun configMediaRecorder(textureView: TextureView){
val videoFile = File(PathUtils.getExternalDownloadsPath(),"record.mp4")
if (videoFile.exists()){
videoFile.delete()
}
camera = Camera.open(0)
camera?.stopPreview()
camera?.unlock()
val profile = CamcorderProfile.get( 0, CamcorderProfile.QUALITY_480P )
// val sizeList = camera.parameters.supportedVideoSizes
// val videoSize = sizeList.first()
mMediaRecorder?.setCamera(camera)
mMediaRecorder?.setAudioSource(MediaRecorder.AudioSource.CAMCORDER)//設定音訊輸入源 也可以使用 MediaRecorder.AudioSource.MIC
mMediaRecorder?.setVideoSource(MediaRecorder.VideoSource.CAMERA)//設定影片輸入源
mMediaRecorder?.setOutputFormat(profile.fileFormat)//音訊輸出格式
mMediaRecorder?.setAudioEncoder(profile.audioCodec)//設定音訊的編碼格式
mMediaRecorder?.setVideoEncoder(profile.videoCodec)//設定影像編碼格式
mMediaRecorder?.setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight)
mMediaRecorder?.setVideoFrameRate(profile.videoFrameRate)
mMediaRecorder?.setVideoEncodingBitRate(profile.videoBitRate)
mMediaRecorder?.setAudioEncodingBitRate(profile.audioBitRate)
mMediaRecorder?.setAudioSamplingRate(profile.audioSampleRate)
mMediaRecorder?.setAudioChannels(profile.audioChannels)
// mMediaRecorder?.setVideoFrameRate(20)//要錄製的影片幀率 幀率越高影片越流暢 如果設定裝置不支援的幀率會報錯 按照註釋說裝置會支援自動幀率所以一般情況下不需要設定
// mMediaRecorder?.setVideoSize(1080,780)//設定錄製影片的解析度 如果設定裝置不支援的解析度會報錯
// mMediaRecorder?.setVideoEncodingBitRate(5 * 100 * 100) //設定位元率,位元率是每一幀所含的位元組流數量,位元率越大每幀位元組越大,畫面就越清晰,演算法一般是 5 * 選擇解析度寬 * 選擇解析度高,一般可以調整5-10,位元率過大也會報錯
// mMediaRecorder?.setOrientationHint(360)//設定影片的攝像頭角度 只會改變錄製的影片檔案的角度(對預覽影像角度沒有效果)
val surface = Surface(textureView.getSurfaceTexture())
mMediaRecorder?.setOutputFile(videoFile.getAbsolutePath())//MP4檔案儲存路徑
mMediaRecorder?.setPreviewDisplay(surface)//設定拍攝預覽
}
fun startRecorder(textureView: TextureView) {
try {
MyPermissionUtils.requestMicrophonePermissions(object: PermissionUtils.SimpleCallback{
override fun onGranted() {
MyPermissionUtils.requestCameraPermissions(object: PermissionUtils.SimpleCallback{
override fun onGranted() {
try {
configMediaRecorder(textureView) //配置MediaRecorder 因為每一次停止錄製後呼叫重置方法後都會取消配置,所以每一次開始錄製都需要重新配置一次
mMediaRecorder!!.prepare() //準備
mMediaRecorder!!.start() //開啟
isRecording = true
started = true
} catch (e: Exception) {
ToastUtils.showShort(e.message)
e.printStackTrace()
}
}
override fun onDenied() {
ToastUtils.showShort("請開啟錄影許可權")
}
})
}
override fun onDenied() {
ToastUtils.showShort("請開啟錄音許可權")
}
})
} catch (e: IOException) {
e.printStackTrace()
}
}
fun stopRecorder() {
mMediaRecorder!!.stop() //暫停
mMediaRecorder!!.reset() //重置 重置後將進入空閒狀態,再次啟動錄製需要重新配置MediaRecorder
camera?.stopPreview()
camera?.release()
camera?.lock()
isRecording = false
started = false
}
fun pauseRecorder() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mMediaRecorder!!.pause() //暫停
camera?.stopPreview()
isRecording = false
}
}
fun resumeRecorder() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mMediaRecorder!!.resume() //恢復
camera?.startPreview()
isRecording = true
}
}
fun destroy() {
if (mMediaRecorder != null) {
mMediaRecorder!!.stop()
mMediaRecorder!!.release() //釋放 釋放之前需要先呼叫stop()
// 攝像頭關閉預覽和釋放
camera?.stopPreview()
camera?.release()
mMediaRecorder = null
}
instance = null
}
}