diff --git a/encoders/dv8-enc.go b/encoders/dv8-enc.go new file mode 100644 index 0000000..cf05c4f --- /dev/null +++ b/encoders/dv8-enc.go @@ -0,0 +1,84 @@ +package encoders + +import ( + "image" + "io" + "os" + "os/exec" + "strings" + "vnc2webm/logger" +) + +type DV8ImageEncoder struct { + cmd *exec.Cmd + input io.WriteCloser +} + +func (enc *DV8ImageEncoder) Init(videoFileName string) { + fileExt := ".webm" + if !strings.HasSuffix(videoFileName, fileExt) { + videoFileName = videoFileName + fileExt + } + binary := "./ffmpeg" + cmd := exec.Command(binary, + "-f", "image2pipe", + "-vcodec", "ppm", + //"-r", strconv.Itoa(framerate), + "-r", "3", + //"-i", "pipe:0", + "-i", "-", + "-vcodec", "libvpx", //"libvpx",//"libvpx-vp9"//"libx264" + "-b:v", "2M", + "-threads", "8", + //"-speed", "0", + //"-lossless", "1", //for vpx + // "-tile-columns", "6", + //"-frame-parallel", "1", + // "-an", "-f", "webm", + "-cpu-used", "-16", + + "-preset", "ultrafast", + "-deadline", "realtime", + //"-cpu-used", "-5", + "-maxrate", "2.5M", + "-bufsize", "10M", + "-g", "6", + + //"-rc_lookahead", "16", + //"-profile", "0", + "-qmax", "51", + "-qmin", "11", + //"-slices", "4", + //"-vb", "2M", + + videoFileName, + ) + //cmd := exec.Command("/bin/echo") + + //io.Copy(cmd.Stdout, os.Stdout) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + encInput, err := cmd.StdinPipe() + enc.input = encInput + if err != nil { + logger.Error("can't get ffmpeg input pipe") + } + enc.cmd = cmd +} +func (enc *DV8ImageEncoder) Run() { + logger.Debugf("launching binary: %v", enc.cmd.Args) + err := enc.cmd.Run() + if err != nil { + logger.Error("error while launching ffmpeg:", err) + } +} +func (enc *DV8ImageEncoder) Encode(img image.Image) { + err := encodePPM(enc.input, img) + if err != nil { + logger.Error("error while encoding image:", err) + } +} +func (enc *DV8ImageEncoder) Close() { + +} diff --git a/encoders/dv9-enc.go b/encoders/dv9-enc.go new file mode 100644 index 0000000..3a81da8 --- /dev/null +++ b/encoders/dv9-enc.go @@ -0,0 +1,84 @@ +package encoders + +import ( + "image" + "io" + "os" + "os/exec" + "strings" + "vnc2webm/logger" +) + +type DV9ImageEncoder struct { + cmd *exec.Cmd + input io.WriteCloser +} + +func (enc *DV9ImageEncoder) Init(videoFileName string) { + fileExt := ".webm" + if !strings.HasSuffix(videoFileName, fileExt) { + videoFileName = videoFileName + fileExt + } + binary := "./ffmpeg" + cmd := exec.Command(binary, + "-f", "image2pipe", + "-vcodec", "ppm", + //"-r", strconv.Itoa(framerate), + "-r", "3", + //"-i", "pipe:0", + "-i", "-", + "-vcodec", "libvpx-vp9", //"libvpx",//"libvpx-vp9"//"libx264" + "-b:v", "2M", + "-threads", "8", + //"-speed", "0", + //"-lossless", "1", //for vpx + // "-tile-columns", "6", + //"-frame-parallel", "1", + // "-an", "-f", "webm", + "-cpu-used", "-16", + + "-preset", "ultrafast", + "-deadline", "realtime", + //"-cpu-used", "-5", + "-maxrate", "2.5M", + "-bufsize", "10M", + "-g", "6", + + //"-rc_lookahead", "16", + //"-profile", "0", + "-qmax", "51", + "-qmin", "11", + //"-slices", "4", + //"-vb", "2M", + + videoFileName, + ) + //cmd := exec.Command("/bin/echo") + + //io.Copy(cmd.Stdout, os.Stdout) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + encInput, err := cmd.StdinPipe() + enc.input = encInput + if err != nil { + logger.Error("can't get ffmpeg input pipe") + } + enc.cmd = cmd +} +func (enc *DV9ImageEncoder) Run() { + logger.Debugf("launching binary: %v", enc.cmd.Args) + err := enc.cmd.Run() + if err != nil { + logger.Error("error while launching ffmpeg:", err) + } +} +func (enc *DV9ImageEncoder) Encode(img image.Image) { + err := encodePPM(enc.input, img) + if err != nil { + logger.Error("error while encoding image:", err) + } +} +func (enc *DV9ImageEncoder) Close() { + +} diff --git a/encoders/image-enc.go b/encoders/image-enc.go new file mode 100644 index 0000000..399f4f8 --- /dev/null +++ b/encoders/image-enc.go @@ -0,0 +1,43 @@ +package encoders + +import ( + "fmt" + "image" + "image/color" + "io" +) + +func encodePPM(w io.Writer, img image.Image) error { + maxvalue := 255 + size := img.Bounds() + // write ppm header + _, err := fmt.Fprintf(w, "P6\n%d %d\n%d\n", size.Dx(), size.Dy(), maxvalue) + if err != nil { + return err + } + + // write the bitmap + colModel := color.RGBAModel + row := make([]uint8, size.Dx()*3) + for y := size.Min.Y; y < size.Max.Y; y++ { + i := 0 + for x := size.Min.X; x < size.Max.X; x++ { + color := colModel.Convert(img.At(x, y)).(color.RGBA) + row[i] = color.R + row[i+1] = color.G + row[i+2] = color.B + i += 3 + } + if _, err := w.Write(row); err != nil { + return err + } + } + return nil +} + +type ImageEncoder interface { + Init(string) + Run() + Encode(image.Image) + Close() +} diff --git a/encoders/mjpeg-enc.go b/encoders/mjpeg-enc.go new file mode 100644 index 0000000..4a91ae0 --- /dev/null +++ b/encoders/mjpeg-enc.go @@ -0,0 +1,56 @@ +package encoders + +import ( + "bytes" + "image" + "image/jpeg" + "strings" + "vnc2webm/logger" + + "github.com/icza/mjpeg" +) + +type MJPegImageEncoder struct { + avWriter mjpeg.AviWriter + Quality int + Framerate int32 +} + +func (enc *MJPegImageEncoder) Init(videoFileName string) { + fileExt := ".avi" + if !strings.HasSuffix(videoFileName, fileExt) { + videoFileName = videoFileName + fileExt + } + if enc.Framerate <= 0 { + enc.Framerate = 5 + } + avWriter, err := mjpeg.New(videoFileName, 1024, 768, enc.Framerate) + if err != nil { + logger.Error("Error during mjpeg init: ", err) + } + enc.avWriter = avWriter +} +func (enc *MJPegImageEncoder) Run() { +} +func (enc *MJPegImageEncoder) Encode(img image.Image) { + buf := &bytes.Buffer{} + jOpts := &jpeg.Options{Quality: enc.Quality} + if enc.Quality <= 0 { + jOpts = nil + } + err := jpeg.Encode(buf, img, jOpts) + if err != nil { + logger.Error("Error while creating jpeg: ", err) + } + err = enc.avWriter.AddFrame(buf.Bytes()) + if err != nil { + logger.Error("Error while adding frame to mjpeg: ", err) + } + +} +func (enc *MJPegImageEncoder) Close() { + err := enc.avWriter.Close() + if err != nil { + logger.Error("Error while closing mjpeg: ", err) + } +} diff --git a/encoders/x264-enc.go b/encoders/x264-enc.go new file mode 100644 index 0000000..f1481a8 --- /dev/null +++ b/encoders/x264-enc.go @@ -0,0 +1,92 @@ +package encoders + +import ( + "image" + "io" + "os" + "os/exec" + "strings" + "vnc2webm/logger" +) + +type X264ImageEncoder struct { + cmd *exec.Cmd + binaryPath string + input io.WriteCloser +} + +func (enc *X264ImageEncoder) Init(videoFileName string) { + fileExt := ".mp4" + if !strings.HasSuffix(videoFileName, fileExt) { + videoFileName = videoFileName + fileExt + } + //binary := "./ffmpeg" + cmd := exec.Command(enc.binaryPath, + "-f", "image2pipe", + "-vcodec", "ppm", + //"-r", strconv.Itoa(framerate), + "-r", "4", + //"-i", "pipe:0", + "-i", "-", + "-vcodec", "libx264", //"libvpx",//"libvpx-vp9"//"libx264" + "-b:v", "2M", + "-threads", "8", + //"-speed", "0", + //"-lossless", "1", //for vpx + // "-tile-columns", "6", + //"-frame-parallel", "1", + // "-an", "-f", "webm", + "-cpu-used", "-16", + + "-preset", "ultrafast", + "-deadline", "realtime", + //"-cpu-used", "-5", + "-maxrate", "2.5M", + "-bufsize", "10M", + "-g", "6", + + //"-rc_lookahead", "16", + //"-profile", "0", + "-qmax", "51", + "-qmin", "11", + //"-slices", "4", + //"-vb", "2M", + + videoFileName, + ) + //cmd := exec.Command("/bin/echo") + + //io.Copy(cmd.Stdout, os.Stdout) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + encInput, err := cmd.StdinPipe() + enc.input = encInput + if err != nil { + logger.Error("can't get ffmpeg input pipe") + } + enc.cmd = cmd +} +func (enc *X264ImageEncoder) Run(encoderFilePath string, videoFileName string) { + if _, err := os.Stat(encoderFilePath); os.IsNotExist(err) { + logger.Error("encoder file doesn't exist in path:", encoderFilePath) + return + } + + enc.binaryPath = encoderFilePath + enc.Init(videoFileName) + logger.Infof("launching binary: %v", enc.cmd) + err := enc.cmd.Run() + if err != nil { + logger.Errorf("error while launching ffmpeg: %v\n err: %v", enc.cmd.Args, err) + } +} +func (enc *X264ImageEncoder) Encode(img image.Image) { + err := encodePPM(enc.input, img) + if err != nil { + logger.Error("error while encoding image:", err) + } +} +func (enc *X264ImageEncoder) Close() { + +} diff --git a/encoding.go b/encoding.go index 7d5a4a4..249f887 100644 --- a/encoding.go +++ b/encoding.go @@ -3,6 +3,7 @@ package vnc2webm import ( "bytes" "image" + "image/draw" "sync" ) @@ -78,6 +79,10 @@ var bPool = sync.Pool{ }, } +type Renderer interface { + SetTargetImage(draw.Image) +} + // Encoding represents interface for vnc encoding type Encoding interface { Type() EncodingType diff --git a/encoding_tight.go b/encoding_tight.go index d3e4ea4..839f09f 100644 --- a/encoding_tight.go +++ b/encoding_tight.go @@ -12,8 +12,6 @@ import ( "image/jpeg" "io" "math" - "os" - "strconv" "vnc2webm/logger" ) @@ -79,9 +77,9 @@ func getTightColor(c io.Reader, pf *PixelFormat) (*color.RGBA64, error) { return nil, err } rgb := color.RGBA64{ - R: uint16(tbytes[0]), //byte(col >> pf.RedShift & int32(pf.RedMax)), - G: uint16(tbytes[1]), //byte(col >> pf.GreenShift & int32(pf.GreenMax)), - B: uint16(tbytes[2]), //byte(col >> pf.BlueShift & int32(pf.BlueMax)), + R: uint16(tbytes[0]), + G: uint16(tbytes[1]), + B: uint16(tbytes[2]), A: uint16(1), } return &rgb, nil @@ -114,24 +112,9 @@ func getTightColor(c io.Reader, pf *PixelFormat) (*color.RGBA64, error) { B: uint16((pixel >> pf.BlueShift) & uint32(pf.BlueMax)), } - // else { - // *clr = clr.cm[pixel] - // clr.cmIndex = pixel - // } return &rgb, nil } -// func getTightColor(bytes []byte, pf *PixelFormat) color.RGBA { -// col := (int32(bytes[0])&0xff)<<16 | (int32(bytes[1])&0xff)<<8 | int32(bytes[2])&0xff -// rgb := color.RGBA{ -// R: byte(col >> pf.RedShift & int32(pf.RedMax)), -// G: byte(col >> pf.GreenShift & int32(pf.GreenMax)), -// B: byte(col >> pf.BlueShift & int32(pf.BlueMax)), -// A: byte(1), -// } -// return rgb -// } - func calcTightBytePerPixel(pf *PixelFormat) int { bytesPerPixel := int(pf.BPP / 8) @@ -153,16 +136,19 @@ func (enc *TightEncoding) resetDecoders(compControl uint8) { } } +func (enc *TightEncoding) SetTargetImage(img draw.Image) { + enc.Image = img +} + var counter int = 0 func (enc *TightEncoding) Read(c Conn, rect *Rectangle) error { - var out *os.File var err error //////////// - if counter > 40 { - os.Exit(1) - } + // if counter > 40 { + // os.Exit(1) + // } //////////// pixelFmt := c.PixelFormat() bytesPixel := calcTightBytePerPixel(&pixelFmt) @@ -180,15 +166,16 @@ func (enc *TightEncoding) Read(c Conn, rect *Rectangle) error { compctl, err := ReadUint8(c) ///////////////// - if out == nil { - out, err = os.Create("./output" + strconv.Itoa(counter) + "-" + strconv.Itoa(int(compctl)) + ".jpg") - if err != nil { - fmt.Println(err) - os.Exit(1) - } - } - defer func() { counter++ }() - defer jpeg.Encode(out, enc.Image, nil) + // var out *os.File + // if out == nil { + // out, err = os.Create("./output" + strconv.Itoa(counter) + "-" + strconv.Itoa(int(compctl)) + ".jpg") + // if err != nil { + // fmt.Println(err) + // os.Exit(1) + // } + // } + // defer func() { counter++ }() + // defer jpeg.Encode(out, enc.Image, nil) ////////////// if err != nil { @@ -213,15 +200,7 @@ func (enc *TightEncoding) Read(c Conn, rect *Rectangle) error { return err } - //logger.Debugf("bytesPixel= %d, compctl= %d, color= %v", bytesPixel, compctl, rectColor) - - //imgRect := image.Rect(0, 0, int(c.Width()), int(c.Height())) - // if enc.Image == nil { - // enc.Image = image.NewRGBA(imgRect) - // } - c1 := color.RGBAModel.Convert(rectColor).(color.RGBA) - dst := (enc.Image).(*image.RGBA) // enc.Image.(*image.RGBA) var x, y int @@ -232,14 +211,8 @@ func (enc *TightEncoding) Read(c Conn, rect *Rectangle) error { dst.Pix[offset+1] = c1.G dst.Pix[offset+2] = c1.B dst.Pix[offset+3] = c1.A - - //dst.Set(int(x), int(y), c1) - //dst.Pix[y*uint16(dst.Bounds().Max.Y)+x] = []uint8{rectColor.R, rectColor.G, rectColor.B} } } - enc.Image = dst - - //draw.Draw(dst, imgRect, &image.Uniform{rectColor}, image.ZP, draw.Src) if bytesPixel != 3 { return fmt.Errorf("non tight bytesPerPixel format, should be 3 bytes") @@ -337,27 +310,7 @@ func (enc *TightEncoding) handleTightFilters(compCtl uint8, pixelFmt *PixelForma } //logger.Errorf("handleTightFilters: got tight data: %v", tightBytes) - myImg := enc.Image.(draw.Image) - bytePos := 0 - bitPos := 0 - var palettePos int - for i := 0; i < int(rect.Height); i++ { - for j := 0; j < int(rect.Width); j++ { - if len(palette) == 2 { - currByte := tightBytes[bytePos] - palettePos = int(currByte&byte(math.Pow(2.0, float64(bitPos)))) >> uint(bitPos) - //logger.Debugf("palletPos=%d, bitpos=%d, bytepos=%d", palettePos, bitPos, bytePos) - bytePos = bytePos + int((bitPos+1.0)/8.0) - bitPos = (bitPos + 1) % 8 - //logger.Debugf("next: bitpos=%d, bytepos=%d", bitPos, bytePos) - } else { - palettePos = int(tightBytes[bytePos]) - bytePos++ - } - myImg.Set(int(rect.X)+j, int(rect.Y)+i, palette[palettePos]) - //logger.Debugf("(%d,%d): pos: %d col:%d", int(rect.X)+j, int(rect.Y)+i, palettePos, palette[palettePos]) - } - } + enc.drawTightPalette(rect, palette, tightBytes) //enc.Image = myImg case TightFilterGradient: //GRADIENT_FILTER logger.Debugf("----GRADIENT_FILTER: bytesPixel=%d, counter=%d", bytesPixel, counter) @@ -387,6 +340,29 @@ func (enc *TightEncoding) handleTightFilters(compCtl uint8, pixelFmt *PixelForma return } +func (enc *TightEncoding) drawTightPalette(rect *Rectangle, palette color.Palette, tightBytes []byte) { + myImg := enc.Image.(draw.Image) + bytePos := 0 + bitPos := 0 + var palettePos int + for i := 0; i < int(rect.Height); i++ { + for j := 0; j < int(rect.Width); j++ { + if len(palette) == 2 { + currByte := tightBytes[bytePos] + palettePos = int(currByte&byte(math.Pow(2.0, float64(bitPos)))) >> uint(bitPos) + //logger.Debugf("palletPos=%d, bitpos=%d, bytepos=%d", palettePos, bitPos, bytePos) + bytePos = bytePos + int((bitPos+1.0)/8.0) + bitPos = (bitPos + 1) % 8 + //logger.Debugf("next: bitpos=%d, bytepos=%d", bitPos, bytePos) + } else { + palettePos = int(tightBytes[bytePos]) + bytePos++ + } + myImg.Set(int(rect.X)+j, int(rect.Y)+i, palette[palettePos]) + //logger.Debugf("(%d,%d): pos: %d col:%d", int(rect.X)+j, int(rect.Y)+i, palettePos, palette[palettePos]) + } + } +} func (enc *TightEncoding) decodeGradData(rect *Rectangle, buffer []byte) { logger.Debugf("putting gradient size: %v on image: %v", rect, enc.Image.Bounds()) diff --git a/example/client/main.go b/example/client/main.go index a70705a..02ef9e2 100644 --- a/example/client/main.go +++ b/example/client/main.go @@ -3,11 +3,11 @@ package main import ( "context" "image" - "log" "net" "os" "time" vnc "vnc2webm" + "vnc2webm/encoders" "vnc2webm/logger" ) @@ -16,7 +16,7 @@ func main() { // Establish TCP connection to VNC server. nc, err := net.DialTimeout("tcp", os.Args[1], 5*time.Second) if err != nil { - log.Fatalf("Error connecting to VNC host. %v", err) + logger.Fatalf("Error connecting to VNC host. %v", err) } logger.Debugf("starting up the client, connecting to: %s", os.Args[1]) @@ -41,31 +41,54 @@ func main() { cc, err := vnc.Connect(context.Background(), nc, ccfg) if err != nil { - log.Fatalf("Error negotiating connection to VNC host. %v", err) + 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) + // os.Exit(1) + // } + //vcodec := &encoders.MJPegImageEncoder{Quality: 60, Framerate: 6} + vcodec := &encoders.X264ImageEncoder{} + counter := 0 + //vcodec.Init("./output" + strconv.Itoa(counter)) + go vcodec.Run("./ffmpeg", "./output.mp4") + + screenImage := image.NewRGBA(image.Rect(0, 0, 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.Debugf("connected to: %s", os.Args[1]) defer cc.Close() cc.SetEncodings([]vnc.EncodingType{vnc.EncTight}) - rect := image.Rect(0, 0, int(cc.Width()), int(cc.Height())) - screenImage := image.NewRGBA64(rect) + //rect := image.Rect(0, 0, int(cc.Width()), int(cc.Height())) + //screenImage := image.NewRGBA64(rect) // Process messages coming in on the ServerMessage channel. for { select { case err := <-errorCh: panic(err) case msg := <-cchClient: - log.Printf("Received client message type:%v msg:%v\n", msg.Type(), msg) + logger.Debugf("Received client message type:%v msg:%v\n", msg.Type(), msg) case msg := <-cchServer: - log.Printf("Received server message type:%v msg:%v\n", msg.Type(), msg) - myRenderer, ok := msg.(vnc.Renderer) + logger.Debugf("Received server message type:%v msg:%v\n", msg.Type(), msg) - if ok { - err = myRenderer.Render(screenImage) - if err != nil { - log.Printf("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) + // } + + counter++ + //jpeg.Encode(out, screenImage, nil) + vcodec.Encode(screenImage) reqMsg := vnc.FramebufferUpdateRequest{Inc: 1, X: 0, Y: 0, Width: cc.Width(), Height: cc.Height()} reqMsg.Write(cc) } diff --git a/example/proxy/main.go b/example/proxy/main.go index 2d4d5ba..81f8dda 100644 --- a/example/proxy/main.go +++ b/example/proxy/main.go @@ -6,7 +6,6 @@ import ( "encoding/base64" "fmt" "io" - "log" "net" "net/http" _ "net/http/pprof" @@ -15,6 +14,7 @@ import ( "sync" "time" vnc "vnc2webm" + "vnc2webm/logger" ) type Auth struct { @@ -189,7 +189,7 @@ func (auth *AuthVNCHTTP) Auth(c vnc.Conn) error { if err != nil { return fmt.Errorf("failed to get auth data: %s", err.Error()) } - log.Printf("http auth: %s\n", buf.Bytes()) + logger.Infof("http auth: %s\n", buf.Bytes()) res.Body.Close() data := strings.Split(buf.String(), " ") if len(data) < 2 { @@ -223,12 +223,12 @@ func (*AuthVNCHTTP) SubType() vnc.SecuritySubType { func main() { go func() { - log.Println(http.ListenAndServe(":6060", nil)) + logger.Info(http.ListenAndServe(":6060", nil)) }() ln, err := net.Listen("tcp", ":6900") if err != nil { - log.Fatalf("Error listen. %v", err) + logger.Fatalf("Error listen. %v", err) } schClient := make(chan vnc.ClientMessage) diff --git a/example/server/main.go b/example/server/main.go index 301a75b..abf7ed8 100644 --- a/example/server/main.go +++ b/example/server/main.go @@ -4,17 +4,17 @@ import ( "context" "fmt" "image" - "log" "math" "net" "time" vnc "vnc2webm" + "vnc2webm/logger" ) func main() { ln, err := net.Listen("tcp", ":5900") if err != nil { - log.Fatalf("Error listen. %v", err) + logger.Fatalf("Error listen. %v", err) } chServer := make(chan vnc.ClientMessage) @@ -23,7 +23,7 @@ func main() { im := image.NewRGBA(image.Rect(0, 0, width, height)) tick := time.NewTicker(time.Second / 2) defer tick.Stop() - + cfg := &vnc.ServerConfig{ Width: 800, Height: 600, @@ -50,12 +50,12 @@ func main() { case msg := <-chClient: switch msg.Type() { default: - log.Printf("11 Received message type:%v msg:%v\n", msg.Type(), msg) + logger.Debugf("11 Received message type:%v msg:%v\n", msg.Type(), msg) } case msg := <-chServer: switch msg.Type() { default: - log.Printf("22 Received message type:%v msg:%v\n", msg.Type(), msg) + logger.Debugf("22 Received message type:%v msg:%v\n", msg.Type(), msg) } } } diff --git a/logger/logger.go b/logger/logger.go index 0e76d26..7c4a3a5 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -2,7 +2,7 @@ package logger import "fmt" -var simpleLogger = SimpleLogger{LogLevelDebug} +var simpleLogger = SimpleLogger{LogLevelInfo} type Logger interface { Debug(v ...interface{}) diff --git a/messages.go b/messages.go index 2311459..5d77a47 100644 --- a/messages.go +++ b/messages.go @@ -3,7 +3,6 @@ package vnc2webm import ( "encoding/binary" "fmt" - "image/draw" "vnc2webm/logger" ) @@ -83,10 +82,6 @@ type ServerMessage interface { Supported(Conn) bool } -type Renderer interface { - Render(draw.Image) error -} - // FramebufferUpdate holds a FramebufferUpdate wire format message. type FramebufferUpdate struct { _ [1]byte // pad @@ -99,11 +94,6 @@ func (msg *FramebufferUpdate) String() string { return fmt.Sprintf("rects %d rectangle[]: { %v }", msg.NumRect, msg.Rects) } -func (msg *FramebufferUpdate) Render(draw.Image) error { - - return nil -} - func (msg *FramebufferUpdate) Supported(c Conn) bool { return true }