fixed hextile, now tested & working

This commit is contained in:
amit bezalel
2018-01-13 17:16:58 +02:00
parent afc94572a3
commit 16eba765cd
4 changed files with 195 additions and 155 deletions

View File

@@ -20,6 +20,10 @@ func (enc *CursorPseudoEncoding) SetTargetImage(img draw.Image) {
enc.Image = img enc.Image = img
} }
func (enc *CursorPseudoEncoding) Reset() error {
return nil
}
func (*CursorPseudoEncoding) Type() EncodingType { return EncCursorPseudo } func (*CursorPseudoEncoding) Type() EncodingType { return EncCursorPseudo }
func (enc *CursorPseudoEncoding) Read(c Conn, rect *Rectangle) error { func (enc *CursorPseudoEncoding) Read(c Conn, rect *Rectangle) error {

View File

@@ -1,8 +1,6 @@
package vnc2video package vnc2video
import ( import (
"encoding/binary"
"errors"
"image" "image"
"image/color" "image/color"
"image/draw" "image/draw"
@@ -24,51 +22,32 @@ type HextileEncoding struct {
Image draw.Image Image draw.Image
} }
// Read unmarshal color from conn func (enc *HextileEncoding) SetTargetImage(img draw.Image) {
func ReadColor(c io.Reader, pf *PixelFormat) (*color.RGBA, error) { enc.Image = img
if pf.TrueColor == 0 {
return nil, errors.New("support for non true color formats was not implemented")
}
order := pf.order()
var pixel uint32
switch pf.BPP {
case 8:
var px uint8
if err := binary.Read(c, order, &px); err != nil {
return nil, err
}
pixel = uint32(px)
case 16:
var px uint16
if err := binary.Read(c, order, &px); err != nil {
return nil, err
}
pixel = uint32(px)
case 32:
var px uint32
if err := binary.Read(c, order, &px); err != nil {
return nil, err
}
pixel = uint32(px)
}
rgb := color.RGBA{
R: uint8((pixel >> pf.RedShift) & uint32(pf.RedMax)),
G: uint8((pixel >> pf.GreenShift) & uint32(pf.GreenMax)),
B: uint8((pixel >> pf.BlueShift) & uint32(pf.BlueMax)),
A: 1,
}
return &rgb, nil
} }
func (z *HextileEncoding) Type() int32 { func (*HextileEncoding) Supported(Conn) bool {
return 5 return true
} }
func (enc *HextileEncoding) Reset() error {
//enc.decoders = make([]io.Reader, 4)
//enc.decoderBuffs = make([]*bytes.Buffer, 4)
return nil
}
func (z *HextileEncoding) Type() EncodingType {
return EncHextile
}
func (z *HextileEncoding) WriteTo(w io.Writer) (n int, err error) { func (z *HextileEncoding) WriteTo(w io.Writer) (n int, err error) {
return w.Write(z.bytes) return w.Write(z.bytes)
} }
func (enc *HextileEncoding) Write(c Conn, rect *Rectangle) error {
return nil
}
func (z *HextileEncoding) Read(r Conn, rect *Rectangle) error { func (z *HextileEncoding) Read(r Conn, rect *Rectangle) error {
//func (z *HextileEncoding) Read(pixelFmt *PixelFormat, rect *Rectangle, r io.Reader) (Encoding, error) { //func (z *HextileEncoding) Read(pixelFmt *PixelFormat, rect *Rectangle, r io.Reader) (Encoding, error) {
//bytesPerPixel := int(r.PixelFormat().BPP) / 8 //bytesPerPixel := int(r.PixelFormat().BPP) / 8
@@ -83,7 +62,7 @@ func (z *HextileEncoding) Read(r Conn, rect *Rectangle) error {
// defer func() { // defer func() {
// z.bytes = r.EndByteCollection() // z.bytes = r.EndByteCollection()
// }() // }()
logger.Debugf("HextileEncoding.Read: got hextile rect: %v", rect)
for ty := rect.Y; ty < rect.Y+rect.Height; ty += 16 { for ty := rect.Y; ty < rect.Y+rect.Height; ty += 16 {
th := 16 th := 16
if rect.Y+rect.Height-ty < 16 { if rect.Y+rect.Height-ty < 16 {
@@ -106,19 +85,31 @@ func (z *HextileEncoding) Read(r Conn, rect *Rectangle) error {
if (subencoding & HextileRaw) != 0 { if (subencoding & HextileRaw) != 0 {
rawEnc := r.GetEncInstance(EncRaw) rawEnc := r.GetEncInstance(EncRaw)
rawEnc.Read(r, &Rectangle{0, 0, uint16(tw), uint16(th), EncRaw, rawEnc}) rawEnc.Read(r, &Rectangle{X: uint16(tx), Y: uint16(ty), Width: uint16(tw), Height: uint16(th), EncType: EncRaw, Enc: rawEnc})
//ReadBytes(tw*th*bytesPerPixel, r) //ReadBytes(tw*th*int(pf.BPP)/8, r)
continue continue
} }
if (subencoding & HextileBackgroundSpecified) != 0 { if (subencoding & HextileBackgroundSpecified) != 0 {
//ReadBytes(int(bytesPerPixel), r) //ReadBytes(int(bytesPerPixel), r)
bgCol, err = ReadColor(r, &pf) bgCol, err = ReadColor(r, &pf)
rBounds := image.Rectangle{Min: image.Point{int(tx), int(ty)}, Max: image.Point{int(tw), int(th)}} if err != nil {
FillRect(z.Image, &rBounds, bgCol) logger.Errorf("HextileEncoding.Read: error in hextile bg color reader: %v", err)
return err
}
//logger.Debugf("%v %v", rBounds, bgCol)
} }
rBounds := image.Rectangle{Min: image.Point{int(tx), int(ty)}, Max: image.Point{int(tx) + int(tw), int(ty) + int(th)}}
logger.Debugf("filling background rect: %v, col: %v", rBounds, bgCol)
FillRect(z.Image, &rBounds, bgCol)
if (subencoding & HextileForegroundSpecified) != 0 { if (subencoding & HextileForegroundSpecified) != 0 {
fgCol, err = ReadColor(r, &pf) fgCol, err = ReadColor(r, &pf)
if err != nil {
logger.Errorf("HextileEncoding.Read: error in hextile fg color reader: %v", err)
return err
}
} }
if (subencoding & HextileAnySubrects) == 0 { if (subencoding & HextileAnySubrects) == 0 {
//logger.Debug("hextile reader: no Subrects") //logger.Debug("hextile reader: no Subrects")
@@ -136,7 +127,7 @@ func (z *HextileEncoding) Read(r Conn, rect *Rectangle) error {
if colorSpecified { if colorSpecified {
color, err = ReadColor(r, &pf) color, err = ReadColor(r, &pf)
if err != nil { if err != nil {
logger.Error("Hextile decoder: problem reading color from connection: ", err) logger.Error("HextileEncoding.Read: problem reading color from connection: ", err)
return err return err
} }
} else { } else {
@@ -146,20 +137,21 @@ func (z *HextileEncoding) Read(r Conn, rect *Rectangle) error {
fgCol = color fgCol = color
dimensions, err = ReadUint8(r) // bits 7-4 for x, bits 3-0 for y dimensions, err = ReadUint8(r) // bits 7-4 for x, bits 3-0 for y
if err != nil { if err != nil {
logger.Error("Hextile decoder: problem reading dimensions from connection: ", err) logger.Error("HextileEncoding.Read: problem reading dimensions from connection: ", err)
return err return err
} }
subtileX := dimensions >> 4 & 0x0f subtileX := dimensions >> 4 & 0x0f
subtileY := dimensions & 0x0f subtileY := dimensions & 0x0f
dimensions, err = ReadUint8(r) // bits 7-4 for w, bits 3-0 for h dimensions, err = ReadUint8(r) // bits 7-4 for w, bits 3-0 for h
if err != nil { if err != nil {
logger.Error("Hextile decoder: problem reading 2nd dimensions from connection: ", err) logger.Error("HextileEncoding.Read: problem reading 2nd dimensions from connection: ", err)
return err return err
} }
subtileWidth := 1 + (dimensions >> 4 & 0x0f) subtileWidth := 1 + (dimensions >> 4 & 0x0f)
subtileHeight := 1 + (dimensions & 0x0f) subtileHeight := 1 + (dimensions & 0x0f)
subrectBounds := image.Rectangle{Min: image.Point{int(tx) + int(subtileX), int(ty) + int(subtileY)}, Max: image.Point{int(subtileWidth), int(subtileHeight)}} subrectBounds := image.Rectangle{Min: image.Point{int(tx) + int(subtileX), int(ty) + int(subtileY)}, Max: image.Point{int(tx) + int(subtileX) + int(subtileWidth), int(ty) + int(subtileY) + int(subtileHeight)}}
FillRect(z.Image, &subrectBounds, color) FillRect(z.Image, &subrectBounds, color)
//logger.Debugf("%v", subrectBounds)
} }
} }
} }

View File

@@ -1,19 +1,57 @@
package vnc2video package vnc2video
import ( import (
"encoding/binary"
"errors"
"image" "image"
"image/color" "image/color"
"image/draw" "image/draw"
"io"
) )
func FillRect(img draw.Image, rect *image.Rectangle, c color.Color) { func FillRect(img draw.Image, rect *image.Rectangle, c color.Color) {
for x := 0; x < rect.Max.X; x++ { for x := rect.Min.X; x < rect.Max.X; x++ {
for y := 0; y < rect.Max.Y; y++ { for y := rect.Min.Y; y < rect.Max.Y; y++ {
img.Set(x, y, c) img.Set(x, y, c)
} }
} }
} }
func DrawLine(img draw.Image, rect *image.Rectangle, c color.Color) { // Read unmarshal color from conn
func ReadColor(c io.Reader, pf *PixelFormat) (*color.RGBA, error) {
if pf.TrueColor == 0 {
return nil, errors.New("support for non true color formats was not implemented")
}
order := pf.order()
var pixel uint32
switch pf.BPP {
case 8:
var px uint8
if err := binary.Read(c, order, &px); err != nil {
return nil, err
}
pixel = uint32(px)
case 16:
var px uint16
if err := binary.Read(c, order, &px); err != nil {
return nil, err
}
pixel = uint32(px)
case 32:
var px uint32
if err := binary.Read(c, order, &px); err != nil {
return nil, err
}
pixel = uint32(px)
}
rgb := color.RGBA{
R: uint8((pixel >> pf.RedShift) & uint32(pf.RedMax)),
G: uint8((pixel >> pf.GreenShift) & uint32(pf.GreenMax)),
B: uint8((pixel >> pf.BlueShift) & uint32(pf.BlueMax)),
A: 1,
}
return &rgb, nil
} }

View File

@@ -1,102 +1,108 @@
package main package main
import ( import (
"context" "context"
"image" "image"
"net" "net"
"os" "os"
"time" "time"
vnc "vnc2video" vnc "vnc2video"
"vnc2video/encoders" "vnc2video/encoders"
"vnc2video/logger" "vnc2video/logger"
) )
func main() { func main() {
// Establish TCP connection to VNC server. // Establish TCP connection to VNC server.
nc, err := net.DialTimeout("tcp", os.Args[1], 5*time.Second) nc, err := net.DialTimeout("tcp", os.Args[1], 5*time.Second)
if err != nil { if err != nil {
logger.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]) logger.Debugf("starting up the client, connecting to: %s", os.Args[1])
// Negotiate connection with the server. // Negotiate connection with the server.
cchServer := make(chan vnc.ServerMessage) cchServer := make(chan vnc.ServerMessage)
cchClient := make(chan vnc.ClientMessage) cchClient := make(chan vnc.ClientMessage)
errorCh := make(chan error) errorCh := make(chan error)
ccfg := &vnc.ClientConfig{ ccfg := &vnc.ClientConfig{
SecurityHandlers: []vnc.SecurityHandler{ SecurityHandlers: []vnc.SecurityHandler{
//&vnc.ClientAuthATEN{Username: []byte(os.Args[2]), Password: []byte(os.Args[3])} //&vnc.ClientAuthATEN{Username: []byte(os.Args[2]), Password: []byte(os.Args[3])}
&vnc.ClientAuthVNC{Password: []byte("12345")}, &vnc.ClientAuthVNC{Password: []byte("12345")},
&vnc.ClientAuthNone{}, &vnc.ClientAuthNone{},
}, },
PixelFormat: vnc.PixelFormat32bit, PixelFormat: vnc.PixelFormat32bit,
ClientMessageCh: cchClient, ClientMessageCh: cchClient,
ServerMessageCh: cchServer, ServerMessageCh: cchServer,
Messages: vnc.DefaultServerMessages, Messages: vnc.DefaultServerMessages,
Encodings: []vnc.Encoding{&vnc.RawEncoding{}, &vnc.TightEncoding{}}, Encodings: []vnc.Encoding{
ErrorCh: errorCh, &vnc.RawEncoding{},
} //&vnc.TightEncoding{},
&vnc.HextileEncoding{},
cc, err := vnc.Connect(context.Background(), nc, ccfg) //&vnc.CursorPseudoEncoding{},
if err != nil { },
logger.Fatalf("Error negotiating connection to VNC host. %v", err) ErrorCh: errorCh,
} }
// out, err := os.Create("./output" + strconv.Itoa(counter) + ".jpg")
// if err != nil { cc, err := vnc.Connect(context.Background(), nc, ccfg)
// fmt.Println(err) if err != nil {
// os.Exit(1) logger.Fatalf("Error negotiating connection to VNC host. %v", err)
// } }
//vcodec := &encoders.MJPegImageEncoder{Quality: 60, Framerate: 6} // out, err := os.Create("./output" + strconv.Itoa(counter) + ".jpg")
vcodec := &encoders.X264ImageEncoder{} // if err != nil {
//vcodec := &encoders.DV8ImageEncoder{} // fmt.Println(err)
//vcodec := &encoders.DV9ImageEncoder{} // os.Exit(1)
// }
//counter := 0 //vcodec := &encoders.MJPegImageEncoder{Quality: 60, Framerate: 6}
//vcodec.Init("./output" + strconv.Itoa(counter)) vcodec := &encoders.X264ImageEncoder{}
go vcodec.Run("./ffmpeg", "./output.mp4") //vcodec := &encoders.DV8ImageEncoder{}
//vcodec := &encoders.DV9ImageEncoder{}
screenImage := image.NewRGBA(image.Rect(0, 0, int(cc.Width()), int(cc.Height())))
for _, enc := range ccfg.Encodings { //counter := 0
myRenderer, ok := enc.(vnc.Renderer) //vcodec.Init("./output" + strconv.Itoa(counter))
//go vcodec.Run("./ffmpeg", "./output.mp4")
if ok { go vcodec.Run("/Users/amitbet/Dropbox/go/src/vnc2webm/example/file-reader/ffmpeg", "./output.mp4")
myRenderer.SetTargetImage(screenImage)
} screenImage := image.NewRGBA(image.Rect(0, 0, int(cc.Width()), int(cc.Height())))
} for _, enc := range ccfg.Encodings {
// var out *os.File myRenderer, ok := enc.(vnc.Renderer)
logger.Debugf("connected to: %s", os.Args[1]) if ok {
defer cc.Close() myRenderer.SetTargetImage(screenImage)
}
cc.SetEncodings([]vnc.EncodingType{vnc.EncTight}) }
//rect := image.Rect(0, 0, int(cc.Width()), int(cc.Height())) // var out *os.File
//screenImage := image.NewRGBA64(rect)
// Process messages coming in on the ServerMessage channel. logger.Debugf("connected to: %s", os.Args[1])
for { defer cc.Close()
select {
case err := <-errorCh: cc.SetEncodings([]vnc.EncodingType{vnc.EncHextile})
panic(err) //rect := image.Rect(0, 0, int(cc.Width()), int(cc.Height()))
case msg := <-cchClient: //screenImage := image.NewRGBA64(rect)
logger.Debugf("Received client message type:%v msg:%v\n", msg.Type(), msg) // Process messages coming in on the ServerMessage channel.
case msg := <-cchServer: for {
logger.Debugf("Received server message type:%v msg:%v\n", msg.Type(), msg) select {
case err := <-errorCh:
// out, err := os.Create("./output" + strconv.Itoa(counter) + ".jpg") panic(err)
// if err != nil { case msg := <-cchClient:
// fmt.Println(err) logger.Debugf("Received client message type:%v msg:%v\n", msg.Type(), msg)
// os.Exit(1) case msg := <-cchServer:
// } logger.Debugf("Received server message type:%v msg:%v\n", msg.Type(), msg)
if msg.Type() == vnc.FramebufferUpdateMsgType {
//counter++ // out, err := os.Create("./output" + strconv.Itoa(counter) + ".jpg")
//jpeg.Encode(out, screenImage, nil) // if err != nil {
vcodec.Encode(screenImage) // fmt.Println(err)
reqMsg := vnc.FramebufferUpdateRequest{Inc: 1, X: 0, Y: 0, Width: cc.Width(), Height: cc.Height()} // os.Exit(1)
//cc.ResetAllEncodings() // }
reqMsg.Write(cc) if msg.Type() == vnc.FramebufferUpdateMsgType {
} //counter++
} //jpeg.Encode(out, screenImage, nil)
} vcodec.Encode(screenImage)
//cc.Wait() reqMsg := vnc.FramebufferUpdateRequest{Inc: 1, X: 0, Y: 0, Width: cc.Width(), Height: cc.Height()}
} //cc.ResetAllEncodings()
reqMsg.Write(cc)
}
}
}
//cc.Wait()
}