工作这么久,一直都很忙,好不容易闲下来就不习惯了。突然觉得应该做点有意义的事情,这几天研究了一下视屏直播方面的知识,使用camara,surfaceview,MediaRecorder录制音视频,surfaceview提供camara的预览。好了废话不多说了首先了解api吧。

1.使用camara录制视频有两种方式:一是借助Intent和MediaStroe调用系统Camera App程序来实现拍照和摄像功能,二是根据Camera API自写Camera程序。

第一种使用系统录制视频的方法:

对mediaStore有兴趣的同学可以看一篇文章 http://www.xuebuyuan.com/2038576.html;

  • Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
  • //在这里的QUALITY参数,值为两个,一个是0,一个是1,代表录制视频的清晰程度,0最不清楚,1最清楚
  • //没有0-1的中间值,另外,使用1也是比较占内存的,测试了一下,录制1分钟,大概内存是43M多
  • //使用0,录制1分钟大概内存是几兆
  • intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
  • // 限制时长 ,参数61代表61秒,可以根据需求自己调,最高应该是2个小时。
  • //当在这里设置时长之后,录制到达时间,系统会自动保存视频,停止录制
  • intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 61);
  • // 限制大小 限制视频的大小,这里是100兆。当大小到达的时候,系统会自动停止录制
  • intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, 1024 * 1024 * 100);
  • //在这里有录制完成之后的操作,系统会默认把视频放到照片的文件夹中
  • startActivityForResult(intent, 11);
  • 第二种调用camara的api的方法 本文中使用的是第二种方法

    一。首先初始化camara

    camara主要的几个api

    open():通过open方法获取Camera实例。  CameraInfo.CAMERA_FACING_BACK//后置摄像头,CameraInfo.CAMERA_FACING_FRONT前置摄像头
    setPreviewDisplay(SurfaceHolder):设置预览拍照

    mCamera.setPreviewCallback(null)//预览回调 停止预览
    startPreview():开始预览 
    stopPreview():停止预览

    mCamera.lock();// 默认Camera都是锁定的

    mCamera.unlock();解锁摄像头  camara默认是lock状态所以在camara初始化的时候一定要调用mCamera.lock();
    release():释放Camera实例 记住,在应用程序使用完Camera对象后,一定要调用Camera.release()方法来释放Camera对象。

    mCamera.setParameters(params); 传入的是paramas对象 这里可以设置一些camara参数   // 设置旋转代码
                params.setRotation(90);  params.set("orientation", "portrait");//设置屏幕方向  params.setJpegQuality()//设置图像输出质量  params.setPictureFormat//设置图片输出格式  params.setPictureSize设置图片大小  params.setPreviewFormat设置图像预览格式  params.setPreviewSize设置预览画面大小

    上面调用系统Camera App,我们压根不需要任何权限,但是这里用Camera API,就必须在manifest内声明使用权限,通常由以下三项

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

    <uses-feature android:name = "android.hardware.camera" />

    <uses-feature android:name = "android.hardware.camera.autofocus" />

    一般拍照和摄像的时候需要写到sd卡上,所以还有一向权限声明如下

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

    真做摄像功能时,需要音频录制和视频录制功能,所以又需要下面两项权限声明

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

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

    另外使用Camera API拍照或摄像,都需要用到预览,预览就要用到SurfaceView,为此Activity的布局中必须有SurfaceView。

    二。接下来是surfaceview作为camara提供预览 这里介绍一下surfaceview的几个重要的API

  • SurfaceView是View的子类,它内嵌了一个专门用于绘制的Surface,你可以控制这个Surface的格式和尺寸,Surfaceview控制这个Surface的绘制位置。surface是纵深排序(Z-ordered)的,说明它总在自己所在窗口的后面。SurfaceView提供了一个可见区域,只有在这个可见区域内的surface内容才可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者 surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面有透明控件,那么每次surface变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。
    SurfaceView默认使用双缓冲技术的,它支持在子线程中绘制图像,这样就不会阻塞主线程了,所以它更适合于游戏的开发。

    2. SurfaceView的使用
    首先继承SurfaceView,并实现SurfaceHolder.Callback接口,实现它的三个方法:surfaceCreated,surfaceChanged,surfaceDestroyed。

  • SurfaceView.getHolder();//获取surfaceholder对象为访问surface提供访问的接口 surface控制器,用来操纵surface
    surfaceCreated(SurfaceHolder holder):surface创建的时候调用,一般在该方法中启动绘图的线程。
    surfaceChanged(SurfaceHolder holder, int format, int width,int height):surface尺寸发生改变的时候调用,如横竖屏切换。
    surfaceDestroyed(SurfaceHolder holder) :surface被销毁的时候调用,如退出游戏画面,一般在该方法中停止绘图线程。
    还需要获得SurfaceHolder,并添加回调函数,这样这三个方法才会执行。

  • 三,mediarecoder
  • 说明:

    与MediaPlayer类非常相似MediaRecorder也有它自己的状态图。下面是关于MediaRecorder的各个状态的介绍:

    Initial:初始状态,当使用new()方法创建一个MediaRecorder对象或者调用了reset()方法时,该MediaRecorder对象处于Initial状态。在设定视频源或者音频源之后将转换为Initialized状态。另外,在除Released状态外的其它状态通过调用reset()方法都可以使MediaRecorder进入该状态。

    Initialized:已初始化状态,可以通过在Initial状态调用setAudioSource()或setVideoSource()方法进入该状态。在这个状态可以通过setOutputFormat()方法设置输出格式,此时MediaRecorder转换为DataSourceConfigured状态。另外,通过reset()方法进入Initial状态。

    DataSourceConfigured:数据源配置状态,这期间可以设定编码方式、输出文件、屏幕旋转、预览显示等等。可以在Initialized状态通过setOutputFormat()方法进入该状态。另外,可以通过reset()方法回到Initial状态,或者通过prepare()方法到达Prepared状态。

    Prepared:就绪状态,在DataSourceConfigured状态通过prepare()方法进入该状态。在这个状态可以通过start()进入录制状态。另外,可以通过reset()方法回到Initialized状态。

    Recording:录制状态,可以在Prepared状态通过调用start()方法进入该状态。另外,它可以通过stop()方法或reset()方法回到Initial状态。

    Released:释放状态(官方文档给出的词叫做Idle state 空闲状态),可以通过在Initial状态调用release()方法来进入这个状态,这时将会释放所有和MediaRecorder对象绑定的资源。

    Error:错误状态,当错误发生的时候进入这个状态,它可以通过reset()方法进入Initial状态。

    提示:与MediaPlayer相似使用MediaRecorder录音录像时需要严格遵守状态图说明中的函数调用先后顺序,在不同的状态调用不同的函数,否则会出现异常。

  • final static int

    getAudioSourceMax()

    获取音频源的最大值。

    int

    getMaxAmplitude()

    获取在前一次调用此方法之后录音中出现的最大振幅。

    void

    prepare()

    准备录制。

    void

    release()

    释放资源。

    void

    reset()

    将MediaRecorder设为空闲状态,即Initial状态。

    void

    setAudioChannels(int numChannels)

    设置录制的音频通道数。

    void

    setAudioEncoder(int audio_encoder)

    设置所录制的声音的编码格式。

    void

    setAudioEncodingBitRate(int bitRate)

    设置所录制的声音的编码位率。

    void

    setAudioSamplingRate(int samplingRate)

    设置所录制的声音的采样率。

    void

    setAudioSource(int audio_source)

    设置声音来源,一般传入 MediaRecorder. AudioSource.MIC参数指定录制来自麦克风的声音。

    void

    setCamera(Camera c)

    设置一个摄像头用于录制。

    void

    setCaptureRate(double fps)

    设置视频帧捕获率。

    void

    setLocation(float latitude, float longitude)

    设置并存储在输出文件中的地理数据(经度和纬度)。

    void

    setMaxDuration(int max_duration_ms)

    设置录制会话的最长持续时间(以ms为单位)。

    void

    setMaxFileSize(long max_filesize_bytes)

    设置录制文件的最大文件大小。

    void

    setOnErrorListener(MediaRecorder.OnErrorListener l)

    注册一个用于记录录制时出现的错误的监听器。

    void

    setOnInfoListener(MediaRecorder.OnInfoListener listener)

    注册一个用于记录录制时出现的信息事件。

    void

    setOrientationHint(int degrees)

    设置输出的视频播放的方向提示。

    void

    setOutputFile(FileDescriptor fd)

    设置录制的音频文件的保存位置。

    void

    setOutputFile(String path)

    设置录制的音频文件的保存位置。

    void

    setOutputFormat(int output_format)

    设置所录制的音视频文件的格式。

    void

    setPreviewDisplay(Surface sv)

    设置使用哪个SurfaceView来显示视频预览。

    void

    setProfile(CamcorderProfile profile)

    指定CamcorderProfile对象。

    void

    setVideoEncoder(int video_encoder)

    设置所录制视频的编码格式。

    void

    setVideoEncodingBitRate(int bitRate)

    设置所录制视频的编码位率。

    void

    setVideoFrameRate(int rate)

    设置录制视频的捕获帧速率。

    void

    setVideoSize(int width, int height)

    设置要拍摄的宽度和视频的高度。

    void

    setVideoSource(int video_source)

    设置用于录制的视频来源。

    void

    start()

    开始录制。

    void

    stop()

    停止录制。

  • final static int

    getAudioSourceMax()

    获取音频源的最大值。

    int

    getMaxAmplitude()

    获取在前一次调用此方法之后录音中出现的最大振幅。

    void

    prepare()

    准备录制。

    void

    release()

    释放资源。

    void

    reset()

    将MediaRecorder设为空闲状态,即Initial状态。

    void

    setAudioChannels(int numChannels)

    设置录制的音频通道数。

    void

    setAudioEncoder(int audio_encoder)

    设置所录制的声音的编码格式。

    void

    setAudioEncodingBitRate(int bitRate)

    设置所录制的声音的编码位率。

    void

    setAudioSamplingRate(int samplingRate)

    设置所录制的声音的采样率。

    void

    setAudioSource(int audio_source)

    设置声音来源,一般传入 MediaRecorder. AudioSource.MIC参数指定录制来自麦克风的声音。

    void

    setCamera(Camera c)

    设置一个摄像头用于录制。

    void

    setCaptureRate(double fps)

    设置视频帧捕获率。

    void

    setLocation(float latitude, float longitude)

    设置并存储在输出文件中的地理数据(经度和纬度)。

    void

    setMaxDuration(int max_duration_ms)

    设置录制会话的最长持续时间(以ms为单位)。

    void

    setMaxFileSize(long max_filesize_bytes)

    设置录制文件的最大文件大小。

    void

    setOnErrorListener(MediaRecorder.OnErrorListener l)

    注册一个用于记录录制时出现的错误的监听器。

    void

    setOnInfoListener(MediaRecorder.OnInfoListener listener)

    注册一个用于记录录制时出现的信息事件。

    void

    setOrientationHint(int degrees)

    设置输出的视频播放的方向提示。

    void

    setOutputFile(FileDescriptor fd)

    设置录制的音频文件的保存位置。

    void

    setOutputFile(String path)

    设置录制的音频文件的保存位置。

    void

    setOutputFormat(int output_format)

    设置所录制的音视频文件的格式。

    void

    setPreviewDisplay(Surface sv)

    设置使用哪个SurfaceView来显示视频预览。

    void

    setProfile(CamcorderProfile profile)

    指定CamcorderProfile对象。

    void

    setVideoEncoder(int video_encoder)

    设置所录制视频的编码格式。

    void

    setVideoEncodingBitRate(int bitRate)

    设置所录制视频的编码位率。

    void

    setVideoFrameRate(int rate)

    设置录制视频的捕获帧速率。

    void

    setVideoSize(int width, int height)

    设置要拍摄的宽度和视频的高度。

    void

    setVideoSource(int video_source)

    设置用于录制的视频来源。

    void

    start()

    开始录制。

    void

    stop()

    停止录制。

  • private int camaraBack=1;//1后置摄像头  0前置摄像头

    private Camara camara;

    public void initCamara(){

    try {

    if(camara!=null){//初始化释放摄像头资源

    freeCameraResource();//

    }

    if (camaraBack=1) {
                    mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);// 打开后置摄像头

    } else {
                    mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);// 打开前置摄像头

    }

    } catch (Exception e) {
                e.printStackTrace();
                freeCameraResource();

    }

    if (mCamera == null)
                return;

    //设置摄像头参数

    }

    /**
         * 设置摄像头为竖屏
         * 
         * @author lip
         * @date 2015-3-16
         */
        private void setCameraParams() {
            if (mCamera != null) {
                Parameters params = mCamera.getParameters();
                // 设置旋转代码
                params.setRotation(90);
                params.set("orientation", "portrait");

    mCamera.setParameters(params);
            }
        }

    /**
         * 释放摄像头资源
         * 
         * @author liuyinjun
         * @date 2015-2-5
         */
        private void freeCameraResource() {
            if (mCamera != null) {
                mCamera.setPreviewCallback(null);
                mCamera.stopPreview();
                mCamera.lock();
                mCamera.release();
                mCamera = null;
            }
        }

    }

  • 完整代码

  • /**
     * 视频录制控件
     * 
     * @author lip
     * 
     * @date 2015-3-16
     */
    public class MovieRecorderView extends LinearLayout implements OnErrorListener,
    OnInfoListener {

    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;
    private ProgressBar mProgressBar;

    private MediaRecorder mMediaRecorder;
    private Camera mCamera;
    private Timer mTimer;// 计时器
    private OnRecordFinishListener mOnRecordFinishListener;// 录制完成回调接口

    private int mWidth;// 视频分辨率宽度
    private int mHeight;// 视频分辨率高度
    private boolean isOpenCamera;// 是否一开始就打开摄像头
    private int mRecordMaxTime;// 一次拍摄最长时间
    private int mTimeCount;// 时间计数
    private File mVecordFile = null;// 文件
    private boolean isCameraBack = false;
    private Context context;
    /** 滤镜枚举值 */
    private final static String[] FILTER_VALUES = new String[] {
    MediaRecorderFilter.CAMERA_FILTER_NO,
    MediaRecorderFilter.CAMERA_FILTER_BLACKWHITE,
    MediaRecorderFilter.CAMERA_FILTER_SHARPEN,
    MediaRecorderFilter.CAMERA_FILTER_OLD_PHOTOS,
    MediaRecorderFilter.CAMERA_FILTER_NEON_LIGHT,
    MediaRecorderFilter.CAMERA_FILTER_ANTICOLOR,
    MediaRecorderFilter.CAMERA_FILTER_PASS_THROUGH,
    MediaRecorderFilter.CAMERA_FILTER_MOSAICS,
    MediaRecorderFilter.CAMERA_FILTER_REMINISCENCE };

    public void setOnRecordFinishListener(OnRecordFinishListener finishListener) {
    this.mOnRecordFinishListener = finishListener;
    }

    public MovieRecorderView(Context context) {
    this(context, null);
    this.context = context;

    }

    public MovieRecorderView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);

    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public MovieRecorderView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    this.context = context;
    mWidth = 320;
    mHeight = 240;
    isOpenCamera = true;
    mRecordMaxTime = 10;

    LayoutInflater.from(context).inflate(R.layout.camara, this);
    mSurfaceView = (SurfaceView) findViewById(R.id.sufaceView);
    mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
    mProgressBar.setMax(mRecordMaxTime);// 设置进度条最大量

    mSurfaceHolder = mSurfaceView.getHolder();

    mSurfaceHolder.addCallback(new CustomCallBack());
    mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    }

    /**

    * @author liuyinjun

    * @date 2015-2-5
    */
    private class CustomCallBack implements Callback {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    if (!isOpenCamera)
    return;
    try {
    initCamera();

    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
    int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    if (!isOpenCamera)
    return;
    freeCameraResource();

    }

    }

    /**
    * 初始化摄像头

    * @author lip
    * @date 2015-3-16
    * @throws IOException
    */
    private void initCamera() throws IOException {
    if (mCamera != null) {
    freeCameraResource();
    }
    try {
    if (!isCameraBack) {
    mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);// 打开摄像头

    } else {
    mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);// 打开摄像头

    }

    } catch (Exception e) {
    e.printStackTrace();
    freeCameraResource();
    }
    if (mCamera == null)
    return;

    setCameraParams();
    // 设置camera预览的角度,因为默认图片是倾斜90度的

    mCamera.setDisplayOrientation(90);
    mCamera.setPreviewDisplay(mSurfaceHolder);
    mCamera.startPreview();
    mCamera.unlock();
    }

    public void setCamara() {
    if (mCamera == null)
    return;

    setCameraParams();
    // 设置camera预览的角度,因为默认图片是倾斜90度的

    mCamera.setDisplayOrientation(90);
    try {
    mCamera.setPreviewDisplay(mSurfaceHolder);
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    mCamera.startPreview();
    mCamera.unlock();
    }

    /**
    * 设置摄像头为竖屏

    * @author lip
    * @date 2015-3-16
    */
    private void setCameraParams() {
    if (mCamera != null) {
    Parameters params = mCamera.getParameters();
    // 设置旋转代码
    params.setRotation(90);
    params.set("orientation", "portrait");

    mCamera.setParameters(params);
    }
    }

    /**
    * 释放摄像头资源

    * @author liuyinjun
    * @date 2015-2-5
    */
    private void freeCameraResource() {
    if (mCamera != null) {
    mCamera.setPreviewCallback(null);
    mCamera.stopPreview();
    mCamera.lock();
    mCamera.release();
    mCamera = null;
    }
    }

    private void createRecordDir() {
    // File sampleDir = new File(Environment.getExternalStorageDirectory() +
    // File.separator + "im/video/");
    File sampleDir = new File(Environment.getExternalStorageDirectory()
    + File.separator + "RecordVideo/");
    // File sampleDir = new File("/video/");
    if (!sampleDir.exists()) {
    sampleDir.mkdirs();
    }
    File vecordDir = sampleDir;
    // 创建文件
    try {
    mVecordFile = File.createTempFile("recording", ".mp4", vecordDir);// mp4格式
    // LogUtils.i(mVecordFile.getAbsolutePath());
    Log.d("Path:", mVecordFile.getAbsolutePath());
    } catch (IOException e) {
    e.printStackTrace();
    }
    }

    /**
    * 初始化

    * @author lip
    * @date 2015-3-16
    * @throws IOException
    */
    private void initRecord() throws IOException {
    initCamera();
    mMediaRecorder = new MediaRecorder();

    mMediaRecorder.reset();

    if (mCamera != null)

    mMediaRecorder.setCamera(mCamera);
    mMediaRecorder.setOnErrorListener(this);
    mMediaRecorder.setOnInfoListener(this);
    mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
    mMediaRecorder.setVideoSource(VideoSource.CAMERA);// 视频源
    mMediaRecorder.setAudioSource(AudioSource.MIC);// 音频源
    mMediaRecorder.setOutputFormat(OutputFormat.MPEG_4);// 视频输出格式
    mMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);// 音频格式
    mMediaRecorder.setVideoSize(mWidth, mHeight);// 设置分辨率:
    // mMediaRecorder.setVideoFrameRate(16);// 这个我把它去掉了,感觉没什么用
    mMediaRecorder.setVideoEncodingBitRate(1 * 1024 * 512);// 设置帧频率,然后就清晰了

    mMediaRecorder.setOrientationHint(90);// 输出旋转90度,保持竖屏录制
    mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);// 视频录制格式
    // mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);
    // setSocket();
    mMediaRecorder.setOutputFile(mVecordFile.getAbsolutePath());

    try {
    mMediaRecorder.prepare();
    mMediaRecorder.start();
    } catch (IllegalStateException e) {
    e.printStackTrace();
    } catch (RuntimeException e) {
    e.printStackTrace();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    private void setSocket() throws SocketException, IOException {
    Socket socket = new Socket();
    SocketAddress socAddress = new InetSocketAddress("", 100);
    socket.setSoTimeout(10000);
    // 关闭socket时,立即释放socket绑定端口以便端口重用,默认为false
    socket.setReuseAddress(true);
    // 关闭传输缓存,默认为false
    socket.setTcpNoDelay(true);
    // 设置socket保持存状态
    socket.setKeepAlive(true);
    // 关闭socket时,底层socket不会直接关闭,会延迟一会,直到发送完所有数据
    // 等待10秒再关闭底层socket连接,0为立即关闭底层socket连接
    socket.setSoLinger(true, 10);
    // 设置性能参数,可设置任意整数,数值越大,相应的参数重要性越高(连接时间,延迟,带宽)
    socket.setPerformancePreferences(3, 2, 1);
    socket.connect(socAddress, 10000);
    ParcelFileDescriptor descriptor = ParcelFileDescriptor
    .fromSocket(socket);
    mMediaRecorder.setOutputFile(descriptor.getFileDescriptor());

    InputStream inputStream = socket.getInputStream();

    }

    /**
    * 开始录制视频

    * @author liuyinjun
    * @date 2015-2-5 // * @param fileName // * 视频储存位置
    * @param onRecordFinishListener
    *            达到指定时间之后回调接口
    */
    public void record() {

    createRecordDir();
    try {
    if (!isOpenCamera)// 如果未打开摄像头,则打开
    initCamera();
    initRecord();
    mTimeCount = 0;// 时间计数器重新赋值
    mTimer = new Timer();
    mTimer.schedule(new TimerTask() {

    @Override
    public void run() {
    // TODO Auto-generated method stub
    mTimeCount++;
    mProgressBar.setProgress(mTimeCount);// 设置进度条
    String path = mVecordFile.getAbsolutePath();
    FileInputStream fileInputStream = null;
    byte[] bs = null;
    int lenth = 0;
    try {
    fileInputStream = new FileInputStream(path);
    bs = new byte[1024];
    try {
    lenth = fileInputStream.read(bs);
    Log.i("________lenth+", "" + lenth);

    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    if (mTimeCount == mRecordMaxTime) {// 达到指定时间,停止拍摄
    stop();
    Log.i("________stop+", "" + lenth);
    if (mOnRecordFinishListener != null)
    mOnRecordFinishListener.onRecordFinish();
    }
    }
    }, 0, 1000);
    } catch (IOException e) {
    e.printStackTrace();
    }
    }

    /**
    * 停止拍摄

    * @author liuyinjun
    * @date 2015-2-5
    */
    public void stop() {
    stopRecord();
    releaseRecord();
    freeCameraResource();
    }

    /**
    * 停止录制

    * @author liuyinjun
    * @date 2015-2-5
    */
    public void stopRecord() {
    mProgressBar.setProgress(0);
    if (mTimer != null)
    mTimer.cancel();
    if (mMediaRecorder != null) {
    // 设置后不会崩
    mMediaRecorder.setOnErrorListener(null);
    mMediaRecorder.setPreviewDisplay(null);
    try {

    mMediaRecorder.stop();
    } catch (IllegalStateException e) {
    e.printStackTrace();
    } catch (RuntimeException e) {
    e.printStackTrace();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

    /**
    * 释放资源

    * @author liuyinjun
    * @date 2015-2-5
    */
    private void releaseRecord() {
    if (mMediaRecorder != null) {
    mMediaRecorder.setOnErrorListener(null);
    try {
    mMediaRecorder.release();
    } catch (IllegalStateException e) {
    e.printStackTrace();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    mMediaRecorder = null;
    }

    public int getTimeCount() {
    return mTimeCount;
    }

    /**
    * @return the mVecordFile
    */
    public File getmVecordFile() {
    return mVecordFile;
    }

    /**
    * 录制完成回调接口

    * @author lip

    * @date 2015-3-16
    */
    public interface OnRecordFinishListener {
    public void onRecordFinish();
    }

    @Override
    public void onError(MediaRecorder mr, int what, int extra) {
    try {
    if (mr != null)
    mr.reset();
    } catch (IllegalStateException e) {
    e.printStackTrace();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    private int position = 0;

    /**
    * 切换摄像头
    */
    public void backCamera() {
    if (!isCameraBack) {
    isCameraBack = false;
    } else {
    isCameraBack = true;
    }

    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
    position = Camera.getNumberOfCameras();

    for (int i = 0; i < position; i++) {

    Camera.getCameraInfo(i, cameraInfo);
    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
    freeCameraResource();
    mCamera = Camera.open(i);
    // deal(mCamera);
    setCamara();
    }
    }

    }

    public void fronCamera() {
    if (!isCameraBack) {
    isCameraBack = false;
    } else {
    isCameraBack = true;
    }
    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
    position = Camera.getNumberOfCameras();
    for (int i = 0; i < position; i++) {
    Camera.getCameraInfo(i, cameraInfo);
    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
    freeCameraResource();
    mCamera = Camera.open(i);
    setCamara();
    // deal(mCamera);
    }
    }

    }

    public Camera deal(Camera camera) {
    // 设置camera预览的角度,因为默认图片是倾斜90度的
    camera.setDisplayOrientation(90);

    Size pictureSize = null;
    Size previewSize = null;
    Camera.Parameters parameters = camera.getParameters();
    parameters.setPreviewFrameRate(5);
    // 设置旋转代码
    parameters.setRotation(90);
    // parameters.setPictureFormat(PixelFormat.JPEG);

    List<Size> supportedPictureSizes = SupportedSizesReflect
    .getSupportedPictureSizes(parameters);// 获取手机支持的视屏分辨率大小集合
    List<Size> supportedPreviewSizes = SupportedSizesReflect
    .getSupportedPreviewSizes(parameters);

    if (supportedPictureSizes != null && supportedPreviewSizes != null
    && supportedPictureSizes.size() > 0
    && supportedPreviewSizes.size() > 0) {

    // 2.x
    pictureSize = supportedPictureSizes.get(0);

    int maxSize = 1280;
    if (maxSize > 0) {
    for (Size size : supportedPictureSizes) {
    if (maxSize >= Math.max(size.width, size.height)) {
    pictureSize = size;
    break;
    }
    }
    }

    WindowManager windowManager = (WindowManager) context
    .getSystemService(Context.WINDOW_SERVICE);
    Display display = windowManager.getDefaultDisplay();
    DisplayMetrics displayMetrics = new DisplayMetrics();
    display.getMetrics(displayMetrics);

    previewSize = getOptimalPreviewSize(supportedPreviewSizes,
    display.getWidth(), display.getHeight());

    parameters.setPictureSize(pictureSize.width, pictureSize.height);
    parameters.setPreviewSize(previewSize.width, previewSize.height);

    }
    camera.setParameters(parameters);
    return camera;
    }

    private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) w / h;
    if (sizes == null)
    return null;

    Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    // Try to find an size match aspect ratio and size
    for (Size size : sizes) {
    double ratio = (double) size.width / size.height;
    if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
    continue;
    if (Math.abs(size.height - targetHeight) < minDiff) {
    optimalSize = size;
    minDiff = Math.abs(size.height - targetHeight);
    }
    }

    // Cannot find the one match the aspect ratio, ignore the requirement
    if (optimalSize == null) {
    minDiff = Double.MAX_VALUE;
    for (Size size : sizes) {
    if (Math.abs(size.height - targetHeight) < minDiff) {
    optimalSize = size;
    minDiff = Math.abs(size.height - targetHeight);
    }
    }
    }
    return optimalSize;
    }

    @Override
    public void onInfo(MediaRecorder mr, int what, int extra) {
    switch (what) {
    case MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN:// 错误未知

    break;
    case MediaRecorder.MEDIA_ERROR_SERVER_DIED:// 服务器链接失败

    break;
    case MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED:// 记录信息的最大持续时间达到
     stop();

    break;
    case MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED:// 储信息达到最大文件大小

    break;

    default:
    break;
    }

    }

    // public void setCamaraFilter(int position) {
    // FILTER_VALUES[position];
    // }
    }

android MediaRecorder录制音视频实现直播的基础相关推荐

  1. Android -- MediaRecorder录制短视频

    一.权限 AndroidManifest.xml: <uses-permission android:name="android.permission.WRITE_EXTERNAL_S ...

  2. Android MediaRecorder录制视频音量小问题解决 (音视频转码合成)

    之前写得太乱,回头看看感觉自己都有点看不懂,重新写下. 在android上需要做一个录像留言功能,需要生成MP4或者waw格式视频.但是使用MediaRecorder录制出的MP4视频格式音量太小,几 ...

  3. Android音视频点/直播模块开发

    前言 随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能,那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式 ...

  4. Android音视频点/直播模块开发实践总结-zz

    随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能.那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式,以及 ...

  5. android音/视频,直播

    流媒体 采用流式传输的方式在Internet / Intranet播放的媒体格式.流媒体的数据流随时传送随 时播放,只是在开始时有些延迟.边下载边播入的流式传输方式不仅使启动延时大幅度地缩短,而且对系 ...

  6. 安卓Android中腾讯音视频和直播 API的使用

    安卓Android中腾讯音视频和直播 API的使用 文章目录 安卓Android中腾讯音视频和直播 API的使用 前言:安卓Android中腾讯音视频和直播 API的使用,这里没有写UI,功能是放在一 ...

  7. 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)

    随笔分类 - webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译者: ...

  8. C# ffmpeg 录制音视频

    最近研究用ffmpeg录制桌面视频,以下是研究时碰到的问题以及成果记录下. FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序.采用LGPL或GPL许可证.它提供了录 ...

  9. Android IOS WebRTC 音视频开发总结(六五)-- 给韩国电信巨头做咨询

    Android IOS WebRTC 音视频开发总结(六五)-- 给韩国电信巨头做咨询 本文主要总结咨询过程中的一些问题,文章最早发表在我们的微信公众号上,详见这里,欢迎关注微信公众号blackert ...

最新文章

  1. 继国务院后,上海也发布人工智能发展意见,2020年产业规模超千亿
  2. 防火墙技术指标---并发连接数/吞吐量
  3. ElasticSearch 知识点整理(入门)
  4. javascript的Foreach语法
  5. otl oracle存储过程,OTL调用存储过程/函数及注意事项
  6. Java中Jsp和Servlet上传和下载文件
  7. 英特尓祭出开挖数据价值的“六脉神剑”!
  8. 华中农业大学C语言实验5答案,物理实验报告册(上册)-华中农业大学实验.pdf
  9. Altium Designer(十):极坐标
  10. el-select默认选中 显示的是id 不是汉字
  11. 提升方法AdaBoost你真的懂吗
  12. 明道云在建筑工程行业的应用场景
  13. MC(移动立方体)算法
  14. 微信公众号网页 H5 video 标签自动播放
  15. 用Windows自带的系统恢复环境WinRE进行系统重大故障排查,轻松修复Windows蓝屏、白屏等问题
  16. 华为路ws5200设置虚拟服务器,华为WS5200无线路由器怎么设置?
  17. centos修正时区
  18. 关于EasyDarwinGo部署海康威视rtsp转hls视频多摄像头的服务器视频转码
  19. 斗罗大陆壁纸图片高清小舞146集八段摔杨无敌
  20. 判断是否qq或者微信内置浏览器

热门文章

  1. 成都传智播客新装上线
  2. 智慧餐厅解决方案-最新全套文件
  3. word图表标签与编号之间空格删除解决方案
  4. 三相整流器移相触发电路的整体FPGA设计
  5. java sinh_Java StrictMath sinh()用法及代码示例
  6. DIY强大的虚拟化环境-前言与目录
  7. Google中国(谷歌)汉化大事记 1
  8. 智慧市政管理系统升城市形象和品位
  9. 计算机配置文件保存到哪里,微信文件保存在哪里【设置教程】
  10. oppoR17手机计算机的隐藏功能,小技巧隐藏大“智慧”,原来OPPO R17还有这些实用功能...