mirror of
https://github.com/amitbet/vnc2video.git
synced 2025-09-09 08:39:17 +00:00
added fbs reader with an example usage main function
This commit is contained in:
@@ -249,7 +249,9 @@ func (enc *TightEncoding) Read(c Conn, rect *Rectangle) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("problem while decoding jpeg:", err)
|
logger.Error("problem while decoding jpeg:", err)
|
||||||
}
|
}
|
||||||
enc.Image = img
|
dest := enc.Image.(draw.Image)
|
||||||
|
draw.Draw(dest, dest.Bounds(), img, image.Point{int(rect.X), int(rect.Y)}, draw.Src)
|
||||||
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
|
@@ -93,9 +93,10 @@ func main() {
|
|||||||
//jpeg.Encode(out, screenImage, nil)
|
//jpeg.Encode(out, screenImage, nil)
|
||||||
vcodec.Encode(screenImage)
|
vcodec.Encode(screenImage)
|
||||||
reqMsg := vnc.FramebufferUpdateRequest{Inc: 1, X: 0, Y: 0, Width: cc.Width(), Height: cc.Height()}
|
reqMsg := vnc.FramebufferUpdateRequest{Inc: 1, X: 0, Y: 0, Width: cc.Width(), Height: cc.Height()}
|
||||||
|
//cc.ResetAllEncodings()
|
||||||
reqMsg.Write(cc)
|
reqMsg.Write(cc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cc.Wait()
|
//cc.Wait()
|
||||||
}
|
}
|
||||||
|
61
example/file-reader/main.go
Normal file
61
example/file-reader/main.go
Normal file
@@ -0,0 +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)
|
||||||
|
}
|
||||||
|
}
|
201
fbs-connection.go
Normal file
201
fbs-connection.go
Normal file
@@ -0,0 +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
|
||||||
|
}
|
190
fbs-reader.go
Normal file
190
fbs-reader.go
Normal file
@@ -0,0 +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
|
||||||
|
}
|
Reference in New Issue
Block a user