Allow various codecs.

It is now possible to specify codecs other than VP8 and Opus.  This
turns out not to be very useful, since VP8 is the only codec supported
by all browsers (in violation of the WebRTC spec, which mandates support
for H.264), and there is no good reason to use anything other than Opus
for audio.
This commit is contained in:
Juliusz Chroboczek
2020-12-25 17:33:44 +01:00
parent 6c8e20c445
commit 5d38b0a231
6 changed files with 331 additions and 40 deletions
+81
View File
@@ -46,3 +46,84 @@ func TestVP8Keyframe(t *testing.T) {
}
}
}
func TestVP9Keyframe(t *testing.T) {
ps := [][]byte{
{
0x80, 0xe2, 0x6c, 0xb9, 0xcd, 0xa2, 0x77, 0x5c,
0xea, 0xf0, 0x14, 0xe9, 0x8f, 0xbd, 0x90, 0x18,
0x0, 0x10, 0x0, 0x10, 0x1, 0x4, 0x1, 0x82, 0x49,
0x83, 0x42, 0x0, 0x0, 0xf0, 0x0, 0xf4, 0x2, 0x38,
0x24, 0x1c, 0x18, 0x10, 0x0, 0x0, 0x20, 0x40, 0x0,
0x22, 0x9b, 0xff, 0xff, 0xd7, 0xe6, 0xc0, 0xa,
0xf2, 0x32, 0xd4, 0xdd, 0xa3, 0x69, 0xc6, 0xca,
0xd1, 0x50, 0xeb, 0x1c, 0x1, 0x50, 0x91, 0xf6,
0x64, 0xc7, 0x35, 0xe9, 0x0, 0xfe, 0x76, 0xb2,
0xb, 0x4d, 0xd7, 0x35, 0x23, 0xf3, 0x9f, 0x7f,
0x86, 0x37, 0xb9, 0x65, 0x3a, 0xf9, 0x66, 0xa0,
0x6a, 0xb2, 0x9b, 0xb3, 0x36, 0x5b, 0x47, 0xf2,
0x26, 0x5c, 0xe2, 0x23, 0x4f, 0xff, 0xff, 0xff,
0xfe, 0xc3, 0x49, 0x6b, 0x14, 0x58, 0x4d, 0xdc,
0xd8, 0xf5, 0x76, 0x81, 0x2e, 0xb3, 0x7f, 0xff,
0xfe, 0x18, 0xc8, 0xf8, 0x1b, 0xf6, 0xee, 0xc3,
0xc, 0x6f, 0x23, 0x34, 0x80,
},
{
0x80, 0xe2, 0x4a, 0xb5, 0x1a, 0x33, 0x3f, 0x7b,
0x9c, 0xda, 0x7b, 0xd0, 0x8d, 0xec, 0x14, 0x86,
0x0, 0x40, 0x92, 0x88, 0x2c, 0x50, 0x83, 0x30,
0x10, 0x1c, 0x6, 0x3, 0x0, 0x82, 0x99, 0x15, 0xc8,
0x0, 0x0, 0x0, 0x0, 0x18, 0x70, 0x0, 0x0, 0x4c,
0x4, 0xa0,
},
}
var packet rtp.Packet
for i, p := range ps {
err := packet.Unmarshal(p)
if err != nil {
t.Errorf("Unmarshal(p%v): %v", i, err)
}
kf, kfKnown := isKeyframe("video/vp9", &packet)
if kf != (i == 0) || !kfKnown {
t.Errorf("isKeyframe(p%v): %v %v", i, kf, kfKnown)
}
}
}
func TestH264Keyframe(t *testing.T) {
ps := [][]byte{
{
0x80, 0xe6, 0xf, 0xae, 0xfa, 0x86, 0x3b, 0x49,
0x59, 0xbd, 0x79, 0xe7, 0x78, 0x0, 0xc, 0x67,
0x42, 0xc0, 0xc, 0x8c, 0x8d, 0x4e, 0x40, 0x3c,
0x22, 0x11, 0xa8, 0x0, 0x4, 0x68, 0xce, 0x3c,
0x80, 0x0, 0x1a, 0x65, 0xb8, 0x0, 0x4, 0x0, 0x0,
0x9, 0xe3, 0x31, 0x40, 0x0, 0x46, 0x76, 0x38, 0x0,
0x8, 0x2, 0x47, 0x0, 0x2, 0x7f, 0x3f, 0x77, 0x6f,
0x67, 0x80,
},
{
0x80, 0xe6, 0xf, 0xaf, 0xfa, 0x86, 0x46, 0x89,
0x59, 0xbd, 0x79, 0xe7, 0x61, 0xe0, 0x0, 0x40,
0x0, 0xbe, 0x40, 0x9e, 0xa0,
},
}
var packet rtp.Packet
for i, p := range ps {
err := packet.Unmarshal(p)
if err != nil {
t.Errorf("Unmarshal(p%v): %v", i, err)
}
kf, kfKnown := isKeyframe("video/h264", &packet)
if kf != (i == 0) || !kfKnown {
t.Errorf("isKeyframe(p%v): %v %v", i, kf, kfKnown)
}
}
}
+13 -1
View File
@@ -108,7 +108,8 @@ type rtpDownConnection struct {
}
func newDownConn(c group.Client, id string, remote conn.Up) (*rtpDownConnection, error) {
pc, err := c.Group().API().NewPeerConnection(group.IceConfiguration())
api := group.APIFromCodecs(remote.Codecs())
pc, err := api.NewPeerConnection(group.IceConfiguration())
if err != nil {
return nil, err
}
@@ -300,6 +301,17 @@ func (up *rtpUpConnection) Label() string {
return up.label
}
func (up *rtpUpConnection) Codecs() []webrtc.RTPCodecCapability {
up.mu.Lock()
defer up.mu.Unlock()
codecs := make([]webrtc.RTPCodecCapability, len(up.tracks))
for i := range up.tracks {
codecs[i] = up.tracks[i].Codec()
}
return codecs
}
func (up *rtpUpConnection) AddLocal(local conn.Down) error {
up.mu.Lock()
defer up.mu.Unlock()
+89
View File
@@ -30,6 +30,95 @@ func isKeyframe(codec string, packet *rtp.Packet) (bool, bool) {
return true, true
}
return false, true
case "video/vp9":
var vp9 codecs.VP9Packet
_, err := vp9.Unmarshal(packet.Payload)
if err != nil || len(vp9.Payload) < 1 {
return false, false
}
if !vp9.B {
return false, true
}
if (vp9.Payload[0] & 0xc0) != 0x80 {
return false, false
}
profile := (vp9.Payload[0] >> 4) & 0x3
if profile != 3 {
if (vp9.Payload[0] & 0x8) != 0 {
return false, true
}
return (vp9.Payload[0] & 0x4) == 0, true
} else {
if (vp9.Payload[0] & 0x4) != 0 {
return false, true
}
return (vp9.Payload[0] & 0x2) == 0, true
}
case "video/h264":
if len(packet.Payload) < 1 {
return false, false
}
nalu := packet.Payload[0] & 0x1F
if nalu == 0 {
// reserved
return false, false
} else if nalu <= 23 {
// simple NALU
return nalu == 5, true
} else if nalu == 24 || nalu == 25 || nalu == 26 || nalu == 27 {
// STAP-A, STAP-B, MTAP16 or MTAP24
i := 1
if nalu == 25 || nalu == 26 || nalu == 27 {
// skip DON
i += 2
}
for i < len(packet.Payload) {
if i+2 > len(packet.Payload) {
return false, false
}
length := uint16(packet.Payload[i])<<8 |
uint16(packet.Payload[i+1])
i += 2
if i+int(length) > len(packet.Payload) {
return false, false
}
offset := 0
if nalu == 26 {
offset = 3
} else if nalu == 27 {
offset = 4
}
if offset >= int(length) {
return false, false
}
n := packet.Payload[i + offset] & 0x1F
if n == 5 {
return true, true
} else if n >= 24 {
// is this legal?
return false, false
}
i += int(length)
}
if i == len(packet.Payload) {
return false, true
}
return false, false
} else if nalu == 28 || nalu == 29 {
// FU-A or FU-B
if len(packet.Payload) < 2 {
return false, false
}
if (packet.Payload[1] & 0x80) == 0 {
// not a starting fragment
return false, true
}
return (packet.Payload[1]&0x1F == 5), true
}
return false, false
default:
return false, false
}