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:
@@ -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
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user