mirror of
https://github.com/amitbet/vnc2video.git
synced 2025-05-11 08:44:22 +00:00
frame rate to variable
This commit is contained in:
parent
5c4293d610
commit
4f65cf3972
@ -14,10 +14,14 @@ type VP8ImageEncoder struct {
|
||||
FFMpegBinPath string
|
||||
input io.WriteCloser
|
||||
closed bool
|
||||
Framerate int
|
||||
}
|
||||
|
||||
func (enc *VP8ImageEncoder) Init(videoFileName string) {
|
||||
fileExt := ".webm"
|
||||
if enc.Framerate == 0 {
|
||||
enc.Framerate = 12
|
||||
}
|
||||
if !strings.HasSuffix(videoFileName, fileExt) {
|
||||
videoFileName = videoFileName + fileExt
|
||||
}
|
||||
|
@ -13,10 +13,14 @@ type DV9ImageEncoder struct {
|
||||
cmd *exec.Cmd
|
||||
FFMpegBinPath string
|
||||
input io.WriteCloser
|
||||
Framerate int
|
||||
}
|
||||
|
||||
func (enc *DV9ImageEncoder) Init(videoFileName string) {
|
||||
fileExt := ".mp4"
|
||||
if enc.Framerate == 0 {
|
||||
enc.Framerate = 12
|
||||
}
|
||||
if !strings.HasSuffix(videoFileName, fileExt) {
|
||||
videoFileName = videoFileName + fileExt
|
||||
}
|
||||
|
116
encoders/huffyuv-enc.go
Normal file
116
encoders/huffyuv-enc.go
Normal file
@ -0,0 +1,116 @@
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"vnc2video/logger"
|
||||
)
|
||||
|
||||
// this is a very common loseless encoder (but produces huge files)
|
||||
type HuffYuvImageEncoder struct {
|
||||
FFMpegBinPath string
|
||||
cmd *exec.Cmd
|
||||
input io.WriteCloser
|
||||
closed bool
|
||||
Framerate int
|
||||
}
|
||||
|
||||
func (enc *HuffYuvImageEncoder) Init(videoFileName string) {
|
||||
if enc.Framerate == 0 {
|
||||
enc.Framerate = 12
|
||||
}
|
||||
|
||||
fileExt := ".avi"
|
||||
if !strings.HasSuffix(videoFileName, fileExt) {
|
||||
videoFileName = videoFileName + fileExt
|
||||
}
|
||||
//binary := "./ffmpeg"
|
||||
cmd := exec.Command(enc.FFMpegBinPath,
|
||||
"-f", "image2pipe",
|
||||
"-vcodec", "ppm",
|
||||
//"-r", strconv.Itoa(framerate),
|
||||
"-r", "12",
|
||||
|
||||
//"-re",
|
||||
//"-i", "pipe:0",
|
||||
"-an", //no audio
|
||||
//"-vsync", "2",
|
||||
///"-probesize", "10000000",
|
||||
"-y",
|
||||
|
||||
"-i", "-",
|
||||
//"–s", "640×360",
|
||||
"-vcodec", "huffyuv", //"libvpx",//"libvpx-vp9"//"libx264"
|
||||
//"-b:v", "0.33M",
|
||||
"-threads", "7",
|
||||
///"-coder", "1",
|
||||
///"-bf", "0",
|
||||
///"-me_method", "hex",
|
||||
//"-speed", "0",
|
||||
//"-lossless", "1", //for vpx
|
||||
// "-an", "-f", "webm",
|
||||
"-preset", "veryfast",
|
||||
//"-tune", "animation",
|
||||
"-maxrate", "0.5M",
|
||||
"-bufsize", "50M",
|
||||
"-g", "250",
|
||||
|
||||
//"-crf", "0", //for lossless encoding!!!!
|
||||
|
||||
//"-rc_lookahead", "16",
|
||||
//"-profile", "0",
|
||||
"-crf", "34",
|
||||
//"-qmax", "51",
|
||||
//"-qmin", "7",
|
||||
//"-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 *HuffYuvImageEncoder) Run(videoFileName string) error {
|
||||
if _, err := os.Stat(enc.FFMpegBinPath); os.IsNotExist(err) {
|
||||
logger.Error("encoder file doesn't exist in path:", enc.FFMpegBinPath)
|
||||
return errors.New("encoder file doesn't exist in path" + videoFileName)
|
||||
}
|
||||
|
||||
enc.Init(videoFileName)
|
||||
logger.Debugf("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)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (enc *HuffYuvImageEncoder) Encode(img image.Image) {
|
||||
if enc.input == nil || enc.closed {
|
||||
return
|
||||
}
|
||||
|
||||
err := encodePPM(enc.input, img)
|
||||
if err != nil {
|
||||
logger.Error("error while encoding image:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *HuffYuvImageEncoder) Close() {
|
||||
enc.closed = true
|
||||
//enc.cmd.Process.Kill()
|
||||
}
|
@ -19,6 +19,9 @@ type MJPegImageEncoder struct {
|
||||
|
||||
func (enc *MJPegImageEncoder) Init(videoFileName string) {
|
||||
fileExt := ".avi"
|
||||
if enc.Framerate == 0 {
|
||||
enc.Framerate = 12
|
||||
}
|
||||
if !strings.HasSuffix(videoFileName, fileExt) {
|
||||
videoFileName = videoFileName + fileExt
|
||||
}
|
||||
|
115
encoders/qtrle-enc.go
Normal file
115
encoders/qtrle-enc.go
Normal file
@ -0,0 +1,115 @@
|
||||
package encoders
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"vnc2video/logger"
|
||||
)
|
||||
|
||||
// QTRLEImageEncoder quick time rle is an efficient loseless codec, uses .mov extension
|
||||
type QTRLEImageEncoder struct {
|
||||
FFMpegBinPath string
|
||||
cmd *exec.Cmd
|
||||
input io.WriteCloser
|
||||
closed bool
|
||||
Framerate int
|
||||
}
|
||||
|
||||
func (enc *QTRLEImageEncoder) Init(videoFileName string) {
|
||||
fileExt := ".mov"
|
||||
if enc.Framerate == 0 {
|
||||
enc.Framerate = 12
|
||||
}
|
||||
if !strings.HasSuffix(videoFileName, fileExt) {
|
||||
videoFileName = videoFileName + fileExt
|
||||
}
|
||||
//binary := "./ffmpeg"
|
||||
cmd := exec.Command(enc.FFMpegBinPath,
|
||||
"-f", "image2pipe",
|
||||
"-vcodec", "ppm",
|
||||
//"-r", strconv.Itoa(framerate),
|
||||
"-r", "12",
|
||||
|
||||
//"-re",
|
||||
//"-i", "pipe:0",
|
||||
"-an", //no audio
|
||||
//"-vsync", "2",
|
||||
///"-probesize", "10000000",
|
||||
"-y",
|
||||
|
||||
"-i", "-",
|
||||
//"–s", "640×360",
|
||||
"-vcodec", "qtrle", //"libvpx",//"libvpx-vp9"//"libx264"
|
||||
//"-b:v", "0.33M",
|
||||
"-threads", "7",
|
||||
///"-coder", "1",
|
||||
///"-bf", "0",
|
||||
///"-me_method", "hex",
|
||||
//"-speed", "0",
|
||||
//"-lossless", "1", //for vpx
|
||||
// "-an", "-f", "webm",
|
||||
"-preset", "veryfast",
|
||||
//"-tune", "animation",
|
||||
"-maxrate", "0.5M",
|
||||
"-bufsize", "50M",
|
||||
"-g", "250",
|
||||
|
||||
//"-crf", "0", //for lossless encoding!!!!
|
||||
|
||||
//"-rc_lookahead", "16",
|
||||
//"-profile", "0",
|
||||
"-crf", "34",
|
||||
//"-qmax", "51",
|
||||
//"-qmin", "7",
|
||||
//"-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 *QTRLEImageEncoder) Run(videoFileName string) error {
|
||||
if _, err := os.Stat(enc.FFMpegBinPath); os.IsNotExist(err) {
|
||||
logger.Error("encoder file doesn't exist in path:", enc.FFMpegBinPath)
|
||||
return errors.New("encoder file doesn't exist in path" + videoFileName)
|
||||
}
|
||||
|
||||
enc.Init(videoFileName)
|
||||
logger.Debugf("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)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (enc *QTRLEImageEncoder) Encode(img image.Image) {
|
||||
if enc.input == nil || enc.closed {
|
||||
return
|
||||
}
|
||||
|
||||
err := encodePPM(enc.input, img)
|
||||
if err != nil {
|
||||
logger.Error("error while encoding image:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *QTRLEImageEncoder) Close() {
|
||||
enc.closed = true
|
||||
//enc.cmd.Process.Kill()
|
||||
}
|
@ -15,10 +15,14 @@ type X264ImageEncoder struct {
|
||||
cmd *exec.Cmd
|
||||
input io.WriteCloser
|
||||
closed bool
|
||||
Framerate int
|
||||
}
|
||||
|
||||
func (enc *X264ImageEncoder) Init(videoFileName string) {
|
||||
fileExt := ".mp4"
|
||||
if enc.Framerate == 0 {
|
||||
enc.Framerate = 12
|
||||
}
|
||||
if !strings.HasSuffix(videoFileName, fileExt) {
|
||||
videoFileName = videoFileName + fileExt
|
||||
}
|
||||
|
@ -367,9 +367,8 @@ func (enc *TightEncoding) drawTightPalette(rect *Rectangle, palette color.Palett
|
||||
enc.Image.Set(int(rect.X)+x, int(rect.Y)+y, palette[palettePos])
|
||||
//logger.Tracef("(%d,%d): pos: %d col:%d", int(rect.X)+j, int(rect.Y)+i, palettePos, palette[palettePos])
|
||||
}
|
||||
// if bitPos != 7 {
|
||||
// bytePos++
|
||||
// }
|
||||
|
||||
// reset bit alignment to first bit in byte (msb)
|
||||
bitPos = 7
|
||||
}
|
||||
|
||||
|
@ -3,12 +3,18 @@ package vnc2video
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
BlockWidth = 16
|
||||
BlockHeight = 16
|
||||
)
|
||||
|
||||
type VncCanvas struct {
|
||||
draw.Image
|
||||
//DisplayBuff draw.Image
|
||||
@ -20,6 +26,7 @@ type VncCanvas struct {
|
||||
CursorOffset *image.Point
|
||||
CursorLocation *image.Point
|
||||
DrawCursor bool
|
||||
Changed map[string]bool
|
||||
}
|
||||
|
||||
func NewVncCanvas(width, height int) *VncCanvas {
|
||||
@ -33,6 +40,23 @@ func NewVncCanvas(width, height int) *VncCanvas {
|
||||
return &canvas
|
||||
}
|
||||
|
||||
func (c *VncCanvas) SetChanged(rect *Rectangle) {
|
||||
if c.Changed == nil {
|
||||
c.Changed = make(map[string]bool)
|
||||
}
|
||||
for x := int(rect.X) / BlockWidth; x*BlockWidth < int(rect.X+rect.Width); x++ {
|
||||
for y := int(rect.Y) / BlockHeight; y*BlockHeight < int(rect.Y+rect.Height); y++ {
|
||||
key := fmt.Sprintf("%d,%d", x, y)
|
||||
//fmt.Println("setting block: ", key)
|
||||
c.Changed[key] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *VncCanvas) Reset(rect *Rectangle) {
|
||||
c.Changed = nil
|
||||
}
|
||||
|
||||
func (c *VncCanvas) RemoveCursor() image.Image {
|
||||
if c.Cursor == nil || c.CursorLocation == nil {
|
||||
return c.Image
|
||||
|
15
encoding_util_test.go
Normal file
15
encoding_util_test.go
Normal file
@ -0,0 +1,15 @@
|
||||
package vnc2video
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSetChanged(t *testing.T) {
|
||||
canvas := &VncCanvas{}
|
||||
rect := &Rectangle{X: 1, Y: 1, Width: 1024, Height: 64}
|
||||
canvas.SetChanged(rect)
|
||||
if canvas.Changed["64,0"] == false ||
|
||||
canvas.Changed["64,1"] == false ||
|
||||
canvas.Changed["64,4"] == false {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user