Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using shm.GetImage().Reply() #28

Open
Jsewill opened this issue May 19, 2015 · 8 comments
Open

Using shm.GetImage().Reply() #28

Jsewill opened this issue May 19, 2015 · 8 comments

Comments

@Jsewill
Copy link

Jsewill commented May 19, 2015

This is not a bug, just a lack of understanding on my part. I have put xproto.GetImage() to good use in a project I'm working on, but I'd like to use shm.GetImage() to get an image from the X server via SHM, where should I start? I apologize if it is inappropriate for me to post this as an issue, and I'd be glad to delete it if needed.

@BurntSushi
Copy link
Owner

Honestly, I don't know (but I'd like to). I've never used shm before. If I were to investigate, I'd probably look for examples in C that use XCB. XGB should hopefully be a straight-forward translation from that.

@Jsewill
Copy link
Author

Jsewill commented May 19, 2015

Indeed, that was the first place I went looking. It seems I need to brush up on tmpfs/shm, especially as it relates to X11 in general. I'll continue looking into it and reply with any findings.

@BurntSushi
Copy link
Owner

@Jsewill yes, please do! I'm personally quite carious. Even if you're findings are, "I found this good C example but I can't translate it to Go. Can you help?" :-)

@Jsewill
Copy link
Author

Jsewill commented May 19, 2015

Well, I was able to use shm.NewSegId(), shm.CreateSegment().Reply(), and shm.GetImage().Reply() without error. This gets me a segment ID and file descriptor (I think), and has X create the image in that segment. I'm not really sure how to read it.

In my research earlier in the week, I came across an example in C from the VLC project: https://github.com/videolan/vlc/blob/master/modules/access/screen/xcb.c . This is the best example I have found yet. Perhaps I need to attach and detach the segment to and from X and my program, though I was hoping this was happening automatically.

As far as I know, SHM related stuff was explicitly left out of Golang's builtin, "syscall". Short of using a Go wrapper for the C shm related functions, do you have any insight regarding all this?

@Jsewill
Copy link
Author

Jsewill commented May 19, 2015

I've made some progress, but now I'm hitting a wall. The X server comes back with "BadIDChoice" when attempting to attach an SHM segment, whether I create the segment using shm.CreateSegment() or wrapped C functions. Any ideas?

@Jsewill
Copy link
Author

Jsewill commented May 26, 2015

After revisiting this, I figured out the proper arguements and their order, and with that X stops complaining.

The current process is as such:

  • Using low-level C functions (shmget, shmat, etc) create an SHM segment
  • Ask X to attach to that segment using shm.AttachChecked() from the xgb/shm package
  • Make the shm.GetImage().Reply() calls
  • Ask X to detach from the segment using shm.DetachChecked()
  • Attach to the segment using shmat() and retrieve the data.

I still have a problem accessing the data from the segment yet, but I'll work through that when I have more time to work on it.

@sai-prasanna
Copy link

@Jsewill Can you post the code for this?

@sai-prasanna
Copy link

sai-prasanna commented Jun 3, 2017

Here is working version, figured it out.

package main

/*
#include <sys/ipc.h>
#include <sys/shm.h>
*/
import "C"

import (
	"github.com/BurntSushi/xgb"
	"github.com/BurntSushi/xgb/shm"
	"github.com/BurntSushi/xgb/xproto"
        
        "fmt"
	"image"
	"time"
	"unsafe"
)

func main() {
	scr := newXgbShmScreen()
	for i := 0; i < 100; i++ {
		start := time.Now()
		scr.capture()
		elapsed := time.Since(start)
		fmt.Printf("%d\n", elapsed.Nanoseconds())
	}
	scr.Close()
}

type xgbShmScreen struct {
	conn    *xgb.Conn
	screen  *xproto.ScreenInfo
	shmId   int
	data    unsafe.Pointer
	shmSize int
	seg     shm.Seg
}

func newXgbShmScreen() *xgbShmScreen {
	var scr xgbShmScreen
	var err error
	scr.conn, err = xgb.NewConn()
	if err != nil || shm.Init(scr.conn) != nil {
		return nil
	}

	scr.screen = xproto.Setup(scr.conn).DefaultScreen(scr.conn)
	scr.shmSize = int(scr.screen.WidthInPixels) * int(scr.screen.HeightInPixels) * 4
	scr.shmId = int(C.shmget(C.IPC_PRIVATE, C.size_t(scr.shmSize), C.IPC_CREAT|0777))

	if scr.shmId == -1 {
		return nil
	}
	scr.data = C.shmat(C.int(scr.shmId), nil, 0)
	scr.seg, err = shm.NewSegId(scr.conn)
	if err != nil {
		return nil
	}

	shm.AttachChecked(scr.conn, scr.seg, uint32(scr.shmId), false)
	return &scr
}

func (scr *xgbShmScreen) capture() (imgData []byte, err error) {
	_, err = shm.GetImage(scr.conn, xproto.Drawable(scr.screen.Root), 0, 0, scr.screen.WidthInPixels, scr.screen.HeightInPixels, 0xffffffff, byte(xproto.ImageFormatZPixmap), scr.seg, 0).Reply()
	if err != nil {
		return nil, err
	}
	imgData = (*[1 << 30]byte)(scr.data)[:scr.shmSize:scr.shmSize]
	return imgData, nil
}

func (scr *xgbShmScreen) Close() {
	shm.Detach(scr.conn, scr.seg)
	C.shmctl(C.int(scr.shmId), C.IPC_RMID, nil)
	C.shmdt(scr.data)
	scr.conn.Close()
}

@BurntSushi

  1. Is this repo accepting contribs? will give a pull req for this as an example.
  2. Is xcb protocol frozen stable ? Would I be better off in long run using this or just using xcb via c go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants