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
+33 -20
View File
@@ -711,6 +711,7 @@ void reset_display(std::shared_ptr<platf::display_t> &disp, AVHWDeviceType type,
break; break;
} }
// The capture code depends on us to sleep between failures
std::this_thread::sleep_for(200ms); std::this_thread::sleep_for(200ms);
} }
} }
@@ -839,16 +840,32 @@ void captureThread(
// Wait for the other shared_ptr's of display to be destroyed. // Wait for the other shared_ptr's of display to be destroyed.
// New displays will only be created in this thread. // New displays will only be created in this thread.
while(display_wp->use_count() != 1) { 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()) { 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); reset_display(disp, encoder.base_dev_type, display_names[display_p], capture_ctxs.front().config);
if(disp) { if(disp) {
break; break;
} }
std::this_thread::sleep_for(200ms);
} }
if(!disp) { if(!disp) {
return; return;
@@ -1273,6 +1290,13 @@ void encode_run(
auto packets = mail::man->queue<packet_t>(mail::video_packets); auto packets = mail::man->queue<packet_t>(mail::video_packets);
auto idr_events = mail->event<bool>(mail::idr); 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) { while(true) {
if(shutdown_event->peek() || reinit_event.peek() || !images->running()) { if(shutdown_event->peek() || reinit_event.peek() || !images->running()) {
break; break;
@@ -1288,7 +1312,10 @@ void encode_run(
// Encode at a minimum of 10 FPS to avoid image quality issues with static content // Encode at a minimum of 10 FPS to avoid image quality issues with static content
if(!frame->key_frame || images->peek()) { if(!frame->key_frame || images->peek()) {
if(auto img = images->pop(100ms)) { 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()) { else if(!images->running()) {
break; break;
@@ -1399,12 +1426,11 @@ encode_e encode_run_sync(
} }
while(encode_session_ctx_queue.running()) { 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); reset_display(disp, encoder.base_dev_type, display_names[display_p], synced_session_ctxs.front()->config);
if(disp) { if(disp) {
break; break;
} }
std::this_thread::sleep_for(200ms);
} }
if(!disp) { if(!disp) {
@@ -1574,15 +1600,9 @@ void capture_async(
platf::adjust_thread_priority(platf::thread_priority_e::high); platf::adjust_thread_priority(platf::thread_priority_e::high);
while(!shutdown_event->peek() && images->running()) { 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 // Wait for the main capture event when the display is being reinitialized
if(ref->reinit_event.peek()) { if(ref->reinit_event.peek()) {
std::this_thread::sleep_for(100ms); std::this_thread::sleep_for(20ms);
continue; continue;
} }
// Wait for the display to be ready // Wait for the display to be ready
@@ -1603,13 +1623,6 @@ void capture_async(
return; 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 // absolute mouse coordinates require that the dimensions of the screen are known
touch_port_event->raise(make_port(display.get(), config)); touch_port_event->raise(make_port(display.get(), config));