From ddf25e1fbe5d1ec185d59b09b1a0cec4268590ba Mon Sep 17 00:00:00 2001 From: saxon Date: Sat, 17 Nov 2018 17:43:04 +1030 Subject: [PATCH] rtp: started writing encoder for rtp. Needto work out what the packet type part of the header should be --- stream/rtp/encoder.go | 75 ++++++++++++++++++++++++++++++++++++++++++ stream/rtp/rtp.go | 10 ++---- stream/rtp/rtp_test.go | 4 ++- 3 files changed, 81 insertions(+), 8 deletions(-) diff --git a/stream/rtp/encoder.go b/stream/rtp/encoder.go index a5270a13..ada69395 100644 --- a/stream/rtp/encoder.go +++ b/stream/rtp/encoder.go @@ -26,3 +26,78 @@ LICENSE */ 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 +} diff --git a/stream/rtp/rtp.go b/stream/rtp/rtp.go index d7fca6b2..bdf81e93 100644 --- a/stream/rtp/rtp.go +++ b/stream/rtp/rtp.go @@ -31,8 +31,7 @@ LICENSE package rtp const ( - rtpVer = 2 - defaultHeadSize = 3 * 4 // bytes + rtpVer = 2 ) 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!") } - 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[1] |= p.M<<7 | p.PT buf[2] |= byte(p.SN >> 8) buf[3] |= byte(p.SN) - // Second lot of 4 bytes buf[4] |= byte(p.TS >> 24) buf[5] |= byte(p.TS >> 16) buf[6] |= byte(p.TS >> 8) buf[7] |= byte(p.TS) - // Third lot of 4 bytes buf[8] |= byte(p.SSRC >> 24) buf[9] |= byte(p.SSRC >> 16) buf[10] |= byte(p.SSRC >> 8) buf[11] |= byte(p.SSRC) - // Add payload and padding buf = append(buf, p.Payload...) if p.Padding != 0 { buf = append(buf, append(make([]byte, p.Padding-1, p.Padding), byte(p.Padding))...) diff --git a/stream/rtp/rtp_test.go b/stream/rtp/rtp_test.go index 1fe199f2..3d034c32 100644 --- a/stream/rtp/rtp_test.go +++ b/stream/rtp/rtp_test.go @@ -32,6 +32,7 @@ import ( "testing" ) +// TODO (saxon): add more tests var rtpTests = []struct { num int pkt Pkt @@ -66,7 +67,8 @@ func TestRtpPktToByteSlice(t *testing.T) { for _, test := range rtpTests { got := test.pkt.Bytes() 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) } } }