mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-01-23 18:46:11 +00:00
110 lines
2.1 KiB
Go
110 lines
2.1 KiB
Go
package h264encoder
|
|
|
|
import (
|
|
"bytes"
|
|
"log"
|
|
"runtime/debug"
|
|
|
|
"github.com/gen2brain/x264-go"
|
|
"github.com/giongto35/cloud-game/pkg/encoder"
|
|
)
|
|
|
|
const chanSize = 2
|
|
|
|
// H264Encoder yuvI420 image to vp8 video
|
|
type H264Encoder struct {
|
|
Output chan encoder.OutFrame
|
|
Input chan encoder.InFrame
|
|
|
|
buf *bytes.Buffer
|
|
enc *x264.Encoder
|
|
|
|
// C
|
|
width int
|
|
height int
|
|
fps int
|
|
}
|
|
|
|
// NewH264Encoder create h264 encoder
|
|
func NewH264Encoder(width, height, fps int) (encoder.Encoder, error) {
|
|
v := &H264Encoder{
|
|
Output: make(chan encoder.OutFrame, 5*chanSize),
|
|
Input: make(chan encoder.InFrame, chanSize),
|
|
|
|
buf: bytes.NewBuffer(make([]byte, 0)),
|
|
width: width,
|
|
height: height,
|
|
fps: fps,
|
|
}
|
|
|
|
if err := v.init(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return v, nil
|
|
}
|
|
|
|
func (v *H264Encoder) init() error {
|
|
opts := &x264.Options{
|
|
Width: v.width,
|
|
Height: v.height,
|
|
FrameRate: v.fps,
|
|
Tune: "zerolatency",
|
|
Preset: "veryfast",
|
|
Profile: "baseline",
|
|
//LogLevel: x264.LogDebug,
|
|
}
|
|
|
|
enc, err := x264.NewEncoder(v.buf, opts)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
v.enc = enc
|
|
|
|
go v.startLooping()
|
|
return nil
|
|
}
|
|
|
|
func (v *H264Encoder) startLooping() {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
log.Println("Warn: Recovered panic in encoding ", r)
|
|
log.Println(debug.Stack())
|
|
}
|
|
}()
|
|
|
|
for img := range v.Input {
|
|
err := v.enc.Encode(img.Image)
|
|
if err != nil {
|
|
log.Println("err encoding ", img.Image, " using h264")
|
|
}
|
|
v.Output <- encoder.OutFrame{ Data: v.buf.Bytes(), Timestamp: img.Timestamp }
|
|
v.buf.Reset()
|
|
}
|
|
}
|
|
|
|
// Release release memory and stop loop
|
|
func (v *H264Encoder) release() {
|
|
log.Println("Releasing encoder")
|
|
// TODO: Bug here, after close it will signal
|
|
close(v.Output)
|
|
err := v.enc.Close()
|
|
if err != nil {
|
|
log.Println("Failed to close H264 encoder")
|
|
}
|
|
}
|
|
|
|
// GetInputChan returns input channel
|
|
func (v *H264Encoder) GetInputChan() chan encoder.InFrame {
|
|
return v.Input
|
|
}
|
|
|
|
// GetInputChan returns output channel
|
|
func (v *H264Encoder) GetOutputChan() chan encoder.OutFrame {
|
|
return v.Output
|
|
}
|
|
|
|
// GetDoneChan returns done channel
|
|
func (v *H264Encoder) Stop() {
|
|
v.release()
|
|
}
|