当前位置:   article > 正文

Android 使用Camera2 实现拍照录像的功能_android camera2

android camera2

职场小白迷上优美句子:

还是电影  《无问西东》中的台词,这句有点感人:

沈光耀的妈妈对沈光耀说:"当初你离家千里,来到这个地方读书,你父亲和我都没有反对过,因为,是我们想你,能享受到人生的乐趣,比如读万卷书行万里路,比如同你喜欢的女孩子结婚生子。注意不是给我增添子孙,而是你自己,能够享受为人父母的乐趣,你一生所要追求的功名利禄,没有什么是你的祖上没经历过的,那些只不过是人生的幻光。我怕,你还没想好怎么过这一生,你的命就没了啊!"

推荐两篇对Camera2的讲解非常详细的博客 

新根 - - - Android Camera2 API和拍照与录像过程

Camera2.0新API下的摄像头预览、原始图像数据获取等_黄政的博客-CSDN博客


效果图:

 源码地址:

github开源相机Camera2源码https://github.com/13767004362/Camera2App.git

拍照操作类代码

  1. public class PictureOperater extends BaseCamera2Operator {
  2. private static final String TAG = PictureOperater.class.getSimpleName();
  3. private WorkThreadUtils workThreadManager;
  4. /**
  5. * 相机最大的预览宽度
  6. */
  7. private static final int MAX_PREVIEW_WIDTH = 1920;
  8. /**
  9. * 相机最大的预览高度
  10. */
  11. private static final int MAX_PREVIEW_HEIGHT = 1080;
  12. /**
  13. * 处理静态图片的输出
  14. */
  15. private ImageReader imageReader;
  16. /**
  17. * 相机传感器方向
  18. */
  19. private int mSensorOrientation;
  20. /**
  21. * 相机预览的大小Size
  22. */
  23. private Size mPreviewSize;
  24. /**
  25. * 是否支持自动对焦
  26. */
  27. private boolean mAutoFocusSupported;
  28. /**
  29. * 是否支持闪光灯
  30. */
  31. private boolean mFlashSupported;
  32. /**
  33. * 相机的Id
  34. */
  35. private String mCameraId;
  36. /**
  37. * 预览请求的Builder
  38. */
  39. private CaptureRequest.Builder mPreviewRequestBuilder;
  40. /**
  41. * 预览的请求
  42. */
  43. private CaptureRequest mPreviewRequest;
  44. private CameraCaptureSession mCaptureSession;
  45. /**
  46. * 开启相机的锁住时间
  47. */
  48. private final int LOCK_TIME = 2500;
  49. private Camera2Manager camera2Manager;
  50. /**
  51. * 最小的焦距
  52. */
  53. private float minimalFocalDistance = 0;
  54. /**
  55. * 最大的数字变焦值,缩放值
  56. */
  57. private float maxZoom = 0;
  58. public PictureOperater(Camera2Manager camera2Manager) {
  59. this.camera2Manager = camera2Manager;
  60. this.workThreadManager = camera2Manager.getWorkThreadManager();
  61. }
  62. @Override
  63. public void startOperate() {
  64. TextureView textureView = getTextureView();
  65. if (textureView.isAvailable()) {
  66. openCamera(getTextureViewContext(), textureView.getWidth(), textureView.getHeight());
  67. } else {
  68. textureView.setSurfaceTextureListener(mSurfaceTextureListener);
  69. }
  70. }
  71. @Override
  72. public void stopOperate() {
  73. Log.i(TAG, TAG+" 关闭相机的操作 ");
  74. closeCamera();
  75. }
  76. @Override
  77. public void openCamera(Activity activity, int width, int height) {
  78. if (PermissionsManager.checkCameraPermission(activity)) {
  79. setUpCameraOutputs(activity, width, height);
  80. configureTransform(activity, width, height);
  81. CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
  82. try {
  83. //打开相机需要一定时间,因锁住2.5秒,防止程序退出关闭相机
  84. if (!mCameraOpenCloseLock.tryAcquire(LOCK_TIME, TimeUnit.MILLISECONDS)) {
  85. throw new RuntimeException("Time out waiting to lock camera opening.");
  86. }
  87. manager.openCamera(mCameraId, stateCallback, workThreadManager.getBackgroundHandler());
  88. } catch (CameraAccessException e) {
  89. e.printStackTrace();
  90. } catch (InterruptedException e) {
  91. throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
  92. }
  93. }
  94. }
  95. @Override
  96. public void closePreviewSession() {
  97. if (mCaptureSession != null) {
  98. mCaptureSession.close();
  99. mCaptureSession = null;
  100. }
  101. }
  102. @Override
  103. public void configureTransform(Activity activity, int viewWidth, int viewHeight) {
  104. if (null == getTextureView() || null == mPreviewSize || null == activity) {
  105. return;
  106. }
  107. int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
  108. Matrix matrix = new Matrix();
  109. RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
  110. RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
  111. float centerX = viewRect.centerX();
  112. float centerY = viewRect.centerY();
  113. if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
  114. bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
  115. matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
  116. float scale = Math.max((float) viewHeight / mPreviewSize.getHeight(), (float) viewWidth / mPreviewSize.getWidth());
  117. matrix.postScale(scale, scale, centerX, centerY);
  118. matrix.postRotate(90 * (rotation - 2), centerX, centerY);
  119. } else if (Surface.ROTATION_180 == rotation) {
  120. matrix.postRotate(180, centerX, centerY);
  121. }
  122. getTextureView().setTransform(matrix);
  123. }
  124. @Override
  125. public void writePictureData(Image image) {
  126. if (camera2ResultCallBack != null) {
  127. camera2ResultCallBack.callBack(ObservableBuilder.createWriteCaptureImage(appContext, image));
  128. }
  129. }
  130. @Override
  131. public void startPreView() {
  132. //开启相机预览界面
  133. createCameraPreviewSession();
  134. }
  135. @Override
  136. public void cameraClick() {
  137. takePicture();
  138. }
  139. /**
  140. * 关闭当前的相机设备,释放资源
  141. */
  142. private void closeCamera() {
  143. try {
  144. mCameraOpenCloseLock.acquire();
  145. closePreviewSession();
  146. if (null != mCameraDevice) {
  147. mCameraDevice.close();
  148. mCameraDevice = null;
  149. }
  150. if (null != imageReader) {
  151. imageReader.close();
  152. imageReader = null;
  153. }
  154. } catch (InterruptedException e) {
  155. throw new RuntimeException("Interrupted while trying to lock camera closi" + "ng.", e);
  156. } finally {
  157. mCameraOpenCloseLock.release();
  158. }
  159. }
  160. /**
  161. * 拍照
  162. */
  163. public void takePicture() {
  164. ToastUtils.showToast(camera2Manager.getContext()," 客官,请别抖动,正在拍照中。");
  165. if (mAutoFocusSupported) {
  166. Log.i(TAG,TAG+"支持自动调焦,正在锁住焦点");
  167. lockFocus();
  168. } else {//设备不支持自动对焦,则直接拍照。
  169. Log.i(TAG,TAG+"不支持自动调焦,直接拍照");
  170. captureStillPicture();
  171. }
  172. }
  173. /**
  174. * 拍照的第一步,锁住焦点。
  175. */
  176. private void lockFocus() {
  177. try {
  178. //告诉相机,这里已经锁住焦点
  179. mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
  180. // 标识,正在进行拍照动作
  181. mState = STATE_WAITING_LOCK;
  182. //进行拍照处理
  183. mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, workThreadManager.getBackgroundHandler());
  184. } catch (CameraAccessException e) {
  185. e.printStackTrace();
  186. }
  187. }
  188. /**
  189. * 相机开始预览,创建一个CameraCaptureSession对象
  190. */
  191. private void createCameraPreviewSession() {
  192. try {
  193. SurfaceTexture texture = getTextureView().getSurfaceTexture();
  194. //assert断言表达式,为true继续。
  195. assert texture != null;
  196. // We configure the size of default buffer to be the size of camera preview we want.
  197. texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
  198. // 创建一个预览界面需要用到的Surface对象
  199. Surface surface = new Surface(texture);
  200. // 将CaptureRequest的构建器与Surface对象绑定在一起
  201. mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
  202. mPreviewRequestBuilder.addTarget(surface);
  203. // 为相机预览,创建一个CameraCaptureSession对象
  204. mCameraDevice.createCaptureSession(Arrays.asList(surface, imageReader.getSurface()), new CameraCaptureSession.StateCallback() {
  205. @Override
  206. public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
  207. // 相机已经关闭
  208. if (null == mCameraDevice) {
  209. return;
  210. }
  211. //当cameraCaptureSession已经准备完成,开始显示预览界面
  212. mCaptureSession = cameraCaptureSession;
  213. setCameraCaptureSession();
  214. }
  215. @Override
  216. public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
  217. //配置失败
  218. }
  219. }, null);
  220. } catch (CameraAccessException e) {
  221. e.printStackTrace();
  222. }
  223. }
  224. /**
  225. * 设置CameraCaptureSession的特征:
  226. * <p>
  227. * 自动对焦,闪光灯
  228. */
  229. private void setCameraCaptureSession() {
  230. try {
  231. setFocus(mPreviewRequestBuilder);
  232. //若是需要则开启,闪光灯
  233. setAutoFlash(mPreviewRequestBuilder);
  234. // 最后,开启相机预览界面的显示
  235. mPreviewRequest = mPreviewRequestBuilder.build();
  236. //为CameraCaptureSession设置复用的CaptureRequest。
  237. mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, workThreadManager.getBackgroundHandler());
  238. } catch (CameraAccessException e) {
  239. e.printStackTrace();
  240. }
  241. }
  242. private float currentZoom;
  243. @Override
  244. public void notifyFocusState() {
  245. if (mPreviewRequestBuilder != null) {
  246. try {
  247. currentZoom = maxZoom * camera2Manager.getZoomProportion();
  248. setZoom(currentZoom);
  249. } catch (Exception e) {
  250. e.printStackTrace();
  251. }
  252. }
  253. }
  254. private Rect zoomRect;
  255. private void setZoom(float currentZoom) {
  256. try {
  257. zoomRect=createZoomReact();
  258. if (zoomRect==null){
  259. Log.i(TAG, "相机不支持 zoom " );
  260. return ;
  261. }
  262. mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION,zoomRect);
  263. mPreviewRequest = mPreviewRequestBuilder.build();
  264. Log.i(TAG, " 最大缩放值 " + maxZoom + " 设置缩放值 " + currentZoom );
  265. //为CameraCaptureSession设置复用的CaptureRequest。
  266. mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, workThreadManager.getBackgroundHandler());
  267. } catch (Exception e) {
  268. e.printStackTrace();
  269. }
  270. }
  271. /**
  272. * 计算出zoom所对应的裁剪区域
  273. * @return
  274. */
  275. private Rect createZoomReact() {
  276. if (currentZoom==0){
  277. return null;
  278. }
  279. try {
  280. Rect rect = cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
  281. if (rect==null){
  282. return null;
  283. }
  284. zoomRect =Camera2Utils.createZoomRect(rect,currentZoom);
  285. Log.i(TAG, "zoom对应的 rect对应的区域 " + zoomRect.left + " " + zoomRect.right + " " + zoomRect.top + " " + zoomRect.bottom);
  286. } catch (Exception e) {
  287. e.printStackTrace();
  288. }
  289. return zoomRect;
  290. }
  291. /**
  292. * -
  293. * 设置调焦方式:自动连续对焦还是手动调焦
  294. *
  295. * @param requestBuilder
  296. */
  297. private void setFocus(CaptureRequest.Builder requestBuilder) {
  298. /* if (camera2Manager.isManualFocus()) {
  299. float focusDistance = minimum_focus_distance * camera2Manager.getZoomProportion();
  300. setManualFocus(requestBuilder, focusDistance);
  301. } else {
  302. }*/
  303. setAutoFocus(requestBuilder);
  304. }
  305. /**
  306. * 设置连续自动对焦
  307. *
  308. * @param requestBuilder
  309. */
  310. private void setAutoFocus(CaptureRequest.Builder requestBuilder) {
  311. if (requestBuilder != null) {
  312. //为相机预览设置连续对焦。
  313. requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
  314. }
  315. }
  316. /**
  317. * 设置手动对焦,设置焦距值
  318. *
  319. * @param requestBuilder
  320. */
  321. private void setManualFocus(CaptureRequest.Builder requestBuilder, float distance) {
  322. //若是机器不支持焦距设置,则需要检查。
  323. try {
  324. if (requestBuilder != null) {
  325. //先关闭自动对焦的模式
  326. requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_OFF);
  327. requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_OFF);
  328. Log.i(TAG, "手动调焦的 " + distance + " 最大范围值是 " + minimum_focus_distance);
  329. //设置焦距值
  330. requestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, distance);
  331. }
  332. } catch (Exception e) {
  333. e.printStackTrace();
  334. }
  335. }
  336. /**
  337. * Camera state: Showing camera preview.
  338. * 相机预览状态
  339. */
  340. private static final int STATE_PREVIEW = 0;
  341. /**
  342. * Camera state: Waiting for the focus to be locked.
  343. * <p>
  344. * 相机拍照,被锁住,等待焦点状态
  345. */
  346. private static final int STATE_WAITING_LOCK = 1;
  347. /**
  348. * Camera state: Waiting for the exposure to be precapture state.
  349. */
  350. private static final int STATE_WAITING_PRECAPTURE = 2;
  351. /**
  352. * Camera state: Waiting for the exposure state to be something other than precapture.
  353. */
  354. private static final int STATE_WAITING_NON_PRECAPTURE = 3;
  355. /**
  356. * Camera state: Picture was taken.
  357. * 图片已经获取
  358. */
  359. private static final int STATE_PICTURE_TAKEN = 4;
  360. /**
  361. * The current state of camera state for taking pictures.
  362. *
  363. * @see #mCaptureCallback
  364. */
  365. private int mState = STATE_PREVIEW;
  366. /**
  367. * CameraCaptureSession.CaptureCallback : 处理捕获到的JPEG事件。
  368. */
  369. private CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {
  370. private void process(CaptureResult result) {
  371. switch (mState) {
  372. //正常预览状态
  373. case STATE_PREVIEW: {
  374. break;
  375. }
  376. //刚开始拍照,锁住,等待状态
  377. case STATE_WAITING_LOCK: {
  378. //当前自动对焦的状态
  379. Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
  380. if (afState == null) {
  381. captureStillPicture();
  382. } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState || CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
  383. // CONTROL_AE_STATE can be null on some devices
  384. Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
  385. if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
  386. mState = STATE_PICTURE_TAKEN;
  387. captureStillPicture();
  388. } else {
  389. runPrecaptureSequence();
  390. }
  391. }else{
  392. mState = STATE_PICTURE_TAKEN;
  393. captureStillPicture();
  394. }
  395. break;
  396. }
  397. //等待,预捕获
  398. case STATE_WAITING_PRECAPTURE: {
  399. // CONTROL_AE_STATE can be null on some devices
  400. Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
  401. if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE || aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
  402. mState = STATE_WAITING_NON_PRECAPTURE;
  403. }
  404. break;
  405. }
  406. //已经完成预捕获,直接拍照。
  407. case STATE_WAITING_NON_PRECAPTURE: {
  408. // CONTROL_AE_STATE can be null on some devices
  409. Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
  410. if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
  411. mState = STATE_PICTURE_TAKEN;
  412. captureStillPicture();
  413. }
  414. break;
  415. }
  416. default:
  417. break;
  418. }
  419. }
  420. @Override
  421. public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
  422. process(partialResult);
  423. }
  424. @Override
  425. public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
  426. process(result);
  427. }
  428. };
  429. /**
  430. * <p>
  431. * 运行预捕获的序列,为捕获一个静态图片
  432. */
  433. private void runPrecaptureSequence() {
  434. try {
  435. // 告诉相机,这里触发.
  436. mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
  437. //设置成预捕获状态,将需等待。
  438. mState = STATE_WAITING_PRECAPTURE;
  439. mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, workThreadManager.getBackgroundHandler());
  440. } catch (CameraAccessException e) {
  441. e.printStackTrace();
  442. }
  443. }
  444. /**
  445. * 拍照一个静态的图片
  446. * ,当在CaptureCallback监听器响应的时候调用该方法。
  447. * <p>
  448. * 当数字调焦缩放的时候,在写入图片数中也要设置。
  449. */
  450. private void captureStillPicture() {
  451. try {
  452. final Activity activity = getTextureViewContext();
  453. if (null == activity || null == mCameraDevice) {
  454. return;
  455. }
  456. // 创建一个拍照的CaptureRequest.Builder
  457. final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
  458. captureBuilder.addTarget(imageReader.getSurface());
  459. // 使用相同的AE和AF模式作为预览.
  460. captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
  461. //让相机中缩放效果和图片保持一致
  462. // zoomRect=createZoomReact();
  463. if (zoomRect != null) {
  464. Log.i(TAG," 拍照 添加裁剪区域 "+zoomRect.toString());
  465. captureBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);
  466. }
  467. setAutoFlash(captureBuilder);
  468. // 方向
  469. int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
  470. captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, Camera2Utils.getOrientation(ORIENTATIONS, mSensorOrientation, rotation));
  471. CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
  472. @Override
  473. public void onCaptureCompleted(@NonNull CameraCaptureSession session
  474. , @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
  475. //拍照完成,进行释放焦点操作。
  476. unlockFocus();
  477. }
  478. };
  479. //先停止以前的预览状态
  480. mCaptureSession.stopRepeating();
  481. mCaptureSession.abortCaptures();
  482. //执行拍照状态
  483. mCaptureSession.capture(captureBuilder.build(), captureCallback, null);
  484. } catch (CameraAccessException e) {
  485. e.printStackTrace();
  486. }
  487. }
  488. /**
  489. * 完成一些列拍照后,释放焦点。
  490. */
  491. private void unlockFocus() {
  492. try {
  493. // 重置一系列的对焦
  494. mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
  495. setAutoFlash(mPreviewRequestBuilder);
  496. mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, workThreadManager.getBackgroundHandler());
  497. // 恢复正常状态
  498. mState = STATE_PREVIEW;
  499. mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, workThreadManager.getBackgroundHandler());
  500. Log.i(TAG, TAG+" 拍照完成,释放焦点 unlockFocus() ");
  501. } catch (CameraAccessException e) {
  502. e.printStackTrace();
  503. }
  504. }
  505. /**
  506. * 设置是否开启闪光灯
  507. *
  508. * @param requestBuilder
  509. */
  510. private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
  511. if (mFlashSupported) {
  512. requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
  513. }
  514. }
  515. /**
  516. * 获取到最大的焦距值
  517. */
  518. private float minimum_focus_distance;
  519. /**
  520. * 获取相机参数的类
  521. */
  522. private CameraCharacteristics cameraCharacteristics;
  523. /**
  524. * 设置Camera的相关参数变量,长、宽,且返回相机的Id.
  525. *
  526. * @param width
  527. * @param height
  528. */
  529. private void setUpCameraOutputs(Activity activity, int width, int height) {
  530. CameraManager manager = (CameraManager) getTextureViewContext().getSystemService(Context.CAMERA_SERVICE);
  531. try {
  532. //获取到可用的相机
  533. for (String cameraId : manager.getCameraIdList()) {
  534. //获取到每个相机的参数对象,包含前后摄像头,分辨率等
  535. cameraCharacteristics = manager.getCameraCharacteristics(cameraId);
  536. if (!Camera2Utils.matchCameraDirection(cameraCharacteristics, currentDirection)) {
  537. continue;
  538. }
  539. //存储流配置类
  540. StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
  541. if (map == null) {
  542. continue;
  543. }
  544. //检查设备,是否支持自动对焦
  545. mAutoFocusSupported = Camera2Utils.checkAutoFocus(cameraCharacteristics);
  546. //获取最小焦距值。
  547. Float minFocalDistance = Camera2Utils.getMinimumFocusDistance(cameraCharacteristics);
  548. if (minFocalDistance != null) {
  549. minimum_focus_distance = minFocalDistance;
  550. }
  551. Float maxZoomValue = Camera2Utils.getMaxZoom(cameraCharacteristics);
  552. if (maxZoomValue != null) {
  553. maxZoom = maxZoomValue;
  554. }
  555. Log.i(TAG, (currentDirection == CameraCharacteristics.LENS_FACING_BACK ? "后" : "前") + " 摄像头 " + " 是否支持自动对焦 " + mAutoFocusSupported + " 获取到焦距的最大值 " + minimum_focus_distance + " 最大的缩放值 " + maxZoom);
  556. //对于静态图片,使用可用的最大值来拍摄。
  557. Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new CompareSizeByArea());
  558. //设置ImageReader,将大小,图片格式
  559. imageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, /*maxImages*/2);
  560. imageReader.setOnImageAvailableListener(onImageAvailableListener, workThreadManager.getBackgroundHandler());
  561. //获取到屏幕的旋转角度,进一步判断是否,需要交换维度来获取预览大小
  562. int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
  563. //获取相机传感器方向
  564. mSensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
  565. boolean swappedDimensions = false;
  566. switch (displayRotation) {
  567. case Surface.ROTATION_0:
  568. case Surface.ROTATION_180:
  569. if (mSensorOrientation == 90 || mSensorOrientation == 270) {
  570. swappedDimensions = true;
  571. }
  572. break;
  573. case Surface.ROTATION_90:
  574. case Surface.ROTATION_270:
  575. if (mSensorOrientation == 0 || mSensorOrientation == 180) {
  576. swappedDimensions = true;
  577. }
  578. break;
  579. default:
  580. Log.e(TAG, "Display rotation is invalid: " + displayRotation);
  581. }
  582. Point displaySize = new Point();
  583. activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
  584. int rotatedPreviewWidth = width;
  585. int rotatedPreviewHeight = height;
  586. int maxPreviewWidth = displaySize.x;
  587. int maxPreviewHeight = displaySize.y;
  588. //当角度反了的时候
  589. if (swappedDimensions) {
  590. rotatedPreviewWidth = height;
  591. rotatedPreviewHeight = width;
  592. maxPreviewWidth = displaySize.y;
  593. maxPreviewHeight = displaySize.x;
  594. }
  595. if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
  596. maxPreviewWidth = MAX_PREVIEW_WIDTH;
  597. }
  598. if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
  599. maxPreviewHeight = MAX_PREVIEW_HEIGHT;
  600. }
  601. mPreviewSize = Camera2Utils.chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
  602. rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
  603. maxPreviewHeight, largest, new CompareSizeByArea());
  604. // 计算出来的预览大小,设置成TextureView宽高.
  605. int orientation = activity.getResources().getConfiguration().orientation;
  606. AutoFitTextureView mTextureView = (AutoFitTextureView) getTextureView();
  607. //横屏
  608. if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
  609. mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
  610. } else {
  611. mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
  612. }
  613. // 检查,相机是否支持闪光。
  614. Boolean available = cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
  615. mFlashSupported = available == null ? false : available;
  616. mCameraId = cameraId;
  617. // Log.i(TAG, " 根据相机的前后摄像头" + mCameraId + " 方向是:" + currentDirection);
  618. return;
  619. }
  620. } catch (Exception e) {
  621. e.printStackTrace();
  622. //不支持该设备
  623. if (e instanceof NullPointerException) {
  624. ToastUtils.showToast(appContext, "设备不支持Camera2 API");
  625. }
  626. }
  627. }
  628. }

录像操作类代码:

  1. public class VideoRecordOperator extends BaseCamera2Operator {
  2. public static final String TAG = VideoRecordOperator.class.getSimpleName();
  3. private WorkThreadUtils workThreadManager;
  4. /**
  5. * 视频录制的大小
  6. */
  7. private Size mVideoSize;
  8. /**
  9. * 相机预览的大小Size
  10. */
  11. private Size mPreviewSize;
  12. /**
  13. * MediaRecorder
  14. */
  15. private MediaRecorder mMediaRecorder;
  16. /**
  17. * 当前是否是在录制视频
  18. */
  19. private boolean mIsRecordingVideo;
  20. /**
  21. * 传感器的方向
  22. */
  23. private Integer mSensorOrientation;
  24. /**
  25. * 相机预览请求的Builder
  26. */
  27. private CaptureRequest.Builder mPreviewBuilder;
  28. /**
  29. * 点击开启录制时候创建的新视频文件路径
  30. */
  31. private String mNextVideoAbsolutePath;
  32. private CompositeSubscription compositeSubscription;
  33. private Camera2Manager camera2Manager;
  34. public VideoRecordOperator(Camera2Manager camera2Manager) {
  35. this.camera2Manager = camera2Manager;
  36. this.workThreadManager = camera2Manager.getWorkThreadManager();
  37. this.oldVideoPath = new CopyOnWriteArrayList<>();
  38. this.compositeSubscription = new CompositeSubscription();
  39. }
  40. @Override
  41. public void writePictureData(Image image) {
  42. }
  43. /**
  44. * 开始相机的预览界面,创建一个预览的session会话。
  45. */
  46. @Override
  47. public void startPreView() {
  48. TextureView mTextureView = getTextureView();
  49. if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
  50. return;
  51. }
  52. //开始相机预览
  53. try {
  54. closePreviewSession();
  55. SurfaceTexture texture = mTextureView.getSurfaceTexture();
  56. assert texture != null;
  57. texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
  58. mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
  59. Surface previewSurface = new Surface(texture);
  60. mPreviewBuilder.addTarget(previewSurface);
  61. //从拍照切换到摄像头,获取录像完成后需要重新恢复以前的状态
  62. float currentZoom = camera2Manager.getZoomProportion() * maxZoom;
  63. updateZoomRect(currentZoom);
  64. mCameraDevice.createCaptureSession(Collections.singletonList(previewSurface),
  65. new CameraCaptureSession.StateCallback() {
  66. @Override
  67. public void onConfigured(@NonNull CameraCaptureSession session) {
  68. mPreviewSession = session;
  69. updatePreview();
  70. }
  71. @Override
  72. public void onConfigureFailed(@NonNull CameraCaptureSession session) {
  73. Activity activity = getTextureViewContext();
  74. if (null != activity) {
  75. Toast.makeText(activity, "相机预览配置失败", Toast.LENGTH_SHORT).show();
  76. }
  77. }
  78. }, workThreadManager.getBackgroundHandler());
  79. } catch (CameraAccessException e) {
  80. e.printStackTrace();
  81. }
  82. if (null != mTextureView) {
  83. configureTransform(getTextureViewContext(), mTextureView.getWidth(), mTextureView.getHeight());
  84. }
  85. }
  86. /**
  87. * 在 startPreView()之后执行用于更新相机预览界面
  88. */
  89. private void updatePreview() {
  90. if (null == mCameraDevice) {
  91. return;
  92. }
  93. try {
  94. setUpCaptureRequestBuilder(mPreviewBuilder);
  95. mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, workThreadManager.getBackgroundHandler());
  96. } catch (CameraAccessException e) {
  97. e.printStackTrace();
  98. }
  99. }
  100. private void setUpCaptureRequestBuilder(CaptureRequest.Builder builder) {
  101. builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
  102. }
  103. /**
  104. * 为相机创建一个CameraCaptureSession
  105. */
  106. private CameraCaptureSession mPreviewSession;
  107. @Override
  108. public void closePreviewSession() {
  109. if (mPreviewSession != null) {
  110. mPreviewSession.close();
  111. mPreviewSession = null;
  112. }
  113. }
  114. @Override
  115. public void cameraClick() {
  116. if (mIsRecordingVideo) {
  117. stopRecordingVideo(true);
  118. } else {
  119. startRecordingVideo();
  120. }
  121. }
  122. /**
  123. * 停止录制
  124. */
  125. private void stopRecordingVideo(final boolean isFinish) {
  126. // UI
  127. mIsRecordingVideo = false;
  128. /**
  129. * 在MediaRecorder停止前,停止相机预览,防止抛出serious error异常。
  130. *
  131. * android.hardware.camera2.CameraAccessException: The camera device has encountered a serious error
  132. *
  133. * 解决方式:https://stackoverflow.com/questions/27907090/android-camera-2-api
  134. */
  135. try {
  136. mPreviewSession.stopRepeating();
  137. mPreviewSession.abortCaptures();
  138. } catch (CameraAccessException e) {
  139. e.printStackTrace();
  140. }
  141. Subscription subscription = Observable
  142. //延迟三十毫秒
  143. .timer(30, TimeUnit.MICROSECONDS, Schedulers.computation())
  144. .observeOn(AndroidSchedulers.mainThread())
  145. .subscribe(l -> {
  146. // 停止录制
  147. mMediaRecorder.stop();
  148. mMediaRecorder.reset();
  149. if (isFinish) {
  150. isRecordGonging = false;
  151. Log.i(TAG, "stopRecordingVideo 录制完成");
  152. if (camera2VideoRecordCallBack != null) {
  153. camera2VideoRecordCallBack.finishRecord();
  154. }
  155. mergeMultipleFileCallBack();
  156. mNextVideoAbsolutePath = null;
  157. this.oldVideoPath.clear();
  158. } else {//暂停的操作
  159. Log.i(TAG, "pauseRecordingVideo 录制暂停");
  160. //若是开始新的录制,原本暂停产生的多个文件合并成一个文件。
  161. this.oldVideoPath.add(mNextVideoAbsolutePath);
  162. if (oldVideoPath.size() > 1) {
  163. mergeMultipleFile();
  164. }
  165. mNextVideoAbsolutePath = null;
  166. }
  167. startPreView();
  168. });
  169. this.compositeSubscription.add(subscription);
  170. }
  171. /**
  172. * 暂停后又从新恢复录制,合并多个视频文件
  173. */
  174. private void mergeMultipleFile() {
  175. Log.i(TAG, " mergeMultipleFile 开始操作:文件个数 " + this.oldVideoPath.size());
  176. Subscription subscription = ObservableBuilder.createMergeMuiltFile(appContext, this.oldVideoPath.get(0), this.oldVideoPath.get(1))
  177. .subscribeOn(Schedulers.io())
  178. .observeOn(AndroidSchedulers.mainThread())
  179. .subscribe(filePath -> {
  180. this.oldVideoPath.clear();
  181. this.oldVideoPath.add(filePath);
  182. Log.i(TAG, " mergeMultipleFile 完成: 文件个数" + this.oldVideoPath.size());
  183. });
  184. this.compositeSubscription.add(subscription);
  185. }
  186. /**
  187. * 完成录制,输出最终的视频录制文件
  188. */
  189. private void mergeMultipleFileCallBack() {
  190. if (this.oldVideoPath.size() > 0) {
  191. Log.i(TAG, " mergeMultipleFileCallBack 开始操作:文件个数 " + this.oldVideoPath.size());
  192. Subscription subscription = ObservableBuilder.createMergeMuiltFile(appContext, this.oldVideoPath.get(0), mNextVideoAbsolutePath)
  193. .subscribeOn(Schedulers.io())
  194. .observeOn(AndroidSchedulers.mainThread())
  195. .subscribe(s -> {
  196. if (camera2ResultCallBack != null) {
  197. camera2ResultCallBack.callBack(ObservableBuilder.createVideo(s));
  198. }
  199. Log.i(TAG, " mergeMultipleFileCallBack 完成 且回调");
  200. ToastUtils.showToast(appContext, "视频文件保存在" + s);
  201. });
  202. this.compositeSubscription.add(subscription);
  203. } else {
  204. if (camera2ResultCallBack != null) {
  205. camera2ResultCallBack.callBack(ObservableBuilder.createVideo(mNextVideoAbsolutePath));
  206. }
  207. ToastUtils.showToast(appContext, "视频文件保存在" + mNextVideoAbsolutePath);
  208. }
  209. }
  210. /**
  211. * 暂停录制
  212. */
  213. public void pauseRecordingVideo() {
  214. stopRecordingVideo(false);
  215. }
  216. /**
  217. * 开始视频录制,创建一个录像的session会话。
  218. */
  219. private void startRecordingVideo() {
  220. Log.i(TAG, " startRecordingVideo 录制初始化 ");
  221. TextureView mTextureView = getTextureView();
  222. if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
  223. return;
  224. }
  225. try {
  226. closePreviewSession();
  227. setUpMediaRecorder();
  228. SurfaceTexture texture = mTextureView.getSurfaceTexture();
  229. assert texture != null;
  230. texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
  231. //创建录制的session会话
  232. mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
  233. List<Surface> surfaces = new ArrayList<>();
  234. // 为相机预览设置Surface
  235. Surface previewSurface = new Surface(texture);
  236. surfaces.add(previewSurface);
  237. mPreviewBuilder.addTarget(previewSurface);
  238. // 为 MediaRecorder设置Surface
  239. Surface recorderSurface = mMediaRecorder.getSurface();
  240. surfaces.add(recorderSurface);
  241. mPreviewBuilder.addTarget(recorderSurface);
  242. //与未录像的状态保持一致。
  243. if (zoomRect != null) {
  244. mPreviewBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);
  245. }
  246. // Start a capture session
  247. // Once the session starts, we can update the UI and start recording
  248. mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
  249. @Override
  250. public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
  251. mPreviewSession = cameraCaptureSession;
  252. updatePreview();
  253. Log.i(TAG, " startRecordingVideo 正式开始录制 ");
  254. getTextureViewContext().runOnUiThread(() -> {
  255. mIsRecordingVideo = true;
  256. isRecordGonging = true;
  257. mMediaRecorder.start();
  258. if (camera2VideoRecordCallBack != null) {
  259. camera2VideoRecordCallBack.startRecord();
  260. }
  261. });
  262. }
  263. @Override
  264. public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
  265. Activity activity = getTextureViewContext();
  266. if (null != activity) {
  267. Toast.makeText(activity.getApplicationContext(), "相机设备配置失败", Toast.LENGTH_SHORT).show();
  268. }
  269. }
  270. }, workThreadManager.getBackgroundHandler());
  271. } catch (CameraAccessException | IOException e) {
  272. e.printStackTrace();
  273. }
  274. }
  275. /**
  276. * 设置媒体录制器的配置参数
  277. * <p>
  278. * 音频,视频格式,文件路径,频率,编码格式等等
  279. *
  280. * @throws IOException
  281. */
  282. private void setUpMediaRecorder() throws IOException {
  283. final Activity activity = getTextureViewContext();
  284. if (null == activity) {
  285. return;
  286. }
  287. mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  288. mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
  289. mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
  290. mNextVideoAbsolutePath = FileUtils.createVideoDiskFile(appContext, FileUtils.createVideoFileName()).getAbsolutePath();
  291. mMediaRecorder.setOutputFile(mNextVideoAbsolutePath);
  292. mMediaRecorder.setVideoEncodingBitRate(10000000);
  293. //每秒30帧
  294. mMediaRecorder.setVideoFrameRate(30);
  295. mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
  296. mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
  297. mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
  298. int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
  299. switch (mSensorOrientation) {
  300. case SENSOR_ORIENTATION_DEFAULT_DEGREES:
  301. mMediaRecorder.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation));
  302. break;
  303. case SENSOR_ORIENTATION_INVERSE_DEGREES:
  304. mMediaRecorder.setOrientationHint(ORIENTATIONS.get(rotation));
  305. break;
  306. default:
  307. break;
  308. }
  309. mMediaRecorder.prepare();
  310. }
  311. private List<String> oldVideoPath;
  312. @Override
  313. public void startOperate() {
  314. TextureView textureView = getTextureView();
  315. if (textureView.isAvailable()) {
  316. openCamera(getTextureViewContext(), textureView.getWidth(), textureView.getHeight());
  317. } else {
  318. textureView.setSurfaceTextureListener(mSurfaceTextureListener);
  319. }
  320. }
  321. @Override
  322. public void stopOperate() {
  323. try {
  324. mCameraOpenCloseLock.acquire();
  325. closePreviewSession();
  326. if (null != mCameraDevice) {
  327. mCameraDevice.close();
  328. mCameraDevice = null;
  329. }
  330. if (null != mMediaRecorder) {
  331. mMediaRecorder.release();
  332. mMediaRecorder = null;
  333. }
  334. } catch (InterruptedException e) {
  335. throw new RuntimeException("Interrupted while trying to lock camera closing.");
  336. } finally {
  337. mCameraOpenCloseLock.release();
  338. }
  339. }
  340. private boolean isRecordGonging = false;
  341. /**
  342. * 是否在进行视频录制,录制状态,包含进行中,暂停中。
  343. *
  344. * @return
  345. */
  346. public boolean isVideoRecord() {
  347. return isRecordGonging;
  348. }
  349. private Rect zoomRect;
  350. /**
  351. * 更新缩放,数字调焦
  352. *
  353. * @param currentZoom
  354. */
  355. private void updateZoomRect(float currentZoom) {
  356. try {
  357. Rect rect = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
  358. if (rect == null) {
  359. return;
  360. }
  361. zoomRect = Camera2Utils.createZoomRect(rect, currentZoom);
  362. if (zoomRect == null) {
  363. return;
  364. }
  365. Log.i(TAG, "zoom对应的 rect对应的区域 " + zoomRect.left + " " + zoomRect.right + " " + zoomRect.top + " " + zoomRect.bottom);
  366. mPreviewBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);
  367. } catch (Exception e) {
  368. e.printStackTrace();
  369. }
  370. }
  371. private float maxZoom;
  372. private CameraCharacteristics characteristics;
  373. @Override
  374. protected void openCamera(Activity activity, int width, int height) {
  375. if (PermissionsManager.checkVideoRecordPermission(getTextureViewContext())) {
  376. if (null == activity || activity.isFinishing()) {
  377. return;
  378. }
  379. AutoFitTextureView textureView = (AutoFitTextureView) getTextureView();
  380. CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
  381. try {
  382. Log.d(TAG, "tryAcquire");
  383. if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
  384. throw new RuntimeException("锁住相机开启,超时");
  385. }
  386. for (String cameraId : manager.getCameraIdList()) {
  387. characteristics = manager.getCameraCharacteristics(cameraId);
  388. if (!Camera2Utils.matchCameraDirection(characteristics, currentDirection)) {
  389. continue;
  390. }
  391. //存储流配置类
  392. StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
  393. if (map == null) {
  394. continue;
  395. }
  396. Log.i(TAG, "视频录制,重新配置相机设备" + currentDirection + " " + cameraId);
  397. mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
  398. Float maxZoomValue = Camera2Utils.getMaxZoom(characteristics);
  399. if (maxZoomValue != null) {
  400. maxZoom = maxZoomValue;
  401. }
  402. // 计算相机预览和视频录制的的Size
  403. mVideoSize = Camera2Utils.chooseVideoSize(map.getOutputSizes(MediaRecorder.class));
  404. mPreviewSize = Camera2Utils.chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height, mVideoSize);
  405. int orientation = activity.getResources().getConfiguration().orientation;
  406. if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
  407. textureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
  408. } else {
  409. textureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
  410. }
  411. configureTransform(activity, width, height);
  412. mMediaRecorder = new MediaRecorder();
  413. manager.openCamera(cameraId, stateCallback, null);
  414. return;
  415. }
  416. } catch (CameraAccessException e) {
  417. ToastUtils.showToast(appContext, "不能访问相机");
  418. activity.finish();
  419. } catch (NullPointerException e) {
  420. ToastUtils.showToast(appContext, "当前设备不支持Camera2 API");
  421. } catch (InterruptedException e) {
  422. throw new RuntimeException("在锁住相机开启期间被打断.");
  423. }
  424. }
  425. }
  426. @Override
  427. protected void configureTransform(Activity activity, int viewWidth, int viewHeight) {
  428. TextureView textureView = getTextureView();
  429. if (null == textureView || null == mPreviewSize || null == activity) {
  430. return;
  431. }
  432. int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
  433. Matrix matrix = new Matrix();
  434. RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
  435. RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
  436. float centerX = viewRect.centerX();
  437. float centerY = viewRect.centerY();
  438. if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
  439. bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
  440. matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
  441. float scale = Math.max((float) viewHeight / mPreviewSize.getHeight(), (float) viewWidth / mPreviewSize.getWidth());
  442. matrix.postScale(scale, scale, centerX, centerY);
  443. matrix.postRotate(90 * (rotation - 2), centerX, centerY);
  444. }
  445. textureView.setTransform(matrix);
  446. }
  447. @Override
  448. public void notifyFocusState() {
  449. float currentZoom = camera2Manager.getZoomProportion() * maxZoom;
  450. updateZoomRect(currentZoom);
  451. updatePreview();
  452. }
  453. private Camera2VideoRecordCallBack camera2VideoRecordCallBack;
  454. public void setCamera2VideoRecordCallBack(Camera2VideoRecordCallBack camera2VideoRecordCallBack) {
  455. this.camera2VideoRecordCallBack = camera2VideoRecordCallBack;
  456. }
  457. }

Fragment中进行调用:

  1. public class CameraFragment extends Fragment implements CameraContract.View<CameraContract.Presenter>
  2. , View.OnClickListener, RadioGroup.OnCheckedChangeListener
  3. , VerticalProgressBarLayout.VerticalMoveResultListener {
  4. public static final String TAG = CameraFragment.class.getSimpleName();
  5. private ImageView show_result_iv;
  6. private ImageView controller_state_iv;
  7. private VerticalProgressBarLayout verticalProgressBarLayout;
  8. public static CameraFragment newInstance() {
  9. CameraFragment cameraFragment = new CameraFragment();
  10. return cameraFragment;
  11. }
  12. private AutoFitTextureView textureView;
  13. private TextView show_record_tv, record_tip_circle;
  14. private View rootView;
  15. private CameraContract.Presenter presenter;
  16. private Animator flashAnimator;
  17. @Nullable
  18. @Override
  19. public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  20. this.rootView = inflater.inflate(R.layout.fragment_camera, container, false);
  21. initView();
  22. return this.rootView;
  23. }
  24. @Override
  25. public void showToast(String content) {
  26. ToastUtils.showToastRunUIThread(getActivity(), content);
  27. }
  28. private void initView() {
  29. this.textureView = rootView.findViewById(R.id.camera_auto_fit_texture_view);
  30. this.show_result_iv = rootView.findViewById(R.id.camera_show);
  31. this.show_record_tv = rootView.findViewById(R.id.camera_video_record_tip_time_tv);
  32. this.record_tip_circle = rootView.findViewById(R.id.camera_video_record_tip_bg);
  33. this.rootView.findViewById(R.id.camera_btn).setOnClickListener(this);
  34. this.verticalProgressBarLayout = rootView.findViewById(R.id.camera_vertical_progress_bar);
  35. this.controller_state_iv = this.rootView.findViewById(R.id.camera_right_top_controller);
  36. this.controller_state_iv.setTag(CameraContract.View.MODE_RECORD_FINISH);
  37. this.controller_state_iv.setOnClickListener(this);
  38. this.show_result_iv.setOnClickListener(this);
  39. ((RadioGroup) this.rootView.findViewById(R.id.camera_switch_radioGroup)).setOnCheckedChangeListener(this);
  40. ((RadioGroup) this.rootView.findViewById(R.id.camera_direction_radioGroup)).setOnCheckedChangeListener(this);
  41. this.verticalProgressBarLayout.setVerticalMoveResultListener(this);
  42. }
  43. @Override
  44. public void onResume() {
  45. super.onResume();
  46. if (presenter != null) {
  47. presenter.onResume();
  48. }
  49. }
  50. @Override
  51. public void onPause() {
  52. super.onPause();
  53. if (presenter != null) {
  54. presenter.onPause();
  55. }
  56. }
  57. @Override
  58. public void setPresenter(CameraContract.Presenter presenter) {
  59. this.presenter = presenter;
  60. }
  61. @Override
  62. public TextureView getCameraView() {
  63. return textureView;
  64. }
  65. protected String filePath;
  66. @Override
  67. public void loadPictureResult(String filePath) {
  68. this.filePath = filePath;
  69. GlideLoader.loadNetWorkResource(getActivity(), filePath, show_result_iv);
  70. }
  71. @Override
  72. public void onClick(View v) {
  73. switch (v.getId()) {
  74. //点击按钮,进行拍照或录像
  75. case R.id.camera_btn:
  76. this.presenter.takePictureOrVideo();
  77. break;
  78. // 控制视频录制的开关,包含暂停,恢复录制
  79. case R.id.camera_right_top_controller:
  80. int mode = (int) controller_state_iv.getTag();
  81. //录制状态中,可以暂停
  82. if (mode == CameraContract.View.MODE_RECORD_START) {
  83. this.presenter.stopRecord();
  84. }//暂停状态,可以继续开始录制
  85. else if (mode == CameraContract.View.MODE_RECORD_STOP) {
  86. this.presenter.restartRecord();
  87. }
  88. break;
  89. //查看大图
  90. case R.id.camera_show:
  91. if (!TextUtils.isEmpty(filePath)) {
  92. PictureActivity.openActivity(getActivity(), filePath);
  93. }
  94. break;
  95. default:
  96. break;
  97. }
  98. }
  99. @Override
  100. public void setTimingShow(String timing) {
  101. this.show_record_tv.setText(timing);
  102. }
  103. @Override
  104. public void switchRecordMode(int mode) {
  105. switch (mode) {
  106. //录制开始
  107. case CameraContract.View.MODE_RECORD_START:
  108. this.show_record_tv.setVisibility(View.VISIBLE);
  109. this.record_tip_circle.setVisibility(View.VISIBLE);
  110. this.controller_state_iv.setImageResource(R.drawable.camera_stop_iv);
  111. if (flashAnimator != null && flashAnimator.isRunning()) {
  112. flashAnimator.cancel();
  113. }
  114. break;
  115. //录制暂停
  116. case CameraContract.View.MODE_RECORD_STOP:
  117. this.controller_state_iv.setImageResource(R.drawable.camera_start_iv);
  118. this.show_record_tv.setVisibility(View.INVISIBLE);
  119. flashAnimator = AnimatorBuilder.createFlashAnimator(this.record_tip_circle);
  120. flashAnimator.start();
  121. break;
  122. //录制完成
  123. case CameraContract.View.MODE_RECORD_FINISH:
  124. this.show_record_tv.setText("");
  125. this.show_record_tv.setVisibility(View.GONE);
  126. this.record_tip_circle.setVisibility(View.GONE);
  127. this.controller_state_iv.setImageResource(R.drawable.camera_init_iv);
  128. break;
  129. default:
  130. break;
  131. }
  132. this.controller_state_iv.setTag(mode);
  133. }
  134. @Override
  135. public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
  136. switch (checkedId) {
  137. //切换成录像模式
  138. case R.id.camera_video_record_btn:
  139. this.presenter.switchMode(Constant.MODE_VIDEO_RECORD);
  140. break;
  141. //切换到拍照模式
  142. case R.id.camera_switch_picture_btn:
  143. this.presenter.switchMode(Constant.MODE_CAMERA);
  144. break;
  145. //切换到前摄像头
  146. case R.id.camera_direction_front:
  147. this.presenter.switchCamera(Camera2Manager.CAMERA_DIRECTION_FRONT);
  148. break;
  149. //切换到后摄像头
  150. case R.id.camera_direction_back:
  151. this.presenter.switchCamera(Camera2Manager.CAMERA_DIRECTION_BACK);
  152. break;
  153. default:
  154. break;
  155. }
  156. }
  157. @Override
  158. public void moveDistance(float verticalBias) {
  159. Log.d(TAG, "moveDistance--verticalBias: " + verticalBias);
  160. if (presenter != null) {
  161. presenter.setManualFocus(verticalBias);
  162. }
  163. }
  164. }

另外一个项目的效果图:

 源码地址:

github开源专业相机https://github.com/SereneGuest/Camera2

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/591540
推荐阅读
相关标签
  

闽ICP备14008679号