|
| 1 | +using ObsKit.NET; |
| 2 | +using ObsKit.NET.Outputs; |
| 3 | +using ObsKit.NET.Sources; |
| 4 | + |
| 5 | +Console.WriteLine("ObsKit.NET - Webcam Recording Test"); |
| 6 | +Console.WriteLine("===================================\n"); |
| 7 | + |
| 8 | +var obsPath = AppContext.BaseDirectory; |
| 9 | + |
| 10 | +if (!File.Exists(Path.Combine(obsPath, "obs.dll"))) |
| 11 | +{ |
| 12 | + Console.WriteLine("ERROR: OBS runtime not found at " + obsPath); |
| 13 | + Console.WriteLine("Expected obs.dll alongside the executable. See README.md."); |
| 14 | + return 1; |
| 15 | +} |
| 16 | + |
| 17 | +using var obs = Obs.Initialize(config => config |
| 18 | + .WithDataPath(Path.Combine(obsPath, "data", "libobs")) |
| 19 | + .WithModulePath( |
| 20 | + Path.Combine(obsPath, "obs-plugins", "64bit"), |
| 21 | + Path.Combine(obsPath, "data", "obs-plugins", "%module%")) |
| 22 | + .ForHeadlessOperation() |
| 23 | + .WithVideo(v => v.Resolution(1920, 1080).Fps(30)) |
| 24 | + .WithAudio(a => a.WithSampleRate(48000))); |
| 25 | + |
| 26 | +Console.WriteLine($"OBS {Obs.Version} initialized\n"); |
| 27 | + |
| 28 | +// Enumerate webcams |
| 29 | +var devices = WebcamCapture.ListDevices(); |
| 30 | +Console.WriteLine($"Available video capture devices ({devices.Count}):"); |
| 31 | +for (int i = 0; i < devices.Count; i++) |
| 32 | + Console.WriteLine($" [{i}] {devices[i].Name}"); |
| 33 | + |
| 34 | +if (devices.Count == 0) |
| 35 | +{ |
| 36 | + Console.WriteLine("\nNo video capture devices found. Connect a webcam and try again."); |
| 37 | + return 1; |
| 38 | +} |
| 39 | + |
| 40 | +// Pick the Logitech 4K (BRIO) by name when present; otherwise fall back to the first device. |
| 41 | +var chosen = devices.FirstOrDefault(d => |
| 42 | + d.Name.Contains("BRIO", StringComparison.OrdinalIgnoreCase) || |
| 43 | + d.Name.Contains("Logitech", StringComparison.OrdinalIgnoreCase) || |
| 44 | + d.Name.Contains("4K", StringComparison.OrdinalIgnoreCase)) |
| 45 | + ?? devices[0]; |
| 46 | + |
| 47 | +Console.WriteLine($"\nSelected: {chosen.Name}"); |
| 48 | + |
| 49 | +using var webcam = new WebcamCapture("Webcam", chosen.DeviceId); |
| 50 | + |
| 51 | +// Give the device a moment to start producing frames; some webcams take a beat after open. |
| 52 | +Console.WriteLine("Warming up capture device..."); |
| 53 | +for (int i = 0; i < 30 && webcam.Width == 0; i++) |
| 54 | + Thread.Sleep(100); |
| 55 | + |
| 56 | +Console.WriteLine($"Capture stream: {webcam.Width}x{webcam.Height}"); |
| 57 | +if (webcam.Width == 0 || webcam.Height == 0) |
| 58 | +{ |
| 59 | + Console.WriteLine("WARN: webcam reports 0x0 — frames may not be flowing yet. Will continue anyway."); |
| 60 | +} |
| 61 | + |
| 62 | +// Match the canvas to the device's native resolution so we record what the camera produces. |
| 63 | +var canvasW = webcam.Width > 0 ? webcam.Width : 1920u; |
| 64 | +var canvasH = webcam.Height > 0 ? webcam.Height : 1080u; |
| 65 | +Obs.SetVideo(v => v.Resolution(canvasW, canvasH).Fps(30)); |
| 66 | + |
| 67 | +// Build a scene with the webcam. |
| 68 | +using var scene = Obs.Scenes.Create("Webcam Scene"); |
| 69 | +scene.AddSource(webcam); |
| 70 | +scene.SetAsProgram(); |
| 71 | + |
| 72 | +Console.WriteLine($"Scene has {scene.ItemCount} source(s); canvas {canvasW}x{canvasH}\n"); |
| 73 | + |
| 74 | +// Sample a frame from the GPU before recording — confirms non-black content is reaching the canvas. |
| 75 | +Thread.Sleep(500); |
| 76 | +var probe = webcam.TakeScreenshot(); |
| 77 | +if (probe != null) |
| 78 | +{ |
| 79 | + long sum = 0; |
| 80 | + int sampleStride = Math.Max(1, probe.Pixels.Length / 4096); |
| 81 | + for (int i = 0; i < probe.Pixels.Length; i += sampleStride) |
| 82 | + sum += probe.Pixels[i]; |
| 83 | + double avg = (double)sum / (probe.Pixels.Length / sampleStride); |
| 84 | + Console.WriteLine($"Pre-record screenshot: {probe.Width}x{probe.Height}, mean byte value = {avg:F1}"); |
| 85 | + if (avg < 1.0) |
| 86 | + Console.WriteLine("WARN: screenshot looks black. The recording may still capture light if the device starts producing frames during record."); |
| 87 | +} |
| 88 | +else |
| 89 | +{ |
| 90 | + Console.WriteLine("Pre-record screenshot returned null."); |
| 91 | +} |
| 92 | + |
| 93 | +var outputPath = Path.Combine(Environment.CurrentDirectory, $"webcam_{DateTime.Now:yyyyMMdd_HHmmss}.mp4"); |
| 94 | +Console.WriteLine($"\nRecording to: {outputPath}"); |
| 95 | + |
| 96 | +using var recording = new RecordingOutput("Webcam Recording") |
| 97 | + .SetPath(outputPath) |
| 98 | + .SetFormat(RecordingFormat.Mp4) |
| 99 | + .WithDefaultEncoders(videoBitrate: 6000, audioBitrate: 192); |
| 100 | + |
| 101 | +if (!recording.Start()) |
| 102 | +{ |
| 103 | + Console.WriteLine($"Failed to start: {recording.LastError}"); |
| 104 | + return 1; |
| 105 | +} |
| 106 | + |
| 107 | +// Record a fixed 5 seconds so the test is deterministic (no user input needed). |
| 108 | +const int recordSeconds = 5; |
| 109 | +Console.WriteLine($"Recording for {recordSeconds} seconds..."); |
| 110 | +for (int i = 0; i < recordSeconds; i++) |
| 111 | +{ |
| 112 | + Thread.Sleep(1000); |
| 113 | + Console.WriteLine($" ...{i + 1}s frames={recording.TotalFrames} bytes={recording.TotalBytes:N0}"); |
| 114 | +} |
| 115 | + |
| 116 | +var totalFrames = recording.TotalFrames; |
| 117 | +var totalBytes = recording.TotalBytes; |
| 118 | +recording.Stop(); // waits for completion, then auto-disposes when Obs.AutoDispose is true |
| 119 | + |
| 120 | +Console.WriteLine($"\nStopped: frames={totalFrames} bytes={totalBytes:N0}"); |
| 121 | + |
| 122 | +// Validate the output file exists and has plausible size. |
| 123 | +if (!File.Exists(outputPath)) |
| 124 | +{ |
| 125 | + Console.WriteLine("FAIL: no output file produced."); |
| 126 | + return 1; |
| 127 | +} |
| 128 | + |
| 129 | +var fi = new FileInfo(outputPath); |
| 130 | +Console.WriteLine($"File: {outputPath} ({fi.Length:N0} bytes)"); |
| 131 | + |
| 132 | +if (totalFrames == 0) |
| 133 | +{ |
| 134 | + Console.WriteLine("FAIL: zero frames written to recording."); |
| 135 | + return 1; |
| 136 | +} |
| 137 | + |
| 138 | +Console.WriteLine("\nSUCCESS: webcam recording wrote frames. Open the MP4 to confirm content."); |
| 139 | +return 0; |
0 commit comments