From 7caa9b7ea963be4b66f37578c781bf25cf9c091a Mon Sep 17 00:00:00 2001 From: pigeatgarlic Date: Tue, 7 Apr 2026 15:40:27 +0700 Subject: [PATCH] remove synchronous encode --- src/video.cpp | 309 ++------------------------------------------------ 1 file changed, 8 insertions(+), 301 deletions(-) diff --git a/src/video.cpp b/src/video.cpp index 5508e410..bf5e1478 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -263,9 +263,7 @@ public: }; enum flag_e : uint32_t { - DEFAULT = 0, ///< Default flags - PARALLEL_ENCODING = 1 << 1, ///< Capture and encoding can run concurrently on separate threads - H264_ONLY = 1 << 2, ///< When HEVC is too heavy + DEFAULT = 0, ///< Default flags LIMITED_GOP_SIZE = 1 << 3, ///< Some encoders don't like it when you have an infinite GOP_SIZE. e.g. VAAPI SINGLE_SLICE_ONLY = @@ -390,27 +388,6 @@ private: bool force_idr = false; }; -struct sync_session_ctx_t { - safe::signal_t *join_event; - safe::mail_raw_t::event_t shutdown_event; - safe::mail_raw_t::queue_t packets; - safe::mail_raw_t::event_t idr_events; - safe::mail_raw_t::event_t hdr_events; - safe::mail_raw_t::event_t touch_port_events; - - config_t *config; - int frame_nr; - void *channel_data; -}; - -struct sync_session_t { - sync_session_ctx_t *ctx; - std::unique_ptr session; -}; - -using encode_session_ctx_queue_t = safe::queue_t; -using encode_e = platf::capture_e; - struct capture_ctx_t { img_event_t images; config_t *config; @@ -424,13 +401,6 @@ struct capture_thread_async_ctx_t { const encoder_t *encoder_p; sync_util::sync_t> display_wp; }; - -struct capture_thread_sync_ctx_t { - encode_session_ctx_queue_t encode_session_ctx_queue{30}; -}; - -int start_capture_sync(capture_thread_sync_ctx_t &ctx); -void end_capture_sync(capture_thread_sync_ctx_t &ctx); int start_capture_async(capture_thread_async_ctx_t &ctx); void end_capture_async(capture_thread_async_ctx_t &ctx); @@ -438,8 +408,6 @@ void end_capture_async(capture_thread_async_ctx_t &ctx); // reference to the capture thread auto capture_thread_async = safe::make_shared(start_capture_async, end_capture_async); -auto capture_thread_sync = - safe::make_shared(start_capture_sync, end_capture_sync); encoder_t nvenc{ "nvenc"sv, @@ -472,7 +440,7 @@ encoder_t nvenc{ {}, // Fallback options "h264_nvenc"s, }, - PARALLEL_ENCODING | REF_FRAMES_INVALIDATION // flags + REF_FRAMES_INVALIDATION // flags }; encoder_t quicksync{ @@ -571,7 +539,7 @@ encoder_t quicksync{ }, "h264_qsv"s, }, - PARALLEL_ENCODING | CBR_WITH_VBR | RELAXED_COMPLIANCE | NO_RC_BUF_LIMIT | YUV444_SUPPORT}; + CBR_WITH_VBR | RELAXED_COMPLIANCE | NO_RC_BUF_LIMIT | YUV444_SUPPORT}; encoder_t amdvce{ "amdvce"sv, @@ -650,7 +618,7 @@ encoder_t amdvce{ }, "h264_amf"s, }, - PARALLEL_ENCODING}; + 0}; encoder_t software{ "software"sv, @@ -712,7 +680,7 @@ encoder_t software{ {}, // Fallback options "libx264"s, }, - H264_ONLY | PARALLEL_ENCODING | ALWAYS_REPROBE | YUV444_SUPPORT}; + ALWAYS_REPROBE | YUV444_SUPPORT}; static const std::vector encoders{&nvenc, &quicksync, &amdvce, &software}; @@ -1757,241 +1725,6 @@ make_encode_device(platf::display_t &disp, const encoder_t &encoder, const confi return result; } -std::optional make_synced_session(platf::display_t *disp, const encoder_t &encoder, - platf::img_t &img, sync_session_ctx_t &ctx) { - sync_session_t encode_session; - - encode_session.ctx = &ctx; - - auto encode_device = make_encode_device(*disp, encoder, *ctx.config); - if (!encode_device) { - return std::nullopt; - } - - // absolute mouse coordinates require that the dimensions of the screen are known - ctx.touch_port_events->raise(make_port(disp, *ctx.config)); - - // Update client with our current HDR display state - hdr_info_t hdr_info = std::make_unique(false); - if (colorspace_is_hdr(encode_device->colorspace)) { - if (disp->get_hdr_metadata(hdr_info->metadata)) { - hdr_info->enabled = true; - } else { - BOOST_LOG(error) << "Couldn't get display hdr metadata when colorspace selection indicates " - "it should have one"; - } - } - ctx.hdr_events->raise(std::move(hdr_info)); - - auto session = make_encode_session(disp, encoder, *ctx.config, img.width, img.height, - std::move(encode_device)); - if (!session) { - return std::nullopt; - } - - // Load the initial image to prepare for encoding - if (session->convert(img)) { - BOOST_LOG(error) << "Could not convert initial image"sv; - return std::nullopt; - } - - encode_session.session = std::move(session); - - return encode_session; -} - -encode_e encode_run_sync(std::vector> &synced_session_ctxs, - encode_session_ctx_queue_t &encode_session_ctx_queue, - std::vector &display_names, int &display_p) { - const auto &encoder = *chosen_encoder; - - std::shared_ptr disp; - - if (synced_session_ctxs.empty()) { - auto ctx = encode_session_ctx_queue.pop(); - if (!ctx) { - return encode_e::ok; - } - - synced_session_ctxs.emplace_back(std::make_unique(std::move(*ctx))); - } - - while (encode_session_ctx_queue.running()) { - // Refresh display names since a display removal might have caused the reinitialization - refresh_displays(encoder.platform_formats->dev_type, display_names, display_p); - // Process any pending display switch with the new list of displays - if (synced_session_ctxs.front()->config->display.has_value() && - synced_session_ctxs.front()->config->display.value() != display_names[display_p]) { - for (int i = 0; i < display_names.size(); i++) { - if (synced_session_ctxs.front()->config->display.value() == display_names[i]) { - BOOST_LOG(info) << "Switched to display " << display_names[i]; - display_p = i; - goto next; - } - } - BOOST_LOG(info) << "Display " << synced_session_ctxs.front()->config->display.value() - << " not found"; - synced_session_ctxs.front()->config->display = std::nullopt; - } - next: - - // reset_display() will sleep between retries - reset_display(disp, encoder.platform_formats->dev_type, display_names[display_p], - synced_session_ctxs.front()->config); - if (disp) { - break; - } - } - - if (!disp) { - return encode_e::error; - } - - auto img = disp->alloc_img(); - if (!img || disp->dummy_img(img.get())) { - return encode_e::error; - } - - std::vector synced_sessions; - for (auto &ctx : synced_session_ctxs) { - auto synced_session = make_synced_session(disp.get(), encoder, *img, *ctx); - if (!synced_session) { - return encode_e::error; - } - - synced_sessions.emplace_back(std::move(*synced_session)); - } - - auto ec = platf::capture_e::ok; - while (encode_session_ctx_queue.running()) { - auto push_captured_image_callback = [&](std::shared_ptr &&img, - bool frame_captured) -> bool { - while (encode_session_ctx_queue.peek()) { - auto encode_session_ctx = encode_session_ctx_queue.pop(); - if (!encode_session_ctx) { - return false; - } - - synced_session_ctxs.emplace_back( - std::make_unique(std::move(*encode_session_ctx))); - - auto encode_session = - make_synced_session(disp.get(), encoder, *img, *synced_session_ctxs.back()); - if (!encode_session) { - ec = platf::capture_e::error; - return false; - } - - synced_sessions.emplace_back(std::move(*encode_session)); - } - - KITTY_WHILE_LOOP(auto pos = std::begin(synced_sessions), pos != std::end(synced_sessions), { - auto ctx = pos->ctx; - if (ctx->shutdown_event->peek()) { - // Let waiting thread know it can delete shutdown_event - ctx->join_event->raise(true); - - pos = synced_sessions.erase(pos); - synced_session_ctxs.erase( - std::find_if(std::begin(synced_session_ctxs), std::end(synced_session_ctxs), - [&ctx_p = ctx](auto &ctx) { return ctx.get() == ctx_p; })); - - if (synced_sessions.empty()) { - return false; - } - - continue; - } - - if (ctx->config->display.has_value() && - ctx->config->display.value() != display_names[display_p]) { - ec = platf::capture_e::reinit; - return false; - } - - if (ctx->idr_events->peek()) { - pos->session->request_idr_frame(); - ctx->idr_events->pop(); - } - - if (frame_captured && pos->session->convert(*img)) { - BOOST_LOG(error) << "Could not convert image"sv; - ctx->shutdown_event->raise(true); - - continue; - } - - std::optional frame_timestamp; - if (img) { - frame_timestamp = img->frame_timestamp; - } - - if (encode(ctx->frame_nr++, *pos->session, ctx->packets, ctx->channel_data, - frame_timestamp)) { - BOOST_LOG(error) << "Could not encode video packet"sv; - ctx->shutdown_event->raise(true); - - continue; - } - - pos->session->request_normal_frame(); - - ++pos; - }) - - return true; - }; - - auto pull_free_image_callback = [&img](std::shared_ptr &img_out) -> bool { - img_out = img; - img_out->frame_timestamp.reset(); - return true; - }; - - auto status = - disp->capture(push_captured_image_callback, pull_free_image_callback, &display_cursor); - switch (status) { - case platf::capture_e::reinit: - case platf::capture_e::error: - case platf::capture_e::ok: - case platf::capture_e::timeout: - case platf::capture_e::interrupted: - return ec != platf::capture_e::ok ? ec : status; - } - } - - return encode_e::ok; -} - -void captureThreadSync() { - auto ref = capture_thread_sync.ref(); - - std::vector> synced_session_ctxs; - - auto &ctx = ref->encode_session_ctx_queue; - auto lg = util::fail_guard([&]() { - ctx.stop(); - - for (auto &ctx : synced_session_ctxs) { - ctx->shutdown_event->raise(true); - ctx->join_event->raise(true); - } - - for (auto &ctx : ctx.unsafe()) { - ctx.shutdown_event->raise(true); - ctx.join_event->raise(true); - } - }); - - // Encoding and capture takes place on this thread - platf::adjust_thread_priority(platf::thread_priority_e::high); - - std::vector display_names; - int display_p = -1; - while (encode_run_sync(synced_session_ctxs, ctx, display_names, display_p) == encode_e::reinit) { - } -} - void capture_async(safe::mail_t mail, config_t &config, void *channel_data) { auto shutdown_event = mail->event(mail::shutdown); @@ -2069,26 +1802,7 @@ void capture(safe::mail_t mail, config_t config, void *channel_data) { auto idr_events = mail->event(mail::idr); idr_events->raise(true); - if (chosen_encoder->flags & PARALLEL_ENCODING) { - capture_async(std::move(mail), config, channel_data); - } else { - safe::signal_t join_event; - auto ref = capture_thread_sync.ref(); - ref->encode_session_ctx_queue.raise(sync_session_ctx_t{ - &join_event, - mail->event(mail::shutdown), - mail->queue(mail::video_packets), - std::move(idr_events), - mail->event(mail::hdr), - mail->event(mail::touch_port), - &config, - 1, - channel_data, - }); - - // Wait for join signal - join_event.view(); - } + capture_async(std::move(mail), config, channel_data); } enum validate_flag_e { @@ -2157,8 +1871,8 @@ bool validate_encoder(encoder_t &encoder, bool expect_failure) { auto fg = util::fail_guard([&]() { BOOST_LOG(info) << "Encoder ["sv << encoder.name << "] failed"sv; }); - auto test_hevc = active_hevc_mode >= 2 || (active_hevc_mode == 0 && !(encoder.flags & H264_ONLY)); - auto test_av1 = active_av1_mode >= 2 || (active_av1_mode == 0 && !(encoder.flags & H264_ONLY)); + auto test_hevc = active_hevc_mode >= 2 || active_hevc_mode == 0; + auto test_av1 = active_av1_mode >= 2 || active_av1_mode == 0; encoder.h264.capabilities.set(); encoder.hevc.capabilities.set(); @@ -2592,13 +2306,6 @@ void end_capture_async(capture_thread_async_ctx_t &capture_thread_ctx) { capture_thread_ctx.capture_thread.join(); } -int start_capture_sync(capture_thread_sync_ctx_t &ctx) { - std::thread{&captureThreadSync}.detach(); - return 0; -} -void end_capture_sync(capture_thread_sync_ctx_t &ctx) { -} - platf::mem_type_e map_base_dev_type(AVHWDeviceType type) { switch (type) { case AV_HWDEVICE_TYPE_D3D11VA: