mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-07-28 20:40:06 +00:00
Add VP9 encoder option
This commit is contained in:
parent
6258f9a5e4
commit
3459c7e8d6
5 changed files with 40 additions and 14 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ type VideoCodec string
|
|||
const (
|
||||
H264 VideoCodec = "h264"
|
||||
VP8 VideoCodec = "vp8"
|
||||
VP9 VideoCodec = "vp9"
|
||||
VPX VideoCodec = "vpx"
|
||||
)
|
||||
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ package vpx
|
|||
#include <string.h>
|
||||
|
||||
#define VP8_FOURCC 0x30385056
|
||||
#define VP9_FOURCC 0x30395056
|
||||
|
||||
typedef struct VpxInterface {
|
||||
const char *const name;
|
||||
|
|
@ -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)
|
||||
|
|
@ -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 }
|
||||
|
|
@ -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")
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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")
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 == "" {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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},
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue