mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-04 00:20:55 +00:00
qemu-usb: reduce cpu load by webcam model
if no new frame is available for capturing Fixes #4078 #4196
This commit is contained in:
parent
ff452619e3
commit
4aa99fd1a9
@ -42,6 +42,7 @@ typedef struct USBWebcamState {
|
|||||||
uint8_t frame_toggle_bit;
|
uint8_t frame_toggle_bit;
|
||||||
bool delay_packet;
|
bool delay_packet;
|
||||||
bool capture;
|
bool capture;
|
||||||
|
bool timer_active;
|
||||||
uint8_t watchdog;
|
uint8_t watchdog;
|
||||||
uint8_t *frame_pixel;
|
uint8_t *frame_pixel;
|
||||||
} USBWebcamState;
|
} USBWebcamState;
|
||||||
@ -202,8 +203,8 @@ static struct {
|
|||||||
uint8_t bpp;
|
uint8_t bpp;
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
uint16_t height;
|
uint16_t height;
|
||||||
uint32_t interval; /* dwFrameInterval */
|
uint32_t interval; /* dwFrameInterval in 100ns units */
|
||||||
void (*capture)(void *);
|
bool (*capture)(void *);
|
||||||
} formats [2];
|
} formats [2];
|
||||||
|
|
||||||
static unsigned active_format()
|
static unsigned active_format()
|
||||||
@ -400,7 +401,8 @@ static Property webcam_properties[] = {
|
|||||||
|
|
||||||
static void webcam_start_timer(USBWebcamState * const state)
|
static void webcam_start_timer(USBWebcamState * const state)
|
||||||
{
|
{
|
||||||
int64_t const now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
state->timer_active = true;
|
||||||
|
uint64_t const now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
timer_mod(state->timer, now_ns + 100ull * formats[active_format()].interval);
|
timer_mod(state->timer, now_ns + 100ull * formats[active_format()].interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,6 +422,7 @@ static void usb_webcam_init_state(USBWebcamState *state)
|
|||||||
state->delay_packet = false;
|
state->delay_packet = false;
|
||||||
state->capture = false;
|
state->capture = false;
|
||||||
state->watchdog = 0;
|
state->watchdog = 0;
|
||||||
|
state->timer_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_webcam_handle_reset(USBDevice *dev)
|
static void usb_webcam_handle_reset(USBDevice *dev)
|
||||||
@ -448,7 +451,6 @@ static void usb_webcam_setup_packet(USBWebcamState * const state, USBPacket * co
|
|||||||
{
|
{
|
||||||
unsigned packet_size = vs_commit_state.dwMaxPayLoadTransferSize;
|
unsigned packet_size = vs_commit_state.dwMaxPayLoadTransferSize;
|
||||||
struct payload_header header = { .length = 0, .bfh = 0 };
|
struct payload_header header = { .length = 0, .bfh = 0 };
|
||||||
bool start_timer = !state->bytes_frame;
|
|
||||||
|
|
||||||
if (p->iov.size < packet_size)
|
if (p->iov.size < packet_size)
|
||||||
packet_size = p->iov.size;
|
packet_size = p->iov.size;
|
||||||
@ -470,19 +472,16 @@ static void usb_webcam_setup_packet(USBWebcamState * const state, USBPacket * co
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* reset capture watchdog */
|
/* reset capture watchdog */
|
||||||
if (state->watchdog) {
|
if (state->watchdog)
|
||||||
state->watchdog = 0;
|
state->watchdog = 0;
|
||||||
start_timer = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check for capture state change */
|
/* check for capture state change */
|
||||||
if (!state->capture) {
|
if (!state->capture) {
|
||||||
state->capture = true;
|
state->capture = true;
|
||||||
start_timer = true;
|
|
||||||
usb_webcam_capture_state_changed(state->capture);
|
usb_webcam_capture_state_changed(state->capture);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start_timer)
|
if (!state->timer_active)
|
||||||
webcam_start_timer(state);
|
webcam_start_timer(state);
|
||||||
|
|
||||||
/* payload header */
|
/* payload header */
|
||||||
@ -533,6 +532,8 @@ static void webcam_timeout(void *opague)
|
|||||||
USBDevice *dev = (USBDevice *)opague;
|
USBDevice *dev = (USBDevice *)opague;
|
||||||
USBWebcamState *state = USB_WEBCAM(opague);
|
USBWebcamState *state = USB_WEBCAM(opague);
|
||||||
|
|
||||||
|
state->timer_active = false;
|
||||||
|
|
||||||
if (!state->capture)
|
if (!state->capture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -550,14 +551,18 @@ static void webcam_timeout(void *opague)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* start timer before requesting new frame to account the cpu time */
|
||||||
|
webcam_start_timer(state);
|
||||||
|
|
||||||
|
/* request next frame pixel buffer */
|
||||||
|
if (!formats[active_format()].capture(state->frame_pixel))
|
||||||
|
return;
|
||||||
|
|
||||||
USBPacket *p = state->delayed_packet;
|
USBPacket *p = state->delayed_packet;
|
||||||
|
|
||||||
state->delayed_packet = 0;
|
state->delayed_packet = 0;
|
||||||
state->delay_packet = false;
|
state->delay_packet = false;
|
||||||
|
|
||||||
/* request next frame pixel buffer */
|
|
||||||
formats[active_format()].capture(state->frame_pixel);
|
|
||||||
|
|
||||||
/* continue usb transmission with new frame */
|
/* continue usb transmission with new frame */
|
||||||
usb_webcam_setup_packet(state, p);
|
usb_webcam_setup_packet(state, p);
|
||||||
if (p->status == USB_RET_SUCCESS)
|
if (p->status == USB_RET_SUCCESS)
|
||||||
|
@ -18,8 +18,8 @@ struct webcam_config {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern void webcam_backend_config(struct webcam_config *);
|
extern void webcam_backend_config(struct webcam_config *);
|
||||||
extern void capture_bgr_frame(void * pixel);
|
extern bool capture_bgr_frame(void * pixel);
|
||||||
extern void 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, char const * format);
|
||||||
|
|
||||||
#endif /* _WEBCAM_BACKEND_H_ */
|
#endif /* _WEBCAM_BACKEND_H_ */
|
||||||
|
@ -34,6 +34,7 @@ struct Capture_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 };
|
||||||
Attached_dataspace _ds { _env.rm(), _capture.dataspace() };
|
Attached_dataspace _ds { _env.rm(), _capture.dataspace() };
|
||||||
Constructible<Reporter> _reporter { };
|
Constructible<Reporter> _reporter { };
|
||||||
|
|
||||||
@ -54,9 +55,18 @@ struct Capture_webcam
|
|||||||
return area;
|
return area;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_yuv(void *frame)
|
|
||||||
|
bool update_yuv(void *frame)
|
||||||
{
|
{
|
||||||
_capture.capture_at(Capture::Point(0, 0));
|
if (!_area.valid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool changed = _force_update;
|
||||||
|
_capture.capture_at(Capture::Point(0, 0)).for_each_rect([&](auto) {
|
||||||
|
changed = true; });
|
||||||
|
|
||||||
|
if (!changed)
|
||||||
|
return false;
|
||||||
|
|
||||||
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;
|
||||||
@ -64,30 +74,55 @@ struct Capture_webcam
|
|||||||
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());
|
||||||
|
|
||||||
|
if (_force_update)
|
||||||
|
_force_update = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_bgr(void *frame)
|
bool update_bgr(void *frame)
|
||||||
{
|
{
|
||||||
_capture.capture_at(Capture::Point(0, 0));
|
if (!_area.valid())
|
||||||
|
return false;
|
||||||
|
|
||||||
uint8_t * const bgr = reinterpret_cast<uint8_t *>(frame);
|
bool changed = false;
|
||||||
Pixel_rgb888 * data = reinterpret_cast<Pixel_rgb888 *>(_ds.local_addr<void>());
|
|
||||||
|
|
||||||
for (int y = 0; y < _area.h(); y++) {
|
uint8_t * const bgr = reinterpret_cast<uint8_t *>(frame);
|
||||||
unsigned const row = _vflip ? y : _area.h() - 1 - y;
|
Pixel_rgb888 const * const data = _ds.local_addr<Pixel_rgb888>();
|
||||||
unsigned const row_byte = (row * _area.w() * 3);
|
|
||||||
for (int x = 0; x < _area.w(); x++) {
|
|
||||||
bgr[row_byte + x * 3 + 0] = data->b();
|
|
||||||
bgr[row_byte + x * 3 + 1] = data->g();
|
|
||||||
bgr[row_byte + x * 3 + 2] = data->r();
|
|
||||||
|
|
||||||
data++;
|
auto const &update_fn = ([&](auto &rect) {
|
||||||
|
changed = true;
|
||||||
|
for (int y = rect.y1(); y <= rect.y2(); y++) {
|
||||||
|
unsigned const row = _vflip ? y : _area.h() - 1 - y;
|
||||||
|
unsigned const row_byte = (row * _area.w() * 3);
|
||||||
|
|
||||||
|
for (int x = rect.x1(); x < rect.x2(); x++) {
|
||||||
|
auto &pixel = data[y * _area.w() + x];
|
||||||
|
bgr[row_byte + x * 3 + 0] = pixel.b();
|
||||||
|
bgr[row_byte + x * 3 + 1] = pixel.g();
|
||||||
|
bgr[row_byte + x * 3 + 2] = pixel.r();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
if (_force_update) {
|
||||||
|
/* update whole frame */
|
||||||
|
_force_update = false;
|
||||||
|
Rect const whole(Point(0,0), _area);
|
||||||
|
_capture.capture_at(Capture::Point(0, 0));
|
||||||
|
update_fn(whole);
|
||||||
|
} else
|
||||||
|
_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, char const * format)
|
||||||
{
|
{
|
||||||
|
/* next time update whole frame due to format changes or on/off */
|
||||||
|
_force_update = true;
|
||||||
|
|
||||||
if (!_reporter.constructed())
|
if (!_reporter.constructed())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -123,14 +158,14 @@ extern "C" void capture_state_changed(bool on, char const * format)
|
|||||||
capture->capture_state_changed(on, format);
|
capture->capture_state_changed(on, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void capture_bgr_frame(void * pixel)
|
extern "C" bool capture_bgr_frame(void * pixel)
|
||||||
{
|
{
|
||||||
capture->update_bgr(pixel);
|
return capture->update_bgr(pixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void capture_yuv_frame(void * pixel)
|
extern "C" bool capture_yuv_frame(void * pixel)
|
||||||
{
|
{
|
||||||
capture->update_yuv(pixel);
|
return capture->update_yuv(pixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user