简介
这个是ZYCamera项目的说明文档,gitee地址
目的是 帮助用户快速理清ZYCamera的实现逻辑,能够快速去修改工程。
这里只会介绍整体的架构和运行流程。
功能介绍
ZYCamera是一个相机SDK ,主要有预览,拍照,录像3大核心功能。
用到的知识点
ZYCamera涉及到的知识点主要也分3大块:
说明:
- OpenGL相关 :处理相机输出的画面(如添加滤镜效果,添加美容效果) 然后进行显示。
- 相机相关 :产生预览画面和拍照。
- 编码相关:将预览画面 编码混合成MP4格式视频。
ZYCamera工程结构
根据需要功能设计的结构如下,主要有3个Module。
- CameraY_camera :所有相机功能的实现代码。属于Model层。
- CameraY : 逻辑层代码。依赖相机和渲染框架,根据需求进行逻辑处理。
- CameraY_Demo : 测试Module。对单独功能的测试。
CameraY_camera说明
整体结构如下:
代码总体分为3部分:
- 对外接口—Camera与ICamera。
- 参数对象—在包parameter 下,参数按不同功能创建。
- 功能实现—在包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类
- 只能拍照 :MODE_PHOTO,MODE_PANORAMIC
- 只能录像 :MODE_VIDEO ,MODE_SLOW_MOTION ,MODE_TIME_LAPSE,MODE_LIVE,MODE_STORY,MODE_DOLLY_ZOOM
- 能拍照和录像 :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纹理去创建的。具体在代码中的基本流程:
- 显示控件初始化,渲染环境准备。
- 打开相机计算出预览大小。
- 显示控件根据预览大小计算出控件大小。
- 将Surface传递给相机,开始预览。
详细流程 考虑篇幅就不贴代码,用户可以打开工程对着看:
- 用户通过Xml 或 new 创建 CameraView。CameraYun开始初始化。
- CameraYun 在initView()中创建预览组件TextureViewImpl 并将组件添加到CameraView中,创建TextureStatus的监听。
- TextureViewImpl继承TextureView ,初始化时注册setSurfaceTextureListener()监听 创建于渲染框架交互的DisplayRender 对象 并且注册监听setDisplaySurfaceListener()。
- 系统回调onSurfaceTextureAvailable()时 ,调用DisplayRender 的initEngineRuntimeEnvironment() 将SurfaceTexture 传递给渲染框架,并等待回调。
- 渲染框架回调onSurfaceTextureAvailable(),获取返回的SurfaceTexture 并创建Surface,设置状态为SURFACE_CREATE。
- CameraYun收到SURFACE_CREATE后,将预览的Surface设置给PreviewList,控件大小设置为PreviewView,调用startPreview()开始预览。
- 一路简单调用 最后到Camera2Base中的openDevice()。updateCameraCharacteristics()初始化相机相关参数,包括预览大小。
- 在Camera2VideoParameterBase 的resetParameter()中 的resetSupportSize()确定计算出预览大小 设置到PreviewSize对象。
- CameraYun中有监听PreviewSize ,将预览大小设置给TextureData,并通知渲染框架缩放矫正画面。
- TextureViewImpl中有监听TextureData,将SurfaceTexture设置预览大小矫正画面,changeAnimator()计算控件的实际大小。设置到onMeasure()。
- 回到Camera2Base 中的openDevice()中 openCamera()打开相机等待系统打开结果。
- 等待预览画面,流程结束。
拍照流程
- 用户端调用PhotoControl()的 set(PhotoControl.TAKE_PHOTO);
- CameraYun中监听到TAKE_PHOTO 后 根据情况调用PhotoInner 的set(PhotoInner.TAKE_PHOTO_INNER)
- Camera2PhotoParameter 中会监听PhotoInner 得到TAKE_PHOTO_INNER,调用takePhoto()开始拍照。
- Universal 中takePhoto()为最终实现。分开闪光灯和不开。不开则调用captureStillPicture()。
- 将拍照的ImageReader 的surface 添加到 会话中,调用capture() 捕获图片,等待回调。
- mPhotoImageReader的setOnImageAvailableListener()收到返回图的图片数据,设置给PhotoData。
- 用户端会监听PhotoData 得到 图片数据。
- 保存图片数据,流程结束。
录像流程
- 用户端调用RecordPath的.set() 设置拍照路径。
- 调用 RecordControl的 set(RecordControl.RECORD_PREPARE_START)开始录像准备。
- Camera2VideoParameterBase中会监听RecordControl。得到RECORD_PREPARE_START后调用prepareStart()准备开始。
- getVideoProfile()获取到录像参数后 调用prepare(),Camera2VideoParameter会重写prepare() 里面调用MediaRecorder的prepare(), 设置RecordStatus 为PREPARE_START。
- CameraYun中监听RecordStatus为PREPARE_START 后 调用渲染 DisplayRender的开始 把录像Surface 等参数传入 等待回调。
- displayRecordListener中回调startRecord() 后,将RecordControl 设置为RECORD_START。
- 回到Camera2VideoParameterBase,收到RECORD_START 后调用startRecord()开始录像。
- Camera2VideoParameter 会重写 start(),里面调用MediaRecorder.start()开始真正录像,设置RecordStatus为START。
- 流程结束,停止录像也这个流程。
总结
- 考虑复用和简洁问题,CameraY_camera设计成单独的图像输出功能,所有必须的参数不是通过接口的形式传入,而是通过一个包装对象,用户使用前提前设置。比如:预览需要预览Surface,CameraY_camera提供了一个PreviewList参数给调用者设置预览Surface。CameraY也是同样的设计思路,不同功能模块之间并不直接依赖交互,都是通过各自定义的参数对象。类似中介模式。
- 相机与录像会有兼容问题,尤其是高帧率模式。预览和录像效果 与 渲染框架影响密切。
- 许多功能的实现细节并没有说明比如:高帧率、丢帧录像、闪光灯触发、预览画面矫正等。有需要可以针对某个功能单独写一份说明。