From 9ba90938751c5c50edbeedfdb6d0d4fe65f69fa3 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Mon, 17 Mar 2025 05:08:28 -0500 Subject: [PATCH] add a vnc record example --- .gitignore | 2 + vncrecord/Makefile | 10 +++ vncrecord/main.go | 186 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 vncrecord/Makefile create mode 100644 vncrecord/main.go diff --git a/.gitignore b/.gitignore index d07db6a..cb9430f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ go.mod go.sum /files/* /work/* +*.mov forgeConfig/forgeConfig scanGoSrc/scanGoSrc @@ -19,3 +20,4 @@ cf-r2/cf-r2 cf-r2/download cf-r2/upload wit-utils +vncrecord/vncrecord diff --git a/vncrecord/Makefile b/vncrecord/Makefile new file mode 100644 index 0000000..1372ac1 --- /dev/null +++ b/vncrecord/Makefile @@ -0,0 +1,10 @@ +all: build test + +build: + GO111MODULE=off go build + +test: + ./vncrecord localhost:6910 + +clean: + rm -f *.mov vncrecord diff --git a/vncrecord/main.go b/vncrecord/main.go new file mode 100644 index 0000000..779540d --- /dev/null +++ b/vncrecord/main.go @@ -0,0 +1,186 @@ +package main + +import ( + "context" + "log" + "net" + "os" + "os/signal" + "runtime" + "runtime/pprof" + "syscall" + "time" + vnc "github.com/amitbet/vnc2video" + "github.com/amitbet/vnc2video/encoders" + "github.com/amitbet/vnc2video/logger" +) + +func main() { + runtime.GOMAXPROCS(4) + framerate := 12 + runWithProfiler := false + + // Establish TCP connection to VNC server. + nc, err := net.DialTimeout("tcp", os.Args[1], 5*time.Second) + if err != nil { + logger.Fatalf("Error connecting to VNC host. %v", err) + } + + logger.Tracef("starting up the client, connecting to: %s", os.Args[1]) + // Negotiate connection with the server. + cchServer := make(chan vnc.ServerMessage) + cchClient := make(chan vnc.ClientMessage) + errorCh := make(chan error) + + ccfg := &vnc.ClientConfig{ + SecurityHandlers: []vnc.SecurityHandler{ + //&vnc.ClientAuthATEN{Username: []byte(os.Args[2]), Password: []byte(os.Args[3])} + // &vnc.ClientAuthVNC{Password: []byte("12345")}, + &vnc.ClientAuthNone{}, + }, + DrawCursor: true, + PixelFormat: vnc.PixelFormat32bit, + ClientMessageCh: cchClient, + ServerMessageCh: cchServer, + Messages: vnc.DefaultServerMessages, + Encodings: []vnc.Encoding{ + &vnc.RawEncoding{}, + &vnc.TightEncoding{}, + &vnc.HextileEncoding{}, + &vnc.ZRLEEncoding{}, + &vnc.CopyRectEncoding{}, + &vnc.CursorPseudoEncoding{}, + &vnc.CursorPosPseudoEncoding{}, + &vnc.ZLibEncoding{}, + &vnc.RREEncoding{}, + }, + ErrorCh: errorCh, + } + + cc, err := vnc.Connect(context.Background(), nc, ccfg) + screenImage := cc.Canvas + if err != nil { + logger.Fatalf("Error negotiating connection to VNC host. %v", err) + } + // out, err := os.Create("./output" + strconv.Itoa(counter) + ".jpg") + // if err != nil { + // fmt.Println(err)p + // os.Exit(1) + // } + //vcodec := &encoders.MJPegImageEncoder{Quality: 60 , Framerate: framerate} + //vcodec := &encoders.X264ImageEncoder{FFMpegBinPath: "./ffmpeg", Framerate: framerate} + //vcodec := &encoders.HuffYuvImageEncoder{FFMpegBinPath: "./ffmpeg", Framerate: framerate} + vcodec := &encoders.QTRLEImageEncoder{FFMpegBinPath: "/usr/bin/ffmpeg", Framerate: framerate} + //vcodec := &encoders.VP8ImageEncoder{FFMpegBinPath:"./ffmpeg", Framerate: framerate} + //vcodec := &encoders.DV9ImageEncoder{FFMpegBinPath:"./ffmpeg", Framerate: framerate} + + //counter := 0 + //vcodec.Init("./output" + strconv.Itoa(counter)) + + go vcodec.Run("./output.mp4") + //windows + ///go vcodec.Run("/Users/amitbet/Dropbox/go/src/vnc2webm/example/file-reader/ffmpeg", "./output.mp4") + + //go vcodec.Run("C:\\Users\\betzalel\\Dropbox\\go\\src\\vnc2video\\example\\client\\ffmpeg.exe", "output.mp4") + //vcodec.Run("./output") + + //screenImage := vnc.NewVncCanvas(int(cc.Width()), int(cc.Height())) + + for _, enc := range ccfg.Encodings { + myRenderer, ok := enc.(vnc.Renderer) + + if ok { + myRenderer.SetTargetImage(screenImage) + } + } + // var out *os.File + + logger.Tracef("connected to: %s", os.Args[1]) + defer cc.Close() + + cc.SetEncodings([]vnc.EncodingType{ + vnc.EncCursorPseudo, + vnc.EncPointerPosPseudo, + vnc.EncCopyRect, + vnc.EncTight, + vnc.EncZRLE, + //vnc.EncHextile, + //vnc.EncZlib, + //vnc.EncRRE, + }) + //rect := image.Rect(0, 0, int(cc.Width()), int(cc.Height())) + //screenImage := image.NewRGBA64(rect) + // Process messages coming in on the ServerMessage channel. + + go func() { + for { + timeStart := time.Now() + + vcodec.Encode(screenImage.Image) + + timeTarget := timeStart.Add((1000 / time.Duration(framerate)) * time.Millisecond) + timeLeft := timeTarget.Sub(time.Now()) + if timeLeft > 0 { + time.Sleep(timeLeft) + } + } + }() + + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, + syscall.SIGHUP, + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT) + frameBufferReq := 0 + timeStart := time.Now() + + if runWithProfiler { + profFile := "prof.file" + f, err := os.Create(profFile) + if err != nil { + log.Fatal(err) + } + pprof.StartCPUProfile(f) + defer pprof.StopCPUProfile() + } + + for { + select { + case err := <-errorCh: + panic(err) + case msg := <-cchClient: + logger.Tracef("Received client message type:%v msg:%v\n", msg.Type(), msg) + case msg := <-cchServer: + //logger.Tracef("Received server message type:%v msg:%v\n", msg.Type(), msg) + + // out, err := os.Create("./output" + strconv.Itoa(counter) + ".jpg") + // if err != nil { + // fmt.Println(err) + // os.Exit(1) + // } + + if msg.Type() == vnc.FramebufferUpdateMsgType { + secsPassed := time.Now().Sub(timeStart).Seconds() + frameBufferReq++ + reqPerSec := float64(frameBufferReq) / secsPassed + //counter++ + //jpeg.Encode(out, screenImage, nil) + ///vcodec.Encode(screenImage) + logger.Infof("reqs=%d, seconds=%f, Req Per second= %f", frameBufferReq, secsPassed, reqPerSec) + + reqMsg := vnc.FramebufferUpdateRequest{Inc: 1, X: 0, Y: 0, Width: cc.Width(), Height: cc.Height()} + //cc.ResetAllEncodings() + reqMsg.Write(cc) + } + case signal := <-sigc: + if signal != nil { + vcodec.Close() + pprof.StopCPUProfile() + time.Sleep(2 * time.Second) + os.Exit(1) + } + } + } + //cc.Wait() +}