Android视频录制

今天呢介绍一个简单的预览拍摄例子,也是项目中用到的,在Android 4.4以上的手机都是可以支持的,并且支持切换前后置摄像头,开关闪光灯,自动对焦。
下面正式开始:
1.首先我们自定义一个控件,它继承于LinearLayout:

public class RecorderView extends LinearLayout implements MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener {
        /*这里是代码*/
}

实现上面几个接口要重写以下几个方法,

@Override
public void onInfo(MediaRecorder mr, int what, int extra) {
        try {

        } catch (Exception e) {

        }
    }
@Override
public void onError(MediaRecorder mr, int what, int extra) {
        try {

            if (mr != null)
                mr.reset();
        } catch (Exception e) {

        }
    }

上面两个方法一个是视频录制时得到的信息函数,一个是录制过程中出现error时的回调函数,具体处理也很简单直接reset掉就可以了
下面来就是预览控件了

private SurfaceView surfaceView;
private SurfaceHolder surfaceHoler;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RecorderView(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
        this.context = context;
        init();
  }
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RecorderView(Context context, AttributeSet attrs,
                             int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
}
private void init() {        LayoutInflater.from(context).inflate(R.layout.ui_recorder, this);
surfaceView = (SurfaceView) findViewById(R.id.surfaceview);
surfaceHoler = surfaceView.getHolder();
surfaceHoler.addCallback(new VideoCallBack());        surfaceHoler.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.setFocusable(true);
surfaceHoler.setKeepScreenOn(true);
}

这个SurfaceView就是我们需要的,里面获得的suerfaceHolder就是用来预览拍摄视频,
那么怎么把Camera捕捉到的画面放到surfaceView里面去呢,对了就是这个addCallback方法:

class VideoCallBack implements SurfaceHolder.Callback {
   @Override
   public void surfaceCreated(SurfaceHolder holder) {
        switchCamera(false);
   }
   @Override
   public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
        startPreView();
   }
   @Override
   public void surfaceDestroyed(SurfaceHolder holder{
        freeCameraResource();
   }
 }

里面重写了三方方法,对应着调用他们应该打开Camera,设置Camera参数,和释放Camera,很好理解

//选择打开前置还是后置摄像头
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public void switchCamera(boolean isFroCam) {
  freeCameraResource();
  try {
     if (!isFroCam) {
      camera = Camera.open(CameraInfo.CAMERA_FACING_BACK);
      } else {
      camera = Camera.open(CameraInfo.CAMERA_FACING_FRONT);
      isFrontCamera = true;
      }
   } catch (Exception e) {
       e.printStackTrace();
   }
}
//设置camera参数,这里无论是前置还是后置摄像头都要转90度
    public void startPreView(){
        camera.stopPreview();
        if (camera == null)
            return;
        try {
            camera.setDisplayOrientation(90);
            cameraParameters = camera.getParameters();
            cameraParameters.setPreviewSize(1280, 720);
            camera.setPreviewDisplay(surfaceHoler);
            getAutoFocus();
            camera.setParameters(cameraParameters);
            camera.setPreviewDisplay(surfaceHoler);
            camera.startPreview();
            camera.unlock();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

突然间我们发现一个函数叫做getAutoFocus,干嘛的?看名字就明白了是用来自动对焦的,这种方法在4.4到6.0上的手机都是有效的

public void getAutoFocus() {
  if (Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) {
    List<String> focusModes = cameraParameters.getSupportedFocusModes();
     if (focusModes != null) {
        if (((Build.MODEL.startsWith("GT-I950"))
            || (Build.MODEL.endsWith("SCH-I959")) || (Build.MODEL.endsWith("MEIZU MX3")))&& focusModes                     .contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
   cameraParameters.setFocusMode
   (Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
         } else if (focusModes              .contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
   cameraParameters                            .setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
      }
    }
  }
}

然后这个你用完了记得一定要释放camera也就是freeCameraResource

 public void freeCameraResource() {
        if (null != camera) {
            camera.setPreviewCallback(null);
            camera.stopPreview();
            camera.lock();
            camera.release();
            camera = null;
        }
    }

这样一个简单的视频预览拍摄页面就完成了。
下面这个是打开和关闭闪光灯的方法

 public void openflashlight() {
        if (camera == null)
            return;
        camera.lock();
        try {
            if (!isFlashOn) {
                isFlashOn = true;              cameraParameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
            } else {                cameraParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
                isFlashOn = false;
            }
            camera.setParameters(cameraParameters);
        } catch (Exception e) {
            return;
        }
        camera.unlock();
    }

没什么难的,看一下就明白了。
下面就是录制过程了,不多说了,直接上代码,里面设置了一些参数看名字就能猜出来个八九不离十了,

 public void startRecord() {
        if (isRecording)
            return;
        createRecordDir();
        initRecord(isFrontCamera);
        prepareRecord();
    }
//建立一个文件夹,并给拍摄的视频起个名字
 private void createRecordDir() {
        File sampleDir = new File(Environment.getExternalStorageDirectory()
                + File.separator + "You_video/");
        if (!sampleDir.exists()) {
            sampleDir.mkdirs();
        }
        try {
            startTime = String.valueOf(System.currentTimeMillis());
            fileName = "you_video_name" + startTime + ".mp4";
            vecordFile = new File(sampleDir.toString(), fileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
//设置录制视频的各种参数,在这里前后摄像头录制时设置的旋转角度是不
//一样的
 @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    private void initRecord(boolean isFrontCamera) {
        mediaRecorder = new MediaRecorder();
        mediaRecorder.reset();
        if (camera != null)
            mediaRecorder.setCamera(camera);
        mediaRecorder.setOnInfoListener(this);
        mediaRecorder.setOnErrorListener(this);
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        try {
            CamcorderProfile camcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
            mediaRecorder.setProfile(camcorderProfile);
        } catch (RuntimeException re) {
            try {
                mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
                mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
            } catch (Exception e) {

            }
        }
        try {
            mediaRecorder.setVideoSize(1280, 720);
        } catch (Exception e) {

        }
        mediaRecorder.setVideoEncodingBitRate(2 * 1024 * 1024);
        if (!isFrontCamera) {
            mediaRecorder.setOrientationHint(90);
        } else {
            mediaRecorder.setOrientationHint(270);
        }
        mediaRecorder.setMaxDuration(recordMaxTime * 1000);
        mediaRecorder.setOutputFile(vecordFile.getAbsolutePath());
        mediaRecorder.setPreviewDisplay(surfaceHoler.getSurface());
    }
//真正的开始录制是在这里
    private void prepareRecord() {
        try {
            mediaRecorder.prepare();
            mediaRecorder.start();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (RuntimeException re) {
            return;
        }
    }

如果录制视频不满意则调用这个函数

public void cancelRecord(boolean cancel) {
        surfaceView.setVisibility(View.VISIBLE);
        if (!isRecording)
            return;
        isRecording = false;
        stopRecord();
        releaseRecord();
        freeCameraResource();
        if (vecordFile.exists())
            vecordFile.delete();
    }
 private void stopRecord() {
        if (mediaRecorder != null) {
            mediaRecorder.setOnErrorListener(null);
            mediaRecorder.setPreviewDisplay(null);
            try {
                mediaRecorder.stop();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (RuntimeException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void releaseRecord() {
        if (mediaRecorder != null) {
            mediaRecorder.setOnErrorListener(null);
            try {
                mediaRecorder.release();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        mediaRecorder = null;
    }

如果ok拍摄的视频是合格的那么调用下面这个函数

private void completeRecord(PlayVideoListener playVideoListener) {
        if (mediaRecorder != null) {
            mediaRecorder.setOnErrorListener(null);
            mediaRecorder.setPreviewDisplay(null);
            try {
                mediaRecorder.stop();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (RuntimeException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }          playVideoListener.callBackToPlayVideo(vecordFile.getAbsolutePath(), startTime, fileName);
        }
    }

接口

public interface PlayVideoListener {
    void callBackToPlayVideo(String videoPath,String startTime,String fileName);
}

在你的Activity或者fragment中implement这个接口,就可以实现对拍好的视频进行回调方法的处理。
OK,简单的视频拍摄就是这些,后面会把Demo地址更新上来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值