mirror of
https://github.com/pion/mediadevices.git
synced 2025-10-17 06:00:39 +08:00
Optimize x11 screen capture buffer handling
This commit is contained in:
@@ -65,9 +65,11 @@ func (s *screen) VideoRecord(p prop.Media) (video.Reader, error) {
|
|||||||
}
|
}
|
||||||
s.tick = time.NewTicker(time.Duration(float32(time.Second) / p.FrameRate))
|
s.tick = time.NewTicker(time.Duration(float32(time.Second) / p.FrameRate))
|
||||||
|
|
||||||
|
var dst image.RGBA
|
||||||
|
|
||||||
r := video.ReaderFunc(func() (image.Image, error) {
|
r := video.ReaderFunc(func() (image.Image, error) {
|
||||||
<-s.tick.C
|
<-s.tick.C
|
||||||
return s.reader.Read(), nil
|
return s.reader.Read().ToRGBA(&dst), nil
|
||||||
})
|
})
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,36 @@
|
|||||||
package screen
|
package screen
|
||||||
|
|
||||||
// #cgo pkg-config: x11 xext
|
// #cgo pkg-config: x11 xext
|
||||||
|
// #include <stdint.h>
|
||||||
// #include <sys/shm.h>
|
// #include <sys/shm.h>
|
||||||
// #include <X11/Xlib.h>
|
// #include <X11/Xlib.h>
|
||||||
// #define XUTIL_DEFINE_FUNCTIONS
|
// #define XUTIL_DEFINE_FUNCTIONS
|
||||||
// #include <X11/Xutil.h>
|
// #include <X11/Xutil.h>
|
||||||
// #include <X11/extensions/XShm.h>
|
// #include <X11/extensions/XShm.h>
|
||||||
|
// void copyRGBA(void *dst, char *src, size_t l) { // 64bit aligned copy
|
||||||
|
// uint64_t *d = (uint64_t*)dst;
|
||||||
|
// uint64_t *s = (uint64_t*)src;
|
||||||
|
// l /= 8;
|
||||||
|
// for (size_t i = 0; i < l; i ++) {
|
||||||
|
// uint64_t v = *s;
|
||||||
|
// // Reorder BGR to RGB
|
||||||
|
// *d = 0xFF000000FF000000 |
|
||||||
|
// ((v >> 16) & 0xFF00000000) | (v & 0xFF0000000000) | ((v & 0xFF00000000) << 16) |
|
||||||
|
// ((v >> 16) & 0xFF) | (v & 0xFF00) | ((v & 0xFF) << 16);
|
||||||
|
// d++;
|
||||||
|
// s++;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// char *align64(char *ptr) { // return 64bit aligned pointer
|
||||||
|
// if (((size_t)ptr & 0x07) == 0) {
|
||||||
|
// return ptr;
|
||||||
|
// }
|
||||||
|
// // Clear lower 3bits to align the address to 8bytes.
|
||||||
|
// return (char*)(((size_t)ptr & (~(size_t)0x07)) + 0x08);
|
||||||
|
// }
|
||||||
|
// size_t align64ForTest(size_t ptr) {
|
||||||
|
// return (size_t)align64((char*)ptr);
|
||||||
|
// }
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -61,10 +86,7 @@ func (s *shmImage) ColorModel() color.Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *shmImage) Bounds() image.Rectangle {
|
func (s *shmImage) Bounds() image.Rectangle {
|
||||||
return image.Rectangle{
|
return image.Rect(0, 0, int(s.img.width), int(s.img.height))
|
||||||
Min: image.Point{X: 0, Y: 0},
|
|
||||||
Max: image.Point{X: int(s.img.width), Y: int(s.img.height)},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type colorFunc func() (r, g, b, a uint32)
|
type colorFunc func() (r, g, b, a uint32)
|
||||||
@@ -78,12 +100,33 @@ func (s *shmImage) At(x, y int) color.Color {
|
|||||||
b := uint32(s.b[addr]) * 0x100
|
b := uint32(s.b[addr]) * 0x100
|
||||||
g := uint32(s.b[addr+1]) * 0x100
|
g := uint32(s.b[addr+1]) * 0x100
|
||||||
r := uint32(s.b[addr+2]) * 0x100
|
r := uint32(s.b[addr+2]) * 0x100
|
||||||
a := uint32(s.b[addr+3]) * 0x100
|
|
||||||
return colorFunc(func() (_, _, _, _ uint32) {
|
return colorFunc(func() (_, _, _, _ uint32) {
|
||||||
return r, g, b, a
|
return r, g, b, 0xFFFF
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *shmImage) RGBAAt(x, y int) color.RGBA {
|
||||||
|
addr := (x + y*int(s.img.width)) * 4
|
||||||
|
b := s.b[addr]
|
||||||
|
g := s.b[addr+1]
|
||||||
|
r := s.b[addr+2]
|
||||||
|
return color.RGBA{R: r, G: g, B: b, A: 0xFF}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *shmImage) ToRGBA(dst *image.RGBA) *image.RGBA {
|
||||||
|
dst.Rect = s.Bounds()
|
||||||
|
dst.Stride = int(s.img.width) * 4
|
||||||
|
l := int(4 * s.img.width * s.img.height)
|
||||||
|
if len(dst.Pix) < l {
|
||||||
|
if cap(dst.Pix) < l {
|
||||||
|
dst.Pix = make([]uint8, l)
|
||||||
|
}
|
||||||
|
dst.Pix = dst.Pix[:l]
|
||||||
|
}
|
||||||
|
C.copyRGBA(unsafe.Pointer(&dst.Pix[0]), s.img.data, C.ulong(len(dst.Pix)))
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
func newShmImage(dp *C.Display, screen int) (*shmImage, error) {
|
func newShmImage(dp *C.Display, screen int) (*shmImage, error) {
|
||||||
cScreen := C.int(screen)
|
cScreen := C.int(screen)
|
||||||
w := int(C.XDisplayWidth(dp, cScreen))
|
w := int(C.XDisplayWidth(dp, cScreen))
|
||||||
@@ -93,7 +136,7 @@ func newShmImage(dp *C.Display, screen int) (*shmImage, error) {
|
|||||||
|
|
||||||
s := &shmImage{dp: dp}
|
s := &shmImage{dp: dp}
|
||||||
|
|
||||||
s.shm.shmid = C.shmget(C.IPC_PRIVATE, C.ulong(w*h*4), C.IPC_CREAT|0600)
|
s.shm.shmid = C.shmget(C.IPC_PRIVATE, C.ulong(w*h*4+8), C.IPC_CREAT|0600)
|
||||||
if s.shm.shmid == -1 {
|
if s.shm.shmid == -1 {
|
||||||
return nil, errors.New("failed to get shared memory")
|
return nil, errors.New("failed to get shared memory")
|
||||||
}
|
}
|
||||||
@@ -106,7 +149,7 @@ func newShmImage(dp *C.Display, screen int) (*shmImage, error) {
|
|||||||
C.shmctl(s.shm.shmid, C.IPC_RMID, nil)
|
C.shmctl(s.shm.shmid, C.IPC_RMID, nil)
|
||||||
|
|
||||||
s.img = C.XShmCreateImage(
|
s.img = C.XShmCreateImage(
|
||||||
dp, v, C.uint(depth), C.ZPixmap, s.shm.shmaddr, &s.shm, C.uint(w), C.uint(h))
|
dp, v, C.uint(depth), C.ZPixmap, C.align64(s.shm.shmaddr), &s.shm, C.uint(w), C.uint(h))
|
||||||
if s.img == nil {
|
if s.img == nil {
|
||||||
s.Free()
|
s.Free()
|
||||||
return nil, errors.New("failed to create XShm image")
|
return nil, errors.New("failed to create XShm image")
|
||||||
@@ -160,3 +203,8 @@ func (r *reader) Close() {
|
|||||||
r.img.Free()
|
r.img.Free()
|
||||||
C.XCloseDisplay(r.dp)
|
C.XCloseDisplay(r.dp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cAlign64 is fot testing
|
||||||
|
func cAlign64(ptr uintptr) uintptr {
|
||||||
|
return uintptr(C.align64ForTest(C.ulong(uintptr(ptr))))
|
||||||
|
}
|
||||||
|
17
pkg/driver/screen/x11capture_linux_test.go
Normal file
17
pkg/driver/screen/x11capture_linux_test.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package screen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAlign64(t *testing.T) {
|
||||||
|
if ret := cAlign64(0x00010008); ret != 0x00010008 {
|
||||||
|
t.Errorf("Wrong alignment, expected %x, got %x", 0x00010008, ret)
|
||||||
|
}
|
||||||
|
if ret := cAlign64(0x00010006); ret != 0x00010008 {
|
||||||
|
t.Errorf("Wrong alignment, expected %x, got %x", 0x00010008, ret)
|
||||||
|
}
|
||||||
|
if ret := cAlign64(0x00010009); ret != 0x00010010 {
|
||||||
|
t.Errorf("Wrong alignment, expected %x, got %x", 0x00010010, ret)
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user