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 {
|
||||
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
|
||||
default:
|
||||
|
@@ -93,9 +93,10 @@ func main() {
|
||||
//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()
|
||||
//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