视频音频参数详解

742 阅读19分钟

视频参数详解

视频格式与视频编解码器

编解码格式是数据按那种方式编码压缩,便于网络传输和降低带宽的需要;文件格式是将内容按具体的编码格式压缩后,以该文件所规定的格式进行封装的结果,即容器的概念,文件播放则按容器数据的存放方式解析,提取出编码数据然后解码后交由播放设备进行播放。
原始视频通过摄像头采集进来以后很庞大,要想在互联网上进行传输就必须要进行压缩,于是就有了编解码标准,原始视频文件经过压缩以后就有了不同的格式,比如通过h.264压缩的就是.264格式,其它的同理。而我们看的电影之类的视频(AVI,MPEG,MOV)除了包含图像外还有声音,它是将视频和音频封装以后的结果。
所谓视频编码方式就是指通过特定的压缩技术,将某个视频格式的文件转换成另一种视频格式文件的方式。视频流传输中最为重要的编解码标准有国际电联的H.261、H.263、H.264,运动静止图像专家组的M-JPEG和国际标准化组织运动图像专家组的MPEG系列标准,此外在互联网上被广泛应用的还有Real-Networks的RealVideo、微软公司的WMV以及Apple公司的QuickTime等。
所谓视频格式即容器,就是把编码器生成的多媒体内容(视频,音频,字幕,章节信息等)混合封装在一起的标准。容器使得不同多媒体内容同步播放变得很简单,而容器的另一个作用就是为多媒体内容提供索引,也就是说如果没有容器存在的话一部影片你只能从一开始看到最后,不能拖动进度条(当然这种情况下有的播放器会话比较长的时间临时创建索引),而且如果你不自己去手动另外载入音频就没有声音。
视频的编码格式有h.263,h.264,mpeg-4等,视频的文件格式有AVI,MPEG,MOV等格式,h.263,h.264,mpeg-4是3种不同的编解码器。

格式是一个容器,常见bai的格du式包括AVI、MPG、WMV、MKV、TS、TP、RMVB、MOV、MP4、3GP、等等。zhi 编码是向dao这个容器放入东西的方法、例如可以zhuan横放、竖放、侧放,等等。常见的编码包括H.261、H.263、H.264、MPEG4、MPEG2、mpeg1、xvid、divx、VC-1、wmv19、realvideo810等等。 常见的AVI主要由三种编码组成xvid、divx、h264,不常见的AVI还包括很多DV拍摄的视频,由于各个厂家不一样,所使用的编码也不一样。

分辨率

影视领域的分辨率,通常表示水平方向和垂直方向的像素数,比如常见的1080P影像分辨率为1920×1080,即水平方向有1920个像素块,垂直方向有1080个像素块,他们相乘的积(像素总数)为2,073,600,也就是207万像素。

Tips:图像的“清晰程度”与多个因素相关,比如光学系统质量、传感器质量、采样率、压缩算法、色彩空间等等,像素总数是其中影响因素之一,但起不到决定作用。一些手机厂商热衷于宣传“像素”与“清晰程度”成正比,严格来说是错误的。

帧率

视频帧率(Frame rate)是用于测量显示帧数的量度。所谓的测量单位为每秒显示帧数(Frames per Second,简:FPS)或“赫兹”(Hz)。此词多用于影视制作和电子游戏。

每秒的帧数(fps)或者说帧率表示图形处理器处理场时每秒钟能够更新的次数。高的帧率可以得到更流畅、更逼真的动画。一般来说30fps就是可以接受的,但是将性能提升至60fps则可以明显提升交互感和逼真感,但是一般来说超过75fps一般就不容易察觉到有明显的流畅度提升了。如果帧率超过屏幕刷新率只会浪费图形处理的能力,因为监视器不能以这么快的速度更新,这样超过刷新率的帧率就浪费掉了。

像素长宽比

一个像素块的长度与宽度之比。 上图像素长宽比为x/y=0.5,当今主流视频像素长宽比为1,也就是一个像素块为正方形。有些NTSC/PAL的片源的长宽比不为1,还有一些低端摄像机,它们的感光元件为4:3,要拍摄16:9的影片,但又不舍得裁剪,会采用改变像素长宽比的方式。

位深

常见的位深有8-bit,16-bit,32-bit等,如8bit,即8位2进制所代表的 28=256个变化,在影视领域则代表每个像素的每个通道有256级灰度,RGB三通道则有 2563=16,777,216种色彩。

Nuke工作在32-bit浮点线性空间,合成中的32位指每个通道占有32-bit( 32位可能还有另一个解释,即RGBA每通道占用8-bit,四通道一共32-bit,此解释在合成领域不适用),每通道有232=4,294,967,296的灰度级,RGB三通道可表示有232·232·232=7.923 x 1028种色彩。

位深影响的主要是影像的色彩细腻程度,8-bit因为占用空间较小,并且也能够较好地表现色彩,所以广泛应用于网络视频图片及广播电视领域。

10-bit一般用于数字电影放映,16-bit及以上用于调色、合成等后期制作。

码率

比特率,英文为 bit rate,描述每秒钟输出多少 KB 的参数,单位是 Kbps,也就是 kbit/s,8Kbit/s = 1KB/s。也就是说800Kbps意思就是每秒视频就要占用100KB磁盘空间 规范写法是800Kbps,也就是800Kbit/s
由于保存完整的一帧一帧图片的视频原文件太大,必须要通过某种视频压缩算法将视频中的图片压缩,以减小视频文件大小,那么读者应该可以想到,压缩比越大,解压缩还原后用来播放的视频就会有越严重的失真,因为压缩的同时不可避免的丢失了视频中原来图像的数据信息。
在理解这个的前提下,我来举个例子,一个分辨率为1080P的原视频(未经压缩)被压缩成分别为4GB 和 1GB的两个视频文件。由于1GB的视频的压缩比更大,所以在观看1GB视频的明显感觉到没有4GB视频清晰(虽然他们的分辨率都是1080P)。
码率的英文名为bps(bit per second),就是用平均每秒多少bit来衡量一个视频大小。 比如那个被压缩的1080P的视频,假设它的长度为100分钟,大小为1GB。 100M=100X60S=6000s 1GB=1024MB= 1024X1024KB=1024X1024X1024Byte=1024X1024X1024X8bit=8589934592bit 那么这个视频的码率大概就是1.4Mbit/s(8589934592/6000),这个比特率在在线视频中已经是非常高的了,一般主流视频平台的最高码率在1Mbit左右,比如直播网站斗鱼的高清选项实际播放的视频码率是900Kbit/s(0.9Mbit)。

码率控制对于在线视频比较重要。因为在线视频需要考虑其能提供的带宽。 那么,什么是码率?很简单: bitrate = file size / duration 比如一个文件20.8M,时长1分钟,那么,码率就是: biterate = 20.8M bit/60s = 20.8102410248 bit/60s= 2831Kbps 一般音频的码率只有固定几种,比如是128Kbps, 那么,video的就是 video biterate = 2831Kbps -128Kbps = 2703Kbps。 码率可以用来估算文件的大小,大小约等于码率时长/8

清晰度

在码率一定的情况下,分辨率与清晰度成反比关系:分辨率越高,图像越不清晰,分辨率越低,图像越清晰。 在分辨率一定的情况下,码率与清晰度成正比关系,码率越高,图像越清晰;码率越低,图像越不清晰。

音频参数详解

音频

指人耳可以听到的声音频率在20Hz~20kHz之间的声波。 如果在计算机加上相应的音频卡—就是我们经常说的声卡,我们可以把所有的声音录制下来,声音的声学特性如音的高低等都可以用计算机硬盘文件的方式储存下来。反过来,我们也可以把储存下来的音频文件用一定的音频程序播放,还原以前录下的声音。

一、采样频率

指每秒钟取得声音样本的次数。声音其实是一种能量波,因此也有频率和振幅的特征,频率对应于时间轴线,振幅对应于电平轴线。波是无限光滑的,弦线可以看成由无数点组成,由于存储空间是相对有限的,数字编码过程中,必须对弦线的点进行采样。
采样的过程就是抽取某点的频率值,很显然,在一秒中内抽取的点越多,获取得频率信息更丰富,为了复原波形,采样频率越高,声音的质量也就越好,声音的还原也就越真实,但同时它占的资源比较多。由于人耳的分辨率很有限,太高的频率并不能分辨出来。22050 的采样频率是常用的,44100已是CD音质,超过48000或96000的采样对人耳已经没有意义。这和电影的每秒24帧图片的道理差不多。如果是双声道(stereo),采样就是双份的,文件也差不多要大一倍。
根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右。这个定理怎么得来,我们不需要知道,只需知道这个定理告诉我们,如果我们要精确的记录一个信号,我们的采样频率必须大于等于音频信号的最大频率的两倍,记住,是最大频率。
在数字音频领域,常用的采样率有: 8000 Hz - 电话所用采样率, 对于人的说话已经足够 11025 Hz - 电话所用采样率 22050 Hz - 无线电广播所用采样率 32000 Hz - miniDV 数码视频 camcorder、DAT (LP mode)所用采样率 44100 Hz - 音频 CD, 也常用于 MPEG-1 音频(VCD, SVCD,MP3)所用采样率 47250 Hz - 商用 PCM 录音机所用采样率 48000 Hz - miniDV、数字电视、DVD、DAT、电影和专业音频所用的数字声音所用采样率 50000 Hz - 商用数字录音机所用采样率 96000 Hz或者 192000 Hz - DVD-Audio、一些 LPCM DVD 音轨、BD-ROM(蓝光盘)音轨、和 HD-DVD (高清晰度 DVD)音轨所用所用采样率

二、采样位数

采样位数也叫采样大小或量化位数。它是用来衡量声音波动变化的一个参数,也就是声卡的分辨率或可以理解为声卡处理声音的解析度。它的数值越大,分辨率也就越高,录制和回放的声音就越真实。而声卡的位是指声卡在采集和播放声音文件时所使用数字声音信号的二进制位数,声卡的位客观地反映了数字声音信号对输入声音信号描述的准确程度。常见的声卡主要有8位和16位两种,如今市面上所有的主流产品都是16位及以上的声卡。
每个采样数据记录的是振幅, 采样精度取决于采样位数的大小: 1 字节(也就是8bit) 只能记录 256 个数, 也就是只能将振幅划分成 256 个等级; 2 字节(也就是16bit) 可以细到 65536 个数, 这已是 CD 标准了; 4 字节(也就是32bit) 能把振幅细分到 4294967296 个等级, 实在是没必要了.

三、通道数

即声音的通道的数目。常见的单声道和立体声(双声道),现在发展到了四声环绕(四声道)和5.1声道。

1.单身道

单声道是比较原始的声音复制形式,早期的声卡采用的比较普遍。单声道的声音只能使用一个扬声器发声,有的也处理成两个扬声器输出同一个声道的声音,当通过两个扬声器回放单声道信息的时候,我们可以明显感觉到声音是从两个音箱中间传递到我们耳朵里的,无法判断声源的具体位置。

2.立体声

双声道就是有两个声音通道,其原理是人们听到声音时可以根据左耳和右耳对声音相位差来判断声源的具体位置。声音在录制过程中被分配到两个独立的声道,从而达到了很好的声音定位效果。这种技术在音乐欣赏中显得尤为有用,听众可以清晰地分辨出各种乐器来自的方向,从而使音乐更富想象力,更加接近于临场感受。双声目前最常用途与两个,在卡拉OK中,一个是奏乐,一个是歌手的声音;在VCD中,一个是普通话配音,一个是粤语配音。

3.四声环绕

四声道环绕规定了前左、前右,后左、后右四个发声点,听众则被包围在这中间。同时还建议增加一个低音音箱,以加强对低频信号的回放处理(这也就是如今4.1声道音箱系统广泛流行的原因)。就整体效果而言,四声道系统可以为听众带来来自多个不同方向的声音环绕,可以获得身临各种不同环境的听觉感受,给用户以全新的体验。如今四声道技术已经广泛融入于各类中高档声卡的设计中,成为未来发展的主流趋势。

4.5.1声道

5.1声道已广泛运用于各类传统影院和家庭影院中,一些比较知名的声音录制压缩格式,譬如杜比AC-3(Dolby Digital)、DTS等都是以5.1声音系统为技术蓝本的,其中“.1”声道,则是一个专门设计的超低音声道,这一声道可以产生频响范围20~120Hz的超低音。其实5.1声音系统来源于4.1环绕,不同之处在于它增加了一个中置单元。这个中置单元负责传送低于80Hz的声音信号,在欣赏影片时有利于加强人声,把对话集中在整个声场的中部,以增加整体效果。 目前很多在线音乐播放器,比如说QQ音乐,已经提供5.1声道音乐试听和下载。

四、帧

音频的帧的概念没有视频帧那么清晰,几乎所有视频编码格式都可以简单的认为一帧就是编码后的一副图像。但音频帧跟编码格式相关,它是各个编码标准自己实现的。因为如果以PCM(未经编码的音频数据)来说,它根本就不需要帧的概念,根据采样率和采样精度就可以播放了。比如采样率为44.1kHZ,采样精度为16位的双音频,你可以算出比特率是44100162bps,每秒的音频数据是固定的44100162/8 字节。
amr帧比较简单,它规定每20ms的音频是一帧,每一帧音频都是独立的,有可能采用不同的编码算法以及不同的编码参数。 mp3帧较为复杂一点,包含了更多的信息,比如采样率,比特率,等各种参数。

五、周期

音频设备一次处理所需要的帧数,对于音频设备的数据访问以及音频数据的存储,都是以此为单位。

六、交错模式

数字音频信号存储的方式。数据以连续帧的方式存放,即首先记录帧1的左声道样本和右声道样本,再开始帧2的记录。

七、非交错模式

首先记录的是一个周期内所有帧的左声道样本,再记录所有右声道样本。

八、比特率

比特率也叫码率,指音乐每秒播放的数据量,单位用bit表示,也就是二进制位。 bps就是比特率。b就是比特(bit),s就是秒(second),p就是每(per),一个字节相当于8个二进制位。也就是说128bps的4分钟的歌曲的文件大小是这样计算的(128/8)460=3840kB=3.8MB,1B(Byte)=8b(bit),一般mp3在128比特率左右为益,也大概在3-4 BM左右的大小。
在计算机应用中,能够达到最高保真水平的就是PCM编码,被广泛用于素材保存及音乐欣赏,CD、DVD以及我们常见的 WAV文件中均有应用。因此,PCM约定俗成了无损编码,因为PCM代表了数字音频中最佳的保真水准,并不意味着PCM就能够确保信号绝对保真,PCM也只能做到最大程度的无限接近。
要算一个PCM音频流的码率是一件很轻松的事情,采样率值×采样大小值×声道数 bps。一个采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的WAV文件,它的数据速率则为 44.1K×16×2 =1411.2Kbps。我们常见的Audio CD就采用了PCM编码,一张光盘的容量只能容纳72分钟的音乐信息。
双声道的PCM编码的音频信号,1秒钟需要176.4KB的空间,1分钟则约为10.34M,这对大部分用户是不可接受的,尤其是喜欢在电脑上听音乐的朋友,要降低磁盘占用,只有2种方法,降低采样指标或者压缩。降低采样指标是不可取的,因此专家们研发了各种压缩方案。最原始的有DPCM、ADPCM,其中最出名的为MP3。所以,采用了数据压缩以后的码率远小于原始码。

android 中自定义相机

1. 打开相机

打开相机需要传入一个 cameraId,旧的 API 中只有 CAMERA_FACING_BACKCAMERA_FACING_FRONT 两个值可以选择,返回一个 Camera 对象。
    public void openCamera() {
        mCamera = Camera.open(mCameraId); // 打开相机
        Camera.getCameraInfo(mCameraId, mCameraInfo); // 获取相机信息
        initConfig(); // 初始化相机配置
        setDisplayOrientation(); // 设置相机显示方向
    }

2. 初始化相机配置

在Camera API 中,相机的配置都是通过 Parameters 类完成。我们可以设置 闪光模式、聚焦模式、曝光强度、预览图片格式和大小、拍照图片格式和大小 等等信息。

    private void initConfig() {
        try {
            mParameters = mCamera.getParameters();
            // 如果摄像头不支持这些参数都会出错的,所以设置的时候一定要判断是否支持
            List<String> supportedFlashModes = mParameters.getSupportedFlashModes();
            if (supportedFlashModes != null && supportedFlashModes.contains(Parameters.FLASH_MODE_OFF)) {
                mParameters.setFlashMode(Parameters.FLASH_MODE_OFF); // 设置闪光模式(关闭)
            }
            List<String> supportedFocusModes = mParameters.getSupportedFocusModes();
            if (supportedFocusModes != null && supportedFocusModes.contains(Parameters.FOCUS_MODE_AUTO)) {
                mParameters.setFocusMode(Parameters.FOCUS_MODE_AUTO); // 设置聚焦模式(自动)
            }
            mParameters.setPreviewFormat(ImageFormat.NV21); // 设置预览图片格式
            mParameters.setPictureFormat(ImageFormat.JPEG); // 设置拍照图片格式
            mParameters.setExposureCompensation(0); // 设置曝光强度
            Size previewSize = getSuitableSize(mParameters.getSupportedPreviewSizes());
            mPreviewWidth = previewSize.width;
            mPreviewHeight = previewSize.height;
            mParameters.setPreviewSize(mPreviewWidth, mPreviewHeight); // 设置预览图片大小
            Log.d(TAG, "previewWidth: " + mPreviewWidth + ", previewHeight: " + mPreviewHeight);
            Size pictureSize = getSuitableSize(mParameters.getSupportedPictureSizes());
            mParameters.setPictureSize(pictureSize.width, pictureSize.height);
            Log.d(TAG, "pictureWidth: " + pictureSize.width + ", pictureHeight: " + pictureSize.height);
            mCamera.setParameters(mParameters); // 将设置好的parameters添加到相机里
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

3. 设置相机预览时的显示方向

这个方法很重要,关乎着你预览画面是否正常。其实相机底层的预览画面全都是宽度大于高度的,但是竖屏时画面要显示正常,都是通过这个方法设置了一定的显示方向。
    private void setDisplayOrientation() {
        int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            case Surface.ROTATION_270:
                degrees = 270;
                break;
        }
        int result;
        if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (mCameraInfo.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (mCameraInfo.orientation - degrees + 360) % 360;
        }
        mCamera.setDisplayOrientation(result);
    }


4. 开始预览、停止预览

可以通过 SurfaceView 的 getHolder 方法获取一个 SurfaceHolder,设置给 Camera 系统即可帮你完成一系列复杂的绑定。
        public void startPreview(SurfaceHolder holder) {
        if (mCamera != null) {
            try {
                mCamera.setPreviewDisplay(holder); // 先绑定显示的画面
            } catch (IOException e) {
                e.printStackTrace();
            }
            mCamera.startPreview(); // 这里才是开始预览
        }
    }

    public void stopPreview() {
        if (mCamera != null) {
            mCamera.stopPreview(); // 停止预览
        }
    }


5.拍照代码

 public void takePicture(final TakePictureCallback callback) {
        if (mCamera == null) {
            return;
        }
        switch (cameraAngle) {
            case 90:
                nowAngle = Math.abs(angle + cameraAngle) % 360;
                break;
            case 270:
                nowAngle = Math.abs(cameraAngle - angle);
                break;
        }
//
        Log.i("CJT", angle + " = " + cameraAngle + " = " + nowAngle);
        mCamera.takePicture(null, null, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
                Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                Matrix matrix = new Matrix();
                if (SELECTED_CAMERA == CAMERA_POST_POSITION) {
                    matrix.setRotate(nowAngle);
                } else if (SELECTED_CAMERA == CAMERA_FRONT_POSITION) {
                    matrix.setRotate(360 - nowAngle);
                    matrix.postScale(-1, 1);
                }

                bitmap = createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
                if (callback != null) {
                    if (nowAngle == 90 || nowAngle == 270) {
                        callback.captureResult(bitmap, true);
                    } else {
                        callback.captureResult(bitmap, false);
                    }
                }
            }
        });
    }

6.视频录制

 public void startRecord(Surface surface, float screenProp, ErrorCallback callback) {
        mCamera.setPreviewCallback(null);
        final int nowAngle = (angle + 90) % 360;
        //获取第一帧图片
        Camera.Parameters parameters = mCamera.getParameters();
        int width = parameters.getPreviewSize().width;
        int height = parameters.getPreviewSize().height;
        YuvImage yuv = new YuvImage(firstFrame_data, parameters.getPreviewFormat(), width, height, null);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        yuv.compressToJpeg(new Rect(0, 0, width, height), 50, out);
        byte[] bytes = out.toByteArray();
        videoFirstFrame = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        Matrix matrix = new Matrix();
        if (SELECTED_CAMERA == CAMERA_POST_POSITION) {
            matrix.setRotate(nowAngle);
        } else if (SELECTED_CAMERA == CAMERA_FRONT_POSITION) {
            matrix.setRotate(270);
        }
        videoFirstFrame = createBitmap(videoFirstFrame, 0, 0, videoFirstFrame.getWidth(), videoFirstFrame
                .getHeight(), matrix, true);

        if (isRecorder) {
            return;
        }
        if (mCamera == null) {
            openCamera(SELECTED_CAMERA);
        }
        if (mediaRecorder == null) {
            mediaRecorder = new MediaRecorder();
        }
        if (mParams == null) {
            mParams = mCamera.getParameters();
        }
        List<String> focusModes = mParams.getSupportedFocusModes();
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
            mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        }
        mCamera.setParameters(mParams);
        mCamera.unlock();
        mediaRecorder.reset();
        mediaRecorder.setCamera(mCamera);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);


        Camera.Size videoSize;
        if (mParams.getSupportedVideoSizes() == null) { // 支持的分辨率
            videoSize = CameraParamUtil.getInstance().getPreviewSize(mParams.getSupportedPreviewSizes(), 1200,
                    screenProp);
        } else {
            videoSize = CameraParamUtil.getInstance().getPreviewSize(mParams.getSupportedVideoSizes(), 1200,
                    screenProp);
        }

        Log.i(TAG, "setVideoSize    width = " + videoSize.width + "\theight = " + videoSize.height);
        if (videoSize.width == videoSize.height) {
            mediaRecorder.setVideoSize(preview_width, preview_height);
        } else {
            mediaRecorder.setVideoSize(videoSize.width, videoSize.height);
        }
//        if (SELECTED_CAMERA == CAMERA_FRONT_POSITION) {
//            mediaRecorder.setOrientationHint(270);
//        } else {
//            mediaRecorder.setOrientationHint(nowAngle);
////            mediaRecorder.setOrientationHint(90);
//        }

        if (SELECTED_CAMERA == CAMERA_FRONT_POSITION) {
            //手机预览倒立的处理
            if (cameraAngle == 270) {
                //横屏
                if (nowAngle == 0) {
                    mediaRecorder.setOrientationHint(180);
                } else if (nowAngle == 270) {
                    mediaRecorder.setOrientationHint(270);
                } else {
                    mediaRecorder.setOrientationHint(90);
                }
            } else {
                if (nowAngle == 90) {
                    mediaRecorder.setOrientationHint(270);
                } else if (nowAngle == 270) {
                    mediaRecorder.setOrientationHint(90);
                } else {
                    mediaRecorder.setOrientationHint(nowAngle);
                }
            }
        } else {
            mediaRecorder.setOrientationHint(nowAngle);
        }


        if (DeviceUtil.isHuaWeiRongyao()) {
            mediaRecorder.setVideoEncodingBitRate(3 * 1024 * 1024);
        } else {
            mediaRecorder.setVideoEncodingBitRate(mediaQuality);
        }
        mediaRecorder.setPreviewDisplay(surface);

        videoFileName = "video_" + System.currentTimeMillis() + ".mp4";
        if (saveVideoPath.equals("")) {
            saveVideoPath = Environment.getExternalStorageDirectory().getPath();
        }
        videoFileAbsPath = saveVideoPath + File.separator + videoFileName;
        mediaRecorder.setOutputFile(videoFileAbsPath);
        try {
            mediaRecorder.prepare();
            mediaRecorder.start();
            isRecorder = true;
        } catch (IllegalStateException e) {
            e.printStackTrace();
            Log.i("CJT", "startRecord IllegalStateException");
            if (this.errorLisenter != null) {
                this.errorLisenter.onError();
            }
        } catch (IOException e) {
            e.printStackTrace();
            Log.i("CJT", "startRecord IOException");
            if (this.errorLisenter != null) {
                this.errorLisenter.onError();
            }
        } catch (RuntimeException e) {
            Log.i("CJT", "startRecord RuntimeException");
        }
    }


6. 释放相机

  相机是很耗费系统资源的东西,用完一定要释放。对应于 openCamera 。
  
 public void releaseCamera() {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }