mirror of
https://github.com/amitbet/vnc2video.git
synced 2025-05-10 08:14:28 +00:00
name change now: vnc2video,
initial implementation for hextile, cursor
This commit is contained in:
parent
1a112dbead
commit
afc94572a3
.vscode
LICENSEbutton_string.gobuttons.goclient.goclientmessagetype_string.goconn.goencoders
encoding.goencoding_atenhermon.goencoding_copyrect.goencoding_corre.goencoding_cursor.goencoding_desktopname.goencoding_desktopsize.goencoding_hextile.goencoding_raw.goencoding_rre.goencoding_tight.goencoding_tightpng.goencoding_util.goencoding_xcursor.goencoding_zlib.goencoding_zrle.goencodingtype_string.goexample
fbs-connection.gofbs-reader.gohandlers.goimage.gokey_string.gokeys.gologger
messages.gomessages_aten.gopixel_format.gosecurity.gosecurity_aten.gosecurity_none.gosecurity_tight.gosecurity_vencryptplain.gosecurity_vnc.gosecuritysubtype_string.gosecuritytype_string.goserver.gotightcompression_string.gotightfilter_string.go
36
.vscode/launch.json
vendored
36
.vscode/launch.json
vendored
@ -1,19 +1,19 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
"args": [
|
||||
"localhost:5903"
|
||||
],
|
||||
"program": "${workspaceRoot}/example/client"
|
||||
}
|
||||
|
||||
]
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
"args": [
|
||||
"localhost:5903"
|
||||
],
|
||||
"program": "${workspaceRoot}/example/client"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
90
.vscode/tasks.json
vendored
90
.vscode/tasks.json
vendored
@ -1,46 +1,46 @@
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"command": "go",
|
||||
"isShellCommand": true,
|
||||
"echoCommand": true,
|
||||
"showOutput": "always",
|
||||
// "showOutput": "silent",
|
||||
"options": {
|
||||
// "env": {
|
||||
// "GOPATH": "/Users/lukeh/dd/go"
|
||||
// }
|
||||
},
|
||||
"tasks": [
|
||||
{
|
||||
"taskName": "install",
|
||||
"args": [
|
||||
"-v",
|
||||
"./..."
|
||||
],
|
||||
"osx": {
|
||||
"options": {
|
||||
"env": {
|
||||
//"GOPATH": "${env.HOME}/Dropbox/go"
|
||||
}
|
||||
}
|
||||
},
|
||||
"windows": {
|
||||
"options": {
|
||||
"env": {
|
||||
//"GOPATH": "${env.USERPROFILE}\\Dropbox\\go"
|
||||
}
|
||||
}
|
||||
},
|
||||
"isBuildCommand": true,
|
||||
"problemMatcher": "$go"
|
||||
},
|
||||
{
|
||||
"taskName": "test",
|
||||
"args": [
|
||||
"-v",
|
||||
"./..."
|
||||
],
|
||||
"isTestCommand": true
|
||||
}
|
||||
]
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"command": "go",
|
||||
"isShellCommand": true,
|
||||
"echoCommand": true,
|
||||
"showOutput": "always",
|
||||
// "showOutput": "silent",
|
||||
"options": {
|
||||
// "env": {
|
||||
// "GOPATH": "/Users/lukeh/dd/go"
|
||||
// }
|
||||
},
|
||||
"tasks": [
|
||||
{
|
||||
"taskName": "install",
|
||||
"args": [
|
||||
"-v",
|
||||
"./..."
|
||||
],
|
||||
"osx": {
|
||||
"options": {
|
||||
"env": {
|
||||
//"GOPATH": "${env.HOME}/Dropbox/go"
|
||||
}
|
||||
}
|
||||
},
|
||||
"windows": {
|
||||
"options": {
|
||||
"env": {
|
||||
//"GOPATH": "${env.USERPROFILE}\\Dropbox\\go"
|
||||
}
|
||||
}
|
||||
},
|
||||
"isBuildCommand": true,
|
||||
"problemMatcher": "$go"
|
||||
},
|
||||
{
|
||||
"taskName": "test",
|
||||
"args": [
|
||||
"-v",
|
||||
"./..."
|
||||
],
|
||||
"isTestCommand": true
|
||||
}
|
||||
]
|
||||
}
|
47
LICENSE
47
LICENSE
@ -1,23 +1,24 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013 Mitchell Hashimoto
|
||||
Copyright (c) 2016-2017 Kate Ward
|
||||
Copyright (c) 2017 Vasiliy Tolstov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013 Mitchell Hashimoto
|
||||
Copyright (c) 2016-2017 Kate Ward
|
||||
Copyright (c) 2017 Vasiliy Tolstov
|
||||
Copyright (c) 2018 Amit Bezalel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
@ -1,46 +1,46 @@
|
||||
// Code generated by "stringer -type=Button"; DO NOT EDIT.
|
||||
|
||||
package vnc2webm
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_Button_name_0 = "BtnNoneBtnLeftBtnMiddle"
|
||||
_Button_name_1 = "BtnRight"
|
||||
_Button_name_2 = "BtnFour"
|
||||
_Button_name_3 = "BtnFive"
|
||||
_Button_name_4 = "BtnSix"
|
||||
_Button_name_5 = "BtnSeven"
|
||||
_Button_name_6 = "BtnEight"
|
||||
)
|
||||
|
||||
var (
|
||||
_Button_index_0 = [...]uint8{0, 7, 14, 23}
|
||||
_Button_index_1 = [...]uint8{0, 8}
|
||||
_Button_index_2 = [...]uint8{0, 7}
|
||||
_Button_index_3 = [...]uint8{0, 7}
|
||||
_Button_index_4 = [...]uint8{0, 6}
|
||||
_Button_index_5 = [...]uint8{0, 8}
|
||||
_Button_index_6 = [...]uint8{0, 8}
|
||||
)
|
||||
|
||||
func (i Button) String() string {
|
||||
switch {
|
||||
case 0 <= i && i <= 2:
|
||||
return _Button_name_0[_Button_index_0[i]:_Button_index_0[i+1]]
|
||||
case i == 4:
|
||||
return _Button_name_1
|
||||
case i == 8:
|
||||
return _Button_name_2
|
||||
case i == 16:
|
||||
return _Button_name_3
|
||||
case i == 32:
|
||||
return _Button_name_4
|
||||
case i == 64:
|
||||
return _Button_name_5
|
||||
case i == 128:
|
||||
return _Button_name_6
|
||||
default:
|
||||
return fmt.Sprintf("Button(%d)", i)
|
||||
}
|
||||
}
|
||||
// Code generated by "stringer -type=Button"; DO NOT EDIT.
|
||||
|
||||
package vnc2video
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_Button_name_0 = "BtnNoneBtnLeftBtnMiddle"
|
||||
_Button_name_1 = "BtnRight"
|
||||
_Button_name_2 = "BtnFour"
|
||||
_Button_name_3 = "BtnFive"
|
||||
_Button_name_4 = "BtnSix"
|
||||
_Button_name_5 = "BtnSeven"
|
||||
_Button_name_6 = "BtnEight"
|
||||
)
|
||||
|
||||
var (
|
||||
_Button_index_0 = [...]uint8{0, 7, 14, 23}
|
||||
_Button_index_1 = [...]uint8{0, 8}
|
||||
_Button_index_2 = [...]uint8{0, 7}
|
||||
_Button_index_3 = [...]uint8{0, 7}
|
||||
_Button_index_4 = [...]uint8{0, 6}
|
||||
_Button_index_5 = [...]uint8{0, 8}
|
||||
_Button_index_6 = [...]uint8{0, 8}
|
||||
)
|
||||
|
||||
func (i Button) String() string {
|
||||
switch {
|
||||
case 0 <= i && i <= 2:
|
||||
return _Button_name_0[_Button_index_0[i]:_Button_index_0[i+1]]
|
||||
case i == 4:
|
||||
return _Button_name_1
|
||||
case i == 8:
|
||||
return _Button_name_2
|
||||
case i == 16:
|
||||
return _Button_name_3
|
||||
case i == 32:
|
||||
return _Button_name_4
|
||||
case i == 64:
|
||||
return _Button_name_5
|
||||
case i == 128:
|
||||
return _Button_name_6
|
||||
default:
|
||||
return fmt.Sprintf("Button(%d)", i)
|
||||
}
|
||||
}
|
||||
|
48
buttons.go
48
buttons.go
@ -1,24 +1,24 @@
|
||||
package vnc2webm
|
||||
|
||||
// Button represents a mask of pointer presses/releases.
|
||||
type Button uint8
|
||||
|
||||
//go:generate stringer -type=Button
|
||||
|
||||
// All available button mask components.
|
||||
const (
|
||||
BtnLeft Button = 1 << iota
|
||||
BtnMiddle
|
||||
BtnRight
|
||||
BtnFour
|
||||
BtnFive
|
||||
BtnSix
|
||||
BtnSeven
|
||||
BtnEight
|
||||
BtnNone Button = 0
|
||||
)
|
||||
|
||||
// Mask returns button mask
|
||||
func Mask(button Button) uint8 {
|
||||
return uint8(button)
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
// Button represents a mask of pointer presses/releases.
|
||||
type Button uint8
|
||||
|
||||
//go:generate stringer -type=Button
|
||||
|
||||
// All available button mask components.
|
||||
const (
|
||||
BtnLeft Button = 1 << iota
|
||||
BtnMiddle
|
||||
BtnRight
|
||||
BtnFour
|
||||
BtnFive
|
||||
BtnSix
|
||||
BtnSeven
|
||||
BtnEight
|
||||
BtnNone Button = 0
|
||||
)
|
||||
|
||||
// Mask returns button mask
|
||||
func Mask(button Button) uint8 {
|
||||
return uint8(button)
|
||||
}
|
||||
|
694
client.go
694
client.go
@ -1,347 +1,347 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"vnc2webm/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultClientHandlers represents default client handlers
|
||||
DefaultClientHandlers = []Handler{
|
||||
&DefaultClientVersionHandler{},
|
||||
&DefaultClientSecurityHandler{},
|
||||
&DefaultClientClientInitHandler{},
|
||||
&DefaultClientServerInitHandler{},
|
||||
&DefaultClientMessageHandler{},
|
||||
}
|
||||
)
|
||||
|
||||
// Connect handshake with remote server using underlining net.Conn
|
||||
func Connect(ctx context.Context, c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
|
||||
conn, err := NewClientConn(c, cfg)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
cfg.ErrorCh <- err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(cfg.Handlers) == 0 {
|
||||
cfg.Handlers = DefaultClientHandlers
|
||||
}
|
||||
|
||||
for _, h := range cfg.Handlers {
|
||||
if err := h.Handle(conn); err != nil {
|
||||
conn.Close()
|
||||
cfg.ErrorCh <- err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
var _ Conn = (*ClientConn)(nil)
|
||||
|
||||
// Config returns connection config
|
||||
func (c *ClientConn) Config() interface{} {
|
||||
return c.cfg
|
||||
}
|
||||
|
||||
func (c *ClientConn) GetEncInstance(typ EncodingType) Encoding {
|
||||
for _, enc := range c.encodings {
|
||||
if enc.Type() == typ {
|
||||
return enc
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wait waiting for connection close
|
||||
func (c *ClientConn) Wait() {
|
||||
<-c.quit
|
||||
}
|
||||
|
||||
// Conn return underlining net.Conn
|
||||
func (c *ClientConn) Conn() net.Conn {
|
||||
return c.c
|
||||
}
|
||||
|
||||
// SetProtoVersion sets proto version
|
||||
func (c *ClientConn) SetProtoVersion(pv string) {
|
||||
c.protocol = pv
|
||||
}
|
||||
|
||||
// SetEncodings write SetEncodings message
|
||||
func (c *ClientConn) SetEncodings(encs []EncodingType) error {
|
||||
|
||||
msg := &SetEncodings{
|
||||
EncNum: uint16(len(encs)),
|
||||
Encodings: encs,
|
||||
}
|
||||
|
||||
return msg.Write(c)
|
||||
}
|
||||
|
||||
// Flush flushes data to conn
|
||||
func (c *ClientConn) Flush() error {
|
||||
return c.bw.Flush()
|
||||
}
|
||||
|
||||
// Close closing conn
|
||||
func (c *ClientConn) Close() error {
|
||||
if c.quit != nil {
|
||||
close(c.quit)
|
||||
c.quit = nil
|
||||
}
|
||||
if c.quitCh != nil {
|
||||
close(c.quitCh)
|
||||
}
|
||||
return c.c.Close()
|
||||
}
|
||||
|
||||
// Read reads data from conn
|
||||
func (c *ClientConn) Read(buf []byte) (int, error) {
|
||||
return c.br.Read(buf)
|
||||
}
|
||||
|
||||
// Write data to conn must be Flushed
|
||||
func (c *ClientConn) Write(buf []byte) (int, error) {
|
||||
return c.bw.Write(buf)
|
||||
}
|
||||
|
||||
// ColorMap returns color map
|
||||
func (c *ClientConn) ColorMap() ColorMap {
|
||||
return c.colorMap
|
||||
}
|
||||
|
||||
// SetColorMap sets color map
|
||||
func (c *ClientConn) SetColorMap(cm ColorMap) {
|
||||
c.colorMap = cm
|
||||
}
|
||||
|
||||
// DesktopName returns connection desktop name
|
||||
func (c *ClientConn) DesktopName() []byte {
|
||||
return c.desktopName
|
||||
}
|
||||
|
||||
// PixelFormat returns connection pixel format
|
||||
func (c *ClientConn) PixelFormat() PixelFormat {
|
||||
return c.pixelFormat
|
||||
}
|
||||
|
||||
// SetDesktopName sets desktop name
|
||||
func (c *ClientConn) SetDesktopName(name []byte) {
|
||||
c.desktopName = name
|
||||
}
|
||||
|
||||
// SetPixelFormat sets pixel format
|
||||
func (c *ClientConn) SetPixelFormat(pf PixelFormat) error {
|
||||
c.pixelFormat = pf
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encodings returns client encodings
|
||||
func (c *ClientConn) Encodings() []Encoding {
|
||||
return c.encodings
|
||||
}
|
||||
|
||||
// Width returns width
|
||||
func (c *ClientConn) Width() uint16 {
|
||||
return c.fbWidth
|
||||
}
|
||||
|
||||
// Height returns height
|
||||
func (c *ClientConn) Height() uint16 {
|
||||
return c.fbHeight
|
||||
}
|
||||
|
||||
// Protocol returns protocol
|
||||
func (c *ClientConn) Protocol() string {
|
||||
return c.protocol
|
||||
}
|
||||
|
||||
// SetWidth sets width of client conn
|
||||
func (c *ClientConn) SetWidth(width uint16) {
|
||||
c.fbWidth = width
|
||||
}
|
||||
|
||||
// SetHeight sets height of client conn
|
||||
func (c *ClientConn) SetHeight(height uint16) {
|
||||
c.fbHeight = height
|
||||
}
|
||||
|
||||
// SecurityHandler returns security handler
|
||||
func (c *ClientConn) SecurityHandler() SecurityHandler {
|
||||
return c.securityHandler
|
||||
}
|
||||
|
||||
// SetSecurityHandler sets security handler
|
||||
func (c *ClientConn) SetSecurityHandler(sechandler SecurityHandler) error {
|
||||
c.securityHandler = sechandler
|
||||
return nil
|
||||
}
|
||||
|
||||
// The ClientConn type holds client connection information
|
||||
type ClientConn struct {
|
||||
c net.Conn
|
||||
br *bufio.Reader
|
||||
bw *bufio.Writer
|
||||
cfg *ClientConfig
|
||||
protocol string
|
||||
// If the pixel format uses a color map, then this is the color
|
||||
// map that is used. This should not be modified directly, since
|
||||
// the data comes from the server.
|
||||
// Definition in §5 - Representation of Pixel Data.
|
||||
colorMap ColorMap
|
||||
|
||||
// Name associated with the desktop, sent from the server.
|
||||
desktopName []byte
|
||||
|
||||
// Encodings supported by the client. This should not be modified
|
||||
// directly. Instead, SetEncodings() should be used.
|
||||
encodings []Encoding
|
||||
|
||||
securityHandler SecurityHandler
|
||||
|
||||
// Height of the frame buffer in pixels, sent from the server.
|
||||
fbHeight uint16
|
||||
|
||||
// Width of the frame buffer in pixels, sent from the server.
|
||||
fbWidth uint16
|
||||
|
||||
// The pixel format associated with the connection. This shouldn't
|
||||
// be modified. If you wish to set a new pixel format, use the
|
||||
// SetPixelFormat method.
|
||||
pixelFormat PixelFormat
|
||||
|
||||
quitCh chan struct{}
|
||||
quit chan struct{}
|
||||
errorCh chan error
|
||||
}
|
||||
|
||||
func (cc *ClientConn) ResetAllEncodings() {
|
||||
for _, enc := range cc.encodings {
|
||||
enc.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
// NewClientConn creates new client conn using config
|
||||
func NewClientConn(c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
|
||||
if len(cfg.Encodings) == 0 {
|
||||
return nil, fmt.Errorf("client can't handle encodings")
|
||||
}
|
||||
return &ClientConn{
|
||||
c: c,
|
||||
cfg: cfg,
|
||||
br: bufio.NewReader(c),
|
||||
bw: bufio.NewWriter(c),
|
||||
encodings: cfg.Encodings,
|
||||
quitCh: cfg.QuitCh,
|
||||
errorCh: cfg.ErrorCh,
|
||||
pixelFormat: cfg.PixelFormat,
|
||||
quit: make(chan struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DefaultClientMessageHandler represents default client message handler
|
||||
type DefaultClientMessageHandler struct{}
|
||||
|
||||
// Handle handles server messages.
|
||||
func (*DefaultClientMessageHandler) Handle(c Conn) error {
|
||||
logger.Debug("starting DefaultClientMessageHandler")
|
||||
cfg := c.Config().(*ClientConfig)
|
||||
var err error
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
//defer c.Close()
|
||||
|
||||
serverMessages := make(map[ServerMessageType]ServerMessage)
|
||||
for _, m := range cfg.Messages {
|
||||
serverMessages[m.Type()] = m
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case msg := <-cfg.ClientMessageCh:
|
||||
if err = msg.Write(c); err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
default:
|
||||
var messageType ServerMessageType
|
||||
if err = binary.Read(c, binary.BigEndian, &messageType); err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
return
|
||||
}
|
||||
logger.Debugf("got server message, msgType=%d", messageType)
|
||||
msg, ok := serverMessages[messageType]
|
||||
if !ok {
|
||||
err = fmt.Errorf("unknown message-type: %v", messageType)
|
||||
cfg.ErrorCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
parsedMsg, err := msg.Read(c)
|
||||
logger.Debugf("============== End Message: type=%d ==============", messageType)
|
||||
|
||||
if err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
return
|
||||
}
|
||||
cfg.ServerMessageCh <- parsedMsg
|
||||
}
|
||||
}
|
||||
}()
|
||||
//encodings := c.Encodings()
|
||||
encTypes := make(map[EncodingType]EncodingType)
|
||||
for _, myEnc := range c.Encodings() {
|
||||
encTypes[myEnc.Type()] = myEnc.Type()
|
||||
//encTypes = append(encTypes, myEnc.Type())
|
||||
}
|
||||
v := make([]EncodingType, 0, len(encTypes))
|
||||
|
||||
for _, value := range encTypes {
|
||||
v = append(v, value)
|
||||
}
|
||||
logger.Debugf("setting encodings: %v", v)
|
||||
c.SetEncodings(v)
|
||||
|
||||
firstMsg := FramebufferUpdateRequest{Inc: 0, X: 0, Y: 0, Width: c.Width(), Height: c.Height()}
|
||||
logger.Debugf("sending initial req message: %v", firstMsg)
|
||||
firstMsg.Write(c)
|
||||
|
||||
//wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// A ClientConfig structure is used to configure a ClientConn. After
|
||||
// one has been passed to initialize a connection, it must not be modified.
|
||||
type ClientConfig struct {
|
||||
Handlers []Handler
|
||||
SecurityHandlers []SecurityHandler
|
||||
Encodings []Encoding
|
||||
PixelFormat PixelFormat
|
||||
ColorMap ColorMap
|
||||
ClientMessageCh chan ClientMessage
|
||||
ServerMessageCh chan ServerMessage
|
||||
Exclusive bool
|
||||
Messages []ServerMessage
|
||||
QuitCh chan struct{}
|
||||
ErrorCh chan error
|
||||
quit chan struct{}
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"vnc2video/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultClientHandlers represents default client handlers
|
||||
DefaultClientHandlers = []Handler{
|
||||
&DefaultClientVersionHandler{},
|
||||
&DefaultClientSecurityHandler{},
|
||||
&DefaultClientClientInitHandler{},
|
||||
&DefaultClientServerInitHandler{},
|
||||
&DefaultClientMessageHandler{},
|
||||
}
|
||||
)
|
||||
|
||||
// Connect handshake with remote server using underlining net.Conn
|
||||
func Connect(ctx context.Context, c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
|
||||
conn, err := NewClientConn(c, cfg)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
cfg.ErrorCh <- err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(cfg.Handlers) == 0 {
|
||||
cfg.Handlers = DefaultClientHandlers
|
||||
}
|
||||
|
||||
for _, h := range cfg.Handlers {
|
||||
if err := h.Handle(conn); err != nil {
|
||||
conn.Close()
|
||||
cfg.ErrorCh <- err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
var _ Conn = (*ClientConn)(nil)
|
||||
|
||||
// Config returns connection config
|
||||
func (c *ClientConn) Config() interface{} {
|
||||
return c.cfg
|
||||
}
|
||||
|
||||
func (c *ClientConn) GetEncInstance(typ EncodingType) Encoding {
|
||||
for _, enc := range c.encodings {
|
||||
if enc.Type() == typ {
|
||||
return enc
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wait waiting for connection close
|
||||
func (c *ClientConn) Wait() {
|
||||
<-c.quit
|
||||
}
|
||||
|
||||
// Conn return underlining net.Conn
|
||||
func (c *ClientConn) Conn() net.Conn {
|
||||
return c.c
|
||||
}
|
||||
|
||||
// SetProtoVersion sets proto version
|
||||
func (c *ClientConn) SetProtoVersion(pv string) {
|
||||
c.protocol = pv
|
||||
}
|
||||
|
||||
// SetEncodings write SetEncodings message
|
||||
func (c *ClientConn) SetEncodings(encs []EncodingType) error {
|
||||
|
||||
msg := &SetEncodings{
|
||||
EncNum: uint16(len(encs)),
|
||||
Encodings: encs,
|
||||
}
|
||||
|
||||
return msg.Write(c)
|
||||
}
|
||||
|
||||
// Flush flushes data to conn
|
||||
func (c *ClientConn) Flush() error {
|
||||
return c.bw.Flush()
|
||||
}
|
||||
|
||||
// Close closing conn
|
||||
func (c *ClientConn) Close() error {
|
||||
if c.quit != nil {
|
||||
close(c.quit)
|
||||
c.quit = nil
|
||||
}
|
||||
if c.quitCh != nil {
|
||||
close(c.quitCh)
|
||||
}
|
||||
return c.c.Close()
|
||||
}
|
||||
|
||||
// Read reads data from conn
|
||||
func (c *ClientConn) Read(buf []byte) (int, error) {
|
||||
return c.br.Read(buf)
|
||||
}
|
||||
|
||||
// Write data to conn must be Flushed
|
||||
func (c *ClientConn) Write(buf []byte) (int, error) {
|
||||
return c.bw.Write(buf)
|
||||
}
|
||||
|
||||
// ColorMap returns color map
|
||||
func (c *ClientConn) ColorMap() ColorMap {
|
||||
return c.colorMap
|
||||
}
|
||||
|
||||
// SetColorMap sets color map
|
||||
func (c *ClientConn) SetColorMap(cm ColorMap) {
|
||||
c.colorMap = cm
|
||||
}
|
||||
|
||||
// DesktopName returns connection desktop name
|
||||
func (c *ClientConn) DesktopName() []byte {
|
||||
return c.desktopName
|
||||
}
|
||||
|
||||
// PixelFormat returns connection pixel format
|
||||
func (c *ClientConn) PixelFormat() PixelFormat {
|
||||
return c.pixelFormat
|
||||
}
|
||||
|
||||
// SetDesktopName sets desktop name
|
||||
func (c *ClientConn) SetDesktopName(name []byte) {
|
||||
c.desktopName = name
|
||||
}
|
||||
|
||||
// SetPixelFormat sets pixel format
|
||||
func (c *ClientConn) SetPixelFormat(pf PixelFormat) error {
|
||||
c.pixelFormat = pf
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encodings returns client encodings
|
||||
func (c *ClientConn) Encodings() []Encoding {
|
||||
return c.encodings
|
||||
}
|
||||
|
||||
// Width returns width
|
||||
func (c *ClientConn) Width() uint16 {
|
||||
return c.fbWidth
|
||||
}
|
||||
|
||||
// Height returns height
|
||||
func (c *ClientConn) Height() uint16 {
|
||||
return c.fbHeight
|
||||
}
|
||||
|
||||
// Protocol returns protocol
|
||||
func (c *ClientConn) Protocol() string {
|
||||
return c.protocol
|
||||
}
|
||||
|
||||
// SetWidth sets width of client conn
|
||||
func (c *ClientConn) SetWidth(width uint16) {
|
||||
c.fbWidth = width
|
||||
}
|
||||
|
||||
// SetHeight sets height of client conn
|
||||
func (c *ClientConn) SetHeight(height uint16) {
|
||||
c.fbHeight = height
|
||||
}
|
||||
|
||||
// SecurityHandler returns security handler
|
||||
func (c *ClientConn) SecurityHandler() SecurityHandler {
|
||||
return c.securityHandler
|
||||
}
|
||||
|
||||
// SetSecurityHandler sets security handler
|
||||
func (c *ClientConn) SetSecurityHandler(sechandler SecurityHandler) error {
|
||||
c.securityHandler = sechandler
|
||||
return nil
|
||||
}
|
||||
|
||||
// The ClientConn type holds client connection information
|
||||
type ClientConn struct {
|
||||
c net.Conn
|
||||
br *bufio.Reader
|
||||
bw *bufio.Writer
|
||||
cfg *ClientConfig
|
||||
protocol string
|
||||
// If the pixel format uses a color map, then this is the color
|
||||
// map that is used. This should not be modified directly, since
|
||||
// the data comes from the server.
|
||||
// Definition in §5 - Representation of Pixel Data.
|
||||
colorMap ColorMap
|
||||
|
||||
// Name associated with the desktop, sent from the server.
|
||||
desktopName []byte
|
||||
|
||||
// Encodings supported by the client. This should not be modified
|
||||
// directly. Instead, SetEncodings() should be used.
|
||||
encodings []Encoding
|
||||
|
||||
securityHandler SecurityHandler
|
||||
|
||||
// Height of the frame buffer in pixels, sent from the server.
|
||||
fbHeight uint16
|
||||
|
||||
// Width of the frame buffer in pixels, sent from the server.
|
||||
fbWidth uint16
|
||||
|
||||
// The pixel format associated with the connection. This shouldn't
|
||||
// be modified. If you wish to set a new pixel format, use the
|
||||
// SetPixelFormat method.
|
||||
pixelFormat PixelFormat
|
||||
|
||||
quitCh chan struct{}
|
||||
quit chan struct{}
|
||||
errorCh chan error
|
||||
}
|
||||
|
||||
func (cc *ClientConn) ResetAllEncodings() {
|
||||
for _, enc := range cc.encodings {
|
||||
enc.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
// NewClientConn creates new client conn using config
|
||||
func NewClientConn(c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
|
||||
if len(cfg.Encodings) == 0 {
|
||||
return nil, fmt.Errorf("client can't handle encodings")
|
||||
}
|
||||
return &ClientConn{
|
||||
c: c,
|
||||
cfg: cfg,
|
||||
br: bufio.NewReader(c),
|
||||
bw: bufio.NewWriter(c),
|
||||
encodings: cfg.Encodings,
|
||||
quitCh: cfg.QuitCh,
|
||||
errorCh: cfg.ErrorCh,
|
||||
pixelFormat: cfg.PixelFormat,
|
||||
quit: make(chan struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DefaultClientMessageHandler represents default client message handler
|
||||
type DefaultClientMessageHandler struct{}
|
||||
|
||||
// Handle handles server messages.
|
||||
func (*DefaultClientMessageHandler) Handle(c Conn) error {
|
||||
logger.Debug("starting DefaultClientMessageHandler")
|
||||
cfg := c.Config().(*ClientConfig)
|
||||
var err error
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
//defer c.Close()
|
||||
|
||||
serverMessages := make(map[ServerMessageType]ServerMessage)
|
||||
for _, m := range cfg.Messages {
|
||||
serverMessages[m.Type()] = m
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case msg := <-cfg.ClientMessageCh:
|
||||
if err = msg.Write(c); err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
default:
|
||||
var messageType ServerMessageType
|
||||
if err = binary.Read(c, binary.BigEndian, &messageType); err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
return
|
||||
}
|
||||
logger.Debugf("got server message, msgType=%d", messageType)
|
||||
msg, ok := serverMessages[messageType]
|
||||
if !ok {
|
||||
err = fmt.Errorf("unknown message-type: %v", messageType)
|
||||
cfg.ErrorCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
parsedMsg, err := msg.Read(c)
|
||||
logger.Debugf("============== End Message: type=%d ==============", messageType)
|
||||
|
||||
if err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
return
|
||||
}
|
||||
cfg.ServerMessageCh <- parsedMsg
|
||||
}
|
||||
}
|
||||
}()
|
||||
//encodings := c.Encodings()
|
||||
encTypes := make(map[EncodingType]EncodingType)
|
||||
for _, myEnc := range c.Encodings() {
|
||||
encTypes[myEnc.Type()] = myEnc.Type()
|
||||
//encTypes = append(encTypes, myEnc.Type())
|
||||
}
|
||||
v := make([]EncodingType, 0, len(encTypes))
|
||||
|
||||
for _, value := range encTypes {
|
||||
v = append(v, value)
|
||||
}
|
||||
logger.Debugf("setting encodings: %v", v)
|
||||
c.SetEncodings(v)
|
||||
|
||||
firstMsg := FramebufferUpdateRequest{Inc: 0, X: 0, Y: 0, Width: c.Width(), Height: c.Height()}
|
||||
logger.Debugf("sending initial req message: %v", firstMsg)
|
||||
firstMsg.Write(c)
|
||||
|
||||
//wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// A ClientConfig structure is used to configure a ClientConn. After
|
||||
// one has been passed to initialize a connection, it must not be modified.
|
||||
type ClientConfig struct {
|
||||
Handlers []Handler
|
||||
SecurityHandlers []SecurityHandler
|
||||
Encodings []Encoding
|
||||
PixelFormat PixelFormat
|
||||
ColorMap ColorMap
|
||||
ClientMessageCh chan ClientMessage
|
||||
ServerMessageCh chan ServerMessage
|
||||
Exclusive bool
|
||||
Messages []ServerMessage
|
||||
QuitCh chan struct{}
|
||||
ErrorCh chan error
|
||||
quit chan struct{}
|
||||
}
|
||||
|
@ -1,27 +1,27 @@
|
||||
// Code generated by "stringer -type=ClientMessageType"; DO NOT EDIT.
|
||||
|
||||
package vnc2webm
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_ClientMessageType_name_0 = "SetPixelFormatMsgType"
|
||||
_ClientMessageType_name_1 = "SetEncodingsMsgTypeFramebufferUpdateRequestMsgTypeKeyEventMsgTypePointerEventMsgTypeClientCutTextMsgType"
|
||||
)
|
||||
|
||||
var (
|
||||
_ClientMessageType_index_0 = [...]uint8{0, 21}
|
||||
_ClientMessageType_index_1 = [...]uint8{0, 19, 50, 65, 84, 104}
|
||||
)
|
||||
|
||||
func (i ClientMessageType) String() string {
|
||||
switch {
|
||||
case i == 0:
|
||||
return _ClientMessageType_name_0
|
||||
case 2 <= i && i <= 6:
|
||||
i -= 2
|
||||
return _ClientMessageType_name_1[_ClientMessageType_index_1[i]:_ClientMessageType_index_1[i+1]]
|
||||
default:
|
||||
return fmt.Sprintf("ClientMessageType(%d)", i)
|
||||
}
|
||||
}
|
||||
// Code generated by "stringer -type=ClientMessageType"; DO NOT EDIT.
|
||||
|
||||
package vnc2video
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_ClientMessageType_name_0 = "SetPixelFormatMsgType"
|
||||
_ClientMessageType_name_1 = "SetEncodingsMsgTypeFramebufferUpdateRequestMsgTypeKeyEventMsgTypePointerEventMsgTypeClientCutTextMsgType"
|
||||
)
|
||||
|
||||
var (
|
||||
_ClientMessageType_index_0 = [...]uint8{0, 21}
|
||||
_ClientMessageType_index_1 = [...]uint8{0, 19, 50, 65, 84, 104}
|
||||
)
|
||||
|
||||
func (i ClientMessageType) String() string {
|
||||
switch {
|
||||
case i == 0:
|
||||
return _ClientMessageType_name_0
|
||||
case 2 <= i && i <= 6:
|
||||
i -= 2
|
||||
return _ClientMessageType_name_1[_ClientMessageType_index_1[i]:_ClientMessageType_index_1[i+1]]
|
||||
default:
|
||||
return fmt.Sprintf("ClientMessageType(%d)", i)
|
||||
}
|
||||
}
|
||||
|
64
conn.go
64
conn.go
@ -1,32 +1,32 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Conn represents vnc conection
|
||||
type Conn interface {
|
||||
io.ReadWriteCloser
|
||||
Conn() net.Conn
|
||||
Config() interface{}
|
||||
Protocol() string
|
||||
PixelFormat() PixelFormat
|
||||
SetPixelFormat(PixelFormat) error
|
||||
ColorMap() ColorMap
|
||||
SetColorMap(ColorMap)
|
||||
Encodings() []Encoding
|
||||
SetEncodings([]EncodingType) error
|
||||
Width() uint16
|
||||
Height() uint16
|
||||
SetWidth(uint16)
|
||||
SetHeight(uint16)
|
||||
DesktopName() []byte
|
||||
SetDesktopName([]byte)
|
||||
Flush() error
|
||||
Wait()
|
||||
SetProtoVersion(string)
|
||||
SetSecurityHandler(SecurityHandler) error
|
||||
SecurityHandler() SecurityHandler
|
||||
GetEncInstance(EncodingType) Encoding
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Conn represents vnc conection
|
||||
type Conn interface {
|
||||
io.ReadWriteCloser
|
||||
Conn() net.Conn
|
||||
Config() interface{}
|
||||
Protocol() string
|
||||
PixelFormat() PixelFormat
|
||||
SetPixelFormat(PixelFormat) error
|
||||
ColorMap() ColorMap
|
||||
SetColorMap(ColorMap)
|
||||
Encodings() []Encoding
|
||||
SetEncodings([]EncodingType) error
|
||||
Width() uint16
|
||||
Height() uint16
|
||||
SetWidth(uint16)
|
||||
SetHeight(uint16)
|
||||
DesktopName() []byte
|
||||
SetDesktopName([]byte)
|
||||
Flush() error
|
||||
Wait()
|
||||
SetProtoVersion(string)
|
||||
SetSecurityHandler(SecurityHandler) error
|
||||
SecurityHandler() SecurityHandler
|
||||
GetEncInstance(EncodingType) Encoding
|
||||
}
|
||||
|
@ -1,91 +1,91 @@
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"image"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"vnc2webm/logger"
|
||||
)
|
||||
|
||||
type DV8ImageEncoder struct {
|
||||
cmd *exec.Cmd
|
||||
binaryPath string
|
||||
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", "5",
|
||||
//"-i", "pipe:0",
|
||||
"-i", "-",
|
||||
"-vcodec", "libvpx", //"libvpx",//"libvpx-vp9"//"libx264"
|
||||
"-b:v", "1M",
|
||||
"-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(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 *DV8ImageEncoder) Encode(img image.Image) {
|
||||
err := encodePPM(enc.input, img)
|
||||
if err != nil {
|
||||
logger.Error("error while encoding image:", err)
|
||||
}
|
||||
}
|
||||
func (enc *DV8ImageEncoder) Close() {
|
||||
|
||||
}
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"image"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"vnc2video/logger"
|
||||
)
|
||||
|
||||
type DV8ImageEncoder struct {
|
||||
cmd *exec.Cmd
|
||||
binaryPath string
|
||||
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", "5",
|
||||
//"-i", "pipe:0",
|
||||
"-i", "-",
|
||||
"-vcodec", "libvpx", //"libvpx",//"libvpx-vp9"//"libx264"
|
||||
"-b:v", "1M",
|
||||
"-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(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 *DV8ImageEncoder) Encode(img image.Image) {
|
||||
err := encodePPM(enc.input, img)
|
||||
if err != nil {
|
||||
logger.Error("error while encoding image:", err)
|
||||
}
|
||||
}
|
||||
func (enc *DV8ImageEncoder) Close() {
|
||||
|
||||
}
|
||||
|
@ -1,91 +1,91 @@
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"image"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"vnc2webm/logger"
|
||||
)
|
||||
|
||||
type DV9ImageEncoder struct {
|
||||
cmd *exec.Cmd
|
||||
binaryPath string
|
||||
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", "5",
|
||||
//"-i", "pipe:0",
|
||||
"-i", "-",
|
||||
"-vcodec", "libvpx-vp9", //"libvpx",//"libvpx-vp9"//"libx264"
|
||||
"-b:v", "1M",
|
||||
"-threads", "8",
|
||||
//"-speed", "0",
|
||||
//"-lossless", "1", //for vpx
|
||||
// "-tile-columns", "6",
|
||||
//"-frame-parallel", "1",
|
||||
// "-an", "-f", "webm",
|
||||
"-cpu-used", "-8",
|
||||
|
||||
"-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(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 *DV9ImageEncoder) Encode(img image.Image) {
|
||||
err := encodePPM(enc.input, img)
|
||||
if err != nil {
|
||||
logger.Error("error while encoding image:", err)
|
||||
}
|
||||
}
|
||||
func (enc *DV9ImageEncoder) Close() {
|
||||
|
||||
}
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"image"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"vnc2video/logger"
|
||||
)
|
||||
|
||||
type DV9ImageEncoder struct {
|
||||
cmd *exec.Cmd
|
||||
binaryPath string
|
||||
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", "5",
|
||||
//"-i", "pipe:0",
|
||||
"-i", "-",
|
||||
"-vcodec", "libvpx-vp9", //"libvpx",//"libvpx-vp9"//"libx264"
|
||||
"-b:v", "1M",
|
||||
"-threads", "8",
|
||||
//"-speed", "0",
|
||||
//"-lossless", "1", //for vpx
|
||||
// "-tile-columns", "6",
|
||||
//"-frame-parallel", "1",
|
||||
// "-an", "-f", "webm",
|
||||
"-cpu-used", "-8",
|
||||
|
||||
"-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(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 *DV9ImageEncoder) Encode(img image.Image) {
|
||||
err := encodePPM(enc.input, img)
|
||||
if err != nil {
|
||||
logger.Error("error while encoding image:", err)
|
||||
}
|
||||
}
|
||||
func (enc *DV9ImageEncoder) Close() {
|
||||
|
||||
}
|
||||
|
@ -1,43 +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()
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
@ -1,56 +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)
|
||||
}
|
||||
}
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
"strings"
|
||||
"vnc2video/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)
|
||||
}
|
||||
}
|
||||
|
@ -1,92 +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", "1M",
|
||||
"-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() {
|
||||
|
||||
}
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"image"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"vnc2video/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", "1M",
|
||||
"-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() {
|
||||
|
||||
}
|
||||
|
242
encoding.go
242
encoding.go
@ -1,121 +1,121 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/draw"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// EncodingType represents a known VNC encoding type.
|
||||
type EncodingType int32
|
||||
|
||||
//go:generate stringer -type=EncodingType
|
||||
|
||||
const (
|
||||
// EncRaw raw encoding
|
||||
EncRaw EncodingType = 0
|
||||
// EncCopyRect copyrect encoding
|
||||
EncCopyRect EncodingType = 1
|
||||
|
||||
EncRRE EncodingType = 2
|
||||
EncCoRRE EncodingType = 4
|
||||
EncHextile EncodingType = 5
|
||||
EncZlib EncodingType = 6
|
||||
EncTight EncodingType = 7
|
||||
EncZlibHex EncodingType = 8
|
||||
EncUltra1 EncodingType = 9
|
||||
EncUltra2 EncodingType = 10
|
||||
EncJPEG EncodingType = 21
|
||||
EncJRLE EncodingType = 22
|
||||
EncTRLE EncodingType = 15
|
||||
EncZRLE EncodingType = 16
|
||||
EncAtenAST2100 EncodingType = 0x57
|
||||
EncAtenASTJPEG EncodingType = 0x58
|
||||
EncAtenHermon EncodingType = 0x59
|
||||
EncAtenYarkon EncodingType = 0x60
|
||||
EncAtenPilot3 EncodingType = 0x61
|
||||
EncJPEGQualityLevelPseudo10 EncodingType = -23
|
||||
EncJPEGQualityLevelPseudo9 EncodingType = -24
|
||||
EncJPEGQualityLevelPseudo8 EncodingType = -25
|
||||
EncJPEGQualityLevelPseudo7 EncodingType = -26
|
||||
EncJPEGQualityLevelPseudo6 EncodingType = -27
|
||||
EncJPEGQualityLevelPseudo5 EncodingType = -28
|
||||
EncJPEGQualityLevelPseudo4 EncodingType = -29
|
||||
EncJPEGQualityLevelPseudo3 EncodingType = -30
|
||||
EncJPEGQualityLevelPseudo2 EncodingType = -31
|
||||
EncJPEGQualityLevelPseudo1 EncodingType = -32
|
||||
EncCursorPseudo EncodingType = -239
|
||||
EncXCursorPseudo EncodingType = -240
|
||||
EncDesktopSizePseudo EncodingType = -223
|
||||
EncLastRectPseudo EncodingType = -224
|
||||
EncCompressionLevel10 EncodingType = -247
|
||||
EncCompressionLevel9 EncodingType = -248
|
||||
EncCompressionLevel8 EncodingType = -249
|
||||
EncCompressionLevel7 EncodingType = -250
|
||||
EncCompressionLevel6 EncodingType = -251
|
||||
EncCompressionLevel5 EncodingType = -252
|
||||
EncCompressionLevel4 EncodingType = -253
|
||||
EncCompressionLevel3 EncodingType = -254
|
||||
EncCompressionLevel2 EncodingType = -255
|
||||
EncCompressionLevel1 EncodingType = -256
|
||||
EncQEMUPointerMotionChangePseudo EncodingType = -257
|
||||
EncQEMUExtendedKeyEventPseudo EncodingType = -258
|
||||
EncTightPng EncodingType = -260
|
||||
EncDesktopNamePseudo EncodingType = -307
|
||||
EncExtendedDesktopSizePseudo EncodingType = -308
|
||||
EncXvpPseudo EncodingType = -309
|
||||
EncClientRedirect EncodingType = -311
|
||||
EncFencePseudo EncodingType = -312
|
||||
EncContinuousUpdatesPseudo EncodingType = -313
|
||||
)
|
||||
|
||||
var bPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
// The Pool's New function should generally only return pointer
|
||||
// types, since a pointer can be put into the return interface
|
||||
// value without an allocation:
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
type Renderer interface {
|
||||
SetTargetImage(draw.Image)
|
||||
}
|
||||
|
||||
// Encoding represents interface for vnc encoding
|
||||
type Encoding interface {
|
||||
Type() EncodingType
|
||||
Read(Conn, *Rectangle) error
|
||||
Write(Conn, *Rectangle) error
|
||||
Supported(Conn) bool
|
||||
Reset() error
|
||||
}
|
||||
|
||||
func setBit(n uint8, pos uint8) uint8 {
|
||||
n |= (1 << pos)
|
||||
return n
|
||||
}
|
||||
|
||||
func clrBit(n uint8, pos uint8) uint8 {
|
||||
n = n &^ (1 << pos)
|
||||
return n
|
||||
}
|
||||
|
||||
func hasBit(n uint8, pos uint8) bool {
|
||||
v := n & (1 << pos)
|
||||
return (v > 0)
|
||||
}
|
||||
|
||||
func getBit(n uint8, pos uint8) uint8 {
|
||||
n = n & (1 << pos)
|
||||
return n
|
||||
}
|
||||
|
||||
func newRGBAImage(rgba []byte, rect *Rectangle) image.Image {
|
||||
img := &image.RGBA{Stride: 4 * int(rect.Width)}
|
||||
img.Pix = rgba
|
||||
img.Rect.Max.X = int(rect.Width)
|
||||
img.Rect.Max.Y = int(rect.Height)
|
||||
return img
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/draw"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// EncodingType represents a known VNC encoding type.
|
||||
type EncodingType int32
|
||||
|
||||
//go:generate stringer -type=EncodingType
|
||||
|
||||
const (
|
||||
// EncRaw raw encoding
|
||||
EncRaw EncodingType = 0
|
||||
// EncCopyRect copyrect encoding
|
||||
EncCopyRect EncodingType = 1
|
||||
|
||||
EncRRE EncodingType = 2
|
||||
EncCoRRE EncodingType = 4
|
||||
EncHextile EncodingType = 5
|
||||
EncZlib EncodingType = 6
|
||||
EncTight EncodingType = 7
|
||||
EncZlibHex EncodingType = 8
|
||||
EncUltra1 EncodingType = 9
|
||||
EncUltra2 EncodingType = 10
|
||||
EncJPEG EncodingType = 21
|
||||
EncJRLE EncodingType = 22
|
||||
EncTRLE EncodingType = 15
|
||||
EncZRLE EncodingType = 16
|
||||
EncAtenAST2100 EncodingType = 0x57
|
||||
EncAtenASTJPEG EncodingType = 0x58
|
||||
EncAtenHermon EncodingType = 0x59
|
||||
EncAtenYarkon EncodingType = 0x60
|
||||
EncAtenPilot3 EncodingType = 0x61
|
||||
EncJPEGQualityLevelPseudo10 EncodingType = -23
|
||||
EncJPEGQualityLevelPseudo9 EncodingType = -24
|
||||
EncJPEGQualityLevelPseudo8 EncodingType = -25
|
||||
EncJPEGQualityLevelPseudo7 EncodingType = -26
|
||||
EncJPEGQualityLevelPseudo6 EncodingType = -27
|
||||
EncJPEGQualityLevelPseudo5 EncodingType = -28
|
||||
EncJPEGQualityLevelPseudo4 EncodingType = -29
|
||||
EncJPEGQualityLevelPseudo3 EncodingType = -30
|
||||
EncJPEGQualityLevelPseudo2 EncodingType = -31
|
||||
EncJPEGQualityLevelPseudo1 EncodingType = -32
|
||||
EncCursorPseudo EncodingType = -239
|
||||
EncXCursorPseudo EncodingType = -240
|
||||
EncDesktopSizePseudo EncodingType = -223
|
||||
EncLastRectPseudo EncodingType = -224
|
||||
EncCompressionLevel10 EncodingType = -247
|
||||
EncCompressionLevel9 EncodingType = -248
|
||||
EncCompressionLevel8 EncodingType = -249
|
||||
EncCompressionLevel7 EncodingType = -250
|
||||
EncCompressionLevel6 EncodingType = -251
|
||||
EncCompressionLevel5 EncodingType = -252
|
||||
EncCompressionLevel4 EncodingType = -253
|
||||
EncCompressionLevel3 EncodingType = -254
|
||||
EncCompressionLevel2 EncodingType = -255
|
||||
EncCompressionLevel1 EncodingType = -256
|
||||
EncQEMUPointerMotionChangePseudo EncodingType = -257
|
||||
EncQEMUExtendedKeyEventPseudo EncodingType = -258
|
||||
EncTightPng EncodingType = -260
|
||||
EncDesktopNamePseudo EncodingType = -307
|
||||
EncExtendedDesktopSizePseudo EncodingType = -308
|
||||
EncXvpPseudo EncodingType = -309
|
||||
EncClientRedirect EncodingType = -311
|
||||
EncFencePseudo EncodingType = -312
|
||||
EncContinuousUpdatesPseudo EncodingType = -313
|
||||
)
|
||||
|
||||
var bPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
// The Pool's New function should generally only return pointer
|
||||
// types, since a pointer can be put into the return interface
|
||||
// value without an allocation:
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
type Renderer interface {
|
||||
SetTargetImage(draw.Image)
|
||||
}
|
||||
|
||||
// Encoding represents interface for vnc encoding
|
||||
type Encoding interface {
|
||||
Type() EncodingType
|
||||
Read(Conn, *Rectangle) error
|
||||
Write(Conn, *Rectangle) error
|
||||
Supported(Conn) bool
|
||||
Reset() error
|
||||
}
|
||||
|
||||
func setBit(n uint8, pos uint8) uint8 {
|
||||
n |= (1 << pos)
|
||||
return n
|
||||
}
|
||||
|
||||
func clrBit(n uint8, pos uint8) uint8 {
|
||||
n = n &^ (1 << pos)
|
||||
return n
|
||||
}
|
||||
|
||||
func hasBit(n uint8, pos uint8) bool {
|
||||
v := n & (1 << pos)
|
||||
return (v > 0)
|
||||
}
|
||||
|
||||
func getBit(n uint8, pos uint8) uint8 {
|
||||
n = n & (1 << pos)
|
||||
return n
|
||||
}
|
||||
|
||||
func newRGBAImage(rgba []byte, rect *Rectangle) image.Image {
|
||||
img := &image.RGBA{Stride: 4 * int(rect.Width)}
|
||||
img.Pix = rgba
|
||||
img.Rect.Max.X = int(rect.Width)
|
||||
img.Rect.Max.Y = int(rect.Height)
|
||||
return img
|
||||
}
|
||||
|
@ -1,216 +1,216 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
EncAtenHermonSubrect EncodingType = 0
|
||||
EncAtenHermonRaw EncodingType = 1
|
||||
)
|
||||
|
||||
type AtenHermon struct {
|
||||
_ [4]byte
|
||||
AtenLength uint32
|
||||
AtenType uint8
|
||||
_ [1]byte
|
||||
AtenSubrects uint32
|
||||
AtenRawLength uint32
|
||||
Encodings []Encoding
|
||||
}
|
||||
|
||||
type AtenHermonSubrect struct {
|
||||
A uint16
|
||||
B uint16
|
||||
Y uint8
|
||||
X uint8
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (*AtenHermon) Supported(Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (*AtenHermon) Type() EncodingType { return EncAtenHermon }
|
||||
func (*AtenHermon) Reset() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *AtenHermon) Read(c Conn, rect *Rectangle) error {
|
||||
var pad4 [4]byte
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, &pad4); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var aten_length uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &aten_length); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.AtenLength = aten_length
|
||||
|
||||
if rect.Width == 64896 && rect.Height == 65056 {
|
||||
if aten_length != 10 && aten_length != 0 {
|
||||
return fmt.Errorf("screen is off and length is invalid")
|
||||
}
|
||||
aten_length = 0
|
||||
}
|
||||
|
||||
if c.Width() != rect.Width && c.Height() != rect.Height {
|
||||
c.SetWidth(rect.Width)
|
||||
c.SetHeight(rect.Height)
|
||||
}
|
||||
|
||||
var aten_type uint8
|
||||
if err := binary.Read(c, binary.BigEndian, &aten_type); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.AtenType = aten_type
|
||||
|
||||
var pad1 [1]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var subrects uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &subrects); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.AtenSubrects = subrects
|
||||
|
||||
var raw_length uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &raw_length); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.AtenRawLength = raw_length
|
||||
|
||||
if aten_length != raw_length {
|
||||
return fmt.Errorf("aten_length != raw_length, %d != %d", aten_length, raw_length)
|
||||
}
|
||||
|
||||
aten_length -= 10 // skip
|
||||
|
||||
for aten_length > 0 {
|
||||
switch EncodingType(aten_type) {
|
||||
case EncAtenHermonSubrect:
|
||||
encSR := &AtenHermonSubrect{}
|
||||
if err := encSR.Read(c, rect); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.Encodings = append(enc.Encodings, encSR)
|
||||
aten_length -= 6 + (16 * 16 * uint32(c.PixelFormat().BPP/8))
|
||||
case EncAtenHermonRaw:
|
||||
encRaw := &RawEncoding{}
|
||||
if err := encRaw.Read(c, rect); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.Encodings = append(enc.Encodings, encRaw)
|
||||
aten_length -= uint32(rect.Area()) * uint32(c.PixelFormat().BPP/8)
|
||||
default:
|
||||
return fmt.Errorf("unknown aten hermon type %d", aten_type)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if aten_length < 0 {
|
||||
return fmt.Errorf("aten_len dropped below zero")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *AtenHermon) Write(c Conn, rect *Rectangle) error {
|
||||
if !enc.Supported(c) {
|
||||
for _, ew := range enc.Encodings {
|
||||
if err := ew.Write(c, rect); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var pad4 [4]byte
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, pad4); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, enc.AtenLength); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, enc.AtenType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pad1 [1]byte
|
||||
if err := binary.Write(c, binary.BigEndian, pad1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, enc.AtenSubrects); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, enc.AtenRawLength); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, ew := range enc.Encodings {
|
||||
if err := ew.Write(c, rect); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*AtenHermonSubrect) Supported(Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (enc *AtenHermonSubrect) Type() EncodingType {
|
||||
return EncAtenHermonSubrect
|
||||
}
|
||||
func (*AtenHermonSubrect) Reset() error {
|
||||
return nil
|
||||
}
|
||||
func (enc *AtenHermonSubrect) Read(c Conn, rect *Rectangle) error {
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.A); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.B); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.Y); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.X); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.Data = make([]byte, 16*16*uint32(c.PixelFormat().BPP/8))
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *AtenHermonSubrect) Write(c Conn, rect *Rectangle) error {
|
||||
if !enc.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.A); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.B); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.Y); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.X); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
EncAtenHermonSubrect EncodingType = 0
|
||||
EncAtenHermonRaw EncodingType = 1
|
||||
)
|
||||
|
||||
type AtenHermon struct {
|
||||
_ [4]byte
|
||||
AtenLength uint32
|
||||
AtenType uint8
|
||||
_ [1]byte
|
||||
AtenSubrects uint32
|
||||
AtenRawLength uint32
|
||||
Encodings []Encoding
|
||||
}
|
||||
|
||||
type AtenHermonSubrect struct {
|
||||
A uint16
|
||||
B uint16
|
||||
Y uint8
|
||||
X uint8
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (*AtenHermon) Supported(Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (*AtenHermon) Type() EncodingType { return EncAtenHermon }
|
||||
func (*AtenHermon) Reset() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *AtenHermon) Read(c Conn, rect *Rectangle) error {
|
||||
var pad4 [4]byte
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, &pad4); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var aten_length uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &aten_length); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.AtenLength = aten_length
|
||||
|
||||
if rect.Width == 64896 && rect.Height == 65056 {
|
||||
if aten_length != 10 && aten_length != 0 {
|
||||
return fmt.Errorf("screen is off and length is invalid")
|
||||
}
|
||||
aten_length = 0
|
||||
}
|
||||
|
||||
if c.Width() != rect.Width && c.Height() != rect.Height {
|
||||
c.SetWidth(rect.Width)
|
||||
c.SetHeight(rect.Height)
|
||||
}
|
||||
|
||||
var aten_type uint8
|
||||
if err := binary.Read(c, binary.BigEndian, &aten_type); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.AtenType = aten_type
|
||||
|
||||
var pad1 [1]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var subrects uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &subrects); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.AtenSubrects = subrects
|
||||
|
||||
var raw_length uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &raw_length); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.AtenRawLength = raw_length
|
||||
|
||||
if aten_length != raw_length {
|
||||
return fmt.Errorf("aten_length != raw_length, %d != %d", aten_length, raw_length)
|
||||
}
|
||||
|
||||
aten_length -= 10 // skip
|
||||
|
||||
for aten_length > 0 {
|
||||
switch EncodingType(aten_type) {
|
||||
case EncAtenHermonSubrect:
|
||||
encSR := &AtenHermonSubrect{}
|
||||
if err := encSR.Read(c, rect); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.Encodings = append(enc.Encodings, encSR)
|
||||
aten_length -= 6 + (16 * 16 * uint32(c.PixelFormat().BPP/8))
|
||||
case EncAtenHermonRaw:
|
||||
encRaw := &RawEncoding{}
|
||||
if err := encRaw.Read(c, rect); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.Encodings = append(enc.Encodings, encRaw)
|
||||
aten_length -= uint32(rect.Area()) * uint32(c.PixelFormat().BPP/8)
|
||||
default:
|
||||
return fmt.Errorf("unknown aten hermon type %d", aten_type)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if aten_length < 0 {
|
||||
return fmt.Errorf("aten_len dropped below zero")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *AtenHermon) Write(c Conn, rect *Rectangle) error {
|
||||
if !enc.Supported(c) {
|
||||
for _, ew := range enc.Encodings {
|
||||
if err := ew.Write(c, rect); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var pad4 [4]byte
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, pad4); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, enc.AtenLength); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, enc.AtenType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pad1 [1]byte
|
||||
if err := binary.Write(c, binary.BigEndian, pad1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, enc.AtenSubrects); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, enc.AtenRawLength); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, ew := range enc.Encodings {
|
||||
if err := ew.Write(c, rect); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*AtenHermonSubrect) Supported(Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (enc *AtenHermonSubrect) Type() EncodingType {
|
||||
return EncAtenHermonSubrect
|
||||
}
|
||||
func (*AtenHermonSubrect) Reset() error {
|
||||
return nil
|
||||
}
|
||||
func (enc *AtenHermonSubrect) Read(c Conn, rect *Rectangle) error {
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.A); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.B); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.Y); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.X); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.Data = make([]byte, 16*16*uint32(c.PixelFormat().BPP/8))
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *AtenHermonSubrect) Write(c Conn, rect *Rectangle) error {
|
||||
if !enc.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.A); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.B); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.Y); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.X); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,35 +1,35 @@
|
||||
package vnc2webm
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
type CopyRectEncoding struct {
|
||||
SX, SY uint16
|
||||
}
|
||||
|
||||
func (*CopyRectEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
func (*CopyRectEncoding) Reset() error {
|
||||
return nil
|
||||
}
|
||||
func (*CopyRectEncoding) Type() EncodingType { return EncCopyRect }
|
||||
|
||||
func (enc *CopyRectEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.SX); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.SY); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *CopyRectEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
if err := binary.Write(c, binary.BigEndian, enc.SX); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.SY); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
type CopyRectEncoding struct {
|
||||
SX, SY uint16
|
||||
}
|
||||
|
||||
func (*CopyRectEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
func (*CopyRectEncoding) Reset() error {
|
||||
return nil
|
||||
}
|
||||
func (*CopyRectEncoding) Type() EncodingType { return EncCopyRect }
|
||||
|
||||
func (enc *CopyRectEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.SX); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.SY); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *CopyRectEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
if err := binary.Write(c, binary.BigEndian, enc.SX); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.SY); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
60
encoding_corre.go
Normal file
60
encoding_corre.go
Normal file
@ -0,0 +1,60 @@
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
type CoRREEncoding struct {
|
||||
numSubRects uint32
|
||||
backgroundColor []byte
|
||||
subRectData []byte
|
||||
}
|
||||
|
||||
func (z *CoRREEncoding) Type() int32 {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (z *CoRREEncoding) WriteTo(w io.Writer) (n int, err error) {
|
||||
binary.Write(w, binary.BigEndian, z.numSubRects)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
w.Write(z.backgroundColor)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
w.Write(z.subRectData)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
b := len(z.backgroundColor) + len(z.subRectData) + 4
|
||||
return b, nil
|
||||
}
|
||||
func (z *CoRREEncoding) Read(r Conn, rect *Rectangle) error {
|
||||
//func (z *CoRREEncoding) Read(pixelFmt *PixelFormat, rect *Rectangle, r io.Reader) (Encoding, error) {
|
||||
bytesPerPixel := int(r.PixelFormat().BPP / 8)
|
||||
var numOfSubrectangles uint32
|
||||
if err := binary.Read(r, binary.BigEndian, &numOfSubrectangles); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
z.numSubRects = numOfSubrectangles
|
||||
var err error
|
||||
//read whole-rect background color
|
||||
z.backgroundColor, err = ReadBytes(bytesPerPixel, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//read all individual rects (color=BPP + x=16b + y=16b + w=16b + h=16b)
|
||||
z.subRectData, err = ReadBytes(int(numOfSubrectangles)*(bytesPerPixel+4), r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,90 +1,110 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"image"
|
||||
"image/draw"
|
||||
)
|
||||
|
||||
type CursorPseudoEncoding struct {
|
||||
Colors []Color
|
||||
BitMask []byte
|
||||
Image image.Image
|
||||
}
|
||||
|
||||
func (*CursorPseudoEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (enc *CursorPseudoEncoding) SetTargetImage(img draw.Image) {
|
||||
enc.Image = img
|
||||
}
|
||||
|
||||
func (*CursorPseudoEncoding) Type() EncodingType { return EncCursorPseudo }
|
||||
|
||||
func (enc *CursorPseudoEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
rgba := make([]byte, int(rect.Height)*int(rect.Width)*int(c.PixelFormat().BPP/8))
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, &rgba); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bitmask := make([]byte, int((rect.Width+7)/8*rect.Height))
|
||||
if err := binary.Read(c, binary.BigEndian, &bitmask); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
rectStride := 4 * rect.Width
|
||||
for i := uint16(0); i < rect.Height; i++ {
|
||||
for j := uint16(0); j < rect.Width; j += 8 {
|
||||
for idx, k := j/8, 7; k >= 0; k-- {
|
||||
if (bitmask[idx] & (1 << uint(k))) == 0 {
|
||||
pIdx := j*4 + i*rectStride
|
||||
rgbaBuffer[pIdx] = 0
|
||||
rgbaBuffer[pIdx+1] = 0
|
||||
rgbaBuffer[pIdx+2] = 0
|
||||
rgbaBuffer[pIdx+3] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
int bytesPerPixel = renderer.getBytesPerPixel();
|
||||
int length = rect.width * rect.height * bytesPerPixel;
|
||||
if (0 == length)
|
||||
return;
|
||||
byte[] buffer = ByteBuffer.getInstance().getBuffer(length);
|
||||
transport.readBytes(buffer, 0, length);
|
||||
|
||||
StringBuilder sb = new StringBuilder(" ");
|
||||
for (int i=0; i<length; ++i) {
|
||||
sb.append(Integer.toHexString(buffer[i]&0xff)).append(" ");
|
||||
}
|
||||
int scanLine = (rect.width + 7) / 8;
|
||||
byte[] bitmask = new byte[scanLine * rect.height];
|
||||
transport.readBytes(bitmask, 0, bitmask.length);
|
||||
|
||||
sb = new StringBuilder(" ");
|
||||
for (byte aBitmask : bitmask) {
|
||||
sb.append(Integer.toHexString(aBitmask & 0xff)).append(" ");
|
||||
}
|
||||
int[] cursorPixels = new int[rect.width * rect.height];
|
||||
for (int y = 0; y < rect.height; ++y) {
|
||||
for (int x = 0; x < rect.width; ++x) {
|
||||
int offset = y * rect.width + x;
|
||||
cursorPixels[offset] = isBitSet(bitmask[y * scanLine + x / 8], x % 8) ?
|
||||
0xFF000000 | renderer.getPixelColor(buffer, offset * bytesPerPixel) :
|
||||
0; // transparent
|
||||
}
|
||||
}
|
||||
renderer.createCursor(cursorPixels, rect);
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *CursorPseudoEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
)
|
||||
|
||||
type CursorPseudoEncoding struct {
|
||||
Colors []Color
|
||||
BitMask []byte
|
||||
Image draw.Image
|
||||
}
|
||||
|
||||
func (*CursorPseudoEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (enc *CursorPseudoEncoding) SetTargetImage(img draw.Image) {
|
||||
enc.Image = img
|
||||
}
|
||||
|
||||
func (*CursorPseudoEncoding) Type() EncodingType { return EncCursorPseudo }
|
||||
|
||||
func (enc *CursorPseudoEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
//rgba := make([]byte, int(rect.Height)*int(rect.Width)*int(c.PixelFormat().BPP/8))
|
||||
numColors := int(rect.Height) * int(rect.Width)
|
||||
colors := make([]color.Color, numColors)
|
||||
var err error
|
||||
pf := c.PixelFormat()
|
||||
for i := 0; i < numColors; i++ {
|
||||
colors[i], err = ReadColor(c, &pf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// if err := binary.Read(c, binary.BigEndian, &rgba); err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
bitmask := make([]byte, int((rect.Width+7)/8*rect.Height))
|
||||
if err := binary.Read(c, binary.BigEndian, &bitmask); err != nil {
|
||||
return err
|
||||
}
|
||||
scanLine := (rect.Width + 7) / 8
|
||||
|
||||
//int[] cursorPixels = new int[rect.width * rect.height];
|
||||
for y := 0; y < int(rect.Height); y++ {
|
||||
for x := 0; x < int(rect.Width); x++ {
|
||||
offset := y*int(rect.Width) + x
|
||||
if bitmask[y*int(scanLine)+x/8]&(1<<uint(7-x%8)) > 0 {
|
||||
enc.Image.Set(x, y, colors[offset])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
rectStride := 4 * rect.Width
|
||||
for i := uint16(0); i < rect.Height; i++ {
|
||||
for j := uint16(0); j < rect.Width; j += 8 {
|
||||
for idx, k := j/8, 7; k >= 0; k-- {
|
||||
if (bitmask[idx] & (1 << uint(k))) == 0 {
|
||||
pIdx := j*4 + i*rectStride
|
||||
rgba[pIdx] = 0
|
||||
rgba[pIdx+1] = 0
|
||||
rgba[pIdx+2] = 0
|
||||
rgba[pIdx+3] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
int bytesPerPixel = renderer.getBytesPerPixel();
|
||||
int length = rect.width * rect.height * bytesPerPixel;
|
||||
if (0 == length)
|
||||
return;
|
||||
byte[] buffer = ByteBuffer.getInstance().getBuffer(length);
|
||||
transport.readBytes(buffer, 0, length);
|
||||
|
||||
StringBuilder sb = new StringBuilder(" ");
|
||||
for (int i=0; i<length; ++i) {
|
||||
sb.append(Integer.toHexString(buffer[i]&0xff)).append(" ");
|
||||
}
|
||||
int scanLine = (rect.width + 7) / 8;
|
||||
byte[] bitmask = new byte[scanLine * rect.height];
|
||||
transport.readBytes(bitmask, 0, bitmask.length);
|
||||
|
||||
sb = new StringBuilder(" ");
|
||||
for (byte aBitmask : bitmask) {
|
||||
sb.append(Integer.toHexString(aBitmask & 0xff)).append(" ");
|
||||
}
|
||||
int[] cursorPixels = new int[rect.width * rect.height];
|
||||
for (int y = 0; y < rect.height; ++y) {
|
||||
for (int x = 0; x < rect.width; ++x) {
|
||||
int offset = y * rect.width + x;
|
||||
cursorPixels[offset] = isBitSet(bitmask[y * scanLine + x / 8], x % 8) ?
|
||||
0xFF000000 | renderer.getPixelColor(buffer, offset * bytesPerPixel) :
|
||||
0; // transparent
|
||||
}
|
||||
}
|
||||
renderer.createCursor(cursorPixels, rect);
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *CursorPseudoEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,41 +1,41 @@
|
||||
package vnc2webm
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// DesktopNamePseudoEncoding represents a desktop size message from the server.
|
||||
type DesktopNamePseudoEncoding struct {
|
||||
Name []byte
|
||||
}
|
||||
|
||||
func (*DesktopNamePseudoEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
func (*DesktopNamePseudoEncoding) Reset() error {
|
||||
return nil
|
||||
}
|
||||
func (*DesktopNamePseudoEncoding) Type() EncodingType { return EncDesktopNamePseudo }
|
||||
|
||||
// Read implements the Encoding interface.
|
||||
func (enc *DesktopNamePseudoEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
var length uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &length); err != nil {
|
||||
return err
|
||||
}
|
||||
name := make([]byte, length)
|
||||
if err := binary.Read(c, binary.BigEndian, &name); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.Name = name
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *DesktopNamePseudoEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
if err := binary.Write(c, binary.BigEndian, uint32(len(enc.Name))); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Flush()
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// DesktopNamePseudoEncoding represents a desktop size message from the server.
|
||||
type DesktopNamePseudoEncoding struct {
|
||||
Name []byte
|
||||
}
|
||||
|
||||
func (*DesktopNamePseudoEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
func (*DesktopNamePseudoEncoding) Reset() error {
|
||||
return nil
|
||||
}
|
||||
func (*DesktopNamePseudoEncoding) Type() EncodingType { return EncDesktopNamePseudo }
|
||||
|
||||
// Read implements the Encoding interface.
|
||||
func (enc *DesktopNamePseudoEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
var length uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &length); err != nil {
|
||||
return err
|
||||
}
|
||||
name := make([]byte, length)
|
||||
if err := binary.Read(c, binary.BigEndian, &name); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.Name = name
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *DesktopNamePseudoEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
if err := binary.Write(c, binary.BigEndian, uint32(len(enc.Name))); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Flush()
|
||||
}
|
||||
|
@ -1,21 +1,21 @@
|
||||
package vnc2webm
|
||||
|
||||
// DesktopSizePseudoEncoding represents a desktop size message from the server.
|
||||
type DesktopSizePseudoEncoding struct{}
|
||||
|
||||
func (*DesktopSizePseudoEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
func (*DesktopSizePseudoEncoding) Reset() error {
|
||||
return nil
|
||||
}
|
||||
func (*DesktopSizePseudoEncoding) Type() EncodingType { return EncDesktopSizePseudo }
|
||||
|
||||
// Read implements the Encoding interface.
|
||||
func (*DesktopSizePseudoEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *DesktopSizePseudoEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
return nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
// DesktopSizePseudoEncoding represents a desktop size message from the server.
|
||||
type DesktopSizePseudoEncoding struct{}
|
||||
|
||||
func (*DesktopSizePseudoEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
func (*DesktopSizePseudoEncoding) Reset() error {
|
||||
return nil
|
||||
}
|
||||
func (*DesktopSizePseudoEncoding) Type() EncodingType { return EncDesktopSizePseudo }
|
||||
|
||||
// Read implements the Encoding interface.
|
||||
func (*DesktopSizePseudoEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *DesktopSizePseudoEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
return nil
|
||||
}
|
||||
|
168
encoding_hextile.go
Normal file
168
encoding_hextile.go
Normal file
@ -0,0 +1,168 @@
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"io"
|
||||
"vnc2video/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
HextileRaw = 1
|
||||
HextileBackgroundSpecified = 2
|
||||
HextileForegroundSpecified = 4
|
||||
HextileAnySubrects = 8
|
||||
HextileSubrectsColoured = 16
|
||||
)
|
||||
|
||||
type HextileEncoding struct {
|
||||
//Colors []Color
|
||||
bytes []byte
|
||||
Image draw.Image
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (z *HextileEncoding) Type() int32 {
|
||||
return 5
|
||||
}
|
||||
func (z *HextileEncoding) WriteTo(w io.Writer) (n int, err error) {
|
||||
return w.Write(z.bytes)
|
||||
}
|
||||
func (z *HextileEncoding) Read(r Conn, rect *Rectangle) error {
|
||||
//func (z *HextileEncoding) Read(pixelFmt *PixelFormat, rect *Rectangle, r io.Reader) (Encoding, error) {
|
||||
//bytesPerPixel := int(r.PixelFormat().BPP) / 8
|
||||
pf := r.PixelFormat()
|
||||
var bgCol *color.RGBA
|
||||
var fgCol *color.RGBA
|
||||
var err error
|
||||
var dimensions byte
|
||||
var subencoding byte
|
||||
|
||||
//r.StartByteCollection()
|
||||
// defer func() {
|
||||
// z.bytes = r.EndByteCollection()
|
||||
// }()
|
||||
|
||||
for ty := rect.Y; ty < rect.Y+rect.Height; ty += 16 {
|
||||
th := 16
|
||||
if rect.Y+rect.Height-ty < 16 {
|
||||
th = int(rect.Y) + int(rect.Height) - int(ty)
|
||||
}
|
||||
|
||||
for tx := rect.X; tx < rect.X+rect.Width; tx += 16 {
|
||||
tw := 16
|
||||
if rect.X+rect.Width-tx < 16 {
|
||||
tw = int(rect.X) + int(rect.Width) - int(tx)
|
||||
}
|
||||
|
||||
//handle Hextile Subrect(tx, ty, tw, th):
|
||||
subencoding, err = ReadUint8(r)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("HextileEncoding.Read: error in hextile reader: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if (subencoding & HextileRaw) != 0 {
|
||||
rawEnc := r.GetEncInstance(EncRaw)
|
||||
rawEnc.Read(r, &Rectangle{0, 0, uint16(tw), uint16(th), EncRaw, rawEnc})
|
||||
//ReadBytes(tw*th*bytesPerPixel, r)
|
||||
continue
|
||||
}
|
||||
if (subencoding & HextileBackgroundSpecified) != 0 {
|
||||
//ReadBytes(int(bytesPerPixel), r)
|
||||
|
||||
bgCol, err = ReadColor(r, &pf)
|
||||
rBounds := image.Rectangle{Min: image.Point{int(tx), int(ty)}, Max: image.Point{int(tw), int(th)}}
|
||||
FillRect(z.Image, &rBounds, bgCol)
|
||||
}
|
||||
if (subencoding & HextileForegroundSpecified) != 0 {
|
||||
fgCol, err = ReadColor(r, &pf)
|
||||
}
|
||||
if (subencoding & HextileAnySubrects) == 0 {
|
||||
//logger.Debug("hextile reader: no Subrects")
|
||||
continue
|
||||
}
|
||||
|
||||
nSubrects, err := ReadUint8(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//bufsize := int(nSubrects) * 2
|
||||
colorSpecified := ((subencoding & HextileSubrectsColoured) != 0)
|
||||
for i := 0; i < int(nSubrects); i++ {
|
||||
var color *color.RGBA
|
||||
if colorSpecified {
|
||||
color, err = ReadColor(r, &pf)
|
||||
if err != nil {
|
||||
logger.Error("Hextile decoder: problem reading color from connection: ", err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
color = fgCol
|
||||
}
|
||||
//int color = colorSpecified ? renderer.readPixelColor(transport) : colors[FG_COLOR_INDEX];
|
||||
fgCol = color
|
||||
dimensions, err = ReadUint8(r) // bits 7-4 for x, bits 3-0 for y
|
||||
if err != nil {
|
||||
logger.Error("Hextile decoder: problem reading dimensions from connection: ", err)
|
||||
return err
|
||||
}
|
||||
subtileX := dimensions >> 4 & 0x0f
|
||||
subtileY := dimensions & 0x0f
|
||||
dimensions, err = ReadUint8(r) // bits 7-4 for w, bits 3-0 for h
|
||||
if err != nil {
|
||||
logger.Error("Hextile decoder: problem reading 2nd dimensions from connection: ", err)
|
||||
return err
|
||||
}
|
||||
subtileWidth := 1 + (dimensions >> 4 & 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)}}
|
||||
FillRect(z.Image, &subrectBounds, color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
120
encoding_raw.go
120
encoding_raw.go
@ -1,60 +1,60 @@
|
||||
package vnc2webm
|
||||
|
||||
import "image"
|
||||
import "image/draw"
|
||||
import "image/color"
|
||||
|
||||
type RawEncoding struct {
|
||||
Image image.Image
|
||||
//Colors []Color
|
||||
}
|
||||
|
||||
func (*RawEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (*RawEncoding) Reset() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *RawEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
var err error
|
||||
//
|
||||
//for _, clr := range enc.Colors {
|
||||
// if err = clr.Write(c); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
|
||||
return err
|
||||
}
|
||||
func (enc *RawEncoding) SetTargetImage(img draw.Image) {
|
||||
enc.Image = img
|
||||
}
|
||||
|
||||
// Read implements the Encoding interface.
|
||||
func (enc *RawEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
pf := c.PixelFormat()
|
||||
cm := c.ColorMap()
|
||||
//colors := make([]Color, rect.Area())
|
||||
|
||||
for y := 0; y < int(rect.Height); y++ {
|
||||
for x := 0; x < int(rect.Width); x++ {
|
||||
c1 := NewColor(&pf, &cm)
|
||||
if err := c1.Read(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c2:=color.RGBA{R:uint8(c1.R),G:uint8(c1.G),B:uint8(c1.B),A:1}
|
||||
//c3 := color.RGBAModel.Convert(c2)
|
||||
|
||||
enc.Image.(draw.Image).Set(int(rect.X)+x,int(rect.Y)+y,c2)
|
||||
//colors[int(y)*int(rect.Width)+int(x)] = *color
|
||||
}
|
||||
}
|
||||
|
||||
//enc.Colors = colors
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*RawEncoding) Type() EncodingType { return EncRaw }
|
||||
package vnc2video
|
||||
|
||||
import "image"
|
||||
import "image/draw"
|
||||
import "image/color"
|
||||
|
||||
type RawEncoding struct {
|
||||
Image image.Image
|
||||
//Colors []Color
|
||||
}
|
||||
|
||||
func (*RawEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (*RawEncoding) Reset() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *RawEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
var err error
|
||||
//
|
||||
//for _, clr := range enc.Colors {
|
||||
// if err = clr.Write(c); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
|
||||
return err
|
||||
}
|
||||
func (enc *RawEncoding) SetTargetImage(img draw.Image) {
|
||||
enc.Image = img
|
||||
}
|
||||
|
||||
// Read implements the Encoding interface.
|
||||
func (enc *RawEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
pf := c.PixelFormat()
|
||||
cm := c.ColorMap()
|
||||
//colors := make([]Color, rect.Area())
|
||||
|
||||
for y := 0; y < int(rect.Height); y++ {
|
||||
for x := 0; x < int(rect.Width); x++ {
|
||||
c1 := NewColor(&pf, &cm)
|
||||
if err := c1.Read(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c2:=color.RGBA{R:uint8(c1.R),G:uint8(c1.G),B:uint8(c1.B),A:1}
|
||||
//c3 := color.RGBAModel.Convert(c2)
|
||||
|
||||
enc.Image.(draw.Image).Set(int(rect.X)+x,int(rect.Y)+y,c2)
|
||||
//colors[int(y)*int(rect.Width)+int(x)] = *color
|
||||
}
|
||||
}
|
||||
|
||||
//enc.Colors = colors
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*RawEncoding) Type() EncodingType { return EncRaw }
|
||||
|
64
encoding_rre.go
Normal file
64
encoding_rre.go
Normal file
@ -0,0 +1,64 @@
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
//"image/draw"
|
||||
)
|
||||
|
||||
type RREEncoding struct {
|
||||
//Colors []Color
|
||||
numSubRects uint32
|
||||
backgroundColor []byte
|
||||
subRectData []byte
|
||||
}
|
||||
|
||||
func (z *RREEncoding) WriteTo(w io.Writer) (n int, err error) {
|
||||
binary.Write(w, binary.BigEndian, z.numSubRects)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
w.Write(z.backgroundColor)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
w.Write(z.subRectData)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
b := len(z.backgroundColor) + len(z.subRectData) + 4
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (z *RREEncoding) Type() int32 {
|
||||
return 2
|
||||
}
|
||||
func (z *RREEncoding) Read(r Conn, rect *Rectangle) error {
|
||||
//func (z *RREEncoding) Read(pixelFmt *PixelFormat, rect *Rectangle, r io.Reader) (Encoding, error) {
|
||||
bytesPerPixel := int(r.PixelFormat().BPP / 8)
|
||||
|
||||
var numOfSubrectangles uint32
|
||||
if err := binary.Read(r, binary.BigEndian, &numOfSubrectangles); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var err error
|
||||
z.numSubRects = numOfSubrectangles
|
||||
|
||||
//read whole-rect background color
|
||||
z.backgroundColor, err = ReadBytes(bytesPerPixel, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//read all individual rects (color=bytesPerPixel + x=16b + y=16b + w=16b + h=16b)
|
||||
z.subRectData, err = ReadBytes(int(numOfSubrectangles)*(bytesPerPixel+8), r) // x+y+w+h=8 bytes
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
1495
encoding_tight.go
1495
encoding_tight.go
File diff suppressed because it is too large
Load Diff
@ -1,95 +1,95 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"io"
|
||||
"vnc2webm/logger"
|
||||
)
|
||||
|
||||
func (*TightPngEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
func (*TightPngEncoding) Reset() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *TightPngEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
if err := writeTightCC(c, enc.TightCC); err != nil {
|
||||
return err
|
||||
}
|
||||
cmp := enc.TightCC.Compression
|
||||
switch cmp {
|
||||
case TightCompressionPNG:
|
||||
buf := bPool.Get().(*bytes.Buffer)
|
||||
buf.Reset()
|
||||
defer bPool.Put(buf)
|
||||
pngEnc := &png.Encoder{CompressionLevel: png.BestSpeed}
|
||||
//pngEnc := &png.Encoder{CompressionLevel: png.NoCompression}
|
||||
if err := pngEnc.Encode(buf, enc.Image); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeTightLength(c, buf.Len()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := buf.WriteTo(c); err != nil {
|
||||
return err
|
||||
}
|
||||
case TightCompressionFill:
|
||||
var tpx TightPixel
|
||||
r, g, b, _ := enc.Image.At(0, 0).RGBA()
|
||||
tpx.R = uint8(r)
|
||||
tpx.G = uint8(g)
|
||||
tpx.B = uint8(b)
|
||||
if err := binary.Write(c, binary.BigEndian, tpx); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown tight compression %d", cmp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type TightPngEncoding struct {
|
||||
TightCC *TightCC
|
||||
Image image.Image
|
||||
}
|
||||
|
||||
func (*TightPngEncoding) Type() EncodingType { return EncTightPng }
|
||||
|
||||
func (enc *TightPngEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
tcc, err := readTightCC(c)
|
||||
logger.Debug("starting to read a tight rect: %v", rect)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enc.TightCC = tcc
|
||||
cmp := enc.TightCC.Compression
|
||||
switch cmp {
|
||||
case TightCompressionPNG:
|
||||
l, err := readTightLength(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enc.Image, err = png.Decode(io.LimitReader(c, int64(l)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case TightCompressionFill:
|
||||
var tpx TightPixel
|
||||
if err := binary.Read(c, binary.BigEndian, &tpx); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.Image = image.NewRGBA(image.Rect(0, 0, 1, 1))
|
||||
enc.Image.(draw.Image).Set(0, 0, color.RGBA{R: tpx.R, G: tpx.G, B: tpx.B, A: 1})
|
||||
default:
|
||||
return fmt.Errorf("unknown compression %d", cmp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"io"
|
||||
"vnc2video/logger"
|
||||
)
|
||||
|
||||
func (*TightPngEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
func (*TightPngEncoding) Reset() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *TightPngEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
if err := writeTightCC(c, enc.TightCC); err != nil {
|
||||
return err
|
||||
}
|
||||
cmp := enc.TightCC.Compression
|
||||
switch cmp {
|
||||
case TightCompressionPNG:
|
||||
buf := bPool.Get().(*bytes.Buffer)
|
||||
buf.Reset()
|
||||
defer bPool.Put(buf)
|
||||
pngEnc := &png.Encoder{CompressionLevel: png.BestSpeed}
|
||||
//pngEnc := &png.Encoder{CompressionLevel: png.NoCompression}
|
||||
if err := pngEnc.Encode(buf, enc.Image); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeTightLength(c, buf.Len()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := buf.WriteTo(c); err != nil {
|
||||
return err
|
||||
}
|
||||
case TightCompressionFill:
|
||||
var tpx TightPixel
|
||||
r, g, b, _ := enc.Image.At(0, 0).RGBA()
|
||||
tpx.R = uint8(r)
|
||||
tpx.G = uint8(g)
|
||||
tpx.B = uint8(b)
|
||||
if err := binary.Write(c, binary.BigEndian, tpx); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown tight compression %d", cmp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type TightPngEncoding struct {
|
||||
TightCC *TightCC
|
||||
Image image.Image
|
||||
}
|
||||
|
||||
func (*TightPngEncoding) Type() EncodingType { return EncTightPng }
|
||||
|
||||
func (enc *TightPngEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
tcc, err := readTightCC(c)
|
||||
logger.Debug("starting to read a tight rect: %v", rect)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enc.TightCC = tcc
|
||||
cmp := enc.TightCC.Compression
|
||||
switch cmp {
|
||||
case TightCompressionPNG:
|
||||
l, err := readTightLength(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enc.Image, err = png.Decode(io.LimitReader(c, int64(l)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case TightCompressionFill:
|
||||
var tpx TightPixel
|
||||
if err := binary.Read(c, binary.BigEndian, &tpx); err != nil {
|
||||
return err
|
||||
}
|
||||
enc.Image = image.NewRGBA(image.Rect(0, 0, 1, 1))
|
||||
enc.Image.(draw.Image).Set(0, 0, color.RGBA{R: tpx.R, G: tpx.G, B: tpx.B, A: 1})
|
||||
default:
|
||||
return fmt.Errorf("unknown compression %d", cmp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
19
encoding_util.go
Normal file
19
encoding_util.go
Normal file
@ -0,0 +1,19 @@
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
)
|
||||
|
||||
func FillRect(img draw.Image, rect *image.Rectangle, c color.Color) {
|
||||
for x := 0; x < rect.Max.X; x++ {
|
||||
for y := 0; y < rect.Max.Y; y++ {
|
||||
img.Set(x, y, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func DrawLine(img draw.Image, rect *image.Rectangle, c color.Color) {
|
||||
|
||||
}
|
@ -1,92 +1,92 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math"
|
||||
)
|
||||
|
||||
type XCursorPseudoEncoding struct {
|
||||
PrimaryR uint8
|
||||
PrimaryG uint8
|
||||
PrimaryB uint8
|
||||
SecondaryR uint8
|
||||
SecondaryG uint8
|
||||
SecondaryB uint8
|
||||
Bitmap []byte
|
||||
Bitmask []byte
|
||||
}
|
||||
|
||||
func (*XCursorPseudoEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
func (*XCursorPseudoEncoding) Reset() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*XCursorPseudoEncoding) Type() EncodingType { return EncXCursorPseudo }
|
||||
|
||||
// Read implements the Encoding interface.
|
||||
func (enc *XCursorPseudoEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.PrimaryR); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.PrimaryG); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.PrimaryB); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.SecondaryR); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.SecondaryG); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.SecondaryB); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bitmapsize := int(math.Floor((float64(rect.Width)+7)/8) * float64(rect.Height))
|
||||
bitmasksize := int(math.Floor((float64(rect.Width)+7)/8) * float64(rect.Height))
|
||||
|
||||
enc.Bitmap = make([]byte, bitmapsize)
|
||||
enc.Bitmask = make([]byte, bitmasksize)
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.Bitmap); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.Bitmask); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *XCursorPseudoEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
if err := binary.Write(c, binary.BigEndian, enc.PrimaryR); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.PrimaryG); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.PrimaryB); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.SecondaryR); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.SecondaryG); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.SecondaryB); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, enc.Bitmap); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.Bitmask); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math"
|
||||
)
|
||||
|
||||
type XCursorPseudoEncoding struct {
|
||||
PrimaryR uint8
|
||||
PrimaryG uint8
|
||||
PrimaryB uint8
|
||||
SecondaryR uint8
|
||||
SecondaryG uint8
|
||||
SecondaryB uint8
|
||||
Bitmap []byte
|
||||
Bitmask []byte
|
||||
}
|
||||
|
||||
func (*XCursorPseudoEncoding) Supported(Conn) bool {
|
||||
return true
|
||||
}
|
||||
func (*XCursorPseudoEncoding) Reset() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*XCursorPseudoEncoding) Type() EncodingType { return EncXCursorPseudo }
|
||||
|
||||
// Read implements the Encoding interface.
|
||||
func (enc *XCursorPseudoEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.PrimaryR); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.PrimaryG); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.PrimaryB); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.SecondaryR); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.SecondaryG); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.SecondaryB); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bitmapsize := int(math.Floor((float64(rect.Width)+7)/8) * float64(rect.Height))
|
||||
bitmasksize := int(math.Floor((float64(rect.Width)+7)/8) * float64(rect.Height))
|
||||
|
||||
enc.Bitmap = make([]byte, bitmapsize)
|
||||
enc.Bitmask = make([]byte, bitmasksize)
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.Bitmap); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &enc.Bitmask); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *XCursorPseudoEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
if err := binary.Write(c, binary.BigEndian, enc.PrimaryR); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.PrimaryG); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.PrimaryB); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.SecondaryR); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.SecondaryG); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.SecondaryB); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, enc.Bitmap); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, enc.Bitmask); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
38
encoding_zlib.go
Normal file
38
encoding_zlib.go
Normal file
@ -0,0 +1,38 @@
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
type ZLibEncoding struct {
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
func (z *ZLibEncoding) Type() int32 {
|
||||
return 6
|
||||
}
|
||||
func (z *ZLibEncoding) WriteTo(w io.Writer) (n int, err error) {
|
||||
return w.Write(z.bytes)
|
||||
}
|
||||
func (z *ZLibEncoding) Read(r Conn, rect *Rectangle) error {
|
||||
//func (z *ZLibEncoding) Read(pixelFmt *PixelFormat, rect *Rectangle, r io.Reader) (Encoding, error) {
|
||||
//conn := RfbReadHelper{Reader:r}
|
||||
//conn := &DataSource{conn: conn.c, PixelFormat: conn.PixelFormat}
|
||||
//bytesPerPixel := c.PixelFormat.BPP / 8
|
||||
bytes := &bytes.Buffer{}
|
||||
len, err := ReadUint32(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
binary.Write(bytes, binary.BigEndian, len)
|
||||
_, err = ReadBytes(int(len), r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//StoreBytes(bytes, bts)
|
||||
z.bytes = bytes.Bytes()
|
||||
return nil
|
||||
}
|
37
encoding_zrle.go
Normal file
37
encoding_zrle.go
Normal file
@ -0,0 +1,37 @@
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
type ZRLEEncoding struct {
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
func (z *ZRLEEncoding) Type() int32 {
|
||||
return 16
|
||||
}
|
||||
|
||||
func (z *ZRLEEncoding) WriteTo(w io.Writer) (n int, err error) {
|
||||
return w.Write(z.bytes)
|
||||
}
|
||||
func (z *ZRLEEncoding) Read(r Conn, rect *Rectangle) error {
|
||||
//func (z *ZRLEEncoding) Read(pixelFmt *PixelFormat, rect *Rectangle, r io.Reader) (Encoding, error) {
|
||||
|
||||
bytes := &bytes.Buffer{}
|
||||
len, err := ReadUint32(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
binary.Write(bytes, binary.BigEndian, len)
|
||||
_, err = ReadBytes(int(len), r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//StoreBytes(bytes, bts)
|
||||
z.bytes = bytes.Bytes()
|
||||
return nil
|
||||
}
|
@ -1,69 +1,69 @@
|
||||
// Code generated by "stringer -type=EncodingType"; DO NOT EDIT.
|
||||
|
||||
package vnc2webm
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _EncodingType_name = "EncContinuousUpdatesPseudoEncFencePseudoEncClientRedirectEncXvpPseudoEncExtendedDesktopSizePseudoEncDesktopNamePseudoEncTightPngEncQEMUExtendedKeyEventPseudoEncQEMUPointerMotionChangePseudoEncCompressionLevel1EncCompressionLevel2EncCompressionLevel3EncCompressionLevel4EncCompressionLevel5EncCompressionLevel6EncCompressionLevel7EncCompressionLevel8EncCompressionLevel9EncCompressionLevel10EncXCursorPseudoEncCursorPseudoEncLastRectPseudoEncDesktopSizePseudoEncJPEGQualityLevelPseudo1EncJPEGQualityLevelPseudo2EncJPEGQualityLevelPseudo3EncJPEGQualityLevelPseudo4EncJPEGQualityLevelPseudo5EncJPEGQualityLevelPseudo6EncJPEGQualityLevelPseudo7EncJPEGQualityLevelPseudo8EncJPEGQualityLevelPseudo9EncJPEGQualityLevelPseudo10EncRawEncCopyRectEncRREEncCoRREEncHextileEncZlibEncTightEncZlibHexEncUltra1EncUltra2EncTRLEEncZRLEEncJPEGEncJRLEEncAtenAST2100EncAtenASTJPEGEncAtenHermonEncAtenYarkonEncAtenPilot3"
|
||||
|
||||
var _EncodingType_map = map[EncodingType]string{
|
||||
-313: _EncodingType_name[0:26],
|
||||
-312: _EncodingType_name[26:40],
|
||||
-311: _EncodingType_name[40:57],
|
||||
-309: _EncodingType_name[57:69],
|
||||
-308: _EncodingType_name[69:97],
|
||||
-307: _EncodingType_name[97:117],
|
||||
-260: _EncodingType_name[117:128],
|
||||
-258: _EncodingType_name[128:157],
|
||||
-257: _EncodingType_name[157:189],
|
||||
-256: _EncodingType_name[189:209],
|
||||
-255: _EncodingType_name[209:229],
|
||||
-254: _EncodingType_name[229:249],
|
||||
-253: _EncodingType_name[249:269],
|
||||
-252: _EncodingType_name[269:289],
|
||||
-251: _EncodingType_name[289:309],
|
||||
-250: _EncodingType_name[309:329],
|
||||
-249: _EncodingType_name[329:349],
|
||||
-248: _EncodingType_name[349:369],
|
||||
-247: _EncodingType_name[369:390],
|
||||
-240: _EncodingType_name[390:406],
|
||||
-239: _EncodingType_name[406:421],
|
||||
-224: _EncodingType_name[421:438],
|
||||
-223: _EncodingType_name[438:458],
|
||||
-32: _EncodingType_name[458:484],
|
||||
-31: _EncodingType_name[484:510],
|
||||
-30: _EncodingType_name[510:536],
|
||||
-29: _EncodingType_name[536:562],
|
||||
-28: _EncodingType_name[562:588],
|
||||
-27: _EncodingType_name[588:614],
|
||||
-26: _EncodingType_name[614:640],
|
||||
-25: _EncodingType_name[640:666],
|
||||
-24: _EncodingType_name[666:692],
|
||||
-23: _EncodingType_name[692:719],
|
||||
0: _EncodingType_name[719:725],
|
||||
1: _EncodingType_name[725:736],
|
||||
2: _EncodingType_name[736:742],
|
||||
4: _EncodingType_name[742:750],
|
||||
5: _EncodingType_name[750:760],
|
||||
6: _EncodingType_name[760:767],
|
||||
7: _EncodingType_name[767:775],
|
||||
8: _EncodingType_name[775:785],
|
||||
9: _EncodingType_name[785:794],
|
||||
10: _EncodingType_name[794:803],
|
||||
15: _EncodingType_name[803:810],
|
||||
16: _EncodingType_name[810:817],
|
||||
21: _EncodingType_name[817:824],
|
||||
22: _EncodingType_name[824:831],
|
||||
87: _EncodingType_name[831:845],
|
||||
88: _EncodingType_name[845:859],
|
||||
89: _EncodingType_name[859:872],
|
||||
96: _EncodingType_name[872:885],
|
||||
97: _EncodingType_name[885:898],
|
||||
}
|
||||
|
||||
func (i EncodingType) String() string {
|
||||
if str, ok := _EncodingType_map[i]; ok {
|
||||
return str
|
||||
}
|
||||
return fmt.Sprintf("EncodingType(%d)", i)
|
||||
}
|
||||
// Code generated by "stringer -type=EncodingType"; DO NOT EDIT.
|
||||
|
||||
package vnc2video
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _EncodingType_name = "EncContinuousUpdatesPseudoEncFencePseudoEncClientRedirectEncXvpPseudoEncExtendedDesktopSizePseudoEncDesktopNamePseudoEncTightPngEncQEMUExtendedKeyEventPseudoEncQEMUPointerMotionChangePseudoEncCompressionLevel1EncCompressionLevel2EncCompressionLevel3EncCompressionLevel4EncCompressionLevel5EncCompressionLevel6EncCompressionLevel7EncCompressionLevel8EncCompressionLevel9EncCompressionLevel10EncXCursorPseudoEncCursorPseudoEncLastRectPseudoEncDesktopSizePseudoEncJPEGQualityLevelPseudo1EncJPEGQualityLevelPseudo2EncJPEGQualityLevelPseudo3EncJPEGQualityLevelPseudo4EncJPEGQualityLevelPseudo5EncJPEGQualityLevelPseudo6EncJPEGQualityLevelPseudo7EncJPEGQualityLevelPseudo8EncJPEGQualityLevelPseudo9EncJPEGQualityLevelPseudo10EncRawEncCopyRectEncRREEncCoRREEncHextileEncZlibEncTightEncZlibHexEncUltra1EncUltra2EncTRLEEncZRLEEncJPEGEncJRLEEncAtenAST2100EncAtenASTJPEGEncAtenHermonEncAtenYarkonEncAtenPilot3"
|
||||
|
||||
var _EncodingType_map = map[EncodingType]string{
|
||||
-313: _EncodingType_name[0:26],
|
||||
-312: _EncodingType_name[26:40],
|
||||
-311: _EncodingType_name[40:57],
|
||||
-309: _EncodingType_name[57:69],
|
||||
-308: _EncodingType_name[69:97],
|
||||
-307: _EncodingType_name[97:117],
|
||||
-260: _EncodingType_name[117:128],
|
||||
-258: _EncodingType_name[128:157],
|
||||
-257: _EncodingType_name[157:189],
|
||||
-256: _EncodingType_name[189:209],
|
||||
-255: _EncodingType_name[209:229],
|
||||
-254: _EncodingType_name[229:249],
|
||||
-253: _EncodingType_name[249:269],
|
||||
-252: _EncodingType_name[269:289],
|
||||
-251: _EncodingType_name[289:309],
|
||||
-250: _EncodingType_name[309:329],
|
||||
-249: _EncodingType_name[329:349],
|
||||
-248: _EncodingType_name[349:369],
|
||||
-247: _EncodingType_name[369:390],
|
||||
-240: _EncodingType_name[390:406],
|
||||
-239: _EncodingType_name[406:421],
|
||||
-224: _EncodingType_name[421:438],
|
||||
-223: _EncodingType_name[438:458],
|
||||
-32: _EncodingType_name[458:484],
|
||||
-31: _EncodingType_name[484:510],
|
||||
-30: _EncodingType_name[510:536],
|
||||
-29: _EncodingType_name[536:562],
|
||||
-28: _EncodingType_name[562:588],
|
||||
-27: _EncodingType_name[588:614],
|
||||
-26: _EncodingType_name[614:640],
|
||||
-25: _EncodingType_name[640:666],
|
||||
-24: _EncodingType_name[666:692],
|
||||
-23: _EncodingType_name[692:719],
|
||||
0: _EncodingType_name[719:725],
|
||||
1: _EncodingType_name[725:736],
|
||||
2: _EncodingType_name[736:742],
|
||||
4: _EncodingType_name[742:750],
|
||||
5: _EncodingType_name[750:760],
|
||||
6: _EncodingType_name[760:767],
|
||||
7: _EncodingType_name[767:775],
|
||||
8: _EncodingType_name[775:785],
|
||||
9: _EncodingType_name[785:794],
|
||||
10: _EncodingType_name[794:803],
|
||||
15: _EncodingType_name[803:810],
|
||||
16: _EncodingType_name[810:817],
|
||||
21: _EncodingType_name[817:824],
|
||||
22: _EncodingType_name[824:831],
|
||||
87: _EncodingType_name[831:845],
|
||||
88: _EncodingType_name[845:859],
|
||||
89: _EncodingType_name[859:872],
|
||||
96: _EncodingType_name[872:885],
|
||||
97: _EncodingType_name[885:898],
|
||||
}
|
||||
|
||||
func (i EncodingType) String() string {
|
||||
if str, ok := _EncodingType_map[i]; ok {
|
||||
return str
|
||||
}
|
||||
return fmt.Sprintf("EncodingType(%d)", i)
|
||||
}
|
||||
|
@ -1,102 +1,102 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"image"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
vnc "vnc2webm"
|
||||
"vnc2webm/encoders"
|
||||
"vnc2webm/logger"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// 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.Debugf("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{},
|
||||
},
|
||||
PixelFormat: vnc.PixelFormat32bit,
|
||||
ClientMessageCh: cchClient,
|
||||
ServerMessageCh: cchServer,
|
||||
Messages: vnc.DefaultServerMessages,
|
||||
Encodings: []vnc.Encoding{&vnc.RawEncoding{}, &vnc.TightEncoding{}},
|
||||
ErrorCh: errorCh,
|
||||
}
|
||||
|
||||
cc, err := vnc.Connect(context.Background(), nc, ccfg)
|
||||
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)
|
||||
// os.Exit(1)
|
||||
// }
|
||||
//vcodec := &encoders.MJPegImageEncoder{Quality: 60, Framerate: 6}
|
||||
vcodec := &encoders.X264ImageEncoder{}
|
||||
//vcodec := &encoders.DV8ImageEncoder{}
|
||||
//vcodec := &encoders.DV9ImageEncoder{}
|
||||
|
||||
//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)
|
||||
// Process messages coming in on the ServerMessage channel.
|
||||
for {
|
||||
select {
|
||||
case err := <-errorCh:
|
||||
panic(err)
|
||||
case msg := <-cchClient:
|
||||
logger.Debugf("Received client message type:%v msg:%v\n", msg.Type(), msg)
|
||||
case msg := <-cchServer:
|
||||
logger.Debugf("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 {
|
||||
//counter++
|
||||
//jpeg.Encode(out, screenImage, nil)
|
||||
vcodec.Encode(screenImage)
|
||||
reqMsg := vnc.FramebufferUpdateRequest{Inc: 1, X: 0, Y: 0, Width: cc.Width(), Height: cc.Height()}
|
||||
//cc.ResetAllEncodings()
|
||||
reqMsg.Write(cc)
|
||||
}
|
||||
}
|
||||
}
|
||||
//cc.Wait()
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"image"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
vnc "vnc2video"
|
||||
"vnc2video/encoders"
|
||||
"vnc2video/logger"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// 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.Debugf("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{},
|
||||
},
|
||||
PixelFormat: vnc.PixelFormat32bit,
|
||||
ClientMessageCh: cchClient,
|
||||
ServerMessageCh: cchServer,
|
||||
Messages: vnc.DefaultServerMessages,
|
||||
Encodings: []vnc.Encoding{&vnc.RawEncoding{}, &vnc.TightEncoding{}},
|
||||
ErrorCh: errorCh,
|
||||
}
|
||||
|
||||
cc, err := vnc.Connect(context.Background(), nc, ccfg)
|
||||
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)
|
||||
// os.Exit(1)
|
||||
// }
|
||||
//vcodec := &encoders.MJPegImageEncoder{Quality: 60, Framerate: 6}
|
||||
vcodec := &encoders.X264ImageEncoder{}
|
||||
//vcodec := &encoders.DV8ImageEncoder{}
|
||||
//vcodec := &encoders.DV9ImageEncoder{}
|
||||
|
||||
//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)
|
||||
// Process messages coming in on the ServerMessage channel.
|
||||
for {
|
||||
select {
|
||||
case err := <-errorCh:
|
||||
panic(err)
|
||||
case msg := <-cchClient:
|
||||
logger.Debugf("Received client message type:%v msg:%v\n", msg.Type(), msg)
|
||||
case msg := <-cchServer:
|
||||
logger.Debugf("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 {
|
||||
//counter++
|
||||
//jpeg.Encode(out, screenImage, nil)
|
||||
vcodec.Encode(screenImage)
|
||||
reqMsg := vnc.FramebufferUpdateRequest{Inc: 1, X: 0, Y: 0, Width: cc.Width(), Height: cc.Height()}
|
||||
//cc.ResetAllEncodings()
|
||||
reqMsg.Write(cc)
|
||||
}
|
||||
}
|
||||
}
|
||||
//cc.Wait()
|
||||
}
|
||||
|
@ -1,61 +1,61 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image"
|
||||
"os"
|
||||
vnc "vnc2webm"
|
||||
"vnc2webm/encoders"
|
||||
"vnc2webm/logger"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
if len(os.Args) <= 1 {
|
||||
logger.Errorf("please provide a fbs file name")
|
||||
return
|
||||
}
|
||||
if _, err := os.Stat(os.Args[1]); os.IsNotExist(err) {
|
||||
logger.Errorf("File doesn't exist", err)
|
||||
return
|
||||
}
|
||||
encs := []vnc.Encoding{
|
||||
&vnc.RawEncoding{},
|
||||
&vnc.TightEncoding{},
|
||||
}
|
||||
|
||||
fbs, err := vnc.NewFbsConn(
|
||||
os.Args[1],
|
||||
encs,
|
||||
)
|
||||
if err != nil {
|
||||
logger.Error("failed to open fbs reader:", err)
|
||||
//return nil, err
|
||||
}
|
||||
|
||||
//launch video encoding process:
|
||||
vcodec := &encoders.X264ImageEncoder{}
|
||||
//vcodec := &encoders.DV8ImageEncoder{}
|
||||
//vcodec := &encoders.DV9ImageEncoder{}
|
||||
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
|
||||
logger.Debugf("current dir: %s", dir)
|
||||
go vcodec.Run("./ffmpeg", "./output.mp4")
|
||||
|
||||
screenImage := image.NewRGBA(image.Rect(0, 0, int(fbs.Width()), int(fbs.Height())))
|
||||
for _, enc := range encs {
|
||||
myRenderer, ok := enc.(vnc.Renderer)
|
||||
|
||||
if ok {
|
||||
myRenderer.SetTargetImage(screenImage)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
msgReader := vnc.NewFBSPlayHelper(fbs)
|
||||
|
||||
//loop over all messages, feed images to video codec:
|
||||
for {
|
||||
msgReader.ReadFbsMessage()
|
||||
vcodec.Encode(screenImage)
|
||||
}
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
"image"
|
||||
"os"
|
||||
vnc "vnc2video"
|
||||
"vnc2video/encoders"
|
||||
"vnc2video/logger"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
if len(os.Args) <= 1 {
|
||||
logger.Errorf("please provide a fbs file name")
|
||||
return
|
||||
}
|
||||
if _, err := os.Stat(os.Args[1]); os.IsNotExist(err) {
|
||||
logger.Errorf("File doesn't exist", err)
|
||||
return
|
||||
}
|
||||
encs := []vnc.Encoding{
|
||||
&vnc.RawEncoding{},
|
||||
&vnc.TightEncoding{},
|
||||
}
|
||||
|
||||
fbs, err := vnc.NewFbsConn(
|
||||
os.Args[1],
|
||||
encs,
|
||||
)
|
||||
if err != nil {
|
||||
logger.Error("failed to open fbs reader:", err)
|
||||
//return nil, err
|
||||
}
|
||||
|
||||
//launch video encoding process:
|
||||
vcodec := &encoders.X264ImageEncoder{}
|
||||
//vcodec := &encoders.DV8ImageEncoder{}
|
||||
//vcodec := &encoders.DV9ImageEncoder{}
|
||||
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
|
||||
logger.Debugf("current dir: %s", dir)
|
||||
go vcodec.Run("./ffmpeg", "./output.mp4")
|
||||
|
||||
screenImage := image.NewRGBA(image.Rect(0, 0, int(fbs.Width()), int(fbs.Height())))
|
||||
for _, enc := range encs {
|
||||
myRenderer, ok := enc.(vnc.Renderer)
|
||||
|
||||
if ok {
|
||||
myRenderer.SetTargetImage(screenImage)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
msgReader := vnc.NewFBSPlayHelper(fbs)
|
||||
|
||||
//loop over all messages, feed images to video codec:
|
||||
for {
|
||||
msgReader.ReadFbsMessage()
|
||||
vcodec.Encode(screenImage)
|
||||
}
|
||||
}
|
||||
|
@ -1,255 +1,255 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
vnc "vnc2webm"
|
||||
"vnc2webm/logger"
|
||||
)
|
||||
|
||||
type Auth struct {
|
||||
Username []byte
|
||||
Password []byte
|
||||
}
|
||||
|
||||
type Proxy struct {
|
||||
cc vnc.Conn
|
||||
conns chan vnc.Conn
|
||||
inp chan vnc.ClientMessage
|
||||
out chan vnc.ServerMessage
|
||||
}
|
||||
|
||||
var (
|
||||
cliconns = make(map[string]*Proxy)
|
||||
srvconns = make(map[vnc.Conn]string)
|
||||
m sync.Mutex
|
||||
)
|
||||
|
||||
func newConn(hostport string, password []byte) (vnc.Conn, chan vnc.ClientMessage, chan vnc.ServerMessage, chan vnc.Conn, error) {
|
||||
fmt.Printf("new conn to %s with %s\n", hostport, password)
|
||||
if cc, ok := cliconns[hostport]; ok {
|
||||
return cc.cc, cc.inp, cc.out, cc.conns, nil
|
||||
}
|
||||
c, err := net.DialTimeout("tcp", hostport, 10*time.Second)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
cchServer := make(chan vnc.ServerMessage)
|
||||
cchClient := make(chan vnc.ClientMessage)
|
||||
errorCh := make(chan error)
|
||||
ccfg := &vnc.ClientConfig{
|
||||
SecurityHandlers: []vnc.SecurityHandler{&vnc.ClientAuthVNC{Password: password}},
|
||||
PixelFormat: vnc.PixelFormat32bit,
|
||||
ClientMessageCh: cchClient,
|
||||
ServerMessageCh: cchServer,
|
||||
//ServerMessages: vnc.DefaultServerMessages,
|
||||
Encodings: []vnc.Encoding{&vnc.RawEncoding{}},
|
||||
ErrorCh: errorCh,
|
||||
}
|
||||
csrv := make(chan vnc.Conn)
|
||||
inp := make(chan vnc.ClientMessage)
|
||||
out := make(chan vnc.ServerMessage)
|
||||
fmt.Printf("connect to vnc\n")
|
||||
cc, err := vnc.Connect(context.Background(), c, ccfg)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
fmt.Printf("connected to vnc %#+v\n", cc)
|
||||
ds := &vnc.DefaultClientMessageHandler{}
|
||||
go ds.Handle(cc)
|
||||
go handleIO(cc, inp, out, csrv)
|
||||
|
||||
return cc, inp, out, csrv, nil
|
||||
}
|
||||
|
||||
func handleIO(cli vnc.Conn, inp chan vnc.ClientMessage, out chan vnc.ServerMessage, csrv chan vnc.Conn) {
|
||||
fmt.Printf("handle io\n")
|
||||
ccfg := cli.Config().(*vnc.ClientConfig)
|
||||
defer cli.Close()
|
||||
var conns []vnc.Conn
|
||||
//var prepared bool
|
||||
|
||||
for {
|
||||
select {
|
||||
case err := <-ccfg.ErrorCh:
|
||||
for _, srv := range conns {
|
||||
srv.Close()
|
||||
}
|
||||
fmt.Printf("err %v\n", err)
|
||||
return
|
||||
case msg := <-ccfg.ServerMessageCh:
|
||||
for _, srv := range conns {
|
||||
scfg := srv.Config().(*vnc.ServerConfig)
|
||||
scfg.ServerMessageCh <- msg
|
||||
}
|
||||
case msg := <-inp:
|
||||
// messages from real clients
|
||||
fmt.Printf("3 %#+v\n", msg)
|
||||
switch msg.Type() {
|
||||
case vnc.SetPixelFormatMsgType:
|
||||
|
||||
case vnc.SetEncodingsMsgType:
|
||||
var encTypes []vnc.EncodingType
|
||||
encs := []vnc.Encoding{
|
||||
// &vnc.TightPngEncoding{},
|
||||
&vnc.CopyRectEncoding{},
|
||||
&vnc.RawEncoding{},
|
||||
}
|
||||
for _, senc := range encs {
|
||||
for _, cenc := range msg.(*vnc.SetEncodings).Encodings {
|
||||
if cenc == senc.Type() {
|
||||
encTypes = append(encTypes, senc.Type())
|
||||
}
|
||||
}
|
||||
}
|
||||
ccfg.ClientMessageCh <- &vnc.SetEncodings{Encodings: encTypes}
|
||||
default:
|
||||
ccfg.ClientMessageCh <- msg
|
||||
}
|
||||
case msg := <-out:
|
||||
fmt.Printf("4 %#+v\n", msg)
|
||||
case srv := <-csrv:
|
||||
conns = append(conns, srv)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type HijackHandler struct{}
|
||||
|
||||
func (*HijackHandler) Handle(c vnc.Conn) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
hostport, ok := srvconns[c]
|
||||
if !ok {
|
||||
return fmt.Errorf("client connect in server pool not found")
|
||||
}
|
||||
proxy, ok := cliconns[hostport]
|
||||
if !ok {
|
||||
return fmt.Errorf("client connect to qemu not found")
|
||||
}
|
||||
cfg := c.Config().(*vnc.ServerConfig)
|
||||
cfg.ClientMessageCh = proxy.inp
|
||||
cfg.ServerMessageCh = proxy.out
|
||||
|
||||
proxy.conns <- c
|
||||
ds := &vnc.DefaultServerMessageHandler{}
|
||||
go ds.Handle(c)
|
||||
return nil
|
||||
}
|
||||
|
||||
type AuthVNCHTTP struct {
|
||||
c *http.Client
|
||||
vnc.ServerAuthVNC
|
||||
}
|
||||
|
||||
func (auth *AuthVNCHTTP) Auth(c vnc.Conn) error {
|
||||
auth.ServerAuthVNC.Challenge = []byte("clodo.ruclodo.ru")
|
||||
if err := auth.ServerAuthVNC.WriteChallenge(c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := auth.ServerAuthVNC.ReadChallenge(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
enc := base64.NewEncoder(base64.StdEncoding, buf)
|
||||
enc.Write(auth.ServerAuthVNC.Crypted)
|
||||
enc.Close()
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("hash", buf.String())
|
||||
buf.Reset()
|
||||
src, _, _ := net.SplitHostPort(c.Conn().RemoteAddr().String())
|
||||
v.Set("ip", src)
|
||||
res, err := auth.c.PostForm("https://api.ix.clodo.ru/system/vnc", v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.StatusCode != 200 || res.Body == nil {
|
||||
if res.Body != nil {
|
||||
io.Copy(buf, res.Body)
|
||||
}
|
||||
fmt.Printf("failed to get auth data: code %d body %s\n", res.StatusCode, buf.String())
|
||||
defer buf.Reset()
|
||||
return fmt.Errorf("failed to get auth data: code %d body %s", res.StatusCode, buf.String())
|
||||
}
|
||||
_, err = io.Copy(buf, res.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get auth data: %s", err.Error())
|
||||
}
|
||||
logger.Infof("http auth: %s\n", buf.Bytes())
|
||||
res.Body.Close()
|
||||
data := strings.Split(buf.String(), " ")
|
||||
if len(data) < 2 {
|
||||
return fmt.Errorf("failed to get auth data data invalid")
|
||||
}
|
||||
buf.Reset()
|
||||
|
||||
hostport := string(data[0])
|
||||
password := []byte(data[1])
|
||||
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
cc, inp, out, conns, err := newConn(hostport, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cliconns[hostport] = &Proxy{cc, conns, inp, out}
|
||||
srvconns[c] = hostport
|
||||
c.SetWidth(cc.Width())
|
||||
c.SetHeight(cc.Height())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*AuthVNCHTTP) Type() vnc.SecurityType {
|
||||
return vnc.SecTypeVNC
|
||||
}
|
||||
|
||||
func (*AuthVNCHTTP) SubType() vnc.SecuritySubType {
|
||||
return vnc.SecSubTypeUnknown
|
||||
}
|
||||
|
||||
func main() {
|
||||
go func() {
|
||||
logger.Info(http.ListenAndServe(":6060", nil))
|
||||
}()
|
||||
|
||||
ln, err := net.Listen("tcp", ":6900")
|
||||
if err != nil {
|
||||
logger.Fatalf("Error listen. %v", err)
|
||||
}
|
||||
|
||||
schClient := make(chan vnc.ClientMessage)
|
||||
schServer := make(chan vnc.ServerMessage)
|
||||
|
||||
scfg := &vnc.ServerConfig{
|
||||
SecurityHandlers: []vnc.SecurityHandler{
|
||||
&AuthVNCHTTP{c: &http.Client{}},
|
||||
},
|
||||
Encodings: []vnc.Encoding{
|
||||
// &vnc.TightPngEncoding{},
|
||||
&vnc.CopyRectEncoding{},
|
||||
&vnc.RawEncoding{},
|
||||
},
|
||||
PixelFormat: vnc.PixelFormat32bit,
|
||||
ClientMessageCh: schClient,
|
||||
ServerMessageCh: schServer,
|
||||
//ClientMessages: vnc.DefaultClientMessages,
|
||||
DesktopName: []byte("vnc proxy"),
|
||||
}
|
||||
scfg.Handlers = append(scfg.Handlers, vnc.DefaultServerHandlers...)
|
||||
scfg.Handlers = append(scfg.Handlers[:len(scfg.Handlers)-1], &HijackHandler{})
|
||||
vnc.Serve(context.Background(), ln, scfg)
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
vnc "vnc2video"
|
||||
"vnc2video/logger"
|
||||
)
|
||||
|
||||
type Auth struct {
|
||||
Username []byte
|
||||
Password []byte
|
||||
}
|
||||
|
||||
type Proxy struct {
|
||||
cc vnc.Conn
|
||||
conns chan vnc.Conn
|
||||
inp chan vnc.ClientMessage
|
||||
out chan vnc.ServerMessage
|
||||
}
|
||||
|
||||
var (
|
||||
cliconns = make(map[string]*Proxy)
|
||||
srvconns = make(map[vnc.Conn]string)
|
||||
m sync.Mutex
|
||||
)
|
||||
|
||||
func newConn(hostport string, password []byte) (vnc.Conn, chan vnc.ClientMessage, chan vnc.ServerMessage, chan vnc.Conn, error) {
|
||||
fmt.Printf("new conn to %s with %s\n", hostport, password)
|
||||
if cc, ok := cliconns[hostport]; ok {
|
||||
return cc.cc, cc.inp, cc.out, cc.conns, nil
|
||||
}
|
||||
c, err := net.DialTimeout("tcp", hostport, 10*time.Second)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
cchServer := make(chan vnc.ServerMessage)
|
||||
cchClient := make(chan vnc.ClientMessage)
|
||||
errorCh := make(chan error)
|
||||
ccfg := &vnc.ClientConfig{
|
||||
SecurityHandlers: []vnc.SecurityHandler{&vnc.ClientAuthVNC{Password: password}},
|
||||
PixelFormat: vnc.PixelFormat32bit,
|
||||
ClientMessageCh: cchClient,
|
||||
ServerMessageCh: cchServer,
|
||||
//ServerMessages: vnc.DefaultServerMessages,
|
||||
Encodings: []vnc.Encoding{&vnc.RawEncoding{}},
|
||||
ErrorCh: errorCh,
|
||||
}
|
||||
csrv := make(chan vnc.Conn)
|
||||
inp := make(chan vnc.ClientMessage)
|
||||
out := make(chan vnc.ServerMessage)
|
||||
fmt.Printf("connect to vnc\n")
|
||||
cc, err := vnc.Connect(context.Background(), c, ccfg)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
fmt.Printf("connected to vnc %#+v\n", cc)
|
||||
ds := &vnc.DefaultClientMessageHandler{}
|
||||
go ds.Handle(cc)
|
||||
go handleIO(cc, inp, out, csrv)
|
||||
|
||||
return cc, inp, out, csrv, nil
|
||||
}
|
||||
|
||||
func handleIO(cli vnc.Conn, inp chan vnc.ClientMessage, out chan vnc.ServerMessage, csrv chan vnc.Conn) {
|
||||
fmt.Printf("handle io\n")
|
||||
ccfg := cli.Config().(*vnc.ClientConfig)
|
||||
defer cli.Close()
|
||||
var conns []vnc.Conn
|
||||
//var prepared bool
|
||||
|
||||
for {
|
||||
select {
|
||||
case err := <-ccfg.ErrorCh:
|
||||
for _, srv := range conns {
|
||||
srv.Close()
|
||||
}
|
||||
fmt.Printf("err %v\n", err)
|
||||
return
|
||||
case msg := <-ccfg.ServerMessageCh:
|
||||
for _, srv := range conns {
|
||||
scfg := srv.Config().(*vnc.ServerConfig)
|
||||
scfg.ServerMessageCh <- msg
|
||||
}
|
||||
case msg := <-inp:
|
||||
// messages from real clients
|
||||
fmt.Printf("3 %#+v\n", msg)
|
||||
switch msg.Type() {
|
||||
case vnc.SetPixelFormatMsgType:
|
||||
|
||||
case vnc.SetEncodingsMsgType:
|
||||
var encTypes []vnc.EncodingType
|
||||
encs := []vnc.Encoding{
|
||||
// &vnc.TightPngEncoding{},
|
||||
&vnc.CopyRectEncoding{},
|
||||
&vnc.RawEncoding{},
|
||||
}
|
||||
for _, senc := range encs {
|
||||
for _, cenc := range msg.(*vnc.SetEncodings).Encodings {
|
||||
if cenc == senc.Type() {
|
||||
encTypes = append(encTypes, senc.Type())
|
||||
}
|
||||
}
|
||||
}
|
||||
ccfg.ClientMessageCh <- &vnc.SetEncodings{Encodings: encTypes}
|
||||
default:
|
||||
ccfg.ClientMessageCh <- msg
|
||||
}
|
||||
case msg := <-out:
|
||||
fmt.Printf("4 %#+v\n", msg)
|
||||
case srv := <-csrv:
|
||||
conns = append(conns, srv)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type HijackHandler struct{}
|
||||
|
||||
func (*HijackHandler) Handle(c vnc.Conn) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
hostport, ok := srvconns[c]
|
||||
if !ok {
|
||||
return fmt.Errorf("client connect in server pool not found")
|
||||
}
|
||||
proxy, ok := cliconns[hostport]
|
||||
if !ok {
|
||||
return fmt.Errorf("client connect to qemu not found")
|
||||
}
|
||||
cfg := c.Config().(*vnc.ServerConfig)
|
||||
cfg.ClientMessageCh = proxy.inp
|
||||
cfg.ServerMessageCh = proxy.out
|
||||
|
||||
proxy.conns <- c
|
||||
ds := &vnc.DefaultServerMessageHandler{}
|
||||
go ds.Handle(c)
|
||||
return nil
|
||||
}
|
||||
|
||||
type AuthVNCHTTP struct {
|
||||
c *http.Client
|
||||
vnc.ServerAuthVNC
|
||||
}
|
||||
|
||||
func (auth *AuthVNCHTTP) Auth(c vnc.Conn) error {
|
||||
auth.ServerAuthVNC.Challenge = []byte("clodo.ruclodo.ru")
|
||||
if err := auth.ServerAuthVNC.WriteChallenge(c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := auth.ServerAuthVNC.ReadChallenge(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
enc := base64.NewEncoder(base64.StdEncoding, buf)
|
||||
enc.Write(auth.ServerAuthVNC.Crypted)
|
||||
enc.Close()
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("hash", buf.String())
|
||||
buf.Reset()
|
||||
src, _, _ := net.SplitHostPort(c.Conn().RemoteAddr().String())
|
||||
v.Set("ip", src)
|
||||
res, err := auth.c.PostForm("https://api.ix.clodo.ru/system/vnc", v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.StatusCode != 200 || res.Body == nil {
|
||||
if res.Body != nil {
|
||||
io.Copy(buf, res.Body)
|
||||
}
|
||||
fmt.Printf("failed to get auth data: code %d body %s\n", res.StatusCode, buf.String())
|
||||
defer buf.Reset()
|
||||
return fmt.Errorf("failed to get auth data: code %d body %s", res.StatusCode, buf.String())
|
||||
}
|
||||
_, err = io.Copy(buf, res.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get auth data: %s", err.Error())
|
||||
}
|
||||
logger.Infof("http auth: %s\n", buf.Bytes())
|
||||
res.Body.Close()
|
||||
data := strings.Split(buf.String(), " ")
|
||||
if len(data) < 2 {
|
||||
return fmt.Errorf("failed to get auth data data invalid")
|
||||
}
|
||||
buf.Reset()
|
||||
|
||||
hostport := string(data[0])
|
||||
password := []byte(data[1])
|
||||
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
cc, inp, out, conns, err := newConn(hostport, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cliconns[hostport] = &Proxy{cc, conns, inp, out}
|
||||
srvconns[c] = hostport
|
||||
c.SetWidth(cc.Width())
|
||||
c.SetHeight(cc.Height())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*AuthVNCHTTP) Type() vnc.SecurityType {
|
||||
return vnc.SecTypeVNC
|
||||
}
|
||||
|
||||
func (*AuthVNCHTTP) SubType() vnc.SecuritySubType {
|
||||
return vnc.SecSubTypeUnknown
|
||||
}
|
||||
|
||||
func main() {
|
||||
go func() {
|
||||
logger.Info(http.ListenAndServe(":6060", nil))
|
||||
}()
|
||||
|
||||
ln, err := net.Listen("tcp", ":6900")
|
||||
if err != nil {
|
||||
logger.Fatalf("Error listen. %v", err)
|
||||
}
|
||||
|
||||
schClient := make(chan vnc.ClientMessage)
|
||||
schServer := make(chan vnc.ServerMessage)
|
||||
|
||||
scfg := &vnc.ServerConfig{
|
||||
SecurityHandlers: []vnc.SecurityHandler{
|
||||
&AuthVNCHTTP{c: &http.Client{}},
|
||||
},
|
||||
Encodings: []vnc.Encoding{
|
||||
// &vnc.TightPngEncoding{},
|
||||
&vnc.CopyRectEncoding{},
|
||||
&vnc.RawEncoding{},
|
||||
},
|
||||
PixelFormat: vnc.PixelFormat32bit,
|
||||
ClientMessageCh: schClient,
|
||||
ServerMessageCh: schServer,
|
||||
//ClientMessages: vnc.DefaultClientMessages,
|
||||
DesktopName: []byte("vnc proxy"),
|
||||
}
|
||||
scfg.Handlers = append(scfg.Handlers, vnc.DefaultServerHandlers...)
|
||||
scfg.Handlers = append(scfg.Handlers[:len(scfg.Handlers)-1], &HijackHandler{})
|
||||
vnc.Serve(context.Background(), ln, scfg)
|
||||
}
|
||||
|
@ -1,93 +1,93 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"image"
|
||||
"math"
|
||||
"net"
|
||||
"time"
|
||||
vnc "vnc2webm"
|
||||
"vnc2webm/logger"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ln, err := net.Listen("tcp", ":5900")
|
||||
if err != nil {
|
||||
logger.Fatalf("Error listen. %v", err)
|
||||
}
|
||||
|
||||
chServer := make(chan vnc.ClientMessage)
|
||||
chClient := make(chan vnc.ServerMessage)
|
||||
|
||||
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,
|
||||
//VersionHandler: vnc.ServerVersionHandler,
|
||||
//SecurityHandler: vnc.ServerSecurityHandler,
|
||||
SecurityHandlers: []vnc.SecurityHandler{&vnc.ClientAuthNone{}},
|
||||
//ClientInitHandler: vnc.ServerClientInitHandler,
|
||||
//ServerInitHandler: vnc.ServerServerInitHandler,
|
||||
Encodings: []vnc.Encoding{&vnc.RawEncoding{}},
|
||||
PixelFormat: vnc.PixelFormat32bit,
|
||||
ClientMessageCh: chServer,
|
||||
ServerMessageCh: chClient,
|
||||
Messages: vnc.DefaultClientMessages,
|
||||
}
|
||||
cfg.Handlers = vnc.DefaultServerHandlers
|
||||
go vnc.Serve(context.Background(), ln, cfg)
|
||||
|
||||
// Process messages coming in on the ClientMessage channel.
|
||||
for {
|
||||
select {
|
||||
case <-tick.C:
|
||||
drawImage(im, 0)
|
||||
fmt.Printf("tick\n")
|
||||
case msg := <-chClient:
|
||||
switch msg.Type() {
|
||||
default:
|
||||
logger.Debugf("11 Received message type:%v msg:%v\n", msg.Type(), msg)
|
||||
}
|
||||
case msg := <-chServer:
|
||||
switch msg.Type() {
|
||||
default:
|
||||
logger.Debugf("22 Received message type:%v msg:%v\n", msg.Type(), msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
width = 800
|
||||
height = 600
|
||||
)
|
||||
|
||||
func drawImage(im *image.RGBA, anim int) {
|
||||
pos := 0
|
||||
const border = 50
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
var r, g, b uint8
|
||||
switch {
|
||||
case x < border*2.5 && x < int((1.1+math.Sin(float64(y+anim*2)/40))*border):
|
||||
r = 255
|
||||
case x > width-border*2.5 && x > width-int((1.1+math.Sin(math.Pi+float64(y+anim*2)/40))*border):
|
||||
g = 255
|
||||
case y < border*2.5 && y < int((1.1+math.Sin(float64(x+anim*2)/40))*border):
|
||||
r, g = 255, 255
|
||||
case y > height-border*2.5 && y > height-int((1.1+math.Sin(math.Pi+float64(x+anim*2)/40))*border):
|
||||
b = 255
|
||||
default:
|
||||
r, g, b = uint8(x+anim), uint8(y+anim), uint8(x+y+anim*3)
|
||||
}
|
||||
im.Pix[pos] = r
|
||||
im.Pix[pos+1] = g
|
||||
im.Pix[pos+2] = b
|
||||
pos += 4 // skipping alpha
|
||||
}
|
||||
}
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"image"
|
||||
"math"
|
||||
"net"
|
||||
"time"
|
||||
vnc "vnc2video"
|
||||
"vnc2video/logger"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ln, err := net.Listen("tcp", ":5900")
|
||||
if err != nil {
|
||||
logger.Fatalf("Error listen. %v", err)
|
||||
}
|
||||
|
||||
chServer := make(chan vnc.ClientMessage)
|
||||
chClient := make(chan vnc.ServerMessage)
|
||||
|
||||
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,
|
||||
//VersionHandler: vnc.ServerVersionHandler,
|
||||
//SecurityHandler: vnc.ServerSecurityHandler,
|
||||
SecurityHandlers: []vnc.SecurityHandler{&vnc.ClientAuthNone{}},
|
||||
//ClientInitHandler: vnc.ServerClientInitHandler,
|
||||
//ServerInitHandler: vnc.ServerServerInitHandler,
|
||||
Encodings: []vnc.Encoding{&vnc.RawEncoding{}},
|
||||
PixelFormat: vnc.PixelFormat32bit,
|
||||
ClientMessageCh: chServer,
|
||||
ServerMessageCh: chClient,
|
||||
Messages: vnc.DefaultClientMessages,
|
||||
}
|
||||
cfg.Handlers = vnc.DefaultServerHandlers
|
||||
go vnc.Serve(context.Background(), ln, cfg)
|
||||
|
||||
// Process messages coming in on the ClientMessage channel.
|
||||
for {
|
||||
select {
|
||||
case <-tick.C:
|
||||
drawImage(im, 0)
|
||||
fmt.Printf("tick\n")
|
||||
case msg := <-chClient:
|
||||
switch msg.Type() {
|
||||
default:
|
||||
logger.Debugf("11 Received message type:%v msg:%v\n", msg.Type(), msg)
|
||||
}
|
||||
case msg := <-chServer:
|
||||
switch msg.Type() {
|
||||
default:
|
||||
logger.Debugf("22 Received message type:%v msg:%v\n", msg.Type(), msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
width = 800
|
||||
height = 600
|
||||
)
|
||||
|
||||
func drawImage(im *image.RGBA, anim int) {
|
||||
pos := 0
|
||||
const border = 50
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
var r, g, b uint8
|
||||
switch {
|
||||
case x < border*2.5 && x < int((1.1+math.Sin(float64(y+anim*2)/40))*border):
|
||||
r = 255
|
||||
case x > width-border*2.5 && x > width-int((1.1+math.Sin(math.Pi+float64(y+anim*2)/40))*border):
|
||||
g = 255
|
||||
case y < border*2.5 && y < int((1.1+math.Sin(float64(x+anim*2)/40))*border):
|
||||
r, g = 255, 255
|
||||
case y > height-border*2.5 && y > height-int((1.1+math.Sin(math.Pi+float64(x+anim*2)/40))*border):
|
||||
b = 255
|
||||
default:
|
||||
r, g, b = uint8(x+anim), uint8(y+anim), uint8(x+y+anim*3)
|
||||
}
|
||||
im.Pix[pos] = r
|
||||
im.Pix[pos+1] = g
|
||||
im.Pix[pos+2] = b
|
||||
pos += 4 // skipping alpha
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,201 +1,201 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"vnc2webm/logger"
|
||||
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Conn represents vnc conection
|
||||
type FbsConn struct {
|
||||
FbsReader
|
||||
|
||||
protocol string
|
||||
//c net.IServerConn
|
||||
//config *ClientConfig
|
||||
colorMap ColorMap
|
||||
|
||||
// Encodings supported by the client. This should not be modified
|
||||
// directly. Instead, SetEncodings should be used.
|
||||
encodings []Encoding
|
||||
|
||||
// Height of the frame buffer in pixels, sent from the server.
|
||||
fbHeight uint16
|
||||
|
||||
// Width of the frame buffer in pixels, sent from the server.
|
||||
fbWidth uint16
|
||||
desktopName string
|
||||
// The pixel format associated with the connection. This shouldn't
|
||||
// be modified. If you wish to set a new pixel format, use the
|
||||
// SetPixelFormat method.
|
||||
pixelFormat PixelFormat
|
||||
}
|
||||
|
||||
// func (c *FbsConn) Close() error {
|
||||
// return c.fbs.Close()
|
||||
// }
|
||||
|
||||
// // Read reads data from conn
|
||||
// func (c *FbsConn) Read(buf []byte) (int, error) {
|
||||
// return c.fbs.Read(buf)
|
||||
// }
|
||||
|
||||
//dummy, no writing to this conn...
|
||||
func (c *FbsConn) Write(buf []byte) (int, error) {
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func (c *FbsConn) Conn() net.Conn {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FbsConn) Config() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FbsConn) Protocol() string {
|
||||
return "RFB 003.008"
|
||||
}
|
||||
func (c *FbsConn) PixelFormat() PixelFormat {
|
||||
return c.pixelFormat
|
||||
}
|
||||
|
||||
func (c *FbsConn) SetPixelFormat(pf PixelFormat) error {
|
||||
c.pixelFormat = pf
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FbsConn) ColorMap() ColorMap { return c.colorMap }
|
||||
func (c *FbsConn) SetColorMap(cm ColorMap) { c.colorMap = cm }
|
||||
func (c *FbsConn) Encodings() []Encoding { return c.encodings }
|
||||
func (c *FbsConn) SetEncodings([]EncodingType) error { return nil }
|
||||
func (c *FbsConn) Width() uint16 { return c.fbWidth }
|
||||
func (c *FbsConn) Height() uint16 { return c.fbHeight }
|
||||
func (c *FbsConn) SetWidth(w uint16) { c.fbWidth = w }
|
||||
func (c *FbsConn) SetHeight(h uint16) { c.fbHeight = h }
|
||||
func (c *FbsConn) DesktopName() []byte { return []byte(c.desktopName) }
|
||||
func (c *FbsConn) SetDesktopName(d []byte) { c.desktopName = string(d) }
|
||||
func (c *FbsConn) Flush() error { return nil }
|
||||
func (c *FbsConn) Wait() {}
|
||||
func (c *FbsConn) SetProtoVersion(string) {}
|
||||
func (c *FbsConn) SetSecurityHandler(SecurityHandler) error { return nil }
|
||||
func (c *FbsConn) SecurityHandler() SecurityHandler { return nil }
|
||||
func (c *FbsConn) GetEncInstance(typ EncodingType) Encoding {
|
||||
for _, enc := range c.encodings {
|
||||
if enc.Type() == typ {
|
||||
return enc
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type VncStreamFileReader interface {
|
||||
io.Reader
|
||||
CurrentTimestamp() int
|
||||
ReadStartSession() (*ServerInit, error)
|
||||
CurrentPixelFormat() *PixelFormat
|
||||
Encodings() []Encoding
|
||||
}
|
||||
|
||||
type FBSPlayHelper struct {
|
||||
Conn *FbsConn
|
||||
//Fbs VncStreamFileReader
|
||||
serverMessageMap map[uint8]ServerMessage
|
||||
firstSegDone bool
|
||||
startTime int
|
||||
}
|
||||
|
||||
func NewFbsConn(filename string, encs []Encoding) (*FbsConn, error) {
|
||||
|
||||
fbs, err := NewFbsReader(filename)
|
||||
if err != nil {
|
||||
logger.Error("failed to open fbs reader:", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
//NewFbsReader("/Users/amitbet/vncRec/recording.rbs")
|
||||
initMsg, err := fbs.ReadStartSession()
|
||||
if err != nil {
|
||||
logger.Error("failed to open read fbs start session:", err)
|
||||
return nil, err
|
||||
}
|
||||
fbsConn := &FbsConn{FbsReader: *fbs}
|
||||
fbsConn.encodings = encs
|
||||
fbsConn.SetPixelFormat(initMsg.PixelFormat)
|
||||
fbsConn.SetHeight(initMsg.FBHeight)
|
||||
fbsConn.SetWidth(initMsg.FBWidth)
|
||||
fbsConn.SetDesktopName([]byte(initMsg.NameText))
|
||||
|
||||
return fbsConn, nil
|
||||
}
|
||||
|
||||
func NewFBSPlayHelper(r *FbsConn) *FBSPlayHelper {
|
||||
h := &FBSPlayHelper{Conn: r}
|
||||
h.startTime = int(time.Now().UnixNano() / int64(time.Millisecond))
|
||||
|
||||
h.serverMessageMap = make(map[uint8]ServerMessage)
|
||||
h.serverMessageMap[0] = &FramebufferUpdate{}
|
||||
h.serverMessageMap[1] = &SetColorMapEntries{}
|
||||
h.serverMessageMap[2] = &Bell{}
|
||||
h.serverMessageMap[3] = &ServerCutText{}
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
// func (handler *FBSPlayHelper) Consume(seg *RfbSegment) error {
|
||||
|
||||
// switch seg.SegmentType {
|
||||
// case SegmentFullyParsedClientMessage:
|
||||
// clientMsg := seg.Message.(ClientMessage)
|
||||
// logger.Debugf("ClientUpdater.Consume:(vnc-server-bound) got ClientMessage type=%s", clientMsg.Type())
|
||||
// switch clientMsg.Type() {
|
||||
|
||||
// case FramebufferUpdateRequestMsgType:
|
||||
// if !handler.firstSegDone {
|
||||
// handler.firstSegDone = true
|
||||
// handler.startTime = int(time.Now().UnixNano() / int64(time.Millisecond))
|
||||
// }
|
||||
// handler.sendFbsMessage()
|
||||
// }
|
||||
// // server.MsgFramebufferUpdateRequest:
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
func (h *FBSPlayHelper) ReadFbsMessage() ServerMessage {
|
||||
var messageType uint8
|
||||
//messages := make(map[uint8]ServerMessage)
|
||||
fbs := h.Conn
|
||||
//conn := h.Conn
|
||||
err := binary.Read(fbs, binary.BigEndian, &messageType)
|
||||
if err != nil {
|
||||
logger.Error("TestServer.NewConnHandler: Error in reading FBS: ", err)
|
||||
return nil
|
||||
}
|
||||
//IClientConn{}
|
||||
//binary.Write(h.Conn, binary.BigEndian, messageType)
|
||||
msg := h.serverMessageMap[messageType]
|
||||
if msg == nil {
|
||||
logger.Error("TestServer.NewConnHandler: Error unknown message type: ", messageType)
|
||||
return nil
|
||||
}
|
||||
//read the actual message data
|
||||
//err = binary.Read(fbs, binary.BigEndian, &msg)
|
||||
parsedMsg, err := msg.Read(fbs)
|
||||
if err != nil {
|
||||
logger.Error("TestServer.NewConnHandler: Error in reading FBS message: ", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
timeSinceStart := int(time.Now().UnixNano()/int64(time.Millisecond)) - h.startTime
|
||||
timeToSleep := fbs.CurrentTimestamp() - timeSinceStart
|
||||
if timeToSleep > 0 {
|
||||
time.Sleep(time.Duration(timeToSleep) * time.Millisecond)
|
||||
}
|
||||
|
||||
return parsedMsg
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"vnc2video/logger"
|
||||
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Conn represents vnc conection
|
||||
type FbsConn struct {
|
||||
FbsReader
|
||||
|
||||
protocol string
|
||||
//c net.IServerConn
|
||||
//config *ClientConfig
|
||||
colorMap ColorMap
|
||||
|
||||
// Encodings supported by the client. This should not be modified
|
||||
// directly. Instead, SetEncodings should be used.
|
||||
encodings []Encoding
|
||||
|
||||
// Height of the frame buffer in pixels, sent from the server.
|
||||
fbHeight uint16
|
||||
|
||||
// Width of the frame buffer in pixels, sent from the server.
|
||||
fbWidth uint16
|
||||
desktopName string
|
||||
// The pixel format associated with the connection. This shouldn't
|
||||
// be modified. If you wish to set a new pixel format, use the
|
||||
// SetPixelFormat method.
|
||||
pixelFormat PixelFormat
|
||||
}
|
||||
|
||||
// func (c *FbsConn) Close() error {
|
||||
// return c.fbs.Close()
|
||||
// }
|
||||
|
||||
// // Read reads data from conn
|
||||
// func (c *FbsConn) Read(buf []byte) (int, error) {
|
||||
// return c.fbs.Read(buf)
|
||||
// }
|
||||
|
||||
//dummy, no writing to this conn...
|
||||
func (c *FbsConn) Write(buf []byte) (int, error) {
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func (c *FbsConn) Conn() net.Conn {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FbsConn) Config() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FbsConn) Protocol() string {
|
||||
return "RFB 003.008"
|
||||
}
|
||||
func (c *FbsConn) PixelFormat() PixelFormat {
|
||||
return c.pixelFormat
|
||||
}
|
||||
|
||||
func (c *FbsConn) SetPixelFormat(pf PixelFormat) error {
|
||||
c.pixelFormat = pf
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FbsConn) ColorMap() ColorMap { return c.colorMap }
|
||||
func (c *FbsConn) SetColorMap(cm ColorMap) { c.colorMap = cm }
|
||||
func (c *FbsConn) Encodings() []Encoding { return c.encodings }
|
||||
func (c *FbsConn) SetEncodings([]EncodingType) error { return nil }
|
||||
func (c *FbsConn) Width() uint16 { return c.fbWidth }
|
||||
func (c *FbsConn) Height() uint16 { return c.fbHeight }
|
||||
func (c *FbsConn) SetWidth(w uint16) { c.fbWidth = w }
|
||||
func (c *FbsConn) SetHeight(h uint16) { c.fbHeight = h }
|
||||
func (c *FbsConn) DesktopName() []byte { return []byte(c.desktopName) }
|
||||
func (c *FbsConn) SetDesktopName(d []byte) { c.desktopName = string(d) }
|
||||
func (c *FbsConn) Flush() error { return nil }
|
||||
func (c *FbsConn) Wait() {}
|
||||
func (c *FbsConn) SetProtoVersion(string) {}
|
||||
func (c *FbsConn) SetSecurityHandler(SecurityHandler) error { return nil }
|
||||
func (c *FbsConn) SecurityHandler() SecurityHandler { return nil }
|
||||
func (c *FbsConn) GetEncInstance(typ EncodingType) Encoding {
|
||||
for _, enc := range c.encodings {
|
||||
if enc.Type() == typ {
|
||||
return enc
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type VncStreamFileReader interface {
|
||||
io.Reader
|
||||
CurrentTimestamp() int
|
||||
ReadStartSession() (*ServerInit, error)
|
||||
CurrentPixelFormat() *PixelFormat
|
||||
Encodings() []Encoding
|
||||
}
|
||||
|
||||
type FBSPlayHelper struct {
|
||||
Conn *FbsConn
|
||||
//Fbs VncStreamFileReader
|
||||
serverMessageMap map[uint8]ServerMessage
|
||||
firstSegDone bool
|
||||
startTime int
|
||||
}
|
||||
|
||||
func NewFbsConn(filename string, encs []Encoding) (*FbsConn, error) {
|
||||
|
||||
fbs, err := NewFbsReader(filename)
|
||||
if err != nil {
|
||||
logger.Error("failed to open fbs reader:", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
//NewFbsReader("/Users/amitbet/vncRec/recording.rbs")
|
||||
initMsg, err := fbs.ReadStartSession()
|
||||
if err != nil {
|
||||
logger.Error("failed to open read fbs start session:", err)
|
||||
return nil, err
|
||||
}
|
||||
fbsConn := &FbsConn{FbsReader: *fbs}
|
||||
fbsConn.encodings = encs
|
||||
fbsConn.SetPixelFormat(initMsg.PixelFormat)
|
||||
fbsConn.SetHeight(initMsg.FBHeight)
|
||||
fbsConn.SetWidth(initMsg.FBWidth)
|
||||
fbsConn.SetDesktopName([]byte(initMsg.NameText))
|
||||
|
||||
return fbsConn, nil
|
||||
}
|
||||
|
||||
func NewFBSPlayHelper(r *FbsConn) *FBSPlayHelper {
|
||||
h := &FBSPlayHelper{Conn: r}
|
||||
h.startTime = int(time.Now().UnixNano() / int64(time.Millisecond))
|
||||
|
||||
h.serverMessageMap = make(map[uint8]ServerMessage)
|
||||
h.serverMessageMap[0] = &FramebufferUpdate{}
|
||||
h.serverMessageMap[1] = &SetColorMapEntries{}
|
||||
h.serverMessageMap[2] = &Bell{}
|
||||
h.serverMessageMap[3] = &ServerCutText{}
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
// func (handler *FBSPlayHelper) Consume(seg *RfbSegment) error {
|
||||
|
||||
// switch seg.SegmentType {
|
||||
// case SegmentFullyParsedClientMessage:
|
||||
// clientMsg := seg.Message.(ClientMessage)
|
||||
// logger.Debugf("ClientUpdater.Consume:(vnc-server-bound) got ClientMessage type=%s", clientMsg.Type())
|
||||
// switch clientMsg.Type() {
|
||||
|
||||
// case FramebufferUpdateRequestMsgType:
|
||||
// if !handler.firstSegDone {
|
||||
// handler.firstSegDone = true
|
||||
// handler.startTime = int(time.Now().UnixNano() / int64(time.Millisecond))
|
||||
// }
|
||||
// handler.sendFbsMessage()
|
||||
// }
|
||||
// // server.MsgFramebufferUpdateRequest:
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
func (h *FBSPlayHelper) ReadFbsMessage() ServerMessage {
|
||||
var messageType uint8
|
||||
//messages := make(map[uint8]ServerMessage)
|
||||
fbs := h.Conn
|
||||
//conn := h.Conn
|
||||
err := binary.Read(fbs, binary.BigEndian, &messageType)
|
||||
if err != nil {
|
||||
logger.Error("TestServer.NewConnHandler: Error in reading FBS: ", err)
|
||||
return nil
|
||||
}
|
||||
//IClientConn{}
|
||||
//binary.Write(h.Conn, binary.BigEndian, messageType)
|
||||
msg := h.serverMessageMap[messageType]
|
||||
if msg == nil {
|
||||
logger.Error("TestServer.NewConnHandler: Error unknown message type: ", messageType)
|
||||
return nil
|
||||
}
|
||||
//read the actual message data
|
||||
//err = binary.Read(fbs, binary.BigEndian, &msg)
|
||||
parsedMsg, err := msg.Read(fbs)
|
||||
if err != nil {
|
||||
logger.Error("TestServer.NewConnHandler: Error in reading FBS message: ", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
timeSinceStart := int(time.Now().UnixNano()/int64(time.Millisecond)) - h.startTime
|
||||
timeToSleep := fbs.CurrentTimestamp() - timeSinceStart
|
||||
if timeToSleep > 0 {
|
||||
time.Sleep(time.Duration(timeToSleep) * time.Millisecond)
|
||||
}
|
||||
|
||||
return parsedMsg
|
||||
}
|
||||
|
380
fbs-reader.go
380
fbs-reader.go
@ -1,190 +1,190 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"os"
|
||||
//"vncproxy/common"
|
||||
//"vncproxy/encodings"
|
||||
"vnc2webm/logger"
|
||||
//"vncproxy/encodings"
|
||||
//"vncproxy/encodings"
|
||||
)
|
||||
|
||||
type FbsReader struct {
|
||||
reader io.ReadCloser
|
||||
buffer bytes.Buffer
|
||||
currentTimestamp int
|
||||
//pixelFormat *PixelFormat
|
||||
//encodings []IEncoding
|
||||
}
|
||||
|
||||
func (fbs *FbsReader) Close() error {
|
||||
return fbs.reader.Close()
|
||||
}
|
||||
|
||||
func (fbs *FbsReader) CurrentTimestamp() int {
|
||||
return fbs.currentTimestamp
|
||||
}
|
||||
|
||||
func (fbs *FbsReader) Read(p []byte) (n int, err error) {
|
||||
if fbs.buffer.Len() < len(p) {
|
||||
seg, err := fbs.ReadSegment()
|
||||
|
||||
if err != nil {
|
||||
logger.Error("FBSReader.Read: error reading FBSsegment: ", err)
|
||||
return 0, err
|
||||
}
|
||||
fbs.buffer.Write(seg.bytes)
|
||||
fbs.currentTimestamp = int(seg.timestamp)
|
||||
}
|
||||
return fbs.buffer.Read(p)
|
||||
}
|
||||
|
||||
//func (fbs *FbsReader) CurrentPixelFormat() *PixelFormat { return fbs.pixelFormat }
|
||||
//func (fbs *FbsReader) CurrentColorMap() *common.ColorMap { return &common.ColorMap{} }
|
||||
//func (fbs *FbsReader) Encodings() []IEncoding { return fbs.encodings }
|
||||
|
||||
func NewFbsReader(fbsFile string) (*FbsReader, error) {
|
||||
|
||||
reader, err := os.OpenFile(fbsFile, os.O_RDONLY, 0644)
|
||||
if err != nil {
|
||||
logger.Error("NewFbsReader: can't open fbs file: ", fbsFile)
|
||||
return nil, err
|
||||
}
|
||||
return &FbsReader{reader: reader}, //encodings: []IEncoding{
|
||||
// //&encodings.CopyRectEncoding{},
|
||||
// //&encodings.ZLibEncoding{},
|
||||
// //&encodings.ZRLEEncoding{},
|
||||
// //&encodings.CoRREEncoding{},
|
||||
// //&encodings.HextileEncoding{},
|
||||
// &TightEncoding{},
|
||||
// //&TightPngEncoding{},
|
||||
// //&EncCursorPseudo{},
|
||||
// &RawEncoding{},
|
||||
// //&encodings.RREEncoding{},
|
||||
//},
|
||||
nil
|
||||
|
||||
}
|
||||
|
||||
func (fbs *FbsReader) ReadStartSession() (*ServerInit, error) {
|
||||
|
||||
initMsg := ServerInit{}
|
||||
reader := fbs.reader
|
||||
|
||||
var framebufferWidth uint16
|
||||
var framebufferHeight uint16
|
||||
var SecTypeNone uint32
|
||||
//read rfb header information (the only part done without the [size|data|timestamp] block wrapper)
|
||||
//.("FBS 001.000\n")
|
||||
bytes := make([]byte, 12)
|
||||
_, err := reader.Read(bytes)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init message - FBS file Version:", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//read the version message into the buffer, it is written in the first fbs block
|
||||
//RFB 003.008\n
|
||||
bytes = make([]byte, 12)
|
||||
_, err = fbs.Read(bytes)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - RFB Version: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//push sec type and fb dimensions
|
||||
binary.Read(fbs, binary.BigEndian, &SecTypeNone)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - SecType: ", err)
|
||||
}
|
||||
|
||||
//read frame buffer width, height
|
||||
binary.Read(fbs, binary.BigEndian, &framebufferWidth)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - FBWidth: ", err)
|
||||
return nil, err
|
||||
}
|
||||
initMsg.FBWidth = framebufferWidth
|
||||
|
||||
binary.Read(fbs, binary.BigEndian, &framebufferHeight)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - FBHeight: ", err)
|
||||
return nil, err
|
||||
}
|
||||
initMsg.FBHeight = framebufferHeight
|
||||
|
||||
//read pixel format
|
||||
pixelFormat := &PixelFormat{}
|
||||
binary.Read(fbs, binary.BigEndian, pixelFormat)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - Pixelformat: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
initMsg.PixelFormat = *pixelFormat
|
||||
|
||||
//read desktop name
|
||||
var desknameLen uint32
|
||||
binary.Read(fbs, binary.BigEndian, &desknameLen)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - deskname Len: ", err)
|
||||
return nil, err
|
||||
}
|
||||
initMsg.NameLength = desknameLen
|
||||
|
||||
bytes = make([]byte, desknameLen)
|
||||
fbs.Read(bytes)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - desktopName: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
initMsg.NameText = bytes
|
||||
|
||||
return &initMsg, nil
|
||||
}
|
||||
|
||||
func (fbs *FbsReader) ReadSegment() (*FbsSegment, error) {
|
||||
reader := fbs.reader
|
||||
var bytesLen uint32
|
||||
|
||||
//read length
|
||||
err := binary.Read(reader, binary.BigEndian, &bytesLen)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: read len, error reading rbs file: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
paddedSize := (bytesLen + 3) & 0x7FFFFFFC
|
||||
|
||||
//read bytes
|
||||
bytes := make([]byte, paddedSize)
|
||||
_, err = reader.Read(bytes)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadSegment: read bytes, error reading rbs file: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//remove padding
|
||||
actualBytes := bytes[:bytesLen]
|
||||
|
||||
//read timestamp
|
||||
var timeSinceStart uint32
|
||||
binary.Read(reader, binary.BigEndian, &timeSinceStart)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadSegment: read timestamp, error reading rbs file: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//timeStamp := time.Unix(timeSinceStart, 0)
|
||||
seg := &FbsSegment{bytes: actualBytes, timestamp: timeSinceStart}
|
||||
return seg, nil
|
||||
}
|
||||
|
||||
type FbsSegment struct {
|
||||
bytes []byte
|
||||
timestamp uint32
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"os"
|
||||
//"vncproxy/common"
|
||||
//"vncproxy/encodings"
|
||||
"vnc2video/logger"
|
||||
//"vncproxy/encodings"
|
||||
//"vncproxy/encodings"
|
||||
)
|
||||
|
||||
type FbsReader struct {
|
||||
reader io.ReadCloser
|
||||
buffer bytes.Buffer
|
||||
currentTimestamp int
|
||||
//pixelFormat *PixelFormat
|
||||
//encodings []IEncoding
|
||||
}
|
||||
|
||||
func (fbs *FbsReader) Close() error {
|
||||
return fbs.reader.Close()
|
||||
}
|
||||
|
||||
func (fbs *FbsReader) CurrentTimestamp() int {
|
||||
return fbs.currentTimestamp
|
||||
}
|
||||
|
||||
func (fbs *FbsReader) Read(p []byte) (n int, err error) {
|
||||
if fbs.buffer.Len() < len(p) {
|
||||
seg, err := fbs.ReadSegment()
|
||||
|
||||
if err != nil {
|
||||
logger.Error("FBSReader.Read: error reading FBSsegment: ", err)
|
||||
return 0, err
|
||||
}
|
||||
fbs.buffer.Write(seg.bytes)
|
||||
fbs.currentTimestamp = int(seg.timestamp)
|
||||
}
|
||||
return fbs.buffer.Read(p)
|
||||
}
|
||||
|
||||
//func (fbs *FbsReader) CurrentPixelFormat() *PixelFormat { return fbs.pixelFormat }
|
||||
//func (fbs *FbsReader) CurrentColorMap() *common.ColorMap { return &common.ColorMap{} }
|
||||
//func (fbs *FbsReader) Encodings() []IEncoding { return fbs.encodings }
|
||||
|
||||
func NewFbsReader(fbsFile string) (*FbsReader, error) {
|
||||
|
||||
reader, err := os.OpenFile(fbsFile, os.O_RDONLY, 0644)
|
||||
if err != nil {
|
||||
logger.Error("NewFbsReader: can't open fbs file: ", fbsFile)
|
||||
return nil, err
|
||||
}
|
||||
return &FbsReader{reader: reader}, //encodings: []IEncoding{
|
||||
// //&encodings.CopyRectEncoding{},
|
||||
// //&encodings.ZLibEncoding{},
|
||||
// //&encodings.ZRLEEncoding{},
|
||||
// //&encodings.CoRREEncoding{},
|
||||
// //&encodings.HextileEncoding{},
|
||||
// &TightEncoding{},
|
||||
// //&TightPngEncoding{},
|
||||
// //&EncCursorPseudo{},
|
||||
// &RawEncoding{},
|
||||
// //&encodings.RREEncoding{},
|
||||
//},
|
||||
nil
|
||||
|
||||
}
|
||||
|
||||
func (fbs *FbsReader) ReadStartSession() (*ServerInit, error) {
|
||||
|
||||
initMsg := ServerInit{}
|
||||
reader := fbs.reader
|
||||
|
||||
var framebufferWidth uint16
|
||||
var framebufferHeight uint16
|
||||
var SecTypeNone uint32
|
||||
//read rfb header information (the only part done without the [size|data|timestamp] block wrapper)
|
||||
//.("FBS 001.000\n")
|
||||
bytes := make([]byte, 12)
|
||||
_, err := reader.Read(bytes)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init message - FBS file Version:", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//read the version message into the buffer, it is written in the first fbs block
|
||||
//RFB 003.008\n
|
||||
bytes = make([]byte, 12)
|
||||
_, err = fbs.Read(bytes)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - RFB Version: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//push sec type and fb dimensions
|
||||
binary.Read(fbs, binary.BigEndian, &SecTypeNone)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - SecType: ", err)
|
||||
}
|
||||
|
||||
//read frame buffer width, height
|
||||
binary.Read(fbs, binary.BigEndian, &framebufferWidth)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - FBWidth: ", err)
|
||||
return nil, err
|
||||
}
|
||||
initMsg.FBWidth = framebufferWidth
|
||||
|
||||
binary.Read(fbs, binary.BigEndian, &framebufferHeight)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - FBHeight: ", err)
|
||||
return nil, err
|
||||
}
|
||||
initMsg.FBHeight = framebufferHeight
|
||||
|
||||
//read pixel format
|
||||
pixelFormat := &PixelFormat{}
|
||||
binary.Read(fbs, binary.BigEndian, pixelFormat)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - Pixelformat: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
initMsg.PixelFormat = *pixelFormat
|
||||
|
||||
//read desktop name
|
||||
var desknameLen uint32
|
||||
binary.Read(fbs, binary.BigEndian, &desknameLen)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - deskname Len: ", err)
|
||||
return nil, err
|
||||
}
|
||||
initMsg.NameLength = desknameLen
|
||||
|
||||
bytes = make([]byte, desknameLen)
|
||||
fbs.Read(bytes)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: error reading rbs init - desktopName: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
initMsg.NameText = bytes
|
||||
|
||||
return &initMsg, nil
|
||||
}
|
||||
|
||||
func (fbs *FbsReader) ReadSegment() (*FbsSegment, error) {
|
||||
reader := fbs.reader
|
||||
var bytesLen uint32
|
||||
|
||||
//read length
|
||||
err := binary.Read(reader, binary.BigEndian, &bytesLen)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadStartSession: read len, error reading rbs file: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
paddedSize := (bytesLen + 3) & 0x7FFFFFFC
|
||||
|
||||
//read bytes
|
||||
bytes := make([]byte, paddedSize)
|
||||
_, err = reader.Read(bytes)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadSegment: read bytes, error reading rbs file: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//remove padding
|
||||
actualBytes := bytes[:bytesLen]
|
||||
|
||||
//read timestamp
|
||||
var timeSinceStart uint32
|
||||
binary.Read(reader, binary.BigEndian, &timeSinceStart)
|
||||
if err != nil {
|
||||
logger.Error("FbsReader.ReadSegment: read timestamp, error reading rbs file: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//timeStamp := time.Unix(timeSinceStart, 0)
|
||||
seg := &FbsSegment{bytes: actualBytes, timestamp: timeSinceStart}
|
||||
return seg, nil
|
||||
}
|
||||
|
||||
type FbsSegment struct {
|
||||
bytes []byte
|
||||
timestamp uint32
|
||||
}
|
||||
|
816
handlers.go
816
handlers.go
@ -1,408 +1,408 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"vnc2webm/logger"
|
||||
)
|
||||
|
||||
// Handler represents handler of handshake
|
||||
type Handler interface {
|
||||
Handle(Conn) error
|
||||
}
|
||||
|
||||
// ProtoVersionLength protocol version length
|
||||
const ProtoVersionLength = 12
|
||||
|
||||
const (
|
||||
// ProtoVersionUnknown unknown version
|
||||
ProtoVersionUnknown = ""
|
||||
// ProtoVersion33 sets if proto 003.003
|
||||
ProtoVersion33 = "RFB 003.003\n"
|
||||
// ProtoVersion38 sets if proto 003.008
|
||||
ProtoVersion38 = "RFB 003.008\n"
|
||||
// ProtoVersion37 sets if proto 003.007
|
||||
ProtoVersion37 = "RFB 003.007\n"
|
||||
)
|
||||
|
||||
// ParseProtoVersion parse protocol version
|
||||
func ParseProtoVersion(pv []byte) (uint, uint, error) {
|
||||
var major, minor uint
|
||||
|
||||
if len(pv) < ProtoVersionLength {
|
||||
return 0, 0, fmt.Errorf("ProtocolVersion message too short (%v < %v)", len(pv), ProtoVersionLength)
|
||||
}
|
||||
|
||||
l, err := fmt.Sscanf(string(pv), "RFB %d.%d\n", &major, &minor)
|
||||
if l != 2 {
|
||||
return 0, 0, fmt.Errorf("error parsing protocol version")
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return major, minor, nil
|
||||
}
|
||||
|
||||
// DefaultClientVersionHandler represents default handler
|
||||
type DefaultClientVersionHandler struct{}
|
||||
|
||||
// Handle provide version handler for client side
|
||||
func (*DefaultClientVersionHandler) Handle(c Conn) error {
|
||||
var version [ProtoVersionLength]byte
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, &version); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
major, minor, err := ParseProtoVersion(version[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pv := ProtoVersionUnknown
|
||||
if major == 3 {
|
||||
if minor >= 8 {
|
||||
pv = ProtoVersion38
|
||||
} else if minor >= 3 {
|
||||
pv = ProtoVersion38
|
||||
}
|
||||
}
|
||||
if pv == ProtoVersionUnknown {
|
||||
return fmt.Errorf("ProtocolVersion handshake failed; unsupported version '%v'", string(version[:]))
|
||||
}
|
||||
c.SetProtoVersion(string(version[:]))
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, []byte(pv)); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// DefaultServerVersionHandler represents default server handler
|
||||
type DefaultServerVersionHandler struct{}
|
||||
|
||||
// Handle provide server version handler
|
||||
func (*DefaultServerVersionHandler) Handle(c Conn) error {
|
||||
var version [ProtoVersionLength]byte
|
||||
if err := binary.Write(c, binary.BigEndian, []byte(ProtoVersion38)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &version); err != nil {
|
||||
return err
|
||||
}
|
||||
major, minor, err := ParseProtoVersion(version[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pv := ProtoVersionUnknown
|
||||
if major == 3 {
|
||||
if minor >= 8 {
|
||||
pv = ProtoVersion38
|
||||
} else if minor >= 3 {
|
||||
pv = ProtoVersion33
|
||||
}
|
||||
}
|
||||
if pv == ProtoVersionUnknown {
|
||||
return fmt.Errorf("ProtocolVersion handshake failed; unsupported version '%v'", string(version[:]))
|
||||
}
|
||||
|
||||
c.SetProtoVersion(pv)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultClientSecurityHandler used for client security handler
|
||||
type DefaultClientSecurityHandler struct{}
|
||||
|
||||
// Handle provide client side security handler
|
||||
func (*DefaultClientSecurityHandler) Handle(c Conn) error {
|
||||
cfg := c.Config().(*ClientConfig)
|
||||
var numSecurityTypes uint8
|
||||
if err := binary.Read(c, binary.BigEndian, &numSecurityTypes); err != nil {
|
||||
return err
|
||||
}
|
||||
secTypes := make([]SecurityType, numSecurityTypes)
|
||||
if err := binary.Read(c, binary.BigEndian, &secTypes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var secType SecurityHandler
|
||||
for _, st := range cfg.SecurityHandlers {
|
||||
for _, sc := range secTypes {
|
||||
if st.Type() == sc {
|
||||
secType = st
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, cfg.SecurityHandlers[0].Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := secType.Auth(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var authCode uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &authCode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Debugf("authenticating, secType: %d, auth code(0=success): %d", secType.Type(), authCode)
|
||||
if authCode == 1 {
|
||||
var reasonLength uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &reasonLength); err != nil {
|
||||
return err
|
||||
}
|
||||
reasonText := make([]byte, reasonLength)
|
||||
if err := binary.Read(c, binary.BigEndian, &reasonText); err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("%s", reasonText)
|
||||
}
|
||||
c.SetSecurityHandler(secType)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultServerSecurityHandler used for server security handler
|
||||
type DefaultServerSecurityHandler struct{}
|
||||
|
||||
// Handle provide server side security handler
|
||||
func (*DefaultServerSecurityHandler) Handle(c Conn) error {
|
||||
cfg := c.Config().(*ServerConfig)
|
||||
var secType SecurityType
|
||||
if c.Protocol() == ProtoVersion37 || c.Protocol() == ProtoVersion38 {
|
||||
if err := binary.Write(c, binary.BigEndian, uint8(len(cfg.SecurityHandlers))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, sectype := range cfg.SecurityHandlers {
|
||||
if err := binary.Write(c, binary.BigEndian, sectype.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
st := uint32(0)
|
||||
for _, sectype := range cfg.SecurityHandlers {
|
||||
if uint32(sectype.Type()) > st {
|
||||
st = uint32(sectype.Type())
|
||||
secType = sectype.Type()
|
||||
}
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, st); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Protocol() == ProtoVersion38 {
|
||||
if err := binary.Read(c, binary.BigEndian, &secType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
secTypes := make(map[SecurityType]SecurityHandler)
|
||||
for _, sType := range cfg.SecurityHandlers {
|
||||
secTypes[sType.Type()] = sType
|
||||
}
|
||||
|
||||
sType, ok := secTypes[secType]
|
||||
if !ok {
|
||||
return fmt.Errorf("security type %d not implemented", secType)
|
||||
}
|
||||
|
||||
var authCode uint32
|
||||
authErr := sType.Auth(c)
|
||||
if authErr != nil {
|
||||
authCode = uint32(1)
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, authCode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if authErr == nil {
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.SetSecurityHandler(sType)
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.Protocol() == ProtoVersion38 {
|
||||
if err := binary.Write(c, binary.BigEndian, uint32(len(authErr.Error()))); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, []byte(authErr.Error())); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return authErr
|
||||
}
|
||||
|
||||
// DefaultClientServerInitHandler default client server init handler
|
||||
type DefaultClientServerInitHandler struct{}
|
||||
|
||||
// Handle provide default server init handler
|
||||
func (*DefaultClientServerInitHandler) Handle(c Conn) error {
|
||||
logger.Debug("starting DefaultClientServerInitHandler")
|
||||
var err error
|
||||
srvInit := ServerInit{}
|
||||
|
||||
if err = binary.Read(c, binary.BigEndian, &srvInit.FBWidth); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &srvInit.FBHeight); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &srvInit.PixelFormat); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &srvInit.NameLength); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
srvInit.NameText = make([]byte, srvInit.NameLength)
|
||||
if err = binary.Read(c, binary.BigEndian, &srvInit.NameText); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Debugf("DefaultClientServerInitHandler got serverInit: %v", srvInit)
|
||||
c.SetDesktopName(srvInit.NameText)
|
||||
if c.Protocol() == "aten1" {
|
||||
c.SetWidth(800)
|
||||
c.SetHeight(600)
|
||||
c.SetPixelFormat(NewPixelFormatAten())
|
||||
} else {
|
||||
c.SetWidth(srvInit.FBWidth)
|
||||
c.SetHeight(srvInit.FBHeight)
|
||||
|
||||
//telling the server to use 32bit pixels (with 24 dept, tight standard format)
|
||||
pixelMsg:=SetPixelFormat{PF: PixelFormat32bit}
|
||||
pixelMsg.Write(c)
|
||||
c.SetPixelFormat(PixelFormat32bit)
|
||||
//c.SetPixelFormat(srvInit.PixelFormat)
|
||||
}
|
||||
if c.Protocol() == "aten1" {
|
||||
ikvm := struct {
|
||||
_ [8]byte
|
||||
IKVMVideoEnable uint8
|
||||
IKVMKMEnable uint8
|
||||
IKVMKickEnable uint8
|
||||
VUSBEnable uint8
|
||||
}{}
|
||||
if err = binary.Read(c, binary.BigEndian, &ikvm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
/*
|
||||
caps := struct {
|
||||
ServerMessagesNum uint16
|
||||
ClientMessagesNum uint16
|
||||
EncodingsNum uint16
|
||||
_ [2]byte
|
||||
}{}
|
||||
if err := binary.Read(c, binary.BigEndian, &caps); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
caps.ServerMessagesNum = uint16(1)
|
||||
var item [16]byte
|
||||
for i := uint16(0); i < caps.ServerMessagesNum; i++ {
|
||||
if err := binary.Read(c, binary.BigEndian, &item); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("server message cap %s\n", item)
|
||||
}
|
||||
|
||||
for i := uint16(0); i < caps.ClientMessagesNum; i++ {
|
||||
if err := binary.Read(c, binary.BigEndian, &item); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("client message cap %s\n", item)
|
||||
}
|
||||
for i := uint16(0); i < caps.EncodingsNum; i++ {
|
||||
if err := binary.Read(c, binary.BigEndian, &item); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("encoding cap %s\n", item)
|
||||
}
|
||||
// var pad [1]byte
|
||||
// if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
// return err
|
||||
// }
|
||||
}*/
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultServerServerInitHandler default server server init handler
|
||||
type DefaultServerServerInitHandler struct{}
|
||||
|
||||
// Handle provide default server server init handler
|
||||
func (*DefaultServerServerInitHandler) Handle(c Conn) error {
|
||||
if err := binary.Write(c, binary.BigEndian, c.Width()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, c.Height()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, c.PixelFormat()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, uint32(len(c.DesktopName()))); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, []byte(c.DesktopName())); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// DefaultClientClientInitHandler default client client init handler
|
||||
type DefaultClientClientInitHandler struct{}
|
||||
|
||||
// Handle provide default client client init handler
|
||||
func (*DefaultClientClientInitHandler) Handle(c Conn) error {
|
||||
logger.Debug("starting DefaultClientClientInitHandler")
|
||||
cfg := c.Config().(*ClientConfig)
|
||||
var shared uint8
|
||||
if cfg.Exclusive {
|
||||
shared = 0
|
||||
} else {
|
||||
shared = 1
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, shared); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Debugf("DefaultClientClientInitHandler sending: shared=%d", shared)
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// DefaultServerClientInitHandler default server client init handler
|
||||
type DefaultServerClientInitHandler struct{}
|
||||
|
||||
// Handle provide default server client init handler
|
||||
func (*DefaultServerClientInitHandler) Handle(c Conn) error {
|
||||
var shared uint8
|
||||
if err := binary.Read(c, binary.BigEndian, &shared); err != nil {
|
||||
return err
|
||||
}
|
||||
/* TODO
|
||||
if shared != 1 {
|
||||
c.SetShared(false)
|
||||
}
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"vnc2video/logger"
|
||||
)
|
||||
|
||||
// Handler represents handler of handshake
|
||||
type Handler interface {
|
||||
Handle(Conn) error
|
||||
}
|
||||
|
||||
// ProtoVersionLength protocol version length
|
||||
const ProtoVersionLength = 12
|
||||
|
||||
const (
|
||||
// ProtoVersionUnknown unknown version
|
||||
ProtoVersionUnknown = ""
|
||||
// ProtoVersion33 sets if proto 003.003
|
||||
ProtoVersion33 = "RFB 003.003\n"
|
||||
// ProtoVersion38 sets if proto 003.008
|
||||
ProtoVersion38 = "RFB 003.008\n"
|
||||
// ProtoVersion37 sets if proto 003.007
|
||||
ProtoVersion37 = "RFB 003.007\n"
|
||||
)
|
||||
|
||||
// ParseProtoVersion parse protocol version
|
||||
func ParseProtoVersion(pv []byte) (uint, uint, error) {
|
||||
var major, minor uint
|
||||
|
||||
if len(pv) < ProtoVersionLength {
|
||||
return 0, 0, fmt.Errorf("ProtocolVersion message too short (%v < %v)", len(pv), ProtoVersionLength)
|
||||
}
|
||||
|
||||
l, err := fmt.Sscanf(string(pv), "RFB %d.%d\n", &major, &minor)
|
||||
if l != 2 {
|
||||
return 0, 0, fmt.Errorf("error parsing protocol version")
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return major, minor, nil
|
||||
}
|
||||
|
||||
// DefaultClientVersionHandler represents default handler
|
||||
type DefaultClientVersionHandler struct{}
|
||||
|
||||
// Handle provide version handler for client side
|
||||
func (*DefaultClientVersionHandler) Handle(c Conn) error {
|
||||
var version [ProtoVersionLength]byte
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, &version); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
major, minor, err := ParseProtoVersion(version[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pv := ProtoVersionUnknown
|
||||
if major == 3 {
|
||||
if minor >= 8 {
|
||||
pv = ProtoVersion38
|
||||
} else if minor >= 3 {
|
||||
pv = ProtoVersion38
|
||||
}
|
||||
}
|
||||
if pv == ProtoVersionUnknown {
|
||||
return fmt.Errorf("ProtocolVersion handshake failed; unsupported version '%v'", string(version[:]))
|
||||
}
|
||||
c.SetProtoVersion(string(version[:]))
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, []byte(pv)); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// DefaultServerVersionHandler represents default server handler
|
||||
type DefaultServerVersionHandler struct{}
|
||||
|
||||
// Handle provide server version handler
|
||||
func (*DefaultServerVersionHandler) Handle(c Conn) error {
|
||||
var version [ProtoVersionLength]byte
|
||||
if err := binary.Write(c, binary.BigEndian, []byte(ProtoVersion38)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &version); err != nil {
|
||||
return err
|
||||
}
|
||||
major, minor, err := ParseProtoVersion(version[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pv := ProtoVersionUnknown
|
||||
if major == 3 {
|
||||
if minor >= 8 {
|
||||
pv = ProtoVersion38
|
||||
} else if minor >= 3 {
|
||||
pv = ProtoVersion33
|
||||
}
|
||||
}
|
||||
if pv == ProtoVersionUnknown {
|
||||
return fmt.Errorf("ProtocolVersion handshake failed; unsupported version '%v'", string(version[:]))
|
||||
}
|
||||
|
||||
c.SetProtoVersion(pv)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultClientSecurityHandler used for client security handler
|
||||
type DefaultClientSecurityHandler struct{}
|
||||
|
||||
// Handle provide client side security handler
|
||||
func (*DefaultClientSecurityHandler) Handle(c Conn) error {
|
||||
cfg := c.Config().(*ClientConfig)
|
||||
var numSecurityTypes uint8
|
||||
if err := binary.Read(c, binary.BigEndian, &numSecurityTypes); err != nil {
|
||||
return err
|
||||
}
|
||||
secTypes := make([]SecurityType, numSecurityTypes)
|
||||
if err := binary.Read(c, binary.BigEndian, &secTypes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var secType SecurityHandler
|
||||
for _, st := range cfg.SecurityHandlers {
|
||||
for _, sc := range secTypes {
|
||||
if st.Type() == sc {
|
||||
secType = st
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, cfg.SecurityHandlers[0].Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := secType.Auth(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var authCode uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &authCode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Debugf("authenticating, secType: %d, auth code(0=success): %d", secType.Type(), authCode)
|
||||
if authCode == 1 {
|
||||
var reasonLength uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &reasonLength); err != nil {
|
||||
return err
|
||||
}
|
||||
reasonText := make([]byte, reasonLength)
|
||||
if err := binary.Read(c, binary.BigEndian, &reasonText); err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("%s", reasonText)
|
||||
}
|
||||
c.SetSecurityHandler(secType)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultServerSecurityHandler used for server security handler
|
||||
type DefaultServerSecurityHandler struct{}
|
||||
|
||||
// Handle provide server side security handler
|
||||
func (*DefaultServerSecurityHandler) Handle(c Conn) error {
|
||||
cfg := c.Config().(*ServerConfig)
|
||||
var secType SecurityType
|
||||
if c.Protocol() == ProtoVersion37 || c.Protocol() == ProtoVersion38 {
|
||||
if err := binary.Write(c, binary.BigEndian, uint8(len(cfg.SecurityHandlers))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, sectype := range cfg.SecurityHandlers {
|
||||
if err := binary.Write(c, binary.BigEndian, sectype.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
st := uint32(0)
|
||||
for _, sectype := range cfg.SecurityHandlers {
|
||||
if uint32(sectype.Type()) > st {
|
||||
st = uint32(sectype.Type())
|
||||
secType = sectype.Type()
|
||||
}
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, st); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Protocol() == ProtoVersion38 {
|
||||
if err := binary.Read(c, binary.BigEndian, &secType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
secTypes := make(map[SecurityType]SecurityHandler)
|
||||
for _, sType := range cfg.SecurityHandlers {
|
||||
secTypes[sType.Type()] = sType
|
||||
}
|
||||
|
||||
sType, ok := secTypes[secType]
|
||||
if !ok {
|
||||
return fmt.Errorf("security type %d not implemented", secType)
|
||||
}
|
||||
|
||||
var authCode uint32
|
||||
authErr := sType.Auth(c)
|
||||
if authErr != nil {
|
||||
authCode = uint32(1)
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, authCode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if authErr == nil {
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.SetSecurityHandler(sType)
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.Protocol() == ProtoVersion38 {
|
||||
if err := binary.Write(c, binary.BigEndian, uint32(len(authErr.Error()))); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, []byte(authErr.Error())); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return authErr
|
||||
}
|
||||
|
||||
// DefaultClientServerInitHandler default client server init handler
|
||||
type DefaultClientServerInitHandler struct{}
|
||||
|
||||
// Handle provide default server init handler
|
||||
func (*DefaultClientServerInitHandler) Handle(c Conn) error {
|
||||
logger.Debug("starting DefaultClientServerInitHandler")
|
||||
var err error
|
||||
srvInit := ServerInit{}
|
||||
|
||||
if err = binary.Read(c, binary.BigEndian, &srvInit.FBWidth); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &srvInit.FBHeight); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &srvInit.PixelFormat); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &srvInit.NameLength); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
srvInit.NameText = make([]byte, srvInit.NameLength)
|
||||
if err = binary.Read(c, binary.BigEndian, &srvInit.NameText); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Debugf("DefaultClientServerInitHandler got serverInit: %v", srvInit)
|
||||
c.SetDesktopName(srvInit.NameText)
|
||||
if c.Protocol() == "aten1" {
|
||||
c.SetWidth(800)
|
||||
c.SetHeight(600)
|
||||
c.SetPixelFormat(NewPixelFormatAten())
|
||||
} else {
|
||||
c.SetWidth(srvInit.FBWidth)
|
||||
c.SetHeight(srvInit.FBHeight)
|
||||
|
||||
//telling the server to use 32bit pixels (with 24 dept, tight standard format)
|
||||
pixelMsg:=SetPixelFormat{PF: PixelFormat32bit}
|
||||
pixelMsg.Write(c)
|
||||
c.SetPixelFormat(PixelFormat32bit)
|
||||
//c.SetPixelFormat(srvInit.PixelFormat)
|
||||
}
|
||||
if c.Protocol() == "aten1" {
|
||||
ikvm := struct {
|
||||
_ [8]byte
|
||||
IKVMVideoEnable uint8
|
||||
IKVMKMEnable uint8
|
||||
IKVMKickEnable uint8
|
||||
VUSBEnable uint8
|
||||
}{}
|
||||
if err = binary.Read(c, binary.BigEndian, &ikvm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
/*
|
||||
caps := struct {
|
||||
ServerMessagesNum uint16
|
||||
ClientMessagesNum uint16
|
||||
EncodingsNum uint16
|
||||
_ [2]byte
|
||||
}{}
|
||||
if err := binary.Read(c, binary.BigEndian, &caps); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
caps.ServerMessagesNum = uint16(1)
|
||||
var item [16]byte
|
||||
for i := uint16(0); i < caps.ServerMessagesNum; i++ {
|
||||
if err := binary.Read(c, binary.BigEndian, &item); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("server message cap %s\n", item)
|
||||
}
|
||||
|
||||
for i := uint16(0); i < caps.ClientMessagesNum; i++ {
|
||||
if err := binary.Read(c, binary.BigEndian, &item); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("client message cap %s\n", item)
|
||||
}
|
||||
for i := uint16(0); i < caps.EncodingsNum; i++ {
|
||||
if err := binary.Read(c, binary.BigEndian, &item); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("encoding cap %s\n", item)
|
||||
}
|
||||
// var pad [1]byte
|
||||
// if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
// return err
|
||||
// }
|
||||
}*/
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultServerServerInitHandler default server server init handler
|
||||
type DefaultServerServerInitHandler struct{}
|
||||
|
||||
// Handle provide default server server init handler
|
||||
func (*DefaultServerServerInitHandler) Handle(c Conn) error {
|
||||
if err := binary.Write(c, binary.BigEndian, c.Width()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, c.Height()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, c.PixelFormat()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, uint32(len(c.DesktopName()))); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, []byte(c.DesktopName())); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// DefaultClientClientInitHandler default client client init handler
|
||||
type DefaultClientClientInitHandler struct{}
|
||||
|
||||
// Handle provide default client client init handler
|
||||
func (*DefaultClientClientInitHandler) Handle(c Conn) error {
|
||||
logger.Debug("starting DefaultClientClientInitHandler")
|
||||
cfg := c.Config().(*ClientConfig)
|
||||
var shared uint8
|
||||
if cfg.Exclusive {
|
||||
shared = 0
|
||||
} else {
|
||||
shared = 1
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, shared); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Debugf("DefaultClientClientInitHandler sending: shared=%d", shared)
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// DefaultServerClientInitHandler default server client init handler
|
||||
type DefaultServerClientInitHandler struct{}
|
||||
|
||||
// Handle provide default server client init handler
|
||||
func (*DefaultServerClientInitHandler) Handle(c Conn) error {
|
||||
var shared uint8
|
||||
if err := binary.Read(c, binary.BigEndian, &shared); err != nil {
|
||||
return err
|
||||
}
|
||||
/* TODO
|
||||
if shared != 1 {
|
||||
c.SetShared(false)
|
||||
}
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
|
404
image.go
404
image.go
@ -1,202 +1,202 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"image"
|
||||
)
|
||||
|
||||
//var _ draw.Drawer = (*ServerConn)(nil)
|
||||
//var _ draw.Image = (*ServerConn)(nil)
|
||||
|
||||
// Color represents a single color in a color map.
|
||||
type Color struct {
|
||||
pf *PixelFormat
|
||||
cm *ColorMap
|
||||
cmIndex uint32 // Only valid if pf.TrueColor is false.
|
||||
R, G, B uint16
|
||||
}
|
||||
|
||||
// ColorMap represent color map
|
||||
type ColorMap [256]Color
|
||||
|
||||
// NewColor returns a new Color object
|
||||
func NewColor(pf *PixelFormat, cm *ColorMap) *Color {
|
||||
return &Color{
|
||||
pf: pf,
|
||||
cm: cm,
|
||||
}
|
||||
}
|
||||
|
||||
// Rectangle represents a rectangle of pixel data
|
||||
type Rectangle struct {
|
||||
X, Y uint16
|
||||
Width, Height uint16
|
||||
EncType EncodingType
|
||||
Enc Encoding
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (rect *Rectangle) String() string {
|
||||
return fmt.Sprintf("rect x: %d, y: %d, width: %d, height: %d, enc: %s", rect.X, rect.Y, rect.Width, rect.Height, rect.EncType)
|
||||
}
|
||||
|
||||
// NewRectangle returns new rectangle
|
||||
func NewRectangle() *Rectangle {
|
||||
return &Rectangle{}
|
||||
}
|
||||
|
||||
// Write marshal color to conn
|
||||
func (clr *Color) Write(c Conn) error {
|
||||
var err error
|
||||
pf := c.PixelFormat()
|
||||
order := pf.order()
|
||||
pixel := clr.cmIndex
|
||||
if clr.pf.TrueColor != 0 {
|
||||
pixel = uint32(clr.R) << pf.RedShift
|
||||
pixel |= uint32(clr.G) << pf.GreenShift
|
||||
pixel |= uint32(clr.B) << pf.BlueShift
|
||||
}
|
||||
|
||||
switch pf.BPP {
|
||||
case 8:
|
||||
err = binary.Write(c, order, byte(pixel))
|
||||
case 16:
|
||||
err = binary.Write(c, order, uint16(pixel))
|
||||
case 32:
|
||||
err = binary.Write(c, order, uint32(pixel))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Read unmarshal color from conn
|
||||
func (clr *Color) Read(c Conn) error {
|
||||
order := clr.pf.order()
|
||||
var pixel uint32
|
||||
|
||||
switch clr.pf.BPP {
|
||||
case 8:
|
||||
var px uint8
|
||||
if err := binary.Read(c, order, &px); err != nil {
|
||||
return err
|
||||
}
|
||||
pixel = uint32(px)
|
||||
case 16:
|
||||
var px uint16
|
||||
if err := binary.Read(c, order, &px); err != nil {
|
||||
return err
|
||||
}
|
||||
pixel = uint32(px)
|
||||
case 32:
|
||||
var px uint32
|
||||
if err := binary.Read(c, order, &px); err != nil {
|
||||
return err
|
||||
}
|
||||
pixel = uint32(px)
|
||||
}
|
||||
|
||||
if clr.pf.TrueColor != 0 {
|
||||
clr.R = uint16((pixel >> clr.pf.RedShift) & uint32(clr.pf.RedMax))
|
||||
clr.G = uint16((pixel >> clr.pf.GreenShift) & uint32(clr.pf.GreenMax))
|
||||
clr.B = uint16((pixel >> clr.pf.BlueShift) & uint32(clr.pf.BlueMax))
|
||||
} else {
|
||||
*clr = clr.cm[pixel]
|
||||
clr.cmIndex = pixel
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func colorsToImage(x, y, width, height uint16, colors []Color) *image.RGBA64 {
|
||||
rect := image.Rect(int(x), int(y), int(x+width), int(y+height))
|
||||
rgba := image.NewRGBA64(rect)
|
||||
a := uint16(1)
|
||||
for i, color := range colors {
|
||||
rgba.Pix[4*i+0] = uint8(color.R >> 8)
|
||||
rgba.Pix[4*i+1] = uint8(color.R)
|
||||
rgba.Pix[4*i+2] = uint8(color.G >> 8)
|
||||
rgba.Pix[4*i+3] = uint8(color.G)
|
||||
rgba.Pix[4*i+4] = uint8(color.B >> 8)
|
||||
rgba.Pix[4*i+5] = uint8(color.B)
|
||||
rgba.Pix[4*i+6] = uint8(a >> 8)
|
||||
rgba.Pix[4*i+7] = uint8(a)
|
||||
}
|
||||
return rgba
|
||||
}
|
||||
|
||||
// Write marshal rectangle to conn
|
||||
func (rect *Rectangle) Write(c Conn) error {
|
||||
var err error
|
||||
|
||||
if err = binary.Write(c, binary.BigEndian, rect.X); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Write(c, binary.BigEndian, rect.Y); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Write(c, binary.BigEndian, rect.Width); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Write(c, binary.BigEndian, rect.Height); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Write(c, binary.BigEndian, rect.EncType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return rect.Enc.Write(c, rect)
|
||||
}
|
||||
|
||||
// Read unmarshal rectangle from conn
|
||||
func (rect *Rectangle) Read(c Conn) error {
|
||||
var err error
|
||||
|
||||
if err = binary.Read(c, binary.BigEndian, &rect.X); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &rect.Y); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &rect.Width); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &rect.Height); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &rect.EncType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch rect.EncType {
|
||||
// case EncCopyRect:
|
||||
// rect.Enc = &CopyRectEncoding{}
|
||||
// case EncTight:
|
||||
// rect.Enc = c.GetEncInstance(rect.EncType)
|
||||
// case EncTightPng:
|
||||
// rect.Enc = &TightPngEncoding{}
|
||||
// case EncRaw:
|
||||
// if strings.HasPrefix(c.Protocol(), "aten") {
|
||||
// rect.Enc = &AtenHermon{}
|
||||
// } else {
|
||||
// rect.Enc = &RawEncoding{}
|
||||
// }
|
||||
case EncDesktopSizePseudo:
|
||||
rect.Enc = &DesktopSizePseudoEncoding{}
|
||||
case EncDesktopNamePseudo:
|
||||
rect.Enc = &DesktopNamePseudoEncoding{}
|
||||
// case EncXCursorPseudo:
|
||||
// rect.Enc = &XCursorPseudoEncoding{}
|
||||
// case EncAtenHermon:
|
||||
// rect.Enc = &AtenHermon{}
|
||||
default:
|
||||
rect.Enc = c.GetEncInstance(rect.EncType)
|
||||
if rect.Enc == nil {
|
||||
return fmt.Errorf("unsupported encoding %s", rect.EncType)
|
||||
}
|
||||
}
|
||||
|
||||
return rect.Enc.Read(c, rect)
|
||||
}
|
||||
|
||||
// Area returns the total area in pixels of the Rectangle
|
||||
func (rect *Rectangle) Area() int { return int(rect.Width) * int(rect.Height) }
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"image"
|
||||
)
|
||||
|
||||
//var _ draw.Drawer = (*ServerConn)(nil)
|
||||
//var _ draw.Image = (*ServerConn)(nil)
|
||||
|
||||
// Color represents a single color in a color map.
|
||||
type Color struct {
|
||||
pf *PixelFormat
|
||||
cm *ColorMap
|
||||
cmIndex uint32 // Only valid if pf.TrueColor is false.
|
||||
R, G, B uint16
|
||||
}
|
||||
|
||||
// ColorMap represent color map
|
||||
type ColorMap [256]Color
|
||||
|
||||
// NewColor returns a new Color object
|
||||
func NewColor(pf *PixelFormat, cm *ColorMap) *Color {
|
||||
return &Color{
|
||||
pf: pf,
|
||||
cm: cm,
|
||||
}
|
||||
}
|
||||
|
||||
// Rectangle represents a rectangle of pixel data
|
||||
type Rectangle struct {
|
||||
X, Y uint16
|
||||
Width, Height uint16
|
||||
EncType EncodingType
|
||||
Enc Encoding
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (rect *Rectangle) String() string {
|
||||
return fmt.Sprintf("rect x: %d, y: %d, width: %d, height: %d, enc: %s", rect.X, rect.Y, rect.Width, rect.Height, rect.EncType)
|
||||
}
|
||||
|
||||
// NewRectangle returns new rectangle
|
||||
func NewRectangle() *Rectangle {
|
||||
return &Rectangle{}
|
||||
}
|
||||
|
||||
// Write marshal color to conn
|
||||
func (clr *Color) Write(c Conn) error {
|
||||
var err error
|
||||
pf := c.PixelFormat()
|
||||
order := pf.order()
|
||||
pixel := clr.cmIndex
|
||||
if clr.pf.TrueColor != 0 {
|
||||
pixel = uint32(clr.R) << pf.RedShift
|
||||
pixel |= uint32(clr.G) << pf.GreenShift
|
||||
pixel |= uint32(clr.B) << pf.BlueShift
|
||||
}
|
||||
|
||||
switch pf.BPP {
|
||||
case 8:
|
||||
err = binary.Write(c, order, byte(pixel))
|
||||
case 16:
|
||||
err = binary.Write(c, order, uint16(pixel))
|
||||
case 32:
|
||||
err = binary.Write(c, order, uint32(pixel))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Read unmarshal color from conn
|
||||
func (clr *Color) Read(c Conn) error {
|
||||
order := clr.pf.order()
|
||||
var pixel uint32
|
||||
|
||||
switch clr.pf.BPP {
|
||||
case 8:
|
||||
var px uint8
|
||||
if err := binary.Read(c, order, &px); err != nil {
|
||||
return err
|
||||
}
|
||||
pixel = uint32(px)
|
||||
case 16:
|
||||
var px uint16
|
||||
if err := binary.Read(c, order, &px); err != nil {
|
||||
return err
|
||||
}
|
||||
pixel = uint32(px)
|
||||
case 32:
|
||||
var px uint32
|
||||
if err := binary.Read(c, order, &px); err != nil {
|
||||
return err
|
||||
}
|
||||
pixel = uint32(px)
|
||||
}
|
||||
|
||||
if clr.pf.TrueColor != 0 {
|
||||
clr.R = uint16((pixel >> clr.pf.RedShift) & uint32(clr.pf.RedMax))
|
||||
clr.G = uint16((pixel >> clr.pf.GreenShift) & uint32(clr.pf.GreenMax))
|
||||
clr.B = uint16((pixel >> clr.pf.BlueShift) & uint32(clr.pf.BlueMax))
|
||||
} else {
|
||||
*clr = clr.cm[pixel]
|
||||
clr.cmIndex = pixel
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func colorsToImage(x, y, width, height uint16, colors []Color) *image.RGBA64 {
|
||||
rect := image.Rect(int(x), int(y), int(x+width), int(y+height))
|
||||
rgba := image.NewRGBA64(rect)
|
||||
a := uint16(1)
|
||||
for i, color := range colors {
|
||||
rgba.Pix[4*i+0] = uint8(color.R >> 8)
|
||||
rgba.Pix[4*i+1] = uint8(color.R)
|
||||
rgba.Pix[4*i+2] = uint8(color.G >> 8)
|
||||
rgba.Pix[4*i+3] = uint8(color.G)
|
||||
rgba.Pix[4*i+4] = uint8(color.B >> 8)
|
||||
rgba.Pix[4*i+5] = uint8(color.B)
|
||||
rgba.Pix[4*i+6] = uint8(a >> 8)
|
||||
rgba.Pix[4*i+7] = uint8(a)
|
||||
}
|
||||
return rgba
|
||||
}
|
||||
|
||||
// Write marshal rectangle to conn
|
||||
func (rect *Rectangle) Write(c Conn) error {
|
||||
var err error
|
||||
|
||||
if err = binary.Write(c, binary.BigEndian, rect.X); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Write(c, binary.BigEndian, rect.Y); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Write(c, binary.BigEndian, rect.Width); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Write(c, binary.BigEndian, rect.Height); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Write(c, binary.BigEndian, rect.EncType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return rect.Enc.Write(c, rect)
|
||||
}
|
||||
|
||||
// Read unmarshal rectangle from conn
|
||||
func (rect *Rectangle) Read(c Conn) error {
|
||||
var err error
|
||||
|
||||
if err = binary.Read(c, binary.BigEndian, &rect.X); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &rect.Y); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &rect.Width); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &rect.Height); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(c, binary.BigEndian, &rect.EncType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch rect.EncType {
|
||||
// case EncCopyRect:
|
||||
// rect.Enc = &CopyRectEncoding{}
|
||||
// case EncTight:
|
||||
// rect.Enc = c.GetEncInstance(rect.EncType)
|
||||
// case EncTightPng:
|
||||
// rect.Enc = &TightPngEncoding{}
|
||||
// case EncRaw:
|
||||
// if strings.HasPrefix(c.Protocol(), "aten") {
|
||||
// rect.Enc = &AtenHermon{}
|
||||
// } else {
|
||||
// rect.Enc = &RawEncoding{}
|
||||
// }
|
||||
case EncDesktopSizePseudo:
|
||||
rect.Enc = &DesktopSizePseudoEncoding{}
|
||||
case EncDesktopNamePseudo:
|
||||
rect.Enc = &DesktopNamePseudoEncoding{}
|
||||
// case EncXCursorPseudo:
|
||||
// rect.Enc = &XCursorPseudoEncoding{}
|
||||
// case EncAtenHermon:
|
||||
// rect.Enc = &AtenHermon{}
|
||||
default:
|
||||
rect.Enc = c.GetEncInstance(rect.EncType)
|
||||
if rect.Enc == nil {
|
||||
return fmt.Errorf("unsupported encoding %s", rect.EncType)
|
||||
}
|
||||
}
|
||||
|
||||
return rect.Enc.Read(c, rect)
|
||||
}
|
||||
|
||||
// Area returns the total area in pixels of the Rectangle
|
||||
func (rect *Rectangle) Area() int { return int(rect.Width) * int(rect.Height) }
|
||||
|
394
key_string.go
394
key_string.go
@ -1,197 +1,197 @@
|
||||
// Code generated by "stringer -type=Key"; DO NOT EDIT.
|
||||
|
||||
package vnc2webm
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _Key_name = "SpaceExclaimQuoteDblNumberSignDollarPercentAmpersandApostropheParenLeftParenRightAsteriskPlusCommaMinusPeriodSlashDigit0Digit1Digit2Digit3Digit4Digit5Digit6Digit7Digit8Digit9ColonSemicolonLessEqualGreaterQuestionAtABCDEFGHIJKLMNOPQRSTUVWXYZBracketLeftBackslashBracketRightAsciiCircumUnderscoreGraveSmallASmallBSmallCSmallDSmallESmallFSmallGSmallHSmallISmallJSmallKSmallLSmallMSmallNSmallOSmallPSmallQSmallRSmallSSmallTSmallUSmallVSmallWSmallXSmallYSmallZBraceLeftBarBraceRightAsciiTildeBackSpaceTabLinefeedClearReturnPauseScrollLockSysReqEscapeHomeLeftUpRightDownPageUpPageDownEndBeginSelectModeSwitchNumLockKeypadSpaceKeypadTabKeypadEnterKeypadF1KeypadF2KeypadF3KeypadF4KeypadHomeKeypadLeftKeypadUpKeypadRightKeypadDownKeypadPriorKeypadPageUpKeypadNextKeypadPageDownKeypadEndKeypadBeginKeypadInsertKeypadDeleteKeypadMultiplyKeypadAddKeypadSeparatorKeypadSubtractKeypadDecimalKeypadDivideKeypad0Keypad1Keypad2Keypad3Keypad4Keypad5Keypad6Keypad7Keypad8Keypad9KeypadEqualF1F2F3F4F5F6F7F8F9F10F11F12ShiftLeftShiftRightControlLeftControlRightCapsLockShiftLockMetaLeftMetaRightAltLeftAltRightSuperLeftSuperRightHyperLeftHyperRightDelete"
|
||||
|
||||
var _Key_map = map[Key]string{
|
||||
32: _Key_name[0:5],
|
||||
33: _Key_name[5:12],
|
||||
34: _Key_name[12:20],
|
||||
35: _Key_name[20:30],
|
||||
36: _Key_name[30:36],
|
||||
37: _Key_name[36:43],
|
||||
38: _Key_name[43:52],
|
||||
39: _Key_name[52:62],
|
||||
40: _Key_name[62:71],
|
||||
41: _Key_name[71:81],
|
||||
42: _Key_name[81:89],
|
||||
43: _Key_name[89:93],
|
||||
44: _Key_name[93:98],
|
||||
45: _Key_name[98:103],
|
||||
46: _Key_name[103:109],
|
||||
47: _Key_name[109:114],
|
||||
48: _Key_name[114:120],
|
||||
49: _Key_name[120:126],
|
||||
50: _Key_name[126:132],
|
||||
51: _Key_name[132:138],
|
||||
52: _Key_name[138:144],
|
||||
53: _Key_name[144:150],
|
||||
54: _Key_name[150:156],
|
||||
55: _Key_name[156:162],
|
||||
56: _Key_name[162:168],
|
||||
57: _Key_name[168:174],
|
||||
58: _Key_name[174:179],
|
||||
59: _Key_name[179:188],
|
||||
60: _Key_name[188:192],
|
||||
61: _Key_name[192:197],
|
||||
62: _Key_name[197:204],
|
||||
63: _Key_name[204:212],
|
||||
64: _Key_name[212:214],
|
||||
65: _Key_name[214:215],
|
||||
66: _Key_name[215:216],
|
||||
67: _Key_name[216:217],
|
||||
68: _Key_name[217:218],
|
||||
69: _Key_name[218:219],
|
||||
70: _Key_name[219:220],
|
||||
71: _Key_name[220:221],
|
||||
72: _Key_name[221:222],
|
||||
73: _Key_name[222:223],
|
||||
74: _Key_name[223:224],
|
||||
75: _Key_name[224:225],
|
||||
76: _Key_name[225:226],
|
||||
77: _Key_name[226:227],
|
||||
78: _Key_name[227:228],
|
||||
79: _Key_name[228:229],
|
||||
80: _Key_name[229:230],
|
||||
81: _Key_name[230:231],
|
||||
82: _Key_name[231:232],
|
||||
83: _Key_name[232:233],
|
||||
84: _Key_name[233:234],
|
||||
85: _Key_name[234:235],
|
||||
86: _Key_name[235:236],
|
||||
87: _Key_name[236:237],
|
||||
88: _Key_name[237:238],
|
||||
89: _Key_name[238:239],
|
||||
90: _Key_name[239:240],
|
||||
91: _Key_name[240:251],
|
||||
92: _Key_name[251:260],
|
||||
93: _Key_name[260:272],
|
||||
94: _Key_name[272:283],
|
||||
95: _Key_name[283:293],
|
||||
96: _Key_name[293:298],
|
||||
97: _Key_name[298:304],
|
||||
98: _Key_name[304:310],
|
||||
99: _Key_name[310:316],
|
||||
100: _Key_name[316:322],
|
||||
101: _Key_name[322:328],
|
||||
102: _Key_name[328:334],
|
||||
103: _Key_name[334:340],
|
||||
104: _Key_name[340:346],
|
||||
105: _Key_name[346:352],
|
||||
106: _Key_name[352:358],
|
||||
107: _Key_name[358:364],
|
||||
108: _Key_name[364:370],
|
||||
109: _Key_name[370:376],
|
||||
110: _Key_name[376:382],
|
||||
111: _Key_name[382:388],
|
||||
112: _Key_name[388:394],
|
||||
113: _Key_name[394:400],
|
||||
114: _Key_name[400:406],
|
||||
115: _Key_name[406:412],
|
||||
116: _Key_name[412:418],
|
||||
117: _Key_name[418:424],
|
||||
118: _Key_name[424:430],
|
||||
119: _Key_name[430:436],
|
||||
120: _Key_name[436:442],
|
||||
121: _Key_name[442:448],
|
||||
122: _Key_name[448:454],
|
||||
123: _Key_name[454:463],
|
||||
124: _Key_name[463:466],
|
||||
125: _Key_name[466:476],
|
||||
126: _Key_name[476:486],
|
||||
65288: _Key_name[486:495],
|
||||
65289: _Key_name[495:498],
|
||||
65290: _Key_name[498:506],
|
||||
65291: _Key_name[506:511],
|
||||
65293: _Key_name[511:517],
|
||||
65299: _Key_name[517:522],
|
||||
65300: _Key_name[522:532],
|
||||
65301: _Key_name[532:538],
|
||||
65307: _Key_name[538:544],
|
||||
65360: _Key_name[544:548],
|
||||
65361: _Key_name[548:552],
|
||||
65362: _Key_name[552:554],
|
||||
65363: _Key_name[554:559],
|
||||
65364: _Key_name[559:563],
|
||||
65365: _Key_name[563:569],
|
||||
65366: _Key_name[569:577],
|
||||
65367: _Key_name[577:580],
|
||||
65368: _Key_name[580:585],
|
||||
65376: _Key_name[585:591],
|
||||
65406: _Key_name[591:601],
|
||||
65407: _Key_name[601:608],
|
||||
65408: _Key_name[608:619],
|
||||
65417: _Key_name[619:628],
|
||||
65421: _Key_name[628:639],
|
||||
65425: _Key_name[639:647],
|
||||
65426: _Key_name[647:655],
|
||||
65427: _Key_name[655:663],
|
||||
65428: _Key_name[663:671],
|
||||
65429: _Key_name[671:681],
|
||||
65430: _Key_name[681:691],
|
||||
65431: _Key_name[691:699],
|
||||
65432: _Key_name[699:710],
|
||||
65433: _Key_name[710:720],
|
||||
65434: _Key_name[720:731],
|
||||
65435: _Key_name[731:743],
|
||||
65436: _Key_name[743:753],
|
||||
65437: _Key_name[753:767],
|
||||
65438: _Key_name[767:776],
|
||||
65439: _Key_name[776:787],
|
||||
65440: _Key_name[787:799],
|
||||
65441: _Key_name[799:811],
|
||||
65442: _Key_name[811:825],
|
||||
65443: _Key_name[825:834],
|
||||
65444: _Key_name[834:849],
|
||||
65445: _Key_name[849:863],
|
||||
65446: _Key_name[863:876],
|
||||
65447: _Key_name[876:888],
|
||||
65448: _Key_name[888:895],
|
||||
65449: _Key_name[895:902],
|
||||
65450: _Key_name[902:909],
|
||||
65451: _Key_name[909:916],
|
||||
65452: _Key_name[916:923],
|
||||
65453: _Key_name[923:930],
|
||||
65454: _Key_name[930:937],
|
||||
65455: _Key_name[937:944],
|
||||
65456: _Key_name[944:951],
|
||||
65457: _Key_name[951:958],
|
||||
65469: _Key_name[958:969],
|
||||
65470: _Key_name[969:971],
|
||||
65471: _Key_name[971:973],
|
||||
65472: _Key_name[973:975],
|
||||
65473: _Key_name[975:977],
|
||||
65474: _Key_name[977:979],
|
||||
65475: _Key_name[979:981],
|
||||
65476: _Key_name[981:983],
|
||||
65477: _Key_name[983:985],
|
||||
65478: _Key_name[985:987],
|
||||
65479: _Key_name[987:990],
|
||||
65480: _Key_name[990:993],
|
||||
65481: _Key_name[993:996],
|
||||
65505: _Key_name[996:1005],
|
||||
65506: _Key_name[1005:1015],
|
||||
65507: _Key_name[1015:1026],
|
||||
65508: _Key_name[1026:1038],
|
||||
65509: _Key_name[1038:1046],
|
||||
65510: _Key_name[1046:1055],
|
||||
65511: _Key_name[1055:1063],
|
||||
65512: _Key_name[1063:1072],
|
||||
65513: _Key_name[1072:1079],
|
||||
65514: _Key_name[1079:1087],
|
||||
65515: _Key_name[1087:1096],
|
||||
65516: _Key_name[1096:1106],
|
||||
65517: _Key_name[1106:1115],
|
||||
65518: _Key_name[1115:1125],
|
||||
65535: _Key_name[1125:1131],
|
||||
}
|
||||
|
||||
func (i Key) String() string {
|
||||
if str, ok := _Key_map[i]; ok {
|
||||
return str
|
||||
}
|
||||
return fmt.Sprintf("Key(%d)", i)
|
||||
}
|
||||
// Code generated by "stringer -type=Key"; DO NOT EDIT.
|
||||
|
||||
package vnc2video
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _Key_name = "SpaceExclaimQuoteDblNumberSignDollarPercentAmpersandApostropheParenLeftParenRightAsteriskPlusCommaMinusPeriodSlashDigit0Digit1Digit2Digit3Digit4Digit5Digit6Digit7Digit8Digit9ColonSemicolonLessEqualGreaterQuestionAtABCDEFGHIJKLMNOPQRSTUVWXYZBracketLeftBackslashBracketRightAsciiCircumUnderscoreGraveSmallASmallBSmallCSmallDSmallESmallFSmallGSmallHSmallISmallJSmallKSmallLSmallMSmallNSmallOSmallPSmallQSmallRSmallSSmallTSmallUSmallVSmallWSmallXSmallYSmallZBraceLeftBarBraceRightAsciiTildeBackSpaceTabLinefeedClearReturnPauseScrollLockSysReqEscapeHomeLeftUpRightDownPageUpPageDownEndBeginSelectModeSwitchNumLockKeypadSpaceKeypadTabKeypadEnterKeypadF1KeypadF2KeypadF3KeypadF4KeypadHomeKeypadLeftKeypadUpKeypadRightKeypadDownKeypadPriorKeypadPageUpKeypadNextKeypadPageDownKeypadEndKeypadBeginKeypadInsertKeypadDeleteKeypadMultiplyKeypadAddKeypadSeparatorKeypadSubtractKeypadDecimalKeypadDivideKeypad0Keypad1Keypad2Keypad3Keypad4Keypad5Keypad6Keypad7Keypad8Keypad9KeypadEqualF1F2F3F4F5F6F7F8F9F10F11F12ShiftLeftShiftRightControlLeftControlRightCapsLockShiftLockMetaLeftMetaRightAltLeftAltRightSuperLeftSuperRightHyperLeftHyperRightDelete"
|
||||
|
||||
var _Key_map = map[Key]string{
|
||||
32: _Key_name[0:5],
|
||||
33: _Key_name[5:12],
|
||||
34: _Key_name[12:20],
|
||||
35: _Key_name[20:30],
|
||||
36: _Key_name[30:36],
|
||||
37: _Key_name[36:43],
|
||||
38: _Key_name[43:52],
|
||||
39: _Key_name[52:62],
|
||||
40: _Key_name[62:71],
|
||||
41: _Key_name[71:81],
|
||||
42: _Key_name[81:89],
|
||||
43: _Key_name[89:93],
|
||||
44: _Key_name[93:98],
|
||||
45: _Key_name[98:103],
|
||||
46: _Key_name[103:109],
|
||||
47: _Key_name[109:114],
|
||||
48: _Key_name[114:120],
|
||||
49: _Key_name[120:126],
|
||||
50: _Key_name[126:132],
|
||||
51: _Key_name[132:138],
|
||||
52: _Key_name[138:144],
|
||||
53: _Key_name[144:150],
|
||||
54: _Key_name[150:156],
|
||||
55: _Key_name[156:162],
|
||||
56: _Key_name[162:168],
|
||||
57: _Key_name[168:174],
|
||||
58: _Key_name[174:179],
|
||||
59: _Key_name[179:188],
|
||||
60: _Key_name[188:192],
|
||||
61: _Key_name[192:197],
|
||||
62: _Key_name[197:204],
|
||||
63: _Key_name[204:212],
|
||||
64: _Key_name[212:214],
|
||||
65: _Key_name[214:215],
|
||||
66: _Key_name[215:216],
|
||||
67: _Key_name[216:217],
|
||||
68: _Key_name[217:218],
|
||||
69: _Key_name[218:219],
|
||||
70: _Key_name[219:220],
|
||||
71: _Key_name[220:221],
|
||||
72: _Key_name[221:222],
|
||||
73: _Key_name[222:223],
|
||||
74: _Key_name[223:224],
|
||||
75: _Key_name[224:225],
|
||||
76: _Key_name[225:226],
|
||||
77: _Key_name[226:227],
|
||||
78: _Key_name[227:228],
|
||||
79: _Key_name[228:229],
|
||||
80: _Key_name[229:230],
|
||||
81: _Key_name[230:231],
|
||||
82: _Key_name[231:232],
|
||||
83: _Key_name[232:233],
|
||||
84: _Key_name[233:234],
|
||||
85: _Key_name[234:235],
|
||||
86: _Key_name[235:236],
|
||||
87: _Key_name[236:237],
|
||||
88: _Key_name[237:238],
|
||||
89: _Key_name[238:239],
|
||||
90: _Key_name[239:240],
|
||||
91: _Key_name[240:251],
|
||||
92: _Key_name[251:260],
|
||||
93: _Key_name[260:272],
|
||||
94: _Key_name[272:283],
|
||||
95: _Key_name[283:293],
|
||||
96: _Key_name[293:298],
|
||||
97: _Key_name[298:304],
|
||||
98: _Key_name[304:310],
|
||||
99: _Key_name[310:316],
|
||||
100: _Key_name[316:322],
|
||||
101: _Key_name[322:328],
|
||||
102: _Key_name[328:334],
|
||||
103: _Key_name[334:340],
|
||||
104: _Key_name[340:346],
|
||||
105: _Key_name[346:352],
|
||||
106: _Key_name[352:358],
|
||||
107: _Key_name[358:364],
|
||||
108: _Key_name[364:370],
|
||||
109: _Key_name[370:376],
|
||||
110: _Key_name[376:382],
|
||||
111: _Key_name[382:388],
|
||||
112: _Key_name[388:394],
|
||||
113: _Key_name[394:400],
|
||||
114: _Key_name[400:406],
|
||||
115: _Key_name[406:412],
|
||||
116: _Key_name[412:418],
|
||||
117: _Key_name[418:424],
|
||||
118: _Key_name[424:430],
|
||||
119: _Key_name[430:436],
|
||||
120: _Key_name[436:442],
|
||||
121: _Key_name[442:448],
|
||||
122: _Key_name[448:454],
|
||||
123: _Key_name[454:463],
|
||||
124: _Key_name[463:466],
|
||||
125: _Key_name[466:476],
|
||||
126: _Key_name[476:486],
|
||||
65288: _Key_name[486:495],
|
||||
65289: _Key_name[495:498],
|
||||
65290: _Key_name[498:506],
|
||||
65291: _Key_name[506:511],
|
||||
65293: _Key_name[511:517],
|
||||
65299: _Key_name[517:522],
|
||||
65300: _Key_name[522:532],
|
||||
65301: _Key_name[532:538],
|
||||
65307: _Key_name[538:544],
|
||||
65360: _Key_name[544:548],
|
||||
65361: _Key_name[548:552],
|
||||
65362: _Key_name[552:554],
|
||||
65363: _Key_name[554:559],
|
||||
65364: _Key_name[559:563],
|
||||
65365: _Key_name[563:569],
|
||||
65366: _Key_name[569:577],
|
||||
65367: _Key_name[577:580],
|
||||
65368: _Key_name[580:585],
|
||||
65376: _Key_name[585:591],
|
||||
65406: _Key_name[591:601],
|
||||
65407: _Key_name[601:608],
|
||||
65408: _Key_name[608:619],
|
||||
65417: _Key_name[619:628],
|
||||
65421: _Key_name[628:639],
|
||||
65425: _Key_name[639:647],
|
||||
65426: _Key_name[647:655],
|
||||
65427: _Key_name[655:663],
|
||||
65428: _Key_name[663:671],
|
||||
65429: _Key_name[671:681],
|
||||
65430: _Key_name[681:691],
|
||||
65431: _Key_name[691:699],
|
||||
65432: _Key_name[699:710],
|
||||
65433: _Key_name[710:720],
|
||||
65434: _Key_name[720:731],
|
||||
65435: _Key_name[731:743],
|
||||
65436: _Key_name[743:753],
|
||||
65437: _Key_name[753:767],
|
||||
65438: _Key_name[767:776],
|
||||
65439: _Key_name[776:787],
|
||||
65440: _Key_name[787:799],
|
||||
65441: _Key_name[799:811],
|
||||
65442: _Key_name[811:825],
|
||||
65443: _Key_name[825:834],
|
||||
65444: _Key_name[834:849],
|
||||
65445: _Key_name[849:863],
|
||||
65446: _Key_name[863:876],
|
||||
65447: _Key_name[876:888],
|
||||
65448: _Key_name[888:895],
|
||||
65449: _Key_name[895:902],
|
||||
65450: _Key_name[902:909],
|
||||
65451: _Key_name[909:916],
|
||||
65452: _Key_name[916:923],
|
||||
65453: _Key_name[923:930],
|
||||
65454: _Key_name[930:937],
|
||||
65455: _Key_name[937:944],
|
||||
65456: _Key_name[944:951],
|
||||
65457: _Key_name[951:958],
|
||||
65469: _Key_name[958:969],
|
||||
65470: _Key_name[969:971],
|
||||
65471: _Key_name[971:973],
|
||||
65472: _Key_name[973:975],
|
||||
65473: _Key_name[975:977],
|
||||
65474: _Key_name[977:979],
|
||||
65475: _Key_name[979:981],
|
||||
65476: _Key_name[981:983],
|
||||
65477: _Key_name[983:985],
|
||||
65478: _Key_name[985:987],
|
||||
65479: _Key_name[987:990],
|
||||
65480: _Key_name[990:993],
|
||||
65481: _Key_name[993:996],
|
||||
65505: _Key_name[996:1005],
|
||||
65506: _Key_name[1005:1015],
|
||||
65507: _Key_name[1015:1026],
|
||||
65508: _Key_name[1026:1038],
|
||||
65509: _Key_name[1038:1046],
|
||||
65510: _Key_name[1046:1055],
|
||||
65511: _Key_name[1055:1063],
|
||||
65512: _Key_name[1063:1072],
|
||||
65513: _Key_name[1072:1079],
|
||||
65514: _Key_name[1079:1087],
|
||||
65515: _Key_name[1087:1096],
|
||||
65516: _Key_name[1096:1106],
|
||||
65517: _Key_name[1106:1115],
|
||||
65518: _Key_name[1115:1125],
|
||||
65535: _Key_name[1125:1131],
|
||||
}
|
||||
|
||||
func (i Key) String() string {
|
||||
if str, ok := _Key_map[i]; ok {
|
||||
return str
|
||||
}
|
||||
return fmt.Sprintf("Key(%d)", i)
|
||||
}
|
||||
|
508
keys.go
508
keys.go
@ -1,254 +1,254 @@
|
||||
package vnc2webm
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Key represents a VNC key press.
|
||||
type Key uint32
|
||||
|
||||
//go:generate stringer -type=Key
|
||||
|
||||
// Keys is a slice of Key values.
|
||||
type Keys []Key
|
||||
|
||||
var keymap = map[rune]Key{
|
||||
'-': Minus,
|
||||
'0': Digit0,
|
||||
'1': Digit1,
|
||||
'2': Digit2,
|
||||
'3': Digit3,
|
||||
'4': Digit4,
|
||||
'5': Digit5,
|
||||
'6': Digit6,
|
||||
'7': Digit7,
|
||||
'8': Digit8,
|
||||
'9': Digit9,
|
||||
}
|
||||
|
||||
// IntToKeys returns Keys that represent the key presses required to type an int.
|
||||
func IntToKeys(v int) Keys {
|
||||
k := Keys{}
|
||||
for _, c := range fmt.Sprintf("%d", v) {
|
||||
k = append(k, keymap[c])
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
// Latin 1 (byte 3 = 0)
|
||||
// ISO/IEC 8859-1 = Unicode U+0020..U+00FF
|
||||
const (
|
||||
Space Key = iota + 0x0020
|
||||
Exclaim // exclamation mark
|
||||
QuoteDbl
|
||||
NumberSign
|
||||
Dollar
|
||||
Percent
|
||||
Ampersand
|
||||
Apostrophe
|
||||
ParenLeft
|
||||
ParenRight
|
||||
Asterisk
|
||||
Plus
|
||||
Comma
|
||||
Minus
|
||||
Period
|
||||
Slash
|
||||
Digit0
|
||||
Digit1
|
||||
Digit2
|
||||
Digit3
|
||||
Digit4
|
||||
Digit5
|
||||
Digit6
|
||||
Digit7
|
||||
Digit8
|
||||
Digit9
|
||||
Colon
|
||||
Semicolon
|
||||
Less
|
||||
Equal
|
||||
Greater
|
||||
Question
|
||||
At
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
BracketLeft
|
||||
Backslash
|
||||
BracketRight
|
||||
AsciiCircum
|
||||
Underscore
|
||||
Grave
|
||||
SmallA
|
||||
SmallB
|
||||
SmallC
|
||||
SmallD
|
||||
SmallE
|
||||
SmallF
|
||||
SmallG
|
||||
SmallH
|
||||
SmallI
|
||||
SmallJ
|
||||
SmallK
|
||||
SmallL
|
||||
SmallM
|
||||
SmallN
|
||||
SmallO
|
||||
SmallP
|
||||
SmallQ
|
||||
SmallR
|
||||
SmallS
|
||||
SmallT
|
||||
SmallU
|
||||
SmallV
|
||||
SmallW
|
||||
SmallX
|
||||
SmallY
|
||||
SmallZ
|
||||
BraceLeft
|
||||
Bar
|
||||
BraceRight
|
||||
AsciiTilde
|
||||
)
|
||||
|
||||
const (
|
||||
BackSpace Key = iota + 0xff08
|
||||
Tab
|
||||
Linefeed
|
||||
Clear
|
||||
_
|
||||
Return
|
||||
)
|
||||
|
||||
const (
|
||||
Pause Key = iota + 0xff13
|
||||
ScrollLock
|
||||
SysReq
|
||||
Escape Key = 0xff1b
|
||||
Delete Key = 0xffff
|
||||
)
|
||||
|
||||
const ( // Cursor control & motion.
|
||||
Home Key = iota + 0xff50
|
||||
Left
|
||||
Up
|
||||
Right
|
||||
Down
|
||||
PageUp
|
||||
PageDown
|
||||
End
|
||||
Begin
|
||||
)
|
||||
|
||||
const ( // Misc functions.
|
||||
Select Key = 0xff60
|
||||
Print
|
||||
Execute
|
||||
Insert
|
||||
Undo
|
||||
Redo
|
||||
Menu
|
||||
Find
|
||||
Cancel
|
||||
Help
|
||||
Break
|
||||
ModeSwitch Key = 0xff7e
|
||||
NumLock Key = 0xff7f
|
||||
)
|
||||
|
||||
const ( // Keypad functions.
|
||||
KeypadSpace Key = 0xff80
|
||||
KeypadTab Key = 0xff89
|
||||
KeypadEnter Key = 0xff8d
|
||||
)
|
||||
|
||||
const ( // Keypad functions cont.
|
||||
KeypadF1 Key = iota + 0xff91
|
||||
KeypadF2
|
||||
KeypadF3
|
||||
KeypadF4
|
||||
KeypadHome
|
||||
KeypadLeft
|
||||
KeypadUp
|
||||
KeypadRight
|
||||
KeypadDown
|
||||
KeypadPrior
|
||||
KeypadPageUp
|
||||
KeypadNext
|
||||
KeypadPageDown
|
||||
KeypadEnd
|
||||
KeypadBegin
|
||||
KeypadInsert
|
||||
KeypadDelete
|
||||
KeypadMultiply
|
||||
KeypadAdd
|
||||
KeypadSeparator
|
||||
KeypadSubtract
|
||||
KeypadDecimal
|
||||
KeypadDivide
|
||||
Keypad0
|
||||
Keypad1
|
||||
Keypad2
|
||||
Keypad3
|
||||
Keypad4
|
||||
Keypad5
|
||||
Keypad6
|
||||
Keypad7
|
||||
Keypad8
|
||||
Keypad9
|
||||
KeypadEqual Key = 0xffbd
|
||||
)
|
||||
|
||||
const (
|
||||
F1 Key = iota + 0xffbe
|
||||
F2
|
||||
F3
|
||||
F4
|
||||
F5
|
||||
F6
|
||||
F7
|
||||
F8
|
||||
F9
|
||||
F10
|
||||
F11
|
||||
F12
|
||||
)
|
||||
|
||||
const (
|
||||
ShiftLeft Key = iota + 0xffe1
|
||||
ShiftRight
|
||||
ControlLeft
|
||||
ControlRight
|
||||
CapsLock
|
||||
ShiftLock
|
||||
MetaLeft
|
||||
MetaRight
|
||||
AltLeft
|
||||
AltRight
|
||||
SuperLeft
|
||||
SuperRight
|
||||
HyperLeft
|
||||
HyperRight
|
||||
)
|
||||
package vnc2video
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Key represents a VNC key press.
|
||||
type Key uint32
|
||||
|
||||
//go:generate stringer -type=Key
|
||||
|
||||
// Keys is a slice of Key values.
|
||||
type Keys []Key
|
||||
|
||||
var keymap = map[rune]Key{
|
||||
'-': Minus,
|
||||
'0': Digit0,
|
||||
'1': Digit1,
|
||||
'2': Digit2,
|
||||
'3': Digit3,
|
||||
'4': Digit4,
|
||||
'5': Digit5,
|
||||
'6': Digit6,
|
||||
'7': Digit7,
|
||||
'8': Digit8,
|
||||
'9': Digit9,
|
||||
}
|
||||
|
||||
// IntToKeys returns Keys that represent the key presses required to type an int.
|
||||
func IntToKeys(v int) Keys {
|
||||
k := Keys{}
|
||||
for _, c := range fmt.Sprintf("%d", v) {
|
||||
k = append(k, keymap[c])
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
// Latin 1 (byte 3 = 0)
|
||||
// ISO/IEC 8859-1 = Unicode U+0020..U+00FF
|
||||
const (
|
||||
Space Key = iota + 0x0020
|
||||
Exclaim // exclamation mark
|
||||
QuoteDbl
|
||||
NumberSign
|
||||
Dollar
|
||||
Percent
|
||||
Ampersand
|
||||
Apostrophe
|
||||
ParenLeft
|
||||
ParenRight
|
||||
Asterisk
|
||||
Plus
|
||||
Comma
|
||||
Minus
|
||||
Period
|
||||
Slash
|
||||
Digit0
|
||||
Digit1
|
||||
Digit2
|
||||
Digit3
|
||||
Digit4
|
||||
Digit5
|
||||
Digit6
|
||||
Digit7
|
||||
Digit8
|
||||
Digit9
|
||||
Colon
|
||||
Semicolon
|
||||
Less
|
||||
Equal
|
||||
Greater
|
||||
Question
|
||||
At
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
BracketLeft
|
||||
Backslash
|
||||
BracketRight
|
||||
AsciiCircum
|
||||
Underscore
|
||||
Grave
|
||||
SmallA
|
||||
SmallB
|
||||
SmallC
|
||||
SmallD
|
||||
SmallE
|
||||
SmallF
|
||||
SmallG
|
||||
SmallH
|
||||
SmallI
|
||||
SmallJ
|
||||
SmallK
|
||||
SmallL
|
||||
SmallM
|
||||
SmallN
|
||||
SmallO
|
||||
SmallP
|
||||
SmallQ
|
||||
SmallR
|
||||
SmallS
|
||||
SmallT
|
||||
SmallU
|
||||
SmallV
|
||||
SmallW
|
||||
SmallX
|
||||
SmallY
|
||||
SmallZ
|
||||
BraceLeft
|
||||
Bar
|
||||
BraceRight
|
||||
AsciiTilde
|
||||
)
|
||||
|
||||
const (
|
||||
BackSpace Key = iota + 0xff08
|
||||
Tab
|
||||
Linefeed
|
||||
Clear
|
||||
_
|
||||
Return
|
||||
)
|
||||
|
||||
const (
|
||||
Pause Key = iota + 0xff13
|
||||
ScrollLock
|
||||
SysReq
|
||||
Escape Key = 0xff1b
|
||||
Delete Key = 0xffff
|
||||
)
|
||||
|
||||
const ( // Cursor control & motion.
|
||||
Home Key = iota + 0xff50
|
||||
Left
|
||||
Up
|
||||
Right
|
||||
Down
|
||||
PageUp
|
||||
PageDown
|
||||
End
|
||||
Begin
|
||||
)
|
||||
|
||||
const ( // Misc functions.
|
||||
Select Key = 0xff60
|
||||
Print
|
||||
Execute
|
||||
Insert
|
||||
Undo
|
||||
Redo
|
||||
Menu
|
||||
Find
|
||||
Cancel
|
||||
Help
|
||||
Break
|
||||
ModeSwitch Key = 0xff7e
|
||||
NumLock Key = 0xff7f
|
||||
)
|
||||
|
||||
const ( // Keypad functions.
|
||||
KeypadSpace Key = 0xff80
|
||||
KeypadTab Key = 0xff89
|
||||
KeypadEnter Key = 0xff8d
|
||||
)
|
||||
|
||||
const ( // Keypad functions cont.
|
||||
KeypadF1 Key = iota + 0xff91
|
||||
KeypadF2
|
||||
KeypadF3
|
||||
KeypadF4
|
||||
KeypadHome
|
||||
KeypadLeft
|
||||
KeypadUp
|
||||
KeypadRight
|
||||
KeypadDown
|
||||
KeypadPrior
|
||||
KeypadPageUp
|
||||
KeypadNext
|
||||
KeypadPageDown
|
||||
KeypadEnd
|
||||
KeypadBegin
|
||||
KeypadInsert
|
||||
KeypadDelete
|
||||
KeypadMultiply
|
||||
KeypadAdd
|
||||
KeypadSeparator
|
||||
KeypadSubtract
|
||||
KeypadDecimal
|
||||
KeypadDivide
|
||||
Keypad0
|
||||
Keypad1
|
||||
Keypad2
|
||||
Keypad3
|
||||
Keypad4
|
||||
Keypad5
|
||||
Keypad6
|
||||
Keypad7
|
||||
Keypad8
|
||||
Keypad9
|
||||
KeypadEqual Key = 0xffbd
|
||||
)
|
||||
|
||||
const (
|
||||
F1 Key = iota + 0xffbe
|
||||
F2
|
||||
F3
|
||||
F4
|
||||
F5
|
||||
F6
|
||||
F7
|
||||
F8
|
||||
F9
|
||||
F10
|
||||
F11
|
||||
F12
|
||||
)
|
||||
|
||||
const (
|
||||
ShiftLeft Key = iota + 0xffe1
|
||||
ShiftRight
|
||||
ControlLeft
|
||||
ControlRight
|
||||
CapsLock
|
||||
ShiftLock
|
||||
MetaLeft
|
||||
MetaRight
|
||||
AltLeft
|
||||
AltRight
|
||||
SuperLeft
|
||||
SuperRight
|
||||
HyperLeft
|
||||
HyperRight
|
||||
)
|
||||
|
312
logger/logger.go
312
logger/logger.go
@ -1,156 +1,156 @@
|
||||
package logger
|
||||
|
||||
import "fmt"
|
||||
|
||||
var simpleLogger = SimpleLogger{LogLevelInfo}
|
||||
|
||||
type Logger interface {
|
||||
Debug(v ...interface{})
|
||||
Debugf(format string, v ...interface{})
|
||||
Info(v ...interface{})
|
||||
Infof(format string, v ...interface{})
|
||||
Warn(v ...interface{})
|
||||
Warnf(format string, v ...interface{})
|
||||
Error(v ...interface{})
|
||||
Errorf(format string, v ...interface{})
|
||||
Fatal(v ...interface{})
|
||||
Fatalf(format string, v ...interface{})
|
||||
}
|
||||
type LogLevel int
|
||||
|
||||
const (
|
||||
LogLevelTrace LogLevel = iota
|
||||
LogLevelDebug
|
||||
LogLevelInfo
|
||||
LogLevelWarn
|
||||
LogLevelError
|
||||
LogLevelFatal
|
||||
)
|
||||
|
||||
type SimpleLogger struct {
|
||||
level LogLevel
|
||||
}
|
||||
|
||||
func (sl *SimpleLogger) Trace(v ...interface{}) {
|
||||
if sl.level <= LogLevelTrace {
|
||||
arr := []interface{}{"[Trace]"}
|
||||
for _, item := range v {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
|
||||
fmt.Println(arr...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Tracef(format string, v ...interface{}) {
|
||||
if sl.level <= LogLevelTrace {
|
||||
fmt.Printf("[Trace] "+format+"\n", v...)
|
||||
}
|
||||
}
|
||||
|
||||
func (sl *SimpleLogger) Debug(v ...interface{}) {
|
||||
if sl.level <= LogLevelDebug {
|
||||
arr := []interface{}{"[Debug]"}
|
||||
for _, item := range v {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
|
||||
fmt.Println(arr...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Debugf(format string, v ...interface{}) {
|
||||
if sl.level <= LogLevelDebug {
|
||||
fmt.Printf("[Debug] "+format+"\n", v...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Info(v ...interface{}) {
|
||||
if sl.level <= LogLevelInfo {
|
||||
arr := []interface{}{"[Info ]"}
|
||||
for _, item := range v {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
fmt.Println(arr...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Infof(format string, v ...interface{}) {
|
||||
if sl.level <= LogLevelInfo {
|
||||
fmt.Printf("[Info ] "+format+"\n", v...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Warn(v ...interface{}) {
|
||||
if sl.level <= LogLevelWarn {
|
||||
arr := []interface{}{"[Warn ]"}
|
||||
for _, item := range v {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
fmt.Println(arr...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Warnf(format string, v ...interface{}) {
|
||||
if sl.level <= LogLevelWarn {
|
||||
fmt.Printf("[Warn ] "+format+"\n", v...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Error(v ...interface{}) {
|
||||
if sl.level <= LogLevelError {
|
||||
arr := []interface{}{"[Error]"}
|
||||
for _, item := range v {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
fmt.Println(arr...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Errorf(format string, v ...interface{}) {
|
||||
if sl.level <= LogLevelError {
|
||||
fmt.Printf("[Error] "+format+"\n", v...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Fatal(v ...interface{}) {
|
||||
if sl.level <= LogLevelFatal {
|
||||
arr := []interface{}{"[Fatal]"}
|
||||
for _, item := range v {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
fmt.Println(arr...)
|
||||
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Fatalf(format string, v ...interface{}) {
|
||||
if sl.level <= LogLevelFatal {
|
||||
fmt.Printf("[Fatal] "+format+"\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
func Debug(v ...interface{}) {
|
||||
simpleLogger.Debug(v...)
|
||||
}
|
||||
func Debugf(format string, v ...interface{}) {
|
||||
simpleLogger.Debugf(format, v...)
|
||||
}
|
||||
|
||||
func Info(v ...interface{}) {
|
||||
simpleLogger.Info(v...)
|
||||
}
|
||||
func Infof(format string, v ...interface{}) {
|
||||
simpleLogger.Infof(format, v...)
|
||||
}
|
||||
|
||||
func Warn(v ...interface{}) {
|
||||
simpleLogger.Warn(v...)
|
||||
}
|
||||
func Warnf(format string, v ...interface{}) {
|
||||
simpleLogger.Warnf(format, v...)
|
||||
}
|
||||
|
||||
func Error(v ...interface{}) {
|
||||
simpleLogger.Error(v...)
|
||||
}
|
||||
func Errorf(format string, v ...interface{}) {
|
||||
simpleLogger.Errorf(format, v...)
|
||||
}
|
||||
|
||||
func Fatal(v ...interface{}) {
|
||||
simpleLogger.Fatal(v...)
|
||||
}
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
simpleLogger.Fatalf(format, v...)
|
||||
}
|
||||
package logger
|
||||
|
||||
import "fmt"
|
||||
|
||||
var simpleLogger = SimpleLogger{LogLevelInfo}
|
||||
|
||||
type Logger interface {
|
||||
Debug(v ...interface{})
|
||||
Debugf(format string, v ...interface{})
|
||||
Info(v ...interface{})
|
||||
Infof(format string, v ...interface{})
|
||||
Warn(v ...interface{})
|
||||
Warnf(format string, v ...interface{})
|
||||
Error(v ...interface{})
|
||||
Errorf(format string, v ...interface{})
|
||||
Fatal(v ...interface{})
|
||||
Fatalf(format string, v ...interface{})
|
||||
}
|
||||
type LogLevel int
|
||||
|
||||
const (
|
||||
LogLevelTrace LogLevel = iota
|
||||
LogLevelDebug
|
||||
LogLevelInfo
|
||||
LogLevelWarn
|
||||
LogLevelError
|
||||
LogLevelFatal
|
||||
)
|
||||
|
||||
type SimpleLogger struct {
|
||||
level LogLevel
|
||||
}
|
||||
|
||||
func (sl *SimpleLogger) Trace(v ...interface{}) {
|
||||
if sl.level <= LogLevelTrace {
|
||||
arr := []interface{}{"[Trace]"}
|
||||
for _, item := range v {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
|
||||
fmt.Println(arr...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Tracef(format string, v ...interface{}) {
|
||||
if sl.level <= LogLevelTrace {
|
||||
fmt.Printf("[Trace] "+format+"\n", v...)
|
||||
}
|
||||
}
|
||||
|
||||
func (sl *SimpleLogger) Debug(v ...interface{}) {
|
||||
if sl.level <= LogLevelDebug {
|
||||
arr := []interface{}{"[Debug]"}
|
||||
for _, item := range v {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
|
||||
fmt.Println(arr...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Debugf(format string, v ...interface{}) {
|
||||
if sl.level <= LogLevelDebug {
|
||||
fmt.Printf("[Debug] "+format+"\n", v...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Info(v ...interface{}) {
|
||||
if sl.level <= LogLevelInfo {
|
||||
arr := []interface{}{"[Info ]"}
|
||||
for _, item := range v {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
fmt.Println(arr...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Infof(format string, v ...interface{}) {
|
||||
if sl.level <= LogLevelInfo {
|
||||
fmt.Printf("[Info ] "+format+"\n", v...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Warn(v ...interface{}) {
|
||||
if sl.level <= LogLevelWarn {
|
||||
arr := []interface{}{"[Warn ]"}
|
||||
for _, item := range v {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
fmt.Println(arr...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Warnf(format string, v ...interface{}) {
|
||||
if sl.level <= LogLevelWarn {
|
||||
fmt.Printf("[Warn ] "+format+"\n", v...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Error(v ...interface{}) {
|
||||
if sl.level <= LogLevelError {
|
||||
arr := []interface{}{"[Error]"}
|
||||
for _, item := range v {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
fmt.Println(arr...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Errorf(format string, v ...interface{}) {
|
||||
if sl.level <= LogLevelError {
|
||||
fmt.Printf("[Error] "+format+"\n", v...)
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Fatal(v ...interface{}) {
|
||||
if sl.level <= LogLevelFatal {
|
||||
arr := []interface{}{"[Fatal]"}
|
||||
for _, item := range v {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
fmt.Println(arr...)
|
||||
|
||||
}
|
||||
}
|
||||
func (sl *SimpleLogger) Fatalf(format string, v ...interface{}) {
|
||||
if sl.level <= LogLevelFatal {
|
||||
fmt.Printf("[Fatal] "+format+"\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
func Debug(v ...interface{}) {
|
||||
simpleLogger.Debug(v...)
|
||||
}
|
||||
func Debugf(format string, v ...interface{}) {
|
||||
simpleLogger.Debugf(format, v...)
|
||||
}
|
||||
|
||||
func Info(v ...interface{}) {
|
||||
simpleLogger.Info(v...)
|
||||
}
|
||||
func Infof(format string, v ...interface{}) {
|
||||
simpleLogger.Infof(format, v...)
|
||||
}
|
||||
|
||||
func Warn(v ...interface{}) {
|
||||
simpleLogger.Warn(v...)
|
||||
}
|
||||
func Warnf(format string, v ...interface{}) {
|
||||
simpleLogger.Warnf(format, v...)
|
||||
}
|
||||
|
||||
func Error(v ...interface{}) {
|
||||
simpleLogger.Error(v...)
|
||||
}
|
||||
func Errorf(format string, v ...interface{}) {
|
||||
simpleLogger.Errorf(format, v...)
|
||||
}
|
||||
|
||||
func Fatal(v ...interface{}) {
|
||||
simpleLogger.Fatal(v...)
|
||||
}
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
simpleLogger.Fatalf(format, v...)
|
||||
}
|
||||
|
1266
messages.go
1266
messages.go
File diff suppressed because it is too large
Load Diff
740
messages_aten.go
740
messages_aten.go
@ -1,370 +1,370 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Aten IKVM server message types
|
||||
const (
|
||||
AteniKVMFrontGroundEventMsgType ServerMessageType = 4
|
||||
AteniKVMKeepAliveEventMsgType ServerMessageType = 22
|
||||
AteniKVMVideoGetInfoMsgType ServerMessageType = 51
|
||||
AteniKVMMouseGetInfoMsgType ServerMessageType = 55
|
||||
AteniKVMSessionMessageMsgType ServerMessageType = 57
|
||||
AteniKVMGetViewerLangMsgType ServerMessageType = 60
|
||||
)
|
||||
|
||||
// Aten IKVM client message types
|
||||
const (
|
||||
AteniKVMKeyEventMsgType ClientMessageType = 4
|
||||
AteniKVMPointerEventMsgType ClientMessageType = 5
|
||||
)
|
||||
|
||||
// AteniKVMKeyEvent holds the wire format message
|
||||
type AteniKVMKeyEvent struct {
|
||||
_ [1]byte // padding
|
||||
Down uint8 // down-flag
|
||||
_ [2]byte // padding
|
||||
Key Key // key
|
||||
_ [9]byte // padding
|
||||
}
|
||||
|
||||
// AteniKVMPointerEvent holds the wire format message
|
||||
type AteniKVMPointerEvent struct {
|
||||
_ [1]byte // padding
|
||||
Mask uint8 // mask
|
||||
X uint16 // x
|
||||
Y uint16 // y
|
||||
_ [11]byte // padding
|
||||
}
|
||||
|
||||
func (msg *AteniKVMPointerEvent) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (msg *AteniKVMPointerEvent) String() string {
|
||||
return fmt.Sprintf("mask: %d, x:%d, y:%d", msg.Mask, msg.X, msg.Y)
|
||||
}
|
||||
|
||||
func (msg *AteniKVMPointerEvent) Type() ClientMessageType {
|
||||
return AteniKVMPointerEventMsgType
|
||||
}
|
||||
|
||||
func (*AteniKVMPointerEvent) Read(c Conn) (ClientMessage, error) {
|
||||
msg := AteniKVMPointerEvent{}
|
||||
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
func (msg *AteniKVMPointerEvent) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, msg); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
func (msg *AteniKVMKeyEvent) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (msg *AteniKVMKeyEvent) String() string {
|
||||
return fmt.Sprintf("down:%d, key:%s", msg.Down, msg.Key)
|
||||
}
|
||||
|
||||
func (msg *AteniKVMKeyEvent) Type() ClientMessageType {
|
||||
return AteniKVMKeyEventMsgType
|
||||
}
|
||||
|
||||
func (*AteniKVMKeyEvent) Read(c Conn) (ClientMessage, error) {
|
||||
msg := AteniKVMKeyEvent{}
|
||||
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
func (msg *AteniKVMKeyEvent) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, msg); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// AteniKVMFrontGroundEvent unknown aten ikvm message
|
||||
type AteniKVMFrontGroundEvent struct {
|
||||
_ [20]byte
|
||||
}
|
||||
|
||||
func (msg *AteniKVMFrontGroundEvent) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (msg *AteniKVMFrontGroundEvent) String() string {
|
||||
return fmt.Sprintf("%s", msg.Type())
|
||||
}
|
||||
|
||||
// Type return ServerMessageType
|
||||
func (*AteniKVMFrontGroundEvent) Type() ServerMessageType {
|
||||
return AteniKVMFrontGroundEventMsgType
|
||||
}
|
||||
|
||||
// Read unmarshal message from conn
|
||||
func (*AteniKVMFrontGroundEvent) Read(c Conn) (ServerMessage, error) {
|
||||
msg := &AteniKVMFrontGroundEvent{}
|
||||
var pad [20]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Write marshal message to conn
|
||||
func (msg *AteniKVMFrontGroundEvent) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
var pad [20]byte
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// AteniKVMKeepAliveEvent unknown aten ikvm message
|
||||
type AteniKVMKeepAliveEvent struct {
|
||||
_ [1]byte
|
||||
}
|
||||
|
||||
func (msg *AteniKVMKeepAliveEvent) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (msg *AteniKVMKeepAliveEvent) String() string {
|
||||
return fmt.Sprintf("%s", msg.Type())
|
||||
}
|
||||
|
||||
// Type return ServerMessageType
|
||||
func (*AteniKVMKeepAliveEvent) Type() ServerMessageType {
|
||||
return AteniKVMKeepAliveEventMsgType
|
||||
}
|
||||
|
||||
// Read unmarshal message from conn
|
||||
func (*AteniKVMKeepAliveEvent) Read(c Conn) (ServerMessage, error) {
|
||||
msg := &AteniKVMKeepAliveEvent{}
|
||||
var pad [1]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Write marshal message to conn
|
||||
func (msg *AteniKVMKeepAliveEvent) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
var pad [1]byte
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// AteniKVMVideoGetInfo unknown aten ikvm message
|
||||
type AteniKVMVideoGetInfo struct {
|
||||
_ [20]byte
|
||||
}
|
||||
|
||||
func (msg *AteniKVMVideoGetInfo) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (msg *AteniKVMVideoGetInfo) String() string {
|
||||
return fmt.Sprintf("%s", msg.Type())
|
||||
}
|
||||
|
||||
// Type return ServerMessageType
|
||||
func (*AteniKVMVideoGetInfo) Type() ServerMessageType {
|
||||
return AteniKVMVideoGetInfoMsgType
|
||||
}
|
||||
|
||||
// Read unmarshal message from conn
|
||||
func (*AteniKVMVideoGetInfo) Read(c Conn) (ServerMessage, error) {
|
||||
msg := &AteniKVMVideoGetInfo{}
|
||||
var pad [40]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Write marshal message to conn
|
||||
func (msg *AteniKVMVideoGetInfo) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
var pad [4]byte
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// AteniKVMMouseGetInfo unknown aten ikvm message
|
||||
type AteniKVMMouseGetInfo struct {
|
||||
_ [2]byte
|
||||
}
|
||||
|
||||
func (msg *AteniKVMMouseGetInfo) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (msg *AteniKVMMouseGetInfo) String() string {
|
||||
return fmt.Sprintf("%s", msg.Type())
|
||||
}
|
||||
|
||||
// Type return ServerMessageType
|
||||
func (*AteniKVMMouseGetInfo) Type() ServerMessageType {
|
||||
return AteniKVMMouseGetInfoMsgType
|
||||
}
|
||||
|
||||
// Read unmarshal message from conn
|
||||
func (*AteniKVMMouseGetInfo) Read(c Conn) (ServerMessage, error) {
|
||||
msg := &AteniKVMFrontGroundEvent{}
|
||||
var pad [2]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Write marshal message to conn
|
||||
func (msg *AteniKVMMouseGetInfo) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
var pad [2]byte
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// AteniKVMSessionMessage unknown aten ikvm message
|
||||
type AteniKVMSessionMessage struct {
|
||||
_ [264]byte
|
||||
}
|
||||
|
||||
func (msg *AteniKVMSessionMessage) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (msg *AteniKVMSessionMessage) String() string {
|
||||
return fmt.Sprintf("%s", msg.Type())
|
||||
}
|
||||
|
||||
// Type return ServerMessageType
|
||||
func (*AteniKVMSessionMessage) Type() ServerMessageType {
|
||||
return AteniKVMSessionMessageMsgType
|
||||
}
|
||||
|
||||
// Read unmarshal message from conn
|
||||
func (*AteniKVMSessionMessage) Read(c Conn) (ServerMessage, error) {
|
||||
msg := &AteniKVMSessionMessage{}
|
||||
var pad [264]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Write marshal message to conn
|
||||
func (msg *AteniKVMSessionMessage) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
var pad [264]byte
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AteniKVMGetViewerLang unknown aten ikvm message
|
||||
type AteniKVMGetViewerLang struct {
|
||||
_ [8]byte
|
||||
}
|
||||
|
||||
func (msg *AteniKVMGetViewerLang) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (msg *AteniKVMGetViewerLang) String() string {
|
||||
return fmt.Sprintf("%s", msg.Type())
|
||||
}
|
||||
|
||||
// Type return ServerMessageType
|
||||
func (*AteniKVMGetViewerLang) Type() ServerMessageType {
|
||||
return AteniKVMGetViewerLangMsgType
|
||||
}
|
||||
|
||||
// Read unmarshal message from conn
|
||||
func (*AteniKVMGetViewerLang) Read(c Conn) (ServerMessage, error) {
|
||||
msg := &AteniKVMGetViewerLang{}
|
||||
var pad [8]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Write marshal message to conn
|
||||
func (msg *AteniKVMGetViewerLang) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
var pad [8]byte
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Aten IKVM server message types
|
||||
const (
|
||||
AteniKVMFrontGroundEventMsgType ServerMessageType = 4
|
||||
AteniKVMKeepAliveEventMsgType ServerMessageType = 22
|
||||
AteniKVMVideoGetInfoMsgType ServerMessageType = 51
|
||||
AteniKVMMouseGetInfoMsgType ServerMessageType = 55
|
||||
AteniKVMSessionMessageMsgType ServerMessageType = 57
|
||||
AteniKVMGetViewerLangMsgType ServerMessageType = 60
|
||||
)
|
||||
|
||||
// Aten IKVM client message types
|
||||
const (
|
||||
AteniKVMKeyEventMsgType ClientMessageType = 4
|
||||
AteniKVMPointerEventMsgType ClientMessageType = 5
|
||||
)
|
||||
|
||||
// AteniKVMKeyEvent holds the wire format message
|
||||
type AteniKVMKeyEvent struct {
|
||||
_ [1]byte // padding
|
||||
Down uint8 // down-flag
|
||||
_ [2]byte // padding
|
||||
Key Key // key
|
||||
_ [9]byte // padding
|
||||
}
|
||||
|
||||
// AteniKVMPointerEvent holds the wire format message
|
||||
type AteniKVMPointerEvent struct {
|
||||
_ [1]byte // padding
|
||||
Mask uint8 // mask
|
||||
X uint16 // x
|
||||
Y uint16 // y
|
||||
_ [11]byte // padding
|
||||
}
|
||||
|
||||
func (msg *AteniKVMPointerEvent) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (msg *AteniKVMPointerEvent) String() string {
|
||||
return fmt.Sprintf("mask: %d, x:%d, y:%d", msg.Mask, msg.X, msg.Y)
|
||||
}
|
||||
|
||||
func (msg *AteniKVMPointerEvent) Type() ClientMessageType {
|
||||
return AteniKVMPointerEventMsgType
|
||||
}
|
||||
|
||||
func (*AteniKVMPointerEvent) Read(c Conn) (ClientMessage, error) {
|
||||
msg := AteniKVMPointerEvent{}
|
||||
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
func (msg *AteniKVMPointerEvent) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, msg); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
func (msg *AteniKVMKeyEvent) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (msg *AteniKVMKeyEvent) String() string {
|
||||
return fmt.Sprintf("down:%d, key:%s", msg.Down, msg.Key)
|
||||
}
|
||||
|
||||
func (msg *AteniKVMKeyEvent) Type() ClientMessageType {
|
||||
return AteniKVMKeyEventMsgType
|
||||
}
|
||||
|
||||
func (*AteniKVMKeyEvent) Read(c Conn) (ClientMessage, error) {
|
||||
msg := AteniKVMKeyEvent{}
|
||||
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
func (msg *AteniKVMKeyEvent) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, msg); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// AteniKVMFrontGroundEvent unknown aten ikvm message
|
||||
type AteniKVMFrontGroundEvent struct {
|
||||
_ [20]byte
|
||||
}
|
||||
|
||||
func (msg *AteniKVMFrontGroundEvent) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (msg *AteniKVMFrontGroundEvent) String() string {
|
||||
return fmt.Sprintf("%s", msg.Type())
|
||||
}
|
||||
|
||||
// Type return ServerMessageType
|
||||
func (*AteniKVMFrontGroundEvent) Type() ServerMessageType {
|
||||
return AteniKVMFrontGroundEventMsgType
|
||||
}
|
||||
|
||||
// Read unmarshal message from conn
|
||||
func (*AteniKVMFrontGroundEvent) Read(c Conn) (ServerMessage, error) {
|
||||
msg := &AteniKVMFrontGroundEvent{}
|
||||
var pad [20]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Write marshal message to conn
|
||||
func (msg *AteniKVMFrontGroundEvent) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
var pad [20]byte
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// AteniKVMKeepAliveEvent unknown aten ikvm message
|
||||
type AteniKVMKeepAliveEvent struct {
|
||||
_ [1]byte
|
||||
}
|
||||
|
||||
func (msg *AteniKVMKeepAliveEvent) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (msg *AteniKVMKeepAliveEvent) String() string {
|
||||
return fmt.Sprintf("%s", msg.Type())
|
||||
}
|
||||
|
||||
// Type return ServerMessageType
|
||||
func (*AteniKVMKeepAliveEvent) Type() ServerMessageType {
|
||||
return AteniKVMKeepAliveEventMsgType
|
||||
}
|
||||
|
||||
// Read unmarshal message from conn
|
||||
func (*AteniKVMKeepAliveEvent) Read(c Conn) (ServerMessage, error) {
|
||||
msg := &AteniKVMKeepAliveEvent{}
|
||||
var pad [1]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Write marshal message to conn
|
||||
func (msg *AteniKVMKeepAliveEvent) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
var pad [1]byte
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// AteniKVMVideoGetInfo unknown aten ikvm message
|
||||
type AteniKVMVideoGetInfo struct {
|
||||
_ [20]byte
|
||||
}
|
||||
|
||||
func (msg *AteniKVMVideoGetInfo) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (msg *AteniKVMVideoGetInfo) String() string {
|
||||
return fmt.Sprintf("%s", msg.Type())
|
||||
}
|
||||
|
||||
// Type return ServerMessageType
|
||||
func (*AteniKVMVideoGetInfo) Type() ServerMessageType {
|
||||
return AteniKVMVideoGetInfoMsgType
|
||||
}
|
||||
|
||||
// Read unmarshal message from conn
|
||||
func (*AteniKVMVideoGetInfo) Read(c Conn) (ServerMessage, error) {
|
||||
msg := &AteniKVMVideoGetInfo{}
|
||||
var pad [40]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Write marshal message to conn
|
||||
func (msg *AteniKVMVideoGetInfo) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
var pad [4]byte
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// AteniKVMMouseGetInfo unknown aten ikvm message
|
||||
type AteniKVMMouseGetInfo struct {
|
||||
_ [2]byte
|
||||
}
|
||||
|
||||
func (msg *AteniKVMMouseGetInfo) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (msg *AteniKVMMouseGetInfo) String() string {
|
||||
return fmt.Sprintf("%s", msg.Type())
|
||||
}
|
||||
|
||||
// Type return ServerMessageType
|
||||
func (*AteniKVMMouseGetInfo) Type() ServerMessageType {
|
||||
return AteniKVMMouseGetInfoMsgType
|
||||
}
|
||||
|
||||
// Read unmarshal message from conn
|
||||
func (*AteniKVMMouseGetInfo) Read(c Conn) (ServerMessage, error) {
|
||||
msg := &AteniKVMFrontGroundEvent{}
|
||||
var pad [2]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Write marshal message to conn
|
||||
func (msg *AteniKVMMouseGetInfo) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
var pad [2]byte
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// AteniKVMSessionMessage unknown aten ikvm message
|
||||
type AteniKVMSessionMessage struct {
|
||||
_ [264]byte
|
||||
}
|
||||
|
||||
func (msg *AteniKVMSessionMessage) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (msg *AteniKVMSessionMessage) String() string {
|
||||
return fmt.Sprintf("%s", msg.Type())
|
||||
}
|
||||
|
||||
// Type return ServerMessageType
|
||||
func (*AteniKVMSessionMessage) Type() ServerMessageType {
|
||||
return AteniKVMSessionMessageMsgType
|
||||
}
|
||||
|
||||
// Read unmarshal message from conn
|
||||
func (*AteniKVMSessionMessage) Read(c Conn) (ServerMessage, error) {
|
||||
msg := &AteniKVMSessionMessage{}
|
||||
var pad [264]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Write marshal message to conn
|
||||
func (msg *AteniKVMSessionMessage) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
var pad [264]byte
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AteniKVMGetViewerLang unknown aten ikvm message
|
||||
type AteniKVMGetViewerLang struct {
|
||||
_ [8]byte
|
||||
}
|
||||
|
||||
func (msg *AteniKVMGetViewerLang) Supported(c Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// String return string representation
|
||||
func (msg *AteniKVMGetViewerLang) String() string {
|
||||
return fmt.Sprintf("%s", msg.Type())
|
||||
}
|
||||
|
||||
// Type return ServerMessageType
|
||||
func (*AteniKVMGetViewerLang) Type() ServerMessageType {
|
||||
return AteniKVMGetViewerLangMsgType
|
||||
}
|
||||
|
||||
// Read unmarshal message from conn
|
||||
func (*AteniKVMGetViewerLang) Read(c Conn) (ServerMessage, error) {
|
||||
msg := &AteniKVMGetViewerLang{}
|
||||
var pad [8]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Write marshal message to conn
|
||||
func (msg *AteniKVMGetViewerLang) Write(c Conn) error {
|
||||
if !msg.Supported(c) {
|
||||
return nil
|
||||
}
|
||||
var pad [8]byte
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
272
pixel_format.go
272
pixel_format.go
@ -1,136 +1,136 @@
|
||||
// Implementation of RFC 6143 §7.4 Pixel Format Data Structure.
|
||||
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
// PixelFormat8bit returns 8 bit pixel format
|
||||
PixelFormat8bit = NewPixelFormat(8)
|
||||
// PixelFormat16bit returns 16 bit pixel format
|
||||
PixelFormat16bit = NewPixelFormat(16)
|
||||
// PixelFormat32bit returns 32 bit pixel format
|
||||
PixelFormat32bit = NewPixelFormat(32)
|
||||
// PixelFormatAten returns pixel format used in Aten IKVM
|
||||
PixelFormatAten = NewPixelFormatAten()
|
||||
)
|
||||
|
||||
// PixelFormat describes the way a pixel is formatted for a VNC connection
|
||||
type PixelFormat struct {
|
||||
BPP uint8 // bits-per-pixel
|
||||
Depth uint8 // depth
|
||||
BigEndian uint8 // big-endian-flag
|
||||
TrueColor uint8 // true-color-flag
|
||||
RedMax, GreenMax, BlueMax uint16 // red-, green-, blue-max (2^BPP-1)
|
||||
RedShift, GreenShift, BlueShift uint8 // red-, green-, blue-shift
|
||||
_ [3]byte // padding
|
||||
}
|
||||
|
||||
const pixelFormatLen = 16
|
||||
|
||||
// NewPixelFormat returns a populated PixelFormat structure
|
||||
func NewPixelFormat(bpp uint8) PixelFormat {
|
||||
bigEndian := uint8(0)
|
||||
// rgbMax := uint16(math.Exp2(float64(bpp))) - 1
|
||||
rMax := uint16(255)
|
||||
gMax := uint16(255)
|
||||
bMax := uint16(255)
|
||||
var (
|
||||
tc = uint8(1)
|
||||
rs, gs, bs uint8
|
||||
depth uint8
|
||||
)
|
||||
switch bpp {
|
||||
case 8:
|
||||
tc = 0
|
||||
depth = 8
|
||||
rs, gs, bs = 0, 0, 0
|
||||
case 16:
|
||||
depth = 16
|
||||
rs, gs, bs = 0, 4, 8
|
||||
case 32:
|
||||
depth = 24
|
||||
// rs, gs, bs = 0, 8, 16
|
||||
rs, gs, bs = 16, 8, 0
|
||||
}
|
||||
return PixelFormat{bpp, depth, bigEndian, tc, rMax, gMax, bMax, rs, gs, bs, [3]byte{}}
|
||||
}
|
||||
|
||||
// NewPixelFormatAten returns Aten IKVM pixel format
|
||||
func NewPixelFormatAten() PixelFormat {
|
||||
return PixelFormat{16, 15, 0, 1, (1 << 5) - 1, (1 << 5) - 1, (1 << 5) - 1, 10, 5, 0, [3]byte{}}
|
||||
}
|
||||
|
||||
// Marshal implements the Marshaler interface
|
||||
func (pf PixelFormat) Marshal() ([]byte, error) {
|
||||
// Validation checks.
|
||||
switch pf.BPP {
|
||||
case 8, 16, 32:
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid BPP value %v; must be 8, 16, or 32", pf.BPP)
|
||||
}
|
||||
|
||||
if pf.Depth < pf.BPP {
|
||||
return nil, fmt.Errorf("Invalid Depth value %v; cannot be < BPP", pf.Depth)
|
||||
}
|
||||
switch pf.Depth {
|
||||
case 8, 16, 32:
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid Depth value %v; must be 8, 16, or 32", pf.Depth)
|
||||
}
|
||||
|
||||
// Create the slice of bytes
|
||||
buf := bPool.Get().(*bytes.Buffer)
|
||||
buf.Reset()
|
||||
defer bPool.Put(buf)
|
||||
|
||||
if err := binary.Write(buf, binary.BigEndian, &pf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Read reads from an io.Reader, and populates the PixelFormat
|
||||
func (pf PixelFormat) Read(r io.Reader) error {
|
||||
buf := make([]byte, pixelFormatLen)
|
||||
if _, err := io.ReadAtLeast(r, buf, pixelFormatLen); err != nil {
|
||||
return err
|
||||
}
|
||||
return pf.Unmarshal(buf)
|
||||
}
|
||||
|
||||
// Unmarshal implements the Unmarshaler interface
|
||||
func (pf PixelFormat) Unmarshal(data []byte) error {
|
||||
buf := bPool.Get().(*bytes.Buffer)
|
||||
buf.Reset()
|
||||
defer bPool.Put(buf)
|
||||
|
||||
if _, err := buf.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(buf, binary.BigEndian, &pf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer interface
|
||||
func (pf PixelFormat) String() string {
|
||||
return fmt.Sprintf("{ bpp: %d depth: %d big-endian: %d true-color: %d red-max: %d green-max: %d blue-max: %d red-shift: %d green-shift: %d blue-shift: %d }",
|
||||
pf.BPP, pf.Depth, pf.BigEndian, pf.TrueColor, pf.RedMax, pf.GreenMax, pf.BlueMax, pf.RedShift, pf.GreenShift, pf.BlueShift)
|
||||
}
|
||||
|
||||
func (pf PixelFormat) order() binary.ByteOrder {
|
||||
if pf.BigEndian == 1 {
|
||||
return binary.BigEndian
|
||||
}
|
||||
return binary.LittleEndian
|
||||
}
|
||||
// Implementation of RFC 6143 §7.4 Pixel Format Data Structure.
|
||||
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
// PixelFormat8bit returns 8 bit pixel format
|
||||
PixelFormat8bit = NewPixelFormat(8)
|
||||
// PixelFormat16bit returns 16 bit pixel format
|
||||
PixelFormat16bit = NewPixelFormat(16)
|
||||
// PixelFormat32bit returns 32 bit pixel format
|
||||
PixelFormat32bit = NewPixelFormat(32)
|
||||
// PixelFormatAten returns pixel format used in Aten IKVM
|
||||
PixelFormatAten = NewPixelFormatAten()
|
||||
)
|
||||
|
||||
// PixelFormat describes the way a pixel is formatted for a VNC connection
|
||||
type PixelFormat struct {
|
||||
BPP uint8 // bits-per-pixel
|
||||
Depth uint8 // depth
|
||||
BigEndian uint8 // big-endian-flag
|
||||
TrueColor uint8 // true-color-flag
|
||||
RedMax, GreenMax, BlueMax uint16 // red-, green-, blue-max (2^BPP-1)
|
||||
RedShift, GreenShift, BlueShift uint8 // red-, green-, blue-shift
|
||||
_ [3]byte // padding
|
||||
}
|
||||
|
||||
const pixelFormatLen = 16
|
||||
|
||||
// NewPixelFormat returns a populated PixelFormat structure
|
||||
func NewPixelFormat(bpp uint8) PixelFormat {
|
||||
bigEndian := uint8(0)
|
||||
// rgbMax := uint16(math.Exp2(float64(bpp))) - 1
|
||||
rMax := uint16(255)
|
||||
gMax := uint16(255)
|
||||
bMax := uint16(255)
|
||||
var (
|
||||
tc = uint8(1)
|
||||
rs, gs, bs uint8
|
||||
depth uint8
|
||||
)
|
||||
switch bpp {
|
||||
case 8:
|
||||
tc = 0
|
||||
depth = 8
|
||||
rs, gs, bs = 0, 0, 0
|
||||
case 16:
|
||||
depth = 16
|
||||
rs, gs, bs = 0, 4, 8
|
||||
case 32:
|
||||
depth = 24
|
||||
// rs, gs, bs = 0, 8, 16
|
||||
rs, gs, bs = 16, 8, 0
|
||||
}
|
||||
return PixelFormat{bpp, depth, bigEndian, tc, rMax, gMax, bMax, rs, gs, bs, [3]byte{}}
|
||||
}
|
||||
|
||||
// NewPixelFormatAten returns Aten IKVM pixel format
|
||||
func NewPixelFormatAten() PixelFormat {
|
||||
return PixelFormat{16, 15, 0, 1, (1 << 5) - 1, (1 << 5) - 1, (1 << 5) - 1, 10, 5, 0, [3]byte{}}
|
||||
}
|
||||
|
||||
// Marshal implements the Marshaler interface
|
||||
func (pf PixelFormat) Marshal() ([]byte, error) {
|
||||
// Validation checks.
|
||||
switch pf.BPP {
|
||||
case 8, 16, 32:
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid BPP value %v; must be 8, 16, or 32", pf.BPP)
|
||||
}
|
||||
|
||||
if pf.Depth < pf.BPP {
|
||||
return nil, fmt.Errorf("Invalid Depth value %v; cannot be < BPP", pf.Depth)
|
||||
}
|
||||
switch pf.Depth {
|
||||
case 8, 16, 32:
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid Depth value %v; must be 8, 16, or 32", pf.Depth)
|
||||
}
|
||||
|
||||
// Create the slice of bytes
|
||||
buf := bPool.Get().(*bytes.Buffer)
|
||||
buf.Reset()
|
||||
defer bPool.Put(buf)
|
||||
|
||||
if err := binary.Write(buf, binary.BigEndian, &pf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Read reads from an io.Reader, and populates the PixelFormat
|
||||
func (pf PixelFormat) Read(r io.Reader) error {
|
||||
buf := make([]byte, pixelFormatLen)
|
||||
if _, err := io.ReadAtLeast(r, buf, pixelFormatLen); err != nil {
|
||||
return err
|
||||
}
|
||||
return pf.Unmarshal(buf)
|
||||
}
|
||||
|
||||
// Unmarshal implements the Unmarshaler interface
|
||||
func (pf PixelFormat) Unmarshal(data []byte) error {
|
||||
buf := bPool.Get().(*bytes.Buffer)
|
||||
buf.Reset()
|
||||
defer bPool.Put(buf)
|
||||
|
||||
if _, err := buf.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(buf, binary.BigEndian, &pf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer interface
|
||||
func (pf PixelFormat) String() string {
|
||||
return fmt.Sprintf("{ bpp: %d depth: %d big-endian: %d true-color: %d red-max: %d green-max: %d blue-max: %d red-shift: %d green-shift: %d blue-shift: %d }",
|
||||
pf.BPP, pf.Depth, pf.BigEndian, pf.TrueColor, pf.RedMax, pf.GreenMax, pf.BlueMax, pf.RedShift, pf.GreenShift, pf.BlueShift)
|
||||
}
|
||||
|
||||
func (pf PixelFormat) order() binary.ByteOrder {
|
||||
if pf.BigEndian == 1 {
|
||||
return binary.BigEndian
|
||||
}
|
||||
return binary.LittleEndian
|
||||
}
|
||||
|
100
security.go
100
security.go
@ -1,50 +1,50 @@
|
||||
package vnc2webm
|
||||
|
||||
type SecurityType uint8
|
||||
|
||||
//go:generate stringer -type=SecurityType
|
||||
|
||||
const (
|
||||
SecTypeUnknown SecurityType = SecurityType(0)
|
||||
SecTypeNone SecurityType = SecurityType(1)
|
||||
SecTypeVNC SecurityType = SecurityType(2)
|
||||
SecTypeTight SecurityType = SecurityType(16)
|
||||
SecTypeATEN SecurityType = SecurityType(16)
|
||||
SecTypeVeNCrypt SecurityType = SecurityType(19)
|
||||
)
|
||||
|
||||
type SecuritySubType uint32
|
||||
|
||||
//go:generate stringer -type=SecuritySubType
|
||||
|
||||
const (
|
||||
SecSubTypeUnknown SecuritySubType = SecuritySubType(0)
|
||||
)
|
||||
|
||||
const (
|
||||
SecSubTypeVeNCrypt01Unknown SecuritySubType = SecuritySubType(0)
|
||||
SecSubTypeVeNCrypt01Plain SecuritySubType = SecuritySubType(19)
|
||||
SecSubTypeVeNCrypt01TLSNone SecuritySubType = SecuritySubType(20)
|
||||
SecSubTypeVeNCrypt01TLSVNC SecuritySubType = SecuritySubType(21)
|
||||
SecSubTypeVeNCrypt01TLSPlain SecuritySubType = SecuritySubType(22)
|
||||
SecSubTypeVeNCrypt01X509None SecuritySubType = SecuritySubType(23)
|
||||
SecSubTypeVeNCrypt01X509VNC SecuritySubType = SecuritySubType(24)
|
||||
SecSubTypeVeNCrypt01X509Plain SecuritySubType = SecuritySubType(25)
|
||||
)
|
||||
|
||||
const (
|
||||
SecSubTypeVeNCrypt02Unknown SecuritySubType = SecuritySubType(0)
|
||||
SecSubTypeVeNCrypt02Plain SecuritySubType = SecuritySubType(256)
|
||||
SecSubTypeVeNCrypt02TLSNone SecuritySubType = SecuritySubType(257)
|
||||
SecSubTypeVeNCrypt02TLSVNC SecuritySubType = SecuritySubType(258)
|
||||
SecSubTypeVeNCrypt02TLSPlain SecuritySubType = SecuritySubType(259)
|
||||
SecSubTypeVeNCrypt02X509None SecuritySubType = SecuritySubType(260)
|
||||
SecSubTypeVeNCrypt02X509VNC SecuritySubType = SecuritySubType(261)
|
||||
SecSubTypeVeNCrypt02X509Plain SecuritySubType = SecuritySubType(262)
|
||||
)
|
||||
|
||||
type SecurityHandler interface {
|
||||
Type() SecurityType
|
||||
SubType() SecuritySubType
|
||||
Auth(Conn) error
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
type SecurityType uint8
|
||||
|
||||
//go:generate stringer -type=SecurityType
|
||||
|
||||
const (
|
||||
SecTypeUnknown SecurityType = SecurityType(0)
|
||||
SecTypeNone SecurityType = SecurityType(1)
|
||||
SecTypeVNC SecurityType = SecurityType(2)
|
||||
SecTypeTight SecurityType = SecurityType(16)
|
||||
SecTypeATEN SecurityType = SecurityType(16)
|
||||
SecTypeVeNCrypt SecurityType = SecurityType(19)
|
||||
)
|
||||
|
||||
type SecuritySubType uint32
|
||||
|
||||
//go:generate stringer -type=SecuritySubType
|
||||
|
||||
const (
|
||||
SecSubTypeUnknown SecuritySubType = SecuritySubType(0)
|
||||
)
|
||||
|
||||
const (
|
||||
SecSubTypeVeNCrypt01Unknown SecuritySubType = SecuritySubType(0)
|
||||
SecSubTypeVeNCrypt01Plain SecuritySubType = SecuritySubType(19)
|
||||
SecSubTypeVeNCrypt01TLSNone SecuritySubType = SecuritySubType(20)
|
||||
SecSubTypeVeNCrypt01TLSVNC SecuritySubType = SecuritySubType(21)
|
||||
SecSubTypeVeNCrypt01TLSPlain SecuritySubType = SecuritySubType(22)
|
||||
SecSubTypeVeNCrypt01X509None SecuritySubType = SecuritySubType(23)
|
||||
SecSubTypeVeNCrypt01X509VNC SecuritySubType = SecuritySubType(24)
|
||||
SecSubTypeVeNCrypt01X509Plain SecuritySubType = SecuritySubType(25)
|
||||
)
|
||||
|
||||
const (
|
||||
SecSubTypeVeNCrypt02Unknown SecuritySubType = SecuritySubType(0)
|
||||
SecSubTypeVeNCrypt02Plain SecuritySubType = SecuritySubType(256)
|
||||
SecSubTypeVeNCrypt02TLSNone SecuritySubType = SecuritySubType(257)
|
||||
SecSubTypeVeNCrypt02TLSVNC SecuritySubType = SecuritySubType(258)
|
||||
SecSubTypeVeNCrypt02TLSPlain SecuritySubType = SecuritySubType(259)
|
||||
SecSubTypeVeNCrypt02X509None SecuritySubType = SecuritySubType(260)
|
||||
SecSubTypeVeNCrypt02X509VNC SecuritySubType = SecuritySubType(261)
|
||||
SecSubTypeVeNCrypt02X509Plain SecuritySubType = SecuritySubType(262)
|
||||
)
|
||||
|
||||
type SecurityHandler interface {
|
||||
Type() SecurityType
|
||||
SubType() SecuritySubType
|
||||
Auth(Conn) error
|
||||
}
|
||||
|
214
security_aten.go
214
security_aten.go
@ -1,107 +1,107 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ClientAuthATEN struct {
|
||||
Username []byte
|
||||
Password []byte
|
||||
}
|
||||
|
||||
func (*ClientAuthATEN) Type() SecurityType {
|
||||
return SecTypeATEN
|
||||
}
|
||||
|
||||
func (*ClientAuthATEN) SubType() SecuritySubType {
|
||||
return SecSubTypeUnknown
|
||||
}
|
||||
|
||||
func charCodeAt(s string, n int) rune {
|
||||
for i, r := range s {
|
||||
if i == n {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (auth *ClientAuthATEN) Auth(c Conn) error {
|
||||
var definedAuthLen = 24
|
||||
|
||||
if len(auth.Username) > definedAuthLen || len(auth.Password) > definedAuthLen {
|
||||
return fmt.Errorf("username/password is too long, allowed 0-23")
|
||||
}
|
||||
|
||||
nt, err := readTightTunnels(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
/*
|
||||
fmt.Printf("tunnels %d\n", nt)
|
||||
for i := uint32(0); i < nt; i++ {
|
||||
code, vendor, signature, err := readTightCaps(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("code %d vendor %s signature %s\n", code, vendor, signature)
|
||||
}
|
||||
*/
|
||||
if ((nt&0xffff0ff0)>>0 == 0xaff90fb0) || (nt <= 0 || nt > 0x1000000) {
|
||||
c.SetProtoVersion("aten1")
|
||||
var skip [20]byte
|
||||
binary.Read(c, binary.BigEndian, &skip)
|
||||
//fmt.Printf("skip %v\n", skip)
|
||||
}
|
||||
|
||||
username := make([]byte, definedAuthLen)
|
||||
password := make([]byte, definedAuthLen)
|
||||
copy(username, auth.Username)
|
||||
copy(password, auth.Password)
|
||||
challenge := bytes.Join([][]byte{username, password}, []byte(""))
|
||||
if err := binary.Write(c, binary.BigEndian, challenge); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
/*
|
||||
|
||||
sendUsername := make([]byte, definedAuthLen)
|
||||
for i := 0; i < definedAuthLen; i++ {
|
||||
if i < len(auth.Username) {
|
||||
sendUsername[i] = byte(charCodeAt(string(auth.Username), i))
|
||||
} else {
|
||||
sendUsername[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
sendPassword := make([]byte, definedAuthLen)
|
||||
|
||||
for i := 0; i < definedAuthLen; i++ {
|
||||
if i < len(auth.Password) {
|
||||
sendPassword[i] = byte(charCodeAt(string(auth.Password), i))
|
||||
} else {
|
||||
sendPassword[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, sendUsername); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, sendPassword); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
*/
|
||||
//var pp [10]byte
|
||||
//binary.Read(c, binary.BigEndian, &pp)
|
||||
//fmt.Printf("ddd %v\n", pp)
|
||||
return nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ClientAuthATEN struct {
|
||||
Username []byte
|
||||
Password []byte
|
||||
}
|
||||
|
||||
func (*ClientAuthATEN) Type() SecurityType {
|
||||
return SecTypeATEN
|
||||
}
|
||||
|
||||
func (*ClientAuthATEN) SubType() SecuritySubType {
|
||||
return SecSubTypeUnknown
|
||||
}
|
||||
|
||||
func charCodeAt(s string, n int) rune {
|
||||
for i, r := range s {
|
||||
if i == n {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (auth *ClientAuthATEN) Auth(c Conn) error {
|
||||
var definedAuthLen = 24
|
||||
|
||||
if len(auth.Username) > definedAuthLen || len(auth.Password) > definedAuthLen {
|
||||
return fmt.Errorf("username/password is too long, allowed 0-23")
|
||||
}
|
||||
|
||||
nt, err := readTightTunnels(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
/*
|
||||
fmt.Printf("tunnels %d\n", nt)
|
||||
for i := uint32(0); i < nt; i++ {
|
||||
code, vendor, signature, err := readTightCaps(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("code %d vendor %s signature %s\n", code, vendor, signature)
|
||||
}
|
||||
*/
|
||||
if ((nt&0xffff0ff0)>>0 == 0xaff90fb0) || (nt <= 0 || nt > 0x1000000) {
|
||||
c.SetProtoVersion("aten1")
|
||||
var skip [20]byte
|
||||
binary.Read(c, binary.BigEndian, &skip)
|
||||
//fmt.Printf("skip %v\n", skip)
|
||||
}
|
||||
|
||||
username := make([]byte, definedAuthLen)
|
||||
password := make([]byte, definedAuthLen)
|
||||
copy(username, auth.Username)
|
||||
copy(password, auth.Password)
|
||||
challenge := bytes.Join([][]byte{username, password}, []byte(""))
|
||||
if err := binary.Write(c, binary.BigEndian, challenge); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
/*
|
||||
|
||||
sendUsername := make([]byte, definedAuthLen)
|
||||
for i := 0; i < definedAuthLen; i++ {
|
||||
if i < len(auth.Username) {
|
||||
sendUsername[i] = byte(charCodeAt(string(auth.Username), i))
|
||||
} else {
|
||||
sendUsername[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
sendPassword := make([]byte, definedAuthLen)
|
||||
|
||||
for i := 0; i < definedAuthLen; i++ {
|
||||
if i < len(auth.Password) {
|
||||
sendPassword[i] = byte(charCodeAt(string(auth.Password), i))
|
||||
} else {
|
||||
sendPassword[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, sendUsername); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, sendPassword); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
*/
|
||||
//var pp [10]byte
|
||||
//binary.Read(c, binary.BigEndian, &pp)
|
||||
//fmt.Printf("ddd %v\n", pp)
|
||||
return nil
|
||||
}
|
||||
|
@ -1,30 +1,30 @@
|
||||
package vnc2webm
|
||||
|
||||
type ClientAuthNone struct{}
|
||||
|
||||
func (*ClientAuthNone) Type() SecurityType {
|
||||
return SecTypeNone
|
||||
}
|
||||
|
||||
func (*ClientAuthNone) SubType() SecuritySubType {
|
||||
return SecSubTypeUnknown
|
||||
}
|
||||
|
||||
func (*ClientAuthNone) Auth(conn Conn) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServerAuthNone is the "none" authentication. See 7.2.1.
|
||||
type ServerAuthNone struct{}
|
||||
|
||||
func (*ServerAuthNone) Type() SecurityType {
|
||||
return SecTypeNone
|
||||
}
|
||||
|
||||
func (*ServerAuthNone) SubType() SecuritySubType {
|
||||
return SecSubTypeUnknown
|
||||
}
|
||||
|
||||
func (*ServerAuthNone) Auth(c Conn) error {
|
||||
return nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
type ClientAuthNone struct{}
|
||||
|
||||
func (*ClientAuthNone) Type() SecurityType {
|
||||
return SecTypeNone
|
||||
}
|
||||
|
||||
func (*ClientAuthNone) SubType() SecuritySubType {
|
||||
return SecSubTypeUnknown
|
||||
}
|
||||
|
||||
func (*ClientAuthNone) Auth(conn Conn) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServerAuthNone is the "none" authentication. See 7.2.1.
|
||||
type ServerAuthNone struct{}
|
||||
|
||||
func (*ServerAuthNone) Type() SecurityType {
|
||||
return SecTypeNone
|
||||
}
|
||||
|
||||
func (*ServerAuthNone) SubType() SecuritySubType {
|
||||
return SecSubTypeUnknown
|
||||
}
|
||||
|
||||
func (*ServerAuthNone) Auth(c Conn) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -1,27 +1,27 @@
|
||||
package vnc2webm
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
func readTightTunnels(c Conn) (uint32, error) {
|
||||
var n uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &n); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func readTightCaps(c Conn) (int32, []byte, []byte, error) {
|
||||
var code int32
|
||||
var vendor [4]byte
|
||||
var signature [8]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &code); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &vendor); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &signature); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
return code, vendor[:], signature[:], nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
func readTightTunnels(c Conn) (uint32, error) {
|
||||
var n uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &n); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func readTightCaps(c Conn) (int32, []byte, []byte, error) {
|
||||
var code int32
|
||||
var vendor [4]byte
|
||||
var signature [8]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &code); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &vendor); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &signature); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
return code, vendor[:], signature[:], nil
|
||||
}
|
||||
|
@ -1,109 +1,109 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (*ClientAuthVeNCrypt02Plain) Type() SecurityType {
|
||||
return SecTypeVeNCrypt
|
||||
}
|
||||
|
||||
func (*ClientAuthVeNCrypt02Plain) SubType() SecuritySubType {
|
||||
return SecSubTypeVeNCrypt02Plain
|
||||
}
|
||||
|
||||
// ClientAuthVeNCryptPlain see https://www.berrange.com/~dan/vencrypt.txt
|
||||
type ClientAuthVeNCrypt02Plain struct {
|
||||
Username []byte
|
||||
Password []byte
|
||||
}
|
||||
|
||||
func (auth *ClientAuthVeNCrypt02Plain) Auth(c Conn) error {
|
||||
if err := binary.Write(c, binary.BigEndian, []uint8{0, 2}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
major, minor uint8
|
||||
)
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, &major); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &minor); err != nil {
|
||||
return err
|
||||
}
|
||||
res := uint8(1)
|
||||
if major == 0 && minor == 2 {
|
||||
res = uint8(0)
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, res); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Flush()
|
||||
if err := binary.Write(c, binary.BigEndian, uint8(1)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, auth.SubType()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
var secType SecuritySubType
|
||||
if err := binary.Read(c, binary.BigEndian, &secType); err != nil {
|
||||
return err
|
||||
}
|
||||
if secType != auth.SubType() {
|
||||
binary.Write(c, binary.BigEndian, uint8(1))
|
||||
c.Flush()
|
||||
return fmt.Errorf("invalid sectype")
|
||||
}
|
||||
if len(auth.Password) == 0 || len(auth.Username) == 0 {
|
||||
return fmt.Errorf("Security Handshake failed; no username and/or password provided for VeNCryptAuth.")
|
||||
}
|
||||
/*
|
||||
if err := binary.Write(c, binary.BigEndian, uint32(len(auth.Username))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, uint32(len(auth.Password))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, auth.Username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, auth.Password); err != nil {
|
||||
return err
|
||||
}
|
||||
*/
|
||||
var (
|
||||
uLength, pLength uint32
|
||||
)
|
||||
if err := binary.Read(c, binary.BigEndian, &uLength); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &pLength); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
username := make([]byte, uLength)
|
||||
password := make([]byte, pLength)
|
||||
if err := binary.Read(c, binary.BigEndian, &username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, &password); err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(auth.Username, username) || !bytes.Equal(auth.Password, password) {
|
||||
return fmt.Errorf("invalid username/password")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (*ClientAuthVeNCrypt02Plain) Type() SecurityType {
|
||||
return SecTypeVeNCrypt
|
||||
}
|
||||
|
||||
func (*ClientAuthVeNCrypt02Plain) SubType() SecuritySubType {
|
||||
return SecSubTypeVeNCrypt02Plain
|
||||
}
|
||||
|
||||
// ClientAuthVeNCryptPlain see https://www.berrange.com/~dan/vencrypt.txt
|
||||
type ClientAuthVeNCrypt02Plain struct {
|
||||
Username []byte
|
||||
Password []byte
|
||||
}
|
||||
|
||||
func (auth *ClientAuthVeNCrypt02Plain) Auth(c Conn) error {
|
||||
if err := binary.Write(c, binary.BigEndian, []uint8{0, 2}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
major, minor uint8
|
||||
)
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, &major); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &minor); err != nil {
|
||||
return err
|
||||
}
|
||||
res := uint8(1)
|
||||
if major == 0 && minor == 2 {
|
||||
res = uint8(0)
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, res); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Flush()
|
||||
if err := binary.Write(c, binary.BigEndian, uint8(1)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, auth.SubType()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
var secType SecuritySubType
|
||||
if err := binary.Read(c, binary.BigEndian, &secType); err != nil {
|
||||
return err
|
||||
}
|
||||
if secType != auth.SubType() {
|
||||
binary.Write(c, binary.BigEndian, uint8(1))
|
||||
c.Flush()
|
||||
return fmt.Errorf("invalid sectype")
|
||||
}
|
||||
if len(auth.Password) == 0 || len(auth.Username) == 0 {
|
||||
return fmt.Errorf("Security Handshake failed; no username and/or password provided for VeNCryptAuth.")
|
||||
}
|
||||
/*
|
||||
if err := binary.Write(c, binary.BigEndian, uint32(len(auth.Username))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, uint32(len(auth.Password))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, auth.Username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, auth.Password); err != nil {
|
||||
return err
|
||||
}
|
||||
*/
|
||||
var (
|
||||
uLength, pLength uint32
|
||||
)
|
||||
if err := binary.Read(c, binary.BigEndian, &uLength); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(c, binary.BigEndian, &pLength); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
username := make([]byte, uLength)
|
||||
password := make([]byte, pLength)
|
||||
if err := binary.Read(c, binary.BigEndian, &username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, &password); err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(auth.Username, username) || !bytes.Equal(auth.Password, password) {
|
||||
return fmt.Errorf("invalid username/password")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
240
security_vnc.go
240
security_vnc.go
@ -1,120 +1,120 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/des"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ServerAuthVNC is the standard password authentication. See 7.2.2.
|
||||
type ServerAuthVNC struct {
|
||||
Challenge []byte
|
||||
Password []byte
|
||||
Crypted []byte
|
||||
}
|
||||
|
||||
func (*ServerAuthVNC) Type() SecurityType {
|
||||
return SecTypeVNC
|
||||
}
|
||||
func (*ServerAuthVNC) SubType() SecuritySubType {
|
||||
return SecSubTypeUnknown
|
||||
}
|
||||
|
||||
func (auth *ServerAuthVNC) WriteChallenge(c Conn) error {
|
||||
if err := binary.Write(c, binary.BigEndian, auth.Challenge); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
func (auth *ServerAuthVNC) ReadChallenge(c Conn) error {
|
||||
var crypted [16]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &crypted); err != nil {
|
||||
return err
|
||||
}
|
||||
auth.Crypted = crypted[:]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (auth *ServerAuthVNC) Auth(c Conn) error {
|
||||
if err := auth.WriteChallenge(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := auth.ReadChallenge(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encrypted, err := AuthVNCEncode(auth.Password, auth.Challenge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(encrypted, auth.Crypted) {
|
||||
return fmt.Errorf("password invalid")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClientAuthVNC is the standard password authentication. See 7.2.2.
|
||||
type ClientAuthVNC struct {
|
||||
Challenge []byte
|
||||
Password []byte
|
||||
}
|
||||
|
||||
func (*ClientAuthVNC) Type() SecurityType {
|
||||
return SecTypeVNC
|
||||
}
|
||||
func (*ClientAuthVNC) SubType() SecuritySubType {
|
||||
return SecSubTypeUnknown
|
||||
}
|
||||
|
||||
func (auth *ClientAuthVNC) Auth(c Conn) error {
|
||||
if len(auth.Password) == 0 {
|
||||
return fmt.Errorf("Security Handshake failed; no password provided for VNCAuth.")
|
||||
}
|
||||
|
||||
var challenge [16]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &challenge); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encrypted, err := AuthVNCEncode(auth.Password, challenge[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Send the encrypted challenge back to server
|
||||
if err := binary.Write(c, binary.BigEndian, encrypted); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
func AuthVNCEncode(password []byte, challenge []byte) ([]byte, error) {
|
||||
if len(challenge) != 16 {
|
||||
return nil, fmt.Errorf("challenge size not 16 byte long")
|
||||
}
|
||||
// Copy password string to 8 byte 0-padded slice
|
||||
key := make([]byte, 8)
|
||||
copy(key, password)
|
||||
|
||||
// Each byte of the password needs to be reversed. This is a
|
||||
// non RFC-documented behaviour of VNC clients and servers
|
||||
for i := range key {
|
||||
key[i] = (key[i]&0x55)<<1 | (key[i]&0xAA)>>1 // Swap adjacent bits
|
||||
key[i] = (key[i]&0x33)<<2 | (key[i]&0xCC)>>2 // Swap adjacent pairs
|
||||
key[i] = (key[i]&0x0F)<<4 | (key[i]&0xF0)>>4 // Swap the 2 halves
|
||||
}
|
||||
|
||||
// Encrypt challenge with key.
|
||||
cipher, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(challenge); i += cipher.BlockSize() {
|
||||
cipher.Encrypt(challenge[i:i+cipher.BlockSize()], challenge[i:i+cipher.BlockSize()])
|
||||
}
|
||||
|
||||
return challenge, nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/des"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ServerAuthVNC is the standard password authentication. See 7.2.2.
|
||||
type ServerAuthVNC struct {
|
||||
Challenge []byte
|
||||
Password []byte
|
||||
Crypted []byte
|
||||
}
|
||||
|
||||
func (*ServerAuthVNC) Type() SecurityType {
|
||||
return SecTypeVNC
|
||||
}
|
||||
func (*ServerAuthVNC) SubType() SecuritySubType {
|
||||
return SecSubTypeUnknown
|
||||
}
|
||||
|
||||
func (auth *ServerAuthVNC) WriteChallenge(c Conn) error {
|
||||
if err := binary.Write(c, binary.BigEndian, auth.Challenge); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
func (auth *ServerAuthVNC) ReadChallenge(c Conn) error {
|
||||
var crypted [16]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &crypted); err != nil {
|
||||
return err
|
||||
}
|
||||
auth.Crypted = crypted[:]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (auth *ServerAuthVNC) Auth(c Conn) error {
|
||||
if err := auth.WriteChallenge(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := auth.ReadChallenge(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encrypted, err := AuthVNCEncode(auth.Password, auth.Challenge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(encrypted, auth.Crypted) {
|
||||
return fmt.Errorf("password invalid")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClientAuthVNC is the standard password authentication. See 7.2.2.
|
||||
type ClientAuthVNC struct {
|
||||
Challenge []byte
|
||||
Password []byte
|
||||
}
|
||||
|
||||
func (*ClientAuthVNC) Type() SecurityType {
|
||||
return SecTypeVNC
|
||||
}
|
||||
func (*ClientAuthVNC) SubType() SecuritySubType {
|
||||
return SecSubTypeUnknown
|
||||
}
|
||||
|
||||
func (auth *ClientAuthVNC) Auth(c Conn) error {
|
||||
if len(auth.Password) == 0 {
|
||||
return fmt.Errorf("Security Handshake failed; no password provided for VNCAuth.")
|
||||
}
|
||||
|
||||
var challenge [16]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &challenge); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encrypted, err := AuthVNCEncode(auth.Password, challenge[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Send the encrypted challenge back to server
|
||||
if err := binary.Write(c, binary.BigEndian, encrypted); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
func AuthVNCEncode(password []byte, challenge []byte) ([]byte, error) {
|
||||
if len(challenge) != 16 {
|
||||
return nil, fmt.Errorf("challenge size not 16 byte long")
|
||||
}
|
||||
// Copy password string to 8 byte 0-padded slice
|
||||
key := make([]byte, 8)
|
||||
copy(key, password)
|
||||
|
||||
// Each byte of the password needs to be reversed. This is a
|
||||
// non RFC-documented behaviour of VNC clients and servers
|
||||
for i := range key {
|
||||
key[i] = (key[i]&0x55)<<1 | (key[i]&0xAA)>>1 // Swap adjacent bits
|
||||
key[i] = (key[i]&0x33)<<2 | (key[i]&0xCC)>>2 // Swap adjacent pairs
|
||||
key[i] = (key[i]&0x0F)<<4 | (key[i]&0xF0)>>4 // Swap the 2 halves
|
||||
}
|
||||
|
||||
// Encrypt challenge with key.
|
||||
cipher, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(challenge); i += cipher.BlockSize() {
|
||||
cipher.Encrypt(challenge[i:i+cipher.BlockSize()], challenge[i:i+cipher.BlockSize()])
|
||||
}
|
||||
|
||||
return challenge, nil
|
||||
}
|
||||
|
@ -1,32 +1,32 @@
|
||||
// Code generated by "stringer -type=SecuritySubType"; DO NOT EDIT.
|
||||
|
||||
package vnc2webm
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_SecuritySubType_name_0 = "SecSubTypeUnknown"
|
||||
_SecuritySubType_name_1 = "SecSubTypeVeNCrypt01PlainSecSubTypeVeNCrypt01TLSNoneSecSubTypeVeNCrypt01TLSVNCSecSubTypeVeNCrypt01TLSPlainSecSubTypeVeNCrypt01X509NoneSecSubTypeVeNCrypt01X509VNCSecSubTypeVeNCrypt01X509Plain"
|
||||
_SecuritySubType_name_2 = "SecSubTypeVeNCrypt02PlainSecSubTypeVeNCrypt02TLSNoneSecSubTypeVeNCrypt02TLSVNCSecSubTypeVeNCrypt02TLSPlainSecSubTypeVeNCrypt02X509NoneSecSubTypeVeNCrypt02X509VNCSecSubTypeVeNCrypt02X509Plain"
|
||||
)
|
||||
|
||||
var (
|
||||
_SecuritySubType_index_0 = [...]uint8{0, 17}
|
||||
_SecuritySubType_index_1 = [...]uint8{0, 25, 52, 78, 106, 134, 161, 190}
|
||||
_SecuritySubType_index_2 = [...]uint8{0, 25, 52, 78, 106, 134, 161, 190}
|
||||
)
|
||||
|
||||
func (i SecuritySubType) String() string {
|
||||
switch {
|
||||
case i == 0:
|
||||
return _SecuritySubType_name_0
|
||||
case 19 <= i && i <= 25:
|
||||
i -= 19
|
||||
return _SecuritySubType_name_1[_SecuritySubType_index_1[i]:_SecuritySubType_index_1[i+1]]
|
||||
case 256 <= i && i <= 262:
|
||||
i -= 256
|
||||
return _SecuritySubType_name_2[_SecuritySubType_index_2[i]:_SecuritySubType_index_2[i+1]]
|
||||
default:
|
||||
return fmt.Sprintf("SecuritySubType(%d)", i)
|
||||
}
|
||||
}
|
||||
// Code generated by "stringer -type=SecuritySubType"; DO NOT EDIT.
|
||||
|
||||
package vnc2video
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_SecuritySubType_name_0 = "SecSubTypeUnknown"
|
||||
_SecuritySubType_name_1 = "SecSubTypeVeNCrypt01PlainSecSubTypeVeNCrypt01TLSNoneSecSubTypeVeNCrypt01TLSVNCSecSubTypeVeNCrypt01TLSPlainSecSubTypeVeNCrypt01X509NoneSecSubTypeVeNCrypt01X509VNCSecSubTypeVeNCrypt01X509Plain"
|
||||
_SecuritySubType_name_2 = "SecSubTypeVeNCrypt02PlainSecSubTypeVeNCrypt02TLSNoneSecSubTypeVeNCrypt02TLSVNCSecSubTypeVeNCrypt02TLSPlainSecSubTypeVeNCrypt02X509NoneSecSubTypeVeNCrypt02X509VNCSecSubTypeVeNCrypt02X509Plain"
|
||||
)
|
||||
|
||||
var (
|
||||
_SecuritySubType_index_0 = [...]uint8{0, 17}
|
||||
_SecuritySubType_index_1 = [...]uint8{0, 25, 52, 78, 106, 134, 161, 190}
|
||||
_SecuritySubType_index_2 = [...]uint8{0, 25, 52, 78, 106, 134, 161, 190}
|
||||
)
|
||||
|
||||
func (i SecuritySubType) String() string {
|
||||
switch {
|
||||
case i == 0:
|
||||
return _SecuritySubType_name_0
|
||||
case 19 <= i && i <= 25:
|
||||
i -= 19
|
||||
return _SecuritySubType_name_1[_SecuritySubType_index_1[i]:_SecuritySubType_index_1[i+1]]
|
||||
case 256 <= i && i <= 262:
|
||||
i -= 256
|
||||
return _SecuritySubType_name_2[_SecuritySubType_index_2[i]:_SecuritySubType_index_2[i+1]]
|
||||
default:
|
||||
return fmt.Sprintf("SecuritySubType(%d)", i)
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,30 @@
|
||||
// Code generated by "stringer -type=SecurityType"; DO NOT EDIT.
|
||||
|
||||
package vnc2webm
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_SecurityType_name_0 = "SecTypeUnknownSecTypeNoneSecTypeVNC"
|
||||
_SecurityType_name_1 = "SecTypeTight"
|
||||
_SecurityType_name_2 = "SecTypeVeNCrypt"
|
||||
)
|
||||
|
||||
var (
|
||||
_SecurityType_index_0 = [...]uint8{0, 14, 25, 35}
|
||||
_SecurityType_index_1 = [...]uint8{0, 12}
|
||||
_SecurityType_index_2 = [...]uint8{0, 15}
|
||||
)
|
||||
|
||||
func (i SecurityType) String() string {
|
||||
switch {
|
||||
case 0 <= i && i <= 2:
|
||||
return _SecurityType_name_0[_SecurityType_index_0[i]:_SecurityType_index_0[i+1]]
|
||||
case i == 16:
|
||||
return _SecurityType_name_1
|
||||
case i == 19:
|
||||
return _SecurityType_name_2
|
||||
default:
|
||||
return fmt.Sprintf("SecurityType(%d)", i)
|
||||
}
|
||||
}
|
||||
// Code generated by "stringer -type=SecurityType"; DO NOT EDIT.
|
||||
|
||||
package vnc2video
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_SecurityType_name_0 = "SecTypeUnknownSecTypeNoneSecTypeVNC"
|
||||
_SecurityType_name_1 = "SecTypeTight"
|
||||
_SecurityType_name_2 = "SecTypeVeNCrypt"
|
||||
)
|
||||
|
||||
var (
|
||||
_SecurityType_index_0 = [...]uint8{0, 14, 25, 35}
|
||||
_SecurityType_index_1 = [...]uint8{0, 12}
|
||||
_SecurityType_index_2 = [...]uint8{0, 15}
|
||||
)
|
||||
|
||||
func (i SecurityType) String() string {
|
||||
switch {
|
||||
case 0 <= i && i <= 2:
|
||||
return _SecurityType_name_0[_SecurityType_index_0[i]:_SecurityType_index_0[i+1]]
|
||||
case i == 16:
|
||||
return _SecurityType_name_1
|
||||
case i == 19:
|
||||
return _SecurityType_name_2
|
||||
default:
|
||||
return fmt.Sprintf("SecurityType(%d)", i)
|
||||
}
|
||||
}
|
||||
|
684
server.go
684
server.go
@ -1,342 +1,342 @@
|
||||
package vnc2webm
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var _ Conn = (*ServerConn)(nil)
|
||||
|
||||
// Config returns config for server conn
|
||||
func (c *ServerConn) Config() interface{} {
|
||||
return c.cfg
|
||||
}
|
||||
func (c *ServerConn) GetEncInstance(typ EncodingType) Encoding {
|
||||
for _, enc := range c.encodings {
|
||||
if enc.Type() == typ {
|
||||
return enc
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Conn returns underlining server net.Conn
|
||||
func (c *ServerConn) Conn() net.Conn {
|
||||
return c.c
|
||||
}
|
||||
|
||||
// Wait waits connection to close
|
||||
func (c *ServerConn) Wait() {
|
||||
<-c.quit
|
||||
}
|
||||
|
||||
// SetEncodings ??? sets server connection encodings
|
||||
func (c *ServerConn) SetEncodings(encs []EncodingType) error {
|
||||
encodings := make(map[EncodingType]Encoding)
|
||||
for _, enc := range c.cfg.Encodings {
|
||||
encodings[enc.Type()] = enc
|
||||
}
|
||||
for _, encType := range encs {
|
||||
if enc, ok := encodings[encType]; ok {
|
||||
c.encodings = append(c.encodings, enc)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetProtoVersion ??? sets proto version
|
||||
func (c *ServerConn) SetProtoVersion(pv string) {
|
||||
c.protocol = pv
|
||||
}
|
||||
|
||||
// Flush buffered data to server conn
|
||||
func (c *ServerConn) Flush() error {
|
||||
return c.bw.Flush()
|
||||
}
|
||||
|
||||
// Close closing server conn
|
||||
func (c *ServerConn) Close() error {
|
||||
if c.quit != nil {
|
||||
close(c.quit)
|
||||
c.quit = nil
|
||||
}
|
||||
return c.c.Close()
|
||||
}
|
||||
|
||||
// Read reads data from net.Conn
|
||||
func (c *ServerConn) Read(buf []byte) (int, error) {
|
||||
return c.br.Read(buf)
|
||||
}
|
||||
|
||||
// Write writes data to net.Conn, must be Flashed
|
||||
func (c *ServerConn) Write(buf []byte) (int, error) {
|
||||
return c.bw.Write(buf)
|
||||
}
|
||||
|
||||
// ColorMap returns server connection color map
|
||||
func (c *ServerConn) ColorMap() ColorMap {
|
||||
return c.colorMap
|
||||
}
|
||||
|
||||
// SetColorMap sets connection color map
|
||||
func (c *ServerConn) SetColorMap(cm ColorMap) {
|
||||
c.colorMap = cm
|
||||
}
|
||||
|
||||
// DesktopName returns connection desktop name
|
||||
func (c *ServerConn) DesktopName() []byte {
|
||||
return c.desktopName
|
||||
}
|
||||
|
||||
// PixelFormat return connection pixel format
|
||||
func (c *ServerConn) PixelFormat() PixelFormat {
|
||||
return c.pixelFormat
|
||||
}
|
||||
|
||||
// SetDesktopName sets connection desktop name
|
||||
func (c *ServerConn) SetDesktopName(name []byte) {
|
||||
c.desktopName = name
|
||||
}
|
||||
|
||||
// SetPixelFormat sets pixel format for server conn
|
||||
func (c *ServerConn) SetPixelFormat(pf PixelFormat) error {
|
||||
c.pixelFormat = pf
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encodings returns connection encodings
|
||||
func (c *ServerConn) Encodings() []Encoding {
|
||||
return c.encodings
|
||||
}
|
||||
|
||||
// Width returns framebuffer width
|
||||
func (c *ServerConn) Width() uint16 {
|
||||
return c.fbWidth
|
||||
}
|
||||
|
||||
// Height returns framebuffer height
|
||||
func (c *ServerConn) Height() uint16 {
|
||||
return c.fbHeight
|
||||
}
|
||||
|
||||
// Protocol returns protocol
|
||||
func (c *ServerConn) Protocol() string {
|
||||
return c.protocol
|
||||
}
|
||||
|
||||
// SecurityHandler returns security handler
|
||||
func (c *ServerConn) SecurityHandler() SecurityHandler {
|
||||
return c.securityHandler
|
||||
}
|
||||
|
||||
// SetSecurityHandler sets security handler
|
||||
func (c *ServerConn) SetSecurityHandler(sechandler SecurityHandler) error {
|
||||
c.securityHandler = sechandler
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWidth sets framebuffer width
|
||||
func (c *ServerConn) SetWidth(w uint16) {
|
||||
// TODO send desktopsize pseudo encoding
|
||||
c.fbWidth = w
|
||||
}
|
||||
|
||||
// SetHeight sets framebuffer height
|
||||
func (c *ServerConn) SetHeight(h uint16) {
|
||||
// TODO send desktopsize pseudo encoding
|
||||
c.fbHeight = h
|
||||
}
|
||||
|
||||
// ServerConn underlining server conn
|
||||
type ServerConn struct {
|
||||
c net.Conn
|
||||
cfg *ServerConfig
|
||||
br *bufio.Reader
|
||||
bw *bufio.Writer
|
||||
protocol string
|
||||
// If the pixel format uses a color map, then this is the color
|
||||
// map that is used. This should not be modified directly, since
|
||||
// the data comes from the server.
|
||||
// Definition in §5 - Representation of Pixel Data.
|
||||
colorMap ColorMap
|
||||
|
||||
// Name associated with the desktop, sent from the server.
|
||||
desktopName []byte
|
||||
|
||||
// Encodings supported by the client. This should not be modified
|
||||
// directly. Instead, SetEncodings() should be used.
|
||||
encodings []Encoding
|
||||
|
||||
securityHandler SecurityHandler
|
||||
|
||||
// Height of the frame buffer in pixels, sent to the client.
|
||||
fbHeight uint16
|
||||
|
||||
// Width of the frame buffer in pixels, sent to the client.
|
||||
fbWidth uint16
|
||||
|
||||
// The pixel format associated with the connection. This shouldn't
|
||||
// be modified. If you wish to set a new pixel format, use the
|
||||
// SetPixelFormat method.
|
||||
pixelFormat PixelFormat
|
||||
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultServerHandlers uses default handlers for hanshake
|
||||
DefaultServerHandlers = []Handler{
|
||||
&DefaultServerVersionHandler{},
|
||||
&DefaultServerSecurityHandler{},
|
||||
&DefaultServerClientInitHandler{},
|
||||
&DefaultServerServerInitHandler{},
|
||||
&DefaultServerMessageHandler{},
|
||||
}
|
||||
)
|
||||
|
||||
// ServerConfig config struct
|
||||
type ServerConfig struct {
|
||||
Handlers []Handler
|
||||
SecurityHandlers []SecurityHandler
|
||||
Encodings []Encoding
|
||||
PixelFormat PixelFormat
|
||||
ColorMap ColorMap
|
||||
ClientMessageCh chan ClientMessage
|
||||
ServerMessageCh chan ServerMessage
|
||||
Messages []ClientMessage
|
||||
DesktopName []byte
|
||||
Height uint16
|
||||
Width uint16
|
||||
ErrorCh chan error
|
||||
}
|
||||
|
||||
// NewServerConn returns new Server connection fron net.Conn
|
||||
func NewServerConn(c net.Conn, cfg *ServerConfig) (*ServerConn, error) {
|
||||
return &ServerConn{
|
||||
c: c,
|
||||
br: bufio.NewReader(c),
|
||||
bw: bufio.NewWriter(c),
|
||||
cfg: cfg,
|
||||
desktopName: cfg.DesktopName,
|
||||
encodings: cfg.Encodings,
|
||||
pixelFormat: cfg.PixelFormat,
|
||||
fbWidth: cfg.Width,
|
||||
fbHeight: cfg.Height,
|
||||
quit: make(chan struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Serve serves requests from net.Listener using ServerConfig
|
||||
func Serve(ctx context.Context, ln net.Listener, cfg *ServerConfig) error {
|
||||
for {
|
||||
|
||||
c, err := ln.Accept()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
conn, err := NewServerConn(c, cfg)
|
||||
if err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
continue
|
||||
}
|
||||
|
||||
if len(cfg.Handlers) == 0 {
|
||||
cfg.Handlers = DefaultServerHandlers
|
||||
}
|
||||
|
||||
handlerLoop:
|
||||
for _, h := range cfg.Handlers {
|
||||
if err := h.Handle(conn); err != nil {
|
||||
if cfg.ErrorCh != nil {
|
||||
cfg.ErrorCh <- err
|
||||
}
|
||||
conn.Close()
|
||||
break handlerLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultServerMessageHandler default package handler
|
||||
type DefaultServerMessageHandler struct{}
|
||||
|
||||
// Handle handles messages from clients
|
||||
func (*DefaultServerMessageHandler) Handle(c Conn) error {
|
||||
cfg := c.Config().(*ServerConfig)
|
||||
var err error
|
||||
var wg sync.WaitGroup
|
||||
|
||||
defer c.Close()
|
||||
clientMessages := make(map[ClientMessageType]ClientMessage)
|
||||
for _, m := range cfg.Messages {
|
||||
clientMessages[m.Type()] = m
|
||||
}
|
||||
wg.Add(2)
|
||||
|
||||
quit := make(chan struct{})
|
||||
|
||||
// server
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-quit:
|
||||
return
|
||||
case msg := <-cfg.ServerMessageCh:
|
||||
if err = msg.Write(c); err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
if quit != nil {
|
||||
close(quit)
|
||||
quit = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// client
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-quit:
|
||||
return
|
||||
default:
|
||||
var messageType ClientMessageType
|
||||
if err := binary.Read(c, binary.BigEndian, &messageType); err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
if quit != nil {
|
||||
close(quit)
|
||||
quit = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
msg, ok := clientMessages[messageType]
|
||||
if !ok {
|
||||
cfg.ErrorCh <- fmt.Errorf("unsupported message-type: %v", messageType)
|
||||
close(quit)
|
||||
return
|
||||
}
|
||||
parsedMsg, err := msg.Read(c)
|
||||
if err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
if quit != nil {
|
||||
close(quit)
|
||||
quit = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
cfg.ClientMessageCh <- parsedMsg
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
package vnc2video
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var _ Conn = (*ServerConn)(nil)
|
||||
|
||||
// Config returns config for server conn
|
||||
func (c *ServerConn) Config() interface{} {
|
||||
return c.cfg
|
||||
}
|
||||
func (c *ServerConn) GetEncInstance(typ EncodingType) Encoding {
|
||||
for _, enc := range c.encodings {
|
||||
if enc.Type() == typ {
|
||||
return enc
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Conn returns underlining server net.Conn
|
||||
func (c *ServerConn) Conn() net.Conn {
|
||||
return c.c
|
||||
}
|
||||
|
||||
// Wait waits connection to close
|
||||
func (c *ServerConn) Wait() {
|
||||
<-c.quit
|
||||
}
|
||||
|
||||
// SetEncodings ??? sets server connection encodings
|
||||
func (c *ServerConn) SetEncodings(encs []EncodingType) error {
|
||||
encodings := make(map[EncodingType]Encoding)
|
||||
for _, enc := range c.cfg.Encodings {
|
||||
encodings[enc.Type()] = enc
|
||||
}
|
||||
for _, encType := range encs {
|
||||
if enc, ok := encodings[encType]; ok {
|
||||
c.encodings = append(c.encodings, enc)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetProtoVersion ??? sets proto version
|
||||
func (c *ServerConn) SetProtoVersion(pv string) {
|
||||
c.protocol = pv
|
||||
}
|
||||
|
||||
// Flush buffered data to server conn
|
||||
func (c *ServerConn) Flush() error {
|
||||
return c.bw.Flush()
|
||||
}
|
||||
|
||||
// Close closing server conn
|
||||
func (c *ServerConn) Close() error {
|
||||
if c.quit != nil {
|
||||
close(c.quit)
|
||||
c.quit = nil
|
||||
}
|
||||
return c.c.Close()
|
||||
}
|
||||
|
||||
// Read reads data from net.Conn
|
||||
func (c *ServerConn) Read(buf []byte) (int, error) {
|
||||
return c.br.Read(buf)
|
||||
}
|
||||
|
||||
// Write writes data to net.Conn, must be Flashed
|
||||
func (c *ServerConn) Write(buf []byte) (int, error) {
|
||||
return c.bw.Write(buf)
|
||||
}
|
||||
|
||||
// ColorMap returns server connection color map
|
||||
func (c *ServerConn) ColorMap() ColorMap {
|
||||
return c.colorMap
|
||||
}
|
||||
|
||||
// SetColorMap sets connection color map
|
||||
func (c *ServerConn) SetColorMap(cm ColorMap) {
|
||||
c.colorMap = cm
|
||||
}
|
||||
|
||||
// DesktopName returns connection desktop name
|
||||
func (c *ServerConn) DesktopName() []byte {
|
||||
return c.desktopName
|
||||
}
|
||||
|
||||
// PixelFormat return connection pixel format
|
||||
func (c *ServerConn) PixelFormat() PixelFormat {
|
||||
return c.pixelFormat
|
||||
}
|
||||
|
||||
// SetDesktopName sets connection desktop name
|
||||
func (c *ServerConn) SetDesktopName(name []byte) {
|
||||
c.desktopName = name
|
||||
}
|
||||
|
||||
// SetPixelFormat sets pixel format for server conn
|
||||
func (c *ServerConn) SetPixelFormat(pf PixelFormat) error {
|
||||
c.pixelFormat = pf
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encodings returns connection encodings
|
||||
func (c *ServerConn) Encodings() []Encoding {
|
||||
return c.encodings
|
||||
}
|
||||
|
||||
// Width returns framebuffer width
|
||||
func (c *ServerConn) Width() uint16 {
|
||||
return c.fbWidth
|
||||
}
|
||||
|
||||
// Height returns framebuffer height
|
||||
func (c *ServerConn) Height() uint16 {
|
||||
return c.fbHeight
|
||||
}
|
||||
|
||||
// Protocol returns protocol
|
||||
func (c *ServerConn) Protocol() string {
|
||||
return c.protocol
|
||||
}
|
||||
|
||||
// SecurityHandler returns security handler
|
||||
func (c *ServerConn) SecurityHandler() SecurityHandler {
|
||||
return c.securityHandler
|
||||
}
|
||||
|
||||
// SetSecurityHandler sets security handler
|
||||
func (c *ServerConn) SetSecurityHandler(sechandler SecurityHandler) error {
|
||||
c.securityHandler = sechandler
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWidth sets framebuffer width
|
||||
func (c *ServerConn) SetWidth(w uint16) {
|
||||
// TODO send desktopsize pseudo encoding
|
||||
c.fbWidth = w
|
||||
}
|
||||
|
||||
// SetHeight sets framebuffer height
|
||||
func (c *ServerConn) SetHeight(h uint16) {
|
||||
// TODO send desktopsize pseudo encoding
|
||||
c.fbHeight = h
|
||||
}
|
||||
|
||||
// ServerConn underlining server conn
|
||||
type ServerConn struct {
|
||||
c net.Conn
|
||||
cfg *ServerConfig
|
||||
br *bufio.Reader
|
||||
bw *bufio.Writer
|
||||
protocol string
|
||||
// If the pixel format uses a color map, then this is the color
|
||||
// map that is used. This should not be modified directly, since
|
||||
// the data comes from the server.
|
||||
// Definition in §5 - Representation of Pixel Data.
|
||||
colorMap ColorMap
|
||||
|
||||
// Name associated with the desktop, sent from the server.
|
||||
desktopName []byte
|
||||
|
||||
// Encodings supported by the client. This should not be modified
|
||||
// directly. Instead, SetEncodings() should be used.
|
||||
encodings []Encoding
|
||||
|
||||
securityHandler SecurityHandler
|
||||
|
||||
// Height of the frame buffer in pixels, sent to the client.
|
||||
fbHeight uint16
|
||||
|
||||
// Width of the frame buffer in pixels, sent to the client.
|
||||
fbWidth uint16
|
||||
|
||||
// The pixel format associated with the connection. This shouldn't
|
||||
// be modified. If you wish to set a new pixel format, use the
|
||||
// SetPixelFormat method.
|
||||
pixelFormat PixelFormat
|
||||
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultServerHandlers uses default handlers for hanshake
|
||||
DefaultServerHandlers = []Handler{
|
||||
&DefaultServerVersionHandler{},
|
||||
&DefaultServerSecurityHandler{},
|
||||
&DefaultServerClientInitHandler{},
|
||||
&DefaultServerServerInitHandler{},
|
||||
&DefaultServerMessageHandler{},
|
||||
}
|
||||
)
|
||||
|
||||
// ServerConfig config struct
|
||||
type ServerConfig struct {
|
||||
Handlers []Handler
|
||||
SecurityHandlers []SecurityHandler
|
||||
Encodings []Encoding
|
||||
PixelFormat PixelFormat
|
||||
ColorMap ColorMap
|
||||
ClientMessageCh chan ClientMessage
|
||||
ServerMessageCh chan ServerMessage
|
||||
Messages []ClientMessage
|
||||
DesktopName []byte
|
||||
Height uint16
|
||||
Width uint16
|
||||
ErrorCh chan error
|
||||
}
|
||||
|
||||
// NewServerConn returns new Server connection fron net.Conn
|
||||
func NewServerConn(c net.Conn, cfg *ServerConfig) (*ServerConn, error) {
|
||||
return &ServerConn{
|
||||
c: c,
|
||||
br: bufio.NewReader(c),
|
||||
bw: bufio.NewWriter(c),
|
||||
cfg: cfg,
|
||||
desktopName: cfg.DesktopName,
|
||||
encodings: cfg.Encodings,
|
||||
pixelFormat: cfg.PixelFormat,
|
||||
fbWidth: cfg.Width,
|
||||
fbHeight: cfg.Height,
|
||||
quit: make(chan struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Serve serves requests from net.Listener using ServerConfig
|
||||
func Serve(ctx context.Context, ln net.Listener, cfg *ServerConfig) error {
|
||||
for {
|
||||
|
||||
c, err := ln.Accept()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
conn, err := NewServerConn(c, cfg)
|
||||
if err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
continue
|
||||
}
|
||||
|
||||
if len(cfg.Handlers) == 0 {
|
||||
cfg.Handlers = DefaultServerHandlers
|
||||
}
|
||||
|
||||
handlerLoop:
|
||||
for _, h := range cfg.Handlers {
|
||||
if err := h.Handle(conn); err != nil {
|
||||
if cfg.ErrorCh != nil {
|
||||
cfg.ErrorCh <- err
|
||||
}
|
||||
conn.Close()
|
||||
break handlerLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultServerMessageHandler default package handler
|
||||
type DefaultServerMessageHandler struct{}
|
||||
|
||||
// Handle handles messages from clients
|
||||
func (*DefaultServerMessageHandler) Handle(c Conn) error {
|
||||
cfg := c.Config().(*ServerConfig)
|
||||
var err error
|
||||
var wg sync.WaitGroup
|
||||
|
||||
defer c.Close()
|
||||
clientMessages := make(map[ClientMessageType]ClientMessage)
|
||||
for _, m := range cfg.Messages {
|
||||
clientMessages[m.Type()] = m
|
||||
}
|
||||
wg.Add(2)
|
||||
|
||||
quit := make(chan struct{})
|
||||
|
||||
// server
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-quit:
|
||||
return
|
||||
case msg := <-cfg.ServerMessageCh:
|
||||
if err = msg.Write(c); err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
if quit != nil {
|
||||
close(quit)
|
||||
quit = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// client
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-quit:
|
||||
return
|
||||
default:
|
||||
var messageType ClientMessageType
|
||||
if err := binary.Read(c, binary.BigEndian, &messageType); err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
if quit != nil {
|
||||
close(quit)
|
||||
quit = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
msg, ok := clientMessages[messageType]
|
||||
if !ok {
|
||||
cfg.ErrorCh <- fmt.Errorf("unsupported message-type: %v", messageType)
|
||||
close(quit)
|
||||
return
|
||||
}
|
||||
parsedMsg, err := msg.Read(c)
|
||||
if err != nil {
|
||||
cfg.ErrorCh <- err
|
||||
if quit != nil {
|
||||
close(quit)
|
||||
quit = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
cfg.ClientMessageCh <- parsedMsg
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
@ -1,27 +1,27 @@
|
||||
// Code generated by "stringer -type=TightCompression"; DO NOT EDIT.
|
||||
|
||||
package vnc2webm
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_TightCompression_name_0 = "TightCompressionBasic"
|
||||
_TightCompression_name_1 = "TightCompressionFillTightCompressionJPEGTightCompressionPNG"
|
||||
)
|
||||
|
||||
var (
|
||||
_TightCompression_index_0 = [...]uint8{0, 21}
|
||||
_TightCompression_index_1 = [...]uint8{0, 20, 40, 59}
|
||||
)
|
||||
|
||||
func (i TightCompression) String() string {
|
||||
switch {
|
||||
case i == 0:
|
||||
return _TightCompression_name_0
|
||||
case 8 <= i && i <= 10:
|
||||
i -= 8
|
||||
return _TightCompression_name_1[_TightCompression_index_1[i]:_TightCompression_index_1[i+1]]
|
||||
default:
|
||||
return fmt.Sprintf("TightCompression(%d)", i)
|
||||
}
|
||||
}
|
||||
// Code generated by "stringer -type=TightCompression"; DO NOT EDIT.
|
||||
|
||||
package vnc2video
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_TightCompression_name_0 = "TightCompressionBasic"
|
||||
_TightCompression_name_1 = "TightCompressionFillTightCompressionJPEGTightCompressionPNG"
|
||||
)
|
||||
|
||||
var (
|
||||
_TightCompression_index_0 = [...]uint8{0, 21}
|
||||
_TightCompression_index_1 = [...]uint8{0, 20, 40, 59}
|
||||
)
|
||||
|
||||
func (i TightCompression) String() string {
|
||||
switch {
|
||||
case i == 0:
|
||||
return _TightCompression_name_0
|
||||
case 8 <= i && i <= 10:
|
||||
i -= 8
|
||||
return _TightCompression_name_1[_TightCompression_index_1[i]:_TightCompression_index_1[i+1]]
|
||||
default:
|
||||
return fmt.Sprintf("TightCompression(%d)", i)
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
// Code generated by "stringer -type=TightFilter"; DO NOT EDIT.
|
||||
|
||||
package vnc2webm
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _TightFilter_name = "TightFilterCopyTightFilterPaletteTightFilterGradient"
|
||||
|
||||
var _TightFilter_index = [...]uint8{0, 15, 33, 52}
|
||||
|
||||
func (i TightFilter) String() string {
|
||||
if i >= TightFilter(len(_TightFilter_index)-1) {
|
||||
return fmt.Sprintf("TightFilter(%d)", i)
|
||||
}
|
||||
return _TightFilter_name[_TightFilter_index[i]:_TightFilter_index[i+1]]
|
||||
}
|
||||
// Code generated by "stringer -type=TightFilter"; DO NOT EDIT.
|
||||
|
||||
package vnc2video
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _TightFilter_name = "TightFilterCopyTightFilterPaletteTightFilterGradient"
|
||||
|
||||
var _TightFilter_index = [...]uint8{0, 15, 33, 52}
|
||||
|
||||
func (i TightFilter) String() string {
|
||||
if i >= TightFilter(len(_TightFilter_index)-1) {
|
||||
return fmt.Sprintf("TightFilter(%d)", i)
|
||||
}
|
||||
return _TightFilter_name[_TightFilter_index[i]:_TightFilter_index[i+1]]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user