@livedesk/client 0.1.94 → 0.1.96

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.
@@ -17,8 +17,12 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
17
17
  private let writeLock = NSLock()
18
18
  private var stream: SCStream?
19
19
  private var compressionSession: VTCompressionSession?
20
+ private var sampleCount: Int = 0
20
21
  private var frameCount: Int = 0
22
+ private var skippedCount: Int = 0
21
23
  private var encodedCount: Int = 0
24
+ private var encodedKeyCount: Int = 0
25
+ private var encodedDeltaCount: Int = 0
22
26
 
23
27
  init(displayIndex: Int, width: Int, height: Int, fps: Int, bitrateKbps: Int) {
24
28
  self.displayIndex = max(0, displayIndex)
@@ -52,7 +56,7 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
52
56
  configuration.width = width
53
57
  configuration.height = height
54
58
  configuration.minimumFrameInterval = CMTime(value: 1, timescale: CMTimeScale(fps))
55
- configuration.queueDepth = 1
59
+ configuration.queueDepth = 3
56
60
  configuration.showsCursor = false
57
61
  configuration.pixelFormat = kCVPixelFormatType_32BGRA
58
62
 
@@ -69,12 +73,15 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
69
73
 
70
74
  private func createCompressionSession() throws {
71
75
  var session: VTCompressionSession?
76
+ let encoderSpecification: [CFString: Any] = [
77
+ kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder: true
78
+ ]
72
79
  let status = VTCompressionSessionCreate(
73
80
  allocator: kCFAllocatorDefault,
74
81
  width: Int32(width),
75
82
  height: Int32(height),
76
83
  codecType: kCMVideoCodecType_H264,
77
- encoderSpecification: nil,
84
+ encoderSpecification: encoderSpecification as CFDictionary,
78
85
  imageBufferAttributes: nil,
79
86
  compressedDataAllocator: nil,
80
87
  outputCallback: Self.compressionCallback,
@@ -86,7 +93,9 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
86
93
  }
87
94
 
88
95
  VTSessionSetProperty(session, key: kVTCompressionPropertyKey_RealTime, value: kCFBooleanTrue)
96
+ VTSessionSetProperty(session, key: kVTCompressionPropertyKey_AllowTemporalCompression, value: kCFBooleanTrue)
89
97
  VTSessionSetProperty(session, key: kVTCompressionPropertyKey_AllowFrameReordering, value: kCFBooleanFalse)
98
+ VTSessionSetProperty(session, key: kVTCompressionPropertyKey_MaxFrameDelayCount, value: NSNumber(value: 1))
90
99
  VTSessionSetProperty(session, key: kVTCompressionPropertyKey_ProfileLevel, value: kVTProfileLevel_H264_Baseline_AutoLevel)
91
100
  VTSessionSetProperty(session, key: kVTCompressionPropertyKey_MaxKeyFrameInterval, value: NSNumber(value: fps))
92
101
  VTSessionSetProperty(session, key: kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, value: NSNumber(value: 1.0))
@@ -111,12 +120,18 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
111
120
  func stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of type: SCStreamOutputType) {
112
121
  guard type == .screen,
113
122
  CMSampleBufferDataIsReady(sampleBuffer),
114
- isCompleteFrame(sampleBuffer),
115
123
  let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer),
116
124
  let session = compressionSession else {
117
125
  return
118
126
  }
119
127
 
128
+ sampleCount += 1
129
+ guard isCompleteFrame(sampleBuffer) else {
130
+ skippedCount += 1
131
+ logCaptureProgressIfNeeded()
132
+ return
133
+ }
134
+
120
135
  frameCount += 1
121
136
  let pts = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
122
137
  let duration = CMTime(value: 1, timescale: CMTimeScale(fps))
@@ -139,6 +154,7 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
139
154
  if status != noErr && (frameCount == 1 || frameCount % 120 == 0) {
140
155
  fputs("LiveDeskSCK encode status=\(status) frames=\(frameCount)\n", stderr)
141
156
  }
157
+ logCaptureProgressIfNeeded()
142
158
  }
143
159
 
144
160
  func stream(_ stream: SCStream, didStopWithError error: Error) {
@@ -155,14 +171,22 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
155
171
  return rawStatus == SCFrameStatus.complete.rawValue
156
172
  }
157
173
 
174
+ private func logCaptureProgressIfNeeded() {
175
+ let interval = max(1, fps * 5)
176
+ if sampleCount == 1 || sampleCount % interval == 0 {
177
+ fputs("LiveDeskSCK capture samples=\(sampleCount) complete=\(frameCount) skipped=\(skippedCount)\n", stderr)
178
+ }
179
+ }
180
+
158
181
  private func writeEncodedSampleBuffer(_ sampleBuffer: CMSampleBuffer) {
159
182
  guard let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) else {
160
183
  return
161
184
  }
162
185
 
186
+ let keyFrame = isKeyFrame(sampleBuffer)
163
187
  var output = Data()
164
188
  appendAccessUnitDelimiter(to: &output)
165
- if isKeyFrame(sampleBuffer), let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer) {
189
+ if keyFrame, let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer) {
166
190
  appendParameterSet(formatDescription, index: 0, to: &output)
167
191
  appendParameterSet(formatDescription, index: 1, to: &output)
168
192
  }
@@ -205,8 +229,13 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
205
229
  writeLock.unlock()
206
230
 
207
231
  encodedCount += 1
232
+ if keyFrame {
233
+ encodedKeyCount += 1
234
+ } else {
235
+ encodedDeltaCount += 1
236
+ }
208
237
  if encodedCount == 1 || encodedCount % max(1, fps * 5) == 0 {
209
- fputs("LiveDeskSCK encoded frames=\(encodedCount) bytes=\(output.count)\n", stderr)
238
+ fputs("LiveDeskSCK encoded frames=\(encodedCount) key=\(encodedKeyCount) delta=\(encodedDeltaCount) bytes=\(output.count)\n", stderr)
210
239
  }
211
240
  }
212
241
 
@@ -17,8 +17,12 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
17
17
  private let writeLock = NSLock()
18
18
  private var stream: SCStream?
19
19
  private var compressionSession: VTCompressionSession?
20
+ private var sampleCount: Int = 0
20
21
  private var frameCount: Int = 0
22
+ private var skippedCount: Int = 0
21
23
  private var encodedCount: Int = 0
24
+ private var encodedKeyCount: Int = 0
25
+ private var encodedDeltaCount: Int = 0
22
26
 
23
27
  init(displayIndex: Int, width: Int, height: Int, fps: Int, bitrateKbps: Int) {
24
28
  self.displayIndex = max(0, displayIndex)
@@ -52,7 +56,7 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
52
56
  configuration.width = width
53
57
  configuration.height = height
54
58
  configuration.minimumFrameInterval = CMTime(value: 1, timescale: CMTimeScale(fps))
55
- configuration.queueDepth = 1
59
+ configuration.queueDepth = 3
56
60
  configuration.showsCursor = false
57
61
  configuration.pixelFormat = kCVPixelFormatType_32BGRA
58
62
 
@@ -69,12 +73,15 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
69
73
 
70
74
  private func createCompressionSession() throws {
71
75
  var session: VTCompressionSession?
76
+ let encoderSpecification: [CFString: Any] = [
77
+ kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder: true
78
+ ]
72
79
  let status = VTCompressionSessionCreate(
73
80
  allocator: kCFAllocatorDefault,
74
81
  width: Int32(width),
75
82
  height: Int32(height),
76
83
  codecType: kCMVideoCodecType_H264,
77
- encoderSpecification: nil,
84
+ encoderSpecification: encoderSpecification as CFDictionary,
78
85
  imageBufferAttributes: nil,
79
86
  compressedDataAllocator: nil,
80
87
  outputCallback: Self.compressionCallback,
@@ -86,7 +93,9 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
86
93
  }
87
94
 
88
95
  VTSessionSetProperty(session, key: kVTCompressionPropertyKey_RealTime, value: kCFBooleanTrue)
96
+ VTSessionSetProperty(session, key: kVTCompressionPropertyKey_AllowTemporalCompression, value: kCFBooleanTrue)
89
97
  VTSessionSetProperty(session, key: kVTCompressionPropertyKey_AllowFrameReordering, value: kCFBooleanFalse)
98
+ VTSessionSetProperty(session, key: kVTCompressionPropertyKey_MaxFrameDelayCount, value: NSNumber(value: 1))
90
99
  VTSessionSetProperty(session, key: kVTCompressionPropertyKey_ProfileLevel, value: kVTProfileLevel_H264_Baseline_AutoLevel)
91
100
  VTSessionSetProperty(session, key: kVTCompressionPropertyKey_MaxKeyFrameInterval, value: NSNumber(value: fps))
92
101
  VTSessionSetProperty(session, key: kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, value: NSNumber(value: 1.0))
@@ -111,12 +120,18 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
111
120
  func stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of type: SCStreamOutputType) {
112
121
  guard type == .screen,
113
122
  CMSampleBufferDataIsReady(sampleBuffer),
114
- isCompleteFrame(sampleBuffer),
115
123
  let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer),
116
124
  let session = compressionSession else {
117
125
  return
118
126
  }
119
127
 
128
+ sampleCount += 1
129
+ guard isCompleteFrame(sampleBuffer) else {
130
+ skippedCount += 1
131
+ logCaptureProgressIfNeeded()
132
+ return
133
+ }
134
+
120
135
  frameCount += 1
121
136
  let pts = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
122
137
  let duration = CMTime(value: 1, timescale: CMTimeScale(fps))
@@ -139,6 +154,7 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
139
154
  if status != noErr && (frameCount == 1 || frameCount % 120 == 0) {
140
155
  fputs("LiveDeskSCK encode status=\(status) frames=\(frameCount)\n", stderr)
141
156
  }
157
+ logCaptureProgressIfNeeded()
142
158
  }
143
159
 
144
160
  func stream(_ stream: SCStream, didStopWithError error: Error) {
@@ -155,14 +171,22 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
155
171
  return rawStatus == SCFrameStatus.complete.rawValue
156
172
  }
157
173
 
174
+ private func logCaptureProgressIfNeeded() {
175
+ let interval = max(1, fps * 5)
176
+ if sampleCount == 1 || sampleCount % interval == 0 {
177
+ fputs("LiveDeskSCK capture samples=\(sampleCount) complete=\(frameCount) skipped=\(skippedCount)\n", stderr)
178
+ }
179
+ }
180
+
158
181
  private func writeEncodedSampleBuffer(_ sampleBuffer: CMSampleBuffer) {
159
182
  guard let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) else {
160
183
  return
161
184
  }
162
185
 
186
+ let keyFrame = isKeyFrame(sampleBuffer)
163
187
  var output = Data()
164
188
  appendAccessUnitDelimiter(to: &output)
165
- if isKeyFrame(sampleBuffer), let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer) {
189
+ if keyFrame, let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer) {
166
190
  appendParameterSet(formatDescription, index: 0, to: &output)
167
191
  appendParameterSet(formatDescription, index: 1, to: &output)
168
192
  }
@@ -205,8 +229,13 @@ final class LiveDeskScreenCaptureKitEncoder: NSObject, SCStreamOutput, SCStreamD
205
229
  writeLock.unlock()
206
230
 
207
231
  encodedCount += 1
232
+ if keyFrame {
233
+ encodedKeyCount += 1
234
+ } else {
235
+ encodedDeltaCount += 1
236
+ }
208
237
  if encodedCount == 1 || encodedCount % max(1, fps * 5) == 0 {
209
- fputs("LiveDeskSCK encoded frames=\(encodedCount) bytes=\(output.count)\n", stderr)
238
+ fputs("LiveDeskSCK encoded frames=\(encodedCount) key=\(encodedKeyCount) delta=\(encodedDeltaCount) bytes=\(output.count)\n", stderr)
210
239
  }
211
240
  }
212
241
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livedesk/client",
3
- "version": "0.1.94",
3
+ "version": "0.1.96",
4
4
  "description": "LiveDesk local remote client",
5
5
  "type": "module",
6
6
  "bin": {