mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 08:25:38 +00:00
parent
6f1d3862cd
commit
d078f7db76
@ -33,28 +33,21 @@ when the timer triggers.
|
|||||||
Usage webcam model attached to the xHCI model
|
Usage webcam model attached to the xHCI model
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
If the xHCI model is enabled and used, then the webcam device model can be
|
If the xHCI model is enabled and used, the webcam device model can be
|
||||||
enabled by specifying a XML node in the config ROM:
|
enabled by specifying a XML node in the config ROM.
|
||||||
|
|
||||||
<config ...>
|
<config ...>
|
||||||
...
|
...
|
||||||
<webcam width="640" height="480" fps="15" vertical_flip="false" screen_size="false" report="false"/>
|
<webcam width="640" height="480" fps="15" vertical_flip="false" screen_size="false"/>
|
||||||
...
|
...
|
||||||
</config>
|
</config>
|
||||||
|
|
||||||
The webcam attributes are optional. The values shown above, are the default ones
|
Webcam attributes are optional, default values are depicted above. The model
|
||||||
when a attribute is not specified. When the webcam node is specified, the model
|
supports YUV2 and BGR3 image formats reported to the guest via bFormatIndex.
|
||||||
will open and will use a Genode capture session to obtain the
|
It requests a Genode capture session to obtain the frames in the rate as
|
||||||
frames in the rate as specified by the frame per secondes (fps) attribute. The
|
specified by the 'fps' (frame per seconds) attribute. The 'vertical_flip'
|
||||||
'vertical_flip' attribute specifies, whether the frames are shown flipped
|
attribute specifies, whether the frames are shown flipped vertically for
|
||||||
for guests. For Windows guests the value has to be false, for Linux guests
|
guests. For Windows guests the value has to be false, for Linux guests true.
|
||||||
true. The format supported by the model is YUV2 or BGR3. If the 'screen_size' is set
|
If the 'screen_size' attribute is set to true, the webcam model configures the
|
||||||
to true, the webcam model will try to use the screen size as provided by the
|
initial screen size to the size provided by the capture session. If the screen
|
||||||
capture session. If the screen size is invalid (e.g. 0x0), the attribute
|
size is invalid (e.g. 0x0), 'width' and 'height' will be used as fallback.
|
||||||
values of 'width' and 'height' will be used instead. If the 'report' attribute
|
|
||||||
is set, a report will be generated whenever the guests starts/ends capturing and
|
|
||||||
if the capturing format choosen by the guest changes,
|
|
||||||
|
|
||||||
<capture enabled="..." format="BGR3"/>
|
|
||||||
or
|
|
||||||
<capture enabled="..." format="YUV2"/>
|
|
||||||
|
@ -435,18 +435,6 @@ static void usb_webcam_handle_reset(USBDevice *dev)
|
|||||||
usb_webcam_init_state(state);
|
usb_webcam_init_state(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_webcam_capture_state_changed(bool const on)
|
|
||||||
{
|
|
||||||
char const * format = "unknown";
|
|
||||||
|
|
||||||
if (vs_commit_state.bFormatIndex == DEVICE_VS_FORMAT_BGR)
|
|
||||||
format = "BGR3";
|
|
||||||
else if (vs_commit_state.bFormatIndex == DEVICE_VS_FORMAT_YUV)
|
|
||||||
format = "YUY2";
|
|
||||||
|
|
||||||
capture_state_changed(on, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usb_webcam_setup_packet(USBWebcamState * const state, USBPacket * const p)
|
static void usb_webcam_setup_packet(USBWebcamState * const state, USBPacket * const p)
|
||||||
{
|
{
|
||||||
unsigned packet_size = vs_commit_state.dwMaxPayLoadTransferSize;
|
unsigned packet_size = vs_commit_state.dwMaxPayLoadTransferSize;
|
||||||
@ -458,7 +446,7 @@ static void usb_webcam_setup_packet(USBWebcamState * const state, USBPacket * co
|
|||||||
if (packet_size <= sizeof(header)) {
|
if (packet_size <= sizeof(header)) {
|
||||||
p->status = USB_RET_STALL;
|
p->status = USB_RET_STALL;
|
||||||
if (state->capture)
|
if (state->capture)
|
||||||
usb_webcam_capture_state_changed(false);
|
capture_state_changed(false);
|
||||||
usb_webcam_init_state(state);
|
usb_webcam_init_state(state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -466,7 +454,7 @@ static void usb_webcam_setup_packet(USBWebcamState * const state, USBPacket * co
|
|||||||
if (state->bytes_frame >= max_frame_size(active_format())) {
|
if (state->bytes_frame >= max_frame_size(active_format())) {
|
||||||
p->status = USB_RET_STALL;
|
p->status = USB_RET_STALL;
|
||||||
if (state->capture)
|
if (state->capture)
|
||||||
usb_webcam_capture_state_changed(false);
|
capture_state_changed(false);
|
||||||
usb_webcam_init_state(state);
|
usb_webcam_init_state(state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -478,7 +466,7 @@ static void usb_webcam_setup_packet(USBWebcamState * const state, USBPacket * co
|
|||||||
/* check for capture state change */
|
/* check for capture state change */
|
||||||
if (!state->capture) {
|
if (!state->capture) {
|
||||||
state->capture = true;
|
state->capture = true;
|
||||||
usb_webcam_capture_state_changed(state->capture);
|
capture_state_changed(state->capture);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state->timer_active)
|
if (!state->timer_active)
|
||||||
@ -543,7 +531,7 @@ static void webcam_timeout(void *opague)
|
|||||||
if (state->delay_packet || (state->watchdog && state->watchdog >= fps)) {
|
if (state->delay_packet || (state->watchdog && state->watchdog >= fps)) {
|
||||||
state->capture = false;
|
state->capture = false;
|
||||||
state->delay_packet = false;
|
state->delay_packet = false;
|
||||||
usb_webcam_capture_state_changed(state->capture);
|
capture_state_changed(state->capture);
|
||||||
} else {
|
} else {
|
||||||
state->watchdog ++;
|
state->watchdog ++;
|
||||||
webcam_start_timer(state);
|
webcam_start_timer(state);
|
||||||
@ -625,7 +613,7 @@ static void usb_webcam_handle_control(USBDevice * const dev,
|
|||||||
if (state->capture) {
|
if (state->capture) {
|
||||||
state->capture = false;
|
state->capture = false;
|
||||||
state->delay_packet = false;
|
state->delay_packet = false;
|
||||||
usb_webcam_capture_state_changed(state->capture);
|
capture_state_changed(state->capture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stall = false;
|
stall = false;
|
||||||
@ -689,7 +677,7 @@ static void usb_webcam_handle_control(USBDevice * const dev,
|
|||||||
|
|
||||||
if (notify) {
|
if (notify) {
|
||||||
USBWebcamState *state = USB_WEBCAM(dev);
|
USBWebcamState *state = USB_WEBCAM(dev);
|
||||||
usb_webcam_capture_state_changed(state->capture);
|
capture_state_changed(state->capture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -719,7 +707,7 @@ static void usb_webcam_handle_data(USBDevice *dev, USBPacket *p)
|
|||||||
if (!p->ep || p->ep->nr != DEVICE_EP_ID) {
|
if (!p->ep || p->ep->nr != DEVICE_EP_ID) {
|
||||||
p->status = USB_RET_STALL;
|
p->status = USB_RET_STALL;
|
||||||
if (state->capture)
|
if (state->capture)
|
||||||
usb_webcam_capture_state_changed(false);
|
capture_state_changed(false);
|
||||||
usb_webcam_init_state(state);
|
usb_webcam_init_state(state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -727,7 +715,7 @@ static void usb_webcam_handle_data(USBDevice *dev, USBPacket *p)
|
|||||||
default:
|
default:
|
||||||
p->status = USB_RET_STALL;
|
p->status = USB_RET_STALL;
|
||||||
if (state->capture)
|
if (state->capture)
|
||||||
usb_webcam_capture_state_changed(false);
|
capture_state_changed(false);
|
||||||
usb_webcam_init_state(state);
|
usb_webcam_init_state(state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,6 @@ struct webcam_config {
|
|||||||
extern void webcam_backend_config(struct webcam_config *);
|
extern void webcam_backend_config(struct webcam_config *);
|
||||||
extern bool capture_bgr_frame(void * pixel);
|
extern bool capture_bgr_frame(void * pixel);
|
||||||
extern bool capture_yuv_frame(void * pixel);
|
extern bool capture_yuv_frame(void * pixel);
|
||||||
extern void capture_state_changed(bool on, char const * format);
|
extern void capture_state_changed(bool on);
|
||||||
|
|
||||||
#endif /* _WEBCAM_BACKEND_H_ */
|
#endif /* _WEBCAM_BACKEND_H_ */
|
||||||
|
@ -30,28 +30,27 @@ using namespace Genode;
|
|||||||
struct Capture_webcam
|
struct Capture_webcam
|
||||||
{
|
{
|
||||||
Env &_env;
|
Env &_env;
|
||||||
Capture::Connection _capture { _env, "webcam" };
|
|
||||||
Gui::Area const _area;
|
Gui::Area const _area;
|
||||||
bool const _vflip;
|
bool const _vflip;
|
||||||
uint8_t const _fps;
|
uint8_t const _fps;
|
||||||
bool _force_update { false };
|
bool _force_update { false };
|
||||||
Attached_dataspace _ds { _env.rm(), _capture.dataspace() };
|
|
||||||
Constructible<Reporter> _reporter { };
|
|
||||||
|
|
||||||
|
Constructible<Capture::Connection> _capture;
|
||||||
|
Constructible<Attached_dataspace> _ds;
|
||||||
|
|
||||||
Gui::Area setup_area(Gui::Area const area_in, bool const auto_area)
|
Gui::Area _setup_area(Gui::Area const area_in, bool const auto_area)
|
||||||
{
|
{
|
||||||
Gui::Area area = area_in;
|
Gui::Area area = area_in;
|
||||||
|
|
||||||
if (auto_area) {
|
if (auto_area) {
|
||||||
area = _capture.screen_size();
|
Capture::Connection probe { _env, "webcam" };
|
||||||
|
|
||||||
|
area = probe.screen_size();
|
||||||
|
|
||||||
if (!area.valid())
|
if (!area.valid())
|
||||||
area = area_in;
|
area = area_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* request setup of dataspace by server */
|
|
||||||
_capture.buffer(area);
|
|
||||||
return area;
|
return area;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +61,7 @@ struct Capture_webcam
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool changed = _force_update;
|
bool changed = _force_update;
|
||||||
_capture.capture_at(Capture::Point(0, 0)).for_each_rect([&](auto) {
|
_capture->capture_at(Capture::Point(0, 0)).for_each_rect([&](auto) {
|
||||||
changed = true; });
|
changed = true; });
|
||||||
|
|
||||||
if (!changed)
|
if (!changed)
|
||||||
@ -71,7 +70,7 @@ struct Capture_webcam
|
|||||||
int const src_stride_argb = _area.w() * 4;
|
int const src_stride_argb = _area.w() * 4;
|
||||||
int const dst_stride_yuy2 = _area.w() * 2;
|
int const dst_stride_yuy2 = _area.w() * 2;
|
||||||
|
|
||||||
libyuv::ARGBToYUY2(_ds.local_addr<uint8_t>(), src_stride_argb,
|
libyuv::ARGBToYUY2(_ds->local_addr<uint8_t>(), src_stride_argb,
|
||||||
reinterpret_cast<uint8_t*>(frame), dst_stride_yuy2,
|
reinterpret_cast<uint8_t*>(frame), dst_stride_yuy2,
|
||||||
_area.w(), _area.h());
|
_area.w(), _area.h());
|
||||||
|
|
||||||
@ -89,7 +88,7 @@ struct Capture_webcam
|
|||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
uint8_t * const bgr = reinterpret_cast<uint8_t *>(frame);
|
uint8_t * const bgr = reinterpret_cast<uint8_t *>(frame);
|
||||||
Pixel_rgb888 const * const data = _ds.local_addr<Pixel_rgb888>();
|
Pixel_rgb888 const * const data = _ds->local_addr<Pixel_rgb888>();
|
||||||
|
|
||||||
auto const &update_fn = ([&](auto &rect) {
|
auto const &update_fn = ([&](auto &rect) {
|
||||||
changed = true;
|
changed = true;
|
||||||
@ -110,52 +109,47 @@ struct Capture_webcam
|
|||||||
/* update whole frame */
|
/* update whole frame */
|
||||||
_force_update = false;
|
_force_update = false;
|
||||||
Rect const whole(Point(0,0), _area);
|
Rect const whole(Point(0,0), _area);
|
||||||
_capture.capture_at(Capture::Point(0, 0));
|
_capture->capture_at(Capture::Point(0, 0));
|
||||||
update_fn(whole);
|
update_fn(whole);
|
||||||
} else
|
} else
|
||||||
_capture.capture_at(Capture::Point(0, 0)).for_each_rect(update_fn);
|
_capture->capture_at(Capture::Point(0, 0)).for_each_rect(update_fn);
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void capture_state_changed(bool on, char const * format)
|
void capture_state_changed(bool on)
|
||||||
{
|
{
|
||||||
/* next time update whole frame due to format changes or on/off */
|
/* next time update whole frame due to format changes or on/off */
|
||||||
_force_update = true;
|
_force_update = true;
|
||||||
|
|
||||||
if (!_reporter.constructed())
|
/* construct/destruct capture connection and dataspace */
|
||||||
return;
|
if (on) {
|
||||||
|
_capture.construct(_env, "webcam");
|
||||||
Reporter::Xml_generator xml(*_reporter, [&] () {
|
_capture->buffer(_area);
|
||||||
xml.attribute("enabled", on);
|
_ds.construct(_env.rm(), _capture->dataspace());
|
||||||
xml.attribute("format", format);
|
} else {
|
||||||
});
|
_ds.destruct();
|
||||||
|
_capture.destruct();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Capture_webcam (Env &env, Gui::Area area, bool auto_area, bool flip,
|
Capture_webcam(Env &env, Gui::Area area, bool auto_area, bool flip, uint8_t fps)
|
||||||
uint8_t fps, bool report)
|
|
||||||
:
|
:
|
||||||
_env(env),
|
_env(env),
|
||||||
_area(setup_area(area, auto_area)),
|
_area(_setup_area(area, auto_area)),
|
||||||
_vflip(flip),
|
_vflip(flip),
|
||||||
_fps(fps)
|
_fps(fps)
|
||||||
{
|
{
|
||||||
if (report) {
|
|
||||||
_reporter.construct(_env, "capture");
|
|
||||||
_reporter->enabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
log("USB webcam ", _area, " fps=", _fps, " vertical_flip=",
|
log("USB webcam ", _area, " fps=", _fps, " vertical_flip=",
|
||||||
_vflip ? "yes" : "no",
|
_vflip ? "yes" : "no");
|
||||||
" report=", _reporter.constructed() ? "enabled" : "disabled");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static Genode::Constructible<Capture_webcam> capture;
|
static Genode::Constructible<Capture_webcam> capture;
|
||||||
|
|
||||||
extern "C" void capture_state_changed(bool on, char const * format)
|
extern "C" void capture_state_changed(bool on)
|
||||||
{
|
{
|
||||||
capture->capture_state_changed(on, format);
|
capture->capture_state_changed(on);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" bool capture_bgr_frame(void * pixel)
|
extern "C" bool capture_bgr_frame(void * pixel)
|
||||||
@ -187,8 +181,7 @@ extern "C" void _type_init_host_webcam_register_types(Env &env,
|
|||||||
webcam.attribute_value("height", 480u)),
|
webcam.attribute_value("height", 480u)),
|
||||||
webcam.attribute_value("screen_size", false),
|
webcam.attribute_value("screen_size", false),
|
||||||
webcam.attribute_value("vertical_flip", false),
|
webcam.attribute_value("vertical_flip", false),
|
||||||
webcam.attribute_value("fps", 15u),
|
webcam.attribute_value("fps", 15u));
|
||||||
webcam.attribute_value("report", false));
|
|
||||||
|
|
||||||
/* register webcam model, which will call webcam_backend_config() */
|
/* register webcam model, which will call webcam_backend_config() */
|
||||||
_type_init_usb_webcam_register_types();
|
_type_init_usb_webcam_register_types();
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
<file_system label="shared"/>
|
<file_system label="shared"/>
|
||||||
<nic/>
|
<nic/>
|
||||||
<capture/>
|
<capture/>
|
||||||
<report label="capture"/>
|
|
||||||
<gui/>
|
<gui/>
|
||||||
<rom label="capslock"/>
|
<rom label="capslock"/>
|
||||||
<report label="shape"/>
|
<report label="shape"/>
|
||||||
@ -67,7 +66,7 @@
|
|||||||
<fs writeable="yes"/>
|
<fs writeable="yes"/>
|
||||||
</vfs>
|
</vfs>
|
||||||
<libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc"/>
|
<libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc"/>
|
||||||
<webcam vertical_flip="true" fps="30" report="true" screen_size="false" width="640" height="480"/>
|
<webcam vertical_flip="true" fps="30" screen_size="false" width="640" height="480"/>
|
||||||
</config>
|
</config>
|
||||||
<route>
|
<route>
|
||||||
<service name="Audio_out"> <parent/> </service>
|
<service name="Audio_out"> <parent/> </service>
|
||||||
@ -81,7 +80,6 @@
|
|||||||
<service name="Report" label="shape"> <parent label="shape"/> </service>
|
<service name="Report" label="shape"> <parent label="shape"/> </service>
|
||||||
<service name="ROM" label="clipboard"> <parent label="clipboard"/> </service>
|
<service name="ROM" label="clipboard"> <parent label="clipboard"/> </service>
|
||||||
<service name="Report" label="clipboard"> <parent label="clipboard"/> </service>
|
<service name="Report" label="clipboard"> <parent label="clipboard"/> </service>
|
||||||
<service name="Report" label="capture"> <parent label="capture"/> </service>
|
|
||||||
<service name="Gui"> <parent label=""/> </service>
|
<service name="Gui"> <parent label=""/> </service>
|
||||||
<any-service> <parent/> </any-service>
|
<any-service> <parent/> </any-service>
|
||||||
</route>
|
</route>
|
||||||
|
@ -280,7 +280,7 @@ for { set i 1} { $i <= $use_vms } { incr i} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
append_if [expr $use_webcam] config_of_app {
|
append_if [expr $use_webcam] config_of_app {
|
||||||
<webcam vertical_flip="} $webcam_vflip {" fps="15" report="false" screen_size="false" width="640" height="480" />}
|
<webcam vertical_flip="} $webcam_vflip {" fps="15" screen_size="false" width="640" height="480"/>}
|
||||||
|
|
||||||
append config_of_app {
|
append config_of_app {
|
||||||
<libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc" pipe="/pipe"/>
|
<libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc" pipe="/pipe"/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user