Android音视频开发基础(三) : 在Android平台使用Camera API进行视频的采集,并且预览Camera数据,得到NV21数据进行回调

前言

在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》。本文是Android音视频任务列表的第三篇, 对应的要学习的内容是:在Android平台使用Camera API进行视频的采集,分别使用SurfaceView、TextureView来预览Camera数据,取到NV21的数据回调(例如将获取的NV21数据进行处理之后显示在ImageView控件上面)。


音视频任务列表

音视频任务列表: 点击此处跳转查看


一、目录

在这里插入图片描述


(一)Camera采集数据步骤

(1)打开摄像头

 mCamera = Camera.open();

(2)设置摄像头的预览数据界面

预览一般有两种方式:
SurfaceView:是调用setPreviewDisplay方法设置SurfaceHolder,也就是和SurfaceView进行绑定
TextureView:是调用setPreviewTexture方法设置SurfaceTexture,就是和TextureView绑定了

(3)获取到Camera.Parameters参数信息(如果是简单的预览,就不用设置参数信息了)

Camera.Parameters parameters = mCamera.getParameters(); //获取摄像头参数 

// 可以根据情况设置参数
// 镜头缩放
parameters.setZoom();  
// 设置预览照片的大小
parameters.setPreviewSize(200, 200);
// 设置预览照片时每秒显示多少帧的最小值和最大值
parameters.setPreviewFpsRange(4, 10);
// 设置图片格式
parameters.setPictureFormat(ImageFormat.JPEG);
// 设置JPG照片的质量  图片的质量[0-100],100最高
parameters.set("jpeg-quality", 85);
// 设置照片的大小
parameters.setPictureSize(200, 200);

mCamera.setParameters(parameters);

(4)在把添加好的参数信息设置回去,调用startPreview开始预览效果了

mCamera.startPreview();

(5)释放摄像头

  mCamera.release();

注意 Camera用完了之后一定要释放掉,不然别的地方调用不到相机的。


(二)SurfaceView来预览Camera数据

package com.lzacking.cameraapidemo;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;

import java.io.IOException;

public class CameraSurfaceViewActivity extends AppCompatActivity implements SurfaceHolder.Callback {

    private SurfaceView mSurfaceView;
    private Camera mCamera;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera_surface_view);

        mSurfaceView = findViewById(R.id.surfaceView);
        mSurfaceView.getHolder().addCallback(this);

        // 打开摄像头并将展示方向旋转90度
        mCamera = Camera.open(0);
        mCamera.setDisplayOrientation(90);
    }


    //------ SurfaceView预览 -------
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 在控件创建的时候,进行相应的初始化工作
        try {
            mCamera.setPreviewDisplay(holder);
            // 开始预览
            mCamera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 变化时,可以做相应操作
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // 释放摄像头
        mCamera.release();
    }

}

(三)TextureView来预览Camera数据

package com.lzacking.cameraapidemo;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.TextureView;

import java.io.IOException;

public class CameraTextureViewActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {

    private TextureView mTextureView;
    private Camera mCamera;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera_texture_view);

        mTextureView = findViewById(R.id.textureView);
        mTextureView.setSurfaceTextureListener(this);

        // 打开摄像头并将展示方向旋转90度
        mCamera = Camera.open(0);
        mCamera.setDisplayOrientation(90);
    }


    //------ TextureView预览 -------
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        // 在控件创建的时候,进行相应的初始化工作
        try {
            mCamera.setPreviewTexture(surface);
            // 开始预览
            mCamera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        // 变化时,可以做相应操作
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        // 释放相机
        mCamera.release();
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }

}

(四)得到NV21的数据回调

Android 中Google支持的 Camera Preview Callback的YUV常用格式有两种:一个是NV21,一个是YV12。Android一般默认使用YCbCr_420_SP的格式(NV21)

Camera.Parameters parameters = camera.getParameters();
    parameters.setPreviewFormat(ImageFormat.NV21);
    camera.setParameters(parameters);

    // 通过setPreviewCallback方法监听预览的回调:
    camera.setPreviewCallback(new Camera.PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] bytes, Camera camera) {
            // 这里面的Bytes的数据就是NV21格式的数据
        }
    });

用ImageView来显示取到NV21的数据

mCamera.setPreviewCallback(new Camera.PreviewCallback() {
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        // 处理data,这里面的data数据就是NV21格式的数据,将数据显示在ImageView控件上面
        mPreviewSize = camera.getParameters().getPreviewSize();// 获取尺寸,格式转换的时候要用到
        
        // 取发YUVIMAGE
        YuvImage yuvimage = new YuvImage(
                data,
                ImageFormat.NV21,
                mPreviewSize.width,
                mPreviewSize.height,
                null);
        mBaos = new ByteArrayOutputStream();
        
        // yuvimage转换成jpg格式
        yuvimage.compressToJpeg(new Rect(0, 0, mPreviewSize.width, mPreviewSize.height), 100, mBaos);// 80--JPG图片的质量[0-100],100最高
        mImageBytes = mBaos.toByteArray();

        // 将mImageBytes转换成bitmap
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.RGB_565;

        mBitmap = BitmapFactory.decodeByteArray(mImageBytes, 0, mImageBytes.length, options);
        mImageView.setImageBitmap(rotateBitmap(mBitmap, getDegree()));
    }
});

(五)完整代码

(1)布局

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"
    android:gravity="center">

    <Button
        android:id="@+id/btn_surfaceview"
        android:text="SurfaceView预览camera数据"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/btn_textureview"
        android:text="TextureView预览camera数据"
        android:textAllCaps="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"/>

    <Button
        android:id="@+id/btn_nv21data_callback"
        android:text="获取的NV21数据进行回调"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"/>

</LinearLayout>

activity_camera_surface_view.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CameraSurfaceViewActivity">

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </SurfaceView>

</LinearLayout>

activity_camera_texture_view.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CameraTextureViewActivity">

    <TextureView
        android:id="@+id/textureView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

activity_nv21data_callback.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".NV21DataCallbackActivity"
    android:orientation="vertical">

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="400dp" />

    <ImageView
        android:id="@+id/iv_imageview"
        android:layout_width="match_parent"
        android:layout_height="200dp">
    </ImageView>

</LinearLayout>

(2)代码

MainActivity.java

package com.lzacking.cameraapidemo;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button mSurfaceView;
    private Button mTextureView;
    private Button mNv21DataCallback;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // SurfaceView预览camera数据
        mSurfaceView = findViewById(R.id.btn_surfaceview);
        mSurfaceView.setOnClickListener(this);

        // TextureView预览camera数据
        mTextureView = findViewById(R.id.btn_textureview);
        mTextureView.setOnClickListener(this);

        // 获取的NV21数据进行回调
        mNv21DataCallback = findViewById(R.id.btn_nv21data_callback);
        mNv21DataCallback.setOnClickListener(this);

        // 申请权限
        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, 1);
        }

    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.i("info", "onRequestPermissionsResult: " + "权限已经申请");
                } else {
                    Toast.makeText(this, "你需要打开相机权限", Toast.LENGTH_LONG).show();
                }
                break;
            default:
        }
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_surfaceview:
                Intent intentSurfaceView = new Intent(this, CameraSurfaceViewActivity.class);
                startActivity(intentSurfaceView);
                break;

            case R.id.btn_textureview:
                Intent intentTextureView = new Intent(this, CameraTextureViewActivity.class);
                startActivity(intentTextureView);
                break;

            case R.id.btn_nv21data_callback:
                Intent intentNV21DataCallback = new Intent(this, NV21DataCallbackActivity.class);
                startActivity(intentNV21DataCallback);
                break;

            default:
                break;

        }
    }

}

CameraSurfaceViewActivity.java

package com.lzacking.cameraapidemo;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;

import java.io.IOException;

public class CameraSurfaceViewActivity extends AppCompatActivity implements SurfaceHolder.Callback {

    private SurfaceView mSurfaceView;
    private Camera mCamera;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera_surface_view);

        mSurfaceView = findViewById(R.id.surfaceView);
        mSurfaceView.getHolder().addCallback(this);

        // 打开摄像头并将展示方向旋转90度
        mCamera = Camera.open(0);
        mCamera.setDisplayOrientation(90);
    }

    //------ SurfaceView预览 -------
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 在控件创建的时候,进行相应的初始化工作
        try {
            mCamera.setPreviewDisplay(holder);
            // 开始预览
            mCamera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 变化时,可以做相应操作
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // 释放摄像头
        mCamera.release();
    }

}

CameraTextureViewActivity.java

package com.lzacking.cameraapidemo;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.TextureView;

import java.io.IOException;

public class CameraTextureViewActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {

    private TextureView mTextureView;
    private Camera mCamera;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera_texture_view);

        mTextureView = findViewById(R.id.textureView);
        mTextureView.setSurfaceTextureListener(this);

        // 打开摄像头并将展示方向旋转90度
        mCamera = Camera.open(0);
        mCamera.setDisplayOrientation(90);
    }

    //------ TextureView预览 -------
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        // 在控件创建的时候,进行相应的初始化工作
        try {
            mCamera.setPreviewTexture(surface);
            // 开始预览
            mCamera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        // 变化时,可以做相应操作
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        // 释放相机
        mCamera.release();
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }

}

NV21DataCallbackActivity

package com.lzacking.cameraapidemo;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.ImageView;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class NV21DataCallbackActivity extends AppCompatActivity implements SurfaceHolder.Callback {

    private Camera mCamera;
    private SurfaceView mSurfaceView;

    private Camera.Size mPreviewSize; // 预览尺寸大小
    private ByteArrayOutputStream mBaos;
    private byte[] mImageBytes;
    private Bitmap mBitmap;
    private ImageView mImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_nv21data_callback);
        mImageView = findViewById(R.id.iv_imageview);

        mSurfaceView = findViewById(R.id.surfaceView);
        mSurfaceView.getHolder().addCallback(this);

        // 打开摄像头并将展示方向旋转90度
        mCamera = Camera.open(0);
        mCamera.setDisplayOrientation(90);
    }


    @Override
    public void surfaceCreated(SurfaceHolder holder) {

    }


    // 窗口改变
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        doChange(holder);
    }


    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mCamera.release();
    }

    // 当我们的程序开始运行,surFaceView显示当前摄像头获取的内容,获取的NV21数据显示在ImageView控件上
    private void doChange(SurfaceHolder holder) {
        try {
            mCamera.setPreviewDisplay(holder);// 设置摄像机的预览界面
            // 设置surfaceView旋转的角度,系统默认的录制是横向的画面
            mCamera.setDisplayOrientation(getDegree());

            if (mCamera != null ) {
                try {
                    Camera.Parameters parameters = mCamera.getParameters(); // 获取摄像头参数

                    // 可以根据情况设置参数
                    // 镜头缩放
                    // parameters.setZoom();

                    // 设置预览照片的大小
                    // parameters.setPreviewSize(200, 200);

                    // 设置预览照片时每秒显示多少帧的最小值和最大值
                    // parameters.setPreviewFpsRange(4, 10);

                    // 设置图片格式
                    // parameters.setPictureFormat(ImageFormat.JPEG);

                    // 设置JPG照片的质量  图片的质量[0-100],100最高
                    // parameters.set("jpeg-quality", 85);

                    // 设置照片的大小
                    // parameters.setPictureSize(200, 200);

                    // 设置预览图片的图像格式
                    parameters.setPreviewFormat(ImageFormat.NV21);

                    mCamera.setParameters(parameters);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            mCamera.setPreviewCallback(new Camera.PreviewCallback() {
                @Override
                public void onPreviewFrame(byte[] data, Camera camera) {
                    // 处理data,这里面的data数据就是NV21格式的数据,将数据显示在ImageView控件上面
                    mPreviewSize = camera.getParameters().getPreviewSize();// 获取尺寸,格式转换的时候要用到
                    // 取发YUVIMAGE
                    YuvImage yuvimage = new YuvImage(
                            data,
                            ImageFormat.NV21,
                            mPreviewSize.width,
                            mPreviewSize.height,
                            null);
                    mBaos = new ByteArrayOutputStream();
                    // yuvimage转换成jpg格式
                    yuvimage.compressToJpeg(new Rect(0, 0, mPreviewSize.width, mPreviewSize.height), 100, mBaos);// 80--JPG图片的质量[0-100],100最高
                    mImageBytes = mBaos.toByteArray();

                    // 将mImageBytes转换成bitmap
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inPreferredConfig = Bitmap.Config.RGB_565;

                    mBitmap = BitmapFactory.decodeByteArray(mImageBytes, 0, mImageBytes.length, options);
                    mImageView.setImageBitmap(rotateBitmap(mBitmap, getDegree()));
                }
            });

            mCamera.startPreview();// 开始预览

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private int getDegree() {
        // 获取当前屏幕旋转的角度
        int rotating = this.getWindowManager().getDefaultDisplay().getRotation();
        int degree = 0;// 度数
        // 根据手机旋转的角度,来设置surfaceView的显示的角度
        switch (rotating) {
            case Surface.ROTATION_0:
                degree = 90;
                break;
            case Surface.ROTATION_90:
                degree = 0;
                break;
            case Surface.ROTATION_180:
                degree = 270;
                break;
            case Surface.ROTATION_270:
                degree = 180;
                break;
        }
        return degree;
    }


    /**
     * 选择变换
     * @param origin 原图
     * @param degree  旋转角度,可正可负
     * @return 旋转后的图片
     */
    private Bitmap rotateBitmap(Bitmap origin, float degree) {
        if (origin == null) {
            return null;
        }
        int width = origin.getWidth();
        int height = origin.getHeight();
        Matrix matrix = new Matrix();
        matrix.setRotate(degree);
        // 围绕原地进行旋转
        Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
        if (newBM.equals(origin)) {
            return newBM;
        }
        origin.recycle();
        return newBM;
    }

}

(3)权限

<uses-permission android:name="android.permission.CAMERA" />

源代码:
Android音视频开发基础(三) : 在Android平台使用Camera API进行视频的采集,并且预览Camera数据,得到NV21数据进行回调

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
以下是使用Camera2 API进行录像并保存的相关代码: 1. 添加权限到 AndroidManifest.xml 文件中: ```xml <uses-feature android:name="android.hardware.camera"/> <uses-feature android:name="android.hardware.camera.autofocus"/> <uses-feature android:name="android.hardware.camera2.full"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> ``` 2. 在布局文件中添加一个 SurfaceView 用于预览相机: ```xml <SurfaceView android:id="@+id/surface_view" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 3. 在 Activity 中定义相机设备和相机预览会话: ```java private CameraDevice mCameraDevice; private CameraCaptureSession mPreviewSession; ``` 4. 初始化相机设备并打开相机: ```java private void openCamera() { CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { String cameraId = manager.getCameraIdList()[0]; CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); mVideoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder.class)); mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), mVideoSize.getWidth(), mVideoSize.getHeight()); mMediaRecorder = new MediaRecorder(); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { return; } manager.openCamera(cameraId, mStateCallback, null); } catch (CameraAccessException e) { e.printStackTrace(); } } private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { mCameraDevice = camera; startPreview(); } @Override public void onDisconnected(CameraDevice camera) { camera.close(); mCameraDevice = null; } @Override public void onError(CameraDevice camera, int error) { camera.close(); mCameraDevice = null; } }; ``` 5. 创建相机预览会话: ```java private void startPreview() { SurfaceTexture texture = mTextureView.getSurfaceTexture(); texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); Surface surface = new Surface(texture); try { mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewBuilder.addTarget(surface); mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { mPreviewSession = session; updatePreview(); } @Override public void onConfigureFailed(CameraCaptureSession session) { // failed } }, null); } catch (CameraAccessException e) { e.printStackTrace(); } } private void updatePreview() { if (null == mCameraDevice) { return; } mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); HandlerThread thread = new HandlerThread("CameraPreview"); thread.start(); Handler backgroundHandler = new Handler(thread.getLooper()); try { mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, backgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } ``` 6. 开始录像: ```java private void startRecordingVideo() { if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) { return; } try { closePreviewSession(); setUpMediaRecorder(); SurfaceTexture texture = mTextureView.getSurfaceTexture(); texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); List<Surface> surfaces = new ArrayList<>(); Surface previewSurface = new Surface(texture); surfaces.add(previewSurface); mPreviewBuilder.addTarget(previewSurface); Surface recorderSurface = mMediaRecorder.getSurface(); surfaces.add(recorderSurface); mPreviewBuilder.addTarget(recorderSurface); mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession cameraCaptureSession) { mPreviewSession = cameraCaptureSession; updatePreview(); runOnUiThread(new Runnable() { @Override public void run() { mIsRecordingVideo = true; mMediaRecorder.start(); } }); } @Override public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) { // failed } }, null); } catch (Exception e) { e.printStackTrace(); } } private void setUpMediaRecorder() throws IOException { final Activity activity = this; if (null == activity) { return; } mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()); mMediaRecorder.setVideoEncodingBitRate(10000000); mMediaRecorder.setVideoFrameRate(30); mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight()); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); switch (mSensorOrientation) { case SENSOR_ORIENTATION_DEFAULT_DEGREES: mMediaRecorder.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation)); break; case SENSOR_ORIENTATION_INVERSE_DEGREES: mMediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation)); break; } mMediaRecorder.prepare(); } private void closePreviewSession() { if (mPreviewSession != null) { mPreviewSession.close(); mPreviewSession = null; } } private void stopRecordingVideo() { mIsRecordingVideo = false; mMediaRecorder.stop(); mMediaRecorder.reset(); startPreview(); } ``` 7. 释放相机: ```java private void releaseCamera() { if (null != mCameraDevice) { mCameraDevice.close(); mCameraDevice = null; } } ``` 8. 创建保存视频的文件: ```java private static File getOutputMediaFile(int type) { File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), "MyCameraApp"); if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { return null; } } String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File mediaFile; if (type == MEDIA_TYPE_VIDEO) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_" + timeStamp + ".mp4"); } else { return null; } return mediaFile; } ``` 注意:需要在 Android 6.0 及以上版本动态请求相机和存储权限。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值