mirror of
https://github.com/pion/webrtc.git
synced 2025-09-27 19:42:19 +08:00

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.
113 lines
2.3 KiB
Go
113 lines
2.3 KiB
Go
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
// Package fmtp implements per codec parsing of fmtp lines
|
|
package fmtp
|
|
|
|
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 {
|
|
// MimeType returns the MimeType associated with
|
|
// the fmtp
|
|
MimeType() string
|
|
// Match compares two fmtp descriptions for
|
|
// compatibility based on the MimeType
|
|
Match(f FMTP) bool
|
|
// Parameter returns a value for the associated key
|
|
// if contained in the parsed fmtp string
|
|
Parameter(key string) (string, bool)
|
|
}
|
|
|
|
// Parse parses an fmtp string based on the MimeType
|
|
func Parse(mimeType, line string) FMTP {
|
|
var f FMTP
|
|
|
|
parameters := parseParameters(line)
|
|
|
|
switch {
|
|
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,
|
|
parameters: parameters,
|
|
}
|
|
}
|
|
|
|
return f
|
|
}
|
|
|
|
type genericFMTP struct {
|
|
mimeType string
|
|
parameters map[string]string
|
|
}
|
|
|
|
func (g *genericFMTP) MimeType() string {
|
|
return g.mimeType
|
|
}
|
|
|
|
// Match returns true if g and b are compatible fmtp descriptions
|
|
// The generic implementation is used for MimeTypes that are not defined
|
|
func (g *genericFMTP) Match(b FMTP) bool {
|
|
c, ok := b.(*genericFMTP)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
if !strings.EqualFold(g.mimeType, c.MimeType()) {
|
|
return false
|
|
}
|
|
|
|
for k, v := range g.parameters {
|
|
if vb, ok := c.parameters[k]; ok && !strings.EqualFold(vb, v) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
for k, v := range c.parameters {
|
|
if va, ok := g.parameters[k]; ok && !strings.EqualFold(va, v) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (g *genericFMTP) Parameter(key string) (string, bool) {
|
|
v, ok := g.parameters[key]
|
|
return v, ok
|
|
}
|