I'm developing a C++ application on embedded-linux and I need to display video from camera in it. I've used gstreamer to create a window and start the video capture (because it has hardware support on tegra) with command:
system("gst-launch -e v4l2src device=\"/dev/video0\" \
! \"video/x-raw-yuv,width=320,height=240\" \
! videoflip method=counterclockwise \
! nvvidconv \
! nvxvimagesink &")
The main application on the device is running fullscreen, so I need to position this window on a specific location on the screen, so the user has the feeling it all runs in the same "window". I've managed to do this with:
XMoveWindow(display, win_video, x, y); // x, y from top left point in landscape mode!
The problem I'm facing is that the gst-launch is first displayed on 0, 0 coordinates (since it is run from command line) and then "snaps" on the correct location (programmatically) in the application. I do this by running XQueryTree to search all displayed windows and find the one with gst-launch and then move it. This takes some time and doesn't look very good, so I'm looking for better solutions.
I've tried using videobox in the gst-launch pipeline to position the video on the screen, but the problem with this is it draws a black border from 0, 0 to the video window (border-alpha=0 should solve this, but it doesn't - I think the problem is somewhere in nvvidconv or nvxvimagesink, but I have no way to know):
gst-launch -e v4l2src device="/dev/video0" ! "video/x-raw-yuv,width=320,height=240" ! videobox border-alpha=0 top=-50 left=-50 ! nvvidconv ! nvxvimagesink
The second solution was that I set my main application window as always on top, and after I find the video window, move it to position, then set main app back to normal and move the video window on top. I've tried two methods I found here to set the always on top but both didn't work. First:
Status x11_window_set_on_top (Display* display, Window xid)
{
XEvent event;
event.xclient.type = ClientMessage;
event.xclient.serial = 0;
event.xclient.send_event = True;
event.xclient.display = display;
event.xclient.window = xid;
event.xclient.message_type = XInternAtom (display, "_NET_WM_STATE", False);
event.xclient.format = 32;
event.xclient.data.l[0] = _NET_WM_STATE_ADD;
event.xclient.data.l[1] = XInternAtom (display, "_NET_WM_STATE_ABOVE", False);
event.xclient.data.l[2] = 0; //unused.
event.xclient.data.l[3] = 0;
event.xclient.data.l[4] = 0;
return XSendEvent (display,
DefaultRootWindow(display),
False,
SubstructureRedirectMask | SubstructureNotifyMask,
&event);
}
Second:
void Keep_Window_Always_Top(Display *dpy, Window w)
{
Atom stateAbove;
if (w) {
stateAbove = XInternAtom(dpy, "_NET_WM_STATE_ABOVE", False);
XChangeProperty(dpy, w, XInternAtom(dpy, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *) &stateAbove, 1);
}
}
I don't know why this doesn't work as it should.
The question is how to position the window from console command, or intercept the window programmatically before it is displayed and set it the correct coordinates, or somehow get my application to be always on top, so I can get rid of the snapping effect?
Any other suggestions are welcome.