Skip to content

Commit

Permalink
Fix AV1 and VP9 codec matching
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
aler9 committed May 27, 2024
1 parent 09461d5 commit 6e8adf0
Show file tree
Hide file tree
Showing 5 changed files with 573 additions and 235 deletions.
40 changes: 40 additions & 0 deletions internal/fmtp/av1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package fmtp

type av1FMTP struct {
parameters map[string]string
}

func (h *av1FMTP) MimeType() string {
return "video/av1"
}

func (h *av1FMTP) Match(b FMTP) bool {
c, ok := b.(*av1FMTP)
if !ok {
return false
}

// AV1 RTP specification:
// If the profile parameter is not present, it MUST be inferred to be 0 (“Main” profile).
hProfile, ok := h.parameters["profile"]
if !ok {
hProfile = "0"
}
cProfile, ok := c.parameters["profile"]
if !ok {
cProfile = "0"
}
if hProfile != cProfile {
return false
}

return true
}

func (h *av1FMTP) Parameter(key string) (string, bool) {
v, ok := h.parameters[key]
return v, ok

Check warning on line 39 in internal/fmtp/av1.go

View check run for this annotation

Codecov / codecov/patch

internal/fmtp/av1.go#L37-L39

Added lines #L37 - L39 were not covered by tests
}
45 changes: 31 additions & 14 deletions internal/fmtp/fmtp.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@ import (
"strings"
)

func parseParameters(line string) map[string]string {
parameters := make(map[string]string)

for _, p := range strings.Split(line, ";") {
pp := strings.SplitN(strings.TrimSpace(p), "=", 2)
key := strings.ToLower(pp[0])
var value string
if len(pp) > 1 {
value = pp[1]
}
parameters[key] = value
}

return parameters
}

// FMTP interface for implementing custom
// FMTP parsers based on MimeType
type FMTP interface {
Expand All @@ -23,29 +39,30 @@ type FMTP interface {
}

// Parse parses an fmtp string based on the MimeType
func Parse(mimetype, line string) FMTP {
func Parse(mimeType, line string) FMTP {
var f FMTP

parameters := make(map[string]string)

for _, p := range strings.Split(line, ";") {
pp := strings.SplitN(strings.TrimSpace(p), "=", 2)
key := strings.ToLower(pp[0])
var value string
if len(pp) > 1 {
value = pp[1]
}
parameters[key] = value
}
parameters := parseParameters(line)

switch {
case strings.EqualFold(mimetype, "video/h264"):
case strings.EqualFold(mimeType, "video/h264"):
f = &h264FMTP{
parameters: parameters,
}

case strings.EqualFold(mimeType, "video/vp9"):
f = &vp9FMTP{
parameters: parameters,
}

case strings.EqualFold(mimeType, "video/av1"):
f = &av1FMTP{
parameters: parameters,
}

default:
f = &genericFMTP{
mimeType: mimetype,
mimeType: mimeType,
parameters: parameters,
}
}
Expand Down
Loading

0 comments on commit 6e8adf0

Please sign in to comment.