Advertisement
twerd

Highspeed Preview

May 24th, 2016
3,607
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 29.81 KB | None | 0 0
  1. /*
  2.  * Copyright 2014 The Android Open Source Project
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *       http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16.  
  17. package com.example.android.camera2video;
  18.  
  19. import android.Manifest;
  20. import android.app.Activity;
  21. import android.app.AlertDialog;
  22. import android.app.Dialog;
  23. import android.app.DialogFragment;
  24. import android.app.Fragment;
  25. import android.content.Context;
  26. import android.content.DialogInterface;
  27. import android.content.pm.PackageManager;
  28. import android.content.res.Configuration;
  29. import android.graphics.Matrix;
  30. import android.graphics.RectF;
  31. import android.graphics.SurfaceTexture;
  32. import android.hardware.camera2.CameraAccessException;
  33. import android.hardware.camera2.CameraCaptureSession;
  34. import android.hardware.camera2.CameraCharacteristics;
  35. import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession;
  36. import android.hardware.camera2.CameraDevice;
  37. import android.hardware.camera2.CameraManager;
  38. import android.hardware.camera2.CameraMetadata;
  39. import android.hardware.camera2.CaptureRequest;
  40. import android.hardware.camera2.TotalCaptureResult;
  41. import android.hardware.camera2.params.StreamConfigurationMap;
  42. import android.media.MediaRecorder;
  43. import android.opengl.GLES20;
  44. import android.os.Bundle;
  45. import android.os.Handler;
  46. import android.os.HandlerThread;
  47. import android.support.annotation.NonNull;
  48. import android.support.v13.app.FragmentCompat;
  49. import android.support.v4.app.ActivityCompat;
  50. import android.util.Log;
  51. import android.util.Range;
  52. import android.util.Size;
  53. import android.util.SparseIntArray;
  54. import android.view.LayoutInflater;
  55. import android.view.Surface;
  56. import android.view.TextureView;
  57. import android.view.View;
  58. import android.view.ViewGroup;
  59. import android.widget.Button;
  60. import android.widget.Toast;
  61.  
  62. import java.io.IOException;
  63. import java.util.ArrayList;
  64. import java.util.Arrays;
  65. import java.util.Collections;
  66. import java.util.Comparator;
  67. import java.util.List;
  68. import java.util.concurrent.Semaphore;
  69. import java.util.concurrent.TimeUnit;
  70.  
  71. public class Camera2VideoFragment extends Fragment
  72.         implements View.OnClickListener, FragmentCompat.OnRequestPermissionsResultCallback {
  73.  
  74.     private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
  75.     private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
  76.     private static final SparseIntArray DEFAULT_ORIENTATIONS = new SparseIntArray();
  77.     private static final SparseIntArray INVERSE_ORIENTATIONS = new SparseIntArray();
  78.  
  79.     private static final String TAG = "Camera2VideoFragment";
  80.     private static final int REQUEST_VIDEO_PERMISSIONS = 1;
  81.     private static final String FRAGMENT_DIALOG = "dialog";
  82.  
  83.     private static final String[] VIDEO_PERMISSIONS = {
  84.             Manifest.permission.CAMERA,
  85.             Manifest.permission.RECORD_AUDIO,
  86.     };
  87.  
  88.     static {
  89.         DEFAULT_ORIENTATIONS.append(Surface.ROTATION_0, 90);
  90.         DEFAULT_ORIENTATIONS.append(Surface.ROTATION_90, 0);
  91.         DEFAULT_ORIENTATIONS.append(Surface.ROTATION_180, 270);
  92.         DEFAULT_ORIENTATIONS.append(Surface.ROTATION_270, 180);
  93.     }
  94.  
  95.     static {
  96.         INVERSE_ORIENTATIONS.append(Surface.ROTATION_0, 270);
  97.         INVERSE_ORIENTATIONS.append(Surface.ROTATION_90, 180);
  98.         INVERSE_ORIENTATIONS.append(Surface.ROTATION_180, 90);
  99.         INVERSE_ORIENTATIONS.append(Surface.ROTATION_270, 0);
  100.     }
  101.  
  102.     /**
  103.      * An {@link AutoFitTextureView} for camera preview.
  104.      */
  105.     private AutoFitTextureView mTextureView;
  106.  
  107.     /**
  108.      * Button to record video
  109.      */
  110.     private Button mButtonVideo;
  111.  
  112.     /**
  113.      * A refernce to the opened {@link android.hardware.camera2.CameraDevice}.
  114.      */
  115.     private CameraDevice mCameraDevice;
  116.  
  117.     /**
  118.      * A reference to the current {@link android.hardware.camera2.CameraCaptureSession} for
  119.      * preview.
  120.      */
  121.     private CameraConstrainedHighSpeedCaptureSession mPreviewSession;
  122.  
  123.     /**
  124.      * {@link TextureView.SurfaceTextureListener} handles several lifecycle events on a
  125.      * {@link TextureView}.
  126.      */
  127.     private TextureView.SurfaceTextureListener mSurfaceTextureListener
  128.             = new TextureView.SurfaceTextureListener() {
  129.  
  130.         @Override
  131.         public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
  132.                                               int width, int height) {
  133.             openCamera(width, height);
  134.         }
  135.  
  136.         @Override
  137.         public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
  138.                                                 int width, int height) {
  139.             configureTransform(width, height);
  140.         }
  141.  
  142.         @Override
  143.         public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
  144.             return true;
  145.         }
  146.  
  147.         @Override
  148.         public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
  149.             //Should I try using GLES20 here?
  150.             Log.i("Surface Texture", "available");
  151.         }
  152.  
  153.     };
  154.  
  155.     /**
  156.      * The {@link android.util.Size} of camera preview.
  157.      */
  158.     private Size mPreviewSize;
  159.  
  160.     /**
  161.      * The {@link android.util.Size} of video recording.
  162.      */
  163.     private Size mVideoSize;
  164.  
  165.     /**
  166.      * MediaRecorder
  167.      */
  168.     private MediaRecorder mMediaRecorder;
  169.  
  170.     /**
  171.      * Whether the app is recording video now
  172.      */
  173.     private boolean mIsRecordingVideo;
  174.  
  175.     /**
  176.      * An additional thread for running tasks that shouldn't block the UI.
  177.      */
  178.     private HandlerThread mBackgroundThread;
  179.  
  180.     /**
  181.      * A {@link Handler} for running tasks in the background.
  182.      */
  183.     private Handler mBackgroundHandler;
  184.  
  185.     /**
  186.      * A {@link Semaphore} to prevent the app from exiting before closing the camera.
  187.      */
  188.     private Semaphore mCameraOpenCloseLock = new Semaphore(1);
  189.  
  190.     /**
  191.      * {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its status.
  192.      */
  193.     private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
  194.  
  195.         @Override
  196.         public void onOpened(CameraDevice cameraDevice) {
  197.             mCameraDevice = cameraDevice;
  198.             startPreview();
  199.             mCameraOpenCloseLock.release();
  200.             if (null != mTextureView) {
  201.                 configureTransform(mTextureView.getWidth(), mTextureView.getHeight());
  202.             }
  203.         }
  204.  
  205.         @Override
  206.         public void onDisconnected(CameraDevice cameraDevice) {
  207.             mCameraOpenCloseLock.release();
  208.             cameraDevice.close();
  209.             mCameraDevice = null;
  210.         }
  211.  
  212.         @Override
  213.         public void onError(CameraDevice cameraDevice, int error) {
  214.             mCameraOpenCloseLock.release();
  215.             cameraDevice.close();
  216.             mCameraDevice = null;
  217.             Activity activity = getActivity();
  218.             if (null != activity) {
  219.                 activity.finish();
  220.             }
  221.         }
  222.  
  223.     };
  224.     private Integer mSensorOrientation;
  225.     private String mNextVideoAbsolutePath;
  226.     private CaptureRequest.Builder mPreviewBuilder;
  227.     private Surface mRecorderSurface;
  228.  
  229.     public static Camera2VideoFragment newInstance() {
  230.         return new Camera2VideoFragment();
  231.     }
  232.  
  233.     /**
  234.      * In this sample, we choose a video size with 3x4 aspect ratio. Also, we don't use sizes
  235.      * larger than 1080p, since MediaRecorder cannot handle such a high-resolution video.
  236.      *
  237.      * @param choices The list of available sizes
  238.      * @return The video size
  239.      */
  240.     private static Size chooseVideoSize(Size[] choices) {
  241.         for (Size size : choices) {
  242.             if (size.getWidth() == size.getHeight() * 4 / 3 && size.getWidth() <= 1080) {
  243.                 return size;
  244.             }
  245.         }
  246.         Log.e(TAG, "Couldn't find any suitable video size");
  247.         return choices[choices.length - 1];
  248.     }
  249.  
  250.     /**
  251.      * Given {@code choices} of {@code Size}s supported by a camera, chooses the smallest one whose
  252.      * width and height are at least as large as the respective requested values, and whose aspect
  253.      * ratio matches with the specified value.
  254.      *
  255.      * @param choices     The list of sizes that the camera supports for the intended output class
  256.      * @param width       The minimum desired width
  257.      * @param height      The minimum desired height
  258.      * @param aspectRatio The aspect ratio
  259.      * @return The optimal {@code Size}, or an arbitrary one if none were big enough
  260.      */
  261.     private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
  262.         // Collect the supported resolutions that are at least as big as the preview Surface
  263.         List<Size> bigEnough = new ArrayList<Size>();
  264.         int w = aspectRatio.getWidth();
  265.         int h = aspectRatio.getHeight();
  266.         for (Size option : choices) {
  267.             if (option.getHeight() == option.getWidth() * h / w &&
  268.                     option.getWidth() >= width && option.getHeight() >= height) {
  269.                 bigEnough.add(option);
  270.             }
  271.         }
  272.  
  273.         // Pick the smallest of those, assuming we found any
  274.         if (bigEnough.size() > 0) {
  275.             return Collections.min(bigEnough, new CompareSizesByArea());
  276.         } else {
  277.             Log.e(TAG, "Couldn't find any suitable preview size");
  278.             return choices[0];
  279.         }
  280.     }
  281.  
  282.     @Override
  283.     public View onCreateView(LayoutInflater inflater, ViewGroup container,
  284.                              Bundle savedInstanceState) {
  285.         return inflater.inflate(R.layout.fragment_camera2_video, container, false);
  286.     }
  287.  
  288.     @Override
  289.     public void onViewCreated(final View view, Bundle savedInstanceState) {
  290.         mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);
  291.         mButtonVideo = (Button) view.findViewById(R.id.video);
  292.         mButtonVideo.setOnClickListener(this);
  293.         view.findViewById(R.id.info).setOnClickListener(this);
  294.     }
  295.  
  296.     @Override
  297.     public void onResume() {
  298.         super.onResume();
  299.         startBackgroundThread();
  300.         if (mTextureView.isAvailable()) {
  301.             openCamera(mTextureView.getWidth(), mTextureView.getHeight());
  302.         } else {
  303.             mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
  304.         }
  305.     }
  306.  
  307.     @Override
  308.     public void onPause() {
  309.         closeCamera();
  310.         stopBackgroundThread();
  311.         super.onPause();
  312.     }
  313.  
  314.     @Override
  315.     public void onClick(View view) {
  316.         switch (view.getId()) {
  317.             case R.id.info: {
  318.                 Activity activity = getActivity();
  319.                 if (null != activity) {
  320.                     new AlertDialog.Builder(activity)
  321.                             .setMessage(R.string.intro_message)
  322.                             .setPositiveButton(android.R.string.ok, null)
  323.                             .show();
  324.                 }
  325.                 break;
  326.             }
  327.         }
  328.     }
  329.  
  330.     /**
  331.      * Starts a background thread and its {@link Handler}.
  332.      */
  333.     private void startBackgroundThread() {
  334.         mBackgroundThread = new HandlerThread("CameraBackground");
  335.         mBackgroundThread.start();
  336.         mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
  337.     }
  338.  
  339.     /**
  340.      * Stops the background thread and its {@link Handler}.
  341.      */
  342.     private void stopBackgroundThread() {
  343.         mBackgroundThread.quitSafely();
  344.         try {
  345.             mBackgroundThread.join();
  346.             mBackgroundThread = null;
  347.             mBackgroundHandler = null;
  348.         } catch (InterruptedException e) {
  349.             e.printStackTrace();
  350.         }
  351.     }
  352.  
  353.     /**
  354.      * Gets whether you should show UI with rationale for requesting permissions.
  355.      *
  356.      * @param permissions The permissions your app wants to request.
  357.      * @return Whether you can show permission rationale UI.
  358.      */
  359.     private boolean shouldShowRequestPermissionRationale(String[] permissions) {
  360.         for (String permission : permissions) {
  361.             if (FragmentCompat.shouldShowRequestPermissionRationale(this, permission)) {
  362.                 return true;
  363.             }
  364.         }
  365.         return false;
  366.     }
  367.  
  368.     /**
  369.      * Requests permissions needed for recording video.
  370.      */
  371.     private void requestVideoPermissions() {
  372.         if (shouldShowRequestPermissionRationale(VIDEO_PERMISSIONS)) {
  373.             new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);
  374.         } else {
  375.             FragmentCompat.requestPermissions(this, VIDEO_PERMISSIONS, REQUEST_VIDEO_PERMISSIONS);
  376.         }
  377.     }
  378.  
  379.     @Override
  380.     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
  381.                                            @NonNull int[] grantResults) {
  382.         Log.d(TAG, "onRequestPermissionsResult");
  383.         if (requestCode == REQUEST_VIDEO_PERMISSIONS) {
  384.             if (grantResults.length == VIDEO_PERMISSIONS.length) {
  385.                 for (int result : grantResults) {
  386.                     if (result != PackageManager.PERMISSION_GRANTED) {
  387.                         ErrorDialog.newInstance(getString(R.string.permission_request))
  388.                                 .show(getChildFragmentManager(), FRAGMENT_DIALOG);
  389.                         break;
  390.                     }
  391.                 }
  392.             } else {
  393.                 ErrorDialog.newInstance(getString(R.string.permission_request))
  394.                         .show(getChildFragmentManager(), FRAGMENT_DIALOG);
  395.             }
  396.         } else {
  397.             super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  398.         }
  399.     }
  400.  
  401.     private boolean hasPermissionsGranted(String[] permissions) {
  402.         for (String permission : permissions) {
  403.             if (ActivityCompat.checkSelfPermission(getActivity(), permission)
  404.                     != PackageManager.PERMISSION_GRANTED) {
  405.                 return false;
  406.             }
  407.         }
  408.         return true;
  409.     }
  410.  
  411.     /**
  412.      * Tries to open a {@link CameraDevice}. The result is listened by `mStateCallback`.
  413.      */
  414.     private void openCamera(int width, int height) {
  415.         if (!hasPermissionsGranted(VIDEO_PERMISSIONS)) {
  416.             requestVideoPermissions();
  417.             return;
  418.         }
  419.         final Activity activity = getActivity();
  420.         if (null == activity || activity.isFinishing()) {
  421.             return;
  422.         }
  423.         CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
  424.         try {
  425.             Log.d(TAG, "tryAcquire");
  426.             if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
  427.                 throw new RuntimeException("Time out waiting to lock camera opening.");
  428.             }
  429.             String cameraId = manager.getCameraIdList()[0];
  430.  
  431.             // Choose the sizes for camera preview and video recording
  432.             CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
  433.             StreamConfigurationMap map = characteristics
  434.                     .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
  435.  
  436.             mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
  437.             mVideoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder.class));
  438.             mPreviewSize = new Size(1280, 720);//chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height, mVideoSize);
  439.  
  440.             int orientation = getResources().getConfiguration().orientation;
  441.             if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
  442.                 mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
  443.             } else {
  444.                 mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
  445.             }
  446.             configureTransform(width, height);
  447.             mMediaRecorder = new MediaRecorder();
  448.             manager.openCamera(cameraId, mStateCallback, null);
  449.         } catch (CameraAccessException e) {
  450.             Toast.makeText(activity, "Cannot access the camera.", Toast.LENGTH_SHORT).show();
  451.             activity.finish();
  452.         } catch (NullPointerException e) {
  453.             // Currently an NPE is thrown when the Camera2API is used but not supported on the
  454.             // device this code runs.
  455.             ErrorDialog.newInstance(getString(R.string.camera_error))
  456.                     .show(getChildFragmentManager(), FRAGMENT_DIALOG);
  457.         } catch (InterruptedException e) {
  458.             throw new RuntimeException("Interrupted while trying to lock camera opening.");
  459.         }
  460.     }
  461.  
  462.     private void closeCamera() {
  463.         try {
  464.             mCameraOpenCloseLock.acquire();
  465.             closePreviewSession();
  466.             if (null != mCameraDevice) {
  467.                 mCameraDevice.close();
  468.                 mCameraDevice = null;
  469.             }
  470.             if (null != mMediaRecorder) {
  471.                 mMediaRecorder.release();
  472.                 mMediaRecorder = null;
  473.             }
  474.         } catch (InterruptedException e) {
  475.             throw new RuntimeException("Interrupted while trying to lock camera closing.");
  476.         } finally {
  477.             mCameraOpenCloseLock.release();
  478.         }
  479.     }
  480.  
  481.     /**
  482.      * Start the camera preview.
  483.      */
  484.     private void startPreview() {
  485.         if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
  486.             return;
  487.         }
  488.         try {
  489.             closePreviewSession();
  490.             SurfaceTexture texture = mTextureView.getSurfaceTexture();
  491.             assert texture != null;
  492.             texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
  493.             mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
  494.  
  495.             Surface previewSurface = new Surface(texture);
  496.             mPreviewBuilder.addTarget(previewSurface);
  497.  
  498.             mCameraDevice.createConstrainedHighSpeedCaptureSession(Arrays.asList(previewSurface), new CameraCaptureSession.StateCallback() {
  499.  
  500.                 @Override
  501.                 public void onConfigured(CameraCaptureSession cameraCaptureSession) {
  502.                     mPreviewSession = (CameraConstrainedHighSpeedCaptureSession) cameraCaptureSession;
  503.                     updatePreview();
  504.                 }
  505.  
  506.                 @Override
  507.                 public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
  508.                     Activity activity = getActivity();
  509.                     if (null != activity) {
  510.                         Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
  511.                     }
  512.                 }
  513.             }, mBackgroundHandler);
  514.         } catch (CameraAccessException e) {
  515.             e.printStackTrace();
  516.         }
  517.     }
  518.  
  519.     /**
  520.      * Update the camera preview. {@link #startPreview()} needs to be called in advance.
  521.      */
  522.     private void updatePreview() {
  523.         if (null == mCameraDevice) {
  524.             return;
  525.         }
  526.         try {
  527.             setUpCaptureRequestBuilder(mPreviewBuilder);
  528.             HandlerThread thread = new HandlerThread("CameraPreview");
  529.             thread.start();
  530.             List<CaptureRequest> capList = mPreviewSession.createHighSpeedRequestList(mPreviewBuilder.build());
  531.             //final long tic = System.currentTimeMillis();
  532.             mPreviewSession.setRepeatingBurst(capList, new CameraCaptureSession.CaptureCallback() {
  533.                 @Override
  534.                 public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
  535.                     super.onCaptureCompleted(session, request, result);
  536.                     //long toc = System. currentTimeMillis();
  537.                     //float fps = (toc-tic)/result.getFrameNumber();
  538.                     Log.i("Completed", "fps:" + result.getFrameNumber());
  539.                 }
  540.             }, mBackgroundHandler);
  541.  
  542.         } catch (CameraAccessException e) {
  543.             e.printStackTrace();
  544.         }
  545.     }
  546.  
  547.     private void setUpCaptureRequestBuilder(CaptureRequest.Builder builder) {
  548.         builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_OFF_KEEP_STATE);
  549.         builder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, new Range<Integer>(120, 120));
  550.     }
  551.  
  552.     /**
  553.      * Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
  554.      * This method should not to be called until the camera preview size is determined in
  555.      * openCamera, or until the size of `mTextureView` is fixed.
  556.      *
  557.      * @param viewWidth  The width of `mTextureView`
  558.      * @param viewHeight The height of `mTextureView`
  559.      */
  560.     private void configureTransform(int viewWidth, int viewHeight) {
  561.         Activity activity = getActivity();
  562.         if (null == mTextureView || null == mPreviewSize || null == activity) {
  563.             return;
  564.         }
  565.         int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
  566.         Matrix matrix = new Matrix();
  567.         RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
  568.         RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
  569.         float centerX = viewRect.centerX();
  570.         float centerY = viewRect.centerY();
  571.         if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
  572.             bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
  573.             matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
  574.             float scale = Math.max(
  575.                     (float) viewHeight / mPreviewSize.getHeight(),
  576.                     (float) viewWidth / mPreviewSize.getWidth());
  577.             matrix.postScale(scale, scale, centerX, centerY);
  578.             matrix.postRotate(90 * (rotation - 2), centerX, centerY);
  579.         }
  580.         mTextureView.setTransform(matrix);
  581.     }
  582.  
  583.     private void setUpMediaRecorder() throws IOException {
  584.         final Activity activity = getActivity();
  585.         if (null == activity) {
  586.             return;
  587.         }
  588.         mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  589.         mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
  590.         mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
  591.         if (mNextVideoAbsolutePath == null || mNextVideoAbsolutePath.isEmpty()) {
  592.             mNextVideoAbsolutePath = getVideoFilePath(getActivity());
  593.         }
  594.         mMediaRecorder.setOutputFile(mNextVideoAbsolutePath);
  595.         mMediaRecorder.setVideoEncodingBitRate(10000000);
  596.         mMediaRecorder.setVideoFrameRate(30);
  597.         mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
  598.         mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
  599.         mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
  600.         int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
  601.         switch (mSensorOrientation) {
  602.             case SENSOR_ORIENTATION_DEFAULT_DEGREES:
  603.                 mMediaRecorder.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation));
  604.                 break;
  605.             case SENSOR_ORIENTATION_INVERSE_DEGREES:
  606.                 mMediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation));
  607.                 break;
  608.         }
  609.         mMediaRecorder.prepare();
  610.     }
  611.  
  612.     private String getVideoFilePath(Context context) {
  613.         return context.getExternalFilesDir(null).getAbsolutePath() + "/"
  614.                 + System.currentTimeMillis() + ".mp4";
  615.     }
  616.  
  617. //    private void startRecordingVideo() {
  618. //        if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
  619. //            return;
  620. //        }
  621. //        try {
  622. //            closePreviewSession();
  623. //            setUpMediaRecorder();
  624. //            SurfaceTexture texture = mTextureView.getSurfaceTexture();
  625. //            assert texture != null;
  626. //            texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
  627. //            mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
  628. //            List<Surface> surfaces = new ArrayList<>();
  629. //
  630. //            // Set up Surface for the camera preview
  631. //            Surface previewSurface = new Surface(texture);
  632. //            surfaces.add(previewSurface);
  633. //            mPreviewBuilder.addTarget(previewSurface);
  634. //
  635. //            // Set up Surface for the MediaRecorder
  636. //            mRecorderSurface = mMediaRecorder.getSurface();
  637. //            surfaces.add(mRecorderSurface);
  638. //            mPreviewBuilder.addTarget(mRecorderSurface);
  639. //
  640. //            // Start a capture session
  641. //            // Once the session starts, we can update the UI and start recording
  642. //            mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
  643. //
  644. //                @Override
  645. //                public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
  646. //                    mPreviewSession = cameraCaptureSession;
  647. //                    updatePreview();
  648. //                    getActivity().runOnUiThread(new Runnable() {
  649. //                        @Override
  650. //                        public void run() {
  651. //                            // UI
  652. //                            mButtonVideo.setText(R.string.stop);
  653. //                            mIsRecordingVideo = true;
  654. //
  655. //                            // Start recording
  656. //                            mMediaRecorder.start();
  657. //                        }
  658. //                    });
  659. //                }
  660. //
  661. //                @Override
  662. //                public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
  663. //                    Activity activity = getActivity();
  664. //                    if (null != activity) {
  665. //                        Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
  666. //                    }
  667. //                }
  668. //            }, mBackgroundHandler);
  669. //        } catch (CameraAccessException e) {
  670. //            e.printStackTrace();
  671. //        } catch (IOException e) {
  672. //            e.printStackTrace();
  673. //        }
  674. //
  675. //    }
  676.  
  677.     private void closePreviewSession() {
  678.         if (mPreviewSession != null) {
  679.             mPreviewSession.close();
  680.             mPreviewSession = null;
  681.         }
  682.     }
  683.  
  684.     private void stopRecordingVideo() {
  685.         // UI
  686.         mIsRecordingVideo = false;
  687.         mButtonVideo.setText(R.string.record);
  688.         // Stop recording
  689.         mMediaRecorder.stop();
  690.         mMediaRecorder.reset();
  691.  
  692.         Activity activity = getActivity();
  693.         if (null != activity) {
  694.             Toast.makeText(activity, "Video saved: " + mNextVideoAbsolutePath,
  695.                     Toast.LENGTH_SHORT).show();
  696.             Log.d(TAG, "Video saved: " + mNextVideoAbsolutePath);
  697.         }
  698.         mNextVideoAbsolutePath = null;
  699.         startPreview();
  700.     }
  701.  
  702.     /**
  703.      * Compares two {@code Size}s based on their areas.
  704.      */
  705.     static class CompareSizesByArea implements Comparator<Size> {
  706.  
  707.         @Override
  708.         public int compare(Size lhs, Size rhs) {
  709.             // We cast here to ensure the multiplications won't overflow
  710.             return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
  711.                     (long) rhs.getWidth() * rhs.getHeight());
  712.         }
  713.  
  714.     }
  715.  
  716.     public static class ErrorDialog extends DialogFragment {
  717.  
  718.         private static final String ARG_MESSAGE = "message";
  719.  
  720.         public static ErrorDialog newInstance(String message) {
  721.             ErrorDialog dialog = new ErrorDialog();
  722.             Bundle args = new Bundle();
  723.             args.putString(ARG_MESSAGE, message);
  724.             dialog.setArguments(args);
  725.             return dialog;
  726.         }
  727.  
  728.         @Override
  729.         public Dialog onCreateDialog(Bundle savedInstanceState) {
  730.             final Activity activity = getActivity();
  731.             return new AlertDialog.Builder(activity)
  732.                     .setMessage(getArguments().getString(ARG_MESSAGE))
  733.                     .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
  734.                         @Override
  735.                         public void onClick(DialogInterface dialogInterface, int i) {
  736.                             activity.finish();
  737.                         }
  738.                     })
  739.                     .create();
  740.         }
  741.  
  742.     }
  743.  
  744.     public static class ConfirmationDialog extends DialogFragment {
  745.  
  746.         @Override
  747.         public Dialog onCreateDialog(Bundle savedInstanceState) {
  748.             final Fragment parent = getParentFragment();
  749.             return new AlertDialog.Builder(getActivity())
  750.                     .setMessage(R.string.permission_request)
  751.                     .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
  752.                         @Override
  753.                         public void onClick(DialogInterface dialog, int which) {
  754.                             FragmentCompat.requestPermissions(parent, VIDEO_PERMISSIONS,
  755.                                     REQUEST_VIDEO_PERMISSIONS);
  756.                         }
  757.                     })
  758.                     .setNegativeButton(android.R.string.cancel,
  759.                             new DialogInterface.OnClickListener() {
  760.                                 @Override
  761.                                 public void onClick(DialogInterface dialog, int which) {
  762.                                     parent.getActivity().finish();
  763.                                 }
  764.                             })
  765.                     .create();
  766.         }
  767.  
  768.     }
  769.  
  770. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement