diff --git a/const.go b/const.go deleted file mode 100644 index 1ca0116..0000000 --- a/const.go +++ /dev/null @@ -1,9 +0,0 @@ -package mediadevices - -import "github.com/pion/webrtc/v2" - -type Codec string - -const ( - CodecH264 = webrtc.H264 -) diff --git a/examples/simple/main.go b/examples/simple/main.go index 4414078..47bae39 100644 --- a/examples/simple/main.go +++ b/examples/simple/main.go @@ -5,6 +5,7 @@ import ( "github.com/pion/mediadevices" "github.com/pion/mediadevices/examples/internal/signal" + _ "github.com/pion/mediadevices/pkg/codec/h264" // This is required to register h264 video encoder "github.com/pion/webrtc/v2" ) @@ -34,9 +35,9 @@ func main() { s, err := mediaDevices.GetUserMedia(mediadevices.MediaStreamConstraints{ Video: mediadevices.VideoTrackConstraints{ Enabled: true, - Width: 800, // Optional. This is just an ideal value. - Height: 480, // Optional. This is just an ideal value. - Codec: mediadevices.CodecH264, // Optional. H2642 is the default. + Width: 800, // Optional. This is just an ideal value. + Height: 480, // Optional. This is just an ideal value. + Codec: webrtc.H264, }, }) if err != nil { diff --git a/go.mod b/go.mod index 2a947e9..2dd0f75 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.13 require ( github.com/blackjack/webcam v0.0.0-20191123110216-08fa32efcb67 - github.com/pion/webrtc/v2 v2.1.12 + github.com/pion/webrtc/v2 v2.1.19-0.20200106051345-726a16faa60d github.com/satori/go.uuid v1.2.0 - golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e // indirect ) diff --git a/go.sum b/go.sum index 26dcc0c..a812ab3 100644 --- a/go.sum +++ b/go.sum @@ -27,17 +27,21 @@ github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/pion/datachannel v1.4.12 h1:fFdt26Ppkk9US5mpa/G+9QvYDoYXRIWipj0YUhxSBJI= -github.com/pion/datachannel v1.4.12/go.mod h1:Ulrx2j4r8c0Za5ltWFv/hZvSpc3ZpvOvcz46tvnt+PY= -github.com/pion/dtls v1.5.3 h1:zLEjR0hUiXGermhTFq4DmhALcRz9u+lSa//AH7H1sW0= -github.com/pion/dtls v1.5.3/go.mod h1:v4ULmyyV65geAZQBBckCjgMhmngTqz7HQVsQVYnfkGo= -github.com/pion/ice v0.7.1 h1:Leyv/AO/mSPeevlvKuUEgNkfYNZgETONNXTVTYCzMbk= -github.com/pion/ice v0.7.1/go.mod h1:fPnWLWO3B83fJmO6Sci5Mv3ypN4Vd956Py4JlbJfVwU= +github.com/pion/datachannel v1.4.13 h1:ezTn3AtUtXvKemRRjRdUgao/T8bH4ZJwrpOqU8Iz3Ss= +github.com/pion/datachannel v1.4.13/go.mod h1:+rBUwEDonA63KXx994DP/ofyyGVAm6AIMvOqQZxjWRU= +github.com/pion/dtls/v2 v2.0.0-rc.3 h1:u9utI+EDJOjOWfrkGQsD8WNssPcTwfYIanFB6oI8K+4= +github.com/pion/dtls/v2 v2.0.0-rc.3/go.mod h1:x0XH+cN5z+l/+/4nYL8r4sB8g6+0d1Zp2Pfkcoz8BKY= +github.com/pion/dtls/v2 v2.0.0-rc.5 h1:O6RZZGTnHryfMezTisWMSR02XS/Gf6jWnCnYqg5VjMY= +github.com/pion/dtls/v2 v2.0.0-rc.5/go.mod h1:k7HAs0qpJSz+Pelkbc5ZDNtenQpUvXgjg/yq4ZC6CdU= +github.com/pion/ice v0.7.6 h1:EARj1MBq5NYaMtXVhYkK03i0RS/meejNHvZS++K5tSY= +github.com/pion/ice v0.7.6/go.mod h1:4xCajahEEvc5w0AM+Ujx/Rr2EczON/fKndi3jLyDdh4= +github.com/pion/ice v0.7.7 h1:POqtOIISKHwaCd2XqgNyQrylgFl9IZJWZmL9cQQsqkk= +github.com/pion/ice v0.7.7/go.mod h1:4xCajahEEvc5w0AM+Ujx/Rr2EczON/fKndi3jLyDdh4= github.com/pion/logging v0.2.1/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/mdns v0.0.3 h1:DxdOYd0pgwLKiDlIIxfU0qdG5iWh1Xn6CsS9vc6cMAY= -github.com/pion/mdns v0.0.3/go.mod h1:VrN3wefVgtfL8QgpEblPUC46ag1reLIfpqekCnKunLE= +github.com/pion/mdns v0.0.4 h1:O4vvVqr4DGX63vzmO6Fw9vpy3lfztVWHGCQfyw0ZLSY= +github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0= github.com/pion/quic v0.1.1 h1:D951FV+TOqI9A0rTF7tHx0Loooqz+nyzjEyj8o3PuMA= github.com/pion/quic v0.1.1/go.mod h1:zEU51v7ru8Mp4AUBJvj6psrSth5eEFNnVQK5K48oV3k= github.com/pion/rtcp v1.2.1 h1:S3yG4KpYAiSmBVqKAfgRa5JdwBNj4zK3RLUa8JYdhak= @@ -45,8 +49,10 @@ github.com/pion/rtcp v1.2.1/go.mod h1:a5dj2d6BKIKHl43EnAOIrCczcjESrtPuMgfmL6/K6Q github.com/pion/rtp v1.1.3/go.mod h1:/l4cvcKd0D3u9JLs2xSVI95YkfXW87a3br3nqmVtSlE= github.com/pion/rtp v1.1.4 h1:P6xh8Y8JfzR7+JAbI79X2M8kfYETaqbuM5Otm+Z+k6U= github.com/pion/rtp v1.1.4/go.mod h1:/l4cvcKd0D3u9JLs2xSVI95YkfXW87a3br3nqmVtSlE= -github.com/pion/sctp v1.7.2 h1:eSFgSHeHkzG8VUbYFxLlN6RqUM/GaNo0v0Uf+LKn6og= -github.com/pion/sctp v1.7.2/go.mod h1:HlTD+15FeLYYQTTDO35uKEeRLVq5L2AY/ef6ZSvpIXc= +github.com/pion/rtp v1.2.0 h1:Aey1yLxlikAJeux8FZUG3l7dR1njDWxEVY52agQ3aAQ= +github.com/pion/rtp v1.2.0/go.mod h1:/l4cvcKd0D3u9JLs2xSVI95YkfXW87a3br3nqmVtSlE= +github.com/pion/sctp v1.7.3 h1:Pok18oncuAq/WjNxbyltfBSLvbv/6QSCyVJKYyDWP5M= +github.com/pion/sctp v1.7.3/go.mod h1:c6C9jaDGX7f5xeSRVju/140XatpO9sOVe81EwpfzAc8= github.com/pion/sdp/v2 v2.3.1 h1:45dub4NRdwyDmQCD3GIY7DZuqC49GBUwBdjuetvdOr0= github.com/pion/sdp/v2 v2.3.1/go.mod h1:jccXVYW0fuK6ds2pwKr89SVBDYlCjhgMI6nucl5R5rA= github.com/pion/srtp v1.2.6 h1:mHQuAMh0P67R7/j1F260u3O+fbRWLyjKLRPZYYvODFM= @@ -59,8 +65,10 @@ github.com/pion/transport v0.8.10 h1:lTiobMEw2PG6BH/mgIVqTV2mBp/mPT+IJLaN8ZxgdHk github.com/pion/transport v0.8.10/go.mod h1:tBmha/UCjpum5hqTWhfAEs3CO4/tHSg0MYRhSzR+CZ8= github.com/pion/turn v1.4.0 h1:7NUMRehQz4fIo53Qv9ui1kJ0Kr1CA82I81RHKHCeM80= github.com/pion/turn v1.4.0/go.mod h1:aDSi6hWX/hd1+gKia9cExZOR0MU95O7zX9p3Gw/P2aU= -github.com/pion/webrtc/v2 v2.1.12 h1:x/K+Hwj1Iud+62rA3KaCCAugFWIofzxgBvDEyc1KQmM= -github.com/pion/webrtc/v2 v2.1.12/go.mod h1:CYstxYIn64VLKMmqTHgLvJRnYIF9Ofr4APJXsCVpeso= +github.com/pion/webrtc/v2 v2.1.18 h1:g0VN0xfEUSlVNfQmlCD6yOeXy/tMaktESBmHMnBS3bk= +github.com/pion/webrtc/v2 v2.1.18/go.mod h1:m0rKlYgLRZWyhmcMWegpF6xtK1ASxmOg8DAR74ttzQY= +github.com/pion/webrtc/v2 v2.1.19-0.20200106051345-726a16faa60d h1:+S4pHiNfwwYBD0aubXJxnU3bddbec4XiSjdnFITmMco= +github.com/pion/webrtc/v2 v2.1.19-0.20200106051345-726a16faa60d/go.mod h1:7DykaSCTJBQ6lNuwLYF+Rsd2dnM9GYu/bY/1AbcJ1x0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -73,24 +81,23 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191001170739-f9e2070545dc h1:KyTYo8xkh/2WdbFLUyQwBS0Jfn3qfZ9QmuPbok2oENE= -golang.org/x/crypto v0.0.0-20191001170739-f9e2070545dc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191021144547-ec77196f6094 h1:5O4U9trLjNpuhpynaDsqwCk+Tw6seqJz1EbqbnzHrc8= -golang.org/x/net v0.0.0-20191021144547-ec77196f6094/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191023151326-f89234f9a2c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab h1:FvshnhkKW+LO3HWHodML8kuVX8rnJTxKm9dFPuI68UM= +golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -101,6 +108,5 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/mediastreamconstraints.go b/mediastreamconstraints.go index f437e03..fe46bf0 100644 --- a/mediastreamconstraints.go +++ b/mediastreamconstraints.go @@ -14,7 +14,7 @@ type MediaTrackConstraints bool type VideoTrackConstraints struct { Enabled bool Width, Height int - Codec Codec + Codec string } // fitnessDistance is an implementation for https://w3c.github.io/mediacapture-main/#dfn-fitness-distance diff --git a/pkg/codec/codec.go b/pkg/codec/codec.go index 43a6db3..d548e69 100644 --- a/pkg/codec/codec.go +++ b/pkg/codec/codec.go @@ -11,3 +11,12 @@ type VideoDecoder interface { Decode([]byte) (image.Image, error) Close() error } + +type VideoSetting struct { + Width, Height int + TargetBitRate, MaxBitRate int + FrameRate float32 +} + +type VideoEncoderBuilder func(s VideoSetting) (VideoEncoder, error) +type VideoDecoderBuilder func(s VideoSetting) (VideoDecoder, error) diff --git a/pkg/codec/h264/h264.go b/pkg/codec/h264/h264.go index c91ee96..8df1d43 100644 --- a/pkg/codec/h264/h264.go +++ b/pkg/codec/h264/h264.go @@ -12,35 +12,30 @@ import "C" import ( "fmt" "github.com/pion/mediadevices/pkg/codec" + "github.com/pion/webrtc/v2" "image" "unsafe" ) -type Options struct { - Width int - Height int - Bitrate int - MaxFrameRate float32 -} - -// https://github.com/cisco/openh264/wiki/TypesAndStructures#sencparambase -func (h *Options) translate() C.EncoderOptions { - return C.EncoderOptions{ - width: C.int(h.Width), - height: C.int(h.Height), - target_bitrate: C.int(h.Bitrate), - max_fps: C.float(h.MaxFrameRate), - } -} - type h264Encoder struct { encoder *C.Encoder } var _ codec.VideoEncoder = &h264Encoder{} +var _ codec.VideoEncoderBuilder = codec.VideoEncoderBuilder(NewEncoder) -func NewEncoder(opts Options) (codec.VideoEncoder, error) { - encoder, err := C.enc_new(opts.translate()) +func init() { + codec.Register(webrtc.H264, codec.VideoEncoderBuilder(NewEncoder)) +} + +func NewEncoder(s codec.VideoSetting) (codec.VideoEncoder, error) { + encoder, err := C.enc_new(C.EncoderOptions{ + width: C.int(s.Width), + height: C.int(s.Height), + target_bitrate: C.int(s.TargetBitRate), + max_bitrate: C.int(s.MaxBitRate), + max_fps: C.float(s.FrameRate), + }) if err != nil { // TODO: better error message return nil, fmt.Errorf("failed in creating encoder") diff --git a/pkg/codec/registrar.go b/pkg/codec/registrar.go new file mode 100644 index 0000000..9499e8f --- /dev/null +++ b/pkg/codec/registrar.go @@ -0,0 +1,37 @@ +package codec + +import ( + "fmt" +) + +var ( + videoEncoders = make(map[string]VideoEncoderBuilder) + videoDecoders = make(map[string]VideoDecoderBuilder) +) + +func Register(name string, builder interface{}) { + switch b := builder.(type) { + case VideoEncoderBuilder: + videoEncoders[name] = b + case VideoDecoderBuilder: + videoDecoders[name] = b + } +} + +func BuildVideoEncoder(name string, s VideoSetting) (VideoEncoder, error) { + b, ok := videoEncoders[name] + if !ok { + return nil, fmt.Errorf("codec: can't find %s video encoder", name) + } + + return b(s) +} + +func BuildVideoDecoder(name string, s VideoSetting) (VideoDecoder, error) { + b, ok := videoDecoders[name] + if !ok { + return nil, fmt.Errorf("codec: can't find %s video decoder", name) + } + + return b(s) +} diff --git a/track.go b/track.go index b6203a1..8d06559 100644 --- a/track.go +++ b/track.go @@ -1,10 +1,10 @@ package mediadevices import ( + "fmt" "math/rand" "github.com/pion/mediadevices/pkg/codec" - "github.com/pion/mediadevices/pkg/codec/h264" "github.com/pion/mediadevices/pkg/driver" "github.com/pion/mediadevices/pkg/frame" "github.com/pion/webrtc/v2" @@ -26,31 +26,36 @@ type videoTrack struct { encoder codec.VideoEncoder } -func newVideoTrack(pc *webrtc.PeerConnection, d driver.VideoDriver, setting driver.VideoSetting, codecName Codec) (*videoTrack, error) { +func newVideoTrack(pc *webrtc.PeerConnection, d driver.VideoDriver, setting driver.VideoSetting, codecName string) (*videoTrack, error) { var err error decoder, err := frame.NewDecoder(setting.FrameFormat) if err != nil { return nil, err } - var payloadType uint8 - var encoder codec.VideoEncoder - switch codecName { - default: - payloadType = webrtc.DefaultPayloadTypeH264 - encoder, err = h264.NewEncoder(h264.Options{ - Width: setting.Width, - Height: setting.Height, - Bitrate: 1000000, - MaxFrameRate: 30, - }) + var selectedCodec *webrtc.RTPCodec + codecs := pc.GetRegisteredRTPCodecs(webrtc.RTPCodecTypeVideo) + for _, c := range codecs { + if c.Name == codecName { + selectedCodec = c + break + } + } + if selectedCodec == nil { + return nil, fmt.Errorf("video track: %s is not registered in media engine", codecName) } + encoder, err := codec.BuildVideoEncoder(codecName, codec.VideoSetting{ + Width: setting.Width, + Height: setting.Height, + TargetBitRate: 1000000, + FrameRate: 30, + }) if err != nil { return nil, err } - track, err := pc.NewTrack(payloadType, rand.Uint32(), "video", d.ID()) + track, err := pc.NewTrack(selectedCodec.PayloadType, rand.Uint32(), "video", d.ID()) if err != nil { encoder.Close() return nil, err