mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-25 23:35:43 +00:00
Start recordings at the first accepted video frame
This commit is contained in:
@@ -394,13 +394,8 @@ final class ScreenCaptureRecorder: NSObject, SCStreamOutput, SCStreamDelegate {
|
||||
|
||||
func stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of outputType: SCStreamOutputType) {
|
||||
guard sessionStarted, sampleBuffer.isValid, isRecording else { return }
|
||||
guard let presentationTime = adjustedPresentationTime(for: sampleBuffer, outputType: outputType) else { return }
|
||||
|
||||
if outputType == .screen {
|
||||
if frameCount > 0 && CMTimeCompare(presentationTime, lastVideoPresentationTime) <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
guard let attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, createIfNecessary: false) as? [[SCStreamFrameInfo: Any]],
|
||||
let attachment = attachments.first,
|
||||
let statusRawValue = attachment[SCStreamFrameInfo.status] as? Int,
|
||||
@@ -413,8 +408,10 @@ final class ScreenCaptureRecorder: NSObject, SCStreamOutput, SCStreamDelegate {
|
||||
assetWriter?.status == .writing,
|
||||
videoInput.isReadyForMoreMediaData else { return }
|
||||
|
||||
if firstSampleTime == .zero {
|
||||
firstSampleTime = sampleBuffer.presentationTimeStamp
|
||||
// Only a complete frame that the writer can accept may establish time zero.
|
||||
guard let presentationTime = adjustedPresentationTime(for: sampleBuffer, outputType: outputType) else { return }
|
||||
if frameCount > 0 && CMTimeCompare(presentationTime, lastVideoPresentationTime) <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
lastSampleBuffer = sampleBuffer
|
||||
@@ -439,10 +436,16 @@ final class ScreenCaptureRecorder: NSObject, SCStreamOutput, SCStreamDelegate {
|
||||
print("Recording started")
|
||||
fflush(stdout)
|
||||
}
|
||||
} else if frameCount == 0 {
|
||||
// A failed crop/append must not leave an empty interval before frame one.
|
||||
firstSampleTime = .zero
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
guard frameCount > 0,
|
||||
let presentationTime = adjustedPresentationTime(for: sampleBuffer, outputType: outputType) else { return }
|
||||
|
||||
if outputType == .audio {
|
||||
guard let systemAudioInput else { return }
|
||||
appendAudioSampleBuffer(sampleBuffer, to: systemAudioInput, of: systemAudioWriter, firstSampleTime: &firstSystemAudioSampleTime, lastPresentationTime: &lastSystemAudioPresentationTime, presentationTime: presentationTime)
|
||||
|
||||
@@ -84,3 +84,19 @@ describe("ScreenCaptureKitRecorder window capture", () => {
|
||||
expect(recorderSource).toContain("self.windowCropRect = cropRect");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("ScreenCaptureKitRecorder first frame timing", () => {
|
||||
const callback = recorderSource.slice(recorderSource.indexOf("func stream(_ stream:"), recorderSource.indexOf("func stream(_ stream:") + 5000);
|
||||
it("validates a complete frame and writer readiness before setting time zero", () => {
|
||||
const clock = callback.indexOf("adjustedPresentationTime(for:");
|
||||
expect(clock).toBeGreaterThan(callback.indexOf("status == .complete"));
|
||||
expect(clock).toBeGreaterThan(callback.indexOf("videoInput.isReadyForMoreMediaData"));
|
||||
});
|
||||
it("resets the origin after a rejected first frame and gates audio on accepted video", () => {
|
||||
expect(callback).toMatch(/else if frameCount == 0\s*\{[^}]*firstSampleTime = \.zero/);
|
||||
const audioGuard = callback.indexOf("guard frameCount > 0,");
|
||||
expect(audioGuard).toBeGreaterThan(0);
|
||||
expect(audioGuard).toBeLessThan(callback.indexOf("if outputType == .audio"));
|
||||
});
|
||||
});
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user