Vuo 2.4.4
Loading...
Searching...
No Matches
VuoScreenCapture.m
Go to the documentation of this file.
1
10#include "VuoScreenCapture.h"
11#include "VuoApp.h"
12#include "VuoGlPool.h"
13
15#import <AVFoundation/AVFoundation.h>
16#import <OpenGL/gl.h>
17
18#ifdef VUO_COMPILER
20 "title" : "VuoScreenCapture",
21 "dependencies" : [
22 "VuoApp",
23 "AVFoundation.framework",
24 "CoreMedia.framework",
25 "CoreVideo.framework"
26 ]
27 });
28#endif
29
31
35typedef struct
36{
37 CVOpenGLTextureCacheRef textureCache;
38 dispatch_queue_t queue;
39 AVCaptureSession *session;
41 void (*capturedImageTrigger)(VuoImage image);
43
48{
49}
50
54@interface VuoScreenCaptureDelegate : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
56@end
57
58@implementation VuoScreenCaptureDelegate
64- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
65{
66 CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
67
68#pragma clang diagnostic push
69#pragma clang diagnostic ignored "-Wdeprecated-declarations"
70 __block CVOpenGLTextureRef texture;
71 VuoGlContext_perform(^(CGLContextObj cgl_ctx){
72 CVOpenGLTextureCacheCreateTextureFromImage(NULL, _sci->textureCache, pixelBuffer, NULL, &texture);
73 });
74
76 CVOpenGLTextureGetName(texture),
77 GL_RGB,
78 CVPixelBufferGetWidth(pixelBuffer),
79 CVPixelBufferGetHeight(pixelBuffer),
81 VuoRetain(rectImage);
82 VuoImage image = VuoImage_makeCopy(rectImage, CVOpenGLTextureIsFlipped(texture), 0, 0, false);
83 _sci->capturedImageTrigger(image);
84 CVOpenGLTextureRelease(texture);
85 VuoRelease(rectImage);
86
87 VuoGlContext_perform(^(CGLContextObj cgl_ctx){
88 CVOpenGLTextureCacheFlush(_sci->textureCache, 0);
89 });
90#pragma clang diagnostic pop
91}
92@end
93
98{
100
101 VUOLOG_PROFILE_BEGIN(mainQueue);
102 dispatch_sync(dispatch_get_main_queue(), ^{
103 VUOLOG_PROFILE_END(mainQueue);
104 [sci->session stopRunning];
105 });
106 dispatch_sync(sci->queue, ^{});
107
108 [sci->session release];
109 [sci->delegate release];
110
111 if (sci->textureCache)
112 VuoGlContext_perform(^(CGLContextObj cgl_ctx){
113#pragma clang diagnostic push
114#pragma clang diagnostic ignored "-Wdeprecated-declarations"
115 CVOpenGLTextureCacheRelease(sci->textureCache);
116#pragma clang diagnostic pop
117 });
118
119 dispatch_release(sci->queue);
120 free(sci);
121}
122
126VuoScreenCapture VuoScreenCapture_make(VuoScreen screen, VuoRectangle rectangle, void (*capturedImage)(VuoImage image))
127{
128 if ( (rectangle.center.x-rectangle.size.x/2.) >= screen.width
129 || (rectangle.center.y-rectangle.size.y/2.) >= screen.height)
130 return NULL;
131
132 // AVCaptureScreenInput causes formerly-headless apps to begin bouncing endlessly in the dock.
133 // https://b33p.net/kosada/vuo/vuo/-/issues/18174
134 VuoApp_init(false);
135
138
139 sci->capturedImageTrigger = capturedImage;
140
141 sci->queue = dispatch_queue_create("org.vuo.VuoScreenCapture", NULL);
142
143 VUOLOG_PROFILE_BEGIN(mainQueue);
144 dispatch_sync(dispatch_get_main_queue(), ^{
145 VUOLOG_PROFILE_END(mainQueue);
147 sci->delegate.sci = sci;
148
149 sci->session = [AVCaptureSession new];
150 sci->session.sessionPreset = AVCaptureSessionPresetPhoto;
151
152 {
153 AVCaptureScreenInput *input = [[AVCaptureScreenInput alloc] initWithDisplayID:screen.id];
154 input.minFrameDuration = CMTimeMake(1, 120);
155
156 double width = rectangle.size.x;
157 if (width < 1)
158 width = screen.width;
159
160 double height = rectangle.size.y;
161 if (height < 1)
162 height = screen.height;
163
164 input.cropRect = CGRectMake(
165 (int)(rectangle.center.x - rectangle.size.x/2.),
166 (int)(screen.height - (rectangle.center.y - rectangle.size.y/2.) - height),
167 (int)width,
168 (int)height);
169 // input.capturesMouseClicks = YES;
170 [sci->session addInput:input];
171 [input release];
172 }
173
174 {
175 AVCaptureVideoDataOutput *output = [AVCaptureVideoDataOutput new];
176 [output setAlwaysDiscardsLateVideoFrames:YES];
177 [output setSampleBufferDelegate:sci->delegate queue:sci->queue];
178 [sci->session addOutput:output];
179 [output release];
180 }
181 });
182
183 {
184#pragma clang diagnostic push
185#pragma clang diagnostic ignored "-Wdeprecated-declarations"
186 CGLPixelFormatObj pf = VuoGlContext_makePlatformPixelFormat(false, false, -1);
187 __block CVReturn ret;
188 VuoGlContext_perform(^(CGLContextObj cgl_ctx){
189 ret = CVOpenGLTextureCacheCreate(NULL,
190 (CFDictionaryRef)@{
191 (NSString *)kCVOpenGLTextureCacheChromaSamplingModeKey: (NSString *)kCVOpenGLTextureCacheChromaSamplingModeBestPerformance
192 }, cgl_ctx, pf, NULL, &sci->textureCache);
193 });
194 CGLReleasePixelFormat(pf);
195#pragma clang diagnostic pop
196
197 if (ret != kCVReturnSuccess)
198 {
199 VUserLog("Error: Couldn't create texture cache: %d", ret);
201 return NULL;
202 }
203 }
204
205 {
206 VUOLOG_PROFILE_BEGIN(mainQueue);
207 dispatch_sync(dispatch_get_main_queue(), ^{
208 VUOLOG_PROFILE_END(mainQueue);
209 [sci->session startRunning];
210 });
211 }
212
213 return (VuoScreenCapture)sci;
214}