Other versions of this page
Recording
The SDK lets you capture MP4 videos by merging the camera stream with audio stream from the microphone (remember to ask for permissions!). The quality of the results can be set with fine-grained APIs and is only limited by the capabilities of the current device's hardware, in terms of audio/video encoders, sensor resolution and frame rate, microphone availability and more.
Make sure you declare
CameraFeature.Video
CameraFeature.video
during manager initialization.
For anything video-related, you will interact with the manager's CameraRecorder
:
kotlinval recorder: CameraRecorder = manager.recorder
kotlinlet recorder: CameraRecorder = manager.recorder
Under the hood, the SDK uses a custom encoding and muxing pipeline that allows features that are normally hard to achieve, for example:
- ability to switch cameras while recording
- support for fast start MP4s, that is, streaming-friendly MP4 files that expose video metadata at the beginning of the file
Codecs
The following audio (AudioCodec
) and video (VideoCodec
) codecs are supported.
Type | Codec | Description |
---|---|---|
VideoCodec | H264 .h264 | H264 Advanced Video Coding (AVC), Main Profile. |
VideoCodec | H264Baseline .h264Baseline | H264 Advanced Video Coding (AVC), Baseline Profile. |
VideoCodec | H264High .h264High | H264 Advanced Video Coding (AVC), High Profile. |
VideoCodec | H265 .h265 | H265 High Efficiency Video Coding (HEVC), Main Profile. |
AudioCodec | Aac .aac | Low Complexity (LC) AAC codec. |
AudioCodec | AacLD .aacLD | Low Delay (LD) AAC codec. |
AudioCodec | AacELD .aacELD | Enhanced Low Delay (ELD) AAC codec. |
AudioCodec | AacHE .aacHE | High Efficiency (HE) AAC codec. |
Recording Quality
The first thing you may want to do is decide how "good" the final recording should be. It's not recommended to use settings of a higher quality than what's needed, as video recordings can easily bloat in size.
The AudioProfile
and VideoProfile
classes encapsulate all sorts of settings related to, respectively, audio and video
streams, in both their raw (right after acquisition) and encoded forms. Their meaning is pretty straightforward, for example:
AudioProfile.channels
represents the number of audio channels to be present in the output fileVideoProfile.frameRate
represents the number of video frames per second
After you determine the profiles you want (using one of the two techniques below), they must be passed to the recorder:
kotlinval recorder: CameraRecorder = manager.recorder
recorder.audioProfile.value = myAudioProfile // or null to disable
recorder.videoProfile.value = myVideoProfile
swiftlet recorder: CameraRecorder = manager.recorder
recorder.audioProfile = myAudioProfile // or nil to disable
recorder.videoProfile = myVideoProfile
Using presets
Presets are a collection of profiles that are tailored to the current device and are known to be supported. They are the easiest way for you to configure profiles. For video presets:
kotlinval codec: VideoCodec = VideoCodec.H264 // Or H265
val presets: VideoPresets = recorder.presets(codec) ?: return // codec not supported
// Choose profile among: .p360, .p480, .p540, .p720, .p1080, .p2160
val profile: VideoProfile = presets.p1080 ?: return // 1080p not supported: fallback to something else?
recorder.videoProfile.value = profile
swiftlet codec: VideoCodec = .h264 // Or h265
guard let presets: VideoPresets = recorder.presets(codec: codec) else { return } // codec not supported
// Choose profile among: .p360, .p480, .p540, .p720, .p1080, .p2160
guard let profile: VideoProfile = presets.p1080 else {
// 1080p not supported: fallback to something else?
return
}
recorder.videoProfile = profile
For audio presets, the logic is exactly the same, but the presets fields are called, from highest quality to lowest,
musicHq
, music
, musicLq
, voiceHq
, voice
, and voiceLq
.
Using custom profiles
In case you want to customize profiles with your own settings you must follow a two-steps procedure:
- Create a
Stub
(AudioProfile.Stub
orVideoProfile.Stub
) with your settings - Transform into a real profile with
makeProfile
. This checks whether it's supported or not and possibly adjusts some of the parameters
After that, the profile can be passed to CameraRecorder
as already shown previously. Check the following example for
video:
kotlinval stub: VideoProfile.Stub = VideoProfile.Stub(
codec = VideoCodec.H264,
majorSize = 1080,
minorSize = null, // let the engine choose
bitRate = 16000000,
frameRate = 60
)
val profile: VideoProfile = recorder.makeProfile(stub) ?: return // Not supported!
swiftlet stub: VideoProfile.Stub = VideoProfile.Stub(
codec: .h264,
majorSize: 1080,
minorSize: nil, // let the engine choose
bitRate: 16000000,
frameRate: 60
)
guard let profile: VideoProfile = recorder.makeProfile(stub: stub) else { return } // Not supported!
When one size is specified and there is not, you can also pass an aspectRatio
(like 16/9
) and let the engine figure
out the other dimensions based on that.
Recording APIs
Once profiles are chosen (or if you decide to use default profiles, for what it's worth), you can start recording.
Switching between cameras while recording is allowed: the SDK will seamlessly switch the video source from one sensor to the other and you'll see no artifacts in the final video.
Start and stop
To start recording, use CameraRecorder.record()
. This is a async / suspending function with a
single URL / String parameter which should point to a writable, empty location on disk.
The function must be called in a dedicated Task / coroutine because it represents the whole recording operation:
- once the function returns, the video is ready
- if it throws, recording has failed
kotlinscope.launch {
try {
recorder.record(myFilePath)
// Recording complete!
} catch (e: Throwable) {
// Something went wrong.
}
}
swiftTask {
do {
try await recorder.record(at: myURL)
// Recording complete!
} catch {
// Something went wrong.
}
}
To stop recording, simply call recorder.stop()
.
Pause and resume
While recording is ongoing, you can also toggle between a paused and recording state using the pause()
and resume()
APIs:
kotlin// CameraRecorder APIs
suspend fun pause() { ... }
suspend fun resume() { ... }
swift// CameraRecorder APIs
func pause() async throws { ... }
func resume() async throws { ... }