mirror of https://bitbucket.org/ausocean/av.git
rtp: started writing encoder for rtp. Needto work out what the packet type part of the header should be
This commit is contained in:
parent
1a15889522
commit
ddf25e1fbe
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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))...)
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue