Event Download
Pre-requisite: The user has to be signed in to perform the following operations.
EventDownloader builds the commands needed to turn a recorded event into a local video file or a still image. The SDK fetches the event’s playlist with eventM3U8, appends the Authorization token to every segment, writes the rewritten playlist to the temporary directory and builds the FFmpeg command against that file. Only the probe and the FFmpeg execution are delegated to the app through the closures; executeProbe is not called for snapshots. The call fails with IVError.customError("Authorization token is missing in URL") if the URL carries no token.
EventDownloader.instance
The camera type is passed as EventDownloader.CameraType, which is either .camera or .nvr.
Build the Download Command
To build the command for a recorded event, The following method can be used:
cameraType(optional):.cameraor.nvr. Defaults to.camera.url(required): The playlist url of the event, including its authorization query parameter.isSnapshot(optional): Pass true to produce a still image instead of a video.size(optional): The output size. Passnilto keep the native resolution.hardwareConfig(optional): The hardware config of the camera, for stitched multi sensor output.executeProbe(required): Called with a ready to run probe command. Run it and pass its output back through the suppliedresultclosure, exactly once. The SDK reads the codec name, width and height from that output to decide whether the video can be copied or has to be re-encoded, so pass the output through unparsed. It is not called for snapshots.executeFFmpeg(required): Called once with the final command and the paths it will write, or with an error. Run the command; when it succeeds the files are waiting at those paths.
EventDownloader.instance.buildCommand(
url: eventURL,
isSnapshot: false,
size: outputSize,
hardwareConfig: HardwareConfig(
sensorResolution: nil,
displayResolution: nil,
stitchedSensors: event.hardwareProperties?.stitchedSensors
),
executeProbe: { command, result in
FFprobeKit.executeAsync(command) { session in
guard let session,
ReturnCode.isSuccess(session.getReturnCode()),
let output = session.getOutput() else {
result(.failure(DownloadError.probeFailed))
return
}
result(.success(output)) // the probe output, exactly as printed
}
},
executeFFmpeg: { outcome in
switch outcome {
case let .success((command, outputPaths)):
FFmpegKit.executeAsync(command) { session in
guard let session, ReturnCode.isSuccess(session.getReturnCode()) else {
self.downloadFailed(event, nil)
return
}
// The files are written now. They live in the temporary directory,
// so move them somewhere durable before the system reclaims them.
self.save(outputPaths, for: event)
}
case let .failure(error):
self.downloadFailed(event, error)
}
}
)
Both closures may be called on a background queue, so hop to the main queue before touching UI. A multi sensor event produces one file per sensor, which is why outputPaths is an array — a single sensor event returns one path in it.
FFmpeg and FFprobe are yours, not the SDK’s. IVSDK builds command strings and never runs them; it does not link FFmpeg, and nothing is added to your binary by using
EventDownloader. Bringing your own build is the point of these two closures — the examples above use ffmpeg-kit, but any FFmpeg and FFprobe you can invoke with a command string and get output back from will do. Add the dependency yourself, and make sure your build includes the protocols the commands use —file,http,https,tcp,tlsand the MPEG-TS demuxer.
Daily Summaries
Summary videos are plain files rather than segmented playlists, so they have their own builder with no playlist rewrite:
EventDownloader.buildCommandForDailySummary(cameraType:url:size:hardwareConfig:executeProbe:executeFFmpeg:)
See Daily Summaries.