当前位置: 首页 > wzjs >正文

网站建设指南 菜鸟教程系统开发费用明细

网站建设指南 菜鸟教程,系统开发费用明细,福建泉州做淘宝的拿货什么网站,淘客推广软件MediaRecorder 是 Android 官方提供的一个用于音视频录制的类,简化了音频和视频的录制过程,如果只是想单纯的录制视频,MediaRecorder是一个不错的选择 这里采用 Camera2 MediaRecorder 的方式实现视频录制 步骤: 获取 CameraM…

 MediaRecorder 是 Android 官方提供的一个用于音视频录制的类,简化了音频和视频的录制过程,如果只是想单纯的录制视频,MediaRecorder是一个不错的选择

这里采用 Camera2 + MediaRecorder 的方式实现视频录制

步骤:

  1. 获取 CameraManager 实例
  2. 调用 openCamera,打开摄像头
  3. 创建 session
  4. 开启预览
  5. 开启录制
  6. 停止录制

一、获取CameraManager 实例

// 1. 先获取 CameraManager
mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);

通过 getSystemService(Context.Camera_SERVICE) 即可获取到 CameraManager 的实例,CameraManager 是一个负责查询和建立相机连接的系统服务,Camera2 的所有操作都是从先获取 CameraManager 实例开始

二、调用 openCamera,打开摄像头

// 2. 调用 openCamera,打开摄像头
mCameraManager.openCamera(String.valueOf(mCurrentFacing), new CameraDevice.StateCallback() {@Overridepublic void onOpened(@NonNull CameraDevice camera) {LogUtil.d(TAG, "onOpened: 摄像头链接成功, facing: " + mCurrentFacing);// 摄像头成功打开mCurrentCameraDevice = camera;}
​@Overridepublic void onDisconnected(@NonNull CameraDevice camera) {LogUtil.d(TAG, "onDisconnected: 摄像头链接断开");}
​@Overridepublic void onError(@NonNull CameraDevice camera, int error) {LogUtil.d(TAG, "onError: 摄像头打开失败, error: " + error);camera.close();}
}, null);

使用上一步获取到的 CameraManager 实例,调用 openCamera 方法,即可获取到指定摄像头的 CameraDevice 实例,可以对指定摄像头进行操作

三、创建 session

// 3. 创建session,可以看到这里绑定了两个 surface,一个用于承载预览显示,一个用于视频录制
List<Surface> mOutputs = new ArrayList<>();
mOutputs.add(mPreviewSurface);
mOutputs.add(mRecordSurface);
mCurrentCameraDevice.createCaptureSession(mOutputs, new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession session) {mCurrentCameraCaptureSession = session;try {// 4. 开启预览createPreviewCaptureRequest();mCurrentCameraCaptureSession.setRepeatingRequest(mCurrentPreviewRequest, null, null);} catch (CameraAccessException e) {LogUtil.e(TAG, "onConfigured: ", e);}}
​@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession session) {
​}
}, null);

Camera2 比较特殊的点就是,所有的操作行为都是在 session 上完成的,所以 打开摄像头之后,通过 CameraDevice 实例创建指定的 session

值得注意的是,在 createSession 的时候有一个绑定 surface 的操作,这关系到后续能在 session 上执行什么操作,如果需要预览,那需要绑定 承载预览流的 previewSurface,如果需要录制视频,需要绑定 承载视频流的 recordSurface,如果需要拍照,则需要绑定 承载拍照数据的 imageReader

这里我们需要预览和录制,所以绑定了两个surface,一个用于预览,一个用于录制

四、开启预览

// 4. 开启预览
createPreviewCaptureRequest();
mCurrentCameraCaptureSession.setRepeatingRequest(mCurrentPreviewRequest, null, null);
​
/*** 用于预览显示的request*/
private void createPreviewCaptureRequest() {try {CaptureRequest.Builder mCurrentPreviewRequestBuilder = mCurrentCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);mCurrentPreviewRequestBuilder.addTarget(mPreviewSurface);mCurrentPreviewRequest = mCurrentPreviewRequestBuilder.build();} catch (CameraAccessException e) {LogUtil.e(TAG, "createPreviewCaptureRequest: ", e);}
}

createSession 成功之后,就可以 创建 CaptureRequest,然后通过 session 的 setRepeatingRequest 方法开始呈现预览了

如果只需要呈现预览,到这里已经完成了,接下来开始录制

五、开启录制

private void startRecording(){isRecording = true;try {// 5. 开启录制// 先准备 mediaRecorderprepareMediaRecorder();// 创建录制视频用的 requestcreateVideoRecordCaptureRequest();// 先将 PreviewRequest 停掉,因为 PreviewRequest 只绑定了一个previewSurface target,录制的时候还需要绑定 recordSurface targetmCurrentCameraCaptureSession.stopRepeating();// 开始 recordRequest 请求mCurrentCameraCaptureSession.setRepeatingRequest(mVideoRecordRequest, null, null);// 开始录制mMediaRecorder.start();} catch (CameraAccessException e) {LogUtil.e(TAG, "startRecording: ", e);}
}
​
private void prepareMediaRecorder(){try {// 这里很重要的一个点 mediaRecorder 的复用,不需要每次重新 new 一个新的if(mMediaRecorder == null){mMediaRecorder = new MediaRecorder();}else {// 如果 mMediaRecorder 存在,只需要重新 reset 就行mMediaRecorder.reset();}// surface 通过 MediaCodec.createPersistentInputSurface() 创建,// 然后通过 setInputSurface 的方式设置给 MediaRecorder// 这个 surface 也会在 createSession 时和 previewSurface 一起传入,这样开始录制时就不需要重新创建 sessionif(mRecordSurface == null){mRecordSurface = MediaCodec.createPersistentInputSurface();}mMediaRecorder.setInputSurface(mRecordSurface);mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);// 设置视频文件地址,需要读写权限mMediaRecorder.setOutputFile(mVideoFilePath);mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());mMediaRecorder.setVideoFrameRate(25);mMediaRecorder.setOrientationHint(90);// prepare 执行之后 才能使用mMediaRecorder.prepare();} catch (IOException e) {LogUtil.e(TAG, "prepareMediaRecorder: ", e);}
}
​
/*** 用于录制视频的request*/
private void createVideoRecordCaptureRequest(){try {CaptureRequest.Builder builder = mCurrentCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);// 用于承载录制视频流builder.addTarget(mRecordSurface);// 用于承载预览显示流builder.addTarget(mPreviewSurface);mVideoRecordRequest = builder.build();} catch (CameraAccessException e) {LogUtil.e(TAG, "createVideoRecordCaptureRequest: ", e);}
}

对于视频录制,我们用到了 MediaRecorder,先准备好 MediaRecorder,然后调用 start 方法就可以开始录制了,这里有一个点,MediaRecorder 录制所需要的视频流数据从哪里来,如何和 Camera 绑定?

我们可以先创建 surface,和 MediaRecorder 绑定

if(mRecordSurface == null){mRecordSurface = MediaCodec.createPersistentInputSurface();
}
mMediaRecorder.setInputSurface(mRecordSurface);

还记得上面我们创建 session 的时候绑定了两个 surface,其中一个就是 mRecorderSurface,通过这种方式

  1. mRecordSurface 通过 RepeatingRequest ,持续的从底层拿到了视频流数据

  2. MediaRecorder 又从 mRecordSurface 中拿到视频流数据合成视频

六、停止录制

private void stopRecording(){isRecording = false;// 6. 结束录制if(mMediaRecorder != null){// 停止录制mMediaRecorder.stop();}if(mCurrentCameraCaptureSession != null){try {// 先将 RecordRequest 请求停掉,因为录制停止之后,只需要一个预览流即可,降低功耗mCurrentCameraCaptureSession.stopRepeating();mCurrentCameraCaptureSession.setRepeatingRequest(mCurrentPreviewRequest, null, null);} catch (CameraAccessException e) {LogUtil.e(TAG, "stopRecording: ", e);}}
}

只需要调用 stop 方法,就可以停止视频录制,这里我们还是做了一个功耗优化,停掉了当前的 repeatingRequset,重新只发送只有一个 previewSurface 的 repeatingRequset,这样可以在预览时减少一路流的消耗,降低功耗

完整代码

public class VideoRecord2Activity extends AppCompatActivity {private static final String TAG = "VideoRecordActivity";
​private Context mContext;private CameraManager mCameraManager;private int mFacingFront = -1;private int mFacingBack = -1;private int mCurrentFacing = mFacingFront;
​private CameraDevice mCurrentCameraDevice;private CaptureRequest mCurrentPreviewRequest;private TextureView mTextureView;private Surface mPreviewSurface;private CameraCaptureSession mCurrentCameraCaptureSession;
​private Button mBtnTakePicture;
​private Size mVideoSize = new Size(810,720);
​private boolean isRecording = false;private MediaRecorder mMediaRecorder;private Surface mRecordSurface;private CaptureRequest mVideoRecordRequest;private String mVideoFilePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + "/video.mp4";
​@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_video_record);getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);this.mContext = this;initView();initCamera();mCurrentFacing = mFacingBack;}
​private void initView() {mTextureView = findViewById(R.id.view_camera_texture);mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {@Overridepublic void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {// 这里解释一下,为什么摄像头打开的时候没有马上打开预览,因为预览画面的展示需要 surface 承载,所以需要等 surface 准备好才行surface.setDefaultBufferSize(mVideoSize.getWidth(),mVideoSize.getHeight());// 预览所需的 previewSurfacemPreviewSurface = new Surface(surface);// 准备视频录制时所需的 recordSurfaceprepareMediaRecorder();startPreview();}
​@Overridepublic void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
​}
​@Overridepublic boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {mPreviewSurface.release();mPreviewSurface = null;return false;}
​@Overridepublic void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
​}});
​mBtnTakePicture = findViewById(R.id.btn_take_picture);mBtnTakePicture.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {LogUtil.d(TAG, "onClick: 点击拍照");if(isRecording){stopRecording();mBtnTakePicture.setText("录制");}else {startRecording();mBtnTakePicture.setText("停止");}}});}
​private void initCamera() {// 1. 先获取 CameraManagermCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);if (mCameraManager == null) {return;}try {for (String cameraId : mCameraManager.getCameraIdList()) {CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);int facing = characteristics.get(CameraCharacteristics.LENS_FACING);if (facing == CameraCharacteristics.LENS_FACING_FRONT) {mFacingFront = Integer.parseInt(cameraId);int supportLEVEL = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);LogUtil.d(TAG, "testCamera2: 当前是前摄,supportLEVEL: " + supportLEVEL);} else if (facing == CameraCharacteristics.LENS_FACING_BACK) {mFacingBack = Integer.parseInt(cameraId);int supportLEVEL = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);LogUtil.d(TAG, "testCamera2: 当前是后摄,supportLEVEL: " + supportLEVEL);}}} catch (CameraAccessException e) {Log.e(TAG, "testCamera2: ", e);}}
​private void openCamera(){closeCamera();if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {return;}try {// 2. 调用 openCamera,打开摄像头mCameraManager.openCamera(String.valueOf(mCurrentFacing), new CameraDevice.StateCallback() {@Overridepublic void onOpened(@NonNull CameraDevice camera) {LogUtil.d(TAG, "onOpened: 摄像头链接成功, facing: " + mCurrentFacing);// 摄像头成功打开mCurrentCameraDevice = camera;}
​@Overridepublic void onDisconnected(@NonNull CameraDevice camera) {LogUtil.d(TAG, "onDisconnected: 摄像头链接断开");}
​@Overridepublic void onError(@NonNull CameraDevice camera, int error) {LogUtil.d(TAG, "onError: 摄像头打开失败, error: " + error);camera.close();}}, null);} catch (CameraAccessException e) {Log.e(TAG, "openCamera: ", e);}}
​private void startPreview(){if(mCurrentCameraDevice == null){return;}if(mPreviewSurface == null){return;}try {// 3. 创建session,可以看到这里绑定了两个 surface,一个用于承载预览显示,一个用于视频录制List<Surface> mOutputs = new ArrayList<>();mOutputs.add(mPreviewSurface);mOutputs.add(mRecordSurface);mCurrentCameraDevice.createCaptureSession(mOutputs, new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession session) {mCurrentCameraCaptureSession = session;try {// 4. 开启预览createPreviewCaptureRequest();mCurrentCameraCaptureSession.setRepeatingRequest(mCurrentPreviewRequest, null, null);} catch (CameraAccessException e) {LogUtil.e(TAG, "onConfigured: ", e);}}
​@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession session) {
​}}, null);} catch (CameraAccessException e) {LogUtil.e(TAG, "startPreview: ", e);}}
​/*** 用于预览显示的request*/private void createPreviewCaptureRequest() {try {CaptureRequest.Builder mCurrentPreviewRequestBuilder = mCurrentCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);mCurrentPreviewRequestBuilder.addTarget(mPreviewSurface);mCurrentPreviewRequest = mCurrentPreviewRequestBuilder.build();} catch (CameraAccessException e) {LogUtil.e(TAG, "createPreviewCaptureRequest: ", e);}}
​/*** 用于录制视频的request*/private void createVideoRecordCaptureRequest(){try {CaptureRequest.Builder builder = mCurrentCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);// 用于承载录制视频流builder.addTarget(mRecordSurface);// 用于承载预览显示流builder.addTarget(mPreviewSurface);mVideoRecordRequest = builder.build();} catch (CameraAccessException e) {LogUtil.e(TAG, "createVideoRecordCaptureRequest: ", e);}}
​private void closeCamera(){if(mCurrentCameraDevice != null){mCurrentCameraDevice.close();mCurrentCameraDevice = null;}}
​@Overrideprotected void onResume() {super.onResume();openCamera();}
​@Overrideprotected void onPause() {super.onPause();closeCamera();if(mMediaRecorder != null){mMediaRecorder.release();mMediaRecorder = null;}if(mRecordSurface != null){mRecordSurface.release();mRecordSurface = null;}}
​private void prepareMediaRecorder(){try {// 这里很重要的一个点 mediaRecorder 的复用,不需要每次重新 new 一个新的if(mMediaRecorder == null){mMediaRecorder = new MediaRecorder();}else {// 如果 mMediaRecorder 存在,只需要重新 reset 就行mMediaRecorder.reset();}// surface 通过 MediaCodec.createPersistentInputSurface() 创建,// 然后通过 setInputSurface 的方式设置给 MediaRecorder// 这个 surface 也会在 createSession 时和 previewSurface 一起传入,这样开始录制时就不需要重新创建 sessionif(mRecordSurface == null){mRecordSurface = MediaCodec.createPersistentInputSurface();}mMediaRecorder.setInputSurface(mRecordSurface);mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);// 设置视频文件地址,需要读写权限mMediaRecorder.setOutputFile(mVideoFilePath);mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());mMediaRecorder.setVideoFrameRate(25);mMediaRecorder.setOrientationHint(90);// prepare 执行之后 才能使用mMediaRecorder.prepare();} catch (IOException e) {LogUtil.e(TAG, "prepareMediaRecorder: ", e);}}
​private void startRecording(){isRecording = true;try {// 5. 开启录制// 先准备 mediaRecorderprepareMediaRecorder();// 创建录制视频用的 requestcreateVideoRecordCaptureRequest();// 先将 PreviewRequest 停掉,因为 PreviewRequest 只绑定了一个previewSurface target,录制的时候还需要绑定 recordSurface targetmCurrentCameraCaptureSession.stopRepeating();// 开始 recordRequest 请求mCurrentCameraCaptureSession.setRepeatingRequest(mVideoRecordRequest, null, null);// 开始录制mMediaRecorder.start();} catch (CameraAccessException e) {LogUtil.e(TAG, "startRecording: ", e);}}
​private void stopRecording(){isRecording = false;// 6. 结束录制if(mMediaRecorder != null){// 停止录制mMediaRecorder.stop();}if(mCurrentCameraCaptureSession != null){try {// 先将 RecordRequest 请求停掉,因为录制停止之后,只需要一个预览流即可,降低功耗mCurrentCameraCaptureSession.stopRepeating();mCurrentCameraCaptureSession.setRepeatingRequest(mCurrentPreviewRequest, null, null);} catch (CameraAccessException e) {LogUtil.e(TAG, "stopRecording: ", e);}}}
}

http://www.dtcms.com/wzjs/795803.html

相关文章:

  • 买房网站怎么做镇江市建设工程安全监督站网站
  • 营销网站建设教学电商网站建设心得体会
  • 楚雄市网站建设公司ftp两个网站子域名的绑定
  • 杭州 城西 做网站网站后台超链接怎么做
  • 比较好的网站建设哪家好建设银行网站显示404
  • 广州企业网站设计方案网上订酒店 网站开发
  • 网站内链检测扬中王老大
  • 做网站用到什么开发语言怎么做文学动漫网站
  • 公司网站用服务器建站最好的
  • 无锡科技网站建设棋牌app开发公司
  • 无备案网站微信百度推广优化怎么做
  • 学生做网站的目的怎么做阿里巴巴英文网站
  • 新手织梦网建设网站网站免费模板制作
  • 广州网站设计 信科网络做rom的网站
  • 绿色能源网站模板网站建设 中企动力烟台
  • 拖拽式建站源码建设银行考试报名网站
  • 舟山市普陀区建设局网站有源代码怎么生成网页
  • 郑州网站优化哪家专业友情链接发布平台
  • 建设网站需要懂什么意思艺客网站首页
  • 烟台开发区建设局网站做好的网站怎么优化
  • 深圳网站建设补助建设企业网站前市场分析
  • 大学哪个专业可以做网站企业网站建设方案书 范本
  • 企业网站.net信息流广告形式主要有
  • 网站后台添加关键词兰州家易选网络科技有限公司
  • 建网站哪家好行业现状网页制作网
  • 江苏省建设工程施工安全网站如何做网站ppt
  • 永久网站建设教程个人博客WordPress吗
  • 怎样做生成的二维码链接到网站h5怎么弄到微信公众号
  • 网站备案登陆用户名是什么广州近期流行的传染病
  • 企业建站搭建佛山专业画册设计公司