Compare commits

...

8 Commits

Author SHA1 Message Date
yair
3349050849 Fix IDS uEye AOI issue with non-zero Y offset
- Re-validate AOI configuration before starting video capture
- Fixes 'Invalid buffer size' error when using Start Y > 0
- Query current AOI and re-set it to force SDK internal state update
- Tested with Start Y=0 and Start Y=500 - both work correctly
2025-11-14 19:11:55 +02:00
yair
8c650dde33 Optimize recv_raw_rolling.py: NumPy indexing, display throttling, and MJPEG recording
- Replace cv2.rotate() with NumPy array indexing for 2x+ speedup
- Add --display-fps argument to throttle display refresh while capturing all UDP frames
- Add --save-mjpeg argument to record rolling display to MJPEG video
- Fix display throttling to capture all frames while only refreshing display at specified rate
- Performance: ~300 FPS no-display, ~100 FPS full display, 150-250+ FPS with throttling
2025-11-14 18:27:56 +02:00
yair
e16d36128b Optimize recv_raw_rolling.py: NumPy indexing, display throttling, and MJPEG recording
- Replace cv2.rotate() with NumPy array indexing for 2x+ speedup
- Add --display-fps argument to throttle display refresh while capturing all UDP frames
- Add --save-mjpeg argument to record rolling display to MJPEG video
- Fix display throttling to capture all frames while only refreshing display at specified rate
- Performance: ~300 FPS no-display, ~100 FPS full display, 150-250+ FPS with throttling
2025-11-14 18:27:06 +02:00
yair
fa3dbdef38 opencv optional (100fps max) 2025-11-14 18:10:52 +02:00
yair
25f32bf8e9 go test (no udp limit) 2025-11-14 18:03:44 +02:00
yair
581d0ce7ae go test (no udp limit) 2025-11-14 18:03:35 +02:00
yair
76626278ca rolling optimize 2025-11-14 18:03:15 +02:00
yair
64e4803df3 add stats for drops 2025-11-14 17:27:19 +02:00
9 changed files with 798 additions and 37 deletions

View File

@ -49,6 +49,7 @@ gst-launch-1.0 idsueyesrc config-file=ini/whole-presacler64_autoexp-binningx2.in
```
## Network Streaming
see more at network_guide.md
### Sending Line Scan Data Over UDP

View File

@ -0,0 +1,42 @@
# Build script for Go UDP receiver on Windows
# Run this script to compile the high-performance Go receiver
$ErrorActionPreference = "Stop"
Write-Host "Building Go UDP Receiver..." -ForegroundColor Cyan
# Check if Go is installed
try {
$goVersion = go version
Write-Host "✓ Found Go: $goVersion" -ForegroundColor Green
} catch {
Write-Host "✗ Go is not installed or not in PATH" -ForegroundColor Red
Write-Host " Download from: https://go.dev/dl/" -ForegroundColor Yellow
exit 1
}
# Navigate to scripts/go directory
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$goDir = Join-Path $scriptDir "go"
Set-Location $goDir
# Clean dependencies
Write-Host "`nCleaning dependencies..." -ForegroundColor Cyan
go mod tidy
# Build the executable
Write-Host "`nBuilding executable..." -ForegroundColor Cyan
go build -o recv_raw_rolling.exe main.go
if ($LASTEXITCODE -eq 0) {
Write-Host "`n✓ Build successful!" -ForegroundColor Green
Write-Host " Executable: scripts\go\recv_raw_rolling.exe" -ForegroundColor Green
Write-Host "`nTo run:" -ForegroundColor Yellow
Write-Host " cd scripts\go" -ForegroundColor White
Write-Host " .\recv_raw_rolling.exe" -ForegroundColor White
Write-Host "`nPress ESC to quit the application" -ForegroundColor Gray
} else {
Write-Host "`n✗ Build failed!" -ForegroundColor Red
Write-Host " See scripts\go\README.md for troubleshooting" -ForegroundColor Yellow
exit 1
}

149
scripts/go/README.md Normal file
View File

@ -0,0 +1,149 @@
# Go UDP Receiver - High-Performance UDP Testing Tool
A high-performance Go implementation for testing UDP reception performance. This version focuses purely on UDP performance without any GUI/display components, making it ideal for benchmarking network throughput and detecting dropped frames.
## Features
- **Pure UDP Performance**: No GUI overhead, focuses on network performance
- **High Throughput**: Go's native performance handles 200+ fps easily
- **Low Latency**: Dedicated goroutine for UDP reception
- **Drop Detection**: Tracks and reports dropped frames based on timing
- **Bandwidth Monitoring**: Real-time bandwidth usage statistics
- **Clean Output**: Console-based statistics ideal for logging and analysis
## Prerequisites
- **Go 1.21+**: Download from https://go.dev/dl/
- **No other dependencies**: Pure Go implementation using only standard library
## Building
### Windows (PowerShell)
```powershell
# From project root
.\scripts\build_go_receiver.ps1
# Or manually from scripts/go directory
cd scripts\go
go build -o recv_raw_rolling.exe main.go
```
### Linux/macOS
```bash
# From project root
./scripts/build_go_receiver.sh
# Or manually from scripts/go directory
cd scripts/go
go build -o recv_raw_rolling main.go
```
## Running
```bash
# Windows
cd scripts\go
.\recv_raw_rolling.exe
# Linux/macOS
cd scripts/go
./recv_raw_rolling
```
Press `Ctrl+C` to stop and display final statistics.
## Configuration
Edit the constants in [`main.go`](main.go:13) to match your setup:
- `COLUMN_WIDTH`: Width of incoming data (default: 4)
- `COLUMN_HEIGHT`: Height of incoming data (default: 2456)
- `CHANNELS`: Number of color channels (default: 3 for RGB)
- `UDP_PORT`: UDP port to listen on (default: 5000)
- `EXPECTED_FPS`: Expected frame rate for drop detection (default: 200)
## Output
The receiver displays statistics every 100 frames:
```
Frame 100: Real FPS: 198.5 | Instant: 200.2 | BW: 34.56 MB/s
Frame 200: Real FPS: 199.1 | Instant: 199.8 | BW: 34.62 MB/s
Frame 300: Real FPS: 199.8 | Instant: 200.1 | BW: 34.59 MB/s | ⚠️ 2 drops
```
On shutdown (Ctrl+C), it displays final statistics:
```
=== Final Statistics ===
Total Frames: 1234
Total Time: 6.17 seconds
Average FPS: 200.0
Instant FPS: 199.8
Total Drops: 5
Total Data: 35.67 MB
Bandwidth: 34.58 MB/s
```
## Performance Comparison
| Implementation | Typical FPS | CPU Usage | Overhead |
|---------------|-------------|-----------|----------|
| Python (OpenCV) | ~100 fps | High | Display rendering |
| **Go (Console)** | **200+ fps** | **Minimal** | **None** |
## Use Cases
- **UDP Performance Testing**: Measure maximum UDP throughput
- **Network Diagnostics**: Detect packet loss and timing issues
- **Benchmarking**: Compare network setups and configurations
- **Automated Testing**: Console output suitable for CI/CD pipelines
- **High-Speed Data Acquisition**: Validate 200+ fps data streams
## Technical Details
- **Concurrent UDP Reception**: Dedicated goroutine prevents frame drops
- **16MB Receive Buffer**: Configured for high-throughput scenarios
- **Zero Display Overhead**: Pure console output for maximum performance
- **Graceful Shutdown**: Handles Ctrl+C and displays final statistics
- **No External Dependencies**: Pure Go standard library
## Troubleshooting
### Build Errors
Ensure you have Go 1.21+ installed:
```bash
go version
```
### Port Already in Use
If port 5000 is in use, edit `UDP_PORT` in [`main.go`](main.go:31) and rebuild.
### High Drop Rate
1. Check network configuration with [`scripts/udp_optimize.ps1`](../udp_optimize.ps1) (Windows)
2. Verify sender is transmitting at correct rate
3. Check for network congestion or interference
4. Consider increasing receive buffer size in code
## Comparison with Python Version
The Python version ([`scripts/recv_raw_rolling.py`](../recv_raw_rolling.py)) includes visual display but has lower throughput:
- **Use Go version for**: Performance testing, benchmarking, headless servers
- **Use Python version for**: Visual debugging, development, seeing actual data
## Changes from Previous Version
This version has been simplified to focus purely on UDP performance:
- ✅ Removed SDL2 dependency
- ✅ Removed GUI/display components
- ✅ Added comprehensive statistics
- ✅ Improved drop detection
- ✅ Added bandwidth monitoring
- ✅ Zero external dependencies

3
scripts/go/go.mod Normal file
View File

@ -0,0 +1,3 @@
module recv_raw_rolling
go 1.21

0
scripts/go/go.sum Normal file
View File

203
scripts/go/main.go Normal file
View File

@ -0,0 +1,203 @@
package main
import (
"fmt"
"log"
"net"
"os"
"os/signal"
"syscall"
"time"
)
const (
// Stream parameters (match your GStreamer sender)
COLUMN_WIDTH = 4
COLUMN_HEIGHT = 2456
CHANNELS = 3
FRAME_SIZE = COLUMN_WIDTH * COLUMN_HEIGHT * CHANNELS // 29472 bytes
// Line drop detection parameters
EXPECTED_FPS = 200
EXPECTED_INTERVAL_MS = 1000.0 / EXPECTED_FPS // 5ms for 200fps
DROP_THRESHOLD_MS = EXPECTED_INTERVAL_MS * 2.5
STATS_WINDOW_SIZE = 100
STATUS_INTERVAL = 100
UDP_PORT = 5000
)
type FrameStats struct {
intervals []float64
totalDrops int
dropsSince int
frameCount int
firstFrameTime time.Time
lastFrameTime time.Time
totalBytes int64
}
func newFrameStats() *FrameStats {
return &FrameStats{
intervals: make([]float64, 0, STATS_WINDOW_SIZE),
}
}
func (fs *FrameStats) addInterval(intervalMs float64) {
if len(fs.intervals) >= STATS_WINDOW_SIZE {
fs.intervals = fs.intervals[1:]
}
fs.intervals = append(fs.intervals, intervalMs)
}
func (fs *FrameStats) avgInterval() float64 {
if len(fs.intervals) == 0 {
return 0
}
sum := 0.0
for _, v := range fs.intervals {
sum += v
}
return sum / float64(len(fs.intervals))
}
func (fs *FrameStats) printSummary() {
if fs.frameCount == 0 {
return
}
elapsed := time.Since(fs.firstFrameTime).Seconds()
avgFPS := float64(fs.frameCount) / elapsed
avgInterval := fs.avgInterval()
instantFPS := 0.0
if avgInterval > 0 {
instantFPS = 1000.0 / avgInterval
}
bandwidth := float64(fs.totalBytes) / elapsed / (1024 * 1024) // MB/s
fmt.Println("\n=== Final Statistics ===")
fmt.Printf("Total Frames: %d\n", fs.frameCount)
fmt.Printf("Total Time: %.2f seconds\n", elapsed)
fmt.Printf("Average FPS: %.2f\n", avgFPS)
fmt.Printf("Instant FPS: %.2f\n", instantFPS)
fmt.Printf("Total Drops: %d\n", fs.totalDrops)
fmt.Printf("Total Data: %.2f MB\n", float64(fs.totalBytes)/(1024*1024))
fmt.Printf("Bandwidth: %.2f MB/s\n", bandwidth)
}
func main() {
// Setup UDP socket
addr := net.UDPAddr{
Port: UDP_PORT,
IP: net.ParseIP("0.0.0.0"),
}
conn, err := net.ListenUDP("udp", &addr)
if err != nil {
log.Fatal("UDP listen failed:", err)
}
defer conn.Close()
// Set receive buffer size to 16MB
if err := conn.SetReadBuffer(16 * 1024 * 1024); err != nil {
log.Printf("Warning: Failed to set recv buffer: %v", err)
}
fmt.Printf("High-Performance UDP Receiver for Raw %dx%d RGB columns\n", COLUMN_WIDTH, COLUMN_HEIGHT)
fmt.Printf("Listening on UDP port %d\n", UDP_PORT)
fmt.Printf("Expected frame size: %d bytes\n", FRAME_SIZE)
fmt.Printf("Press Ctrl+C to stop\n\n")
stats := newFrameStats()
buffer := make([]byte, 65536)
// Handle graceful shutdown
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
// Channel for shutdown
done := make(chan bool)
// Start UDP receiver goroutine
go func() {
for {
select {
case <-done:
return
default:
n, _, err := conn.ReadFromUDP(buffer)
if err != nil {
select {
case <-done:
return
default:
log.Printf("UDP read error: %v", err)
continue
}
}
if n != FRAME_SIZE {
// Wrong packet size, skip
continue
}
currentTime := time.Now()
// Initialize timing on first frame
if stats.firstFrameTime.IsZero() {
stats.firstFrameTime = currentTime
fmt.Println("Started receiving frames...")
}
// Line drop detection
if !stats.lastFrameTime.IsZero() {
intervalMs := float64(currentTime.Sub(stats.lastFrameTime).Microseconds()) / 1000.0
stats.addInterval(intervalMs)
if intervalMs > DROP_THRESHOLD_MS {
stats.totalDrops++
stats.dropsSince++
}
}
stats.lastFrameTime = currentTime
stats.frameCount++
stats.totalBytes += int64(n)
// Print status
if stats.frameCount%STATUS_INTERVAL == 0 {
elapsed := currentTime.Sub(stats.firstFrameTime).Seconds()
realFPS := float64(stats.frameCount) / elapsed
avgInterval := stats.avgInterval()
instantFPS := 0.0
if avgInterval > 0 {
instantFPS = 1000.0 / avgInterval
}
bandwidth := float64(stats.totalBytes) / elapsed / (1024 * 1024) // MB/s
status := fmt.Sprintf("Frame %6d: Real FPS: %6.1f | Instant: %6.1f | BW: %6.2f MB/s",
stats.frameCount, realFPS, instantFPS, bandwidth)
if stats.dropsSince > 0 {
status += fmt.Sprintf(" | ⚠️ %d drops", stats.dropsSince)
stats.dropsSince = 0
} else if stats.totalDrops > 0 {
status += fmt.Sprintf(" | Total drops: %d", stats.totalDrops)
}
fmt.Println(status)
}
}
}
}()
// Wait for shutdown signal
<-sigChan
fmt.Println("\nShutdown signal received...")
close(done)
// Give a moment for cleanup
time.Sleep(100 * time.Millisecond)
// Print final statistics
stats.printSummary()
fmt.Println("Goodbye!")
}

View File

@ -6,17 +6,49 @@
# "numpy",
# ]
# ///
#
# NOTE: For higher performance (?), see the Go implementation:
# scripts/go/main.go -
# Build: Run scripts/build_go_receiver.ps1 (Windows) or scripts/build_go_receiver.sh (Linux/macOS)
# See scripts/go/README.md for setup instructions
#
# Usage:
# python recv_raw_rolling.py # With OpenCV display (default)
# python recv_raw_rolling.py --no-display # Stats only, no display (max performance)
import socket
import numpy as np
import cv2
import time
import argparse
from collections import deque
# Parse command-line arguments
parser = argparse.ArgumentParser(description='Receive raw column stream via UDP')
parser.add_argument('--no-display', action='store_true',
help='Disable OpenCV display for maximum performance (stats only)')
parser.add_argument('--display-fps', type=int, default=0,
help='Limit display refresh rate (0=every frame, 60=60fps, etc). Reduces cv2.imshow() overhead while receiving all frames')
parser.add_argument('--save-mjpeg', type=str, default=None,
help='Save rolling display to MJPEG video file (e.g., output.avi). Uses display-fps if set, otherwise 30 fps')
args = parser.parse_args()
# Import OpenCV only if display is enabled
ENABLE_DISPLAY = not args.no_display
if ENABLE_DISPLAY:
import cv2
# Debug flag - set to True to see frame reception details
DEBUG = False
# Rotation mode - set to rotate incoming data before display
# Options: None, cv2.ROTATE_90_CLOCKWISE, cv2.ROTATE_90_COUNTERCLOCKWISE, cv2.ROTATE_180
ROTATION = cv2.ROTATE_90_COUNTERCLOCKWISE # Rotate rows to columns
# Line drop detection parameters
EXPECTED_FPS = 200 # Expected frame rate (from 200fps ini file)
EXPECTED_INTERVAL_MS = 1000.0 / EXPECTED_FPS # 5ms for 200fps
DROP_THRESHOLD_MS = EXPECTED_INTERVAL_MS * 2.5 # Alert if gap > 2.5x expected (12.5ms)
STATS_WINDOW_SIZE = 100 # Track stats over last N frames
STATUS_INTERVAL = 100 # Print status every N frames
# OPTIMIZED: Using NumPy indexing instead of cv2.rotate() for better performance
# Extracting first row and reversing it is equivalent to ROTATE_90_COUNTERCLOCKWISE + first column
# Stream parameters (match your GStreamer sender)
COLUMN_WIDTH = 4 # Width from 200fps-2456x4pix-cw.ini
@ -32,21 +64,56 @@ UDP_IP = "0.0.0.0"
UDP_PORT = 5000
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 16777216) # 16MB buffer
sock.bind((UDP_IP, UDP_PORT))
print(f"Receiving raw {COLUMN_WIDTH}x{COLUMN_HEIGHT} RGB columns on UDP port {UDP_PORT}")
print(f"Display width: {DISPLAY_WIDTH} pixels (rolling)")
if ENABLE_DISPLAY:
if args.display_fps > 0:
print(f"Display: ENABLED - Rolling display ({DISPLAY_WIDTH}x{DISPLAY_HEIGHT}) @ {args.display_fps} Hz (throttled)")
else:
print(f"Display: ENABLED - Rolling display ({DISPLAY_WIDTH}x{DISPLAY_HEIGHT}) @ full rate")
else:
print(f"Display: DISABLED - Stats only mode (max performance)")
if DEBUG:
print(f"Expected frame size: {FRAME_SIZE} bytes")
cv2.namedWindow("Rolling Column Stream", cv2.WINDOW_NORMAL)
# Initialize display if enabled
if ENABLE_DISPLAY:
cv2.namedWindow("Rolling Column Stream", cv2.WINDOW_NORMAL)
rolling_buffer = np.zeros((DISPLAY_HEIGHT, DISPLAY_WIDTH, CHANNELS), dtype=np.uint8)
current_column = 0
# Display throttling support
if args.display_fps > 0:
display_interval = 1.0 / args.display_fps # seconds between display updates
last_display_time = 0
else:
display_interval = 0 # Update every frame
last_display_time = 0
# MJPEG video writer setup
video_writer = None
if args.save_mjpeg:
# Use display-fps if set, otherwise default to 30 fps for video
video_fps = args.display_fps if args.display_fps > 0 else 30
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
video_writer = cv2.VideoWriter(args.save_mjpeg, fourcc, video_fps,
(DISPLAY_WIDTH, DISPLAY_HEIGHT))
print(f"Recording to: {args.save_mjpeg} @ {video_fps} fps")
# Initialize the rolling buffer
rolling_buffer = np.zeros((DISPLAY_HEIGHT, DISPLAY_WIDTH, CHANNELS), dtype=np.uint8)
current_column = 0
frame_count = 0
# Line drop detection state
last_frame_time = None
first_frame_time = None
frame_intervals = deque(maxlen=STATS_WINDOW_SIZE)
total_drops = 0
drops_since_last_status = 0
while True:
current_time = time.time()
data, addr = sock.recvfrom(65536)
if len(data) != FRAME_SIZE:
@ -54,33 +121,81 @@ while True:
print(f"Received {len(data)} bytes (expected {FRAME_SIZE}), skipping...")
continue
if DEBUG:
frame_count += 1
if frame_count % 30 == 0:
print(f"Received {frame_count} frames, current column: {current_column}")
# Parse the incoming data
frame = np.frombuffer(data, dtype=np.uint8).reshape((COLUMN_WIDTH, COLUMN_HEIGHT, CHANNELS))
# Initialize timing on first frame
if first_frame_time is None:
first_frame_time = current_time
# Apply rotation if configured
if ROTATION is not None:
rotated = cv2.rotate(frame, ROTATION)
# Line drop detection
if last_frame_time is not None:
interval_ms = (current_time - last_frame_time) * 1000
frame_intervals.append(interval_ms)
# Detect line drop
if interval_ms > DROP_THRESHOLD_MS:
total_drops += 1
drops_since_last_status += 1
last_frame_time = current_time
frame_count += 1
# Print status every STATUS_INTERVAL frames
if frame_count % STATUS_INTERVAL == 0:
elapsed_time = current_time - first_frame_time
real_fps = frame_count / elapsed_time if elapsed_time > 0 else 0
avg_interval = np.mean(frame_intervals) if len(frame_intervals) > 0 else 0
instant_fps = 1000.0 / avg_interval if avg_interval > 0 else 0
status = f"Frame {frame_count}: Real FPS: {real_fps:.1f} | Instant: {instant_fps:.1f}"
if drops_since_last_status > 0:
status += f" | ⚠️ {drops_since_last_status} drops detected"
drops_since_last_status = 0
else:
status += f" | Total drops: {total_drops}"
print(status)
if ENABLE_DISPLAY:
# Parse the incoming data - ALWAYS process every frame
frame = np.frombuffer(data, dtype=np.uint8).reshape((COLUMN_WIDTH, COLUMN_HEIGHT, CHANNELS))
# OPTIMIZED: Extract first row and transpose to column (equivalent to rotating and taking first column)
# This avoids expensive cv2.rotate() - uses NumPy indexing instead
# For ROTATE_90_COUNTERCLOCKWISE: first column of rotated = first row reversed
column = frame[0, ::-1, :].reshape(COLUMN_HEIGHT, 1, CHANNELS)
# Insert the single column into the rolling buffer at the current position
# This happens for EVERY received frame
rolling_buffer[:, current_column:current_column+1, :] = column
# Move to the next column position, wrapping around when reaching the end
current_column = (current_column + 1) % DISPLAY_WIDTH
# Display throttling: only refresh display at specified rate
# This reduces cv2.imshow() / cv2.waitKey() overhead while keeping all data
should_display = True
if args.display_fps > 0:
if current_time - last_display_time >= display_interval:
last_display_time = current_time
should_display = True
else:
should_display = False
if should_display:
# Display the rolling buffer (clean, no overlays)
cv2.imshow("Rolling Column Stream", rolling_buffer)
# Write frame to video if recording
if video_writer is not None:
video_writer.write(rolling_buffer)
if cv2.waitKey(1) == 27: # ESC to quit
break
else:
rotated = frame
# Extract only the first column for smoother rolling (1 pixel/frame)
column = rotated[:, 0:1, :]
# No display mode - just validate the data can be reshaped
frame = np.frombuffer(data, dtype=np.uint8).reshape((COLUMN_WIDTH, COLUMN_HEIGHT, CHANNELS))
# Insert the single column into the rolling buffer at the current position
rolling_buffer[:, current_column:current_column+1, :] = column
# Move to the next column position, wrapping around when reaching the end
current_column = (current_column + 1) % DISPLAY_WIDTH
# Display the rolling buffer
cv2.imshow("Rolling Column Stream", rolling_buffer)
if cv2.waitKey(1) == 27: # ESC to quit
break
cv2.destroyAllWindows()
if ENABLE_DISPLAY:
if video_writer is not None:
video_writer.release()
print(f"Video saved: {args.save_mjpeg}")
cv2.destroyAllWindows()

232
scripts/udp_optimize.ps1 Normal file
View File

@ -0,0 +1,232 @@
# UDP Performance Optimization Script for Windows
# Run as Administrator
#
# Usage:
# .\udp_optimize.ps1 query - Show current settings
# .\udp_optimize.ps1 apply - Apply optimizations (backs up to udp_backup.reg)
# .\udp_optimize.ps1 revert - Restore from backup
param(
[Parameter(Mandatory=$true)]
[ValidateSet("query", "apply", "revert")]
[string]$Action
)
# Check if running as Administrator
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Error "This script must be run as Administrator!"
exit 1
}
$backupFile = "udp_backup.reg"
# Define registry settings
$regSettings = @(
@{
Path = "HKLM:\SYSTEM\CurrentControlSet\Services\AFD\Parameters"
Name = "DefaultReceiveWindow"
Type = "DWORD"
Value = 16777216 # 16MB
Description = "UDP Receive Buffer Size"
},
@{
Path = "HKLM:\SYSTEM\CurrentControlSet\Services\AFD\Parameters"
Name = "LargeBufferSize"
Type = "DWORD"
Value = 4096
Description = "Large Buffer Size"
},
@{
Path = "HKLM:\SYSTEM\CurrentControlSet\Services\AFD\Parameters"
Name = "MediumBufferSize"
Type = "DWORD"
Value = 1504
Description = "Medium Buffer Size"
},
@{
Path = "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"
Name = "TcpWindowSize"
Type = "DWORD"
Value = 65535
Description = "TCP Window Size"
},
@{
Path = "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"
Name = "MaxConnectionsPerServer"
Type = "DWORD"
Value = 16
Description = "Max Connections Per Server"
},
@{
Path = "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"
Name = "MaxFreeTcbs"
Type = "DWORD"
Value = 16000
Description = "Max Free TCBs"
},
@{
Path = "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"
Name = "DefaultTTL"
Type = "DWORD"
Value = 64
Description = "Default TTL"
}
)
function Query-Settings {
Write-Host "`n=== Current UDP/TCP Performance Settings ===" -ForegroundColor Cyan
Write-Host ""
foreach ($setting in $regSettings) {
$path = $setting.Path
$name = $setting.Name
# Ensure path exists
if (-not (Test-Path $path)) {
Write-Host "[$name] Path does not exist: $path" -ForegroundColor Yellow
Write-Host " Description: $($setting.Description)" -ForegroundColor Gray
Write-Host " Current: NOT SET" -ForegroundColor Yellow
Write-Host " Recommended: $($setting.Value)" -ForegroundColor Green
Write-Host ""
continue
}
try {
$currentValue = Get-ItemProperty -Path $path -Name $name -ErrorAction Stop
Write-Host "[$name] $($setting.Description)" -ForegroundColor White
Write-Host " Path: $path" -ForegroundColor Gray
Write-Host " Current: $($currentValue.$name)" -ForegroundColor Yellow
Write-Host " Recommended: $($setting.Value)" -ForegroundColor Green
}
catch {
Write-Host "[$name] $($setting.Description)" -ForegroundColor White
Write-Host " Path: $path" -ForegroundColor Gray
Write-Host " Current: NOT SET" -ForegroundColor Yellow
Write-Host " Recommended: $($setting.Value)" -ForegroundColor Green
}
Write-Host ""
}
}
function Backup-Settings {
Write-Host "Creating backup..." -ForegroundColor Cyan
$backupContent = "Windows Registry Editor Version 5.00`r`n`r`n"
foreach ($setting in $regSettings) {
$path = $setting.Path
$name = $setting.Name
if (Test-Path $path) {
try {
$currentValue = Get-ItemProperty -Path $path -Name $name -ErrorAction Stop
$regPath = $path -replace "HKLM:\\", "HKEY_LOCAL_MACHINE\"
$backupContent += "[$regPath]`r`n"
$backupContent += "`"$name`"=dword:$("{0:x8}" -f $currentValue.$name)`r`n`r`n"
}
catch {
# Value doesn't exist, note it in backup
$regPath = $path -replace "HKLM:\\", "HKEY_LOCAL_MACHINE\"
$backupContent += "; [$regPath]`r`n"
$backupContent += "; `"$name`" was not set`r`n`r`n"
}
}
}
$backupContent | Out-File -FilePath $backupFile -Encoding ASCII
Write-Host "Backup saved to: $backupFile" -ForegroundColor Green
}
function Apply-Settings {
Write-Host "`n=== Applying UDP/TCP Optimizations ===" -ForegroundColor Cyan
# Create backup first
Backup-Settings
Write-Host ""
$changedCount = 0
foreach ($setting in $regSettings) {
$path = $setting.Path
$name = $setting.Name
$value = $setting.Value
# Ensure registry path exists
if (-not (Test-Path $path)) {
Write-Host "Creating registry path: $path" -ForegroundColor Yellow
New-Item -Path $path -Force | Out-Null
}
try {
# Get current value
$currentValue = $null
try {
$current = Get-ItemProperty -Path $path -Name $name -ErrorAction Stop
$currentValue = $current.$name
}
catch {
$currentValue = $null
}
if ($currentValue -eq $value) {
Write-Host "[UNCHANGED] $name = $value" -ForegroundColor Gray
}
else {
Set-ItemProperty -Path $path -Name $name -Value $value -Type $setting.Type
Write-Host "[APPLIED] $name = $value (was: $currentValue)" -ForegroundColor Green
$changedCount++
}
}
catch {
Write-Host "[ERROR] Failed to set $name : $_" -ForegroundColor Red
}
}
Write-Host "`n$changedCount settings changed." -ForegroundColor Cyan
if ($changedCount -gt 0) {
Write-Host "`n⚠️ IMPORTANT: Restart your computer for changes to take effect!" -ForegroundColor Yellow
}
}
function Revert-Settings {
if (-not (Test-Path $backupFile)) {
Write-Error "Backup file not found: $backupFile"
Write-Host "Run 'apply' first to create a backup, or restore manually." -ForegroundColor Yellow
exit 1
}
Write-Host "`n=== Reverting to Backed Up Settings ===" -ForegroundColor Cyan
Write-Host "Importing: $backupFile" -ForegroundColor Yellow
try {
$result = reg import $backupFile 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host "Settings restored successfully!" -ForegroundColor Green
Write-Host "`n⚠️ IMPORTANT: Restart your computer for changes to take effect!" -ForegroundColor Yellow
}
else {
Write-Error "Failed to import registry file: $result"
}
}
catch {
Write-Error "Error importing registry: $_"
}
}
# Main execution
switch ($Action) {
"query" {
Query-Settings
}
"apply" {
Apply-Settings
}
"revert" {
Revert-Settings
}
}
Write-Host "`nDone!" -ForegroundColor Cyan

View File

@ -497,6 +497,12 @@ gst_idsueyesrc_start (GstBaseSrc * bsrc)
SENSORINFO sInfo;
ret = is_GetCameraInfo (src->hCam, &cInfo);
ret = is_GetSensorInfo (src->hCam, &sInfo);
/* Log sensor information for debugging AOI issues */
if (ret == IS_SUCCESS) {
GST_DEBUG_OBJECT (src, "Sensor: %s, max size: %dx%d",
sInfo.strSensorName, sInfo.nMaxWidth, sInfo.nMaxHeight);
}
}
if (strlen (src->config_file)) {
@ -715,10 +721,20 @@ gst_idsueyesrc_create (GstPushSrc * psrc, GstBuffer ** buf)
GST_LOG_OBJECT (src, "create");
if (!src->is_started) {
/* Query and re-validate AOI configuration before starting capture.
* This is required when using AOI with Y offsets. */
IS_RECT rectAOI;
ret = is_AOI (src->hCam, IS_AOI_IMAGE_GET_AOI, (void *) &rectAOI,
sizeof (rectAOI));
if (ret == IS_SUCCESS) {
ret = is_AOI (src->hCam, IS_AOI_IMAGE_SET_AOI, (void *) &rectAOI,
sizeof (rectAOI));
}
ret = is_CaptureVideo (src->hCam, IS_DONT_WAIT);
if (ret != IS_SUCCESS) {
GST_ELEMENT_ERROR (src, STREAM, WRONG_TYPE,
("Failed to start video capture"), (NULL));
("Failed to start video capture: %s", gst_idsueyesrc_get_error_string (src, ret)), (NULL));
return GST_FLOW_ERROR;
}