默认的声网视频模块可以与设备上已安装的 app 实现无缝互动。另外,声网 SDK 也支持使用自定义视频源,为你的 app 增加更多视频特性。
实时视频传输过程中,声网 SDK 通常会启动默认的视频模块进行采集。然而,在以下场景中,你可能会发现默认的视频模块无法满足开发需求。例如:
使用自定义视频渲染器管理视频采集和播放时,需要自行调用声网 SDK 以外的方法实现。
声网 SDK 提供 setExternalVideoSource
和 pushExternalVideoFrame
方法自定义视频采集。下图展示自定义视频采集 API 调用时序:
下图展示在 Push 模式下进行自定义视频采集时,视频数据的传输过程:
pushExternalVideoFrame
方法,将采集到的视频帧发送至 SDK。在进行操作之前,请确保你已经在项目中实现了基本的实时音视频功能。有关详细信息,请参考实现视频通话或实现视频直播。
参考如下步骤,在你的项目中实现自定义视频采集功能:
加入频道前,调用 setExternalVideoSource
开启自定义视频采集。一旦开启后,你将无法使用 SDK 中的方法采集视频帧。
// 调用 setExternalVideoSource 通知 SDK 你的 app 在使用自定义视频采集
agoraKit.setExternalVideoSource(true, useTexture: true, encodedFrame: true)
实现自定义视频采集。一旦开启自定义视频采集,你需要调用 SDK 以外的方法,自行实现视频的采集。例如,示例项目定义了 AgoraCameraSourcePush
类,并使用系统原生方法实现视频采集。
class AgoraCameraSourcePush: NSObject {
fileprivate var delegate: AgoraCameraSourcePushDelegate?
private var videoView: CustomVideoSourcePreview
private var currentCamera = Camera.defaultCamera()
private let captureSession: AVCaptureSession
private let captureQueue: DispatchQueue
private var currentOutput: AVCaptureVideoDataOutput? {
if let outputs = self.captureSession.outputs as? [AVCaptureVideoDataOutput] {
return outputs.first
} else {
return nil
}
}
// 初始化自定义视频采集
init(delegate: AgoraCameraSourcePushDelegate?, videoView: CustomVideoSourcePreview) {
self.delegate = delegate
self.videoView = videoView
captureSession = AVCaptureSession()
captureSession.usesApplicationAudioSession = false
let captureOutput = AVCaptureVideoDataOutput()
captureOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange]
if captureSession.canAddOutput(captureOutput) {
captureSession.addOutput(captureOutput)
}
captureQueue = DispatchQueue(label: "MyCaptureQueue")
// 将采集到的画面在图层上进行渲染
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoView.insertCaptureVideoPreviewLayer(previewLayer: previewLayer)
}
deinit {
captureSession.stopRunning()
}
// 开始视频帧采集
func startCapture(ofCamera camera: Camera) {
guard let currentOutput = currentOutput else {
return
}
// 将采集设备设置为当前摄像头
currentCamera = camera
currentOutput.setSampleBufferDelegate(self, queue: captureQueue)
captureQueue.async { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.changeCaptureDevice(toIndex: camera.rawValue, ofSession: strongSelf.captureSession)
strongSelf.captureSession.beginConfiguration()
if strongSelf.captureSession.canSetSessionPreset(AVCaptureSession.Preset.vga640x480) {
strongSelf.captureSession.sessionPreset = AVCaptureSession.Preset.vga640x480
}
strongSelf.captureSession.commitConfiguration()
strongSelf.captureSession.startRunning()
}
}
// 结束视频帧采集
func stopCapture() {
currentOutput?.setSampleBufferDelegate(nil, queue: nil)
captureQueue.async { [weak self] in
self?.captureSession.stopRunning()
}
}
// 切换采集摄像头
func switchCamera() {
stopCapture()
currentCamera = currentCamera.next()
startCapture(ofCamera: currentCamera)
}
}
AgoraCameraSourcePushDelegate
类被用于接收采集到的视频帧。
protocol AgoraCameraSourcePushDelegate {
func myVideoCapture(_ capture: AgoraCameraSourcePush, didOutputSampleBuffer pixelBuffer: CVPixelBuffer, rotation: Int, timeStamp: CMTime)
}
实现自定义视频渲染。在 push 模式下,声网 SDK 不支持对采集到的视频进行渲染。因此,你需要调用 SDK 外部方法实现自定义视频渲染。在示例项目中,我们基于系统原生的 AVCaptureVideoPreviewLayer
类定义了一个 CustomVideoSourcePreview
类。
// 初始化 localVideo
var localVideo = CustomVideoSourcePreview(frame: CGRect.zero)
// 定义 CustomVideoSourcePreview 类
class CustomVideoSourcePreview : UIView {
private var previewLayer: AVCaptureVideoPreviewLayer?
func insertCaptureVideoPreviewLayer(previewLayer: AVCaptureVideoPreviewLayer) {
self.previewLayer?.removeFromSuperlayer()
previewLayer.frame = bounds
layer.insertSublayer(previewLayer, below: layer.sublayers?.first)
self.previewLayer = previewLayer
}
override func layoutSublayers(of layer: CALayer) {
super.layoutSublayers(of: layer)
previewLayer?.frame = bounds
}
}
开始视频帧的采集和渲染。在示例项目中,我们基于 AgoraCameraSourcePush
类创建了一个 customCamera
实例,之后调用 startCapture
开始进行采集和渲染。
// 初始化 AgoraCameraSourcePush 类,将摄像头设置为采集设备
customCamera = AgoraCameraSourcePush(delegate: self, videoView:localVideo)
// 调用 AgoraCameraSourcePush 类中的 startCapture 方法,开始采集视频帧
customCamera?.startCapture(ofCamera: .defaultCamera())
将采集到的视频帧推送至 SDK。调用 pushExternalVideoFrame
方法,将采集到的视频帧推送至 SDK。
extension CustomVideoSourcePushMain:AgoraCameraSourcePushDelegate
{
func myVideoCapture(_ capture: AgoraCameraSourcePush, didOutputSampleBuffer pixelBuffer: CVPixelBuffer, rotation: Int, timeStamp: CMTime) {
let videoFrame = AgoraVideoFrame()
videoFrame.format = 12
videoFrame.textureBuf = pixelBuffer
videoFrame.time = timeStamp
videoFrame.rotation = Int32(rotation)
// 将采集到的视频帧推送至 SDK
agoraKit?.pushExternalVideoFrame(videoFrame)
}
}
本节介绍本文中使用方法的更多信息以及相关页面的链接。
声网在 GitHub 上提供了一个开源的示例项目。