为什么视频在camera2 API中被拉长?

时间:2017-01-27 12:39:05

标签: android aspect-ratio android-camera2

我正在构建一个视频摄像头应用程序,它始终处于横向模式,并始终从前置摄像头录制。 但是当我录制视频时,它看起来像是拉长了。如何解决? 我在哪里弄错了?

public class MainActivity extends AppCompatActivity {

public static final int REQUEST_CAMERA_PERMISSION_RESULT = 0;
public static final int REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION_RESULT = 1;
private TextureView mTextureView;
//public ImageView mImageView;
private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
        //Toast.makeText(getApplicationContext(),"TextureView is Available",Toast.LENGTH_SHORT).show();
        setupCamera(width, height);
        connectCamera();
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

    }
};
private CameraDevice mCameraDevice;
private CameraDevice.StateCallback mCameraDeviceStateCallback;

{
    mCameraDeviceStateCallback = new CameraDevice.StateCallback() {

        @Override
        public void onOpened(CameraDevice camera) {
            mCameraDevice = camera;
            mMediaRecorder = new MediaRecorder();

            if (mIsRecording) {
                try {
                    createVideoFileName();
                } catch (IOException e) {
                    Log.e("Error", e.getMessage());
                    e.printStackTrace();
                }
                startRecord();
                mMediaRecorder.start();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mChronometer.setBase(SystemClock.elapsedRealtime());
                        mChronometer.setVisibility(View.VISIBLE);
                        mChronometer.start();
                    }
                });


            } else {

                startPreview();

            }


            //Toast.makeText(getApplicationContext(),"Camera connected",Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onDisconnected(CameraDevice camera) {
            camera.close();
            mCameraDevice = null;


        }


        @Override
        public void onError(CameraDevice camera, int i) {

        }
    };
}

private HandlerThread mBackgroundHandlerThread;
private Handler mBackgroundHandler;
private String mCameraId;
private Size mPreviewSize;
private Size mVideoSize;
private MediaRecorder mMediaRecorder;
private Chronometer mChronometer;
private ImageView thumb;
//private String V1, V2, V3, V4, V5;
//    private Map<String, String> mapA = new HashMap<>();
// private ImageView[] IMGS = {mImageView1, mImageView2, mImageView3, mImageView4, mImageView5};
private int mTotalRotation;
private CaptureRequest.Builder mCaptureRequestBuilder;
public static int count;
public static int max = 5;
private ImageButton mRecordImageButton;
private boolean mIsRecording = false;
public static File mVideoFolder;
private static File mRawVideoFolder;
public static String mVideoFileName;

//Test
private List<Bitmap> bitMapsAvailable = new ArrayList<>();
private List<String> bitMapsFilePath = new ArrayList<>();
private int bitMapIndex;
CameraCaptureSession storedSession;
private ArrayAdapter bitMapAdapter;
private ArrayAdapter bitMapFileAdapter;
private static SparseIntArray ORIENTATIONS = new SparseIntArray();
public int index;
static {
    ORIENTATIONS.append(Surface.ROTATION_0, 0);
    ORIENTATIONS.append(Surface.ROTATION_90, 90);
    ORIENTATIONS.append(Surface.ROTATION_180, 180);
    ORIENTATIONS.append(Surface.ROTATION_270, 270);

}

private static class CompareSizeByArea implements Comparator<Size> {

    @Override
    public int compare(Size lhs, Size rhs) {
        return Long.signum((long) lhs.getWidth() * lhs.getHeight() / (long) rhs.getWidth() * rhs.getHeight());
    }
}


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    createVideoFolder();

    mMediaRecorder = new MediaRecorder();
    mChronometer = (Chronometer) findViewById(R.id.chronometer);
    mTextureView = (TextureView) findViewById(R.id.textureView);

    mRecordImageButton = (ImageButton) findViewById(R.id.videoButton);
    mRecordImageButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mIsRecording) {
                mChronometer.stop();
                mChronometer.setVisibility(View.INVISIBLE);
                mIsRecording = false;
                mRecordImageButton.setImageResource(R.mipmap.start_recording);
                //Toast.makeText(getApplicationContext(),"Started",Toast.LENGTH_SHORT).show();

                if(storedSession != null){
                    try {
                        storedSession.stopRepeating();
                        storedSession.abortCaptures();
                    }catch (CameraAccessException e){
                        throw new RuntimeException(e.getMessage());
                    }
                }
                mMediaRecorder.stop();
                mMediaRecorder.reset();
                startPreview();
                //Create bitmap with current video file path
                Bitmap bitMap = ThumbnailUtils.createVideoThumbnail(mVideoFileName, MediaStore.Video.Thumbnails.MICRO_KIND);
                //Add bitmap to array list
                bitMapsAvailable.add(bitMap);
                bitMapsFilePath.add(mVideoFileName);
                // Shows  thumbnails
                showThumbnails();
            } else {
                checkWriteStoragePermission();
            }
        }

    });
}

private void showThumbnails() {

    LinearLayout layout = (LinearLayout) findViewById(R.id.thumbnails);

    bitMapAdapter = new ArrayAdapter(this, R.layout.activity_main, bitMapsAvailable);
    bitMapFileAdapter = new ArrayAdapter(this, R.layout.activity_main, bitMapsFilePath);


    bitMapIndex = 0;
    if (layout.getChildCount() > 0) {
        layout.removeAllViews();
    }
    for (Bitmap eachBitMap : bitMapsAvailable) {

        bitMapIndex++;
        ImageView thumb = new ImageView(this);
        thumb.setId(new Integer(bitMapIndex+ 17));
        thumb.setLayoutParams(new android.view.ViewGroup.LayoutParams(100, 80));
        thumb.setImageBitmap(eachBitMap);
        // Adds the view to the layout
        thumb.setOnClickListener(previewThumb(thumb));


        layout.addView(thumb);
    }
}
View.OnClickListener previewThumb(final ImageView imageview) {

    return new View.OnClickListener() {
        public void onClick(View arg0) {

            index = imageview.getId()-18;
            imageview.setBackgroundColor(0xff999999);
            // Start NewActivity.class
            Intent myIntent = new Intent(MainActivity.this,
                    VideoViewActivity.class);

            Bundle bundle = new Bundle();

            bundle.putStringArrayList("bitMapsAvailable", new ArrayList(bitMapsAvailable));
            bundle.putStringArrayList("bitMapsFilePath", new ArrayList(bitMapsFilePath));
            //Add your data to bundle
            bundle.putInt("urlIndex", index);
            myIntent.putExtras(bundle);
            bitMapAdapter.notifyDataSetChanged();
            bitMapFileAdapter.notifyDataSetChanged();

          //  startActivity(myIntent);
            startActivityForResult(myIntent, 111);

        }
    };
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {
        if (requestCode == 111) {
            int indexToBeDeleted = data.getIntExtra("indexToBeDeleted",index);
            //bitMapsFilePath.remove(indexToBeDeleted);
            bitMapsAvailable.remove(indexToBeDeleted);
        }
    }
}
@Override
protected void onResume() {
    super.onResume();
    startBackgroundThread();
    if (mTextureView.isAvailable()) {
        setupCamera(mTextureView.getWidth(), mTextureView.getHeight());
        connectCamera();
    } else {
        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permission, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permission, grantResults);
    if (requestCode == REQUEST_CAMERA_PERMISSION_RESULT) {
        if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(getApplicationContext(), "Application will not run without camera service", Toast.LENGTH_SHORT).show();
        }
        if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(getApplicationContext(), "Application will not have audio on record ", Toast.LENGTH_SHORT).show();
        }
    }
    if (requestCode == REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION_RESULT) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            mIsRecording = true;
            mRecordImageButton.setImageResource(R.mipmap.ic_launcher);
            try {
                createVideoFileName();
            } catch (IOException e) {
                Log.e("Error", e.getMessage());
                e.printStackTrace();
            }
            Toast.makeText(this, "Permission Successfully Granted", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "App needs to save video to run", Toast.LENGTH_SHORT).show();
        }
    }
}


@Override
protected void onPause() {
    closeCamera();
    stopBackgroundThread();
    super.onPause();

}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    View decorView = getWindow().getDecorView();
    if (hasFocus) {
        decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
    }
}

private void setupCamera(int width, int height) {
    CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
        for (String cameraId : cameraManager.getCameraIdList()) {
            CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
            if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK) {
                continue;
            }
            StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            //int deviceOrientation = getWindowManager().getDefaultDisplay().getRotation();
            mTotalRotation = sensorToDeviceRotation(cameraCharacteristics);
            boolean swapRotation = mTotalRotation == 90 || mTotalRotation == 270;
            int rotateWidth = width;
            int rotateHeight = height;
            if (swapRotation) {
                rotateWidth = height;
                rotateHeight = width;
            }
            mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), rotateWidth, rotateHeight);
            mVideoSize = chooseOptimalSize(map.getOutputSizes(MediaRecorder.class), rotateWidth, rotateHeight);
            mCameraId = cameraId;

            return;
        }
    } catch (CameraAccessException e) {
        Log.e("Error", e.getMessage());
        e.printStackTrace();
    }
}

private void connectCamera() {
    CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
                cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, mBackgroundHandler);
            } else {
                if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
                    Toast.makeText(this, "Video app required access to camera", Toast.LENGTH_SHORT).show();
                }
                requestPermissions(new String[]{android.Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}, REQUEST_CAMERA_PERMISSION_RESULT);
            }
        } else {
            cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, mBackgroundHandler);
        }
    } catch (CameraAccessException e) {
        Log.e("Error", e.getMessage());
        e.printStackTrace();
    }
}

private void startRecord() {
    if (this.bitMapsAvailable.size() < max) {

        try {
            setupMediaRecorder();
            SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
            surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            Surface previewSurface = new Surface(surfaceTexture);
            Surface recordSurface = mMediaRecorder.getSurface();
            mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
            mCaptureRequestBuilder.addTarget(previewSurface);
            mCaptureRequestBuilder.addTarget(recordSurface);

            mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, recordSurface), new CameraCaptureSession.StateCallback() {

                @Override
                public void onConfigured(CameraCaptureSession session) {
                    try {
                        session.setRepeatingRequest(mCaptureRequestBuilder.build(), null, null);
                        storedSession = session;
                    } catch (CameraAccessException e) {
                        Log.e("Error", e.getMessage());
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession session) {

                }
            }, null);
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }
    } else {

    }

}

private void startPreview() {
    SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
    surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
    Surface previewSurface = new Surface(surfaceTexture);
    try {
        mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        mCaptureRequestBuilder.addTarget(previewSurface);
        mCameraDevice.createCaptureSession(Arrays.asList(previewSurface), new CameraCaptureSession.StateCallback() {

            @Override
            public void onConfigured(CameraCaptureSession session) {
                try {
                    session.stopRepeating();
                    session.abortCaptures();
                    session.setRepeatingRequest(mCaptureRequestBuilder.build(), null, mBackgroundHandler);

                } catch (CameraAccessException e) {
                    Log.e("Error", e.getMessage());
                    e.printStackTrace();
                }
            }

            @Override
            public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
                Toast.makeText(getApplicationContext(), "Unable to setup Camera Preview", Toast.LENGTH_SHORT).show();
            }
        }, null);
    } catch (CameraAccessException e) {
        Log.e("Error", e.getMessage());
        e.printStackTrace();
    }
}

private void closeCamera() {
    if (mCameraDevice != null) {
        mCameraDevice.close();
        mCameraDevice = null;

    }
}

private void startBackgroundThread() {
    mBackgroundHandlerThread = new HandlerThread("AuthorTV");
    mBackgroundHandlerThread.start();
    mBackgroundHandler = new Handler(mBackgroundHandlerThread.getLooper());
}

private void stopBackgroundThread() {
    mBackgroundHandlerThread.quitSafely();
    try {
        mBackgroundHandlerThread.join();
        mBackgroundHandlerThread = null;
        mBackgroundHandler = null;
    } catch (InterruptedException e) {
        Log.e("Error", e.getMessage());
        e.printStackTrace();
    }
}

private static int sensorToDeviceRotation(CameraCharacteristics cameraCharacteristics) {
    int sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
    // deviceOrientation = ORIENTATIONS.get(deviceOrientation);
    return (sensorOrientation + 180 + 360) % 360;
}

private static Size chooseOptimalSize(Size[] choices, int width, int height) {
    List<Size> bigEnough = new ArrayList<Size>();
    for (Size option : choices) {
        if (option.getHeight() == option.getWidth() * height / width && option.getWidth() >= width && option.getHeight() >= height) {
            bigEnough.add(option);
        }
    }
    if (bigEnough.size() > 0) {
        return Collections.min(bigEnough, new CompareSizeByArea());
    } else {
        return choices[0];
    }
}


private void setupMediaRecorder() throws IOException {
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setOutputFile(mVideoFileName);
    mMediaRecorder.setVideoEncodingBitRate(1000000);
    mMediaRecorder.setVideoFrameRate(30);
    mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
    mMediaRecorder.setOrientationHint(mTotalRotation);
    mMediaRecorder.prepare();
}

1 个答案:

答案 0 :(得分:0)

chooseOptimalSize需要针对mPreviewSizemVideoSize进行调整和区分。请检查此链接Camera2VideoFragment.java