录制视频(Surfaceview+MediaRecorder)

来源:互联网 发布:大数据行业什么意思 编辑:程序博客网 时间:2024/05/16 19:22

欢迎转载和提问,转载请注明出处
http://blog.csdn.net/ning_gg/article/details/54314315
这个是自己写的录制视频,为了简单,全写在一个Activity中,可以切换照相机,没有带聚焦,需要聚焦自己写个OnTouch即可。在我的测试机上跑起来畅通无阻,我只有3个测试机。如果你使用了我的有问题可以告诉我。

这个demo比网上什么的写死录像尺寸强多了,全部自匹配尺寸。如果你的跑不起可以第一时间检测这个尺寸设置。我的思路是获取手机屏幕尺寸,得到高/宽的比 比如1280/720 或者1920/1080这样的。然后遍历Camera的预览尺寸,得到一个跟手机尺寸最合适的那一个,这样的话预览的时候图像不会变形,然后获取手机录像的尺寸,这里必须说下不是每个手机都提供这个录像尺寸,像华为mate7就不提供,不提供的另说,提供的会遍历这个尺寸,得到相同比例(比如预览是1920/1080=1.77777)最小的一个(800/450),这样的话比大部分提供的写死一个尺寸强多了,而且录制出来的东西不会变形。为什么要找最小的是因为我们的需求录制的视频最小越好。对于那些不提供录像尺寸的,直接把预览尺寸设成录像尺寸就可以了。mate7就是这样跑通的。

附上代码

import android.hardware.Camera;import android.media.MediaRecorder;import android.os.Environment;import android.support.v7.widget.Toolbar;import android.util.DisplayMetrics;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.widget.Button;import android.widget.TextView;import com.imapedia.ykdemo.R;import com.imapedia.ykdemo.base.BaseActivity;import com.imapedia.ykdemo.utils.L;import java.io.File;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.List;import butterknife.BindView;import butterknife.OnClick;/** * Created by ning_gg on 2017/1/9. * <p/> * 录制视频,切换摄像头,尺寸匹配 */public class RecordVideoActivity extends BaseActivity implements MediaRecorder.OnErrorListener ,SurfaceHolder.Callback{    private String TAG=RecordVideoActivity.class.getSimpleName();    @BindView(R.id.activity_main_toolbar)    Toolbar activity_main_toolbar;    @BindView(R.id.recordvideo_sv)    SurfaceView recordvideo_sv;    private SurfaceHolder mSurfaceHolder;    @BindView(R.id.toolbar_change_tv)    TextView toolbar_change_tv;    @OnClick (R.id.toolbar_change_tv)    void toolbar_change_tvOnClick(){        if(recording){            try {                stopRecord();            } catch (Exception e) {                e.printStackTrace();            }        }        if (cameraPosition == Camera.CameraInfo.CAMERA_FACING_BACK) {            cameraPosition = Camera.CameraInfo.CAMERA_FACING_FRONT;        } else {            cameraPosition = Camera.CameraInfo.CAMERA_FACING_BACK;        }        if (isOpenCamera) {            mCamera.stopPreview();//停掉原来摄像头的预览            mCamera.release();//释放资源            mCamera = null;//取消原来摄像头            mCamera = Camera.open(cameraPosition);            try {                setCameraParms();            } catch (IOException e) {                e.printStackTrace();            }        }    }    @BindView(R.id.recordvideo_btn)    Button recordvideo_btn;    @OnClick(R.id.recordvideo_btn)    void recordvideo_btnOnClick() {        if (!recording) {            try {                startRecord();            } catch (IOException e) {                e.printStackTrace();            }        } else {            try {                stopRecord();            } catch (Exception e) {                e.printStackTrace();            }        }    }    private int screenHeight;//屏幕的高度    private int screenWidth;//屏幕的宽度    private Camera mCamera;    private int videoWidth = 0;// 视频分辨率宽度    private int videoHeight = 0;// 视频分辨率高度    public  Camera.Size pictureSize;//照片分辨率    private Camera.Size previewSize;//预览分辨率    private boolean isOpenCamera;// 是否已经打开摄像头    private int cameraPosition = Camera.CameraInfo.CAMERA_FACING_FRONT;//当前摄像头    private MediaRecorder mMediaRecorder;    private String FilePath = Environment            .getExternalStorageDirectory().getPath() + File.separator + "ninggegetest" + File.separator;    private File mVecordFile;    //是否正在录制中    private boolean recording;    @Override    protected int getLayoutId() {        return R.layout.activity_recordvideo;    }    @Override    protected void init() {        DisplayMetrics dm = getResources().getDisplayMetrics();        screenWidth = dm.widthPixels;        screenHeight = dm.heightPixels;        mSurfaceHolder=recordvideo_sv.getHolder();        mSurfaceHolder.addCallback(this);    }    /**     * 开始录制     */    private void startRecord() throws IOException {        createRecordDir();        initRecord();        recording=true;        recordvideo_btn.setBackgroundResource(R.drawable.stoprecord);    }    /**     * 创建文件     */    private void createRecordDir() throws IOException {        File sampleDir = new File(FilePath);        if (!sampleDir.exists()) {            sampleDir.mkdirs();        }        File vecordDir = sampleDir;        // 创建文件        SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日_HH_mm_ss");        Date curDate = new Date(System.currentTimeMillis());//获取当前时间        String str = formatter.format(curDate);        mVecordFile = File.createTempFile(str, ".mp4", vecordDir);//mp4格式    }    /**     * 初始化     *     * @throws IOException     * @author ning_gg     * @date 2015-3-16     */    private void initRecord() throws IOException {        //必须解锁  不然会报错        mCamera.unlock();        mMediaRecorder = new MediaRecorder();        mMediaRecorder.reset();        if (mCamera != null)            mMediaRecorder.setCamera(mCamera);        mMediaRecorder.setOnErrorListener(this);        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);        //后置摄像头是旋转90度        if (cameraPosition == 0) {            mMediaRecorder.setOrientationHint(90);// 输出旋转90度,保持竖屏录制        } else {            //前置摄像头是旋转270度            mMediaRecorder.setOrientationHint(270);        }        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);// 视频输出格式        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 音频格式        //H264用得最广  基本每个手机都支持  反倒其他的没有每个都支持        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);        mMediaRecorder.setVideoSize(videoWidth, videoHeight);// 设置分辨率        mMediaRecorder.setVideoEncodingBitRate(2 * 1024 * 1024);// 设置帧频率,然后就清晰了        // 设置录制的视频帧率。必须放在设置编码和格式的后面,否则报错        // mMediaRecorder.setVideoFrameRate(20);        // mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);        mMediaRecorder.setOutputFile(mVecordFile.getAbsolutePath());        mMediaRecorder.prepare();        mMediaRecorder.start();    }    /**     * 停止录制     */    private void stopRecord() throws Exception {        if (mMediaRecorder != null) {            // 设置后不会崩            mMediaRecorder.setOnErrorListener(null);            mMediaRecorder.setPreviewDisplay(null);            mMediaRecorder.stop();            mMediaRecorder.release();            mMediaRecorder = null;        }        recording=false;        recordvideo_btn.setBackgroundResource(R.drawable.startrecord);    }    @Override    public void onError(MediaRecorder mediaRecorder, int i, int i1) {    }    @Override    public void surfaceCreated(SurfaceHolder surfaceHolder) {        if (mCamera != null) {            mCamera.stopPreview();//停掉原来摄像头的预览            mCamera.release();//释放资源            mCamera = null;//取消原来摄像头        }            int i = Camera.getNumberOfCameras();            //如果只有一个摄像头            if (i == 1) {                mCamera = Camera.open();                toolbar_change_tv.setVisibility(View.GONE);            } else {                mCamera = Camera.open(cameraPosition);            }        isOpenCamera=true;        try {            setCameraParms();        } catch (IOException e) {            e.printStackTrace();        }    }    @Override    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {    }    @Override    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {        try {            stopRecord();        } catch (Exception e) {            e.printStackTrace();        }        if (mCamera != null) {            mCamera.setPreviewCallback(null);            mCamera.stopPreview();            mCamera.release();            mCamera = null;        }    }    private void setCameraParms() throws IOException{        mCamera.setPreviewDisplay(mSurfaceHolder);        Camera.Parameters myParam = mCamera.getParameters();        List<String> flashModes = myParam.getSupportedFlashModes();        String flashMode = myParam.getFlashMode();        // Check if camera flash exists        if (flashModes!=null&&!Camera.Parameters.FLASH_MODE_OFF.equals(flashMode)) {            // Turn off the flash            if (flashModes.contains(Camera.Parameters.FLASH_MODE_OFF)) {                myParam.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);            }        }        float percent = calcPreviewPercent();        List<Camera.Size> supportedPreviewSizes = myParam.getSupportedPreviewSizes();        //因为有些手机videoSizes不提供  比如华为mate7  那样的话就只能拿照相机预览数据了 当然预览数据尺寸不知道能不能当视频录制尺寸        List<Camera.Size> videoSizes = mCamera.getParameters().getSupportedVideoSizes();        previewSize = getPreviewMaxSize(supportedPreviewSizes, percent);        L.e(TAG, "预览尺寸w===" + previewSize.width + ",h==="                + previewSize.height);        if (videoSizes != null) {            for (Camera.Size _s : videoSizes) {                float videoS = (float) _s.width / _s.height;                if (videoS == percent && _s.width < previewSize.width && _s.height < previewSize.height) {                    videoWidth = _s.width;                    videoHeight = _s.height;                    continue;                }            }        }        if (videoWidth == 0 && videoHeight == 0) {            //如果没有拿到值  那就是当前的预览数据了            videoWidth = previewSize.width;            videoHeight = previewSize.height;        }        L.e(TAG, "录像尺寸w===" + videoWidth + ",h==="                + videoHeight);        // 获取摄像头支持的各种分辨率        List<Camera.Size> supportedPictureSizes = myParam.getSupportedPictureSizes();        pictureSize = findSizeFromList(supportedPictureSizes, previewSize);        if (pictureSize == null) {            pictureSize = getPictureMaxSize(supportedPictureSizes, previewSize);        }        L.e(TAG, "照片尺寸w===" + pictureSize.width + ",h==="                + pictureSize.height);        // 设置照片分辨率,注意要在摄像头支持的范围内选择        myParam.setPictureSize(pictureSize.width, pictureSize.height);        // 设置预浏尺寸,注意要在摄像头支持的范围内选择        myParam.setPreviewSize(previewSize.width, previewSize.height);        myParam.setJpegQuality(70);        mCamera.setParameters(myParam);        mCamera.setDisplayOrientation(90);        mCamera.startPreview();        mCamera.cancelAutoFocus();    }    private float calcPreviewPercent() {        float d = screenHeight;        return d / screenWidth;    }    private Camera.Size findSizeFromList(List<Camera.Size> supportedPictureSizes, Camera.Size size) {        Camera.Size s = null;        if (supportedPictureSizes != null && !supportedPictureSizes.isEmpty()) {            for (Camera.Size su : supportedPictureSizes) {                if (size.width == su.width && size.height == su.height) {                    s = su;                    break;                }            }        }        return s;    }    // 根据摄像头的获取与屏幕分辨率最为接近的一个分辨率    private Camera.Size getPictureMaxSize(List<Camera.Size> l, Camera.Size size) {        Camera.Size s = null;        for (int i = 0; i < l.size(); i++) {            if (l.get(i).width >= size.width && l.get(i).height >= size.width                    && l.get(i).height != l.get(i).width) {                if (s == null) {                    s = l.get(i);                } else {                    if (s.height * s.width > l.get(i).width * l.get(i).height) {                        s = l.get(i);                    }                }            }        }        return s;    }    // 获取预览的最大分辨率    private Camera.Size getPreviewMaxSize(List<Camera.Size> l, float j) {        int idx_best = 0;        int best_width = 0;        float best_diff = 100.0f;        for (int i = 0; i < l.size(); i++) {            int w = l.get(i).width;            int h = l.get(i).height;            if (w * h < screenHeight * screenWidth)                continue;            float previewPercent = (float) w / h;            float diff = Math.abs(previewPercent - j);            if (diff < best_diff) {                idx_best = i;                best_diff = diff;                best_width = w;            } else if (diff == best_diff && w > best_width) {                idx_best = i;                best_diff = diff;                best_width = w;            }        }        return l.get(idx_best);    }    @Override    public void onBackPressed() {        super.onBackPressed();        try {            stopRecord();        } catch (Exception e) {            e.printStackTrace();        }        finish();    }}

TextureView+MediaRecorder录像原理跟这个是一样的,只是把SurfaceView替换成TextureView就行了,怎么使用TextureView在这里
http://blog.csdn.net/ning_gg/article/details/54134918
欢迎转载和提问,转载请注明出处
http://blog.csdn.net/ning_gg/article/details/54314315

0 0
原创粉丝点击