前言
这个博客本来是用来详细介绍MediaRecorder与Camera2,但是出乎预料之外,在获取mMediaRecorder.getSurface();的时候无论如何都是报错的,报错为Surface没有初始化.我查阅了相当多网址甚至在国外网址上查看都没查到问题如何解决(问题查到了都没给出解决办法).所以下面的代码只做临时记录后续将继续看看此问题到底怎么解决.后续看看google官网文档怎么搞的
代码部分
package demo.yt.com.demo; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Camera; import android.graphics.ImageFormat; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.MediaRecorder; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.util.DisplayMetrics; import android.util.Log; import android.util.Size; 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.ArrayList; import java.util.Arrays; import java.util.List; public class MedioRecorderCamera2Activity extends AppCompatActivity { private static final String TAG = MedioRecorderCamera2Activity.class.getSimpleName(); private Button mBtnStatr,mBtnFinish; private TextureView mTextureView; private CameraManager mCameraManager; private CameraDevice mCameraDevice; private CameraCaptureSession mCameraCaptureSession; private CameraDevice.StateCallback mCameraDeviceStateCallback; private CameraCaptureSession.StateCallback mSessionStateCallback; private CameraCaptureSession.CaptureCallback mSessionCaptureCallback; private CaptureRequest.Builder mPreviewCaptureRequest; private CaptureRequest.Builder mRecorderCaptureRequest; private MediaRecorder mMediaRecorder; private String mCurrentSelectCamera; private Handler mChildHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_medio_recorder_camera2); mTextureView = findViewById(R.id.textureview); mBtnStatr = findViewById(R.id.btn_start); mBtnFinish = findViewById(R.id.btn_finish); initClickListener(); initChildHandler(); initTextureViewStateListener(); initMediaRecorder(); initCameraDeviceStateCallback(); initSessionStateCallback(); initSessionCaptureCallback(); } private void initClickListener(){ mBtnStatr.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { config(); startRecorder(); } }); mBtnFinish.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopRecorder(); } }); } private void initTextureViewStateListener(){ mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { initCameraManager(); selectCamera(); openCamera(); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } }); } private void initChildHandler(){ HandlerThread handlerThread = new HandlerThread("Camera2Demo"); handlerThread.start(); mChildHandler = new Handler(handlerThread.getLooper()); } private void initMediaRecorder(){ mMediaRecorder = new MediaRecorder(); } private void configMediaRecorder(){ File file = new File(getExternalCacheDir(),"demo.mp4"); if (file.exists()){ file.delete(); } mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT); mMediaRecorder.setVideoEncodingBitRate(8*1024*1920); mMediaRecorder.setVideoFrameRate(30); Size size = getMatchingSize2(); mMediaRecorder.setVideoSize(size.getWidth(),size.getHeight()); mMediaRecorder.setOrientationHint(90); Surface surface = new Surface(mTextureView.getSurfaceTexture()); mMediaRecorder.setPreviewDisplay(surface); mMediaRecorder.setOutputFile(file.getAbsolutePath()); try { mMediaRecorder.prepare(); } catch (IOException e) { e.printStackTrace(); } } private void config(){ try { mCameraCaptureSession.stopRepeating(); mCameraCaptureSession.close(); mCameraCaptureSession = null; } catch (CameraAccessException e) { e.printStackTrace(); } configMediaRecorder(); Size cameraSize = getMatchingSize2(); SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture(); surfaceTexture.setDefaultBufferSize(cameraSize.getWidth(),cameraSize.getHeight()); Surface previewSurface = new Surface(surfaceTexture); Surface recorderSurface = mMediaRecorder.getSurface(); try { mPreviewCaptureRequest = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewCaptureRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); mPreviewCaptureRequest.addTarget(previewSurface); mPreviewCaptureRequest.addTarget(recorderSurface); mCameraDevice.createCaptureSession(Arrays.asList(previewSurface,recorderSurface),mSessionStateCallback,mChildHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } private void startRecorder(){ mMediaRecorder.start(); } private void stopRecorder(){ mMediaRecorder.stop(); mMediaRecorder.reset(); configMediaRecorder(); } private void initCameraManager(){ mCameraManager = (CameraManager)getSystemService(Context.CAMERA_SERVICE); } private void selectCamera(){ if (mCameraManager != null) { Log.e(TAG, "selectCamera: CameraManager is null"); } try { String[] cameraIdList = mCameraManager.getCameraIdList(); if (cameraIdList.length == 0){ Log.e(TAG, "selectCamera: cameraIdList length is 0"); } for (String cameraId : cameraIdList){ CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId); Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (facing == CameraCharacteristics.LENS_FACING_BACK){ mCurrentSelectCamera = cameraId; } } } catch (CameraAccessException e) { e.printStackTrace(); } } private void initCameraDeviceStateCallback(){ mCameraDeviceStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { try { mCameraDevice = camera; Size cameraSize = getMatchingSize2(); SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture(); surfaceTexture.setDefaultBufferSize(cameraSize.getWidth(),cameraSize.getHeight()); Surface previewSurface = new Surface(surfaceTexture); mPreviewCaptureRequest = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewCaptureRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); mPreviewCaptureRequest.addTarget(previewSurface); mCameraDevice.createCaptureSession(Arrays.asList(previewSurface),mSessionStateCallback,mChildHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onDisconnected(@NonNull CameraDevice camera) { } @Override public void onError(@NonNull CameraDevice camera, int error) { } }; } private void initSessionStateCallback(){ mSessionStateCallback = new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { mCameraCaptureSession = session; try { mCameraCaptureSession.setRepeatingRequest(mPreviewCaptureRequest.build(),mSessionCaptureCallback,mChildHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { } }; } private void initSessionCaptureCallback(){ mSessionCaptureCallback = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) { super.onCaptureStarted(session, request, timestamp, frameNumber); } @Override public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { super.onCaptureProgressed(session, request, partialResult); } @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); } @Override public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) { super.onCaptureFailed(session, request, failure); } }; } @SuppressLint("MissingPermission") private void openCamera(){ try { mCameraManager.openCamera(mCurrentSelectCamera,mCameraDeviceStateCallback,mChildHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } private Size getMatchingSize2(){ Size selectSize = null; try { CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCurrentSelectCamera); StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); Size[] sizes = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG); DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); //因为我这里是将预览铺满屏幕,所以直接获取屏幕分辨率 int deviceWidth = displayMetrics.widthPixels; //屏幕分辨率宽 int deviceHeigh = displayMetrics.heightPixels; //屏幕分辨率高 Log.e(TAG, "getMatchingSize2: 屏幕密度宽度="+deviceWidth); Log.e(TAG, "getMatchingSize2: 屏幕密度高度="+deviceHeigh ); /** * 循环40次,让宽度范围从最小逐步增加,找到最符合屏幕宽度的分辨率, * 你要是不放心那就增加循环,肯定会找到一个分辨率,不会出现此方法返回一个null的Size的情况 * ,但是循环越大后获取的分辨率就越不匹配 */ for (int j = 1; j < 41; j++) { for (int i = 0; i < sizes.length; i++) { //遍历所有Size Size itemSize = sizes[i]; Log.e(TAG,"当前itemSize 宽="+itemSize.getWidth()+"高="+itemSize.getHeight()); //判断当前Size高度小于屏幕宽度+j*5 && 判断当前Size高度大于屏幕宽度-j*5 && 判断当前Size宽度小于当前屏幕高度 if (itemSize.getHeight() < (deviceWidth + j*5) && itemSize.getHeight() > (deviceWidth - j*5)) { if (selectSize != null){ //如果之前已经找到一个匹配的宽度 if (Math.abs(deviceHeigh-itemSize.getWidth()) < Math.abs(deviceHeigh - selectSize.getWidth())){ //求绝对值算出最接近设备高度的尺寸 selectSize = itemSize; continue; } }else { selectSize = itemSize; } } } if (selectSize != null){ //如果不等于null 说明已经找到了 跳出循环 break; } } } catch (CameraAccessException e) { e.printStackTrace(); } Log.e(TAG, "getMatchingSize2: 选择的分辨率宽度="+selectSize.getWidth()); Log.e(TAG, "getMatchingSize2: 选择的分辨率高度="+selectSize.getHeight()); return selectSize; } }