mirror of
				https://github.com/amitbet/vncproxy.git
				synced 2025-10-31 17:22:48 +00:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			v1.1
			...
			keyframes_
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 1bce301125 | 
| @@ -2,7 +2,7 @@ package logger | |||||||
|  |  | ||||||
| import "fmt" | import "fmt" | ||||||
|  |  | ||||||
| var simpleLogger = SimpleLogger{LogLevelWarn} | var simpleLogger = SimpleLogger{LogLevelInfo} | ||||||
|  |  | ||||||
| type Logger interface { | type Logger interface { | ||||||
| 	Debug(v ...interface{}) | 	Debug(v ...interface{}) | ||||||
|   | |||||||
							
								
								
									
										199
									
								
								player/rfb-reader.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								player/rfb-reader.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | |||||||
|  | package player | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"io" | ||||||
|  | 	"os" | ||||||
|  | 	"vncproxy/common" | ||||||
|  | 	"vncproxy/encodings" | ||||||
|  | 	"vncproxy/logger" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type RfbReader struct { | ||||||
|  | 	reader           io.Reader | ||||||
|  | 	buffer           bytes.Buffer | ||||||
|  | 	currentTimestamp int | ||||||
|  | 	pixelFormat      *common.PixelFormat | ||||||
|  | 	encodings        []common.IEncoding | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /************************************************************** | ||||||
|  | ** RFB File documentation: | ||||||
|  | ** Sections: | ||||||
|  | ** 0. header: | ||||||
|  | 	* index seek position | ||||||
|  | 	* | ||||||
|  | ** 1. init message | ||||||
|  | ** 2. content | ||||||
|  | 	* frame message: | ||||||
|  | 		* size, timestamp, type, content | ||||||
|  | ** 3. index: | ||||||
|  | 	* each frame message start position, full/incremental, timestamp | ||||||
|  | 	* | ||||||
|  | ***************************************************************/ | ||||||
|  |  | ||||||
|  | func (rfb *RfbReader) CurrentTimestamp() int { | ||||||
|  | 	return rfb.currentTimestamp | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (rfb *RfbReader) Read(p []byte) (n int, err error) { | ||||||
|  | 	if rfb.buffer.Len() < len(p) { | ||||||
|  | 		seg, err := rfb.ReadSegment() | ||||||
|  |  | ||||||
|  | 		if err != nil { | ||||||
|  | 			logger.Error("rfbReader.Read: error reading rfbsegment: ", err) | ||||||
|  | 			return 0, err | ||||||
|  | 		} | ||||||
|  | 		rfb.buffer.Write(seg.bytes) | ||||||
|  | 		rfb.currentTimestamp = int(seg.timestamp) | ||||||
|  | 	} | ||||||
|  | 	return rfb.buffer.Read(p) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (rfb *RfbReader) CurrentPixelFormat() *common.PixelFormat { return rfb.pixelFormat } | ||||||
|  |  | ||||||
|  | //func (rfb *rfbReader) CurrentColorMap() *common.ColorMap       { return &common.ColorMap{} } | ||||||
|  | func (rfb *RfbReader) Encodings() []common.IEncoding { return rfb.encodings } | ||||||
|  |  | ||||||
|  | func NewRfbReader(rfbFile string) (*RfbReader, error) { | ||||||
|  |  | ||||||
|  | 	reader, err := os.OpenFile(rfbFile, os.O_RDONLY, 0644) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Error("NewrfbReader: can't open rfb file: ", rfbFile) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &RfbReader{reader: reader, | ||||||
|  | 		encodings: []common.IEncoding{ | ||||||
|  | 			&encodings.CopyRectEncoding{}, | ||||||
|  | 			&encodings.ZLibEncoding{}, | ||||||
|  | 			&encodings.ZRLEEncoding{}, | ||||||
|  | 			&encodings.CoRREEncoding{}, | ||||||
|  | 			&encodings.HextileEncoding{}, | ||||||
|  | 			&encodings.TightEncoding{}, | ||||||
|  | 			&encodings.TightPngEncoding{}, | ||||||
|  | 			&encodings.EncCursorPseudo{}, | ||||||
|  | 			&encodings.RawEncoding{}, | ||||||
|  | 			&encodings.RREEncoding{}, | ||||||
|  | 		}, | ||||||
|  | 	}, nil | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (rfb *RfbReader) ReadStartSession() (*common.ServerInit, error) { | ||||||
|  |  | ||||||
|  | 	initMsg := common.ServerInit{} | ||||||
|  | 	reader := rfb.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) | ||||||
|  | 	//.("rfb 001.000\n") | ||||||
|  | 	bytes := make([]byte, 12) | ||||||
|  | 	_, err := reader.Read(bytes) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Error("rfbReader.ReadStartSession: error reading rbs init message - rfb file Version:", err) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	//read the version message into the buffer so it will be written in the first rbs block | ||||||
|  | 	//RFB 003.008\n | ||||||
|  | 	bytes = make([]byte, 12) | ||||||
|  | 	_, err = rfb.Read(bytes) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Error("rfbReader.ReadStartSession: error reading rbs init - RFB Version: ", err) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	//push sec type and fb dimensions | ||||||
|  | 	binary.Read(rfb, binary.BigEndian, &SecTypeNone) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Error("rfbReader.ReadStartSession: error reading rbs init - SecType: ", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	//read frame buffer width, height | ||||||
|  | 	binary.Read(rfb, binary.BigEndian, &framebufferWidth) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Error("rfbReader.ReadStartSession: error reading rbs init - FBWidth: ", err) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	initMsg.FBWidth = framebufferWidth | ||||||
|  |  | ||||||
|  | 	binary.Read(rfb, binary.BigEndian, &framebufferHeight) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Error("rfbReader.ReadStartSession: error reading rbs init - FBHeight: ", err) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	initMsg.FBHeight = framebufferHeight | ||||||
|  |  | ||||||
|  | 	//read pixel format | ||||||
|  | 	pixelFormat := &common.PixelFormat{} | ||||||
|  | 	binary.Read(rfb, binary.BigEndian, pixelFormat) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Error("rfbReader.ReadStartSession: error reading rbs init - Pixelformat: ", err) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	initMsg.PixelFormat = *pixelFormat | ||||||
|  | 	//read padding | ||||||
|  | 	bytes = make([]byte, 3) | ||||||
|  | 	rfb.Read(bytes) | ||||||
|  | 	rfb.pixelFormat = pixelFormat | ||||||
|  |  | ||||||
|  | 	//read desktop name | ||||||
|  | 	var desknameLen uint32 | ||||||
|  | 	binary.Read(rfb, binary.BigEndian, &desknameLen) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Error("rfbReader.ReadStartSession: error reading rbs init - deskname Len: ", err) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	initMsg.NameLength = desknameLen | ||||||
|  |  | ||||||
|  | 	bytes = make([]byte, desknameLen) | ||||||
|  | 	rfb.Read(bytes) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Error("rfbReader.ReadStartSession: error reading rbs init - desktopName: ", err) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	initMsg.NameText = bytes | ||||||
|  |  | ||||||
|  | 	return &initMsg, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (rfb *RfbReader) ReadSegment() (*FbsSegment, error) { | ||||||
|  | 	reader := rfb.reader | ||||||
|  | 	var bytesLen uint32 | ||||||
|  |  | ||||||
|  | 	//read length | ||||||
|  | 	err := binary.Read(reader, binary.BigEndian, &bytesLen) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Error("rfbReader.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("rfbReader.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("rfbReader.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 | ||||||
|  | } | ||||||
| @@ -67,7 +67,11 @@ func main() { | |||||||
| 		}) | 		}) | ||||||
|  |  | ||||||
| 	clientConn.Listeners.AddListener(rec) | 	clientConn.Listeners.AddListener(rec) | ||||||
| 	clientConn.Listeners.AddListener(&recorder.RfbRequester{Conn: clientConn, Name: "Rfb Requester"}) | 	clientConn.Listeners.AddListener(&recorder.RfbRequester{ | ||||||
|  | 		Conn: clientConn, | ||||||
|  | 		Name: "Rfb Requester", | ||||||
|  | 		FullScreenRefreshInSec: 30, //create a full refresh key frame every 30sec for seeking | ||||||
|  | 	}) | ||||||
| 	clientConn.Connect() | 	clientConn.Connect() | ||||||
|  |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|   | |||||||
| @@ -189,6 +189,11 @@ func (r *Recorder) writeToDisk() error { | |||||||
| 	paddedSize := (bytesLen + 3) & 0x7FFFFFFC | 	paddedSize := (bytesLen + 3) & 0x7FFFFFFC | ||||||
| 	paddingSize := paddedSize - bytesLen | 	paddingSize := paddedSize - bytesLen | ||||||
|  |  | ||||||
|  | 	/// KeyFramePos, _ := r.writer.Seek(0, os.SEEK_CUR) | ||||||
|  | 	/// fi, err := r.writer.Stat() | ||||||
|  | 	/// KeyFramePos := fi.Size() + KeyFramePosInBuffer | ||||||
|  | 	// now save the KF pos in some file | ||||||
|  |  | ||||||
| 	//logger.Debugf("paddedSize=%d paddingSize=%d bytesLen=%d", paddedSize, paddingSize, bytesLen) | 	//logger.Debugf("paddedSize=%d paddingSize=%d bytesLen=%d", paddedSize, paddingSize, bytesLen) | ||||||
| 	//write buffer padded to 32bit | 	//write buffer padded to 32bit | ||||||
| 	_, err := r.buffer.WriteTo(r.writer) | 	_, err := r.buffer.WriteTo(r.writer) | ||||||
|   | |||||||
| @@ -13,6 +13,8 @@ type RfbRequester struct { | |||||||
| 	Width                  uint16 | 	Width                  uint16 | ||||||
| 	Height                 uint16 | 	Height                 uint16 | ||||||
| 	lastRequestTime        time.Time | 	lastRequestTime        time.Time | ||||||
|  | 	nextFullScreenRefresh  time.Time | ||||||
|  | 	FullScreenRefreshInSec int // refresh interval (creates keyframes) if 0, disables keyframe creation | ||||||
| } | } | ||||||
|  |  | ||||||
| func (p *RfbRequester) Consume(seg *common.RfbSegment) error { | func (p *RfbRequester) Consume(seg *common.RfbSegment) error { | ||||||
| @@ -29,6 +31,7 @@ func (p *RfbRequester) Consume(seg *common.RfbSegment) error { | |||||||
| 		p.Height = serverInitMessage.FBHeight | 		p.Height = serverInitMessage.FBHeight | ||||||
| 		p.lastRequestTime = time.Now() | 		p.lastRequestTime = time.Now() | ||||||
| 		p.Conn.FramebufferUpdateRequest(false, 0, 0, p.Width, p.Height) | 		p.Conn.FramebufferUpdateRequest(false, 0, 0, p.Width, p.Height) | ||||||
|  | 		p.nextFullScreenRefresh = time.Now().Add(time.Duration(p.FullScreenRefreshInSec) * time.Second) | ||||||
|  |  | ||||||
| 	case common.SegmentMessageStart: | 	case common.SegmentMessageStart: | ||||||
| 	case common.SegmentRectSeparator: | 	case common.SegmentRectSeparator: | ||||||
| @@ -39,7 +42,20 @@ func (p *RfbRequester) Consume(seg *common.RfbSegment) error { | |||||||
| 		// timeForNextReq := p.lastRequestTime.Unix() + minTimeBetweenReq.Nanoseconds()/1000 | 		// timeForNextReq := p.lastRequestTime.Unix() + minTimeBetweenReq.Nanoseconds()/1000 | ||||||
| 		// if seg.UpcomingObjectType == int(common.FramebufferUpdate) && time.Now().Unix() > timeForNextReq { | 		// if seg.UpcomingObjectType == int(common.FramebufferUpdate) && time.Now().Unix() > timeForNextReq { | ||||||
| 		//time.Sleep(300 * time.Millisecond) | 		//time.Sleep(300 * time.Millisecond) | ||||||
| 		p.Conn.FramebufferUpdateRequest(true, 0, 0, p.Width, p.Height) | 		p.lastRequestTime = time.Now() | ||||||
|  | 		incremental := true | ||||||
|  |  | ||||||
|  | 		if p.FullScreenRefreshInSec > 0 { | ||||||
|  | 			// if p.nextFullScreenRefresh.IsZero() { | ||||||
|  | 			// 	p.nextFullScreenRefresh = time.Now().Add(time.Duration(p.FullScreenRefreshInSec) * time.Second) | ||||||
|  | 			// } | ||||||
|  | 			if time.Now().Sub(p.nextFullScreenRefresh) <= 0 { | ||||||
|  | 				logger.Warn(">>Creating keyframe") | ||||||
|  | 				p.nextFullScreenRefresh = time.Now().Add(time.Duration(p.FullScreenRefreshInSec) * time.Second) | ||||||
|  | 				incremental = false | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		p.Conn.FramebufferUpdateRequest(incremental, 0, 0, p.Width, p.Height) | ||||||
| 		//} | 		//} | ||||||
| 	default: | 	default: | ||||||
| 	} | 	} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user