Android音视频开发(一)之基础知识

一、视频录制

视频录制有两种方式:

  1. 调用系统相机录制
    在Android中调用系统相机,通过Intent设置系统相机的Action,然后startActivity就可以启动。但这种方式在实际开发中通常不能很好满足业务需要,比如我要指定一下录制视频的码率、分辨率、预览画面的大小和视频画面的尺寸等。

  2. 自定义相机录制

    自定义相机开发过程相对复杂,使用Android SDK提供的Camera和Mediarecorder类来完成,单纯使用Mediarecorder也能直接进行录制,但通常是前置方式来实现。相机相关的API,Google已经出过几种了,Camera类已经废弃了,在高Android系统版本中不建议使用,目前最新的是Camera2和jetpack架构支持的CameraX。

二、预览和录制方向

2.1 传感器方向

对于手机摄像头来说,器传感器有个天然的画面捕获方向,获取的预览画面帧或捕获的照片视频方向是固定的。传感器方向后置相机默认90,前置相机默认270。

以后置相机为例,其传感器坐标系示意图2-1如下
Android音视频开发(一)之基础知识_第1张图片
而屏幕坐标系,众所周知如图2-2
Android音视频开发(一)之基础知识_第2张图片

那么,打开相机预览画面或进行拍照、录制的时候,必然涉及到一个方向的转换,否则会导致获取的照片视频方向是颠倒的。

1)后置相机

还是以后置相机为例,如果竖屏拍摄的话,那么最终呈现在屏幕上的效果如图2-3所示。
Android音视频开发(一)之基础知识_第3张图片

可以发现,图像时横放的,所以在预览和拍照录像时,需要对其方向做相应设置,旋转90,确保预览和拍摄录制时,所见即所得。而在横屏预览(自然方向270°)的情况下,由于传感器方向和屏幕坐标系重合,所以无需特殊处理。图2-4

Android音视频开发(一)之基础知识_第4张图片

2)前置相机
同理,对于前置相机来说,也会存在画面的颠倒,但同时由于前置相机的画面是镜像的(镜面对称),所以在旋转时,注意旋转角度的计算。图2-5
Android音视频开发(一)之基础知识_第5张图片

2.2 自然方向

自然方向就是指手机是竖向还是横向,自然方向只有4种,分别是0,90,180,270。图2-6
Android音视频开发(一)之基础知识_第6张图片

2.3 预览方向

当打开相机后就可以开始进行预览,如果手机自然方向为0(即以自拍方式握持手机),而且使用的后置相机,在没有任何方向设置情况下,会发现图像横置。这是因为预览画面是展示的传感器捕获的图片帧,而传感器捕获方向是横向,预览画面也就是横向了。图2-7

Android音视频开发(一)之基础知识_第7张图片

所以需要进行方向变换,Android SDK的Camera类提供了setDisplayOrientation方法来设置预览方向,根据当前手机自然方向和使用的前后置相机来进行画面旋转角度计算。

前置相机的传感器方向是270,所以我们需要旋转270度才能在竖屏预览时保证画面也是竖向,但是前置相机是镜面对称成像,其实最终也只需要旋转90度即可,示意图如下。图2-8

Android音视频开发(一)之基础知识_第8张图片

综上,在竖屏预览的情况下,对于前置和后置相机来说直接旋转90度即可。

Google给出了计算预览画面旋转角度的示例方法。

private void setCameraDisplayOrientation(int cameraId) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);
        int deviceOrientation = this.getWindowManager().getDefaultDisplay().getRotation();
        int degree = 0;

        switch (deviceOrientation) {
            case Surface.ROTATION_0:
                degree = 0;
                break;
            case Surface.ROTATION_90:
                degree = 90;
                break;
            case Surface.ROTATION_180:
                degree = 180;
                break;
            case Surface.ROTATION_270:
                degree = 270;
                break;
        }
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
            mDisplayOrientation = (info.orientation + degree) % 360;
            mDisplayOrientation = (360 - mDisplayOrientation) % 360;
        }else {
            mDisplayOrientation = (info.orientation - degree + 360) % 360;
        }
        if (mCamera != null){
            mCamera.setDisplayOrientation(mDisplayOrientation);
        }
    }

2.4 拍照和录制方向

使用Camera API进行拍照和录像是时,最终保存的图像或视频是直接由相机传感器采集然后存储到手机,所以为了保证在打开时图片或视频是预览时展现的方向,需要在保存时对图片或视频进行旋转。在旋转视频时Android Camera提供了setOrientationHint方法。

注意:该方法并不是将每帧画面进行旋转,而是在生成的视频文件头部添加一个旋转参数。视频播放器根据这个参数来旋转播放,有的播放器可能会忽略该参数(例如Windows media player),所以该方法不能完全保证播放时画面方向正确。下图是通过ffpmeg查看视频文件获取的参数信息。
Android音视频开发(一)之基础知识_第9张图片
拍照时,通过需要旋转的角度,使用一个旋转矩阵,去调整图片方向。

2.4.1 录像方向

相机 自然方向 预览方向 旋转角度计算 旋转角度
后置相机 0 0 此时,只用考虑传感器方向,只用旋转90度(见图2-1),即可保证录制的视频内容和预览画面一致 90
后置 90 0 在横屏情况下,通过注册传感器方向监听来判断自然方向是90还是270。对于自然方向90°的情况,需要旋转180°。 180
后置 180 0 需要旋转270° 270
后置 270 0 这种情况,传感器方向和画面预览方向重合,无需旋转或旋转0° 0

2.4.2 拍照方向

只要确定了照片需要旋转的角度,通过一个旋转矩阵对拍照获取的照片进行旋转。照片旋转角度可以通过前文去判断。

......		
  public Bitmap rotatePicture(Bitmap bitmap, int degree){
  	......
		// 根据旋转角度,生成旋转矩阵
    Matrix matrix = new Matrix();
    matrix.postRotate(degree);
    // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
    mBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
  	......
    return mBitmap
}
......

旋转矩阵方式耗时比较长,图片较大时不适用。这时可以通过ExifInterface对其旋转。简单介绍一下Exif(Exchangeable image file format 可交换图像文件),是附加在图片文件中的,记录数码照片的属性信息和拍摄数据的信息,包括分辨率、光圈、曝光补偿、闪光灯等等信息。ExifInterface就是Android提供的读写图片文件exif信息的API。

...... 
	ExifInterface exifInterface = new ExifInterface(path);
  // 修正图片的旋转角度,设置其不旋转。这里也可以设置其旋转的角度,可以传值过去,
 // 例如旋转90度,传值ExifInterface.ORIENTATION_ROTATE_90,需要将这个值转换为String类型的
 exifInterface.setAttribute(ExifInterface.TAG_ORIENTATION, String.valueOf(degreee))
 exifInterface.saveAttributes();
......

注意:这种方法一定要在保存完图片之后再使用,否则不会生效。

三、预览画面尺寸

在开启相机进行预览时,要提前设置一些参数(Camera.Parameters),其中就包括了预览画面的尺寸参数(宽高)。调用setPreviewSize(width, height)设置预览画面宽高时,一定不能随意指定,如果手机不支持会报错并且应用崩溃。一般是要去获取手机支持的预览尺寸。Camera.Parameters提供了getSupportedPreviewSizes方法用以获取系统支持的预览画面尺寸,开发时可以设置一个预期的画面宽度,然后设置一个宽高比。如果系统支持所设定的尺寸则可以直接使用,如果没有支持,则选择最接近的尺寸来预览。例如,华为P10 Plus支持的预览尺寸如下。

2020-08-01 15:11:36.023 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 1920, height = 1080
2020-08-01 15:11:36.023 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 1440, height = 1080
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 1536, height = 864
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 1280, height = 960
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 1280, height = 720
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 960, height = 720
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 960, height = 540
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 720, height = 720
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 720, height = 540
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 640, height = 480
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 640, height = 360
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 736, height = 412
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 544, height = 408
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 480, height = 360
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 400, height = 400
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 352, height = 288
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 320, height = 240
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 208, height = 144
2020-08-01 15:11:36.024 18021-18021/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 176, height = 144

注意,这里宽度比高度数值大,是因为是计算的手机横向时的宽高比。比例选择一般可以参考使用4:3和16:9等。

四、照片尺寸和视频分辨率

对于最后获取的照片和视频尺寸也需要设置尺寸大小,同样对于视频尺寸,也需要设置视频文件大小,实测华为P10 Plus支持的预览尺寸如下。

2020-08-01 15:20:17.586 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 3840, height = 2160
2020-08-01 15:20:17.586 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 3264, height = 1840
2020-08-01 15:20:17.586 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 2592, height = 1952
2020-08-01 15:20:17.586 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 2048, height = 1536
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 1920, height = 1080
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 1440, height = 1080
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 1536, height = 864
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 1280, height = 960
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 1280, height = 720
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 960, height = 720
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 960, height = 540
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 720, height = 720
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 720, height = 540
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 640, height = 480
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 640, height = 360
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 736, height = 412
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 544, height = 408
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 480, height = 360
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 400, height = 400
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 352, height = 288
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 320, height = 240
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 208, height = 144
2020-08-01 15:20:17.587 22124-22124/com.sankuai.meituan.dispatch.crowdsource D/xxx: width = 176, height = 144

五、总结

本文主要是介绍了音视频开发的一些基础先导知识,在进行预览、拍照、录制等功能开发时所必要的基本概念。主要介绍了

  • 视频录制的主要方式,调用系统相机或自定义相机

  • 重点说明了在自定义相机开发中的所涉及的各种「方向」的概念,包括预览画面方向、照片方向和视频方向,对前后置相机传感器方向坐标进行了讲解,不同的手机自然方向和前后置相机类型需要计算对应的旋转角度并进行旋转处理。

  • 介绍了预览画面尺寸和视频储存的尺寸,需要从系统支持的分辨率尺寸中获取,而不能任意指定。

参考资料

Camera 开发实战(一)——预览尺寸的选取与旋转角度的设定
Android Camera-相机尺寸、方向和图像数据
Android 拍摄 录制

你可能感兴趣的:(Android技术文章,android)