feat: inference subsystem and optimization to decoder

This commit is contained in:
Siwat Sirichai 2025-11-09 00:57:08 +07:00
commit 3c83a57e44
19 changed files with 3897 additions and 0 deletions

152
test_stream.py Executable file
View file

@ -0,0 +1,152 @@
#!/usr/bin/env python3
"""
CLI test script for StreamDecoder
Tests RTSP stream decoding with NVDEC hardware acceleration
"""
import argparse
import time
import sys
from services.stream_decoder import StreamDecoderFactory, ConnectionStatus
def main():
parser = argparse.ArgumentParser(description='Test RTSP stream decoder with NVDEC')
parser.add_argument(
'--rtsp-url',
type=str,
required=True,
help='RTSP stream URL (e.g., rtsp://user:pass@host/path)'
)
parser.add_argument(
'--gpu-id',
type=int,
default=0,
help='GPU device ID'
)
parser.add_argument(
'--buffer-size',
type=int,
default=30,
help='Frame buffer size'
)
parser.add_argument(
'--duration',
type=int,
default=30,
help='Test duration in seconds'
)
parser.add_argument(
'--check-interval',
type=float,
default=1.0,
help='Status check interval in seconds'
)
args = parser.parse_args()
print("=" * 80)
print("RTSP Stream Decoder Test")
print("=" * 80)
print(f"RTSP URL: {args.rtsp_url}")
print(f"GPU ID: {args.gpu_id}")
print(f"Buffer Size: {args.buffer_size} frames")
print(f"Test Duration: {args.duration} seconds")
print("=" * 80)
print()
try:
# Create factory with shared CUDA context
print("[1/4] Initializing StreamDecoderFactory...")
factory = StreamDecoderFactory(gpu_id=args.gpu_id)
print("✓ Factory initialized with shared CUDA context\n")
# Create decoder
print("[2/4] Creating StreamDecoder...")
decoder = factory.create_decoder(
rtsp_url=args.rtsp_url,
buffer_size=args.buffer_size,
codec='h264'
)
print(f"✓ Decoder created: {decoder}\n")
# Start decoding
print("[3/4] Starting decoder thread...")
decoder.start()
print("✓ Decoder thread started\n")
# Monitor for specified duration
print(f"[4/4] Monitoring stream for {args.duration} seconds...")
print("-" * 80)
start_time = time.time()
last_frame_count = 0
while time.time() - start_time < args.duration:
time.sleep(args.check_interval)
# Get status
status = decoder.get_status()
buffer_size = decoder.get_buffer_size()
frame_count = decoder.frame_count
fps = (frame_count - last_frame_count) / args.check_interval
last_frame_count = frame_count
# Print status
elapsed = time.time() - start_time
print(f"[{elapsed:6.1f}s] Status: {status.value:12s} | "
f"Buffer: {buffer_size:2d}/{args.buffer_size:2d} | "
f"Frames: {frame_count:5d} | "
f"FPS: {fps:5.1f}")
# Try to get latest frame
if status == ConnectionStatus.CONNECTED:
frame = decoder.get_latest_frame()
if frame is not None:
print(f" Frame shape: {frame.shape}, dtype: {frame.dtype}, "
f"device: {frame.device}")
# Check for errors
if status == ConnectionStatus.ERROR:
print("\n✗ ERROR: Stream connection failed!")
break
print("-" * 80)
# Final statistics
print("\n" + "=" * 80)
print("Test Complete - Final Statistics")
print("=" * 80)
print(f"Total Frames Decoded: {decoder.frame_count}")
print(f"Average FPS: {decoder.frame_count / args.duration:.2f}")
print(f"Final Status: {decoder.get_status().value}")
print(f"Buffer Utilization: {decoder.get_buffer_size()}/{args.buffer_size}")
if decoder.frame_width and decoder.frame_height:
print(f"Frame Resolution: {decoder.frame_width}x{decoder.frame_height}")
print("=" * 80)
except KeyboardInterrupt:
print("\n\n✗ Interrupted by user")
sys.exit(1)
except Exception as e:
print(f"\n\n✗ Error: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
finally:
# Cleanup
if 'decoder' in locals():
print("\nCleaning up...")
decoder.stop()
print("✓ Decoder stopped")
print("\n✓ Test completed successfully")
sys.exit(0)
if __name__ == '__main__':
main()