Skip to content

Commit

Permalink
Add VP9 encoder option
Browse files Browse the repository at this point in the history
  • Loading branch information
sergystepanov committed Feb 15, 2024
1 parent 6258f9a commit 3459c7e
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 14 deletions.
2 changes: 1 addition & 1 deletion pkg/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ encoder:
# so we keep the frame buffer roughly half of that size or 2 RTC packets per frame
frame: 10
video:
# h264, vpx (VP8)
# h264, vpx (vp8) or vp9
codec: h264
# Threaded encoder if supported, 0 - auto, 1 - nope, >1 - multi-threaded
threads: 0
Expand Down
12 changes: 9 additions & 3 deletions pkg/encoder/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type VideoCodec string
const (
H264 VideoCodec = "h264"
VP8 VideoCodec = "vp8"
VP9 VideoCodec = "vp9"
VPX VideoCodec = "vpx"
)

Expand All @@ -48,13 +49,18 @@ const (
func NewVideoEncoder(w, h, dw, dh int, scale float64, conf config.Video, log *logger.Logger) (*Video, error) {
var enc Encoder
var err error
switch VideoCodec(conf.Codec) {
codec := VideoCodec(conf.Codec)
switch codec {
case H264:
opts := h264.Options(conf.H264)
enc, err = h264.NewEncoder(dw, dh, conf.Threads, &opts)
case VP8, VPX:
case VP8, VP9, VPX:
opts := vpx.Options(conf.Vpx)
enc, err = vpx.NewEncoder(dw, dh, &opts)
v := 8
if codec == VP9 {
v = 9
}
enc, err = vpx.NewEncoder(dw, dh, conf.Threads, v, &opts)
default:
err = fmt.Errorf("unsupported codec: %v", conf.Codec)
}
Expand Down
26 changes: 21 additions & 5 deletions pkg/encoder/vpx/libvpx.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package vpx
#include <string.h>
#define VP8_FOURCC 0x30385056
#define VP9_FOURCC 0x30395056
typedef struct VpxInterface {
const char *const name;
Expand Down Expand Up @@ -42,7 +43,10 @@ FrameBuffer get_frame_buffer(vpx_codec_ctx_t *codec, vpx_codec_iter_t *iter) {
return fb;
}
const VpxInterface vpx_encoders[] = {{ "vp8", VP8_FOURCC, &vpx_codec_vp8_cx }};
const VpxInterface vpx_encoders[] = {
{ "vp8", VP8_FOURCC, &vpx_codec_vp8_cx },
{ "vp9", VP9_FOURCC, &vpx_codec_vp9_cx },
};
int vpx_img_plane_width(const vpx_image_t *img, int plane) {
if (plane > 0 && img->x_chroma_shift > 0)
Expand Down Expand Up @@ -85,6 +89,7 @@ type Vpx struct {
codecCtx C.vpx_codec_ctx_t
kfi C.int
flipped bool
v int
}

func (vpx *Vpx) SetFlip(b bool) { vpx.flipped = b }
Expand All @@ -96,8 +101,12 @@ type Options struct {
KeyframeInterval uint
}

func NewEncoder(w, h int, opts *Options) (*Vpx, error) {
encoder := &C.vpx_encoders[0]
func NewEncoder(w, h int, th int, version int, opts *Options) (*Vpx, error) {
idx := 0
if version == 9 {
idx = 1
}
encoder := &C.vpx_encoders[idx]
if encoder == nil {
return nil, fmt.Errorf("couldn't get the encoder")
}
Expand All @@ -112,6 +121,7 @@ func NewEncoder(w, h int, opts *Options) (*Vpx, error) {
vpx := Vpx{
frameCount: C.int(0),
kfi: C.int(opts.KeyframeInterval),
v: version,
}

if C.vpx_img_alloc(&vpx.image, C.VPX_IMG_FMT_I420, C.uint(w), C.uint(h), 1) == nil {
Expand All @@ -125,8 +135,12 @@ func NewEncoder(w, h int, opts *Options) (*Vpx, error) {

cfg.g_w = C.uint(w)
cfg.g_h = C.uint(h)
if th != 0 {
cfg.g_threads = C.uint(th)
}
cfg.g_lag_in_frames = 0
cfg.rc_target_bitrate = C.uint(opts.Bitrate)
cfg.g_error_resilient = 1
cfg.g_error_resilient = C.VPX_ERROR_RESILIENT_DEFAULT

if C.call_vpx_codec_enc_init(&vpx.codecCtx, encoder, &cfg) != 0 {
return nil, fmt.Errorf("failed to initialize encoder")
Expand Down Expand Up @@ -160,7 +174,9 @@ func (vpx *Vpx) Encode(yuv []byte) []byte {
return C.GoBytes(fb.ptr, fb.size)
}

func (vpx *Vpx) Info() string { return fmt.Sprintf("vpx: %v", C.GoString(C.vpx_codec_version_str())) }
func (vpx *Vpx) Info() string {
return fmt.Sprintf("vpx (%v): %v", vpx.v, C.GoString(C.vpx_codec_version_str()))
}

func (vpx *Vpx) IntraRefresh() {
// !to implement
Expand Down
2 changes: 2 additions & 0 deletions pkg/network/webrtc/webrtc.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ func newTrack(id string, label string, codec string) (*webrtc.TrackLocalStaticSa
mime = webrtc.MimeTypeH264
case "vpx", "vp8":
mime = webrtc.MimeTypeVP8
case "vp9":
mime = webrtc.MimeTypeVP9
}
}
if mime == "" {
Expand Down
12 changes: 7 additions & 5 deletions pkg/worker/room/room_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,15 @@ func TestMain(m *testing.M) {

func TestRoom(t *testing.T) {
tests := []testParams{
{game: alwas, codecs: []codec{encoder.H264}, frames: 300},
{game: alwas, codecs: []codec{encoder.H264, encoder.VP8, encoder.VP9}, frames: 300},
}

for _, test := range tests {
room := room(conf{codec: test.codecs[0], game: test.game})
room.WaitFrame(test.frames)
room.Close()
for _, codec := range test.codecs {
room := room(conf{codec: codec, game: test.game})
room.WaitFrame(test.frames)
room.Close()
}
}
}

Expand Down Expand Up @@ -245,7 +247,7 @@ func room(cfg conf) testRoom {
func BenchmarkRoom(b *testing.B) {
benches := []testParams{
// warm up
{system: "gba", game: sushi, codecs: []codec{encoder.VP8}, frames: 50},
{system: "gba", game: sushi, codecs: []codec{encoder.VP8, encoder.VP9}, frames: 50},
{system: "gba", game: sushi, codecs: []codec{encoder.VP8, encoder.H264}, frames: 100},
{system: "nes", game: alwas, codecs: []codec{encoder.VP8, encoder.H264}, frames: 100},
}
Expand Down

0 comments on commit 3459c7e

Please sign in to comment.