Compare commits

...

8 Commits

Author SHA1 Message Date
Daniel Widerin
9f06939cdc
Merge pull request #8 from bdhood/master
Add -pix_fmt yuv420p
2022-03-07 10:28:16 +01:00
Ben Hood
0e5de504f3 Add -pix_fmt yuv420p 2021-04-09 22:53:34 -05:00
Ben Hood
e5db4f2150 Add -pix_fmt yuv420p 2021-04-09 22:48:13 -05:00
Daniel Widerin
d779ad2d6d
fix version in readme
Signed-off-by: Daniel Widerin <daniel@widerin.net>
2020-10-25 14:31:55 +01:00
Daniel Widerin
b50a802795
better logging and var-naming
Signed-off-by: Daniel Widerin <daniel@widerin.net>
2020-10-25 14:28:33 +01:00
Daniel Widerin
cb6ef6d550
set correct version in cli
Signed-off-by: Daniel Widerin <daniel@widerin.net>
2020-10-25 14:26:30 +01:00
Daniel Widerin
b46e488cd3
drop unused function
Signed-off-by: Daniel Widerin <daniel@widerin.net>
2020-10-25 14:26:16 +01:00
Daniel Widerin
f43371de08
cleanup imports
Signed-off-by: Daniel Widerin <daniel@widerin.net>
2020-10-25 14:25:57 +01:00
3 changed files with 48 additions and 43 deletions

View File

@ -18,7 +18,7 @@ library which made this wrapper possible.
vnc-recorder [global options] command [command options] [arguments...] vnc-recorder [global options] command [command options] [arguments...]
VERSION: VERSION:
1.0 0.3.0
AUTHOR: AUTHOR:
Daniel Widerin <daniel@widerin.net> Daniel Widerin <daniel@widerin.net>

View File

@ -10,7 +10,7 @@ import (
"fmt" "fmt"
vnc "github.com/amitbet/vnc2video" vnc "github.com/amitbet/vnc2video"
"github.com/amitbet/vnc2video/encoders" "github.com/amitbet/vnc2video/encoders"
log "github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"image" "image"
"image/color" "image/color"
"io" "io"
@ -107,11 +107,11 @@ func encodePPMforRGBImage(w io.Writer, img *vnc.RGBImage) error {
type X264ImageCustomEncoder struct { type X264ImageCustomEncoder struct {
encoders.X264ImageEncoder encoders.X264ImageEncoder
FFMpegBinPath string FFMpegBinPath string
cmd *exec.Cmd cmd *exec.Cmd
input io.WriteCloser input io.WriteCloser
closed bool closed bool
Framerate int Framerate int
ConstantRateFactor int ConstantRateFactor int
} }
@ -130,6 +130,7 @@ func (enc *X264ImageCustomEncoder) Init(videoFileName string) {
"-preset", "veryfast", "-preset", "veryfast",
"-g", "250", "-g", "250",
"-crf", strconv.Itoa(enc.ConstantRateFactor), "-crf", strconv.Itoa(enc.ConstantRateFactor),
"-pix_fmt", "yuv420p",
videoFileName, videoFileName,
) )
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
@ -137,7 +138,7 @@ func (enc *X264ImageCustomEncoder) Init(videoFileName string) {
encInput, err := cmd.StdinPipe() encInput, err := cmd.StdinPipe()
enc.input = encInput enc.input = encInput
if err != nil { if err != nil {
log.Error("can't get ffmpeg input pipe") logrus.WithError(err).Error("can't get ffmpeg input pipe.")
} }
enc.cmd = cmd enc.cmd = cmd
} }
@ -147,10 +148,10 @@ func (enc *X264ImageCustomEncoder) Run(videoFileName string) error {
} }
enc.Init(videoFileName) enc.Init(videoFileName)
log.Infof("launching binary: %v", enc.cmd) logrus.Infof("launching binary: %v", enc.cmd)
err := enc.cmd.Run() err := enc.cmd.Run()
if err != nil { if err != nil {
log.Errorf("error while launching ffmpeg: %v\n err: %v", enc.cmd.Args, err) logrus.WithError(err).Errorf("error while launching ffmpeg: %v", enc.cmd.Args)
return err return err
} }
return nil return nil
@ -162,7 +163,7 @@ func (enc *X264ImageCustomEncoder) Encode(img image.Image) {
err := encodePPM(enc.input, img) err := encodePPM(enc.input, img)
if err != nil { if err != nil {
log.Error("error while encoding image:", err) logrus.WithError(err).Error("error while encoding image.")
} }
} }
@ -173,7 +174,7 @@ func (enc *X264ImageCustomEncoder) Close() {
enc.closed = true enc.closed = true
err := enc.input.Close() err := enc.input.Close()
if err != nil { if err != nil {
log.Error("could not close input", err) logrus.WithError(err).Error("could not close input.")
} }
} }

66
main.go
View File

@ -4,8 +4,8 @@ import (
"context" "context"
"fmt" "fmt"
vnc "github.com/amitbet/vnc2video" vnc "github.com/amitbet/vnc2video"
log "github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
cli "github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"net" "net"
"os" "os"
@ -16,16 +16,11 @@ import (
"time" "time"
) )
func init() {
log.SetOutput(os.Stdout)
log.SetLevel(log.InfoLevel)
}
func main() { func main() {
app := &cli.App{ app := &cli.App{
Name: path.Base(os.Args[0]), Name: path.Base(os.Args[0]),
Usage: "Connect to a vnc server and record the screen to a video.", Usage: "Connect to a vnc server and record the screen to a video.",
Version: "1.0", Version: "0.3.0",
Authors: []*cli.Author{ Authors: []*cli.Author{
&cli.Author{ &cli.Author{
Name: "Daniel Widerin", Name: "Daniel Widerin",
@ -80,20 +75,20 @@ func main() {
} }
if err := app.Run(os.Args); err != nil { if err := app.Run(os.Args); err != nil {
log.Fatal(err) logrus.WithError(err).Fatal("recording failed.")
} }
} }
func recorder(c *cli.Context) error { func recorder(c *cli.Context) error {
address := fmt.Sprintf("%s:%d", c.String("host"), c.Int("port")) address := fmt.Sprintf("%s:%d", c.String("host"), c.Int("port"))
nc, err := net.DialTimeout("tcp", address, 5*time.Second) dialer, err := net.DialTimeout("tcp", address, 5*time.Second)
if err != nil { if err != nil {
log.Fatalf("Error connecting to VNC host. %v", err) logrus.WithError(err).Error("connection to VNC host failed.")
return err return err
} }
defer nc.Close() defer dialer.Close()
log.Infof("Connected to %s", address) logrus.WithField("address", address).Info("connection established.")
// Negotiate connection with the server. // Negotiate connection with the server.
cchServer := make(chan vnc.ServerMessage) cchServer := make(chan vnc.ServerMessage)
@ -111,7 +106,7 @@ func recorder(c *cli.Context) error {
} }
} }
ccfg := &vnc.ClientConfig{ ccflags := &vnc.ClientConfig{
SecurityHandlers: secHandlers, SecurityHandlers: secHandlers,
DrawCursor: true, DrawCursor: true,
PixelFormat: vnc.PixelFormat32bit, PixelFormat: vnc.PixelFormat32bit,
@ -132,30 +127,31 @@ func recorder(c *cli.Context) error {
ErrorCh: errorCh, ErrorCh: errorCh,
} }
cc, err := vnc.Connect(context.Background(), nc, ccfg) vncConnection, err := vnc.Connect(context.Background(), dialer, ccflags)
defer cc.Close() defer vncConnection.Close()
screenImage := cc.Canvas
if err != nil { if err != nil {
log.Fatalf("Error negotiating connection to VNC host. %v", err) logrus.WithError(err).Error("connection negotiation to VNC host failed.")
return err return err
} }
screenImage := vncConnection.Canvas
ffmpeg_path, err := exec.LookPath(c.String("ffmpeg")) ffmpegPath, err := exec.LookPath(c.String("ffmpeg"))
if err != nil { if err != nil {
panic(err) logrus.WithError(err).Error("ffmpeg binary not found.")
return err
} }
log.Infof("Using %s for encoding", ffmpeg_path) logrus.WithField("ffmpeg", ffmpegPath).Info("ffmpeg binary for recording found")
vcodec := &X264ImageCustomEncoder{ vcodec := &X264ImageCustomEncoder{
FFMpegBinPath: ffmpeg_path, FFMpegBinPath: ffmpegPath,
Framerate: c.Int("framerate"), Framerate: c.Int("framerate"),
ConstantRateFactor: c.Int("crf"), ConstantRateFactor: c.Int("crf"),
} }
//goland:noinspection GoUnhandledErrorResult //goland:noinspection GoUnhandledErrorResult
go vcodec.Run(c.String("outfile")) go vcodec.Run(c.String("outfile"))
for _, enc := range ccfg.Encodings { for _, enc := range ccflags.Encodings {
myRenderer, ok := enc.(vnc.Renderer) myRenderer, ok := enc.(vnc.Renderer)
if ok { if ok {
@ -163,7 +159,7 @@ func recorder(c *cli.Context) error {
} }
} }
cc.SetEncodings([]vnc.EncodingType{ vncConnection.SetEncodings([]vnc.EncodingType{
vnc.EncCursorPseudo, vnc.EncCursorPseudo,
vnc.EncPointerPosPseudo, vnc.EncPointerPosPseudo,
vnc.EncCopyRect, vnc.EncCopyRect,
@ -206,20 +202,28 @@ func recorder(c *cli.Context) error {
case err := <-errorCh: case err := <-errorCh:
panic(err) panic(err)
case msg := <-cchClient: case msg := <-cchClient:
log.Debugf("Received client message type:%v msg:%v\n", msg.Type(), msg) logrus.WithFields(logrus.Fields{
"messageType": msg.Type(),
"message": msg,
}).Debug("client message received.")
case msg := <-cchServer: case msg := <-cchServer:
if msg.Type() == vnc.FramebufferUpdateMsgType { if msg.Type() == vnc.FramebufferUpdateMsgType {
secsPassed := time.Now().Sub(timeStart).Seconds() secsPassed := time.Now().Sub(timeStart).Seconds()
frameBufferReq++ frameBufferReq++
reqPerSec := float64(frameBufferReq) / secsPassed reqPerSec := float64(frameBufferReq) / secsPassed
log.Debugf("reqs=%d, seconds=%f, Req Per second= %f", frameBufferReq, secsPassed, reqPerSec) logrus.WithFields(logrus.Fields{
"reqs": frameBufferReq,
"seconds": secsPassed,
"Req Per second": reqPerSec,
}).Debug("framebuffer update")
reqMsg := vnc.FramebufferUpdateRequest{Inc: 1, X: 0, Y: 0, Width: cc.Width(), Height: cc.Height()} reqMsg := vnc.FramebufferUpdateRequest{Inc: 1, X: 0, Y: 0, Width: vncConnection.Width(), Height: vncConnection.Height()}
reqMsg.Write(cc) reqMsg.Write(vncConnection)
} }
case signal := <-sigCh: case signal := <-sigCh:
if signal != nil { if signal != nil {
log.Info(signal, " received, exit.") logrus.WithField("signal", signal).Info("signal received.")
vcodec.Close() vcodec.Close()
// give some time to write the file // give some time to write the file
time.Sleep(time.Second * 1) time.Sleep(time.Second * 1)