Wowza/WebRTC - 如何在相机翻转时重新协商视频格式

问题描述

我遵循了 here 的一些提示,在 iOS 上通过 WebRTC 进行演示/流式传输时使相机从前向后翻转。翻转本身有效,但是当 RTcmediaStream 中的视频轨道发生变化时,RTCPeerConnection 会再次调用 peerConnectionShouldNegotiate 委托方法。这是我当前的实现(它适用于前置摄像头视频的初始调用,但在视频翻转时第二次调用时失败):

func peerConnectionShouldNegotiate(_ peerConnection: RTCPeerConnection) {
        guard let stream = liveStream else {
            return
        }
        print("peerConnectionShouldNegotiate")
        peerConnection.offer(for: mediaConstraints) { (desc,err) in
            if let error = err {
                print("peerConnectionShouldNegotiate error",error)
            } else if let desc = desc {
                self.con?.setLocalDescription(desc,completionHandler: { (err) in
                    if let error = err {
                        print("set local desc error",error)
                    } else {
                        let message: [String: Any] = [
                            "direction": "publish","command": "sendOffer","streamInfo": [
                                "applicationName": stream.appName,"streamName": stream.streamName,"sessionId": self.sessionId
                            ],"sdp": [
                                "type": RTCSessionDescription.string(for: desc.type),"sdp": desc.sdp
                            ],"userData": [
                                "param1": "value1"
                            ]
                        ]
                        let messageData = try! JSONSerialization.data(withJSONObject: message,options: [])
                        let messageStr = String(data: messageData,encoding: .utf8)!
                        self.socket?.write(string: messageStr)
                    }
                })
            } else {
                print("this is a no no")
            }
        }
    }

来自信令服务器的 web-socket 响应带有错误和消息 Stream name is already in use: [my-stream-id]

我不知道我应该向 Wowza 的信令服务器发送什么样的消息来更新现有流中的视频格式。看来 sendOffer 试图开始一个新的蒸汽。很难找到任何关于此的文档。

解决方法

如果其他人遇到同样的问题,请在此处发布我的解决方案,我花了几天的反复试验才找到解决方案。

我真正需要的是在不重新协商 RTCPeerConnection 的情况下切换相机。我看到 javascript 示例,他们在 RTCRtpSender 上切换视频轨道,但这在 iOS 上不起作用,而且 iOS 框架也没有 replaceVideoTrack 方法存在于浏览器的 javascript WebRTC 库中。

我的解决方案是仅更新现有 RTCCameraVideoCapturer 上的相机,从而保留现有 RTCVideoSourceRTCVideoTrack

我最初创建视频轨道的调用是这样的:

    func createVideoTrack() -> RTCVideoTrack? {
        let devices = RTCCameraVideoCapturer.captureDevices()
        guard
            let camera = selectedCamera(devices: devices)
        else {
            return nil
        }
        let source = rtcPCFactory.videoSource()
        let format = selectFormat(formats: camera.formats)
        let dims = CMVideoFormatDescriptionGetDimensions(format.formatDescription)
        if dims.width > dims.height {
            videoSize = CGSize(width: CGFloat(dims.height),height: CGFloat(dims.width))
        } else {
            videoSize = CGSize(width: CGFloat(dims.width),height: CGFloat(dims.height))
        }
        let fps = selectFrameRate(ranges: format.videoSupportedFrameRateRanges)
        source.adaptOutputFormat(toWidth: 512,height: 288,fps: Int32(fps))
        let videoTrack = rtcPCFactory.videoTrack(with: source,trackId: internalStreamId + "v0")

        let capturer = RTCCameraVideoCapturer(delegate: source)
        capturer.startCapture(with: camera,format: format,fps: Int(fps))
        
        cameraPreviewView.captureSession = capturer.captureSession
        videoCapturer = capturer
        return videoTrack
    }

它成功地协商了对等连接,然后在翻转相机时我做到了:

    func updateCapturerCamera() {
        let devices = RTCCameraVideoCapturer.captureDevices()
        guard
            let camera = selectedCamera(devices: devices),let capturer = videoCapturer
        else {
            return
        }
        let format = selectFormat(formats: camera.formats)
        let dims = CMVideoFormatDescriptionGetDimensions(format.formatDescription)
        if dims.width > dims.height {
            videoSize = CGSize(width: CGFloat(dims.height),height: CGFloat(dims.height))
        }
        let fps = selectFrameRate(ranges: format.videoSupportedFrameRateRanges)
        capturer.startCapture(with: camera,fps: Int(fps))
    }

...并且相机翻转功能在实时视频流中发挥了魅力,无需重新协商连接。