Skip to content

Commit 31c2c0d

Browse files
committed
Fix AV1 and VP9 codec matching
Currently, AV1 or VP9 formats are matched regardless of the profile parameter. This was not noticeable until browsers started advertising multiple VP9 formats at the same time, each with a different profile ID, in order to allow the counterpart to send different streams on the basis of supported profiles. This causes two issues: first, the library includes in the SDP all formats passed by the browser, regardless of the fact that the profile ID is registered in the API or not. Then, the library is unable to choose the correct format for streaming, causing an intermittent failure. This patch fixes the matching algorithm and also covers the case in which the profile ID is missing, by using values dictated by specifications. Tests were refactored since previous ones covered the same lines multiple times.
1 parent fc3521e commit 31c2c0d

File tree

5 files changed

+573
-235
lines changed

5 files changed

+573
-235
lines changed

internal/fmtp/av1.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
2+
// SPDX-License-Identifier: MIT
3+
4+
package fmtp
5+
6+
type av1FMTP struct {
7+
parameters map[string]string
8+
}
9+
10+
func (h *av1FMTP) MimeType() string {
11+
return "video/av1"
12+
}
13+
14+
func (h *av1FMTP) Match(b FMTP) bool {
15+
c, ok := b.(*av1FMTP)
16+
if !ok {
17+
return false
18+
}
19+
20+
// AV1 RTP specification:
21+
// If the profile parameter is not present, it MUST be inferred to be 0 (“Main” profile).
22+
hProfile, ok := h.parameters["profile"]
23+
if !ok {
24+
hProfile = "0"
25+
}
26+
cProfile, ok := c.parameters["profile"]
27+
if !ok {
28+
cProfile = "0"
29+
}
30+
if hProfile != cProfile {
31+
return false
32+
}
33+
34+
return true
35+
}
36+
37+
func (h *av1FMTP) Parameter(key string) (string, bool) {
38+
v, ok := h.parameters[key]
39+
return v, ok
40+
}

internal/fmtp/fmtp.go

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@ import (
88
"strings"
99
)
1010

11+
func parseParameters(line string) map[string]string {
12+
parameters := make(map[string]string)
13+
14+
for _, p := range strings.Split(line, ";") {
15+
pp := strings.SplitN(strings.TrimSpace(p), "=", 2)
16+
key := strings.ToLower(pp[0])
17+
var value string
18+
if len(pp) > 1 {
19+
value = pp[1]
20+
}
21+
parameters[key] = value
22+
}
23+
24+
return parameters
25+
}
26+
1127
// FMTP interface for implementing custom
1228
// FMTP parsers based on MimeType
1329
type FMTP interface {
@@ -23,29 +39,30 @@ type FMTP interface {
2339
}
2440

2541
// Parse parses an fmtp string based on the MimeType
26-
func Parse(mimetype, line string) FMTP {
42+
func Parse(mimeType, line string) FMTP {
2743
var f FMTP
2844

29-
parameters := make(map[string]string)
30-
31-
for _, p := range strings.Split(line, ";") {
32-
pp := strings.SplitN(strings.TrimSpace(p), "=", 2)
33-
key := strings.ToLower(pp[0])
34-
var value string
35-
if len(pp) > 1 {
36-
value = pp[1]
37-
}
38-
parameters[key] = value
39-
}
45+
parameters := parseParameters(line)
4046

4147
switch {
42-
case strings.EqualFold(mimetype, "video/h264"):
48+
case strings.EqualFold(mimeType, "video/h264"):
4349
f = &h264FMTP{
4450
parameters: parameters,
4551
}
52+
53+
case strings.EqualFold(mimeType, "video/vp9"):
54+
f = &vp9FMTP{
55+
parameters: parameters,
56+
}
57+
58+
case strings.EqualFold(mimeType, "video/av1"):
59+
f = &av1FMTP{
60+
parameters: parameters,
61+
}
62+
4663
default:
4764
f = &genericFMTP{
48-
mimeType: mimetype,
65+
mimeType: mimeType,
4966
parameters: parameters,
5067
}
5168
}

0 commit comments

Comments
 (0)