API 문서
RTSP & 백채널 제어문서

RTSP 통신문서

cctv와 video, audio등 rtsp을 통해서 양방향 사용되는 프로토콜입니다.
rtsp://admin:xxxx@ip:port/채널이름 형식으로 사용됩니다.

오디오 / 비디오 스트리밍

cctv는 음성을 pcmu 8000hz 8bit mono로 전달을 하고 비디오는 h264로 전달을 합니다. 그렇기 때문에 webrtc를 통해서 음성을 cctv의 백채널로 전달을 하기위해서는 pcmu 그대로 전달해야합니다.

아래와 같이 webrtc음성을 받으면 자체적으로 timestamp, seq를 증가시키고 rtsp를 통해서 cctv로 전달을 합니다.

func (w *worker) webrtcVoiceToToCCTVVoice(audioReceiveData *rtp.Packet, timestamp *uint32, seq *uint16) {
	p := rtp.Packet{
		Payload: audioReceiveData.Payload,
		Header: rtp.Header{
			PayloadType:    0,
			Marker:         true,
			Timestamp:      *timestamp,
			SequenceNumber: *seq,
			SSRC:           audioReceiveData.SSRC,
			CSRC:           audioReceiveData.CSRC,
			Version:        audioReceiveData.Version,
		},
	}
 
	*timestamp += uint32(len(audioReceiveData.Payload))
	*seq++
	encodePacket, _ := p.Marshal()
	frame := w.createInterleavedFrame(encodePacket)
	if _, err := w.rtspClient.SendPacket(frame); err != nil {
		log.Errorf("RTSPClient.SendPacket Error", err)
		w.errorChan <- fmt.Sprintf("rtspClient SendPacket %s", err.Error())
		return
	}
}

비디오 전송을 위해서는 아래와 같이 cctv로 받은 비디오 스트림의 packet payload데이타를 H.264 비디오 스트림을 WebRTC에서 사용할 수 있는 형식으로 변환하여 전송하는 작업을 수행합니다. H.264 비디오 스트림은 SPS (Sequence Parameter Set)와 PPS (Picture Parameter Set)와 같은 필수 헤더 정보를 포함해야하며 아래와 같습니다.

append([]byte{0, 0, 0, 1}, ...) 이유:

H.264 비디오 데이터는 NAL (Network Abstraction Layer) 유닛으로 분리되어 전송됩니다. 0x00 0x00 0x00 0x01은 NAL 유닛의 시작을 나타내는 마커입니다.

cctvVideoReceiveData.codec.SPS() 및 cctvVideoReceiveData.codec.PPS(): 이 함수들은 각각 Sequence Parameter Set(SPS)와 Picture Parameter Set(PPS)를 반환합니다. SPS와 PPS는 H.264 비디오 스트림에서 압축을 위해서 필수적인 헤더 정보입니다.

cctvVideoReceiveData.packet.Data[4:]: 패킷의 데이터 부분에서 헤더 정보를 제외한 나머지 비디오 데이터입니다.

비키프레임 처리: 비키프레임의 경우, 0x00 0x00 0x00 0x01 마커와 비디오 데이터만 포함됩니다.

// cctv 비디오 -> webrtc
func (w *worker) cctvVideoToWebRTCVideo(cctvVideoReceiveData *AvPacket) {
	var packetData []byte
	if cctvVideoReceiveData.packet.IsKeyFrame {
		packetData = append([]byte{0, 0, 0, 1}, bytes.Join([][]byte{cctvVideoReceiveData.codec.SPS(), cctvVideoReceiveData.codec.PPS(), cctvVideoReceiveData.packet.Data[4:]}, []byte{0, 0, 0, 1})...)
	} else {
		packetData = append([]byte{0, 0, 0, 1}, cctvVideoReceiveData.packet.Data[4:]...)
	}
	if w.videoTrack != nil {
 
		if err := w.videoTrack.WriteSample(media.Sample{Data: packetData, Duration: cctvVideoReceiveData.packet.Duration}); err != nil {
			w.errorChan <- fmt.Sprintf("videoTrack WriteSample %s", err.Error())
			log.Errorf("Failed to write sample to video track: %v", err)
		}
	}
}

백채널로 음성 전달 방법

webRTC를통해서 관리자와 사용자간에 음성을 전달을 하기위해서는 rtsp를 통해서 음성을 전달해야합니다. 일반적으로 rtp통신을 하지만 rtp통신으로 음성을 전달을 하면 소리가 나지 않습니다.

Interleaved Packets

Interleaving

"Interleaved"라는 용어는 RTP 패킷이 RTSP 컨트롤 메시지와 같은 채널을 통해 전송된다는 것을 의미합니다. 이는 RTSP가 전송 채널을 설정하고 RTP 데이터가 그 채널을 통해 전송되도록 하기 때문에, RTP와 RTSP가 동일한 연결을 공유하는 것을 나타냅니다.

이유 : Interleaving을 사용하면 RTSP와 RTP가 동일한 TCP 연결을 공유하므로 방화벽 및 NAT 통과 이슈 등을 해결할 수 있습니다.

Interleaved 프레임 구조

아래와 같이 4byte를 붙여서 그이외는 RTP패킷 정보를 구성한다.

  • (2바이트) 헤더: 첫 바이트: 0x24 (특정 의미를 가짐, 예를 들어 프레임 시작을 나타낼 수 있음) 두 번째 바이트: 채널 번호 (여기서는 0x04)
  • (2바이트) 길이 필드: RTP 패킷의 길이를 나타냄
  • RTP 데이터: packet Data
데이타 전송 방법

아래와 같이 rtp.Packet(RTP) 추가로 4byte를 붙여서 전송을 합니다.

// rtsp interleaveframe packet 생성 4byte
func (w *worker) createInterleavedFrame(rtpPacket []byte) []byte {
	var buffer bytes.Buffer
 
	channel := byte(4) // RTP 데이터 채널
	header := []byte{0x24, channel} // 0x24 RTSP interleaved 프레임의 시작
 
	lengthBuffer := new(bytes.Buffer)
	length := uint16(len(rtpPacket))
	_ = binary.Write(lengthBuffer, binary.BigEndian, length)
 
	buffer.Write(header)
	buffer.Write(lengthBuffer.Bytes())
	buffer.Write(rtpPacket)
	return buffer.Bytes()
}

Go RTSP제어를 위해서 vdk lib사용

golang rtsp제어를 위해서 vdk lib를 사용했습니다. 하지만, vdk에서 만든 라이브러리와 저희가 필요한 기능에서 몇가지 차이가 있어서 수정을 하였습니다. 그래서 현재 rtspback에서는 vdk라이브러리를 포함해서 배포했습니다.

실제 그에 따른 vdk/format/rtspv2/client쪽 파일을 확인해서 처리해야합니다.

수정사항

RTSP 명령어는 다음과 같은 형식을 가집니다.

SETUP: 스트리밍 세션을 설정하고 미디어 스트림의 전송 방법을 지정합니다.
PLAY: 미디어 스트리밍을 시작합니다.
PAUSE: 미디어 스트리밍을 일시 정지합니다.
TEARDOWN: 스트리밍 세션을 종료합니다.
DESCRIBE: 미디어의 메타데이터를 요청합니다.
OPTIONS: 서버에서 지원하는 명령어와 옵션을 요청합니다.
ANNOUNCE: 서버에 미디어 스트림을 알립니다 (일반적으로 SIP와 함께 사용됨).

모든 요청 Header에 아래와 같은 backchannel처리를 추가합니다. 기타 수정처리 필요함. 추가 문서로 대체함.

"Require": "www.onvif.org/ver20/backchannel",