pixelflux 1.3.1__tar.gz → 1.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pixelflux might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pixelflux
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: A performant web native pixel delivery pipeline for diverse sources, blending VNC-inspired parallel processing of pixel buffers with flexible modern encoding formats.
5
5
  Home-page: https://github.com/linuxserver/pixelflux
6
6
  Author: Linuxserver.io
@@ -87,15 +87,20 @@ settings.output_mode = 1
87
87
  # Force CPU encoding and ignore hardware encoders
88
88
  capture_settings.use_cpu = False
89
89
 
90
+ # --- Debugging ---
91
+ settings.debug_logging = False # Enable/disable the continuous FPS and settings log to the console.
92
+
90
93
  # --- JPEG Settings ---
91
94
  settings.jpeg_quality = 75 # Quality for changed stripes (0-100)
92
95
  settings.paint_over_jpeg_quality = 90 # Quality for static "paint-over" stripes (0-100)
93
96
 
94
97
  # --- H.264 Settings ---
95
- settings.h264_crf = 23 # CRF value (0-51, lower is better quality/higher bitrate)
96
- settings.h264_fullcolor = False # Use I444 (full color) instead of I420 for software encoding
97
- settings.h264_fullframe = True # Encode full frames (required for HW accel) instead of just changed stripes
98
- settings.h264_streaming_mode = False # Bypass all VNC logic and work like a normal video encoder, higher constant CPU usage for fullscreen gaming/videos
98
+ settings.h264_crf = 25 # CRF value (0-51, lower is better quality/higher bitrate)
99
+ settings.h264_paintover_crf = 18 # CRF for H.264 paintover on static content. Must be lower than h264_crf to activate.
100
+ settings.h264_paintover_burst_frames = 5 # Number of high-quality frames to send in a burst when a paintover is triggered.
101
+ settings.h264_fullcolor = False # Use I444 (full color) instead of I420 for software encoding
102
+ settings.h264_fullframe = True # Encode full frames (required for HW accel) instead of just changed stripes
103
+ settings.h264_streaming_mode = False # Bypass all VNC logic and work like a normal video encoder, higher constant CPU usage for fullscreen gaming/videos
99
104
 
100
105
  # --- Hardware Acceleration ---
101
106
  # Set to >= 0 to enable VA-API on a specific /dev/dri/renderD* node.
@@ -73,15 +73,20 @@ settings.output_mode = 1
73
73
  # Force CPU encoding and ignore hardware encoders
74
74
  capture_settings.use_cpu = False
75
75
 
76
+ # --- Debugging ---
77
+ settings.debug_logging = False # Enable/disable the continuous FPS and settings log to the console.
78
+
76
79
  # --- JPEG Settings ---
77
80
  settings.jpeg_quality = 75 # Quality for changed stripes (0-100)
78
81
  settings.paint_over_jpeg_quality = 90 # Quality for static "paint-over" stripes (0-100)
79
82
 
80
83
  # --- H.264 Settings ---
81
- settings.h264_crf = 23 # CRF value (0-51, lower is better quality/higher bitrate)
82
- settings.h264_fullcolor = False # Use I444 (full color) instead of I420 for software encoding
83
- settings.h264_fullframe = True # Encode full frames (required for HW accel) instead of just changed stripes
84
- settings.h264_streaming_mode = False # Bypass all VNC logic and work like a normal video encoder, higher constant CPU usage for fullscreen gaming/videos
84
+ settings.h264_crf = 25 # CRF value (0-51, lower is better quality/higher bitrate)
85
+ settings.h264_paintover_crf = 18 # CRF for H.264 paintover on static content. Must be lower than h264_crf to activate.
86
+ settings.h264_paintover_burst_frames = 5 # Number of high-quality frames to send in a burst when a paintover is triggered.
87
+ settings.h264_fullcolor = False # Use I444 (full color) instead of I420 for software encoding
88
+ settings.h264_fullframe = True # Encode full frames (required for HW accel) instead of just changed stripes
89
+ settings.h264_streaming_mode = False # Bypass all VNC logic and work like a normal video encoder, higher constant CPU usage for fullscreen gaming/videos
85
90
 
86
91
  # --- Hardware Acceleration ---
87
92
  # Set to >= 0 to enable VA-API on a specific /dev/dri/renderD* node.
@@ -16,6 +16,8 @@ class CaptureSettings(ctypes.Structure):
16
16
  ("damage_block_duration", ctypes.c_int),
17
17
  ("output_mode", ctypes.c_int),
18
18
  ("h264_crf", ctypes.c_int),
19
+ ("h264_paintover_crf", ctypes.c_int),
20
+ ("h264_paintover_burst_frames", ctypes.c_int),
19
21
  ("h264_fullcolor", ctypes.c_bool),
20
22
  ("h264_fullframe", ctypes.c_bool),
21
23
  ("h264_streaming_mode", ctypes.c_bool),
@@ -24,6 +26,7 @@ class CaptureSettings(ctypes.Structure):
24
26
  ("watermark_location_enum", ctypes.c_int),
25
27
  ("vaapi_render_node_index", ctypes.c_int),
26
28
  ("use_cpu", ctypes.c_bool),
29
+ ("debug_logging", ctypes.c_bool),
27
30
  ]
28
31
 
29
32
  WATERMARK_LOCATION_NONE = 0
@@ -288,12 +288,6 @@ enum class WatermarkLocation : int {
288
288
  NONE = 0, TL = 1, TR = 2, BL = 3, BR = 4, MI = 5, AN = 6
289
289
  };
290
290
 
291
- /**
292
- * @brief Defines static paintover settings for CPU encoding
293
- */
294
- const int H264_PAINTOVER_BURST_FRAMES = 3;
295
- const int H264_PAINTOVER_CRF = 18;
296
-
297
291
  /**
298
292
  * @brief Holds settings for screen capture and encoding.
299
293
  * This struct aggregates all configurable parameters for the capture process,
@@ -313,6 +307,8 @@ struct CaptureSettings {
313
307
  int damage_block_duration;
314
308
  OutputMode output_mode;
315
309
  int h264_crf;
310
+ int h264_paintover_crf;
311
+ int h264_paintover_burst_frames;
316
312
  bool h264_fullcolor;
317
313
  bool h264_fullframe;
318
314
  bool h264_streaming_mode;
@@ -321,6 +317,7 @@ struct CaptureSettings {
321
317
  WatermarkLocation watermark_location_enum;
322
318
  int vaapi_render_node_index;
323
319
  bool use_cpu;
320
+ bool debug_logging;
324
321
 
325
322
  /**
326
323
  * @brief Default constructor for CaptureSettings.
@@ -340,6 +337,8 @@ struct CaptureSettings {
340
337
  damage_block_duration(30),
341
338
  output_mode(OutputMode::JPEG),
342
339
  h264_crf(25),
340
+ h264_paintover_crf(18),
341
+ h264_paintover_burst_frames(5),
343
342
  h264_fullcolor(false),
344
343
  h264_fullframe(false),
345
344
  h264_streaming_mode(false),
@@ -347,7 +346,8 @@ struct CaptureSettings {
347
346
  watermark_path(nullptr),
348
347
  watermark_location_enum(WatermarkLocation::NONE),
349
348
  vaapi_render_node_index(-1),
350
- use_cpu(false) {}
349
+ use_cpu(false),
350
+ debug_logging(false) {}
351
351
 
352
352
  /**
353
353
  * @brief Parameterized constructor for CaptureSettings.
@@ -371,12 +371,12 @@ struct CaptureSettings {
371
371
  */
372
372
  CaptureSettings(int cw, int ch, int cx, int cy, double fps, int jq,
373
373
  int pojq, bool upoq, int potf, int dbt, int dbd,
374
- OutputMode om = OutputMode::JPEG, int crf = 25,
374
+ OutputMode om = OutputMode::JPEG, int crf = 25, int h264_po_crf = 18, int h264_po_burst = 5,
375
375
  bool h264_fc = false, bool h264_ff = false, bool h264_sm = false,
376
376
  bool capture_cursor = false,
377
377
  const char* wm_path = nullptr,
378
378
  WatermarkLocation wm_loc = WatermarkLocation::NONE,
379
- int vaapi_idx = -1, bool use_cpu_flag = false)
379
+ int vaapi_idx = -1, bool use_cpu_flag = false, bool debug_log = false)
380
380
  : capture_width(cw),
381
381
  capture_height(ch),
382
382
  capture_x(cx),
@@ -390,6 +390,8 @@ struct CaptureSettings {
390
390
  damage_block_duration(dbd),
391
391
  output_mode(om),
392
392
  h264_crf(crf),
393
+ h264_paintover_crf(h264_po_crf),
394
+ h264_paintover_burst_frames(h264_po_burst),
393
395
  h264_fullcolor(h264_fc),
394
396
  h264_fullframe(h264_ff),
395
397
  h264_streaming_mode(h264_sm),
@@ -397,7 +399,8 @@ struct CaptureSettings {
397
399
  watermark_path(wm_path),
398
400
  watermark_location_enum(wm_loc),
399
401
  vaapi_render_node_index(vaapi_idx),
400
- use_cpu(use_cpu_flag) {}
402
+ use_cpu(use_cpu_flag),
403
+ debug_logging(debug_log) {}
401
404
  };
402
405
 
403
406
  /**
@@ -708,6 +711,34 @@ bool initialize_nvenc_encoder(int width,
708
711
  return true;
709
712
  }
710
713
 
714
+ if (g_nvenc_state.initialized && g_nvenc_state.initialized_width == width &&
715
+ g_nvenc_state.initialized_height == height &&
716
+ g_nvenc_state.initialized_buffer_format == target_buffer_format) {
717
+
718
+ NV_ENC_RECONFIGURE_PARAMS reconfigure_params = {0};
719
+ NV_ENC_CONFIG new_config = g_nvenc_state.encode_config;
720
+
721
+ reconfigure_params.version = NV_ENC_RECONFIGURE_PARAMS_VER;
722
+ reconfigure_params.reInitEncodeParams = g_nvenc_state.init_params;
723
+ reconfigure_params.reInitEncodeParams.encodeConfig = &new_config;
724
+
725
+ new_config.rcParams.constQP.qpInterP = target_qp;
726
+ new_config.rcParams.constQP.qpIntra = target_qp;
727
+ new_config.rcParams.constQP.qpInterB = target_qp;
728
+
729
+ bool is_quality_increasing = (target_qp < g_nvenc_state.initialized_qp);
730
+ reconfigure_params.forceIDR = is_quality_increasing;
731
+
732
+ NVENCSTATUS status = g_nvenc_state.nvenc_funcs.nvEncReconfigureEncoder(
733
+ g_nvenc_state.encoder_session, &reconfigure_params);
734
+
735
+ if (status == NV_ENC_SUCCESS) {
736
+ g_nvenc_state.initialized_qp = target_qp;
737
+ g_nvenc_state.encode_config = new_config;
738
+ return true;
739
+ }
740
+ }
741
+
711
742
  if (g_nvenc_state.initialized) {
712
743
  g_nvenc_mutex.unlock();
713
744
  reset_nvenc_encoder();
@@ -1705,6 +1736,8 @@ public:
1705
1736
  int damage_block_threshold = 15;
1706
1737
  int damage_block_duration = 30;
1707
1738
  int h264_crf = 25;
1739
+ int h264_paintover_crf = 18;
1740
+ int h264_paintover_burst_frames = 5;
1708
1741
  bool h264_fullcolor = false;
1709
1742
  bool h264_fullframe = false;
1710
1743
  bool h264_streaming_mode = false;
@@ -1713,6 +1746,7 @@ public:
1713
1746
  std::string watermark_path_internal;
1714
1747
  WatermarkLocation watermark_location_internal;
1715
1748
  bool use_cpu = false;
1749
+ bool debug_logging = false;
1716
1750
 
1717
1751
  std::atomic<bool> stop_requested;
1718
1752
  std::thread capture_thread;
@@ -1852,12 +1886,15 @@ public:
1852
1886
  damage_block_duration = new_settings.damage_block_duration;
1853
1887
  output_mode = new_settings.output_mode;
1854
1888
  h264_crf = new_settings.h264_crf;
1889
+ h264_paintover_crf = new_settings.h264_paintover_crf;
1890
+ h264_paintover_burst_frames = new_settings.h264_paintover_burst_frames;
1855
1891
  h264_fullcolor = new_settings.h264_fullcolor;
1856
1892
  h264_fullframe = new_settings.h264_fullframe;
1857
1893
  h264_streaming_mode = new_settings.h264_streaming_mode;
1858
1894
  capture_cursor = new_settings.capture_cursor;
1859
1895
  vaapi_render_node_index = new_settings.vaapi_render_node_index;
1860
1896
  use_cpu = new_settings.use_cpu;
1897
+ debug_logging = new_settings.debug_logging;
1861
1898
  std::string new_wm_path_str = new_settings.watermark_path ? new_settings.watermark_path : "";
1862
1899
  bool path_actually_changed_in_settings = (watermark_path_internal != new_wm_path_str);
1863
1900
 
@@ -1883,9 +1920,10 @@ public:
1883
1920
  jpeg_quality, paint_over_jpeg_quality, use_paint_over_quality,
1884
1921
  paint_over_trigger_frames, damage_block_threshold,
1885
1922
  damage_block_duration, output_mode, h264_crf,
1923
+ h264_paintover_crf, h264_paintover_burst_frames,
1886
1924
  h264_fullcolor, h264_fullframe, h264_streaming_mode, capture_cursor,
1887
1925
  watermark_path_internal.c_str(), watermark_location_internal,
1888
- vaapi_render_node_index, use_cpu
1926
+ vaapi_render_node_index, use_cpu, debug_logging
1889
1927
  );
1890
1928
  }
1891
1929
 
@@ -2009,6 +2047,8 @@ private:
2009
2047
  int local_current_damage_block_threshold;
2010
2048
  int local_current_damage_block_duration;
2011
2049
  int local_current_h264_crf;
2050
+ int local_current_h264_paintover_crf;
2051
+ int local_current_h264_paintover_burst_frames;
2012
2052
  bool local_current_h264_fullcolor;
2013
2053
  bool local_current_h264_fullframe;
2014
2054
  bool local_current_h264_streaming_mode;
@@ -2020,6 +2060,7 @@ private:
2020
2060
  std::string local_watermark_path_setting;
2021
2061
  WatermarkLocation local_watermark_location_setting;
2022
2062
  bool local_use_cpu;
2063
+ bool local_debug_logging;
2023
2064
 
2024
2065
  {
2025
2066
  std::lock_guard<std::mutex> lock(settings_mutex);
@@ -2036,12 +2077,15 @@ private:
2036
2077
  local_current_damage_block_duration = damage_block_duration;
2037
2078
  local_current_output_mode = output_mode;
2038
2079
  local_current_h264_crf = h264_crf;
2080
+ local_current_h264_paintover_crf = h264_paintover_crf;
2081
+ local_current_h264_paintover_burst_frames = h264_paintover_burst_frames;
2039
2082
  local_current_h264_fullcolor = h264_fullcolor;
2040
2083
  local_current_h264_fullframe = h264_fullframe;
2041
2084
  local_current_h264_streaming_mode = h264_streaming_mode;
2042
2085
  local_current_capture_cursor = capture_cursor;
2043
2086
  local_vaapi_render_node_index = vaapi_render_node_index;
2044
2087
  local_use_cpu = use_cpu;
2088
+ local_debug_logging = debug_logging;
2045
2089
  local_watermark_path_setting = watermark_path_internal;
2046
2090
  local_watermark_location_setting = watermark_location_internal;
2047
2091
  }
@@ -2112,6 +2156,25 @@ private:
2112
2156
  }
2113
2157
  Window root_window = DefaultRootWindow(display);
2114
2158
  int screen = DefaultScreen(display);
2159
+ XWindowAttributes attributes;
2160
+ if (XGetWindowAttributes(display, root_window, &attributes)) {
2161
+ if (local_capture_width_actual > attributes.width) {
2162
+ local_capture_width_actual = attributes.width;
2163
+ local_capture_x_offset = 0;
2164
+ }
2165
+ if (local_capture_height_actual > attributes.height) {
2166
+ local_capture_height_actual = attributes.height;
2167
+ local_capture_y_offset = 0;
2168
+ }
2169
+ if (local_capture_x_offset + local_capture_width_actual > attributes.width) {
2170
+ local_capture_x_offset = attributes.width - local_capture_width_actual;
2171
+ }
2172
+ if (local_capture_y_offset + local_capture_height_actual > attributes.height) {
2173
+ local_capture_y_offset = attributes.height - local_capture_height_actual;
2174
+ }
2175
+ if (local_capture_x_offset < 0) local_capture_x_offset = 0;
2176
+ if (local_capture_y_offset < 0) local_capture_y_offset = 0;
2177
+ }
2115
2178
 
2116
2179
  if (!XShmQueryExtension(display)) {
2117
2180
  std::cerr << "Error: X Shared Memory Extension not available!" << std::endl;
@@ -2215,6 +2278,66 @@ private:
2215
2278
  std::cout << "CPU cores available: " << num_cores << std::endl;
2216
2279
  int num_stripes_config = num_cores;
2217
2280
 
2281
+ int N_processing_stripes;
2282
+ if (local_capture_height_actual <= 0) {
2283
+ N_processing_stripes = 0;
2284
+ } else {
2285
+ if (local_current_output_mode == OutputMode::H264) {
2286
+ if (local_current_h264_fullframe) {
2287
+ N_processing_stripes = 1;
2288
+ } else {
2289
+ const int MIN_H264_STRIPE_HEIGHT_PX = 64;
2290
+ if (local_capture_height_actual < MIN_H264_STRIPE_HEIGHT_PX) {
2291
+ N_processing_stripes = 1;
2292
+ } else {
2293
+ int max_stripes_by_min_height =
2294
+ local_capture_height_actual / MIN_H264_STRIPE_HEIGHT_PX;
2295
+ N_processing_stripes =
2296
+ std::min(num_stripes_config, max_stripes_by_min_height);
2297
+ if (N_processing_stripes == 0) N_processing_stripes = 1;
2298
+ }
2299
+ }
2300
+ } else {
2301
+ N_processing_stripes =
2302
+ std::min(num_stripes_config, local_capture_height_actual);
2303
+ if (N_processing_stripes == 0 && local_capture_height_actual > 0) {
2304
+ N_processing_stripes = 1;
2305
+ }
2306
+ }
2307
+ }
2308
+ if (N_processing_stripes == 0 && local_capture_height_actual > 0) {
2309
+ N_processing_stripes = 1;
2310
+ }
2311
+ std::stringstream settings_ss;
2312
+ settings_ss << "Stream settings active -> Res: " << local_capture_width_actual << "x"
2313
+ << local_capture_height_actual
2314
+ << " | FPS: " << std::fixed << std::setprecision(1) << local_current_target_fps
2315
+ << " | Stripes: " << N_processing_stripes;
2316
+ if (local_current_output_mode == OutputMode::JPEG) {
2317
+ settings_ss << " | Mode: JPEG";
2318
+ settings_ss << " | Quality: " << local_current_jpeg_quality;
2319
+ if (local_current_use_paint_over_quality) {
2320
+ settings_ss << " | PaintOver Q: " << local_current_paint_over_jpeg_quality
2321
+ << " (Trigger: " << local_current_paint_over_trigger_frames << "f)";
2322
+ }
2323
+ } else {
2324
+ std::string encoder_type = "CPU";
2325
+ if (this->vaapi_operational) encoder_type = "VAAPI";
2326
+ else if (this->nvenc_operational) encoder_type = "NVENC";
2327
+ settings_ss << " | Mode: H264 (" << encoder_type << ")";
2328
+ settings_ss << (local_current_h264_fullframe ? " FullFrame" : " Striped");
2329
+ if (local_current_h264_streaming_mode) settings_ss << " Streaming";
2330
+ settings_ss << " | CRF: " << local_current_h264_crf;
2331
+ if (local_current_use_paint_over_quality) {
2332
+ settings_ss << " | PaintOver CRF: " << local_current_h264_paintover_crf
2333
+ << " (Burst: " << local_current_h264_paintover_burst_frames << "f)";
2334
+ }
2335
+ settings_ss << " | Colorspace: " << (local_current_h264_fullcolor ? "I444 (Full Range)" : "I420 (Limited Range)");
2336
+ }
2337
+ settings_ss << " | Damage Thresh: " << local_current_damage_block_threshold << "f"
2338
+ << " | Damage Dur: " << local_current_damage_block_duration << "f";
2339
+ std::cout << settings_ss.str() << std::endl;
2340
+
2218
2341
  std::vector<uint64_t> previous_hashes(num_stripes_config, 0);
2219
2342
  std::vector<int> no_motion_frame_counts(num_stripes_config, 0);
2220
2343
  std::vector<bool> paint_over_sent(num_stripes_config, false);
@@ -2276,6 +2399,8 @@ private:
2276
2399
  }
2277
2400
  local_current_output_mode = output_mode;
2278
2401
  local_current_h264_crf = h264_crf;
2402
+ local_current_h264_paintover_crf = h264_paintover_crf;
2403
+ local_current_h264_paintover_burst_frames = h264_paintover_burst_frames;
2279
2404
  local_current_h264_fullcolor = h264_fullcolor;
2280
2405
  local_current_h264_fullframe = h264_fullframe;
2281
2406
  local_current_h264_streaming_mode = h264_streaming_mode;
@@ -2284,6 +2409,7 @@ private:
2284
2409
  local_watermark_path_setting = watermark_path_internal;
2285
2410
  local_watermark_location_setting = watermark_location_internal;
2286
2411
  local_use_cpu = use_cpu;
2412
+ local_debug_logging = debug_logging;
2287
2413
  }
2288
2414
 
2289
2415
  bool current_watermark_is_actually_loaded_in_loop;
@@ -2757,7 +2883,7 @@ private:
2757
2883
  int crf_for_encode = local_current_h264_crf;
2758
2884
  if (local_current_output_mode == OutputMode::H264 && h264_paintover_burst_frames_remaining[i] > 0) {
2759
2885
  send_this_stripe = true;
2760
- crf_for_encode = H264_PAINTOVER_CRF;
2886
+ crf_for_encode = local_current_h264_paintover_crf;
2761
2887
  h264_paintover_burst_frames_remaining[i]--;
2762
2888
  current_hash = calculate_current_hash();
2763
2889
  hash_calculated_this_iteration = true;
@@ -2808,17 +2934,27 @@ private:
2808
2934
  consecutive_stripe_changes[i] = 0;
2809
2935
  no_motion_frame_counts[i]++;
2810
2936
  if (no_motion_frame_counts[i] >= local_current_paint_over_trigger_frames && !paint_over_sent[i]) {
2811
- if (local_current_output_mode == OutputMode::JPEG && local_current_use_paint_over_quality) {
2937
+ if (local_current_output_mode == OutputMode::JPEG &&
2938
+ local_current_use_paint_over_quality &&
2939
+ local_current_paint_over_jpeg_quality > local_current_jpeg_quality) {
2812
2940
  send_this_stripe = true;
2813
2941
  current_jpeg_qualities[i] = local_current_paint_over_jpeg_quality;
2814
2942
  paint_over_sent[i] = true;
2815
2943
  } else if (local_current_output_mode == OutputMode::H264) {
2816
- if (H264_PAINTOVER_CRF < local_current_h264_crf) {
2944
+ if (local_current_use_paint_over_quality && local_current_h264_paintover_crf < local_current_h264_crf) {
2817
2945
  send_this_stripe = true;
2818
- force_idr_for_paintover = true;
2819
- crf_for_encode = H264_PAINTOVER_CRF;
2820
- h264_paintover_burst_frames_remaining[i] = H264_PAINTOVER_BURST_FRAMES - 1;
2821
2946
  paint_over_sent[i] = true;
2947
+ if (this->nvenc_operational) {
2948
+ g_nvenc_force_next_idr_global = true;
2949
+ h264_paintover_burst_frames_remaining[i] = local_current_h264_paintover_burst_frames - 1;
2950
+ } else if (this->vaapi_operational) {
2951
+ g_vaapi_force_next_idr_global = true;
2952
+ h264_paintover_burst_frames_remaining[i] = 0;
2953
+ } else {
2954
+ force_idr_for_paintover = true;
2955
+ crf_for_encode = local_current_h264_paintover_crf;
2956
+ h264_paintover_burst_frames_remaining[i] = local_current_h264_paintover_burst_frames - 1;
2957
+ }
2822
2958
  }
2823
2959
  }
2824
2960
  }
@@ -2865,6 +3001,16 @@ private:
2865
3001
  futures.push_back(task.get_future());
2866
3002
  threads.push_back(std::thread(std::move(task)));
2867
3003
  } else if (this->nvenc_operational) {
3004
+ int target_qp_for_frame = crf_for_encode;
3005
+ if (local_current_use_paint_over_quality && g_nvenc_force_next_idr_global) {
3006
+ target_qp_for_frame = local_current_h264_paintover_crf;
3007
+ }
3008
+ if (!initialize_nvenc_encoder(local_capture_width_actual, local_capture_height_actual, target_qp_for_frame, local_current_target_fps, local_current_h264_fullcolor)) {
3009
+ std::cerr << "NVENC: Re-initialization for QP change failed. Disabling NVENC." << std::endl;
3010
+ this->nvenc_operational = false;
3011
+ reset_nvenc_encoder();
3012
+ continue;
3013
+ }
2868
3014
  std::packaged_task<StripeEncodeResult()> task([=]() {
2869
3015
  bool force_idr = g_nvenc_force_next_idr_global.exchange(false);
2870
3016
  return encode_fullframe_nvenc(
@@ -2877,7 +3023,7 @@ private:
2877
3023
  );
2878
3024
  });
2879
3025
  futures.push_back(task.get_future());
2880
- threads.push_back(std::thread(std::move(task)));
3026
+ threads.push_back(std::thread(std::move(task)));
2881
3027
  } else {
2882
3028
  if (force_idr_for_paintover) {
2883
3029
  std::lock_guard<std::mutex> lock(g_h264_minimal_store.store_mutex);
@@ -2982,7 +3128,7 @@ private:
2982
3128
  std::chrono::duration_cast<std::chrono::seconds>(
2983
3129
  current_output_time_log - last_output_time);
2984
3130
 
2985
- if (output_elapsed_time_log.count() >= 1) {
3131
+ if (local_debug_logging && output_elapsed_time_log.count() >= 1) {
2986
3132
  double actual_fps_val =
2987
3133
  (encoded_frame_count > 0 && output_elapsed_time_log.count() > 0)
2988
3134
  ? static_cast<double>(encoded_frame_count) / output_elapsed_time_log.count()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pixelflux
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: A performant web native pixel delivery pipeline for diverse sources, blending VNC-inspired parallel processing of pixel buffers with flexible modern encoding formats.
5
5
  Home-page: https://github.com/linuxserver/pixelflux
6
6
  Author: Linuxserver.io
@@ -87,15 +87,20 @@ settings.output_mode = 1
87
87
  # Force CPU encoding and ignore hardware encoders
88
88
  capture_settings.use_cpu = False
89
89
 
90
+ # --- Debugging ---
91
+ settings.debug_logging = False # Enable/disable the continuous FPS and settings log to the console.
92
+
90
93
  # --- JPEG Settings ---
91
94
  settings.jpeg_quality = 75 # Quality for changed stripes (0-100)
92
95
  settings.paint_over_jpeg_quality = 90 # Quality for static "paint-over" stripes (0-100)
93
96
 
94
97
  # --- H.264 Settings ---
95
- settings.h264_crf = 23 # CRF value (0-51, lower is better quality/higher bitrate)
96
- settings.h264_fullcolor = False # Use I444 (full color) instead of I420 for software encoding
97
- settings.h264_fullframe = True # Encode full frames (required for HW accel) instead of just changed stripes
98
- settings.h264_streaming_mode = False # Bypass all VNC logic and work like a normal video encoder, higher constant CPU usage for fullscreen gaming/videos
98
+ settings.h264_crf = 25 # CRF value (0-51, lower is better quality/higher bitrate)
99
+ settings.h264_paintover_crf = 18 # CRF for H.264 paintover on static content. Must be lower than h264_crf to activate.
100
+ settings.h264_paintover_burst_frames = 5 # Number of high-quality frames to send in a burst when a paintover is triggered.
101
+ settings.h264_fullcolor = False # Use I444 (full color) instead of I420 for software encoding
102
+ settings.h264_fullframe = True # Encode full frames (required for HW accel) instead of just changed stripes
103
+ settings.h264_streaming_mode = False # Bypass all VNC logic and work like a normal video encoder, higher constant CPU usage for fullscreen gaming/videos
99
104
 
100
105
  # --- Hardware Acceleration ---
101
106
  # Set to >= 0 to enable VA-API on a specific /dev/dri/renderD* node.
@@ -5,6 +5,10 @@ build-backend = "setuptools.build_meta"
5
5
  [tool.cibuildwheel]
6
6
  archs = [ "x86_64", "aarch64" ]
7
7
 
8
+ # Add this new section
9
+ [tool.cibuildwheel.environment]
10
+ LD_LIBRARY_PATH = "/usr/local/lib:/usr/local/lib64"
11
+
8
12
  [tool.cibuildwheel.linux]
9
13
  before-all = """
10
14
  set -euxo pipefail
@@ -15,7 +19,6 @@ before-all = """
15
19
  dnf install -y \
16
20
  libX11-devel \
17
21
  libXext-devel \
18
- libjpeg-turbo-devel \
19
22
  libev-devel \
20
23
  libXcomposite-devel \
21
24
  libva-devel \
@@ -46,6 +49,14 @@ before-all = """
46
49
  make install); \
47
50
  fi && \
48
51
  \
52
+ (cd /tmp && \
53
+ git clone --branch 3.1.1 --depth 1 https://github.com/libjpeg-turbo/libjpeg-turbo.git && \
54
+ cd libjpeg-turbo && \
55
+ mkdir build && cd build && \
56
+ cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release && \
57
+ make -j$(nproc) && \
58
+ make install) && \
59
+ \
49
60
  ldconfig
50
61
 
51
62
  elif command -v apk; then
@@ -53,7 +53,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
53
53
 
54
54
  setup(
55
55
  name="pixelflux",
56
- version="1.3.1",
56
+ version="1.3.3",
57
57
  author="Linuxserver.io",
58
58
  author_email="pypi@linuxserver.io",
59
59
  description="A performant web native pixel delivery pipeline for diverse sources, blending VNC-inspired parallel processing of pixel buffers with flexible modern encoding formats.",
File without changes
File without changes
File without changes