接口文档
Camera SDK功能
连接模块
判断相机是否连接
通过以下方式获取相机的连接状态:
INSCameraManager.socket().cameraState返回状态中,若状态为 INSCameraStateConnected 则表示已成功建立连接。状态定义如下:
INSCameraManager.socket().cameraState
// 总共有以下几种状态
typedef NS_ENUM(NSUInteger, INSCameraState) {
/// an insta360 camera is found, but not connected, will not response
INSCameraStateFound,
/// an insta360 camera is synchronized, but not connected, will not response
INSCameraStateSynchronized,
/// the nano device is connected, app is able to send requests
INSCameraStateConnected,
/// connect failed
INSCameraStateConnectFailed,
/// default state, no insta360 camera is found
INSCameraStateNoConnection,
};连接相机
Wi-Fi连接
- 连接
手机 Wi-Fi 连接相机后,可调用 INSCameraSDK 中的接口建立连接。该接口采用单例模式,首次调用时会创建实例,后续调用则复用同一实例。
INSCameraManager.socket().setup()- 断开连接
当需要断开与相机的连接时,请调用以下接口:
INSCameraManager.socket().shutdown()蓝牙连接
注意:蓝牙连接的情况下,不支持大数据传输。因此传输数据比较大的功能是不支持的。
不支持功能:预览、获取支持列表、下载文件、固件升级、播放、导出图像。
- 搜索蓝牙设备
调用以下方法扫描蓝牙设备
INSBluetoothManager().scanCameras- 建立蓝牙连接
使用下面的接口建立蓝牙连接:
- (id)connectDevice:(INSBluetoothDevice *)device
completion:(void (^)(NSError * _Nullable))completion;- 断开蓝牙连接
- (void)disconnectDevice:(INSBluetoothDevice *)device;向相机发送心跳包
在与相机保持连接时,需要定期向相机发送心跳包 (heartbeat),否则相机会认为连接已断开,从而导致预览中断或指令无效。
通常,如果30 秒内未收到心跳,相机会主动断开连接。
因此,应用在进入预览或录像等需要保持长时间会话的场景下,应当持续发送心跳包。
下面示例代码展示了如何通过 GCDTimer 定时发送心跳指令,每 0.5 秒发送一次:
func startSendingHeartbeats() {
let commandManager = INSCameraManager.shared().commandManager
print("Heartbeat task started")
// 每隔 0.5s 发送一次心跳,确保连接不断开
GCDTimer.shared.scheduledDispatchTimer(
WithTimerName: "HeartbeatsTimer",
timeInterval: 0.5,
queue: DispatchQueue.main,
repeats: true
) {
commandManager.sendHeartbeats(with: nil)
print("Heartbeat sent")
}
}Wi-Fi管理模块
Wi-Fi信息获取
蓝牙连接成功后,调用接口获取 Wi-Fi 信息。示例代码如下:
let bluetoothManager = INSBluetoothManager()
bluetoothManager.command(by: peripheral)?.getOptionsWithTypes(optionTypes) { (err, options, successTypes) in
guard let options = options else {
self?.showAlert(row.tag!, String(describing: err))
return
}
self?.showAlert("ssid:\(String(describing: options.wifiInfo?.ssid)) pw:\(String(describing: options.wifiInfo?.password))", String(describing: err))
}Wi-Fi 国家码及相机Wi-Fi信道设置说明
⚠️ 注意:设置国家码后必须重启相机 Wi-Fi,否则设置不会生效。信道依赖于国家码,每个国家对应不同的信道列表。重启相机之后重新获取信道列表,即可切换信道(蓝牙或Wi-Fi连接都支持)
- 获取当前国家码
func getWifiCountryCode() {
let optionTypes = [
NSNumber(value: INSCameraOptionsType.wifiChannelList.rawValue)
]
INSCameraManager.shared().commandManager.getOptionsWithTypes(optionTypes) { err, options, successTypes in
guard let options = options else {
print("ERROR: \(err?.localizedDescription ?? "Unknown error")")
return
}
self.printWifiChannelList(options.wifiChannelList)
}
}说明:
- 使用
getOptionsWithTypes获取相机当前 Wi-Fi 频道列表及国家码信息。 - 回调返回
options.wifiChannelList,可以通过自定义打印函数查看内容。
- 设置国家码
func setCountryCode(to countryCode: String = "JP") {
let optionTypes = [
NSNumber(value: INSCameraOptionsType.wifiChannelList.rawValue)
]
let wifiChannelList = INSCameraWifiChannelList(countryCode: countryCode)
let options = INSCameraOptions()
options.wifiChannelList = wifiChannelList
INSCameraManager.shared().commandManager.setOptions(options, forTypes: optionTypes) { error, types in
if let error = error {
print("Failed to set country code: \(error.localizedDescription)")
} else {
print("Country code set to \(countryCode). ⚠️ Wi-Fi restart required to apply changes.")
}
}
}说明:
- 参数
countryCode支持任意 ISO 国家码,例如 "JP"、"US"、"CN"。 - 设置完成后,需要重启相机 Wi-Fi 才能生效。
- 回调可用于确认设置是否成功。
- 重启WIFI并设置信道
INSCameraManager.shared().commandManager.resetCameraWifi(channel)信息获取模块
信息获取
相机型号
INSCameraManager.shared().currentCamera?.name相机序列号
与相机建立连接之后即可调用
INSCameraManager.shared().currentCamera?.serialNumber固件版本号
INSCameraManager.shared().currentCamera?.firmwareRevision相机激活时间
let optionTypes = [
NSNumber(value: INSCameraOptionsType.activateTime.rawValue),
];
INSCameraManager.shared().commandManager.getOptionsWithTypes(optionTypes) { (err, options, successTypes) in
guard let options = options else {
self.showAlert("get options", String(describing: err))
return
}
// 激活时间
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
let date = Date(timeIntervalSince1970: Double(options.activateTime / 1000))
print("date :\(date)")
}SD卡总容量和剩余容量
@interface INSCameraStorageStatus : NSObject
// SD卡状态
@property (nonatomic) INSCameraCardState cardState;
// 剩余容量
@property (nonatomic) int64_t freeSpace;
// 总容量
@property (nonatomic) int64_t totalSpace;
// TODO: 需要限制部分SDK访问
@property (nonatomic) INSStorageCardLocation cardLocation;
@end
let optionTypes = [
NSNumber(value: INSCameraOptionsType.storageState.rawValue),
];
INSCameraManager.shared().commandManager.getOptionsWithTypes(optionTypes) { (err, options, successTypes) in
guard let options = options else {
self.showAlert("get options", String(describing: err))
return
}
}SD卡状态
let optionTypes = [
NSNumber(value: INSCameraOptionsType.storageState.rawValue),
];
INSCameraManager.shared().commandManager.getOptionsWithTypes(optionTypes) { (err, options, successTypes) in
guard let options = options else {
self.showAlert("get options", String(describing: err))
return
}
var sdCardStatus = "error"
switch options.storageStatus?.cardState {
case .normal:
sdCardStatus = "Normal"
break
case .noCard:
sdCardStatus = "NoCard"
break
case .noSpace:
sdCardStatus = "NoSpace"
break
case .invalidFormat:
sdCardStatus = "INvalid Format"
break
case .writeProtectCard:
sdCardStatus = "Write Protect Card"
break
case .unknownError:
sdCardStatus = "UnknownError"
break
default:
sdCardStatus = "Status Error"
}
}电池电量信息
let optionTypes = [
NSNumber(value: INSCameraOptionsType.batteryStatus.rawValue),
];
INSCameraManager.shared().commandManager.getOptionsWithTypes(optionTypes) { (err, options, successTypes) in
guard let options = options else {
self.showAlert("get options", String(describing: err))
return
}
print("battery: \(options.batteryStatus!.batteryLevel)")
}相机系统时间
通知模块
低电量通知
通知字符串:INSCameraBatteryLowNotification
NotificationCenter.default.addObserver(self,
selector: #selector(self.batteryLowNotification(_:)),
name: NSNotification.Name.INSCameraBatteryLow,
object: nil)回调示例:
@objc func batteryLowNotification(_ notification: Notification) {
if let status = notification.userInfo?["storage_status"] as? INSCameraBatteryStatus {
self.showAlert("Notification", "Battery Low: \(status.batteryScale)%")
}
print("Notification: Battery Low")
}SD卡状态通知
通知字符串:INSCameraStorageStatusNotification
NotificationCenter.default.addObserver(self,
selector: #selector(self.storageFullNotification(_:)),
name: NSNotification.Name.INSCameraStorageStatus,
object: nil)状态枚举:
typedef NS_ENUM(NSInteger, INSPBCardState) {
INSPBCardState_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
INSPBCardState_StorCsPass = 0, // 正常
INSPBCardState_StorCsNocard = 1, // 无卡
INSPBCardState_StorCsNospace = 2, // 空间不足
INSPBCardState_StorCsInvalidFormat = 3, // 格式错误
INSPBCardState_StorCsWpcard = 4, // 写保护
INSPBCardState_StorCsOtherError = 5 // 其他错误
};回调示例:
@objc func storageFullNotification(_ notification: Notification) {
if let status = notification.userInfo?["card_state"] as? INSCameraCardState {
self.showAlert("Notification", "Battery Low :\(status)")
}
print("Notification: Storage Full")
}录制异常通知
通知字符串:INSCameraCaptureStoppedNotification
NotificationCenter.default.addObserver(self,
selector: #selector(self.captureStoppedNotification(_:)),
name: NSNotification.Name.INSCameraCaptureStopped,
object: nil)回调示例:
@objc func captureStoppedNotification(_ notification: Notification) {
if let info = notification.userInfo?["video"] as? INSCameraVideoInfo, let errorCode = notification.userInfo?["error_code"] as? Int{
self.showAlert("Notification", "Capture Stop, error code:\(errorCode)")
}
print("Notification: Capture Stop")
}说明:录制过程中如果遇到异常,如存储异常或温度过高,设备会主动停止录制。此时应提示用户重新操作,避免丢失重要内容。
相机温度过高通知
通知字符串:INSCameraTemperatureStatusNotification
NotificationCenter.default.addObserver(self,
selector: #selector(self.temperatureValueNotification(_:)),
name: NSNotification.Name.INSCameraTemperatureStatus,
object: nil)回调示例:
@objc func temperatureValueNotification(_ notification: Notification) {
if let status = notification.userInfo?["temperature_status"] as? INSCameraTemperatureStatus {
self.showAlert("Notification", "Temperature warning, \(status.temperature) ")
}
print("Notification: Temperature warning")
}说明:高温可能会导致设备性能下降甚至损坏。收到此通知后,应建议用户停止使用,待设备冷却后再继续使用。
镜头控制模块
以下枚举定义了相机可用的传感器设备类型(镜头类型):
typedef NS_ENUM(NSUInteger, INSSensorDevice) {
INSSensorDeviceUnknown, // 未知类型
INSSensorDeviceFront, // 前置镜头
INSSensorDeviceRear, // 后置镜头
INSSensorDeviceAll, // 全景镜头
};获取当前镜头类型
INSCameraManager.socket().commandManager.getActiveSensor { error, device, str1, str2 in
if error != nil {
self.showAlert("HDR Take:", "Failed!")
return
}
print("device:\(device)")
}- 对于可替换相机镜头类型的相机(One RS、One R),通过下面代码来获取当前镜头类型,Wide为广角,Pano表示全景:
func getLensType(){
let settings: INSCameraDeviceSettings? = INSCameraManager.shared().currentCamera?.settings
guard let mediaOffset = settings?.mediaOffset else {
return
}
let secnsorType = INSLensOffset(offset: mediaOffset).lensType
if secnsorType == INSLensType.oneR577Wide.rawValue {
print("secnsorType:577Wide")
} else if secnsorType == INSLensType.oneR577Pano.rawValue{
print("secnsorType:577Pano")
}
print("secnsorType:\(secnsorType)")
}切换镜头
INSCameraManager.shared().commandManager.setActiveSensorWith(activeSensorDevice) { [weak self] err, mediaOffset, mediaOffsetV3 in
if let err = err {
self?.showAlert("失败", String(describing: err))
} else {
self?.showAlert("成功", "current offset: \(mediaOffset ?? "")")
self?.shouldRestartPreview = true
self?.runMediaSession()
}
}调用说明:
activeSensorDevice:传入需要切换到的镜头类型(例如 .front、.rear、.all)
预览模块
预览有以下几个核心类,具体参考demo:CameraConfigByJsonController
INSCameraSessionPlayer- 绑定iOS端的
bounds - 实现协议:
INSCameraSessionPlayerDelegate - 实现协议:
INSCameraSessionPlayerDataSource,建议一定实现下面两个协议- 配置Offset信息:
updateOffsetToPlayer - 配置防抖信息:
updateStabilizerParamToPlayer
- 配置Offset信息:
- 绑定iOS端的
INSCameraMediaSession
func setupRenderView() {
var frame = self.view.bounds;
let height = frame.size.width * 0.667
frame.origin.x = 0
frame.origin.y = frame.size.height - height
frame.size.height = height
newPlayer = INSCameraSessionPlayer()
newPlayer?.delegate = self
newPlayer?.dataSource = self
newPlayer?.render.renderModelType.displayType = .sphereStitch
if let view = newPlayer?.renderView {
view.frame = frame;
print("预览流: getView = \(view), frame = \(frame)")
self.view.addSubview(view)
}
let config = INSH264DecoderConfig()
config.shouldReloadDecoder = false
config.decodeErrorMaxCount = 30
config.debugLiveStrem = false
config.debugLog = false
self.mediaSession.setDecoderConfig(config)
}预览中获取实时的防抖数据
在预览过程中,通过实现 INSCameraSessionPlayer中的INSCameraSessionGyroDelegate 协议,能够实现防抖数据的实时回调。回调的数据存在两种格式,其一为原始数据 NSData,其二是解析后的 INSGyroRawItem 格式。
@protocol INSCameraSessionGyroDelegate <NSObject>
@optional
- (void)onRawGyroData:(NSData *)rawData timestampMs:(int64_t)timestampMs;
- (void)onParsedGyroData:(NSMutableArray<INSGyroRawItem *> *)gyroItems timestampMs:(int64_t)timestampMs;
@end
@interface INSCameraSessionPlayer : NSObject<INSCameraPlayerSession>
@property (nonatomic, weak ) id<INSCameraSessionGyroDelegate> gyroDelegate;
@end拍摄控制
本模块主要介绍相机的模式切换、参数设置,以及获取相机当前拍摄模式和参数的相关功能。其中,JSON 配置化机制是重点内容。
相机接口支持对所有参数进行设置,但需要注意,并非所有参数在任意模式下都能生效。例如,在视频录制模式下设置拍照间隔参数是无效的。为了解决这一问题,相机内部维护了一份 JSON 配置表,其中定义了各个模式下可用的参数列表及其取值范围。
开发者可以通过下载该 JSON 配置表,准确获取不同拍摄模式下的可用参数及对应值,从而实现更合理、更高效的相机控制与配置。
此外,我们提供了一个管理类 INSCameraAttrManagerWrapper,用于维护相机参数及其依赖关系。该类负责存储所有相机参数,并基于 JSON 配置表判断参数支持情况及取值范围。具体使用方法可参考 Demo 中的 CameraConfigByJsonController.swift。
在实际开发中,开发者可以先从相机获取当前参数,并将其设置到该类中,即可通过类方法查询各参数的支持情况及可选值
获取相机JSON配置化文件
X4及以后相机的拍摄模式和拍摄属性都是以支持列表中所配置的属性为准。不同相机所支持的拍摄模式有所不同,且不同拍摄模式下所支持的拍摄属性亦存在差别,在拍摄前需要同步相机的支持列表(Json文件)。
INSCameraManager.socket().commandManager.fetchStorageFileInfo(with: .json, completion: {error, fileResp in
if let err = error {
return
}
guard let fileResp = fileResp else {
return
}
print("Info: fetchStorageFileInfo Success!")
INSCameraManager.socket().commandManager.fetchResource(withURI: fileResp.uri, toLocalFile: outputURL, progress: {progress in
}, completion: { error in
if let error = error {
print("Error: fetchResource Failed!")
return
}
print("Info: fetchResource Success!")
completion?()
})
})获取当前拍摄模式
使用接口 INSCameraManager.shared().commandManager.getOptionsWithTypes 获取当前相机的拍摄模式。该方法需要传入以下参数:
- optionTypes 指定需要获取哪些参数,每个参数对应一个枚举值(参见
INSCameraOptionsType),需要转换为NSNumber数组。 - requestOptions 可配置请求的最大超时时长(默认 10 秒)。
- completion 回调中返回:
error:为nil表示获取成功,否则包含错误原因。cameraOptions:包含当前相机拍摄模式(拍摄模式为photoSubMode或videoSubMode,具体枚举含义参见下文)。
拍摄模式枚举:
// 拍照
typedef NS_ENUM(NSUInteger, INSPhotoSubMode) {
INSPhotoSubModeSingle = 0,
INSPhotoSubModeHdr,
INSPhotoSubModeInterval,
INSPhotoSubModeBurst,
INSPhotoSubModeNightscape,
INSPhotoSubModeInstaPano,
INSPhotoSubModeInstaPanoHdr,
INSPhotoSubModeStarlapse,
INSPhotoSubModeNone = 100,
};
// 视频录制
typedef NS_ENUM(NSUInteger, INSVideoSubMode) {
INSVideoSubModeNormal = 0,
INSVideoSubModeBulletTime,
INSVideoSubModeTimelapse,
INSVideoSubModeHDR,
INSVideoSubModeTimeShift,
INSVideoSubModeSuperVideo,
INSVideoSubModeLoopRecording,
INSVideoSubModeFPV,
INSVideoSubModeMovieRecording,
INSVideoSubModeSlowMotion,
INSVideoSubModeSelfie,
INSVideoSubModePure,
INSVideoSubModeLiveview,
INSVideoSubModeCameraLiveview,
INSVideoSubModeDashCam,
INSVideoSubModePTZ,
INSVideoSubModeNone = 100,
};调用demo:
func getCurrentCameraMode(completion: (()->Void)?)->Void{
let typeArray: [INSCameraOptionsType] = [.videoSubMode, .photoSubMode]
let optionTypes = typeArray.map { (type) -> NSNumber in
return NSNumber(value: type.rawValue)
}
let requestOptions = INSCameraRequestOptions()
requestOptions.timeout = 10
INSCameraManager.shared().commandManager.getOptionsWithTypes(optionTypes, requestOptions: requestOptions) { [weak self] error, cameraOptions, _ in
if let error = error {
self?.showAlert("Failed", "The camera mode has been get failed: \(error.localizedDescription)")
return
}
guard let cameraOptions = cameraOptions else {return}
var captureMode: HUMCaptureMode? = nil
if cameraOptions.photoSubMode != 100 {
captureMode = HUMCaptureMode.modePhotoFrom(value: cameraOptions.photoSubMode)
}
else if cameraOptions.videoSubMode != 100 {
captureMode = HUMCaptureMode.modeVideoFrom(value: cameraOptions.videoSubMode)
}
guard let mode = captureMode else {return}
completion?()
}
}切换拍摄模式
通过方法:INSCameraManager.shared().commandManager.setOptions将指定模式配置给相机。在设置拍摄模式中有以下几个重要的点
- INSCameraOptions 用于承载拍摄模式配置,主要包含以下两个属性:
photoSubMode:拍照模式videoSubMode:录像模式
- INSCameraOptionsType 用于指定
INSCameraOptions中哪些参数需要生效:- 拍照模式:
INSCameraOptionsType::INSCameraOptionsTypePhotoSubMode - 录制模式:
INSCameraOptionsType::INSCameraOptionsTypeVideoSubMode
- 拍照模式:
以下为示例代码(以设置图片拍摄模式为例):
// 图片拍摄模式枚举
typedef NS_ENUM(NSUInteger, INSPhotoSubMode) {
INSPhotoSubModeSingle = 0,
INSPhotoSubModeHdr,
INSPhotoSubModeInterval,
INSPhotoSubModeBurst,
INSPhotoSubModeNightscape,
INSPhotoSubModeInstaPano,
INSPhotoSubModeInstaPanoHdr,
INSPhotoSubModeStarlapse,
INSPhotoSubModeNone = 100,
};
var typeArray: [INSCameraOptionsType] = [.photoSubMode]
let optionTypes = typeArray.map { NSNumber(value: $0.rawValue) }
let cameraOptions = INSCameraOptions()
cameraOptions.photoSubMode = INSPhotoSubMode.single
INSCameraManager.shared().commandManager.setOptions(cameraOptions, forTypes: optionTypes) { [weak self] error, _ in
if let error = error {
self?.showAlert("Failed", "The camera mode has been set failed: \(error.localizedDescription)")
print("Failed: The camera mode has been set failed: \(error.localizedDescription)")
return
}
print("SUCCESS")
}参数设置
拍摄参数
白平衡(数值类型)
INSPhotographyOptions中的属性为:
@property (nonatomic) uint32_t whiteBalanceValue;在INSPhotographyOptionsType中对应的枚举为:
INSPhotographyOptionsTypeWhiteBalance = 13假设当前拍摄模式INSCameraFunctionMode为6表示普通拍照。
- X2和one X仅支持枚举(
INSCameraWhiteBalance)设置,X3及之后的才支持使用whiteBalanceValue
@property (nonatomic) uint32_t whiteBalanceValue;
@property (nonatomic) INSCameraWhiteBalance whiteBalance;
typedef NS_ENUM(uint16_t, INSCameraWhiteBalance) {
INSCameraWhiteBalanceAutomatic = 0,
/// Inscandescent
INSCameraWhiteBalanceColorTemp2700K,
/// Sunny. ONE X Fluorescent
INSCameraWhiteBalanceColorTemp4000K,
/// Cloudy. ONE X Sunny
INSCameraWhiteBalanceColorTemp5000K,
/// Fluorescent. ONE X Cloudy
INSCameraWhiteBalanceColorTemp6500K,
/// Outdoor.
INSCameraWhiteBalanceColorTemp7500K = 5,
};ExposureBias(数值类型)
仅在曝光模式为"AUTO" "FULL_AUTO"下支持调节
INSPhotographyOptions`中的属性为:`exposureBias
@property (nonatomic) float exposureBias;INSPhotographyOptionsType中对应的枚举为:
INSPhotographyOptionsTypeExposureBias = 7ISO,shutterSpeed(数值类型)
仅在曝光模式为"MANUAL"和"ISO_PRIORITY"两种模式下支持调节
INSPhotographyOptions`中的分别属性为:`stillExposure.iso`,`stillExposure.shutterSpeed
@property (nullable, nonatomic) INSCameraExposureOptions *stillExposure;
@interface INSCameraExposureOptions : NSObject
@property (nonatomic) uint8_t program;
@property (nonatomic) NSUInteger iso;
#if TARGET_OS_IOS
@property (nonatomic) CMTime shutterSpeed;
#endif
@endINSPhotographyOptionsType中对应的枚举为:
INSPhotographyOptionsTypeStillExposureOptions = 20lapse_time(数值类型)
该参数仅在timelapse模式下生效
func setLapseTimeToCamera(completion: (()->Void)?){
let functionMode = self.attrManage.getIntFunctionsMode()
let functionModeHum = HUMCaptureMode.modeFuncionFrom(value: functionMode)
var mode:INSTimelapseMode? = nil
if functionModeHum.isPhotoMode {
mode = INSTimelapseMode.image
}else if functionModeHum.isVideoMode {
mode = INSTimelapseMode.video
}
guard let mode = mode else {return}
guard let options = self.currentLapseTime else {return}
options.lapseTime = UInt(self.attrManage.getLapseTime() * 1000)
// options.duration = self.attrManage.getRecordDuration()
INSCameraManager.shared().commandManager.setTimelapseOptions(options, for: mode, completion: { (err) in
if let err = err {
self.showAlert("Set LapseTime failed", err.localizedDescription);
return
}
completion?()
})
}分辨率(枚举)
自1.8.1之后的版本分辨率统一使用枚举管理。需要手动配置isUseJsonOptions为true
INSPhotographyOptions.isUseJsonOptions = true- 图片
INSPhotographyOptions`中的属性为:`photoSizeForJson
photoSizeForJson = 17`,表示x4相机的分辨率为`8192 x 6144在INSPhotographyOptionsType中对应的枚举为:
INSPhotographyOptionsTypePhotoSize = 40假设当前拍摄模式INSCameraFunctionMode为6表示普通拍照。
代码示例:
let functionMode = INSCameraFunctionMode.init(functionMode: 6)
var typeArray: [INSPhotographyOptionsType] = [.photoSize]
let optionTypes = typeArray.map { NSNumber(value: $0.rawValue) }
options.isUseJsonOptions = true
option.photoSizeForJson = 17
INSCameraManager.shared().commandManager.setPhotographyOptions(option, for: functionMode, types: optionTypes, completion: { [weak self] error, _ in
guard let error = error else {
self?.showAlert("Success", " set successfully")
return
}
self?.showAlert("Failed", "set failed: \(error.localizedDescription)")
})分辨率与枚举值的对应关系
"photo_resolution": {
"6912_3456": "0", // X3 18MP
"6272_3136": "1",
"6080_3040": "2",
"4000_3000": "3",
"4000_2250": "4",
"5212_3542": "5",
"5312_2988": "6",
"8000_6000": "7",
"8000_4500": "8",
"2976_2976": "9",
"5984_5984": "10",
"11968_5984": "11",
"5952_2976": "12", // 72MP
"8192_6144": "17", // X4 18MP
"8192_4608": "18",
"4096_3072": "19",
"4096_2304": "20",
"7680_3840": "21",
"3840_3840": "22"
}- 视频
INSPhotographyOptions`中的属性为:`videoResolutionForJson不在此处展示,可参考common_camera_setting_proto.json文件中的record_resolution列表。
曝光模式(枚举)
INSPhotographyOptions中的属性为:
@property (nullable, nonatomic) INSCameraExposureOptions *stillExposure;
@interface INSCameraExposureOptions : NSObject
@property (nonatomic) uint8_t program; // 曝光模式
@property (nonatomic) NSUInteger iso;
#if TARGET_OS_IOS
@property (nonatomic) CMTime shutterSpeed;
#endif
@endINSPhotographyOptionsType中对应的枚举为:
INSPhotographyOptionsTypeStillExposureOptions = 20
"exposure_program": {
"AUTO": "0",
"ISO_PRIORITY": "1",
"SHUTTER_PRIORITY": "2",
"MANUAL": "3",
"ADAPTIVE": "4",
"FULL_AUTO": "5"
},支持同时设置多个参数给相机,如下:
var typeArray: [INSPhotographyOptionsType] = [.photoSize, .whiteBalanceValue]
let optionTypes = typeArray.map { NSNumber(value: $0.rawValue) }
option.photoSizeForJson = 11
option.whiteBalanceValue = 4000
INSCameraManager.shared().commandManager.setPhotographyOptions(option, for: functionMode, types: optionTypes, completion: { [weak self] error, _ in
guard let error = error else {
self?.showAlert("Success", "The camera resolution has been set successfully")
return
}
self?.showAlert("Failed", "The camera resolution has been set failed: \(error.localizedDescription)")
completion?()
})照片格式(枚举)
注意:X5默认打开pureshot模式,且不支持关闭
INSPhotographyOptions中的属性为:
@property (nonatomic) uint8_t rawCaptureType;在INSPhotographyOptionsType中对应的枚举为:
INSPhotographyOptionsTypeRawCaptureType = 25,枚举类型:
"raw_capture_type": {
"OFF": "0",
"RAW": "1",
"PURESHOT": "3",
"PURESHOT_RAW": "4",
"INSP": "5",
"INSP_RAW": "6"
},机内拼接(Bool)
在拍摄图片时,在相机内部拼接全景图像,无需再外部拼接素材。仅x4及后的相机支持。
var typeArray = [INSCameraOptionsType]()
let cameraOptions = INSCameraOptions()
// 打开为true, 关闭为false
cameraOptions.enableInternalSplicing = true
typeArray.append(.internalSplicing)
let optionTypes = typeArray.map { (type) -> NSNumber in
return NSNumber(value: type.rawValue)
}
INSCameraManager.shared().commandManager.setOptions(cameraOptions, forTypes: optionTypes) { [weak self] error, _ in
if let error = error {
self?.showAlert("Failed", "The camera mode has been set failed: \(error.localizedDescription)")
return
}
completion?()
}获取当前拍摄参数
获取相机通过方法:getPhotographyOptions获取。需要的主要入参有三个functionMode和optionTypes,以及一个闭包回调。
/*!
* @discussion Get photography options. Your app should not call this method to get the current photography options. Instead, your app should rely on the photography options that just set, or they will be as default.
*
* @param functionMode the target function mode to get
* @param optionTypes array of the INSPhotographyOptionsType to get
* @param completion the callback block. If all succeed, error would be nil, if partial failed, error's code would be <code>INSCameraErrorCodeAccept</code>, if all fail, error's code would be the maximum error code.
*/
- (void)getPhotographyOptionsWithFunctionMode:(INSCameraFunctionMode*)functionMode
types:(NSArray <NSNumber *>*)optionTypes
completion:(void(^)(NSError * _Nullable error,
INSPhotographyOptions * _Nullable options,
NSArray <NSNumber *>* _Nullable successTypes))completion;functionMode:表示当前的拍摄模式optionTypes:每个参数对应一个枚举值- 如分辨率对应:
INSPhotographyOptionsTypePhotoSize = 40 - 白平衡对应:
INSPhotographyOptionsTypeWhiteBalance = 13
- 如分辨率对应:
- 闭包会返回一个
NSError和INSPhotographyOptionsNSError为nil表示成功,否则会包含失败原因INSPhotographyOptions中包含当前相机参数的具体值,如分辨率,白平衡等
(示例)获取当前相机白平衡值:
var typeArray: [INSPhotographyOptionsType] = [.whiteBalanceValue]
let optionTypes = typeArray.map { NSNumber(value: $0.rawValue) }
let functionMode = currentFunctionMode.functionMode
INSCameraManager.shared().commandManager.getPhotographyOptions(with: functionMode, types: optionTypes, completion: { [weak self] error, camerOptions, successTags inif let error = error {print("Get Message Failed! Error: \(error.localizedDescription)")return
}
print("getPhotographyOptions Success!")
print("whiteBalance: \(camerOptions?.whiteBalance ?? "N/A")")
})设置相机参数
给相机设置参数需要通过方法:INSCameraManager.shared().commandManager.setPhotographyOptions,需要的主要入参主要有以下几个参数。
INSPhotographyOptions:存储被配置的参数INSPhotographyOptionsType:表示哪些参数需要被配置(每个参数对应一个枚举)INSCameraFunctionMode:当前的拍摄模式,当前拍摄模式。- 相机设置需要的拍摄模式
INSCameraFunctionMode和从相机拿到的拍摄模式INSPhotoSubMode或INSVideoSubMode不能直接转换,对应关系参考工程文件中的类:HUMCaptureMode。通过HUMCaptureMode将相机当前模式INSPhotoSubMode或INSVideoSubMode转成统一的INSCameraFunctionMode
- 相机设置需要的拍摄模式
- 闭包回调:返回是否获取成功
所有参数类型只能设置为相机屏幕上支持的参数,不能随意设置
示例代码如下:设置指定白平衡
let functionMode = INSCameraFunctionMode.init(functionMode: 6)
var typeArray: [INSPhotographyOptionsType] = [.whiteBalanceValue]
let optionTypes = typeArray.map { NSNumber(value: $0.rawValue) }
option.whiteBalanceValue = 4000
INSCameraManager.shared().commandManager.setPhotographyOptions(option, for: functionMode, types: optionTypes, completion: { [weak self] error, _ in
guard let error = error else {
self?.showAlert("Success", "set successfully")
return
}
self?.showAlert("Failed", "set failed: \(error.localizedDescription)")
})拍照
普通拍照
通过INSCameraManager.shared().commandManager.takePicture方法向相机下达拍摄指令,若 error 为 nil,则表示拍摄成功,反之则包含错误信息。optionInfo 中涵盖照片的远程访问地址,可进行远程导出(无需下载至本地)。
INSCameraManager.shared().commandManager.takePicture(with: nil, completion: { (error, optionInfo) in
print("end takePicture \(Date())")
guard let uri = optionInfo?.uri else {
return
}
print("Take Picture Url:\(uri)")\
})HDR拍照
操作方式变更(x4 及后续机型):
x4及之后的机型需要切换到对应的拍摄模式,然后调用拍摄即可
let options:INSTakePictureOptions = INSTakePictureOptions()
INSCameraManager.shared().commandManager.takePicture(with: options, completion: { (error, optionInfo) in
guard let uri = optionInfo?.uri else {
return
}
})X3及以前的机型拍摄HDR,需要将设置拍摄参数中的mode为aeb模式然后再拍照。
let options:INSTakePictureOptions = INSTakePictureOptions()
options.mode = INSPhotoMode.aeb
INSCameraManager.shared().commandManager.takePicture(with: options, completion: { (error, optionInfo) in
guard let uri = optionInfo?.uri else {
return
}
})倒计时拍照(仅支持X5、X4 Air)
需要通过setPhotographyOptions设置photographySelfTimer参数,且countDown为0即可。
录像
普通录制
开始录制:
INSCameraManager.shared().commandManager.startCapture(with: nil, completion: { (err) in
if let err = err {
self.showAlert(row.tag!, "\(String(describing: err))")
return
}
})停止录制
INSCameraManager.shared().commandManager.stopCapture(with: nil, completion: { (err, info) in
if let err = err {
self.showAlert(row.tag!, "\(String(describing: err))")
return
}
})Timelapse录制
开始和停止录制与普通录制方法一致,但是有一些需要注意的点
- 对于 X5 及后续机型,若在录制延时摄影(Timelapse)过程中需要保存 IMU 数据。必须使用我们提供的SDK录制。使用我们的App录制不会保存imu数据
- 且必须通过以下命令调用才能触发存储imu数据的功能
开始录制:
/*!
* Start time lapse capture. For ONE X, you can input `INSExtraInfo` via options if the `INSTimelapseMode` is image.
*
* availability(ONE, ONE X)
*/
- (void)startCaptureTimelapseWithOptions:(INSStartCaptureTimelapseOptions * _Nonnull)options completion:(void(^)(NSError * _Nullable error))completion;停止录制
/*!
* Start time lapse capture
*
* availability(ONE)
*/
- (void)stopCaptureTimelapseWithCompletion:(void(^)(NSError * _Nullable error,
INSCameraVideoInfo * _Nullable videoInfo))completion;文件管理模块
获取文件列表
- (void)fetchPhotoListWithOptions:(INSGetFileListOptions *)options
completion:(void (^)(NSError * _Nullable error, INSCameraResources * _Nullable res))completion;文件下载
- (NSURLSessionTask *)fetchResourceWithURI:(NSString *)URI
toLocalFile:(NSURL *)localFileURL
progress:(void (^)(NSProgress * _Nullable progress))progress
completion:(void(^)(NSError * _Nullable error))completion;日志记录模块
在 INSCameraSDK 中,所有日志信息均通过 INSCameraSDKLoggerProtocol 协议以回调的形式传递给上层。上层在接收到这些日志后,可以选择将其打印输出,便于开发人员在调试阶段观察 SDK 的运行状态。
也可以将日志进行持久化存储,以支持后续的数据分析或问题排查。如需了解更详细的配置方法,建议参考示例控制器 CameraConfigByJsonController。
日志的回调通过 INSCameraSDKLogger 单例对象实现,该对象作为 INSCameraSDKLoggerProtocol 的承载体。
开发者需将自定义实现的日志代理对象赋值给 INSCameraSDKLogger 的 logDelegate 属性,以接收 SDK 输出的各级别日志信息。
日志协议 INSCameraSDKLoggerProtocol 包含以下方法:
@protocol INSCameraSDKLoggerProtocol
- (void)logError:(NSString *)message filePath:(NSString *)filePath funcName:(NSString *)funcName lineNum:(NSInteger)lineNum;
- (void)logWarning:(NSString *)message filePath:(NSString *)filePath funcName:(NSString *)funcName lineNum:(NSInteger)lineNum;
- (void)logInfo:(NSString *)message filePath:(NSString *)filePath funcName:(NSString *)funcName lineNum:(NSInteger)lineNum;
- (void)logDebug:(NSString *)message filePath:(NSString *)filePath funcName:(NSString *)funcName lineNum:(NSInteger)lineNum;
- (void)logCrash:(NSString *)message filePath:(NSString *)filePath funcName:(NSString *)funcName lineNum:(NSInteger)lineNum;
@endGPS数据模块
拍照模式下设置
在调用拍摄接口时,传入INSMediaGps数据到拍摄参数中
func pictureGps() {
// 构造当前位置(GPS)数据,这里用的是香港坐标点作为示例
let newestLocation = CLLocation(
coordinate: CLLocationCoordinate2D(latitude: 22.2803, longitude: 114.1655), // 经纬度
altitude: 10.0, // 海拔高度(米)
horizontalAccuracy: 5.0, // 水平精度(米)
verticalAccuracy: 5.0, // 垂直精度(米)
timestamp: Date() // 当前时间戳
)
// 创建拓展元数据对象(用于附加 GPS、陀螺仪、磁力计等信息)
let metaData = INSExtraMetadata()
// 用构造的 CLLocation 创建一个媒体 GPS 信息对象
let mediaGps = INSMediaGps(clLocation: newestLocation, isValidLocation: true)
// 将 GPS 信息写入元数据中
metaData.gps = mediaGps
// 创建扩展信息对象,并设置元数据(此处未设置陀螺仪数据)
let extraInfo = INSExtraInfo(
version: Int32(INSExtraInfoVersion.one2.rawValue), // 使用扩展信息版本 one2
metadata: metaData, // 附带 GPS 信息的元数据
gyroData: nil // 无陀螺仪数据
)
// 构建拍照选项对象,包含扩展信息
let options: INSTakePictureOptions = INSTakePictureOptions(extraInfo: extraInfo)
// 调用相机拍照命令
INSCameraManager.shared().commandManager.takePicture(with: options, completion: { (error, optionInfo) in
print("end takePicture \(Date())") // 打印拍照完成时间
// 从返回信息中提取图片的 URI
guard let uri = optionInfo?.uri else {
return // 如果获取失败,直接返回
}
print("Take Picture Url:\(uri)") // 打印拍摄照片文件的地址
})
}录像模式下设置
在开始录制之后通过uploadGpsDatas将构造好的GPS数据传到相机。
// 创建额外信息对象(一般用于传递扩展参数)
let extraInfo = INSExtraInfo()
// 创建拍摄参数对象,并设置 extraInfo
let options = INSCaptureOptions(extraInfo: extraInfo)
// 启动拍摄
self?.commandsManager.startCapture(with: options, completion: { (err) in
if let err = err {
// 启动失败,弹窗提示
print("\(row.title!) failed with error: \(err)")
self?.showAlert(row.title!, err.localizedDescription)
return
}
// 延迟 5 秒后执行 GPS 数据上传
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
// 创建一个 GPS 数据数组(模拟 100 条)
var gpsDatas: [INSCameraGpsInfo] = []
for _ in 0..<100 {
let location = CLLocation(
coordinate: CLLocationCoordinate2DMake(22.219749, 11.264474),
altitude: 50.0,
horizontalAccuracy: 1.0,
verticalAccuracy: 1.0,
course: 0.012,
speed: 10.0,
timestamp: Date()
)
let mediaGps = INSCameraGpsInfo(clLocation: location, isValidLocation: true)
gpsDatas.append(mediaGps)
}
// 转换为二进制数据形式(可选:用于调试或上传)
var datas = Data()
for gps in gpsDatas {
guard let gpsD = gps.toGpsData() else {
continue
}
datas.append(gpsD)
}
print("--- \(datas)") // 输出调试信息
// 上传 GPS 数据到相机
INSCameraManager.shared().commandManager.uploadGpsDatas(gpsDatas, completion: { (error) in
if let error = error {
self?.showAlert("error", "upload gps datas error: \(error)")
print("upload gps datas error: \(error)")
} else {
self?.showAlert("success", "upload gps datas success")
print("upload gps datas success")
}
// 上传完成后停止拍摄
INSCameraManager.shared().commandManager.stopCapture(with: options, completion: { [weak self] (err, video) in
if let err = err {
print("\(row.title!) failed with error: \(err)")
self?.showAlert(row.title!, err.localizedDescription)
return
}
})
})
}
})其它功能模块
激活相机
激活相机所需要的Appid和secret需要向Insta360申请:
guard let serialNumber = INSCameraManager.shared().currentCamera?.serialNumber else {
self?.showAlert("提示", "请先连接相机")
return
}
let commandManager = INSCameraManager.shared().commandManager
// 需要申请,填入真实的appid和secret
INSCameraActivateManager.setAppid("Appid", secret: "secret")
INSCameraActivateManager.share().activateCamera(withSerial: serialNumber, commandManager: commandManager) { deviceInfo, error in
if let activateError = error {
self?.showAlert("Activate to \(serialNumber)", String(describing: activateError))
} else {
let deviceType = deviceInfo?["deviceType"] ?? ""
let serialNumber = deviceInfo?["serial"] ?? ""
self?.showAlert("Activate to success", "deviceType: \(deviceType), serial: \(serialNumber)")
}
}关闭提示音
let optionTypes = [
NSNumber(value: INSCameraOptionsType.mute.rawValue),
];
let options = INSCameraOptions()
options.mute = true
INSCameraManager.socket().commandManager.setOptions(options, forTypes: optionTypes, completion: {error,successTypes in
if let error = error {
print("Error:\(error)")
return
}
print("Success")
})格式化SD卡
let optionTypes = [
NSNumber(value: INSCameraOptionsType.mute.rawValue),
];
let options = INSCameraOptions()
options.mute = true
INSCameraManager.socket().commandManager.setOptions(options, forTypes: optionTypes, completion: {error,successTypes in
if let error = error {
print("Error:\(error)")
return
}
print("Success")
})相机锁屏
注意:仅支持X4、X5
屏幕锁定:
INSSetAccessCameraFileStateAccessStateLiveView关闭屏幕锁定:
INSSetAccessCameraFileStateAccessStateIdle = 1
typedef NS_ENUM(NSUInteger, INSSetAccessCameraFileStateAccessState) {
INSSetAccessCameraFileStateAccessStateUnknown = 0,
/**没在在访问文件 */
INSSetAccessCameraFileStateAccessStateIdle = 1,
INSSetAccessCameraFileStateAccessStateExport = 2,
INSSetAccessCameraFileStateAccessStateDownload = 3,
INSSetAccessCameraFileStateAccessStatePlayback = 4,
INSSetAccessCameraFileStateAccessStateLiveView = 5,
};
INSCameraManager.shared().commandManager.setAppAccessFileState(state, completion: { _ in
// 完成回调可以在这里处理
})关闭相机
控制相机关机的指令,示例代码如下:
注意:仅Insta360X5以及之后的相机支持该功能;
INSCameraManager.socket().commandManager.closeCamera({_ in
})固件升级
通过调用updateFirwareWithOptions接口主动升级。INSCameraWriteFileOptions
@interface INSCameraWriteFileOptions : NSObject
/// file type of data to write
@property (nonatomic) INSCameraFileType fileType;
/// data of a file. if fileType is photo, data should be encoded in JPG format.
@property (nonatomic) NSData *data;
/// destinate path of the file in camera, if nil, camera will decide the uri with fileType.
@property (nonatomic, nullable) NSString *uri;
@end
- (void)updateFirwareWithOptions:(INSCameraWriteFileOptions *)options
completion:(void (^)(NSError * _Nullable))completion;错误码
typedef NS_ENUM(NSUInteger, INSCameraErrorCode) {
/// ok
INSCameraErrorCodeOK = 200,
/// accepted
INSCameraErrorCodeAccept = 202,
/// mainly means redirection
INSCameraErrorCodeMovedTemporarily = 302,
/// bad request, check your params
INSCameraErrorCodeBadRequest = 400,
/// the command has timed out
INSCameraErrorCodeTimeout = 408,
/// the requests are sent too often
INSCameraErrorCodeTooManyRequests = 429,
/// request is interrupted and no response has been gotten
INSCameraErrorCodeNoResopnse = 444,
INSCameraErrorCodeShakeHandeError = 445,
INSCameraErrorCodePairError = 446,
/// error on camera
INSCameraErrorCodeInternalServerError = 500,
/// the command is not implemented for this camera or firmware
INSCameraErrorCodeNotImplemented = 501,
/// there is no connection
INSCameraErrorCodeNoConnection = 503,
/// firmware error
INSCameraErrorCodeFirmwareError = 504,
/// Invalid Request
INSCameraErrorCodeInvalidRequest = 505,
/// bluetooth not inited
INSCameraErrorCodeCentralManagerNotInited = 601,
};Media SDK功能
导出视频
导出视频:INSExportSimplify 位于 INSCoreMedia 该类主要用于简化视频导出的操作,提供了一系列可配置的属性和方法,方便开发者根据需求定制导出过程。(仅支持导出视频)。
使用说明
这种方法可以保证基本的导出效果,所有导出所使用的参数都是默认值。用户可以根据特定需求对相关参数进行配置。
初始化方法
-(nonnull instancetype)initWithURLs:(nonnull NSArray<NSURL>)urls outputUrl:(nonnull NSURL*)outputUrl;- 功能:初始化
INSExportSimplify对象,用于指定输入视频文件的 URL 数组和输出视频文件的 URL。 - 参数:
urls:输入视频文件的 URL 数组,不能为空。outputUrl:输出视频文件的 URL,不能为空。
- 返回值:返回一个
INSExportSimplify对象。 - 示例代码:
NSArray<NSURL*> *inputUrls = @[[NSURL fileURLWithPath:@"path/to/input1.mp4"], [NSURL fileURLWithPath:@"path/to/input2.mp4"]];
NSURL *outputUrl = [NSURL fileURLWithPath:@"path/to/output.mp4"];
INSExportSimplify *exporter = [[INSExportSimplify alloc] initWithURLs:inputUrls outputUrl:outputUrl];开始导出
-(nullable NSError*)start;取消导出
-(void)cancel;销毁导出
取消导出,导出完成之后,一定要主动调用,否则可能导致crash
-(void)shutDown;参数说明
导出分辨率
该接口用于输出图像分辨率,(宽高比必须为2:1)
/**
* 默认宽高: 1920 * 960 (导出画面比例需要为2:1)
*/
@property (nonatomic) int width;
@property (nonatomic) int height;拼接模式
总共有三种拼接模式,动态拼接,光流拼接,AI拼接。
- 动态拼接:适合包含近景的场景,或者有运动和快速变化的情况
- 光流拼接:使用场景和动态拼接相同
- AI 拼接:基于影石Insta360现有的光流拼接技术的优化算法,提供更优的拼接效果,该拼接模式需要配置拼接模型路径
aiStitchPath,模型文件在工程文件中,model_export_v22_d7c49187.mlmodelc
@property (nonatomic) NSString *aiStitchPath;
typedef NS_ENUM(NSInteger, INSOpticalFlowType) {
// 动态拼接
INSOpticalFlowTypeDynamicStitch = 0,
// 光流拼接
INSOpticalFlowTypeDisflow = 1,
// AI拼接
INSOpticalFlowTypeAiFlow = 2,
};防抖模式
防抖模式总共支持以下几种,对于全景相机有两种,全防和方向锁定:
- 全防(Still):无论怎么转动相机,相机画面始终保持不动
- 方向锁定(FullDirectional):视角始终随着相机的转动而转动
/**
* 防抖模式,默认 INSStabilizerStabModeZDirectional
*/
@property (nonatomic)INSStabilizerStabMode stabMode;
typedef NS_ENUM(NSInteger, INSStabilizerStabMode) {
/// 关闭防抖
INSStabilizerStabModeOff = -1,
/// 全防
INSStabilizerStabModeStill,
/// 移除yaw方向的防抖, 用于directional lock, view can only move arround z-axis (pan move)
INSStabilizerStabModeZDirectional,
/// 开防抖、开水平矫正,即full-direcional
INSStabilizerStabModeFullDirectional,
///不校准地平线, 即free-footage, total free camera mode, camera can move through three axis
INSStabilizerStabModeFreeFootage,
/// //处理翻转
INSStabilizerStabModeFlipEffect,
///开防抖、平均姿态矫正,即relative-refine
INSStabilizerStabModeRelativeRefine,
///开防抖、开水平矫正,即absulute-refine
INSStabilizerStabModeAbsoluteRefine,
///子弹时间
INSStabilizerStabModeBulletTime,
/// Pano Fpv
INSStabilizerStabModePanoFPV
};保护镜类型
如果拍摄时佩戴保护镜,需要根据类型配置该参数。(商城中的标准保护镜为A级,高级保护镜为S级)
/**
* 保护镜
*/
@property (nonatomic) INSOffsetConvertOptions protectType;
typedef NS_OPTIONS(NSUInteger, INSOffsetConvertOptions) {
INSOffsetConvertOptionNone = 0,
INSOffsetConvertOptionEnableWaterProof = 1 << 0, // ONE X 保护镜
INSOffsetConvertOptionEnableDivingAir = 1 << 1, // 潜水壳(水上)
INSOffsetConvertOptionEnableDivingWater = 1 << 2, // 潜水壳(水下)
INSOffsetConvertOptionEnableDivingAirV2 = 1 << 3, // 新版潜水壳(水上)
INSOffsetConvertOptionEnableDivingWaterV2 = 1 << 4, // 新版潜水壳(水下)
INSOffsetConvertOptionEnableBuckleShell = 1 << 5, // 卡扣式弧面镜
INSOffsetConvertOptionEnableAdhesiveShell = 1 << 6, // 黏贴式球面镜
INSOffsetConvertOptionEnableGlassShell = 1 << 7, // 玻璃保护镜(S)
INSOffsetConvertOptionEnablePlasticCement = 1 << 8, // 塑胶保护镜(A)
INSOffsetConvertOptionEnableAverageShell = 1 << 9 // A/S平均
};消色差
/**
* 消色差: 默认false
*/
@property (nonatomic) BOOL colorFusion;产生色差的原因主要有以下两点:
- 首先,由于两个镜头是分开的,其各自得出的视频曝光可能不太一致。当把它们拼接在一起的时候,会有比较明显的亮度差。这是因为不同镜头在拍摄时的参数设置、感光元件的性能等方面存在差异,从而导致所捕捉到的光线强度有所不同。
- 其次,因为镜头两边的光照不一样,相机曝光不同,有时候前后镜头拍出来的画面也会有明显的亮度差。这种现象在光差比大的地方尤其明显,比如在强光与阴影交界的区域,或者是在室内外光线差异较大的环境中。在这些情况下,相机难以平衡不同区域的光线强度,从而使得拍摄出的画面在亮度上出现较大的差别。
正是为了解决此类问题,消色差技术得以开发。它通过一系列的算法和图像处理手段,对不同镜头拍摄的画面进行调整和优化,以减少或消除亮度差,从而使拼接后的视频看起来更加自然和连贯。
去紫边
该接口具备消除特定现象的功能,具体而言,其专门用于消除录制过程中因光照因素产生的紫边现象。在实际录制场景中,光照情况复杂多变,该接口能够针对性地解决两类常见光照场景下出现的紫边问题。其一为室外强光场景,在阳光强烈的白天进行录制时,室外高强度光线极易引发紫边现象,此接口可有效消除该场景下的紫边;其二为室内灯光场景,室内诸如白炽灯、荧光灯等不同类型的灯光所发出的光线,也可能致使录制画面出现紫边,该接口同样能够对这种室内灯光场景下的紫边现象进行消除处理。
使用方法:使用该算法,需要配置对应模型,该模型通过一个Json文件来管理coreml_model_v2_scale6_scale4.json。需要将这些模型和Json文件拷贝到App内。参数配置参考下列代码:
视频
let jsonFilePath: String = Bundle.main.path(forResource: "coreml_model_v2_scale6_scale4", ofType: "json")!
let components = jsonFilePath.split(separator: "/")
let modelFilePath = components.dropLast().joined(separator: "/")
var jsonContent = ""
do {
let data = try Data(contentsOf: URL(fileURLWithPath: jsonFilePath))
jsonContent = String(data: data, encoding: .utf8) ?? ""
} catch {
assertionFailure("\(jsonFilePath)文件无法读取")
}
let initInfo = INSDePurpleFringeFilterInitInfo.init(imageTransferType: .AUTO, algoAccelType: .AUTO)
let depurpleFringInfo = INSDePurpleFringeFilterInfo()
depurpleFringInfo.setInit(initInfo)
depurpleFringInfo.setModelJsonContent(jsonContent)
depurpleFringInfo.setModelFilePath(modelFilePath)图片
let jsonFilePath: String = Bundle.main.path(forResource: "coreml_model_v2_scale6_scale4", ofType: "json")!
let components = jsonFilePath.split(separator: "/")
let modelFilePath = components.dropLast().joined(separator: "/")
var jsonContent = ""
do {
let data = try Data(contentsOf: URL(fileURLWithPath: jsonFilePath))
jsonContent = String(data: data, encoding: .utf8) ?? ""
} catch {
assertionFailure("\(jsonFilePath)文件无法读取")
}
let depurpleFringInfo = INSExporter2DefringConfiguration.init()
depurpleFringInfo.modelJsonContent = jsonContent
depurpleFringInfo.modelFilePath = modelFilePath
depurpleFringInfo.enableDetect = true
depurpleFringInfo.useFastInferSpeed = false
videoExporter?.defringeConfig = depurpleFringInfo降噪
在视频处理领域,多帧降噪技术是重要的图像处理手段,可减轻或去除视频画面噪点。噪点会影响画质和观看体验。与单帧降噪仅处理单帧画面不同,多帧降噪利用前后多帧冗余信息,更准确区分图像内容与噪点,能在去噪同时保留图像细节,获高质量画面。不过,多帧降噪也有弊端。它需处理多帧信息,计算分析复杂,消耗系统性能,可能使设备运行变慢、卡顿,还会减慢视频导出速度,增加时间成本。
/**
* 降噪
* 该属性用于控制是否启用视频的多帧降噪功能。当设置为YES时,启用降噪功能;设置为NO时,关闭降噪功能。
*/
@property (nonatomic) BOOL enableDenoise;色彩增强
/**
* 色彩增强, 默认false关闭
*/
@property (nonatomic) BOOL clolorPlus;进度和状态回调
开始导出后,该协议INSRExporter2ManagerDelegate会实时回调导出的进度和状态。
typedef NS_ENUM(NSInteger, INSExporter2State) {
INSExporter2StateError = -1, // 表示导出过程中出现错误
INSExporter2StateComplete = 0, // 表示导出成功完成
INSExporter2StateCancel = 1, // 表示用户手动取消了导出操作
INSExporter2StateInterrupt = 2, // 表示导出被意外中断
INSExporter2StateDisconnect = 3, // 表示与服务器断开连接
INSExporter2StateInitError = 4, // 表示初始化时出现错误
};
@protocol INSRExporter2ManagerDelegate <NSObject>
- (void)exporter2Manager:(INSExporter2Manager *)manager progress:(float)progress;
- (void)exporter2Manager:(INSExporter2Manager *)manager state:(INSExporter2State)state error:(nullable NSError*)error;
// 用于全景埋点检测(一般用不到)
- (void)exporter2Manager:(INSExporter2Manager *)manager correctOffset:(NSString*)correctOffset errorNum:(int)errorNum totalNum:(int)totalNum clipIndex:(int)clipIndex type:(NSString*)type;
@end错误码
typedef NS_ENUM(NSInteger, INSExporter2State) {
INSExporter2StateError = -1, // 表示导出过程中出现错误
INSExporter2StateComplete = 0, // 表示导出成功完成
INSExporter2StateCancel = 1, // 表示用户手动取消了导出操作
INSExporter2StateInterrupt = 2, // 表示导出被意外中断
INSExporter2StateDisconnect = 3, // 表示与服务器断开连接
INSExporter2StateInitError = 4, // 表示初始化时出现错误
};导出图片
使用说明
图片导出:INSExportImageSimplify 类属于 INSCoreMedia 框架。该类旨在简化图像导出操作,提供了一系列可配置属性和方法,支持导出普通图像和 HDR 图像,允许开发者根据需求定制导出过程。
导出普通图像
- (NSError*)exportImageWithInputUrl:(nonnull NSURL *)inputUrl outputUrl:(nonnull NSURL *)outputUrl;- 功能:导出普通图像,支持远程或本地图片。支持远程和本地
- 参数:
inputUrl:输入图像的 URL,不能为空。outputUrl:输出图像的 URL,不能为空。
- 返回值:如果导出过程中出现错误,返回一个
NSError对象;如果导出成功,返回nil。 - 示例代码:
INSExportImageSimplify *exporter = [[INSExportImageSimplify alloc] init];
NSURL *inputUrl = [NSURL fileURLWithPath:@"path/to/input.jpg"];
NSURL *outputUrl = [NSURL fileURLWithPath:@"path/to/output.jpg"];
NSError *error = [exporter exportImageWithInputUrl:inputUrl outputUrl:outputUrl];
if (error) {
NSLog(@"导出失败:%@", error.localizedDescription);
} else {
NSLog(@"导出成功");
}HDR 图像合成方法(仅支持本地HDR图片)
X3及更早机型的HDR需在机外合成,拍摄完成后请下载HDR素材集到本地,再调用此接口进行合成。
- (NSError*)exportHdrImageWithInputUrl:(nonnull NSArray<NSURL*> *)inputUrl outputUrl:(nonnull NSURL *)outputUrl;- 功能:
- 该功能主要用于导出高动态范围(HDR)图像。它仅支持本地图像,这意味着图像必须存储在本地设备上才能进行导出操作。此外,为了确保导出的质量和效果,要求输入的图像数量至少为 3 张。
- 参数:
inputUrl:这是一个输入图像的 URL 数组。该数组不能为空,且其中的元素数量必须大于等于 3。这些 URL 指向的是需要进行 HDR 导出的本地图像。outputUrl:指定输出图像的 URL。同样,该参数也不能为空,它用于确定导出后的 HDR 图像的存储位置。
- 返回值:
- 在导出过程中,如果出现任何错误,将会返回一个
NSError对象。这个对象包含了有关错误的详细信息,以便开发者进行错误处理和调试。 - 如果导出成功,没有任何错误发生,那么返回值将为
nil,表示操作顺利完成。
- 在导出过程中,如果出现任何错误,将会返回一个
- 示例代码:
INSExportImageSimplify *exporter = [[INSExportImageSimplify alloc] init];
NSArray<NSURL*> *inputUrls = @[[NSURL fileURLWithPath:@"path/to/input1.jpg"], [NSURL fileURLWithPath:@"path/to/input2.jpg"], [NSURL fileURLWithPath:@"path/to/input3.jpg"]];
NSURL *outputUrl = [NSURL fileURLWithPath:@"path/to/output_hdr.jpg"];
NSError *error = [exporter exportHdrImageWithInputUrl:inputUrls outputUrl:outputUrl];
if (error) {
NSLog(@"导出失败:%@", error.localizedDescription);
} else {
NSLog(@"导出成功");
}参数说明
参考视频参数,图片参数是视频参数的子集。区别点:图片导出没有回调方法,直接通过返回值返回错误信息。
错误码
typedef NS_ENUM(NSInteger, INSExportSimplifyError) {
INSExportSimplifyErrorSuccess = 0,// 成功
INSExportSimplifyErrorInitFailed = 3001, // 导出失败
INSExportSimplifyErrorImageInitFailed = 4001, // 初始化失败
};日志功能
在 INSCoreMedia 这个库当中,关于日志的管理工作能够借助 INSRegisterLogCallback 类来完成。该类提供了颇为丰富的功能。其一,它支持对日志输出路径进行灵活配置。开发者可以依据自身项目的需求,将日志输出到指定的文件或者存储位置,这样便于后续对日志进行集中查看与分析。其二,该类还具备日志等级过滤的功能。不同等级的日志,例如调试级、信息级、警告级、错误级等,在项目开发和运行的不同阶段有不同的重要性。通过配置过滤等级,可以只输出特定等级及以上的日志,从而减少不必要的日志信息干扰,提高开发和调试的效率。
除此之外,INSCoreMedia 还支持注册回调。用户能够通过注册回调函数,在回调中实现对日志的自定义处理。比如,可以在回调中将日志信息打印到控制台,方便开发者在调试过程中实时查看日志内容;也可以将日志存储成 log 文件,便于后续对历史日志进行详细的追溯和分析,为项目的维护和优化提供有力的数据支持。
配置log输出文件:
/**
1, 如果配置log包含文件输出,需要设置文件路径
2, 设置输出log级别,大于等于该级别的log将会输出
*/
- (void)configLogKind:(InsLogKind)kind minLogLevel:(InsLogLevel)level optionalFullFilePath:(NSString * __nullable)fullFilePath;注册回调:
/**
注册Custom log接收的回调
*/
- (void)registerLogCallBack:(void(^)(NSString *_Nonnull tag, InsLogLevel level, NSString * _Nonnull fileName, NSString * _Nonnull funcName, int line, NSString *_Nonnull message))block;
- (void)registerLogCallBackBmg:(void(^)(InsLogLevel level,NSString *_Nonnull message))block;常见问题
HDR拍摄返回URI相关问题
- x4,x5支持机内HDR融合,打开机内融合之后,HDR合成将在相机中合成,合成之后仅生成一个合成之后的图
- x3及以前的相机拍摄HDR图像会返回多个uri,但是在以后的相机如x4,x5不论是否开启机内合成,仅会返回一个uri(固件端未支持)
