rtp: started writing encoder for rtp. Needto work out what the packet type part of the header should be

This commit is contained in:
saxon 2018-11-17 17:43:04 +10:30
parent 1a15889522
commit ddf25e1fbe
3 changed files with 81 additions and 8 deletions

View File

@ -26,3 +26,78 @@ LICENSE
*/ */
package rtp package rtp
import (
"io"
"time"
)
// Time related constants.
const (
rtpVer = 2
yes = 1
no = 0
ccCount = 0
// pcrFreq is the base Program Clock Reference frequency.
timestampFreq = 90000 // Hz
)
type Encoder struct {
dst io.Writer
clock time.Duration
frameInterval time.Duration
}
// NewEncoder returns an Encoder with the specified frame rate.
func NewEncoder(dst io.Writer, fps float64) *Encoder {
return &Encoder{
dst: dst,
frameInterval: time.Duration(float64(time.Second) / fps),
}
}
func (e *Encoder) Encode(nalu []byte) error {
pkt := Pkt{
Pkt{
V: rtpVer, // version
P: no, // padding
X: no, // header extension
CC: ccCount,
M: no, // NOTE: need to check if this works (decoders should ignore this)
PT: 6,
SN: 167,
TS: 160,
SSRC: 10,
Payload: []byte{0x00, 0x01, 0x07, 0xf0, 0x56, 0x37, 0x0a, 0x0f},
Padding: 0,
},
}
// Write rtp packet to
_, err := e.dst.Write(pkt.Bytes())
if err != nil {
return err
}
e.tick()
return nil
}
// tick advances the clock one frame interval.
func (e *Encoder) tick() {
e.clock += e.frameInterval
}
// TODO: alter and make this work for rtp
func (e *Encoder) pts() uint64 {
return uint64((e.clock + e.ptsOffset).Seconds() * pcrFreq)
}
// TODO: alter and apply this to rtp for sequence number
func (e *Encoder) ccFor(pid int) byte {
cc := e.continuity[pid]
const continuityCounterMask = 0xf
e.continuity[pid] = (cc + 1) & continuityCounterMask
return cc
}

View File

@ -32,7 +32,6 @@ package rtp
const ( const (
rtpVer = 2 rtpVer = 2
defaultHeadSize = 3 * 4 // bytes
) )
type Pkt struct { type Pkt struct {
@ -72,25 +71,22 @@ func (p *Pkt) Bytes() []byte {
panic("rtp: CC (CSRC count) not 0, but CSRC headers not yet supported!") panic("rtp: CC (CSRC count) not 0, but CSRC headers not yet supported!")
} }
buf := make([]byte, defaultHeadSize, defaultHeadSize+len(p.Payload)+p.Padding) const headSize = 3 * 4 // bytes
buf := make([]byte, headSize, headSize+len(p.Payload)+p.Padding)
// First 4 bytes
buf[0] |= p.V<<6 | p.P<<5 | p.CC buf[0] |= p.V<<6 | p.P<<5 | p.CC
buf[1] |= p.M<<7 | p.PT buf[1] |= p.M<<7 | p.PT
buf[2] |= byte(p.SN >> 8) buf[2] |= byte(p.SN >> 8)
buf[3] |= byte(p.SN) buf[3] |= byte(p.SN)
// Second lot of 4 bytes
buf[4] |= byte(p.TS >> 24) buf[4] |= byte(p.TS >> 24)
buf[5] |= byte(p.TS >> 16) buf[5] |= byte(p.TS >> 16)
buf[6] |= byte(p.TS >> 8) buf[6] |= byte(p.TS >> 8)
buf[7] |= byte(p.TS) buf[7] |= byte(p.TS)
// Third lot of 4 bytes
buf[8] |= byte(p.SSRC >> 24) buf[8] |= byte(p.SSRC >> 24)
buf[9] |= byte(p.SSRC >> 16) buf[9] |= byte(p.SSRC >> 16)
buf[10] |= byte(p.SSRC >> 8) buf[10] |= byte(p.SSRC >> 8)
buf[11] |= byte(p.SSRC) buf[11] |= byte(p.SSRC)
// Add payload and padding
buf = append(buf, p.Payload...) buf = append(buf, p.Payload...)
if p.Padding != 0 { if p.Padding != 0 {
buf = append(buf, append(make([]byte, p.Padding-1, p.Padding), byte(p.Padding))...) buf = append(buf, append(make([]byte, p.Padding-1, p.Padding), byte(p.Padding))...)

View File

@ -32,6 +32,7 @@ import (
"testing" "testing"
) )
// TODO (saxon): add more tests
var rtpTests = []struct { var rtpTests = []struct {
num int num int
pkt Pkt pkt Pkt
@ -66,7 +67,8 @@ func TestRtpPktToByteSlice(t *testing.T) {
for _, test := range rtpTests { for _, test := range rtpTests {
got := test.pkt.Bytes() got := test.pkt.Bytes()
if !reflect.DeepEqual(got, test.want) { if !reflect.DeepEqual(got, test.want) {
t.Errorf("unexpected error for test %v: got:%v want:%v", test.num, got, test.want) t.Errorf("unexpected error for test %v: got:%v want:%v", test.num, got,
test.want)
} }
} }
} }