[feat] improve the performance of ScreenCapturerSck

This commit is contained in:
dijunkun
2025-05-22 17:17:15 +08:00
parent 97f6c18296
commit 96c7d3174b

View File

@@ -72,13 +72,15 @@ class API_AVAILABLE(macos(14.0)) ScreenCapturerSckImpl : public ScreenCapturer {
unsigned char *nv12_frame_ = nullptr; unsigned char *nv12_frame_ = nullptr;
int width_ = 0; int width_ = 0;
int height_ = 0; int height_ = 0;
int fps_ = 30;
public: public:
// Called by SckHelper when shareable content is returned by ScreenCaptureKit. `content` will be // Called by SckHelper when shareable content is returned by ScreenCaptureKit. `content` will be
// nil if an error occurred. May run on an arbitrary thread. // nil if an error occurred. May run on an arbitrary thread.
void OnShareableContentCreated(SCShareableContent *content); void OnShareableContentCreated(SCShareableContent *content);
// Called by SckHelper to notify of a newly captured frame. May run on an arbitrary thread. // Called by SckHelper to notify of a newly captured frame. May run on an arbitrary thread.
void OnNewIOSurface(IOSurfaceRef io_surface, CFDictionaryRef attachment); // void OnNewIOSurface(IOSurfaceRef io_surface, CFDictionaryRef attachment);
void OnNewCVPixelBuffer(CVPixelBufferRef pixelBuffer, CFDictionaryRef attachment);
private: private:
// Called when starting the capturer or the configuration has changed (either from a // Called when starting the capturer or the configuration has changed (either from a
@@ -239,6 +241,7 @@ void ScreenCapturerSckImpl::OnShareableContentCreated(SCShareableContent *conten
config.width = filter.contentRect.size.width * filter.pointPixelScale; config.width = filter.contentRect.size.width * filter.pointPixelScale;
config.height = filter.contentRect.size.height * filter.pointPixelScale; config.height = filter.contentRect.size.height * filter.pointPixelScale;
config.captureResolution = SCCaptureResolutionNominal; config.captureResolution = SCCaptureResolutionNominal;
config.minimumFrameInterval = CMTimeMake(1, fps_);
std::lock_guard<std::mutex> lock(lock_); std::lock_guard<std::mutex> lock(lock_);
@@ -252,10 +255,12 @@ void ScreenCapturerSckImpl::OnShareableContentCreated(SCShareableContent *conten
// TODO: crbug.com/327458809 - Choose an appropriate sampleHandlerQueue for // TODO: crbug.com/327458809 - Choose an appropriate sampleHandlerQueue for
// best performance. // best performance.
NSError *add_stream_output_error; NSError *add_stream_output_error;
dispatch_queue_t queue = dispatch_queue_create("ScreenCaptureKit.Queue", DISPATCH_QUEUE_SERIAL);
bool add_stream_output_result = [stream_ addStreamOutput:helper_ bool add_stream_output_result = [stream_ addStreamOutput:helper_
type:SCStreamOutputTypeScreen type:SCStreamOutputTypeScreen
sampleHandlerQueue:nil sampleHandlerQueue:queue
error:&add_stream_output_error]; error:&add_stream_output_error];
if (!add_stream_output_result) { if (!add_stream_output_result) {
stream_ = nil; stream_ = nil;
LOG_ERROR("addStreamOutput failed"); LOG_ERROR("addStreamOutput failed");
@@ -279,12 +284,16 @@ void ScreenCapturerSckImpl::OnShareableContentCreated(SCShareableContent *conten
} }
} }
void ScreenCapturerSckImpl::OnNewIOSurface(IOSurfaceRef io_surface, CFDictionaryRef attachment) { void ScreenCapturerSckImpl::OnNewCVPixelBuffer(CVPixelBufferRef pixelBuffer,
size_t width = IOSurfaceGetWidth(io_surface); CFDictionaryRef attachment) {
size_t height = IOSurfaceGetHeight(io_surface); size_t width = CVPixelBufferGetWidth(pixelBuffer);
size_t height = CVPixelBufferGetHeight(pixelBuffer);
uint32_t aseed; CVReturn status = CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
IOSurfaceLock(io_surface, kIOSurfaceLockReadOnly, &aseed); if (status != kCVReturnSuccess) {
LOG_ERROR("Failed to lock CVPixelBuffer base address: %d", status);
return;
}
size_t required_size = width * height * 3 / 2; size_t required_size = width * height * 3 / 2;
if (!nv12_frame_ || (width_ * height_ * 3 / 2 < required_size)) { if (!nv12_frame_ || (width_ * height_ * 3 / 2 < required_size)) {
@@ -294,12 +303,26 @@ void ScreenCapturerSckImpl::OnNewIOSurface(IOSurfaceRef io_surface, CFDictionary
height_ = height; height_ = height;
} }
memcpy(nv12_frame_, IOSurfaceGetBaseAddress(io_surface), width * height * 3 / 2); void *base_y = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
size_t stride_y = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
void *base_uv = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
size_t stride_uv = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1);
unsigned char *dst_y = nv12_frame_;
for (size_t row = 0; row < height; ++row) {
memcpy(dst_y + row * width, static_cast<unsigned char *>(base_y) + row * stride_y, width);
}
unsigned char *dst_uv = nv12_frame_ + width * height;
for (size_t row = 0; row < height / 2; ++row) {
memcpy(dst_uv + row * width, static_cast<unsigned char *>(base_uv) + row * stride_uv, width);
}
_on_data(nv12_frame_, width * height * 3 / 2, width, height, _on_data(nv12_frame_, width * height * 3 / 2, width, height,
display_id_map_reverse_[current_display_]); display_id_map_reverse_[current_display_]);
IOSurfaceUnlock(io_surface, kIOSurfaceLockReadOnly, &aseed); CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
} }
void ScreenCapturerSckImpl::StartOrReconfigureCapturer() { void ScreenCapturerSckImpl::StartOrReconfigureCapturer() {
@@ -349,15 +372,12 @@ std::unique_ptr<ScreenCapturer> ScreenCapturerSck::CreateScreenCapturerSck() {
return; return;
} }
IOSurfaceRef ioSurface = CVPixelBufferGetIOSurface(pixelBuffer); CFRetain(pixelBuffer);
if (!ioSurface) {
return;
}
CFArrayRef attachmentsArray = CFArrayRef attachmentsArray = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, false);
CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, /*createIfNecessary=*/false); if (!attachmentsArray || CFArrayGetCount(attachmentsArray) == 0) {
if (!attachmentsArray || CFArrayGetCount(attachmentsArray) <= 0) {
LOG_ERROR("Discarding frame with no attachments"); LOG_ERROR("Discarding frame with no attachments");
CFRelease(pixelBuffer);
return; return;
} }
@@ -366,8 +386,10 @@ std::unique_ptr<ScreenCapturer> ScreenCapturerSck::CreateScreenCapturerSck() {
std::lock_guard<std::mutex> lock(_capturer_lock); std::lock_guard<std::mutex> lock(_capturer_lock);
if (_capturer) { if (_capturer) {
_capturer->OnNewIOSurface(ioSurface, attachment); _capturer->OnNewCVPixelBuffer(pixelBuffer, attachment);
} }
CFRelease(pixelBuffer);
} }
- (void)releaseCapturer { - (void)releaseCapturer {