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