From d412bc88249ccefb263fa60c35cc3bf18442b3b2 Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Thu, 26 Feb 2026 19:50:38 +0000 Subject: [PATCH] add udpserver switch to hevc in videotoolbox move capturevideopreview to its own file reorg --- Scream.xcodeproj/project.pbxproj | 12 +++- Scream/AppDelegate.swift | 20 ++---- .../CaptureEngine.swift | 6 +- Scream/CaptureVideoPreview.swift | 22 +++++++ .../ScreamPacket.swift | 0 Scream/UDPServer.swift | 62 +++++++++++++++++++ 6 files changed, 102 insertions(+), 20 deletions(-) rename CaptureEngine.swift => Scream/CaptureEngine.swift (98%) create mode 100644 Scream/CaptureVideoPreview.swift rename ScreamPacket.swift => Scream/ScreamPacket.swift (100%) create mode 100644 Scream/UDPServer.swift diff --git a/Scream.xcodeproj/project.pbxproj b/Scream.xcodeproj/project.pbxproj index 96a64bb..43c0e1f 100644 --- a/Scream.xcodeproj/project.pbxproj +++ b/Scream.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ A94E29F72F09B569006E583D /* ScreamPacket.swift in Sources */ = {isa = PBXBuildFile; fileRef = A94E29F62F09B569006E583D /* ScreamPacket.swift */; }; + A98010132F50D19D00A58EF7 /* UDPServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98010122F50D19D00A58EF7 /* UDPServer.swift */; }; + A98010152F50D9B100A58EF7 /* CaptureVideoPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98010142F50D9B100A58EF7 /* CaptureVideoPreview.swift */; }; A98E8BF02F05B2A0006D4458 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98E8BEB2F05B2A0006D4458 /* AppDelegate.swift */; }; A98E8BF12F05B2A0006D4458 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A98E8BEC2F05B2A0006D4458 /* Assets.xcassets */; }; A98E8BF22F05B2A0006D4458 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = A98E8BEE2F05B2A0006D4458 /* MainMenu.xib */; }; @@ -38,6 +40,8 @@ /* Begin PBXFileReference section */ A94E29F62F09B569006E583D /* ScreamPacket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreamPacket.swift; sourceTree = ""; }; + A98010122F50D19D00A58EF7 /* UDPServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UDPServer.swift; sourceTree = ""; }; + A98010142F50D9B100A58EF7 /* CaptureVideoPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaptureVideoPreview.swift; sourceTree = ""; }; A98E8BC02F05B26B006D4458 /* Scream.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Scream.app; sourceTree = BUILT_PRODUCTS_DIR; }; A98E8BCE2F05B26D006D4458 /* ScreamTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ScreamTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; A98E8BD82F05B26D006D4458 /* ScreamUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ScreamUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -81,9 +85,7 @@ A98E8BB72F05B26B006D4458 = { isa = PBXGroup; children = ( - A94E29F62F09B569006E583D /* ScreamPacket.swift */, A9D722602F07304C00050BB0 /* Config.xcconfig */, - A9D7225E2F070FE600050BB0 /* CaptureEngine.swift */, A98E8BEF2F05B2A0006D4458 /* Scream */, A98E8BF42F05B2A2006D4458 /* ScreamTests */, A98E8BF82F05B2A5006D4458 /* ScreamUITests */, @@ -109,6 +111,10 @@ A98E8BEC2F05B2A0006D4458 /* Assets.xcassets */, A98E8BEE2F05B2A0006D4458 /* MainMenu.xib */, A98E8BFC2F05D28D006D4458 /* ScreenRecorder.swift */, + A98010122F50D19D00A58EF7 /* UDPServer.swift */, + A9D7225E2F070FE600050BB0 /* CaptureEngine.swift */, + A94E29F62F09B569006E583D /* ScreamPacket.swift */, + A98010142F50D9B100A58EF7 /* CaptureVideoPreview.swift */, ); path = Scream; sourceTree = ""; @@ -272,6 +278,8 @@ A98E8BF02F05B2A0006D4458 /* AppDelegate.swift in Sources */, A9D7225F2F070FE600050BB0 /* CaptureEngine.swift in Sources */, A98E8BFD2F05D28D006D4458 /* ScreenRecorder.swift in Sources */, + A98010132F50D19D00A58EF7 /* UDPServer.swift in Sources */, + A98010152F50D9B100A58EF7 /* CaptureVideoPreview.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Scream/AppDelegate.swift b/Scream/AppDelegate.swift index 492db7d..e294d33 100644 --- a/Scream/AppDelegate.swift +++ b/Scream/AppDelegate.swift @@ -10,6 +10,7 @@ import Cocoa @main class AppDelegate: NSObject, NSApplicationDelegate { let sr = ScreenRecorder() + let udpserver = UDPServerImplementation(port: 03067) @IBOutlet var window: NSWindow! @@ -18,6 +19,9 @@ class AppDelegate: NSObject, NSApplicationDelegate { await sr.start() } } + @IBAction func Button2(_ sender: Any) { + udpserver.start() + } func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application @@ -25,6 +29,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { preview.frame.size = window.contentView!.frame.size window.contentView?.addSubview(preview) Button(self) + Button2(self) } func applicationWillTerminate(_ aNotification: Notification) { @@ -34,19 +39,4 @@ class AppDelegate: NSObject, NSApplicationDelegate { func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { return true } - - -} - -class CaptureVideoPreview: NSView { - init(layer: CALayer) { - super.init(frame: .zero) - wantsLayer = true - self.layer = layer - layer.autoresizingMask = [.layerWidthSizable, .layerHeightSizable] - } - - required init?(coder: NSCoder) { - fatalError() - } } diff --git a/CaptureEngine.swift b/Scream/CaptureEngine.swift similarity index 98% rename from CaptureEngine.swift rename to Scream/CaptureEngine.swift index cad51d4..3bf0d8c 100644 --- a/CaptureEngine.swift +++ b/Scream/CaptureEngine.swift @@ -42,7 +42,7 @@ class CaptureEngine: NSObject { allocator: kCFAllocatorDefault, width: 3200, height: 1800, - codecType: kCMVideoCodecType_H264, + codecType: kCMVideoCodecType_HEVC, encoderSpecification: videoEncoderSpec, imageBufferAttributes: sourceImageBufferAttrs, compressedDataAllocator: nil, @@ -71,7 +71,7 @@ class CaptureEngine: NSObject { frameProperties: nil, infoFlagsOut: nil ) { status, infoFlags, sampleBuffer in - print() +// print() } // outputHandler: self.outputHandler) @@ -144,7 +144,7 @@ class CaptureEngine: NSObject { err = VTSessionSetProperty(session, key: kVTCompressionPropertyKey_ExpectedFrameRate, value: expectedFrameRate as CFNumber) if err != noErr { print("failed to set to framerte \(err)") } - err = VTSessionSetProperty(session, key: kVTCompressionPropertyKey_ProfileLevel, value: kVTProfileLevel_H264_Main_AutoLevel) + err = VTSessionSetProperty(session, key: kVTCompressionPropertyKey_ProfileLevel, value: kVTProfileLevel_HEVC_Main_AutoLevel) if err != noErr { print("failed to set to profile level \(err)") } err = VTSessionSetProperty(session, key: kVTCompressionPropertyKey_AverageBitRate, value: 10 as CFNumber) diff --git a/Scream/CaptureVideoPreview.swift b/Scream/CaptureVideoPreview.swift new file mode 100644 index 0000000..2fa9275 --- /dev/null +++ b/Scream/CaptureVideoPreview.swift @@ -0,0 +1,22 @@ +// +// CaptureVideoPreview.swift +// Scream +// +// Created by neon443 on 26/02/2026. +// + +import Foundation +import Cocoa + +class CaptureVideoPreview: NSView { + init(layer: CALayer) { + super.init(frame: .zero) + wantsLayer = true + self.layer = layer + layer.autoresizingMask = [.layerWidthSizable, .layerHeightSizable] + } + + required init?(coder: NSCoder) { + fatalError() + } +} diff --git a/ScreamPacket.swift b/Scream/ScreamPacket.swift similarity index 100% rename from ScreamPacket.swift rename to Scream/ScreamPacket.swift diff --git a/Scream/UDPServer.swift b/Scream/UDPServer.swift new file mode 100644 index 0000000..cede375 --- /dev/null +++ b/Scream/UDPServer.swift @@ -0,0 +1,62 @@ +// +// UDPServer.swift +// Scream +// +// Created by neon443 on 26/02/2026. +// + +import Foundation +import Network + +final class UDPServerImplementation: Sendable { + private let connectionListener: NWListener + + //init a udp server at x port + init(port: UInt16) { + connectionListener = try! NWListener( + using: .udp, + on: NWEndpoint.Port(integerLiteral: port) + ) + + connectionListener.newConnectionHandler = { [weak self] connection in + connection.start(queue: .global()) + self?.receive(on: connection) + } + + connectionListener.stateUpdateHandler = { state in + print("state: \(state)") + } + } +} + +protocol UDPServer { + func start() + func stop() +} + +extension UDPServerImplementation: UDPServer { + func start() { + connectionListener.start(queue: .global()) + print("server started") + } + + func stop() { + connectionListener.cancel() + print("server stoped") + } +} + +private extension UDPServerImplementation { + func receive(on connection: NWConnection) { + connection.receiveMessage { data, contentContext, isComplete, error in + if let error { + print("error \(error)") + } + + if let data, + let message = String(data: data, encoding: .utf8) { + print(message) + } + } + } +}