相机说明文档2.0

简介

这个是ZYCamera项目的说明文档,gitee地址
目的是 帮助用户快速理清ZYCamera的实现逻辑,能够快速去修改工程。
这里只会介绍整体的架构和运行流程。

功能介绍

ZYCamera是一个相机SDK ,主要有预览,拍照,录像3大核心功能。
在这里插入图片描述

用到的知识点

ZYCamera涉及到的知识点主要也分3大块:
在这里插入图片描述
说明:

  1. OpenGL相关 :处理相机输出的画面(如添加滤镜效果,添加美容效果) 然后进行显示。
  2. 相机相关 :产生预览画面和拍照。
  3. 编码相关:将预览画面 编码混合成MP4格式视频。

ZYCamera工程结构

根据需要功能设计的结构如下,主要有3个Module。

  • CameraY_camera :所有相机功能的实现代码。属于Model层。
  • CameraY : 逻辑层代码。依赖相机和渲染框架,根据需求进行逻辑处理。
  • CameraY_Demo : 测试Module。对单独功能的测试。
    在这里插入图片描述

CameraY_camera说明

整体结构如下:
在这里插入图片描述
代码总体分为3部分:

  1. 对外接口—Camera与ICamera。
  2. 参数对象—在包parameter 下,参数按不同功能创建。
  3. 功能实现—在包Core下,包含相机、录像。
对外接口
public interface ICamera {
    /**开始预览*/
    void startPreview();
    /**结束预览*/
    void stopPreview();
    /**关闭相机 释放资源*/
    void closeCamera();
    /**获取 相机相关参数*/
    IParameter<?> getParameterCamera(@CameraParameter.Type int parameter);
    /**获取 设备相关参数*/

    IParameter<?> getParameterDevice(@DeviceParameter.Type int parameter);
    /**获取 预览相关参数*/

    IParameter<?> getParameterPreview(@PreviewParameter.Type int parameter);
    /**获取 拍照相关参数*/

    IParameter<?> getParameterPhoto(@PhotoParameter.Type int parameter);
    /**获取 录像相关参数*/

    IParameter<?> getParameterRecord(@RecordParameter.Type int parameter);
    /**获取 特殊模式相关参数*/

    IParameter<?> getParameterSpecialty(@SpecialtyParameter.Type int parameter);
}

目前只有一个实现类Camera

public class Camera implements ICamera {
    /**
     * 控制相机的接口
     */
    private ICameraUser mCameraUser;
    /**
     * 和相机相关的参数
     */
    private final CameraParameter mCameraParameter;

    public Camera(Context context) {
        mCameraParameter = new CameraParameter(context);
        // 省略
    }
    // 省略
    private void openCameraApi(int api, Context context) {
        Zy.d("open Camera Api =" + api);
        switch (api) {
            case CAMERA_2:
                mCameraUser = new Camera2Proxy(context, mCameraParameter);
                break;
            case CAMERA_1:
            default:
                mCameraUser = new Camera1Proxy(mCameraParameter);
                break;
        }
    }
    // 省略
}

起到一个逻辑层作用,内部会创建CameraParameter对象,然后根据需要创建ICameraUser相机的实现类 Camera2Proxy或Camera1Proxy ,并将CameraParameter对象传入。这样用户与相机持有同一个CameraParameter对象 就可以进行相互通信。
在这里插入图片描述

参数对象

在这里插入图片描述
IParameter接口,定义了每个参数共有方法。

public interface IParameter<T> {
    /**设置*/
    void set(T t);
    /**获取*/
    T get();
    /**设置最大和最小值*/
    void setMinMax(T min, T max);
    /**获取最大值*/
    T getMax();
    /**获取最小值*/
    T getMin();
    /**刷新一次回调*/
    void updateT();
    /**参数销毁,清除回调*/
    void destroy();
    /**添加监听*/
    void addObserver(IObserver<T> observer);
    /**移除监听*/
    void removeObserver(IObserver<T> observer);
    /** 回调 接口*/
    interface IObserver<T> {
        /**
         * 参数更新
         * @param t 参数值
         * @param status 参数状态(可用,开关)
         */
        void update(T t, int status);
    }
}

一个抽象类BaseParameter。

public abstract class BaseParameter<T> implements IParameter<T> {
    /** 参数 是否支持 默认支持*/
    public static final byte SUPPORT = 1;
    /** 参数 是否使用 默认打开*/
    public static final byte TRIGGER = 2;
    /** 当前值,最大值,最小值---要注意最小值是负数的情况 */
    protected T mT, mMinT, mMaxT;
    /** 回调集合,使用CopyOnWriteArrayList*/
    protected List<IObserver<T>> mTtList = new CopyOnWriteArrayList<>();
    /** 控制
     * 第一位表示 此参数是否 支持,
     * 第二位表示 此参数是否 生效
    */
    protected byte mStatus = SUPPORT | TRIGGER ;

    /**构造函数不给 客户端调用*/
    @RestrictTo(RestrictTo.Scope.LIBRARY)
    public BaseParameter() {
    }

    public void setSupport(boolean support) {
        setBit(support,SUPPORT);
    }
    public void setTrigger(boolean trigger) {
        setBit(trigger,TRIGGER);
        updateT();
    }
    //省略
}

根据不同功能和需要,定义了许多不同的参数。
比如CameraApi 控制相机的实现API是Camera1 或是 Camera2。 PreviewFlash 控制闪光灯 等等, 每个参数对象都有类注释 说明作用。有需要可以继承BaseParameter增加需要的参数。

/**
* @author zhangxi
* @company 桂林智神信息技术有限公司
* @date 2020/10/12 2:09 PM
* @description 闪光灯--0关闭 1打开 2自动 3常亮
*/
public class PreviewFlash extends BaseParameter<PreviewFlash.FlashType> {
    
    public enum FlashType{
        /**闪光灯关闭*/
         FLASH_OFF (0),
        /**闪光灯打开*/
         FLASH_ON (1),
        /**闪光灯自动*/
         FLASH_AUTO (2),
        /**闪光灯常亮*/
         FLASH_TORCH (3);
         public int value;
        FlashType(int value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return "FlashType{ name=" + name()+
                    ", value=" +value+
                    '}';
        }
    }
    /** 当前模式下支持的闪光灯列表 */
    private final List<FlashType> mSupportList;

    @RestrictTo(RestrictTo.Scope.LIBRARY)
    public PreviewFlash() {
        mT= FlashType.FLASH_OFF;
        mMinT= mT;
        mMaxT= mT;
        mSupportList = new ArrayList<>();
    }
    // 省略
}
功能实现

相机功能
接口ICameraUser:

public interface ICameraUser {
    /**
     * 开始预览
     */
    void startPreview();

    /**
     * 停止预览
     */
    void stopPreview();

    /**
     * 销毁
     */
    void destroy();

    /**
    * 获取所有的参数
    *
    * @param parameter 参数定义的常量
    * @return 参数
    */
    IParameter<?> getParameterAll(int parameter);
}

目前有3个实现类型可选择:

  • 使用系统Camera1 api实现的 Camera1Proxy。
  • 使用系统Camera2 api实现的 Camera2Proxy。
  • 使用华为 Api实现的 HuaweiProxy。

以后用户可以自行扩展。现在主要介绍Camera2的实现,其他2个实现整体流程也类似,只是在具体的某些功能实现上有所区别。

Camera2Proxy

public class Camera2Proxy implements ICameraUser {

    private ICamera2Core mCameraCore;
    private final CameraParameter mCameraParameter;

    public Camera2Proxy(Context context, CameraParameter cameraParameter) {
        mCameraParameter = cameraParameter;
        openCameraMode(mCameraParameter.getCameraMode().get(), context);
        mCameraParameter.getCameraMode().addObserver((integer, status) -> {
            Zy.d("Camera2 mode change=" + integer);
            destroy();
            openCameraMode(integer,context);
            startPreview();
        });
    }
    // 省略
    @Override
    public void startPreview() {
        if (mCameraCore != null) {
            mCameraCore.startPreview();
        }
    }

    @Override
    public void stopPreview() {
        if (mCameraCore != null) {
            mCameraCore.stopPreview();
        }
    }

    @Override
    public void destroy() {
        if (mCameraCore != null) {
            mCameraCore.destroy();
            mCameraCore = null;
        }
    }

    @Override
    public IParameter<?> getParameterAll(int parameter) {
        return mCameraParameter.getSparseArray().get(parameter);
    }

Camera2Proxy是代理类。具体的实现是在ICamera2Core的实现类中。这里会根据CameraMode参数 的值通过openCameraMode()选择一个实现。
这里可以看下CameraMode参数

public class CameraMode extends BaseParameter<CameraMode.ModeType> {
    
    public enum ModeType{
        /**拍照模式*/
         MODE_PHOTO (1),
        /**录像模式*/
         MODE_VIDEO (2),
        /**特殊模式*/
         MODE_SPECIALTY (3),
        /**全景*/
         MODE_PANORAMIC(4),
        /**慢动作,这个需要根据判断是否支持高帧捕获*/
         MODE_SLOW_MOTION (5),
        /**延时摄影*/
         MODE_TIME_LAPSE (6),
        /**直播模式*/
         MODE_LIVE (7),
        /**故事模式*/
         MODE_STORY (8),
        /**希区柯克*/
         MODE_DOLLY_ZOOM (9),
        // 华为API才支持以下 模式
        /**夜景*/
         MODE_NIGHT (10),
        /**大光圈*/
         MODE_BOKEH (11),
        /**人像*/
         MODE_PORTRAIT (12);
         public int value;

        ModeType(int value) {
            this.value = value;
        }
    }
    // 省略
}

可以分为3类

  1. 只能拍照 :MODE_PHOTO,MODE_PANORAMIC
  2. 只能录像 :MODE_VIDEO ,MODE_SLOW_MOTION ,MODE_TIME_LAPSE,MODE_LIVE,MODE_STORY,MODE_DOLLY_ZOOM
  3. 能拍照和录像 :MODE_SPECIALTY

模式虽然很多,但是它们的实现都差不多。有些视频模式就是为了ZYCami需求才加上的。我们只需要搞清楚 MODE_PHOTO和MODE_VIDEO 2种模式的实现就行了。

Camera2Video

/**
* @author zhangxi
* @company 桂林智神信息技术有限公司
* @date 2020/11/2 4:29 PM
* @description Camera2 普通录像模式,只提供录像功能。故事 和希区柯克 是 此模式的衍生
*/
public class Camera2Video extends Camera2VideoBase {

    private Camera2VideoParameter mCamera2VideoParameter;

    public Camera2Video(Context context, CameraParameter cameraParameter) {
        this(context,cameraParameter,true);
    }
    /**
     * 构造函数,主要是第三个参数
     * @param context 上下文
     * @param cameraParameter 控制参数类
     * @param init 是否初始化:主要是为了给继承的类使用,子类都是false
     */
    public Camera2Video(Context context, CameraParameter cameraParameter, boolean init) {
        super(context);
        if (init) {
            mCamera2VideoParameter=new Camera2VideoParameter(this,cameraParameter);
            initCamera2(mCamera2VideoParameter);
        }
    }
    // 省略
}

public class Camera2VideoBase extends Camera2Base {

    protected Camera2VideoParameterBase mCamera2VideoParameterBase;

    public Camera2VideoBase(Context context) {
        mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
    }
    // 省略
}

这里为了减少重复代码,增加了2个继承。
1.希区柯克,直播录像等模式与普通录像的差别不大。所以提取父类Camera2VideoBase公共的录像功能实现代码。
2.不管是拍照模式还是录像模式都要先开启相机预览。所以提取父类Camera2Base公共的预览功能实现代码。

Camera2Base

public abstract class Camera2Base implements ICamera2Core {
    public CameraCharacteristics mCameraCharacteristics;
    public CameraManager mCameraManager;
    public CameraDevice mCameraDevice;
    public CameraCaptureSession mCameraSession;
    public CameraConstrainedHighSpeedCaptureSession mCameraSessionHighSpeed;
    private CaptureRequest.Builder mPreviewBuilder;
    private Camera2BaseParameter mCamera2BaseParameter;

    public void initCamera2(Camera2BaseParameter camera2BaseParameter) {
        Zy.d("init Camera2Base");
        this.mCamera2BaseParameter = camera2BaseParameter;
    }
    /**
     * 当前是否 普通捕获模式
     */
    public abstract boolean isSessionNormal();

    /**
     * 获取 创建 相机会话时 需要添加的surface
     *
     * @return surface列表
     */
    public abstract List<Surface> getSessionSurfaceList();
    /**
     * 获取 预览时 需要添加的surface
     *
     * @return surface列表
     */
    public abstract List<Surface> getPreviewSurfaceList();

    /**
     * 预览的捕获结果
     *
     * @param captureResult 此次捕获的 请求
     * @param request       捕获的结果
     */
    public void callbackCaptureResult(CaptureResult captureResult, CaptureRequest request) { }

    @Override
    public void startPreview() {
        Zy.d("startPreview");
        mCamera2BaseParameter.openDevice();
    }

    @Override
    public void stopPreview() {
        Zy.d("stopPreview");
        mCamera2BaseParameter.closeDevice();
    }

    @Override
    public void destroy() {
        Zy.d("destroy");
        closeDevice();
        mCamera2BaseParameter.release();
        mCameraManager = null;
    }
    // 省略
    public void openDevice() {
        Zy.d("open Device start");
        if (getPreviewView().get() == null || getPreviewSurface() == null) {
            Zy.d("current is preview view=null or  preview surface=null, return");
            return;
        }
        Zy.d("openDevice ,Current DeviceStatus=" + getDeviceStatus().get());
        if (getDeviceStatus().isDeviceOpenIng()) {
            Zy.d("current is open  ing , return");
            return;
        }
        acquireLock();
        getDeviceStatus().set(DEVICE_OPEN_ING);
        // 省略
   }
   // 省略
}

此类负责相机预览的开关。需要注意的点 :人脸坐标,高帧率会话,异步操作注意加锁,捕获结果的处理。
持有Camera2BaseParameter :相机参数的控制和响应。

public abstract class Camera2BaseParameter {
    /**
     * 预览的最大曝光时间,即 预览时 sec的最大值 十分之一秒=100_000_000,如果再大 就无法预览了
     */
    private static final long MAX_PREVIEW_EXPOSURE_TIME = 1_000_000_000L / 10;
    private static final int FOCUS_AREA_WEIGHT = 1000;
    public CameraParameter mCameraParameter;
    public Camera2Base mCamera2Base;
    protected CameraCharacteristics mCameraCharacteristics;
    protected ImageReader mAnalysisImageReader;
    private boolean mLastFaceTrigger = false;
    private boolean mLastDataTrigger = false;
    public static HashMap<PreviewWbMode.WbMode, Integer> sWbModes = new HashMap<>();
	// 省略
	/**
     * 重置各个模式通用的参数
     *
     * @param add true 添加监听,false 取消监听
     */
    private void resetPreviewListener(boolean add) {
        addListener(add, getPreviewAe(), aeListener);
        addListener(add, getPreviewAeMode(), aeModeListener);
        addListener(add, getPreviewWt(), wtListener);
        addListener(add, getPreviewFace(), faceListener);
        addListener(add, getPreviewData(), dataListener);
        addListener(add, getPreviewSize(), previewSizeListener);
        addListener(add, getPreviewRect(), rectListener);
        addListener(add, getPreviewFlash(), flashListener);
        addListener(add, getPreviewAfMode(), afModeListener);
        addListener(add, getPreviewWbMode(), WbModeListener);
        addListener(add, getPreviewId(), idListener);
        addListener(add, getSpecialtyManual(), manualListener);
        previewAfListener(add);
        previewSecListener(add);
        previewIsoListener(add);
        previewWbListener(add);
    }
    // 省略
    /**
     * 更新参数的值--但是要先更新id
     *
     * @param characteristics 属性
     */
    protected void setCameraCharacteristics(CameraCharacteristics characteristics) {
        Zy.d("setCameraCharacteristics start");
        this.mCameraCharacteristics = characteristics;
        resetFps();
        resetCameraMode();
        resetParameter();
        resetAe();
        resetAeMode();
        resetAfMode();
        resetWbMode();
        resetFlash();
        resetWt();
        resetRatio();
        resetDeviceOrientation();
        resetDeviceLevel();
        resetAf();
        resetIso();
        resetSec();
        resetWb();
        resetManual();
        getCameraUpdate().set(CameraUpdate.UpdateType.UPDATE_OTHER);
    }
    // 省略
 }

此类的作用。1.相机打开前setCameraCharacteristics()重置各个预览参数值。2.resetPreviewListener()添加或者移除各预览参数的监听。3.具体参数设置的实现。

这样Camera2Base与Camera2BaseParameter 组合实现了预览功能, 预览控制,预览参数的响应。
子类 Camera2VideoBase与Camera2VideoParameterBase 组合实现 预览+录像功能。
子类 Camera2PhotoBase与Camera2PhotoParameterBase 组合实现 预览+拍照功能。

录像功能
IVideoRecorder接口

/**
 * @author zhangxi
 * @company 桂林智神信息技术有限公司
 * @date 7/14/21 10:08 AM
 * @description 录像接口。
 */
public interface IVideoRecorder {
    /**准备*/
    boolean prepare(VideoProfile videoProfile);
    /**开始*/
    boolean start();
    /**暂停*/
    boolean pause();
    /**恢复继续*/
    boolean resume();
    /**停止*/
    boolean stop();
    /**释放资源*/
    void release();
    /**获取录像时 音量大小*/
    int getVolume();
    /**是否正在录制*/
    boolean isRecording();
    /**由外界提供 pcm音频数据,当使用MediaCodec才有用*/
    void sendAudioData(byte[] pcm);
}

VideoProfile定义了录像所需要的参数。

/**
 * @author zhangxi
 * @company 桂林智神信息技术有限公司
 * @date 7/14/21 10:14 AM
 * @description 创建录像实现类
 */
public class MediaRecordFactory {

    /**使用系统MediaRecorder*/
    public static final int MEDIA_RECORDER=1;
    /**使用 相机中的 录像*/
    public static final int MEDIA_CODEC_CAMERA=2;

    public static IVideoRecorder createMediaRecord(@Type int type) {
        Zy.d("createMediaRecord 3type="+type);
        // 默认使用系统的MediaRecorder
        switch (type) {
            case MEDIA_CODEC_CAMERA:
                return new MediaCodecCamera();
            case MEDIA_RECORDER:
            default:
                return new MediaRecordZy();
        }
    }
    @IntDef({MEDIA_RECORDER,MEDIA_CODEC_CAMERA})
    @Retention(RetentionPolicy.SOURCE)
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @interface Type {}
}

目前录像的实现主要有2种实现方式都是硬编码。1使用系统的MediaRecorder 。2使用系统的MediaCodec 。区别就是MediaCodec更加灵活功能更多。 可以控制到每一帧画面,但是使用复杂会有一些兼容性问题。

CameraY说明

整体结构如下:
在这里插入图片描述
在这里插入图片描述

相比CameraY_camera 要简单一些。
定义了5个接口,从上往下依次是美颜功能,相机功能,Mask辅助,录像,纹理渲染。2个实现类CameraView和CameraYun 。CameraView是一个FrameLayout 是对外接口。

/**
 * @author zhangxi
 * @company 桂林智神信息技术有限公司
 * @date 2020/11/3 10:14 AM
 * @description 外界使用的View---主要是方便可以直接在XML文件中使用.主要的实现逻辑是{@link CameraYun}。
 * 客户端可以通过此类拿到需要的参数对象进行设置,监听等操作。
 */
public class CameraView extends FrameLayout implements SubCamera, SubBeauty, SubMask, SubTexture, SubRecord {

    private CameraYun mCameraYun;

    public CameraView(@NonNull Context context) {
        this(context, null);
    }

    public CameraView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    private void init(Context context, AttributeSet attrs) {
        mCameraYun = new CameraYun(context, this, attrs);
    }

    @Override
    protected void onAttachedToWindow() {
        Zy.d(" CameraView onAttachedToWindow");
        super.onAttachedToWindow();
    }

    @Override
    protected void onDetachedFromWindow() {
        Zy.d(" CameraView onDetachedFromWindow");
        mCameraYun.release();
        super.onDetachedFromWindow();
    }
   // 省略
}

具体的实现在CameraYun中。

/**
 * @author zhangxi
 * @company 桂林智神信息技术有限公司
 * @date 2020/10/2 5:54 PM
 * @description 这个是相机SDK的核心逻辑层,相机API 预览组件API 美颜API等等,都是在此类中完成逻辑交互。配合实现上层需求。
 * 由于 适配的特殊性。目前有2个 不同的项目实现StaCam 与(ZYPlay,ZYCami)
 */
public class CameraYun implements SubCamera, SubBeauty, SubMask, SubTexture, SubRecord {
    private Context mContext;
    private ICamera mCamera;
    private IBeauty mBeauty;
    private IMaskZy mMaskZy;
    private ITexture<DisplayRender> mTexture;
    private IOrientation mOrientation;
    private LocationListen mLocationListen;
    private SoundHelper mSoundHelper;
    /**
     * 以下变量在开启美颜后,使用频率太高,为避免反复进行强制转换而声明
     */
    private Size mPreviewSize;
    private PreviewId mPreviewId;
    private ImageView mBlurView;
    private DisplayRender mDisplayRender;
    private float[] mMvpMatrix;
    private CameraType mCameraType = CameraType.CAMERA_TWO;
    private Lifecycle mLifecycle;


    public CameraYun(Context context, ViewGroup viewGroup, AttributeSet attrs) {
        Zy.init(context);
        Zy.d("init Camera Yun");
        this.mContext = context;
        initView(context, viewGroup, attrs);
        initData(context, viewGroup);
    }

    private void initView(Context context, ViewGroup viewGroup, AttributeSet attrs) {
        // 解析美颜属性
        final TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CameraView);
        int beautyMode = attributes.getInt(R.styleable.CameraView_beauty_mode, 0);
        attributes.recycle();
        //美颜类型 0无,1美颜,2滤镜,3同时2种
        Zy.d("init texture zy ,beautyMode=" + beautyMode);
        mTexture = new TextureViewImpl(context, beautyMode);
//        mTexture = new SurfaceViewImpl(context, beautyMode);
//        mTexture = new TextureViewSys(context ,beautyMode);
//        mTexture = new SurfaceViewSys(context ,beautyMode);
//        mTexture = new GLSurfaceViewSys(context);
        viewGroup.addView(mTexture.getView());
        mDisplayRender = mTexture.getRender();
        createTextureListener();
        Zy.d("init blur view");
        mBlurView = new ImageView(context);
        mBlurView.setScaleType(ImageView.ScaleType.FIT_XY);
        mBlurView.setBackgroundColor(Color.BLACK);
        viewGroup.addView(mBlurView);
    }
    //省略
    private void createCameraListener() {
        Zy.d("create camera listener");
        createStatusListener();
        createPreviewListener();
        createPhotoListener();
        createRecordListener();
    }
    //省略
 }

会createCameraListener()创建一些参数的监听,用于处理逻辑。Texture是渲染环境,Camera是画面生产 CameraYun就是将2着粘合起来 ,保证功能的正常。
在这里插入图片描述

流程讲解

到目前为止估计还是有些懵,下面通过对 预览,拍照,录像 3个流程简单讲解,让用户明白 ZYCamera整体的运行流程。

预览流程

预览是最基础,最重要的流程。主要涉及画面的产生和处理显示。基本流程是:
在这里插入图片描述
在项目中 需要添加滤镜 ,所以Surface 是渲染框架返回的SurfaceTexture纹理去创建的。具体在代码中的基本流程:

  1. 显示控件初始化,渲染环境准备。
  2. 打开相机计算出预览大小。
  3. 显示控件根据预览大小计算出控件大小。
  4. 将Surface传递给相机,开始预览。

详细流程 考虑篇幅就不贴代码,用户可以打开工程对着看:

  1. 用户通过Xml 或 new 创建 CameraView。CameraYun开始初始化。
  2. CameraYun 在initView()中创建预览组件TextureViewImpl 并将组件添加到CameraView中,创建TextureStatus的监听。
  3. TextureViewImpl继承TextureView ,初始化时注册setSurfaceTextureListener()监听 创建于渲染框架交互的DisplayRender 对象 并且注册监听setDisplaySurfaceListener()。
  4. 系统回调onSurfaceTextureAvailable()时 ,调用DisplayRender 的initEngineRuntimeEnvironment() 将SurfaceTexture 传递给渲染框架,并等待回调。
  5. 渲染框架回调onSurfaceTextureAvailable(),获取返回的SurfaceTexture 并创建Surface,设置状态为SURFACE_CREATE。
  6. CameraYun收到SURFACE_CREATE后,将预览的Surface设置给PreviewList,控件大小设置为PreviewView,调用startPreview()开始预览。
  7. 一路简单调用 最后到Camera2Base中的openDevice()。updateCameraCharacteristics()初始化相机相关参数,包括预览大小。
  8. 在Camera2VideoParameterBase 的resetParameter()中 的resetSupportSize()确定计算出预览大小 设置到PreviewSize对象。
  9. CameraYun中有监听PreviewSize ,将预览大小设置给TextureData,并通知渲染框架缩放矫正画面。
  10. TextureViewImpl中有监听TextureData,将SurfaceTexture设置预览大小矫正画面,changeAnimator()计算控件的实际大小。设置到onMeasure()。
  11. 回到Camera2Base 中的openDevice()中 openCamera()打开相机等待系统打开结果。
  12. 等待预览画面,流程结束。
    在这里插入图片描述

拍照流程

在这里插入图片描述

  1. 用户端调用PhotoControl()的 set(PhotoControl.TAKE_PHOTO);
  2. CameraYun中监听到TAKE_PHOTO 后 根据情况调用PhotoInner 的set(PhotoInner.TAKE_PHOTO_INNER)
  3. Camera2PhotoParameter 中会监听PhotoInner 得到TAKE_PHOTO_INNER,调用takePhoto()开始拍照。
  4. Universal 中takePhoto()为最终实现。分开闪光灯和不开。不开则调用captureStillPicture()。
  5. 将拍照的ImageReader 的surface 添加到 会话中,调用capture() 捕获图片,等待回调。
  6. mPhotoImageReader的setOnImageAvailableListener()收到返回图的图片数据,设置给PhotoData。
  7. 用户端会监听PhotoData 得到 图片数据。
  8. 保存图片数据,流程结束。
    在这里插入图片描述

录像流程

在这里插入图片描述

  1. 用户端调用RecordPath的.set() 设置拍照路径。
  2. 调用 RecordControl的 set(RecordControl.RECORD_PREPARE_START)开始录像准备。
  3. Camera2VideoParameterBase中会监听RecordControl。得到RECORD_PREPARE_START后调用prepareStart()准备开始。
  4. getVideoProfile()获取到录像参数后 调用prepare(),Camera2VideoParameter会重写prepare() 里面调用MediaRecorder的prepare(), 设置RecordStatus 为PREPARE_START。
  5. CameraYun中监听RecordStatus为PREPARE_START 后 调用渲染 DisplayRender的开始 把录像Surface 等参数传入 等待回调。
  6. displayRecordListener中回调startRecord() 后,将RecordControl 设置为RECORD_START。
  7. 回到Camera2VideoParameterBase,收到RECORD_START 后调用startRecord()开始录像。
  8. Camera2VideoParameter 会重写 start(),里面调用MediaRecorder.start()开始真正录像,设置RecordStatus为START。
  9. 流程结束,停止录像也这个流程。

在这里插入图片描述

总结

  1. 考虑复用和简洁问题,CameraY_camera设计成单独的图像输出功能,所有必须的参数不是通过接口的形式传入,而是通过一个包装对象,用户使用前提前设置。比如:预览需要预览Surface,CameraY_camera提供了一个PreviewList参数给调用者设置预览Surface。CameraY也是同样的设计思路,不同功能模块之间并不直接依赖交互,都是通过各自定义的参数对象。类似中介模式
    在这里插入图片描述
  2. 相机与录像会有兼容问题,尤其是高帧率模式。预览和录像效果 与 渲染框架影响密切。
  3. 许多功能的实现细节并没有说明比如:高帧率、丢帧录像、闪光灯触发、预览画面矫正等。有需要可以针对某个功能单独写一份说明。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值