Add SelectSettings algorithm and Codec to video constraints

This commit is contained in:
Lukas Herman
2019-12-26 19:08:03 -08:00
parent 23d19f9f85
commit 5679e3c0d7
6 changed files with 121 additions and 20 deletions
+9
View File
@@ -0,0 +1,9 @@
package mediadevices
import "github.com/pion/webrtc/v2"
type Codec string
const (
CodecH264 = webrtc.H264
)
+8 -1
View File
@@ -31,7 +31,14 @@ func main() {
mediaDevices := mediadevices.NewMediaDevices(peerConnection)
s, err := mediaDevices.GetUserMedia(mediadevices.MediaStreamConstraints{})
s, err := mediaDevices.GetUserMedia(mediadevices.MediaStreamConstraints{
Video: mediadevices.VideoTrackConstraints{
Enabled: true,
Width: 800, // This is just an ideal value
Height: 480, // This is just an ideal value
Codec: mediadevices.CodecH264, // This is default, you may omit this
},
})
if err != nil {
panic(err)
}
+60 -11
View File
@@ -1,6 +1,9 @@
package mediadevices
import (
"fmt"
"math"
"github.com/pion/mediadevices/pkg/driver"
"github.com/pion/webrtc/v2"
)
@@ -20,23 +23,69 @@ type mediaDevices struct {
func (m *mediaDevices) GetUserMedia(constraints MediaStreamConstraints) (MediaStream, error) {
// TODO: It should return media stream based on constraints
d := driver.Manager.Query()[0]
err := d.Open()
if err != nil {
return nil, err
}
vd := d.(driver.VideoDriver)
spec := vd.Specs()[0]
trackers := make([]tracker, 0)
if constraints.Video.Enabled {
tracker, err := m.videoSelect(constraints.Video)
if err != nil {
return nil, err
}
tracker, err := newVideoTrack(m.pc, vd, spec, webrtc.H264)
if err != nil {
return nil, err
trackers = append(trackers, tracker)
}
s, err := NewMediaStream(tracker)
s, err := NewMediaStream(trackers...)
if err != nil {
return nil, err
}
return s, nil
}
func (m *mediaDevices) videoSelect(constraints VideoTrackConstraints) (tracker, error) {
videoFilterFn := driver.FilterKind(driver.Video)
drivers := driver.Manager.Query(videoFilterFn)
var bestDriver driver.VideoDriver
var bestSpec driver.VideoSpec
minFitnessDist := math.Inf(1)
for _, d := range drivers {
wasClosed := d.Status() == driver.StateClosed
if wasClosed {
err := d.Open()
if err != nil {
// Skip this driver if we failed to open because we can't get the specs
continue
}
}
vd := d.(driver.VideoDriver)
for _, spec := range vd.Specs() {
fitnessDist := constraints.fitnessDistance(spec)
if fitnessDist < minFitnessDist {
minFitnessDist = fitnessDist
bestDriver = vd
bestSpec = spec
}
}
if wasClosed {
// Since it was closed, we should close it to avoid a leak
d.Close()
}
}
if bestDriver == nil {
return nil, fmt.Errorf("failed to find the best setting")
}
if bestDriver.Status() == driver.StateClosed {
err := bestDriver.Open()
if err != nil {
return nil, fmt.Errorf("failed in opening the best video driver")
}
}
return newVideoTrack(m.pc, bestDriver, bestSpec, constraints.Codec)
}
+30 -1
View File
@@ -1,8 +1,37 @@
package mediadevices
import "github.com/pion/mediadevices/pkg/driver"
import "math"
type MediaStreamConstraints struct {
Audio MediaTrackConstraints
Video MediaTrackConstraints
Video VideoTrackConstraints
}
type MediaTrackConstraints bool
type VideoTrackConstraints struct {
Enabled bool
Width, Height int
Codec Codec
}
// fitnessDistance is an implementation for https://w3c.github.io/mediacapture-main/#dfn-fitness-distance
func (c *VideoTrackConstraints) fitnessDistance(s driver.VideoSpec) float64 {
var dist float64
if s.Width != c.Width {
actualWidth := float64(s.Width)
idealWidth := float64(c.Width)
dist += math.Abs(actualWidth-idealWidth) / math.Max(math.Abs(actualWidth), math.Abs(idealWidth))
}
if s.Height != c.Height {
actualHeight := float64(s.Height)
idealHeight := float64(c.Height)
dist += math.Abs(actualHeight-idealHeight) / math.Max(math.Abs(actualHeight), math.Abs(idealHeight))
}
return dist
}
+12 -2
View File
@@ -2,6 +2,14 @@ package driver
import "fmt"
type FilterFn func(Driver) bool
func FilterKind(k Kind) FilterFn {
return func(d Driver) bool {
return d.Info().Kind == k
}
}
type manager struct {
drivers map[string]Driver
}
@@ -21,10 +29,12 @@ func (m *manager) register(a Adapter) error {
return nil
}
func (m *manager) Query() []Driver {
func (m *manager) Query(f FilterFn) []Driver {
results := make([]Driver, 0)
for _, d := range m.drivers {
results = append(results, d)
if ok := f(d); ok {
results = append(results, d)
}
}
return results
+2 -5
View File
@@ -1,7 +1,6 @@
package mediadevices
import (
"fmt"
"math/rand"
"github.com/pion/codec"
@@ -25,7 +24,7 @@ type videoTrack struct {
encoder codec.Encoder
}
func newVideoTrack(pc *webrtc.PeerConnection, d driver.VideoDriver, spec driver.VideoSpec, codecName string) (*videoTrack, error) {
func newVideoTrack(pc *webrtc.PeerConnection, d driver.VideoDriver, spec driver.VideoSpec, codecName Codec) (*videoTrack, error) {
var err error
decoder, err := frame.NewDecoder(spec.FrameFormat)
if err != nil {
@@ -35,7 +34,7 @@ func newVideoTrack(pc *webrtc.PeerConnection, d driver.VideoDriver, spec driver.
var payloadType uint8
var encoder codec.Encoder
switch codecName {
case webrtc.H264:
default:
payloadType = webrtc.DefaultPayloadTypeH264
encoder, err = h264.NewEncoder(h264.Options{
Width: spec.Width,
@@ -43,8 +42,6 @@ func newVideoTrack(pc *webrtc.PeerConnection, d driver.VideoDriver, spec driver.
Bitrate: 1000000,
MaxFrameRate: 30,
})
default:
err = fmt.Errorf("%s is currently not supported", codecName)
}
if err != nil {