Android 使用MediaRecord录像的一些问题总结

最近一段时间都在做一些录像相关的事情,通过直接找到一些大神的博客,学习怎么使用MediaRecord,总算完成,如果只是这样就不写这篇文章了,关键在我们的技术支持是一个追求完美的人,他提出了三个问题:

1、录像出来的文件清晰度不够;

2、录像文件和系统对比,亮度不够;

3、帧数达不到要求;

总之就是和系统录像有差距,录制的视频文件要和系统录制出来的一样,头大,针对个问题,又是一番百度:

1、针对清晰度问题,直接采用系统配置的参数

private
@Nullable
CamcorderProfile getBestCamcorderProfile() {
    int quality = CamcorderProfile.QUALITY_HIGH;
    if (videoType == 1 && CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_1080P)) {
        quality = CamcorderProfile.QUALITY_1080P;
    } else if (videoType == 2 && CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)) {
        quality = CamcorderProfile.QUALITY_720P;
    } else if (videoType == 3 && CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_480P)) {
        quality = CamcorderProfile.QUALITY_480P;
    } else {
        quality = CamcorderProfile.QUALITY_CIF;
    }
    return CamcorderProfile.get(quality);
}

这样录制的视频清晰度绝对是系统级别的,如果不需要,可以自由调整比特率和分辨率来满足需求;

2、针对亮度不够的问题:

这里走了不少弯路,首先想到的是黑白平衡、亮度、饱和度、曝光级别,设置了都没用,至少在我测试的定制机上是没有效果的;后面又想到了自动聚焦和区域聚焦,结果把自己调到一个更大的坑,一把辛酸泪不多说;最后实在没办法,翻阅系统MediaRecord相关demo,想从这个里面找到原因,看了两天,txt上看真的头疼,好不容易看完,修改录像代码,测试发现没效果;最后只能去阅读camera 源码,在源码里面总算找到一个方法:

Android 使用MediaRecord录像的一些问题总结

没错 就是这个方法,设置之后效果和系统录像一致,达到了要求;

3、第三个问题相比起来简直不是问题,camera直接提供了相应的方法:

Android 使用MediaRecord录像的一些问题总结

查阅了不少大神博客,发现很少有用这个方法的,为了达到要求,设置了这个方法,和系统录像达到一样的帧率,不过要注意的是,最大最小帧率都是30帧,录像文件只有29.xx帧,会有一点损失。

 

三个问题总算解决,成功保住了饭碗,下面贴出代码:

public class MediaRecorderActivity extends BaseActivity
        implements SurfaceHolder.Callback, MediaRecorder.OnErrorListener
        , MediaRecorder.OnInfoListener {


    // ---------------------------- 常量-------------------------------

    // -------------------------- 全局变量------------------------------
    private MediaRecorder mediarecorder;// 录制视频的类
    private SizeSurfaceView surfaceview;// 显示视频的控件
    // 用来显示视频的一个接口,我靠不用还不行,也就是说用mediarecorder录制视频还得给个界面看
    private SurfaceHolder surfaceHolder;
    private int WIDTH_DEF = 1920;
    private int HEIGHT_DEF = 1080;


    private static final int ONE_MINUTE_TIME = 60 * 1000;
    private static final int ONE_HOUR_TIME = 60 * ONE_MINUTE_TIME;

    private String outString;
    private String parentString;

    private static Timer timer;

    private Camera mCamera;

    private int videoType = 3;  //1 : 1080P   2 : 720 P   3 : 480   4: 流畅


    //控制闪光灯 手电筒的
    public static final int FLASH_MODE_OFF = 0;
    public static final int FLASH_MODE_ON = 1;
    public static int flashType = FLASH_MODE_OFF;

    private boolean isNotify = false;

    private long mMediaRecorderStartTImes = 0;

    //记录本地视频信息
    private VideoData videoData = new VideoData();
    private long fragmentVideoDataStartTimes;
    private ArrayList<FragmentVideoData> fragmentVideoDatas = new ArrayList<>();


    public static void launch(Context context) {
        Intent i = new Intent(context, MediaRecorderActivity.class);
        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(i);
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /**
         * 如果录像按钮不处于按下状态,结束录制本地视频
         * 防止出现本地视频自己会开启的情况
         */
        if (!HandlerManager.isPress) {
            finish();
            return;
        }
        setContentView(R.layout.activity_mediarecord);
        initView();
        initData();
    }


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

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 将holder,这个holder为开始在oncreat里面取得的holder,将它赋给surfaceHolder
        surfaceHolder = holder;
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        releaseCamera();
        surfaceview = null;
        surfaceHolder = null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopMediarecorder();
        releaseCamera();
        stopTimer();
        LightPoingManager.getInstance().cancel();
        getDuration();
        VideoManager.getInstance().setIsPress(true);
    }


    @Override
    public void onError(MediaRecorder mr, int what, int extra) {
        TtsManager.getInstance().say("录制出错,已经结束本次录制");
        releaseCamera();
        finish();
    }

    @Override
    public void onInfo(MediaRecorder mr, int what, int extra) {
        if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) {
            releaseCamera();
            finish();
        } else if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
            if (mCamera != null) {
                Camera.Parameters p = mCamera.getParameters();
                String s = p.getFlashMode();
                LogUtil.e(Camera.Parameters.FLASH_MODE_ON.equals(s) ? "手电筒打开" : "手电筒关闭");
            } else {
                LogUtil.e("mCamera null");
            }
            stopMediarecorder();
            fileScan(outString);
            LogUtil.e("已达到录制上限,更换存储路径,即将重新开始录制");
            start();
        } else if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
            releaseCamera();
            finish();
        }
    }


    private void initView() {
        if (surfaceview == null) {
            surfaceview = (SizeSurfaceView) findViewById(R.id.recorder_view);
            surfaceview.getHolder().addCallback(this);
            surfaceview.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            surfaceview.getHolder().setKeepScreenOn(true);
            surfaceview.setUserSize(true);
        }
    }

    private void initData() {
        VideoManager.VIDEO_TYPE = VideoManager.VIDEO_TYPE_RECORD;
        videoType = SpUtil.getLocalVideoType();
        if (videoType == 1) {
            WIDTH_DEF = 1920;
            HEIGHT_DEF = 1080;
        } else if (videoType == 2) {
            WIDTH_DEF = 1280;
            HEIGHT_DEF = 720;
        } else if (videoType == 3) {
            WIDTH_DEF = 640;
            HEIGHT_DEF = 480;
        } else {
            WIDTH_DEF = 480;
            HEIGHT_DEF = 320;
        }
        getVideoPath();
    }


    /**
     * A safe way to get an instance of the Camera object.
     */
    public Camera getCameraInstance() {
        Camera c = null;
        try {
            c = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK); // attempt to get a Camera instance
        } catch (Exception e) {
            // Camera is not available (in use or does not exist)
            TtsManager.getInstance().say("设备初始化失败");
            releaseCamera();
            finish();
        }
        return c; // returns null if camera is unavailable
    }

    /**
     * 初始化摄像头
     */
    public void initCamera() {

        try {
            mCamera = getCameraInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (mCamera == null) {
            TtsManager.getInstance().say("无设备可用");
            releaseCamera();
            finish();
            return;
        }
        try {
            Camera.Parameters p = mCamera.getParameters();
            p.setRecordingHint(true); //主要用于MediaRecord录像
            p.setPreviewFpsRange(30000, 30000);  //主要用于设置视频的帧数
            p.setPreviewSize(WIDTH_DEF, HEIGHT_DEF);
            List<String> supportedFocus = p.getSupportedFocusModes();
            boolean isHave = supportedFocus == null ? false :
                    supportedFocus.indexOf(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO) >= 0;
            if (isHave) {
                p.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
            }
            try {
                mCamera.setParameters(p);
            } catch (Exception e) {
                e.printStackTrace();
                TtsManager.getInstance().say("参数错误,已结束本次录像");
                releaseCamera();
                finish();
            }
            mCamera.setPreviewDisplay(surfaceHolder);
            mCamera.cancelAutoFocus();//只有加上了这一句,才会自动对焦。
            mCamera.startPreview();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private void stopMediarecorder() {
        if (mediarecorder != null) {
            mediarecorder.setOnErrorListener(null);
            mediarecorder.setOnInfoListener(null);
            mediarecorder.setPreviewDisplay(null);
            // 停止录制
            try {
                mediarecorder.stop();
            } catch (IllegalStateException e) {
                // TODO 如果当前java状态和jni里面的状态不一致,
                e.printStackTrace();
                mediarecorder = null;
                mediarecorder = new MediaRecorder();
            }
            mediarecorder.reset();
            // 释放资源
            mediarecorder.release();
            LogUtil.e("release()", " mediarecorder.release();");
            mediarecorder = null;
        }

        FragmentVideoData fragmentVideoData = new FragmentVideoData();
        fragmentVideoData.setId(System.currentTimeMillis());
        fragmentVideoData.fragmentStartTimes = fragmentVideoDataStartTimes;
        fragmentVideoData.fragmentEndTimes = System.currentTimeMillis();
        long duration = fragmentVideoData.fragmentEndTimes - fragmentVideoDataStartTimes;
        if (videoType == 1) {
            fragmentVideoData.duration = duration > 5 * ONE_MINUTE_TIME ? 5 * ONE_MINUTE_TIME : duration;
        } else if (videoType == 2) {
            fragmentVideoData.duration = duration > 5 * ONE_MINUTE_TIME ? 5 * ONE_MINUTE_TIME : duration;
        } else {
            fragmentVideoData.duration = duration > 20 * ONE_MINUTE_TIME ? 20 * ONE_MINUTE_TIME : duration;
        }
        try {
            if (!TextUtils.isEmpty(outString)) {
                fragmentVideoData.videoName = outString.substring(outString.lastIndexOf(File.separator) + 1, outString.length());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        fragmentVideoData.videoStartTime = mMediaRecorderStartTImes;
        VideoDataManager.getInstance().saveFragmentVideoDataToDB(fragmentVideoData);
        fragmentVideoDatas.add(fragmentVideoData);
    }


    private void start() {
        if (mediarecorder == null) {
            mediarecorder = new MediaRecorder(); // 创建MediaRecorder
        }
        try {
            if (mCamera != null) {
                mCamera.stopPreview();
                mCamera.unlock();
                mediarecorder.setCamera(mCamera);
            }
            // 设置音频采集方式
            mediarecorder.setAudioSource(AudioConfig.AUDIO_SOURCE);
            mediarecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            //setVideoOrientRotation(orientRotation);
            CamcorderProfile mProfile = customMediaRecorder();
            if (mProfile != null) {
                mediarecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                mediarecorder.setVideoFrameRate(mProfile.videoFrameRate);
                mediarecorder.setVideoSize(WIDTH_DEF, HEIGHT_DEF);
                if (videoType == 1) {
                    mediarecorder.setVideoEncodingBitRate((int) (mProfile.videoBitRate * 1.03));
                } else if (videoType == 2) {
                    mediarecorder.setVideoEncodingBitRate((int) (mProfile.videoBitRate * 1.03));
                } else if (videoType == 3) {
                    mediarecorder.setVideoEncodingBitRate((int) (mProfile.videoBitRate * 0.7));
                } else {
                    mediarecorder.setVideoEncodingBitRate((int) (mProfile.videoBitRate));
                }
                mediarecorder.setVideoEncoder(mProfile.videoCodec);
                if (mProfile.quality >= CamcorderProfile.QUALITY_TIME_LAPSE_LOW &&
                        mProfile.quality <= CamcorderProfile.QUALITY_TIME_LAPSE_QVGA) {

                } else {
                    mediarecorder.setAudioEncodingBitRate(mProfile.audioBitRate);
                    mediarecorder.setAudioChannels(mProfile.audioChannels);
                    mediarecorder.setAudioSamplingRate(mProfile.audioSampleRate);
                    mediarecorder.setAudioEncoder(mProfile.audioCodec);
                }
            } else {
                mediarecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                mediarecorder.setVideoFrameRate(30);
                mediarecorder.setVideoSize(WIDTH_DEF, HEIGHT_DEF);
                if (videoType == 1) {
                    mediarecorder.setVideoEncodingBitRate((int) (17000000 * 1.03));
                } else if (videoType == 2) {
                    mediarecorder.setVideoEncodingBitRate((int) (9000000 * 1.03));
                } else if (videoType == 3) {
                    mediarecorder.setVideoEncodingBitRate((int) (4500000 * 0.7));
                } else {
                    mediarecorder.setVideoEncodingBitRate((int) (1920000 * 0.7));
                }
                mediarecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
                mediarecorder.setAudioEncodingBitRate(128000);
                mediarecorder.setAudioChannels(2);
                mediarecorder.setAudioSamplingRate(48000);
                mediarecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
            }
            mediarecorder.setOnErrorListener(this);
            mediarecorder.setOnInfoListener(this);
            int maxDuration = 0;
            if (videoType == 1) {
                maxDuration = 5 * ONE_MINUTE_TIME;
            } else if (videoType == 2) {
                maxDuration = 5 * ONE_MINUTE_TIME;
            } else {
                maxDuration = 20 * ONE_MINUTE_TIME;
            }
            mediarecorder.setMaxDuration(maxDuration);

            mediarecorder.setPreviewDisplay(surfaceHolder.getSurface());
            if (mMediaRecorderStartTImes <= 0) {
                mMediaRecorderStartTImes = System.currentTimeMillis();
            }
            fragmentVideoDataStartTimes = System.currentTimeMillis();
            //设置输出文件的路径
            outString = PathConstants.getVideoPath(parentString);
            mediarecorder.setOutputFile(outString);
            //开始录制前,先检查下空间是否足够,不够的话删除再开始录制
            checkSpace();
            //准备录制
            mediarecorder.prepare();
            mediarecorder.start();
            LogUtil.e("mediarecorder()", " mediarecorder.start()");
            if (timer == null) {
                timer = new Timer();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        if (mediarecorder == null) {
                            if (timer != null) {
                                timer.cancel();
                                timer = null;
                            }
                            return;
                        }
                        RingtoneUtils.startAlarmWithStreamVolume("media_recorder_tip.mp3", 1);
                        fileScan(outString);
                        checkSpace();
                        checkBarrery();
                    }
                }, 30 * 1000, 30 * 1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
            TtsManager.getInstance().say("录制出错,已经结束本次录制");
            releaseCamera();
            finish();
        }
    }

    //检测电量   如果不结束,导致录制的视频无法播放
    private void checkBarrery() {
        int barreryLevel = SpUtil.getBattery();
        if (barreryLevel <= 2) {
            TtsManager.getInstance().say("电量不足,即将结束本次录制");
            finish();
        }
    }

    //获取视频存放地址
    private void getVideoPath() {
        List<StorageVolumeUtil.MyStorageVolume> svs = StorageVolumeUtil.getMountedVolumeList(ContextHolder.getContext());
        if (svs != null && svs.size() > 0) {
            boolean flag = false;
            for (int i = 0, size = svs.size(); i < size; i++) {
                final StorageVolumeUtil.MyStorageVolume mv = svs.get(size - 1 - i);
                if (PathConstants.hasEnoughSpaceForWrite(mv.mPath)) {
                    flag = true;
                    parentString = mv.mPath;
                    break;
                }
                LogUtil.e("路径:" + mv.mPath + "   大小:" + (mv.getAvailableSize() / PathConstants.M) + "M");
            }
            if (!flag) {
                if (!TextUtils.isEmpty(parentString)) {
                    FileUtil.deleteEarliestFile(PathConstants.getVideoCachePath(parentString));
                }
            }
            String text = "现在开始";
            if (videoType == 1) {
                text += "超清摄像";
            } else if (videoType == 2) {
                text += "高清摄像";
            } else if (videoType == 3) {
                text += "标清摄像";
            } else {
                text += "摄像";
            }
            TtsManager.getInstance().say(text);
        } else {
            String txt = "存储地址获取失败,已经结束本次录制";
            TtsManager.getInstance().say(txt);
            releaseCamera();
            finish();
        }
    }

    /**
     * 检查存储空间
     */
    private void checkSpace() {
        long residual = PathConstants.getAvailableExternalSize(parentString);
        LogUtil.e("删除文件前:检测剩余空间" + (residual / PathConstants.M) + "M");
        if (residual > 0) {
            if (residual / PathConstants.M < 700 && !isNotify) {
                isNotify = true;
                TtsManager.getInstance().say("剩余空间不足,即将开始覆盖旧数据");
            }
            if (residual / PathConstants.M < 600) {
                if (!TextUtils.isEmpty(parentString)) {
                    FileUtil.deleteEarliestFile(PathConstants.getVideoCachePath(parentString));
                }
            }
            if (Configer.TestMode) {
                long residua2 = PathConstants.getAvailableExternalSize(parentString);
                LogUtil.e("删除文件后:检测剩余空间" + (residua2 / PathConstants.M) + "M");
            }
        }
    }


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

    //获取视频时长
    private void getDuration() {
        long duration = 0;
        for (FragmentVideoData fragmentVideoData : fragmentVideoDatas) {
            duration += fragmentVideoData.duration;
            LogUtil.e("FragmentVideoData", "FragmentVideoData:  " + fragmentVideoData.duration);
        }
        LogUtil.e("FragmentVideoData", "FragmentVideoDataAll:  " + duration);
        if (duration > 2 && duration < 24 * ONE_HOUR_TIME) {
            if (VideoManager.getInstance().getIsPress()) {
                say(duration);
            }
        } else {
            TtsManager.getInstance().say("摄像结束");
        }
        videoData.setId(System.currentTimeMillis());
        videoData.setStartAllTimes(mMediaRecorderStartTImes);
        videoData.fragmentVideoDatas = fragmentVideoDatas;
        videoData.setDurationAll(duration);
        videoData.setEndAllTimes(videoData.getStartAllTimes() + duration);
        //上传视频数据
        try {
            VideoDataManager.getInstance().saveVideoDataToDB(videoData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //发广播扫描,否则生成的文件看不到
        fileScan(outString);
    }

    private void say(long recordTime) {
        if (recordTime >= ONE_HOUR_TIME) {
            int hour = (int) (recordTime / ONE_HOUR_TIME);
            int minute = (int) ((recordTime - hour * ONE_HOUR_TIME) / ONE_MINUTE_TIME);
            int millis = (int) ((recordTime - hour * ONE_HOUR_TIME - minute * ONE_MINUTE_TIME) / 1000);
            TtsManager.getInstance().say("摄像结束,本次摄像时长" + hour + "小时" + minute + "分钟" + (millis > 0 ? (millis + "秒") : ""));
        } else if (recordTime >= 60 * 1000) {
            int minute = (int) (recordTime / ONE_MINUTE_TIME);
            int millis = (int) ((recordTime - minute * ONE_MINUTE_TIME) / 1000);
            TtsManager.getInstance().say("摄像结束,本次摄像时长" + minute + "分钟" + (millis > 0 ? (millis + "秒") : ""));
        } else {
            TtsManager.getInstance().say("摄像结束,本次摄像时长" + recordTime / 1000 + "秒");
        }
    }

    /**
     * 出发扫描 mtp下的文件,在保存文件到 sd卡下后,不能显示,故这里触发一下扫描机制,让手机连上电脑后,就可以读出文件了
     *
     * @param fName,文件的完整路径名
     */
    public void fileScan(String fName) {
        Uri data = Uri.parse("file:///" + fName);
        sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data));
        LogUtil.e("扫描完成");
    }

    public CamcorderProfile customMediaRecorder() {
        CamcorderProfile profile = null;
        if (mediarecorder != null) {
            //设置分辨率,应设置在格式和编码器设置之后
            profile = getBestCamcorderProfile();
        }
        return profile;
    }

    private
    @Nullable
    CamcorderProfile getBestCamcorderProfile() {
        int quality = CamcorderProfile.QUALITY_HIGH;
        if (videoType == 1 && CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_1080P)) {
            quality = CamcorderProfile.QUALITY_1080P;
        } else if (videoType == 2 && CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)) {
            quality = CamcorderProfile.QUALITY_720P;
        } else if (videoType == 3 && CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_480P)) {
            quality = CamcorderProfile.QUALITY_480P;
        } else {
            quality = CamcorderProfile.QUALITY_CIF;
        }
        return CamcorderProfile.get(quality);
    }

    private void stopTimer() {
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }
}

布局文件很简单:

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

    <com.lolaage.policesystem.view.SizeSurfaceView
        android:id="@+id/recorder_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />
</FrameLayout>

 

public class SizeSurfaceView extends SurfaceView {

    private boolean isUserSize = false;

    private int mVideoWidth;
    private int mVideoHeight;

    private int mMeasuredWidth;
    private int mMeasuredHeight;

    public SizeSurfaceView(Context context) {
        super(context);
    }

    public SizeSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SizeSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @SuppressLint("NewApi")
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (isUserSize) {
            doMeasure(widthMeasureSpec, heightMeasureSpec);
            setMeasuredDimension(mMeasuredWidth, mMeasuredHeight);
            setCameraDistance(0.5f);
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }

    }

    public boolean isUserSize() {
        return isUserSize;
    }

    public void setUserSize(boolean isUserSize) {
        this.isUserSize = isUserSize;
    }

    /**
     * 设置视频宽高
     * @param width
     * @param height
     */
    public void setVideoDimension(int width, int height) {
        mVideoWidth = width;
        mVideoHeight = height;
    }

    /**
     * 测量
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    private void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int width = View.getDefaultSize(mVideoWidth, widthMeasureSpec);
        int height = View.getDefaultSize(mVideoHeight, heightMeasureSpec);

        if (mVideoWidth > 0 && mVideoHeight > 0) {
            int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
            float specAspectRatio = (float) widthSpecSize / (float) heightSpecSize;
            float displayAspectRatio = (float) mVideoWidth / (float) mVideoHeight;
            boolean shouldBeWider = displayAspectRatio > specAspectRatio;

            if (shouldBeWider) {
                // not high enough, fix height
                height = heightSpecSize;
                width = (int) (height * displayAspectRatio);
            } else {
                // not wide enough, fix width
                width = widthSpecSize;
                height = (int) (width / displayAspectRatio);
            }
        }
        mMeasuredWidth = width;
        mMeasuredHeight = height;
    }
}