MediaRecorder能夠不依靠Camera API 實現視頻的錄製,可是若是須要切換攝像頭/設置對焦/選擇分辨率等等就須要Camera來參與配合錄製視頻.這篇博客將介紹使用Camera1來實現視頻錄製.此篇博客不在重複一些細節和坑的介紹.若是你剛接觸建議你看我另外一篇博客http://www.javashuo.com/article/p-rrzbrcau-hh.html這篇博客用更簡單易懂的形式說明了MediaRecorder錄製視頻的步驟,而且有大量深坑的詳解介紹,防止你也掉坑裏.html
關鍵點有大量註釋,就不作另外篇幅的介紹java
若是你對下面代碼裏的計算分辨率不甚理解,能夠去我另外一篇博客有更詳細的講解分辨率的計算,這篇博客雖然是拿Camera2 API來計算分辨率,可是原理是同樣的. 傳送門:http://www.javashuo.com/article/p-vqopnfok-ko.htmlandroid
若是你對Camera自動對焦不太理解,能夠去我另外一篇更詳細的博客有介紹Camera1的自動對焦. 傳送門:http://www.javashuo.com/article/p-mzlzotgk-hu.html安全
import androidx.appcompat.app.AppCompatActivity; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.media.MediaRecorder; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.DisplayMetrics; import android.util.Log; import android.view.Surface; import android.view.TextureView; import android.view.View; import android.widget.Button; import java.io.File; import java.io.IOException; import java.util.List; public class MedioRecorderCamera1Activity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = MedioRecorderCamera1Activity.class.getSimpleName(); private TextureView mTextureview; private Button mBtnStart, mBtnFinish; private MediaRecorder mMediaRecorder; private Camera mCamera; private Camera.Size mSelectSize;//記錄當前選擇的分辨率 private boolean isRecorder = false;//用於判斷當前是否在錄製視頻 private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 0x01: mCamera.autoFocus(new Camera.AutoFocusCallback() { //自動對焦 @Override public void onAutoFocus(boolean success, Camera camera) { } }); mHandler.sendEmptyMessageDelayed(0x01,2*1000);//2秒以後在對焦一次,一直重複自動對焦 break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_medio_recorder_camera1); mTextureview = findViewById(R.id.textureview); mBtnStart = findViewById(R.id.btn_start); mBtnFinish = findViewById(R.id.btn_finish); mBtnStart.setOnClickListener(this); mBtnFinish.setOnClickListener(this); initTextureViewListener(); initMediaRecorder(); } /** * 初始化TextureView監聽 */ private void initTextureViewListener(){ mTextureview.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { //Textureview初始化啓用回調 initCamera(); initCameraConfig(); try { mCamera.setPreviewTexture(surface); mCamera.startPreview(); mHandler.sendEmptyMessage(0x01);//啓動對焦 } catch (IOException e) { e.printStackTrace(); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } }); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.btn_start: startRecorder(); break; case R.id.btn_finish: stopRecorder(); break; default: break; } } /** * 初始化MediaRecorder */ private void initMediaRecorder(){ mMediaRecorder = new MediaRecorder(); } /** * 選擇攝像頭 * @param isFacing true=前攝像頭 false=後攝像頭 * @return 攝像id */ private Integer selectCamera(boolean isFacing){ int cameraCount = Camera.getNumberOfCameras(); // CameraInfo.CAMERA_FACING_BACK 後攝像頭 // CameraInfo.CAMERA_FACING_FRONT 前攝像頭 int facing = isFacing ? Camera.CameraInfo.CAMERA_FACING_FRONT : Camera.CameraInfo.CAMERA_FACING_BACK; Log.e(TAG, "selectCamera: cameraCount="+cameraCount); if (cameraCount == 0){ Log.e(TAG, "selectCamera: The device does not have a camera "); return null; } Camera.CameraInfo info = new Camera.CameraInfo(); for (int i=0; i < cameraCount; i++){ Camera.getCameraInfo(i,info); if (info.facing == facing){ return i; } } return null; } /** * 初始化相機 */ private void initCamera(){ mCamera = Camera.open(selectCamera(false)); mSelectSize = selectPreviewSize(mCamera.getParameters()); } /** * 初始化相機配置 */ private void initCameraConfig(){ Camera.Parameters parameters = mCamera.getParameters(); parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);//關閉閃光燈 parameters.setFocusMode(Camera.Parameters.FLASH_MODE_AUTO); //對焦設置爲自動 parameters.setPreviewSize(mSelectSize.width,mSelectSize.height);//設置預覽尺寸 parameters.setPictureSize(mSelectSize.width,mSelectSize.height);//設置圖片尺寸 就拿預覽尺寸做爲圖片尺寸,其實他們基本上是同樣的 parameters.set("orientation", "portrait");//相片方向 parameters.set("rotation", 90); //相片鏡頭角度轉90度(默認攝像頭是橫拍) mCamera.setParameters(parameters);//添加參數 mCamera.setDisplayOrientation(90);//設置顯示方向 } /** * 計算獲取預覽尺寸 * @param parameters * @return */ private Camera.Size selectPreviewSize(Camera.Parameters parameters){ List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes(); if (previewSizeList.size() == 0){ Log.e(TAG, "selectPreviewSize: previewSizeList size is 0" ); return null; } Camera.Size currentSelectSize = null; DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); int deviceWidth =displayMetrics.widthPixels; int deviceHeight = displayMetrics.heightPixels; for (int i = 1; i < 41 ; i++){ for(Camera.Size itemSize : previewSizeList){ // Log.e(TAG, "selectPreviewSize: itemSize 寬="+itemSize.width+"高"+itemSize.height); if (itemSize.height > (deviceWidth - i*5) && itemSize.height < (deviceWidth + i*5)){ if (currentSelectSize != null){ //若是以前已經找到一個匹配的寬度 if (Math.abs(deviceHeight-itemSize.width) < Math.abs(deviceHeight - currentSelectSize.width)){ //求絕對值算出最接近設備高度的尺寸 currentSelectSize = itemSize; continue; } }else { currentSelectSize = itemSize; } } } } Log.e(TAG, "selectPreviewSize: 當前選擇的尺寸 寬="+currentSelectSize.width+"高"+currentSelectSize.height); return currentSelectSize; } /** * 配置MedioRecorder */ private void configMedioRecorder(){ File saveRecorderFile = new File(getExternalCacheDir(),"CameraRecorder.mp4"); if (saveRecorderFile.exists()){ saveRecorderFile.delete(); } mCamera.unlock(); mMediaRecorder.setCamera(mCamera); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);//設置音頻源 mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);//設置視頻源 mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);//設置音頻輸出格式 mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);//設置音頻編碼格式 mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);//設置視頻編碼格式 mMediaRecorder.setVideoSize(mSelectSize.width,mSelectSize.height);//設置視頻分辨率 mMediaRecorder.setVideoEncodingBitRate(8*1920*1080);//設置視頻的比特率 mMediaRecorder.setVideoFrameRate(60);//設置視頻的幀率 mMediaRecorder.setOrientationHint(90);//設置視頻的角度 mMediaRecorder.setMaxDuration(60*1000);//設置最大錄製時間 Surface surface = new Surface(mTextureview.getSurfaceTexture()); mMediaRecorder.setPreviewDisplay(surface);//設置預覽 mMediaRecorder.setOutputFile(saveRecorderFile.getAbsolutePath());//設置文件保存路徑 mMediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() { //錄製異常監聽 @Override public void onError(MediaRecorder mr, int what, int extra) { mMediaRecorder.stop(); mMediaRecorder.reset(); try { mCamera.setPreviewTexture(mTextureview.getSurfaceTexture()); mCamera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } }); } /** * 開啓錄製視頻 */ private void startRecorder(){ if (!isRecorder) {//若是不在錄製視頻 mCamera.stopPreview();//暫停相機預覽 configMedioRecorder();//再次配置MedioRecorder try { mMediaRecorder.prepare();//準備錄製 } catch (IOException e) { e.printStackTrace(); } mMediaRecorder.start();//開始錄製 isRecorder = true; } } /** * 中止錄製視頻 */ private void stopRecorder(){ if (isRecorder){ //若是在錄製視頻 mMediaRecorder.stop();//暫停錄製 mMediaRecorder.reset();//重置,將MediaRecorder調整爲空閒狀態 isRecorder = false; try { mCamera.setPreviewTexture(mTextureview.getSurfaceTexture());//從新設置預覽SurfaceTexture mCamera.startPreview(); //從新開啓相機預覽 mCamera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { } }); } catch (IOException e) { e.printStackTrace(); } } } @Override protected void onDestroy() { super.onDestroy(); if (mMediaRecorder != null){ if (isRecorder) { mMediaRecorder.stop(); } mMediaRecorder.release(); mMediaRecorder = null; } if (mCamera != null){ mCamera.stopPreview(); mCamera.release(); mCamera = null; } } }
這裏說明一下爲何在配置MediaRecorder的時候大量使用DEFAULT 默認模式,是由於若是選定一個模式,並不必定全部機型都是適配的,全部爲了安全適配全部機型這裏最好選擇默認.app
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);//設置音頻源 mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);//設置視頻源 mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);//設置音頻輸出格式 mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);//設置音頻編碼格式 mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);//設置視頻編碼格式