笔记19 | 利用MediaRecorder实现录像

前言

通过上篇通过MediaRecord实现录音后,对MediaRecord有了基本的了解,本篇是通过其实现视频的录制


地址

前人栽树:http://www.cnblogs.com/whoislcj/p/5583833.html 后人乘凉:http://blog.csdn.net/xiangyong_1521/article/details/78249343


补充:MediaRecorder主要配置参数:

  1. 视频编码格式MediaRecorder.VideoEncoderdefault,H263,H264,MPEG4SP,VP8
  2. 音频编码格式MediaRecorder.AudioEncoderdefault,AAC,HEAAC,AACELD,AMRNB,AMRWB,VORBIS
  3. 视频资源获取方式MediaRecorder.VideoSourcedefault,CAMERA,SURFACE
  4. 音频资源获取方式MediaRecorder.AudioSourcedefalut,camcorder,mic,voicecall,voicecommunication,voicedownlink,voicerecognition, voice_uplink
  5. 资源输出格式MediaRecorder.OutputFormatamrnb,amrwb,default,mpeg4,rawamr,threegpp,aacadif, aacadts, outputformatrtpavp, outputformatmpeg2ts ,webm

实现


主要代码

  • MediaRecord
package com.example.book_mediarecorder;

import java.io.File;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.graphics.PixelFormat;
import android.hardware.Camera; 

public class MediaRecord extends Activity implements SurfaceHolder.Callback{
     private SurfaceView mSurfaceView;
        private SurfaceHolder mSurfaceHolder;
        private Button btnStartStop;
        private boolean isRecording = false;//标记是否已经在录制
        private  MediaRecorder mRecorder;//音视频录制类
        private Camera mCamera = null;//相机
        private Camera.Size mSize = null;//相机的尺寸
        private int mCameraFacing = Camera.CameraInfo.CAMERA_FACING_BACK;//默认后置摄像头
        private static final SparseIntArray orientations = new SparseIntArray();//手机旋转对应的调整角度

        static {
            orientations.append(Surface.ROTATION_0, 90);
            orientations.append(Surface.ROTATION_90, 0);
            orientations.append(Surface.ROTATION_180, 270);
            orientations.append(Surface.ROTATION_270, 180);
        }

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setWindow();
            setContentView(R.layout.mediarecord);
            initViews();
        }

        private void setWindow() {
            requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题栏
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏
            // 设置竖屏显示
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            // 选择支持半透明模式,在有surfaceview的activity中使用。
            getWindow().setFormat(PixelFormat.TRANSLUCENT);
        }

        private void initViews() {
            mSurfaceView = (SurfaceView) findViewById(R.id.sf_view);
            btnStartStop = (Button) findViewById(R.id.rButton_media);
            btnStartStop.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    if (!isRecording) {
                        startRecord();
                    } else {
                        stopRecord();
                    }
                }
            });
            SurfaceHolder holder = mSurfaceView.getHolder();// 取得holder
            holder.setFormat(PixelFormat.TRANSPARENT);
            holder.setKeepScreenOn(true);
            holder.addCallback(this); // holder加入回调接口
        }

        /**
         * 初始化相机
         */
        private void initCamera() {
            if (Camera.getNumberOfCameras() == 2) {
                mCamera = Camera.open(mCameraFacing);
            } else {
                mCamera = Camera.open();
            }

            CameraSizeComparator sizeComparator = new CameraSizeComparator();
            Camera.Parameters parameters = mCamera.getParameters();

            if (mSize == null) {
                List<Camera.Size> vSizeList = parameters.getSupportedPreviewSizes();
                Collections.sort(vSizeList, sizeComparator);

                for (int num = 0; num < vSizeList.size(); num++) {
                    Camera.Size size = vSizeList.get(num);

                    if (size.width >= 800 && size.height >= 480) {
                        this.mSize = size;
                        break;
                    }
                }
                mSize = vSizeList.get(0);

                List<String> focusModesList = parameters.getSupportedFocusModes();

                //增加对聚焦模式的判断
                if (focusModesList.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
                    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
                } else if (focusModesList.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
                    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                }
                mCamera.setParameters(parameters);
            }
            int rotation = getWindowManager().getDefaultDisplay().getRotation();
            int orientation = orientations.get(rotation);
            mCamera.setDisplayOrientation(orientation);
        }

        @Override
        protected void onResume() {
            super.onResume();
            initCamera();
        }

        @Override
        public void onPause() {
            releaseCamera();
            super.onPause();
        }

        /**
         * 开始录制
         */
        private void startRecord() {

            if (mRecorder == null) {
                mRecorder = new MediaRecorder(); // 创建MediaRecorder
            }
            if (mCamera != null) {
                mCamera.stopPreview();
                mCamera.unlock();
                mRecorder.setCamera(mCamera);
            }
            try {
                // 设置音频采集方式
                mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
                //设置视频的采集方式
                mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                //设置文件的输出格式
                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);//aac_adif, aac_adts, output_format_rtp_avp, output_format_mpeg2ts ,webm
                //设置audio的编码格式
                mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                //设置video的编码格式
                mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
                //设置录制的视频编码比特率
                mRecorder.setVideoEncodingBitRate(1024 * 1024);
                //设置录制的视频帧率,注意文档的说明:
                mRecorder.setVideoFrameRate(30);
                //设置要捕获的视频的宽度和高度
                mSurfaceHolder.setFixedSize(320, 240);//最高只能设置640x480
                mRecorder.setVideoSize(320, 240);//最高只能设置640x480
                //设置记录会话的最大持续时间(毫秒)
                mRecorder.setMaxDuration(60 * 1000);
                mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
                String path = getExternalCacheDir().getPath();
                if (path != null) {
                    File dir = new File(path + "/videos");
                    if (!dir.exists()) {
                        dir.mkdir();
                    }
                    path = dir + "/" + System.currentTimeMillis() + ".mp4";
                    //设置输出文件的路径
                    mRecorder.setOutputFile(path);
                    //准备录制
                    mRecorder.prepare();
                    //开始录制
                    mRecorder.start();
                    isRecording = true;
                    btnStartStop.setText("停止");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        /**
         * 停止录制
         */
        private void stopRecord() {
            try {
                //停止录制
                mRecorder.stop();
                //重置
                mRecorder.reset();
                btnStartStop.setText("开始");
            } catch (Exception e) {
                e.printStackTrace();
            }
            isRecording = false;
        }

        /**
         * 释放MediaRecorder
         */
        private void releaseMediaRecorder() {
            if (mRecorder != null) {
                mRecorder.release();
                mRecorder = null;
            }
        }

        /**
         * 释放相机资源
         */
        private void releaseCamera() {
            try {
                if (mCamera != null) {
                    mCamera.stopPreview();
                    mCamera.setPreviewCallback(null);
                    mCamera.unlock();
                    mCamera.release();
                }
            } catch (RuntimeException e) {
            } finally {
                mCamera = null;
            }
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                                   int height) {
            // 将holder,这个holder为开始在onCreate里面取得的holder,将它赋给mSurfaceHolder
            mSurfaceHolder = holder;
            if (mCamera == null) {
                return;
            }
            try {
                //设置显示
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            } catch (Exception e) {
                e.printStackTrace();
                releaseCamera();
                finish();
            }
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            // 将holder,这个holder为开始在onCreate里面取得的holder,将它赋给mSurfaceHolder
            mSurfaceHolder = holder;
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            // surfaceDestroyed的时候同时对象设置为null
            if (isRecording && mCamera != null) {
                mCamera.lock();
            }
            mSurfaceView = null;
            mSurfaceHolder = null;
            releaseMediaRecorder();
            releaseCamera();
        }

        private class CameraSizeComparator implements Comparator<Camera.Size> {
            public int compare(Camera.Size lhs, Camera.Size rhs) {
                if (lhs.width == rhs.width) {
                    return 0;
                } else if (lhs.width > rhs.width) {
                    return 1;
                } else {
                    return -1;
                }
            }
        }
    }
  • 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"
    android:orientation="vertical" >

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

    <Button
        android:id="@+id/rButton_media"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="开始录像" />

</RelativeLayout>
  • 权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!-- 硬件支持 -->
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />

原文发布于微信公众号 - 项勇(xiangy_life)

原文发表时间:2017-10-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏增长技术

Android 相机功能模块相关库

Android’s video recording APIs are very difficult to figure out, especially sinc...

2161
来自专栏何俊林

音视频的采集、编码、封包成 mp4 输出

使用 Android Camera API 完成音视频的采集、编码、封包成 mp4 输出 基于android.hardware.Camera,创建一个横屏应用,...

1664
来自专栏Android干货

项目实战工具类(一):PhoneUtil(手机信息相关)

2105
来自专栏developerHaoz 的安卓之旅

Android 录音功能直接拿去用

这个类可以说是这个包的核心了,如果理解了这个 Service,录音这一块基本就没什么问题了。

6033
来自专栏写写代码吃吃瓜

Android简易“吹一吹实现”以及录音和播放示例

2664
来自专栏腾讯Bugly的专栏

Android ImageView 正确使用姿势

导语 本文主要介绍了ImageView的相关重要方法,从源码角度剖析了一些容易令人混淆或百思不得其解的问题。 一、正确合理使用ImageView 的src 和b...

4058
来自专栏刘望舒

感受LiveData与ViewModel结合之美

虽说这篇是说LiveData与ViewModel,但是或多或少都有涉及另外一个组件:Lifecycles 。它们连同Room都是在17年谷歌IO大会推出的,当时...

1412
来自专栏刘望舒

打造一个灵活易用的Banner组件

之前做项目时候出于各种考虑,自己开发了Banner组件FBanner,欢迎大家的Star和PR。github上成熟的轮播图库已经有非常多了,比如banner和A...

1375
来自专栏指尖下的Android

Matisse预览图片黑屏,Glide内存溢出

项目中要到图片、视频选择的功能,然后google了一下,找到Matisse,知乎的图片选择框架,用的人还挺多的,果断依赖gradle,然后开始我的踩坑之旅。 ...

2431
来自专栏Sorrower的专栏

使用VideoView做个实用的视频播放器

1375

扫码关注云+社区

领取腾讯云代金券