Display initialization and frame ownership fixes (#850)

This commit is contained in:
Cameron Gutman 2023-01-28 23:15:37 -06:00 committed by GitHub
parent 9155e39e91
commit 592f3a70a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -711,6 +711,7 @@ void reset_display(std::shared_ptr<platf::display_t> &disp, AVHWDeviceType type,
break;
}
// The capture code depends on us to sleep between failures
std::this_thread::sleep_for(200ms);
}
}
@ -839,16 +840,32 @@ void captureThread(
// Wait for the other shared_ptr's of display to be destroyed.
// New displays will only be created in this thread.
while(display_wp->use_count() != 1) {
std::this_thread::sleep_for(100ms);
// Free images that weren't consumed by the encoders. These can reference the display and prevent
// the ref count from reaching 1. We do this here rather than on the encoder thread to avoid race
// conditions where the encoding loop might free a good frame after reinitializing if we capture
// a new frame here before the encoder has finished reinitializing.
KITTY_WHILE_LOOP(auto capture_ctx = std::begin(capture_ctxs), capture_ctx != std::end(capture_ctxs), {
if(!capture_ctx->images->running()) {
capture_ctx = capture_ctxs.erase(capture_ctx);
continue;
}
while(capture_ctx->images->peek()) {
capture_ctx->images->pop();
}
++capture_ctx;
});
std::this_thread::sleep_for(20ms);
}
while(capture_ctx_queue->running()) {
// reset_display() will sleep between retries
reset_display(disp, encoder.base_dev_type, display_names[display_p], capture_ctxs.front().config);
if(disp) {
break;
}
std::this_thread::sleep_for(200ms);
}
if(!disp) {
return;
@ -1273,6 +1290,13 @@ void encode_run(
auto packets = mail::man->queue<packet_t>(mail::video_packets);
auto idr_events = mail->event<bool>(mail::idr);
// Load a dummy image into the AVFrame to ensure we have something to encode
// even if we time out waiting on the first frame.
auto dummy_img = disp->alloc_img();
if(!dummy_img || disp->dummy_img(dummy_img.get()) || session->device->convert(*dummy_img)) {
return;
}
while(true) {
if(shutdown_event->peek() || reinit_event.peek() || !images->running()) {
break;
@ -1288,7 +1312,10 @@ void encode_run(
// Encode at a minimum of 10 FPS to avoid image quality issues with static content
if(!frame->key_frame || images->peek()) {
if(auto img = images->pop(100ms)) {
session->device->convert(*img);
if(session->device->convert(*img)) {
BOOST_LOG(error) << "Could not convert image"sv;
return;
}
}
else if(!images->running()) {
break;
@ -1399,12 +1426,11 @@ encode_e encode_run_sync(
}
while(encode_session_ctx_queue.running()) {
// reset_display() will sleep between retries
reset_display(disp, encoder.base_dev_type, display_names[display_p], synced_session_ctxs.front()->config);
if(disp) {
break;
}
std::this_thread::sleep_for(200ms);
}
if(!disp) {
@ -1574,15 +1600,9 @@ void capture_async(
platf::adjust_thread_priority(platf::thread_priority_e::high);
while(!shutdown_event->peek() && images->running()) {
// Free images that weren't consumed by the encoder before it quit.
// This is critical to allow the display_t to be freed correctly.
while(images->peek()) {
images->pop();
}
// Wait for the main capture event when the display is being reinitialized
if(ref->reinit_event.peek()) {
std::this_thread::sleep_for(100ms);
std::this_thread::sleep_for(20ms);
continue;
}
// Wait for the display to be ready
@ -1603,13 +1623,6 @@ void capture_async(
return;
}
auto dummy_img = display->alloc_img();
if(!dummy_img || display->dummy_img(dummy_img.get())) {
return;
}
images->raise(std::move(dummy_img));
// absolute mouse coordinates require that the dimensions of the screen are known
touch_port_event->raise(make_port(display.get(), config));