Currently on V1.9.2 branch. To view other versions, please switch branches.
Please visit https://www.insta360.com/sdk/apply to apply for the latest SDK.
Developers' Page: https://www.insta360.com/developer/home
Insta360 Enterprise: https://www.insta360.com/enterprise
Issue Report: https://insta.jinshuju.com/f/hZ4aMW
The iOS SDK is mainly used to connect, set and obtain camera parameters, control the camera to take pictures and record, download files, upgrade firmware, and support video and image export, etc.
Supported models: X5, X4 Air, X4, X3, ONE X2, ONE X, ONE RS, ONE RS 1-Inch.
- Locate the following dependency libraries in the provided sample project and drag them into the target project:
INSCoreMedia.xcframework
INSCameraServiceSDK.xcframework
INSCameraSDK.xcframework
SSZipArchive.xcframework
- In Xcode's Build Settings, add the build option TO_B_SDK=1, and then try compiling to confirm that the project can build normally.
Obtain the camera's connection status through the following methods:
INSCameraManager.socket().cameraStateIf the returned status is INSCameraStateConnected, it indicates a successful connection has been established. The status is defined as follows:
INSCameraManager.socket().cameraState
// There are the following states in total:
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,
};- Connection
After connecting the camera to the phone via Wi-Fi, you can invoke the interface in INSCameraSDK to establish a connection. This interface uses the singleton pattern: an instance is created upon the first call, and subsequent calls reuse the same instance.
INSCameraManager.socket().setup()- Disconnection
When you need to disconnect from the camera, call the following interface:
INSCameraManager.socket().shutdown()Note: Large data transfers are not supported when connected via Bluetooth. Therefore, functions involving the transfer of large data files are not supported.
Unsupported functions: Preview, retrieve supported list, download files, firmware upgrade, playback, export images.
- Search for Bluetooth Devices
Call the following method to scan Bluetooth devices
INSBluetoothManager().scanCameras- Establish a Bluetooth Connection
Establish a Bluetooth connection using the following interface:
- (id)connectDevice:(INSBluetoothDevice *)device
completion:(void (^)(NSError * _Nullable))completion;- Disconnect Bluetooth
- (void)disconnectDevice:(INSBluetoothDevice *)device;
While maintaining a connection with the camera, it is necessary to periodically send heartbeat packets to the camera. Otherwise, the camera will assume the connection has been lost, resulting in interrupted previews or invalid commands.
Typically, if no heartbeat is received within 30 seconds, the camera will actively disconnect.
Therefore, in scenarios requiring prolonged sessions—such as entering preview or recording modes—the application should continuously send heartbeat packets.
The following code example demonstrates how to use GCDTimer to send heartbeat commands at regular intervals, every 0.5 seconds:
func startSendingHeartbeats() {
let commandManager = INSCameraManager.shared().commandManager
print("Heartbeat task started")
// Send a heartbeat every 0.5 seconds to ensure the connection remains active.
GCDTimer.shared.scheduledDispatchTimer(
WithTimerName: "HeartbeatsTimer",
timeInterval: 0.5,
queue: DispatchQueue.main,
repeats: true
) {
commandManager.sendHeartbeats(with: nil)
print("Heartbeat sent")
}
}After establishing a Bluetooth connection, call the interface to retrieve Wi-Fi information. The sample code is as follows:
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))
}
⚠️ Note: After setting the country code, you must restart the camera's Wi-Fi for the settings to take effect. The channel depends on the country code, with each country corresponding to a different channel list. After restarting the camera, retrieve the channel list again to switch channels (both Bluetooth and Wi-Fi connections are supported).
- Retrieve the Current Country Code
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)
}
}
Note:
- Use
getOptionsWithTypesto retrieve the camera's current Wi-Fi channel list and country code information. - The callback returns
options.wifiChannelList, which can be viewed using a custom print function.
- Set the Country Code
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.")
}
}
}
Note:
- The
countryCodeparameter supports any ISO country code, such as “JP”, ‘US’, or “CN”. - After configuration, restart the camera's Wi-Fi for changes to take effect.
- The callback can be used to confirm whether the settings were applied successfully.
- Restart Wi-Fi and Set the Channel.
INSCameraManager.shared().commandManager.resetCameraWifi(channel)
INSCameraManager.shared().currentCamera?.name
The code can be called after establishing a connection with the camera
INSCameraManager.shared().currentCamera?.serialNumberINSCameraManager.shared().currentCamera?.firmwareRevisionlet 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
}
// Activation time
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
let date = Date(timeIntervalSince1970: Double(options.activateTime / 1000))
print("date :\(date)")
}@interface INSCameraStorageStatus : NSObject
// SD card status
@property (nonatomic) INSCameraCardState cardState;
// Available capacity size
@property (nonatomic) int64_t freeSpace;
// Total capacity size
@property (nonatomic) int64_t totalSpace;
// TODO: Restrict access to certain SDKs
@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
}
}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)")
}Notification string: INSCameraBatteryLowNotification
NotificationCenter.default.addObserver(self,
selector: #selector(self.batteryLowNotification(_:)),
name: NSNotification.Name.INSCameraBatteryLow,
object: nil)Callback example:
@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")
}Notification string: INSCameraStorageStatusNotification
NotificationCenter.default.addObserver(self,
selector: #selector(self.storageFullNotification(_:)),
name: NSNotification.Name.INSCameraStorageStatus,
object: nil)Status types:
typedef NS_ENUM(NSInteger, INSPBCardState) {
INSPBCardState_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
INSPBCardState_StorCsPass = 0, // Normal
INSPBCardState_StorCsNocard = 1, // No card
INSPBCardState_StorCsNospace = 2, // No space
INSPBCardState_StorCsInvalidFormat = 3, // Invalid format
INSPBCardState_StorCsWpcard = 4, // Write protection
INSPBCardState_StorCsOtherError = 5 // Other error
};Callback example:
@objc func storageFullNotification(_ notification: Notification) {
if let status = notification.userInfo?["card_state"] as? INSCameraCardState {
self.showAlert("Notification", "Battery Low :\(status)")
}
print("Notification: Storage Full")
}Notification string: INSCameraCaptureStoppedNotification
NotificationCenter.default.addObserver(self,
selector: #selector(self.captureStoppedNotification(_:)),
name: NSNotification.Name.INSCameraCaptureStopped,
object: nil)Callback example:
@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")
}Note: If any anomalies occur during recording, such as storage errors or excessive temperature, the device will automatically stop recording. In such cases, the user should be prompted to restart the operation to prevent loss of important content.
Notification string: INSCameraTemperatureStatusNotification
NotificationCenter.default.addObserver(self,
selector: #selector(self.temperatureValueNotification(_:)),
name: NSNotification.Name.INSCameraTemperatureStatus,
object: nil)Callback example:
@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")
}Note: High temperatures may cause reduced performance or even damage to the camera. Upon receiving this notification, users should be advised to cease operation and allow the camera to cool before resuming use.
The following is the enumeration of sensor device types (lens types) available for the camera:
typedef NS_ENUM(NSUInteger, INSSensorDevice) {
INSSensorDeviceUnknown, // Unknown
INSSensorDeviceFront, // Front
INSSensorDeviceRear, // Rear
INSSensorDeviceAll, // Panoramic
};
INSCameraManager.socket().commandManager.getActiveSensor { error, device, str1, str2 in
if error != nil {
self.showAlert("HDR Take:", "Failed!")
return
}
print("device:\(device)")
}- For cameras with interchangeable lenses (One RS, One R), use the following code to retrieve the current sensor type: Wide indicates wide-angle, Pano indicates panorama:
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()
}
}
Usage Notes:
activeSensorDevice: Pass the sensors type to switch to (e.g., .front, .rear, .all)
The preview has the following core classes; for details, refer to:demo:CameraConfigByJsonController
INSCameraSessionPlayer- Bind iOS-side
bounds - Implementation protocol:
INSCameraSessionPlayerDelegate - Implementation protocol:
INSCameraSessionPlayerDataSource, it is recommended to implement the following two protocols:- Configure Offset information:
updateOffsetToPlayer - Configure stabilization information:
updateStabilizerParamToPlayer
- Configure Offset information:
- Bind iOS-side
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)
}During the preview process, implementing the INSCameraSessionGyroDelegate protocol in INSCameraSessionPlayer enables real-time callbacks for stabilization data. The callback data exists in two formats: raw NSData and parsed INSGyroRawItem format.
@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;
@endThis module primarily covers camera mode switching, parameter configuration, and functions for retrieving the camera's current capturing mode and settings. The JSON configuration mechanism is a key focus.
The camera interface supports configuring all parameters, but note that not all parameters take effect in every mode. For example, setting the photo interval parameter in video recording mode is ineffective. To address this, the camera internally maintains a JSON configuration table defining the list of available parameters and their valid ranges for each mode.
Developers can download this JSON configuration table to accurately retrieve the available parameters and their corresponding values for different capture modes, enabling more rational and efficient camera control and configuration.
Additionally, we provide a management class, INSCameraAttrManagerWrapper, to maintain camera parameters and their dependencies. This class stores all camera parameters and determines parameter support and valid ranges based on the JSON configuration table. Refer to CameraConfigByJsonController.swift in the demo for usage details.
In practice, developers can first retrieve current parameters from the camera and set them in this class. Class methods can then be used to query parameter support status and available values.
For X4 and later cameras, capture modes and attributes are determined by the properties configured in the supported list. Different cameras support varying capture modes, and supported attributes also differ across modes. Before capturing, synchronize the camera's supported list (JSON file).
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?()
})
})Use the interface INSCameraManager.shared().commandManager.getOptionsWithTypes to retrieve the current camera's capture mode. This method requires the following parameters:
- optionTypes Specify which parameters to retrieve. Each parameter corresponds to an enumeration value (see INSCameraOptionsType) and must be converted to an
NSNumberarray. - requestOptions The maximum configurable request timeout duration (default 10 seconds).
- completion Returned in callback:
error:nilindicates successful retrieval; otherwise, contains the error reason.cameraOptions: Contains the current camera capture mode (capture mode is either photoSubMode or videoSubMode; see below for specific enumeration meanings).
Capture mode enumeration:
// Photo capturing
typedef NS_ENUM(NSUInteger, INSPhotoSubMode) {
INSPhotoSubModeSingle = 0,
INSPhotoSubModeHdr,
INSPhotoSubModeInterval,
INSPhotoSubModeBurst,
INSPhotoSubModeNightscape,
INSPhotoSubModeInstaPano,
INSPhotoSubModeInstaPanoHdr,
INSPhotoSubModeStarlapse,
INSPhotoSubModeNone = 100,
};
// Video recording
typedef NS_ENUM(NSUInteger, INSVideoSubMode) {
INSVideoSubModeNormal = 0,
INSVideoSubModeBulletTime,
INSVideoSubModeTimelapse,
INSVideoSubModeHDR,
INSVideoSubModeTimeShift,
INSVideoSubModeSuperVideo,
INSVideoSubModeLoopRecording,
INSVideoSubModeFPV,
INSVideoSubModeMovieRecording,
INSVideoSubModeSlowMotion,
INSVideoSubModeSelfie,
INSVideoSubModePure,
INSVideoSubModeLiveview,
INSVideoSubModeCameraLiveview,
INSVideoSubModeDashCam,
INSVideoSubModePTZ,
INSVideoSubModeNone = 100,
};Call 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?()
}
}The method INSCameraManager.shared().commandManager.setOptions configures the specified mode for the camera. When setting the capture mode, note the following key points:
- INSCameraOptions
Holds the capture mode configuration, primarily comprising two properties:
-
photoSubMode: Photo mode -
videoSubMode: Video mode -
INSCameraOptionsType
Specifies which parameters in INSCameraOptions should take effect:
- Photo mode:
INSCameraOptionsType::INSCameraOptionsTypePhotoSubMode - Video mode:
INSCameraOptionsType::INSCameraOptionsTypeVideoSubMode
The following is sample code (using photo mode configuration as an example):
// Photo Capture Mode Enumeration
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")
}The property in INSPhotographyOptions is:
@property (nonatomic) uint32_t whiteBalanceValue;The corresponding enumeration in INSPhotographyOptionsType is:
INSPhotographyOptionsTypeWhiteBalance = 13Assuming the current shooting mode INSCameraFunctionMode is 6, indicating standard photo capture.
- X2 and One X only support enumeration (
INSCameraWhiteBalance) settings; X3 and later models support usingwhiteBalanceValue.
@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,
};Adjustment is only supported when the exposure mode is set to “AUTO” or “FULL_AUTO”.
The property in INSPhotographyOptions is: exposureBias
@property (nonatomic) float exposureBias;The corresponding enumeration in INSPhotographyOptionsType is:
INSPhotographyOptionsTypeExposureBias = 7Adjustment is supported only in the “MANUAL” and “ISO_PRIORITY” exposure modes.
The respective properties in INSPhotographyOptions are: 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
@endThe corresponding enumeration in INSPhotographyOptionsType is:
INSPhotographyOptionsTypeStillExposureOptions = 20This parameter is only effective in timelapse mode.
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?()
})
}Starting from version 1.8.1, resolution is uniformly managed via enumeration. You must manually configure isUseJsonOptions to true.
INSPhotographyOptions.isUseJsonOptions = true- Photo
The property in INSPhotographyOptions is: photoSizeForJson
photoSizeForJson = 17`, indicating that the x4 camera has a resolution of `8192 x 6144
The corresponding enumeration in INSPhotographyOptionsType is:
INSPhotographyOptionsTypePhotoSize = 40Assuming the current shooting mode INSCameraFunctionMode is 6, indicating standard photo capture.
Code example:
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)")
})Correspondence between Resolution and Enumeration Values
"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"
}- Video
The property in INSPhotographyOptions is: videoResolutionForJson
Not displayed here; refer to the record_resolution list in the common_camera_setting_proto.json file.
The properties in INSPhotographyOptions are:
@property (nullable, nonatomic) INSCameraExposureOptions *stillExposure;
@interface INSCameraExposureOptions : NSObject
@property (nonatomic) uint8_t program; // Exposure mode
@property (nonatomic) NSUInteger iso;
#if TARGET_OS_IOS
@property (nonatomic) CMTime shutterSpeed;
#endif
@endThe corresponding enumeration in INSPhotographyOptionsType is:
INSPhotographyOptionsTypeStillExposureOptions = 20
"exposure_program": {
"AUTO": "0",
"ISO_PRIORITY": "1",
"SHUTTER_PRIORITY": "2",
"MANUAL": "3",
"ADAPTIVE": "4",
"FULL_AUTO": "5"
},Supports setting multiple parameters for the camera simultaneously, as follows:
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?()
})Note: The X5 defaults to PureShot mode and does not support disabling it.
The property in INSPhotographyOptions is:
@property (nonatomic) uint8_t rawCaptureType;The corresponding enumeration in INSPhotographyOptionsType is:
INSPhotographyOptionsTypeRawCaptureType = 25,Enumeration type:
"raw_capture_type": {
"OFF": "0",
"RAW": "1",
"PURESHOT": "3",
"PURESHOT_RAW": "4",
"INSP": "5",
"INSP_RAW": "6"
},When capturing photos, the camera internally splices panoramic images, eliminating the need for external splicing of source material. Supported only on x4 and later camera models.
var typeArray = [INSCameraOptionsType]()
let cameraOptions = INSCameraOptions()
// Open is true, Closed is 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?()
}The camera is obtained via the getPhotographyOptions method. The primary input parameters required are three: functionMode and optionTypes, along with a closure callback.
/*!
* @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: Indicates the current shooting modeoptionTypes: Each parameter corresponds to an enumeration value-
For example,
-
Resolution corresponds to:
INSPhotographyOptionsTypePhotoSize = 40 -
White balance corresponds to:
INSPhotographyOptionsTypeWhiteBalance = 13
-
- The closure returns an
NSErrorandINSPhotographyOptionsNSErrorbeingnilindicates success; otherwise, it contains the reason for failureINSPhotographyOptionscontains the specific values of current camera parameters, such as resolution, white balance, etc.
(Example) Retrieve the current camera white balance value:
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")")
})To configure camera parameters, use the method: INSCameraManager.shared().commandManager.setPhotographyOptions.
The primary input parameters are as follows:
INSPhotographyOptions: Stores the configured parametersINSPhotographyOptionsType: Indicates which parameters require configuration (each parameter corresponds to an enumeration)INSCameraFunctionMode: The current capture mode.- 相机设置需要的拍摄模式
INSCameraFunctionMode和从相机拿到的拍摄模式INSPhotoSubMode或INSVideoSubMode不能直接转换,对应关系参考工程文件中的类:HUMCaptureMode。通过HUMCaptureMode将相机当前模式INSPhotoSubMode或INSVideoSubMode转成统一的INSCameraFunctionMode - The camera settings require the
INSCameraFunctionMode, which cannot be directly converted from theINSPhotoSubModeorINSVideoSubModeobtained from the camera. It can refer to the classHUMCaptureModein the project documentation for the mapping relationship. UseHUMCaptureModeto convert the camera's current mode (INSPhotoSubMode or INSVideoSubMode) into the unified INSCameraFunctionMode.
- 相机设置需要的拍摄模式
- Closure callback: Returns whether the retrieval was successful.
All parameter types must be set to values supported by the camera screen and cannot be set arbitrarily.
Sample code is as follows: Set specified white balance
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 中涵盖照片的远程访问地址,可进行远程导出(无需下载至本地)。
The camera is commanded to take a photo via the INSCameraManager.shared().commandManager.takePicture method. If error is nil, the photo capture was successful; otherwise, it contains error information. The optionInfo contains the remote access URL for the photo, enabling remote export (without downloading to the local device).
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)")\
})Operation Method Change (x4 and Later Models):
For x4 and later models, switch to the corresponding capturing mode before initiating the shot.
let options:INSTakePictureOptions = INSTakePictureOptions()
INSCameraManager.shared().commandManager.takePicture(with: options, completion: { (error, optionInfo) in
guard let uri = optionInfo?.uri else {
return
}
})For HDR capturing on the X3 and earlier models, you need to set the mode to AEB mode in capturing parameters before taking the photo.
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
}
})You need to set the photographySelfTimer parameter using setPhotographyOptions, and set countDown to 0.
开始录制:
INSCameraManager.shared().commandManager.startCapture(with: nil, completion: { (err) in
if let err = err {
self.showAlert(row.tag!, "\(String(describing: err))")
return
}
})Stop recording
INSCameraManager.shared().commandManager.stopCapture(with: nil, completion: { (err, info) in
if let err = err {
self.showAlert(row.tag!, "\(String(describing: err))")
return
}
})Starting and stopping recording follows the standard procedure, but there are some important points to note:
- For the X5 and later models, if you need to save IMU data during timelapse recording, you must use our SDK for recording. Using our app for recording will not save IMU data.
- Furthermore, the IMU data storage function must be triggered by calling the following command:
Start recording
/*!
* 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;Stop recording
/*!
* 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;
In INSCameraSDK, all log information is passed to the upper layer as callbacks via the INSCameraSDKLoggerProtocol protocol. Upon receiving these logs, the upper layer can choose to print them for developers to observe the SDK's operational status during debugging.
Logs can also be stored persistently to support subsequent data analysis or troubleshooting. For detailed configuration methods, refer to the sample controller CameraConfigByJsonController.
Log callbacks are implemented via the INSCameraSDKLogger singleton object, which serves as the protocol delegate for INSCameraSDKLoggerProtocol.
Developers must assign their custom log delegate object to the logDelegate property of INSCameraSDKLogger to receive log messages of all levels output by the SDK.
The logging protocol INSCameraSDKLoggerProtocol includes the following methods:
@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;
@endWhen calling the capture interface, pass the INSMediaGps data into the capture parameters.
func pictureGps() {
// Constructing current location (GPS) data, using Hong Kong coordinate points as an example.
let newestLocation = CLLocation(
coordinate: CLLocationCoordinate2D(latitude: 22.2803, longitude: 114.1655), // 经纬度
altitude: 10.0, // Altitude (meters)
horizontalAccuracy: 5.0, // Horizontal Accuracy (meters)
verticalAccuracy: 5.0, // Vertical Accuracy (meters)
timestamp: Date() // Current Timestamp
)
// Create extended metadata objects (for attaching GPS, gyroscope, magnetometer, and other information)
let metaData = INSExtraMetadata()
// Create a media GPS information object using a constructed CLLocation.
let mediaGps = INSMediaGps(clLocation: newestLocation, isValidLocation: true)
// Write GPS information into the metadata
metaData.gps = mediaGps
// Create an extended information object and set its metadata (gyroscope data is not set here).
let extraInfo = INSExtraInfo(
version: Int32(INSExtraInfoVersion.one2.rawValue), // Using Extended Information Version one2
metadata: metaData, // Metadata with GPS information
gyroData: nil // No gyroscope data
)
// Construct a photo selection object containing extended information
let options: INSTakePictureOptions = INSTakePictureOptions(extraInfo: extraInfo)
// Call the camera to take a photo
INSCameraManager.shared().commandManager.takePicture(with: options, completion: { (error, optionInfo) in
print("end takePicture \(Date())") // Printing the photo capture completion time
// Extract the photo URI from the response data
guard let uri = optionInfo?.uri else {
return // If retrieval fails, return directly.
}
print("Take Picture Url:\(uri)") // Print the Url of the photo file
})
}After starting recording, transmit the constructed GPS data to the camera via uploadGpsDatas.
// Create an extra information object (typically used to pass extended parameters)
let extraInfo = INSExtraInfo()
// Create a recording parameter object and set extraInfo.
let options = INSCaptureOptions(extraInfo: extraInfo)
// Start capturing
self?.commandsManager.startCapture(with: options, completion: { (err) in
if let err = err {
// Startup failed, pop-up alert
print("\(row.title!) failed with error: \(err)")
self?.showAlert(row.title!, err.localizedDescription)
return
}
// Execute GPS data upload after a 5-second delay.
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
// Create a GPS data array (simulating 100 entries)
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)
}
// Convert to binary data format (optional: for debugging or uploading)
var datas = Data()
for gps in gpsDatas {
guard let gpsD = gps.toGpsData() else {
continue
}
datas.append(gpsD)
}
print("--- \(datas)") // Output debugging information
// Upload GPS data to the camera
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")
}
// Stop recording after upload completes.
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
}
})
})
}
})The App ID and secret required to activate the camera must be requested from Insta360:
guard let serialNumber = INSCameraManager.shared().currentCamera?.serialNumber else {
self?.showAlert("提示", "请先连接相机")
return
}
let commandManager = INSCameraManager.shared().commandManager
// You need to apply and enter your real app ID and 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")
})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")
})Note: Only supports X4 and X5
Screen Lock:
INSSetAccessCameraFileStateAccessStateLiveView
Turn off Screen Lock:
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
// The callback completion can be handled here
})
Command to control camera shutdown. Sample code is as follows:
Note: Only Insta360 X5 and later cameras support this feature.
INSCameraManager.socket().commandManager.closeCamera({_ in
})Proactively upgrade by calling updateFirwareWithOptions interface. 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,
};Video Export: INSExportSimplify Located in INSCoreMedia This class primarily simplifies video export operations, providing a set of configurable properties and methods to enable developers to customize the export process according to their needs. (Supports video export only).
This method ensures basic export functionality, with all parameters set to their default values. Users can configure relevant parameters according to specific requirements.
-(nonnull instancetype)initWithURLs:(nonnull NSArray<NSURL>)urls outputUrl:(nonnull NSURL*)outputUrl;- Function: Initializes an
INSExportSimplifyobject to specify an array of input video file URLs and the output video file URL. - Parameters:
urls: An array of input video file URLs. Cannot be empty.outputURL: The URL of the output video file. Cannot be empty.
- Return Value: Returns an
INSExportSimplifyobject. - Sample Code:
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;Cancel export. After exporting is complete, you must explicitly call the function; otherwise, it may cause a crash.
-(void)shutDown;This interface is used to output image resolution (aspect ratio must be 2:1).
/**
* Default width and height: 1920 × 960 (The exported aspect ratio must be 2:1)
*/
@property (nonatomic) int width;
@property (nonatomic) int height;There are a total of three stitching type, namely Dynamic stitching, Disflow stitching, and AI Flow stitching.
- Dynamic Stitching: Suitable for scenes containing close-ups, or situations involving motion and rapid changes.
- Disflow Stitching: The usage scenario is identical to Dynamic stitching.
- AI Flow stitching: Based on the optimized algorithm of Insta360's existing Disflow stitching technology, this mode delivers superior stitching results. It requires configuring the stitching model path
aiStitchPath. The model file is located in the project directory:model_export_v22_d7c49187.mlmodelc.
@property (nonatomic) NSString *aiStitchPath;
typedef NS_ENUM(NSInteger, INSOpticalFlowType) {
// Dynamic Stitching
INSOpticalFlowTypeDynamicStitch = 0,
// Disflow Stitching
INSOpticalFlowTypeDisflow = 1,
// AI Flow Stitching
INSOpticalFlowTypeAiFlow = 2,
};The stabilization mode supports the following options in total. For panoramic cameras, there are two modes: Still and Full Directional:
- Still: No matter how you rotate the camera, the view remains unchanged.
- Full Directional: The perspective always shifts with the camera's movement.
/**
* Stabilization mode, default: INSStabilizerStabModeZDirectional
*/
@property (nonatomic)INSStabilizerStabMode stabMode;
typedef NS_ENUM(NSInteger, INSStabilizerStabMode) {
/// Turn off Stabilization
INSStabilizerStabModeOff = -1,
/// Still
INSStabilizerStabModeStill,
/// Disable yaw stabilization for directional lock; the view can only move around the z-axis (pan movement).
INSStabilizerStabModeZDirectional,
/// Enable image stabilization and enable horizontal correction, i.e., full-directional
INSStabilizerStabModeFullDirectional,
///Without calibrating the horizon, i.e., free-footage, total free camera mode, camera can move through three axis
INSStabilizerStabModeFreeFootage,
/// //Process flipping
INSStabilizerStabModeFlipEffect,
///Enable image stabilization and average attitude correction, i.e.,relative-refine
INSStabilizerStabModeRelativeRefine,
///Enable anti-shake, enable level correction, i.e., absolute-refine
INSStabilizerStabModeAbsoluteRefine,
/// Bullet Time
INSStabilizerStabModeBulletTime,
/// Pano Fpv
INSStabilizerStabModePanoFPV
};If wearing lens guards during filming, configure this parameter according to the type. (Standard lens guards in the store is rated Class A, while premium lens guards is rated Class S.)
/**
* Lens Guards
*/
@property (nonatomic) INSOffsetConvertOptions protectType;
typedef NS_OPTIONS(NSUInteger, INSOffsetConvertOptions) {
INSOffsetConvertOptionNone = 0,
INSOffsetConvertOptionEnableWaterProof = 1 << 0, // ONE X lens guards
INSOffsetConvertOptionEnableDivingAir = 1 << 1, // Invisible dive case (Air)
INSOffsetConvertOptionEnableDivingWater = 1 << 2, // Invisible dive case(Water)
INSOffsetConvertOptionEnableDivingAirV2 = 1 << 3, // Invisible dive case (Air, V2)
INSOffsetConvertOptionEnableDivingWaterV2 = 1 << 4, // Invisible dive case (Water, V2)
INSOffsetConvertOptionEnableBuckleShell = 1 << 5, // Buckle shell
INSOffsetConvertOptionEnableAdhesiveShell = 1 << 6, // Adhesive shell
INSOffsetConvertOptionEnableGlassShell = 1 << 7, // Premium lens guards (S)
INSOffsetConvertOptionEnablePlasticCement = 1 << 8, // Standard lens guards (A)
INSOffsetConvertOptionEnableAverageShell = 1 << 9 // A/S average shell
};/**
* Color Fusion: Default false
*/
@property (nonatomic) BOOL colorFusion;The primary causes of chromatic aberration are as follows:
- First, since the two lenses operate independently, their respective video exposures may not align perfectly. When stitched together, noticeable brightness differences can occur. This stems from variations in capturing parameters and sensor performance between lenses, resulting in differing light intensities captured.
- Second, uneven lighting on either side of the lens leads to differing camera exposures, sometimes resulting in noticeable brightness differences between the front and rear lens footage. This phenomenon is particularly pronounced in high-contrast lighting scenarios, such as areas where bright light meets shadow, or environments with significant indoor-outdoor lighting disparities. In these cases, the camera struggles to balance light intensity across different zones, causing substantial brightness variations in the captured images.
To address these issues, Color Fusion technology was developed. Through a series of algorithms and image processing techniques, it adjusts and optimizes footage captured by different lenses to reduce or eliminate brightness discrepancies. This ensures the stitched video appears more natural and seamless.
This interface features a function to eliminate specific phenomena, specifically designed to counteract purple fringing caused by lighting conditions during recording. In real-world recording scenarios where lighting is complex and variable, this interface effectively addresses purple fringing issues arising from two common lighting situations. The first scenario involves intense outdoor sunlight. When recording during bright daylight hours, high-intensity outdoor light easily triggers purple fringing. This interface effectively eliminates fringing in such conditions. The second scenario pertains to indoor lighting. Light emitted by various indoor sources, such as incandescent bulbs or fluorescent lights, can also cause purple fringing in recorded footage. This interface similarly eliminates fringing in these indoor lighting scenarios.
Usage: To utilize this algorithm, configure the corresponding model managed via a JSON file: coreml_model_v2_scale6_scale4.json. Copy these models and JSON files into the app. Refer to the following code for parameter configuration:
Video
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)Photo
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 = depurpleFringInfoIn the field of video processing, multi-frame denoising technology is a crucial image processing method that can reduce or eliminate noise in video frames. Noise adversely affects image quality and viewing experience. Unlike single-frame denoising, which processes only a single frame, multi-frame denoising leverages redundant information from preceding and subsequent frames to more accurately distinguish between image content and noise. This approach preserves image details while removing noise, resulting in high-quality footage. However, multi-frame denoising also has drawbacks. It requires processing multiple frames, involving complex computational analysis that consumes system resources. This may cause devices to slow down or experience lag, while also reducing video export speed and increasing time costs.
/**
* Denoise
* This property controls whether to enable multi-frame noise reduction for video. When set to YES, noise reduction is enabled; when set to NO, noise reduction is disabled.
*/
@property (nonatomic) BOOL enableDenoise;/**
* Color enhancement, disabled by default
*/
@property (nonatomic) BOOL clolorPlus;After exporting begins, the INSRExporter2ManagerDelegate protocol will provide real-time callbacks regarding the export progress and status.
typedef NS_ENUM(NSInteger, INSExporter2State) {
INSExporter2StateError = -1, // Indicates that an error occurred during the export process.
INSExporter2StateComplete = 0, // Indicates that the export has been successfully completed.
INSExporter2StateCancel = 1, // Indicates that the user manually canceled the export operation.
INSExporter2StateInterrupt = 2, // Indicates that the export was unexpectedly interrupted.
INSExporter2StateDisconnect = 3, // Indicates disconnection from the server
INSExporter2StateInitError = 4, // Indicates an error occurred during initialization.
};
@protocol INSRExporter2ManagerDelegate <NSObject>
- (void)exporter2Manager:(INSExporter2Manager *)manager progress:(float)progress;
- (void)exporter2Manager:(INSExporter2Manager *)manager state:(INSExporter2State)state error:(nullable NSError*)error;
// Used for panoramic tracking detection (generally not required)
- (void)exporter2Manager:(INSExporter2Manager *)manager correctOffset:(NSString*)correctOffset errorNum:(int)errorNum totalNum:(int)totalNum clipIndex:(int)clipIndex type:(NSString*)type;
@endtypedef NS_ENUM(NSInteger, INSExporter2State) {
INSExporter2StateError = -1, // Indicates that an error occurred during the export process.
INSExporter2StateComplete = 0, // Indicates that the export has been successfully completed.
INSExporter2StateCancel = 1, // Indicates that the user manually canceled the export operation.
INSExporter2StateInterrupt = 2, // Indicates that the export was unexpectedly interrupted.
INSExporter2StateDisconnect = 3, // Indicates disconnection from the server
INSExporter2StateInitError = 4, // Indicates an error occurred during initialization.
};
};Photo Export: The INSExportImageSimplify class belongs to the INSCoreMedia framework. This class aims to simplify photo export operations by providing a set of configurable properties and methods. It supports exporting both standard photos and HDR photos, allowing developers to customize the export process according to their requirements.
- (NSError*)exportImageWithInputUrl:(nonnull NSURL *)inputUrl outputUrl:(nonnull NSURL *)outputUrl;- Functions: Exports standard photos, supporting both remote and local.
- Parameters:
inputURL: URL of the input image. Cannot be empty.outputURL: URL of the output image. Cannot be empty.
- Return Value: Returns an NSError object if an error occurs during export; returns nil if export succeeds.
- Sample Code:
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(@"导出成功");
}For X3 and earlier models, HDR needs to be composited externally. After shooting, please download the HDR footage to your local device and then use this interface to composite it.
- (NSError*)exportHdrImageWithInputUrl:(nonnull NSArray<NSURL*> *)inputUrl outputUrl:(nonnull NSURL *)outputUrl;- Function:
- This function is primarily used for exporting high dynamic range (HDR) images. It supports only local photos, which must be stored on the local device to perform the export operation. Additionally, to ensure the quality and effectiveness of the export, a minimum of 3 input photos is required.
- Parameters:
inputURL: An array of URLs for input photos. This array cannot be empty, and its elements must be greater than or equal to 3. These URLs point to local photos requiring HDR export.outputURL: Specifies the URL for the output photo. Similarly, this parameter cannot be empty and determines the storage location for the exported HDR photo.
- Return Values:
- During export, any errors encountered will return an
NSErrorobject. This object contains detailed error information for developer error handling and debugging. - If export succeeds without errors, the return value will be
nil, indicating the operation completed successfully.
- During export, any errors encountered will return an
- Sample Code:
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(@"导出成功");
}参考视频参数,图片参数是视频参数的子集。区别点:图片导出没有回调方法,直接通过返回值返回错误信息。
Refer to the video parameters; image parameters are a subset of video parameters. Key difference: Image export does not use callback methods; error messages are returned directly via the return value.
typedef NS_ENUM(NSInteger, INSExportSimplifyError) {
INSExportSimplifyErrorSuccess = 0,// Success
INSExportSimplifyErrorInitFailed = 3001, // Export failed
INSExportSimplifyErrorImageInitFailed = 4001, // Initialization failed
};
Within the INSCoreMedia library, log management tasks can be accomplished using the INSRegisterLogCallback class. This class offers a rich set of functionalities. First, it supports flexible configuration of log output paths. Developers can direct logs to specified files or storage locations based on project requirements, facilitating centralized log review and analysis later. Second, it features log level filtering. Logs of different levels—such as debug, info, warning, and error—hold varying importance during different stages of project development and operation. By configuring filter levels, developers can output only logs of specific levels or higher, reducing unnecessary log clutter and enhancing development and debugging efficiency.
Additionally, INSCoreMedia supports callback registration. Users can register callback functions to implement custom log processing within these callbacks. For instance, logs can be printed to the console in callbacks, enabling developers to view log content in real-time during debugging. Alternatively, logs can be stored as log files for detailed retrospective analysis and tracing, providing robust data support for project maintenance and optimization.
Configuring log output files:
/**
1. If the configuration includes file output for logging, the file path must be set.
2. Set the output log level; logs of this level or higher will be output.
*/
- (void)configLogKind:(InsLogKind)kind minLogLevel:(InsLogLevel)level optionalFullFilePath:(NSString * __nullable)fullFilePath;Registration callback:
/**
Custom log received callbacks
*/
- (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;- The x4 and x5 models support in-camera HDR merging. When in-camera merging is enabled, HDR synthesis occurs within the camera, resulting in a single merged image after processing.
- Cameras up to and including the X3 return multiple URIs when capturing HDR images. However, newer cameras such as the X4 and X5 return only one URI regardless of whether in-camera merging is enabled (not supported at the firmware level).