mirror of
https://github.com/pion/mediadevices.git
synced 2025-09-27 12:52:20 +08:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0d09f7f458 | ||
![]() |
e780bdc6f9 | ||
![]() |
ff18b21629 | ||
![]() |
eaf9ff42a8 |
@@ -125,18 +125,6 @@ func TestSelectBestDriverConstraintsResultIsSetProperly(t *testing.T) {
|
||||
frameFormat: frame.FormatI420,
|
||||
frameRate: expectedProp.FrameRate,
|
||||
},
|
||||
"DifferentFrameRate": {
|
||||
width: expectedProp.Width,
|
||||
height: expectedProp.Height,
|
||||
frameFormat: expectedProp.FrameFormat,
|
||||
frameRate: expectedProp.FrameRate - 1,
|
||||
},
|
||||
"NoFrameRateConstraints": {
|
||||
width: expectedProp.Width,
|
||||
height: expectedProp.Height,
|
||||
frameFormat: expectedProp.FrameFormat,
|
||||
frameRate: -1,
|
||||
},
|
||||
}
|
||||
|
||||
for name, c := range cases {
|
||||
@@ -229,12 +217,6 @@ func TestSelectBestDriverConstraintsNoFit(t *testing.T) {
|
||||
frameFormat: frame.FormatI420,
|
||||
frameRate: expectedProp.FrameRate,
|
||||
},
|
||||
"DifferentFrameRate": {
|
||||
width: expectedProp.Width,
|
||||
height: expectedProp.Height,
|
||||
frameFormat: expectedProp.FrameFormat,
|
||||
frameRate: expectedProp.FrameRate - 1,
|
||||
},
|
||||
}
|
||||
|
||||
for name, c := range cases {
|
||||
|
@@ -81,7 +81,7 @@ Slice enc_encode(Encoder *e, Frame f, int *eresult) {
|
||||
Slice payload = {0};
|
||||
|
||||
if(e->force_key_frame == 1) {
|
||||
info.eFrameType = videoFrameTypeI;
|
||||
e->engine->ForceIntraFrame(true);
|
||||
e->force_key_frame = 0;
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,7 @@ typedef struct Encoder {
|
||||
x264_t *h;
|
||||
x264_picture_t pic_in;
|
||||
x264_param_t param;
|
||||
int force_key_frame;
|
||||
} Encoder;
|
||||
|
||||
Encoder *enc_new(x264_param_t param, char *preset, int *rc) {
|
||||
@@ -85,8 +86,14 @@ Slice enc_encode(Encoder *e, uint8_t *y, uint8_t *cb, uint8_t *cr, int *rc) {
|
||||
e->pic_in.img.plane[0] = y;
|
||||
e->pic_in.img.plane[1] = cb;
|
||||
e->pic_in.img.plane[2] = cr;
|
||||
if (e->force_key_frame) {
|
||||
e->pic_in.i_type = X264_TYPE_IDR;
|
||||
} else {
|
||||
e->pic_in.i_type = X264_TYPE_AUTO;
|
||||
}
|
||||
|
||||
int frame_size = x264_encoder_encode(e->h, &nal, &i_nal, &e->pic_in, &pic_out);
|
||||
e->force_key_frame = 0;
|
||||
Slice s = {.data_len = frame_size};
|
||||
if (frame_size <= 0) {
|
||||
*rc = ERR_ENCODE;
|
||||
|
@@ -129,7 +129,8 @@ func (e *encoder) SetBitRate(b int) error {
|
||||
}
|
||||
|
||||
func (e *encoder) ForceKeyFrame() error {
|
||||
panic("ForceKeyFrame is not implemented")
|
||||
e.engine.force_key_frame = C.int(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *encoder) Close() error {
|
||||
|
@@ -18,13 +18,32 @@ type Encoding interface {
|
||||
// the proper data.
|
||||
Read(*ClientConn, *Rectangle, io.Reader) (Encoding, error)
|
||||
}
|
||||
type CursorEncoding struct {
|
||||
}
|
||||
|
||||
func (*CursorEncoding) Type() int32 {
|
||||
return -239
|
||||
}
|
||||
func (*CursorEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) {
|
||||
size := int(rect.Height) * int(rect.Width) * int(c.PixelFormat.BPP) / 8
|
||||
pixelBytes := make([]uint8, size)
|
||||
if _, err := io.ReadFull(r, pixelBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mask := ((int(rect.Width) + 7) / 8) * int(rect.Height)
|
||||
maskBytes := make([]uint8, mask)
|
||||
if _, err := io.ReadFull(r, maskBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &CursorEncoding{}, nil
|
||||
}
|
||||
|
||||
// RawEncoding is raw pixel data sent by the server.
|
||||
//
|
||||
// See RFC 6143 Section 7.7.1
|
||||
type RawEncoding struct {
|
||||
Colors []Color
|
||||
RawPixel []uint32 //RGBA
|
||||
Colors []Color
|
||||
RawPixel []uint32 //RGBA
|
||||
}
|
||||
|
||||
func (*RawEncoding) Type() int32 {
|
||||
@@ -32,6 +51,7 @@ func (*RawEncoding) Type() int32 {
|
||||
}
|
||||
|
||||
func (*RawEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) {
|
||||
//fmt.Println("RawEncoding")
|
||||
bytesPerPixel := c.PixelFormat.BPP / 8
|
||||
pixelBytes := make([]uint8, bytesPerPixel)
|
||||
|
||||
@@ -41,7 +61,7 @@ func (*RawEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding,
|
||||
}
|
||||
|
||||
colors := make([]Color, int(rect.Height)*int(rect.Width))
|
||||
rawPixels:=make([]uint32,int(rect.Height)*int(rect.Width))
|
||||
rawPixels := make([]uint32, int(rect.Height)*int(rect.Width))
|
||||
for y := uint16(0); y < rect.Height; y++ {
|
||||
for x := uint16(0); x < rect.Width; x++ {
|
||||
if _, err := io.ReadFull(r, pixelBytes); err != nil {
|
||||
@@ -62,24 +82,30 @@ func (*RawEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding,
|
||||
color.R = uint16((rawPixel >> c.PixelFormat.RedShift) & uint32(c.PixelFormat.RedMax))
|
||||
color.G = uint16((rawPixel >> c.PixelFormat.GreenShift) & uint32(c.PixelFormat.GreenMax))
|
||||
color.B = uint16((rawPixel >> c.PixelFormat.BlueShift) & uint32(c.PixelFormat.BlueMax))
|
||||
if c.PixelFormat.BPP == 16 {
|
||||
color.B = color.B<<3 | color.B>>2
|
||||
color.G = color.G<<2 | color.G>>2
|
||||
color.R = color.R<<3 | color.R>>2
|
||||
}
|
||||
} else {
|
||||
*color = c.ColorMap[rawPixel]
|
||||
}
|
||||
rawPixels[int(y)*int(rect.Width)+int(x)]=uint32(color.B)<<16 | uint32(color.G)<<8 | uint32(color.R)
|
||||
rawPixels[int(y)*int(rect.Width)+int(x)] = uint32(0xff)<<24 | uint32(color.B)<<16 | uint32(color.G)<<8 | uint32(color.R)
|
||||
//fmt.Printf("%x %x",rawPixel,rawPixels[int(y)*int(rect.Width)+int(x)])
|
||||
}
|
||||
}
|
||||
|
||||
return &RawEncoding{colors,rawPixels}, nil
|
||||
return &RawEncoding{colors, rawPixels}, nil
|
||||
}
|
||||
|
||||
// ZlibEncoding is raw pixel data sent by the server compressed by Zlib.
|
||||
//
|
||||
// A single Zlib stream is created. There is only a single header for a framebuffer request response.
|
||||
type ZlibEncoding struct {
|
||||
Colors []Color
|
||||
RawPixel[] uint32
|
||||
ZStream *bytes.Buffer
|
||||
ZReader io.ReadCloser
|
||||
Colors []Color
|
||||
RawPixel []uint32
|
||||
ZStream *bytes.Buffer
|
||||
ZReader io.ReadCloser
|
||||
}
|
||||
|
||||
func (*ZlibEncoding) Type() int32 {
|
||||
@@ -87,6 +113,7 @@ func (*ZlibEncoding) Type() int32 {
|
||||
}
|
||||
|
||||
func (ze *ZlibEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) {
|
||||
//fmt.Println("ZlibEncoding")
|
||||
bytesPerPixel := c.PixelFormat.BPP / 8
|
||||
pixelBytes := make([]uint8, bytesPerPixel)
|
||||
|
||||
@@ -98,7 +125,6 @@ func (ze *ZlibEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encod
|
||||
// Format
|
||||
// 4 bytes | uint32 | length
|
||||
// 'length' bytes | []byte | zlibData
|
||||
|
||||
// Read zlib length
|
||||
var zipLength uint32
|
||||
err := binary.Read(r, binary.BigEndian, &zipLength)
|
||||
@@ -146,7 +172,7 @@ func (ze *ZlibEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encod
|
||||
colorReader := bytes.NewReader(colorBytes)
|
||||
|
||||
colors := make([]Color, int(rect.Height)*int(rect.Width))
|
||||
rawPixels:=make([]uint32,int(rect.Height)*int(rect.Width))
|
||||
rawPixels := make([]uint32, int(rect.Height)*int(rect.Width))
|
||||
for y := uint16(0); y < rect.Height; y++ {
|
||||
for x := uint16(0); x < rect.Width; x++ {
|
||||
if _, err := io.ReadFull(colorReader, pixelBytes); err != nil {
|
||||
@@ -167,14 +193,19 @@ func (ze *ZlibEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encod
|
||||
color.R = uint16((rawPixel >> c.PixelFormat.RedShift) & uint32(c.PixelFormat.RedMax))
|
||||
color.G = uint16((rawPixel >> c.PixelFormat.GreenShift) & uint32(c.PixelFormat.GreenMax))
|
||||
color.B = uint16((rawPixel >> c.PixelFormat.BlueShift) & uint32(c.PixelFormat.BlueMax))
|
||||
if c.PixelFormat.BPP == 16 {
|
||||
color.B = color.B<<3 | color.B>>2
|
||||
color.G = color.G<<2 | color.G>>2
|
||||
color.R = color.R<<3 | color.R>>2
|
||||
}
|
||||
} else {
|
||||
*color = c.ColorMap[rawPixel]
|
||||
}
|
||||
rawPixels[int(y)*int(rect.Width)+int(x)]=uint32(color.B)<<16 | uint32(color.G)<<8 | uint32(color.R)
|
||||
rawPixels[int(y)*int(rect.Width)+int(x)] = uint32(0xff)<<24 | uint32(color.B)<<16 | uint32(color.G)<<8 | uint32(color.R)
|
||||
}
|
||||
}
|
||||
|
||||
return &ZlibEncoding{Colors: colors,RawPixel: rawPixels}, nil
|
||||
return &ZlibEncoding{Colors: colors, RawPixel: rawPixels}, nil
|
||||
}
|
||||
|
||||
func (ze *ZlibEncoding) Close() {
|
||||
@@ -183,4 +214,4 @@ func (ze *ZlibEncoding) Close() {
|
||||
ze.ZReader.Close()
|
||||
ze.ZReader = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,13 +5,14 @@ import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/pion/mediadevices/pkg/driver/vncdriver/vnc"
|
||||
"image"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pion/mediadevices/pkg/driver/vncdriver/vnc"
|
||||
|
||||
"github.com/pion/mediadevices/pkg/frame"
|
||||
"github.com/pion/mediadevices/pkg/io/video"
|
||||
"github.com/pion/mediadevices/pkg/prop"
|
||||
@@ -32,12 +33,12 @@ func NewVnc(vncAddr string) *vncDevice {
|
||||
return &vncDevice{vncAddr: vncAddr}
|
||||
}
|
||||
func (d *vncDevice) PointerEvent(mask uint8, x, y uint16) {
|
||||
if d.vClient!=nil{
|
||||
if d.vClient != nil {
|
||||
d.vClient.PointerEvent(vnc.ButtonMask(mask), x, y)
|
||||
}
|
||||
}
|
||||
func (d *vncDevice) KeyEvent(keysym uint32, down bool) {
|
||||
if d.vClient!=nil {
|
||||
if d.vClient != nil {
|
||||
d.vClient.KeyEvent(keysym, down)
|
||||
}
|
||||
}
|
||||
@@ -49,7 +50,10 @@ func (d *vncDevice) Open() error {
|
||||
d.closed = ctx.Done()
|
||||
d.cancel = cancel
|
||||
msg := make(chan vnc.ServerMessage, 1)
|
||||
//auth:=new(vnc.PasswordAuth)
|
||||
//auth.Password="####"
|
||||
conf := vnc.ClientConfig{
|
||||
//Auth: []vnc.ClientAuth{auth},
|
||||
ServerMessageCh: msg,
|
||||
Exclusive: false,
|
||||
}
|
||||
@@ -66,6 +70,7 @@ func (d *vncDevice) Open() error {
|
||||
d.vClient.SetEncodings([]vnc.Encoding{
|
||||
&vnc.ZlibEncoding{},
|
||||
&vnc.RawEncoding{},
|
||||
&vnc.CursorEncoding{},
|
||||
})
|
||||
d.w = int(d.vClient.FrameBufferWidth)
|
||||
d.h = int(d.vClient.FrameBufferHeight)
|
||||
@@ -89,6 +94,9 @@ func (d *vncDevice) Open() error {
|
||||
for _, rect := range t.Rectangles {
|
||||
var pix []uint32
|
||||
switch t := rect.Enc.(type) {
|
||||
case *vnc.CursorEncoding:
|
||||
//ignore remote cursor messages
|
||||
continue
|
||||
case *vnc.RawEncoding:
|
||||
pix = t.RawPixel
|
||||
case *vnc.ZlibEncoding:
|
||||
@@ -97,19 +105,16 @@ func (d *vncDevice) Open() error {
|
||||
for y := int(rect.Y); y < int(rect.Height+rect.Y); y++ {
|
||||
for x := int(rect.X); x < int(rect.Width+rect.X); x++ {
|
||||
binary.LittleEndian.PutUint32(d.rawPixel[(y*d.w+x)*4:], pix[(y-int(rect.Y))*int(rect.Width)+(x-int(rect.X))])
|
||||
//BigEndian
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//time.Sleep(33 * time.Millisecond)
|
||||
d.vClient.FramebufferUpdateRequest(true, 0, 0, uint16(d.w), uint16(d.h))
|
||||
break
|
||||
default:
|
||||
|
||||
}
|
||||
case <-time.After(10 * time.Second):
|
||||
//fmt.Println("Timeout FramebufferUpdate")
|
||||
if d.vClient.FramebufferUpdateRequest(true, 0, 0, uint16(d.w), uint16(d.h)) != nil {
|
||||
d.cancel()
|
||||
return
|
||||
@@ -137,13 +142,12 @@ func (d *vncDevice) Close() error {
|
||||
|
||||
func (d *vncDevice) VideoRecord(p prop.Media) (video.Reader, error) {
|
||||
if p.FrameRate == 0 {
|
||||
p.FrameRate = 15
|
||||
p.FrameRate = 30
|
||||
}
|
||||
|
||||
tick := time.NewTicker(time.Duration(float32(time.Second) / p.FrameRate))
|
||||
d.tick = tick
|
||||
closed := d.closed
|
||||
pixs := make([]byte, d.h*d.w*4)
|
||||
r := video.ReaderFunc(func() (image.Image, func(), error) {
|
||||
select {
|
||||
case <-closed:
|
||||
@@ -153,9 +157,8 @@ func (d *vncDevice) VideoRecord(p prop.Media) (video.Reader, error) {
|
||||
}
|
||||
|
||||
<-tick.C
|
||||
copy(pixs, d.rawPixel)
|
||||
return &image.RGBA{
|
||||
Pix: pixs,
|
||||
Pix: d.rawPixel,
|
||||
Stride: 4,
|
||||
Rect: image.Rect(0, 0, d.w, d.h),
|
||||
}, func() {}, nil
|
||||
|
@@ -145,14 +145,17 @@ func (p *MediaConstraints) FitnessDistance(o Media) (float64, bool) {
|
||||
cmps.add(p.Width, o.Width)
|
||||
cmps.add(p.Height, o.Height)
|
||||
cmps.add(p.FrameFormat, o.FrameFormat)
|
||||
cmps.add(p.FrameRate, o.FrameRate)
|
||||
// The next line is comment out for now to not include framerate in the fitness function.
|
||||
// As camera.Properties does not have access to the list of available framerate at the moment,
|
||||
// no driver can be matched with a framerate constraint.
|
||||
// Note this also affect screen caputre as screen.Properties does not fill in the Framerate field.
|
||||
// cmps.add(p.FrameRate, o.FrameRate)
|
||||
cmps.add(p.SampleRate, o.SampleRate)
|
||||
cmps.add(p.Latency, o.Latency)
|
||||
cmps.add(p.ChannelCount, o.ChannelCount)
|
||||
cmps.add(p.IsBigEndian, o.IsBigEndian)
|
||||
cmps.add(p.IsFloat, o.IsFloat)
|
||||
cmps.add(p.IsInterleaved, o.IsInterleaved)
|
||||
|
||||
return cmps.fitnessDistance()
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user