Enregistrement de fichiers vidéo sous Android

Avant de parler d'enregistrement et de lecture audio, nous parlons maintenant d'enregistrement vidéo. En fait, l'enregistrement vidéo utilise toujours MediaRecorder et coopère avec Camera pour fonctionner. Nous expliquons donc ici en détail la pratique de l'enregistrement vidéo. En ce qui concerne la lecture vidéo, en raison d'une série de problèmes liés à la commutation plein écran, à la gestion du cycle de vie, etc., je n'écrirai pas de blog ici.Les étudiants intéressés peuvent trouver mon cadre dans mes ressources, qui contient des cas de lecture vidéo.

Eh bien, nous commençons à enregistrer l'apprentissage vidéo.

1. Méthodes courantes de lecteur multimédia MediaRecorder (courantes pour l'enregistrement et l'enregistrement)

  • reset: réinitialise la ressource d'enregistrement.
  • préparer: se préparer à enregistrer.
  • start: Démarrez l'enregistrement.
  • stop: Arrêtez l'enregistrement.
  • release: Libérez les ressources d'enregistrement.
  • setOnErrorListener: définit l'écouteur d'erreur. Peut surveiller les exceptions de serveur et les événements d'erreur inconnus. Besoin d'implémenter la méthode onError de l'interface MediaRecorder.OnErrorListener.
  • setOnInfoListener: définit l'écouteur d'informations. Vous pouvez surveiller l'événement de fin d'enregistrement, y compris atteindre la durée d'enregistrement ou atteindre la taille d'enregistrement. Besoin d'implémenter la méthode onInfo de l'interface MediaRecorder.OnInfoListener.
  • setMaxDuration: définissez la durée maximale d'enregistrement, en millisecondes.
  • setMaxFileSize: définit la taille maximale du fichier enregistrable, en octets.
  • setOutputFile: définit le chemin du fichier de sortie.

2. Méthodes courantes utilisées par MeidaRecorder pour l'enregistrement

  • setCamera: définissez l'objet caméra.
  • setPreviewDisplay: définissez l'interface de prévisualisation. L'objet d'interface d'aperçu peut être obtenu via la méthode getSurface de l'objet SurfaceHolder.
  • setOrientationHint: définissez l'angle de l'aperçu. Réglez sur 90 comme pour prendre des photos, ce qui signifie que l'interface pivote de 90 degrés de l'horizontale à la verticale.
  • setVideoSource: définissez la source vidéo. Utilisez généralement VideoSource.CAMERA pour représenter la caméra.
  • setOutputFormat: définit le format de sortie multimédia. La valeur du format de sortie multimédia est indiquée dans le tableau 1.
Tableau 1
Le format de sortie de la classe OutputFormat Classification des formats nom de l'extension Description du format
AMR_NB l'audio .amr Format à bande étroite
AMR_WB l'audio .amr Format large bande
AAC_ADTS l'audio .aac Format de flux de transport audio avancé
MPEG_4 vidéo .mp4 Format MPEG4
TROIS_GPP vidéo .3gp Format 3GP
  • setVideoEncoder: règle l'encodeur vidéo. En général, VideoEncoder.MPEG_4_SP est utilisé pour représenter l'encodage MPEG4. Cette méthode est appelée après la méthode setOutputFormat, sinon une erreur java.lang.IllegalStateException sera signalée.
  • setVideoSize: définissez la résolution de la vidéo.
  • setVideoFrameRate: définissez le nombre d'images vidéo enregistrées par seconde. Plus la vidéo est volumineuse, plus la vidéo est cohérente, bien sûr, plus le fichier vidéo final est volumineux.
  • setVideoEncodingBitRate: définissez le nombre d'octets de vidéo enregistrés par seconde. Plus la vidéo est grande, plus la vidéo est claire, il suffit de définir l'un des paramètres setVideoFrameRate et setVideoEncodingBitRate.

3. Exemple de code

Demande d'accès

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.FLASHLIGHT"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>

Code de mise en page activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/fr_root"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <Button
        android:id="@+id/bt_record"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="录制视频"/>
</RelativeLayout>

MainActivity.java

public class MainActivity extends WaterPermissionActivity implements MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener {

    private TextView bt_record;
    private FrameLayout fr_root;
    private SurfaceHolder mHolder; // 声明一个表面持有者对象
    private Camera mCamera; // 声明一个相机对象
    private MediaRecorder mMediaRecorder;
    private String moviePath;//视频路径

    @Override
    protected MvcBaseModel getModelImp() {
        return null;
    }

    @Override
    protected int getContentLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initWidget() {
        fr_root = findViewById(R.id.fr_root);
        bt_record = findViewById(R.id.bt_record);
        bt_record.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    //按下,开始录制
                    getPath();//初始化视频路径
                    initRecord();//开始录制
                } else if (event.getAction() == MotionEvent.ACTION_UP) {
                    //松开,停止录制
                    cancelRecord(); // 取消录制操作
                    freeCamera(); // 释放相机资源
                }
                return true;
            }
        });
        requestPermission(WRITE_EXTERNAL_STORAGE);
    }

    @Override
    protected void doSDWrite() {
        requestPermission(READ_EXTERNAL_STORAGE);
    }

    @Override
    protected void doSDRead() {
        requestPermission(CAMERA);
    }

    @Override
    protected void doCamera() {
        requestPermission(RECORD);
    }

    @Override
    protected void doRecord() {
        //这里为了请求好动态权限再让Surface初始化才这么弄得,可以在进入录制页面就请求好动态权限,就不用这么写了。
        SurfaceView surfaceView = new SurfaceView(this);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
        surfaceView.setLayoutParams(params);
        fr_root.addView(surfaceView);
        // 获取表面视图的表面持有者
        mHolder = surfaceView.getHolder();
        // 给表面持有者添加表面变更监听器
        mHolder.addCallback(mSurfaceCallback);
    }

    /**
     * 初始化录制操作,开始录制调用这个方法
     */
    private void initRecord() {
        mMediaRecorder = new MediaRecorder(); // 创建一个媒体录制器
        mMediaRecorder.setCamera(mCamera); // 设置媒体录制器的摄像头
        mMediaRecorder.setOnErrorListener(this); // 设置媒体录制器的错误监听器
        mMediaRecorder.setOnInfoListener(this); // 设置媒体录制器的信息监听器
        mMediaRecorder.setPreviewDisplay(mHolder.getSurface()); // 设置媒体录制器的预览界面
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // 设置视频源为摄像头
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置音频源为麦克风
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); // 设置媒体的输出格式
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // 设置媒体的音频编码器
        // 如果录像报错:MediaRecorder start failed: -19
        // 试试把setVideoSize和setVideoFrameRate注释掉,因为尺寸设置必须为摄像头所支持,否则报错
         mMediaRecorder.setVideoSize(2280, 1080); // 设置视频的分辨率
        // mMediaRecorder.setVideoFrameRate(16); // 设置视频每秒录制的帧数
        // setVideoFrameRate与setVideoEncodingBitRate设置其一即可
        mMediaRecorder.setVideoEncodingBitRate(1 * 1024 * 512); // 设置视频每秒录制的字节数
        mMediaRecorder.setOrientationHint(90); // 输出旋转90度,也就是保持竖屏录制
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP); // 设置媒体的视频编码器
        mMediaRecorder.setMaxDuration(10 * 1000); // 设置媒体的最大录制时长
        // mMediaRecorder.setMaxFileSize(1024*1024*10); // 设置媒体的最大文件大小
        // setMaxFileSize与setMaxDuration设置其一即可
        mMediaRecorder.setOutputFile(moviePath); // 设置媒体文件的保存路径
        try {
            mMediaRecorder.prepare(); // 媒体录制器准备就绪
            mMediaRecorder.start(); // 媒体录制器开始录制
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 定义一个表面持有者的变更监听器
     */
    private SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {
        // 在表面视图创建时触发
        public void surfaceCreated(SurfaceHolder holder) {
            initCamera(); // 初始化相机
        }

        // 在表面视图变更时触发
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        }

        // 在表面视图销毁时触发
        public void surfaceDestroyed(SurfaceHolder holder) {
            freeCamera(); // 释放相机资源
        }
    };

    /**
     * 释放相机资源
     */
    private void freeCamera() {
        if (mCamera != null) {
            mCamera.stopPreview(); // 停止预览
            mCamera.lock(); // 锁定相机,即关闭相机
            mCamera.release(); // 释放相机资源
            mCamera = null;
        }
    }

    /**
     * 初始化相机操作
     */
    private void initCamera() {
        if (mCamera != null) {
            freeCamera();
        }
        try {
            // 打开摄像头,默认后置摄像头
            mCamera = Camera.open();
            // 设置相机的展示角度
            mCamera.setDisplayOrientation(90);
            // 设置相机的预览界面
            mCamera.setPreviewDisplay(mHolder);
            // 开始预览画面
            mCamera.startPreview();
            // 解锁相机,即打开相机
            mCamera.unlock();
        } catch (Exception e) {
            e.printStackTrace();
            freeCamera();
        }
    }

    /**
     * 录制前创建一个空文件并获取路径
     */
    private void getPath() {
        List<String> list = new ArrayList<>();
        list.add("record");
        String dirPath = PathGetUtil.getLongwayPath(this, list);
        File fileDir = new File(dirPath);
        if (!fileDir.exists()) {
            fileDir.mkdirs();
        }
        File fileVoice = new File(dirPath, "movie" + System.currentTimeMillis() + ".mp4");
        if (!fileVoice.exists()) {
            try {
                fileVoice.createNewFile();
                moviePath = fileVoice.getPath();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onError(MediaRecorder mr, int what, int extra) {
        if (mr != null) {
            mr.reset();  // 重置媒体录制器
        }
    }

    @Override
    public void onInfo(MediaRecorder mr, int what, int extra) {
        // 录制达到最大时长,或者达到文件大小限制,都停止录制
        if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
                || what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
            cancelRecord();
        }
    }

    /**
     * 取消录制操作,停止录制的时候调用该方法
     */
    private void cancelRecord() {
        if (mMediaRecorder != null) {
            mMediaRecorder.setOnErrorListener(null); // 错误监听器置空
            mMediaRecorder.setPreviewDisplay(null); // 预览界面置空
            try {
                mMediaRecorder.stop(); // 媒体录制器停止录制
            } catch (Exception e) {
                e.printStackTrace();
            }
            mMediaRecorder.release(); // 媒体录制器释放资源
            mMediaRecorder = null;
        }
    }
}

De même, comme la vidéo que nous avons enregistrée n'a pas été traitée, la qualité vidéo n'était pas très élevée et ce n'était pas très clair. Donc, si vous voulez être plus clair, vous pouvez envisager de changer la partie Caméra du paramètre sur Camera2 ou un meilleur CameraX. Je n'effectuerai pas d'opérations spécifiques ici, les principes sont les mêmes, vous pouvez l'essayer si cela vous intéresse.

Je suppose que tu aimes

Origine blog.csdn.net/weixin_38322371/article/details/115249593
conseillé
Classement