Vuo  2.4.1
VuoRunnerCocoa.mm
Go to the documentation of this file.
1
10#include "VuoRunnerCocoa.h"
12
13#include <OpenGL/CGLMacro.h>
15#include <QuartzCore/CoreImage.h>
16
17#include <dispatch/dispatch.h>
18
19#include <zmq/zmq.h>
20#include <vector>
21#include <set>
22#include "VuoRunner.hh"
23#include "VuoCompiler.hh"
24#include "VuoCompilerIssue.hh"
25#include "VuoComposition.hh"
27#include "VuoException.hh"
28#include "VuoProtocol.hh"
29#include "VuoHeap.h"
30#include "VuoGlContext.h"
31#include "VuoGlPool.h"
32
33extern "C" {
34#include "VuoInteger.h"
35#include "VuoImageGet.h"
36}
37
39
43@interface VuoRunnerCocoa ()
44@property dispatch_queue_t runnerQueue;
45@property VuoRunner *runner;
46@property (retain) NSURL *compositionURL;
47@property (retain) NSString *compositionString;
48@property (retain) NSString *compositionSourcePath;
49@property (retain) NSString *compositionProcessName;
50@property (retain) NSString *compositionName;
51@property (retain) NSString *compositionDescription;
52@property (retain) NSString *compositionCopyright;
53@property VuoProtocol *protocol;
54@property set<VuoRunner::Port *> *changedPorts;
55@end
56
57@implementation VuoRunnerCocoa
58@synthesize runnerQueue;
59@synthesize runner;
60@synthesize compositionURL;
61@synthesize compositionString;
62@synthesize compositionSourcePath;
63@synthesize compositionProcessName;
64@synthesize compositionName;
65@synthesize compositionDescription;
66@synthesize compositionCopyright;
67@synthesize protocol;
68@synthesize changedPorts;
69
80+ (void)setGlobalRootContext:(CGLContextObj)context
81{
83}
84
94{
95 @synchronized(self)
96 {
98 {
102 }
103 }
104}
105
109+ (BOOL)isComposition:(NSURL *)compositionURL compliantWithProtocol:(VuoProtocol *)protocol
110{
111 VuoRunnerCocoa *runner = [[VuoRunnerCocoa alloc] initWithComposition:compositionURL protocol:protocol];
112 if (!runner)
113 return NO;
114
115 [runner release];
116 return YES;
117}
118
122+ (BOOL)isCompositionString:(NSString *)compositionString compliantWithProtocol:(VuoProtocol *)protocol
123{
124 VuoRunnerCocoa *runner = [[VuoRunnerCocoa alloc] initWithCompositionString:compositionString name:@"" sourcePath:nil protocol:protocol];
125 if (!runner)
126 return NO;
127
128 [runner release];
129 return YES;
130}
131
135- (id)initWithComposition:(NSURL *)theCompositionURL protocol:(VuoProtocol *)theProtocol
136{
137 NSError *error;
138 NSString *s = [NSString stringWithContentsOfURL:theCompositionURL encoding:NSUTF8StringEncoding error:&error];
139 if (!s)
140 {
141 NSLog(@"[VuoRunnerCocoa initWithComposition:protocol:] Error reading composition: %@", error);
142 [self release];
143 return nil;
144 }
145
146 self = [self initWithCompositionString:s name:[theCompositionURL lastPathComponent] sourcePath:nil protocol:theProtocol];
147 if (!self)
148 return nil;
149
150 self.compositionURL = theCompositionURL;
151
152 return self;
153}
154
158- (id)initWithCompositionString:(NSString *)theCompositionString name:(NSString *)processName sourcePath:(NSString *)sourcePath protocol:(VuoProtocol *)theProtocol
159{
160 if (!(self = [super init]))
161 return nil;
162
163 self.protocol = theProtocol;
164
165 self.runnerQueue = dispatch_queue_create("org.vuo.runner.cocoa", NULL);
166 self.runner = NULL;
167
168 self.compositionString = theCompositionString;
169 const char *compositionCString = [self.compositionString UTF8String];
170 if (!theProtocol->isCompositionCompliant(compositionCString))
171 {
172 [self release];
173 return nil;
174 }
175
176 self.compositionProcessName = processName;
177 self.compositionSourcePath = sourcePath;
178
179 VuoCompositionMetadata metadata(compositionCString);
180 self.compositionName = [NSString stringWithUTF8String:metadata.getName().c_str()];
181 self.compositionDescription = [NSString stringWithUTF8String:metadata.getDescription().c_str()];
182 self.compositionCopyright = [NSString stringWithUTF8String:metadata.getCopyright().c_str()];
183
184 self.changedPorts = new set<VuoRunner::Port *>();
185
186 return self;
187}
188
192- (void)dealloc
193{
194 dispatch_sync(self.runnerQueue, ^{
195 if (self.runner)
196 {
197 self.runner->stop();
198 delete self.runner;
199 }
200 });
201 dispatch_release(self.runnerQueue);
202 [compositionURL release];
203 [compositionString release];
204 [compositionSourcePath release];
205 [compositionName release];
206 [compositionDescription release];
207 [compositionCopyright release];
208 delete self.changedPorts;
209 [super dealloc];
210}
211
212- (void)compileAndRun
213{
215
216 dispatch_sync(self.runnerQueue, ^{
217 VuoCompilerIssues issues;
218 if (self.compositionURL)
219 self.runner = VuoCompiler::newSeparateProcessRunnerFromCompositionFile(
220 [[self.compositionURL path] UTF8String],
221 &issues);
222 else
223 self.runner = VuoCompiler::newSeparateProcessRunnerFromCompositionString(
224 [self.compositionString UTF8String],
225 [self.compositionProcessName UTF8String],
226 [self.compositionSourcePath UTF8String],
227 &issues);
228
229 if (!issues.isEmpty())
230 VUserLog("%s", issues.getLongDescription(false).c_str());
231
232 if (self.runner)
233 {
234 self.runner->start();
235 self.runner->subscribeToEventTelemetry("");
236
237 try
238 {
239 vector<VuoRunner::Port *> allInputPorts = self.runner->getPublishedInputPorts();
240 std::copy_if(allInputPorts.begin(), allInputPorts.end(), std::inserter(*self.changedPorts, self.changedPorts->begin()),
241 [] (VuoRunner::Port *port) { return ! port->getType().empty(); });
242 }
243 catch (VuoException &e)
244 {
245 VUserLog("Error: %s", e.what());
246 }
247 }
248 });
249}
250
254- (BOOL)isStopped
255{
256 __block BOOL isStopped = YES;
257 dispatch_sync(self.runnerQueue, ^{
258 if (self.runner && !self.runner->isStopped())
259 isStopped = NO;
260 });
261 return isStopped;
262}
263
267- (NSString *)description
268{
269 return [NSString stringWithFormat:@"VuoRunnerCocoa(\"%@\")", compositionName];
270}
271
276- (NSArray *)inputPorts
277{
278 if ([self isStopped])
279 return nil;
280
281 NSMutableArray *portsArray = [[NSMutableArray new] autorelease];
282 vector<VuoRunner::Port *> ports = self.runner->getPublishedInputPorts();
283 for (vector<VuoRunner::Port *>::iterator it = ports.begin(); it != ports.end(); ++it)
284 if (self.protocol && !self.protocol->hasInputPort((*it)->getName()))
285 [portsArray addObject:[NSString stringWithUTF8String:(*it)->getName().c_str()]];
286 return portsArray;
287}
288
293- (NSArray *)outputPorts
294{
295 if ([self isStopped])
296 return nil;
297
298 NSMutableArray *portsArray = [[NSMutableArray new] autorelease];
299 vector<VuoRunner::Port *> ports = self.runner->getPublishedOutputPorts();
300 for (vector<VuoRunner::Port *>::iterator it = ports.begin(); it != ports.end(); ++it)
301 if (self.protocol && !self.protocol->hasOutputPort((*it)->getName()))
302 [portsArray addObject:[NSString stringWithUTF8String:(*it)->getName().c_str()]];
303 return portsArray;
304}
305
335- (NSDictionary *)detailsForPort:(NSString *)portName
336{
337 const char *portNameCString = [portName UTF8String];
338 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName(portNameCString);
339 if (!port)
340 {
341 port = self.runner->getPublishedOutputPortWithName(portNameCString);
342 if (!port)
343 return nil;
344 }
345
346 NSMutableDictionary *details = [[NSMutableDictionary new] autorelease];
347
348 details[@"title"] = [NSString stringWithUTF8String:port->getName().c_str()];
349
350 details[@"type"] = [NSString stringWithUTF8String:port->getType().c_str()];
351
352 json_object *js = port->getDetails();
353 if (js)
354 {
355 json_object *o = NULL;
356
357 if (json_object_object_get_ex(js, "default", &o))
358 {
359 id cocoaObject = [VuoRunnerCocoa cocoaObjectWithVuoValue:o ofType:port->getType()];
360 if (cocoaObject)
361 details[@"default"] = cocoaObject;
362 }
363
364 if (json_object_object_get_ex(js, "suggestedMin", &o))
365 {
366 id cocoaObject = [VuoRunnerCocoa cocoaObjectWithVuoValue:o ofType:port->getType()];
367 if (cocoaObject)
368 details[@"suggestedMin"] = cocoaObject;
369 }
370
371 if (json_object_object_get_ex(js, "suggestedMax", &o))
372 {
373 id cocoaObject = [VuoRunnerCocoa cocoaObjectWithVuoValue:o ofType:port->getType()];
374 if (cocoaObject)
375 details[@"suggestedMax"] = cocoaObject;
376 }
377
378 if (json_object_object_get_ex(js, "suggestedStep", &o))
379 {
380 id cocoaObject = [VuoRunnerCocoa cocoaObjectWithVuoValue:o ofType:port->getType()];
381 if (cocoaObject)
382 details[@"suggestedStep"] = cocoaObject;
383 }
384
385 if (json_object_object_get_ex(js, "menuItems", &o))
386 {
387 NSMutableArray *menuItems = [NSMutableArray new];
388
389 int itemCount = json_object_array_length(o);
390 for (int i = 0; i < itemCount; ++i)
391 {
392 json_object *item = json_object_array_get_idx(o, i);
393 id menuItem = nil;
394
395 if (json_object_is_type(item, json_type_object))
396 {
397 json_object *value;
398 json_object_object_get_ex(item, "value", &value);
399 json_object *name;
400 json_object_object_get_ex(item, "name", &name);
401
402 id valueNS = nil;
403 if (json_object_is_type(value, json_type_string))
404 valueNS = [NSString stringWithUTF8String:json_object_get_string(value)];
405 else if (json_object_is_type(value, json_type_int))
406 valueNS = [NSNumber numberWithLong:json_object_get_int64(value)];
407
408 const char *summary = json_object_get_string(name);
409 menuItem = @{
410 @"value": valueNS,
411 @"name": [NSString stringWithUTF8String:summary],
412 };
413 }
414 else if (json_object_is_type(item, json_type_string))
415 menuItem = [NSString stringWithUTF8String:json_object_get_string(item)];
416
417 if (menuItem)
418 [menuItems addObject:menuItem];
419 }
420
421 details[@"menuItems"] = menuItems;
422 [menuItems release];
423 }
424 }
425
426 return details;
427}
428
433{
434 if ([self isStopped])
435 return nil;
436
437 NSMutableDictionary *properties = [[NSMutableDictionary new] autorelease];
438
439 vector<VuoRunner::Port *> ports = self.runner->getPublishedInputPorts();
440 for (vector<VuoRunner::Port *>::iterator it = ports.begin(); it != ports.end(); ++it)
441 if (self.protocol && !self.protocol->hasInputPort((*it)->getName()))
442 {
443 json_object *portValue = self.runner->getPublishedInputPortValue(*it);
444 const char *valueAsString = json_object_to_json_string_ext(portValue, JSON_C_TO_STRING_PLAIN);
445 properties[[NSString stringWithUTF8String:(*it)->getName().c_str()]] = [NSString stringWithUTF8String:valueAsString];
446 }
447
448 return properties;
449}
450
457- (BOOL)setInputValuesWithPropertyList:(id)propertyList
458{
459 if ([self isStopped])
460 return NO;
461
462 __block BOOL ok = YES;
463 __block map<VuoRunner::Port *, json_object *> m;
464 [(NSDictionary *)propertyList enumerateKeysAndObjectsUsingBlock:^(NSString *portName, NSString *value, BOOL *stop) {
465 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName([portName UTF8String]);
466 if (!port)
467 {
468 ok = NO;
469 return;
470 }
471
472 json_object *valueJson = json_tokener_parse([value UTF8String]);
473 if (!valueJson)
474 {
475 ok = NO;
476 return;
477 }
478
479 m[port] = valueJson;
480 }];
481
483
484 for (auto &kv : m)
485 {
486 self.changedPorts->insert(kv.first);
487 json_object_put(kv.second);
488 }
489
490 return ok;
491}
492
508- (BOOL)setInputValues:(NSDictionary *)namesAndValues
509{
510 if ([self isStopped])
511 return NO;
512
513 BOOL ok = YES;
514 map<VuoRunner::Port *, json_object *> m;
515 for (NSString *portName in namesAndValues)
516 {
517 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName([portName UTF8String]);
518 if (!port)
519 {
520 ok = NO;
521 continue;
522 }
523
524 id value = namesAndValues[portName];
526 if (!valueJson)
527 {
528 ok = NO;
529 continue;
530 }
531
532 m[port] = valueJson;
533 }
534
535 self.runner->setPublishedInputPortValues(m);
536
537 for (auto &kv : m)
538 {
539 self.changedPorts->insert(kv.first);
540 json_object_put(kv.second);
541 }
542
543 return ok;
544}
545
553- (BOOL)setInputJSON:(NSDictionary *)namesAndJSON
554{
555 if ([self isStopped])
556 return NO;
557
558 BOOL ok = YES;
559 map<VuoRunner::Port *, json_object *> m;
560 for (NSString *portName in namesAndJSON)
561 {
562 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName([portName UTF8String]);
563 if (!port)
564 {
565 ok = NO;
566 continue;
567 }
568
569 id nsValue = namesAndJSON[portName];
570 json_object *value = (json_object *)[nsValue pointerValue];
571
572 // If we're feeding a string to a VuoImage port, assume it's an image URL, and try to load it.
573 if (port->getType() == "VuoImage")
574 {
575 if (json_object_get_type(value) == json_type_string)
576 {
577 char *s = strdup(json_object_get_string(value));
578 VuoImage image = VuoImage_get(s);
579 if (!image)
580 {
581 NSLog(@"Error: Couldn't load image '%s'.\n", s);
582 free(s);
583 ok = NO;
584 continue;
585 }
586 free(s);
587
588 m[port] = VuoImage_getInterprocessJson(image);
589 }
590 }
591 else
592 m[port] = value;
593 }
594
595 self.runner->setPublishedInputPortValues(m);
596
597 for (auto &kv : m)
598 self.changedPorts->insert(kv.first);
599
600 return ok;
601}
602
620- (id)valueForOutputPort:(NSString *)portName
621{
622 if ([self isStopped])
623 return nil;
624
625 VuoRunner::Port *port = self.runner->getPublishedOutputPortWithName([portName UTF8String]);
626 if (!port)
627 return nil;
628
629 json_object *valueJson = self.runner->getPublishedOutputPortValue(port);
630 return [VuoRunnerCocoa cocoaObjectWithVuoValue:valueJson ofType:port->getType()];
631}
632
642- (GLuint)glTextureWithTarget:(GLuint)target forOutputPort:(NSString *)portName outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh
643{
644 if ([self isStopped])
645 return 0;
646
647 VuoRunner::Port *port = self.runner->getPublishedOutputPortWithName([portName UTF8String]);
648 if (!port)
649 return 0;
650
651 json_object *valueJson = self.runner->getPublishedOutputPortValue(port);
652 VuoImage vuoImage = VuoImage_makeFromJson(valueJson);
653 if (!vuoImage)
654 return 0;
655 json_object_put(valueJson);
656
657 if (target == GL_TEXTURE_RECTANGLE_ARB)
658 {
659 VuoRetain(vuoImage);
660 VuoImage newVuoImage = VuoImage_makeGlTextureRectangleCopy(vuoImage);
661 VuoRelease(vuoImage);
662 vuoImage = newVuoImage;
663 }
664
665 if (outputPixelsWide)
666 *outputPixelsWide = vuoImage->pixelsWide;
667 if (outputPixelsHigh)
668 *outputPixelsHigh = vuoImage->pixelsHigh;
669
670 VuoGlTexture_disown(vuoImage->glTextureName);
671
672 return vuoImage->glTextureName;
673}
674
694- (GLuint)glTextureFromProvider:(GLuint (^)(NSUInteger pixelsWide, NSUInteger pixelsHigh))provider forOutputPort:(NSString *)portName outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh ioSurface:(IOSurfaceRef *)outputIOSurface
695{
696 if ([self isStopped])
697 return 0;
698
699 VuoRunner::Port *port = self.runner->getPublishedOutputPortWithName([portName UTF8String]);
700 if (!port)
701 return 0;
702
703 json_object *valueJson = self.runner->getPublishedOutputPortValue(port);
704
705 GLuint (^provider2)(unsigned int, unsigned int) = ^GLuint(unsigned int pixelsWide, unsigned int pixelsHigh){
706 return provider(pixelsWide, pixelsHigh);
707 };
708 unsigned int outputPixelsWide2, outputPixelsHigh2;
709 GLuint outputTexture = VuoImage_resolveInterprocessJsonUsingTextureProvider(valueJson, provider2, &outputPixelsWide2, &outputPixelsHigh2, outputIOSurface);
710 *outputPixelsWide = outputPixelsWide2;
711 *outputPixelsHigh = outputPixelsHigh2;
712 return outputTexture;
713}
714
715@end
716
717
718@implementation VuoImageFilter
722+ (BOOL)canOpenComposition:(NSURL *)compositionURL
723{
724 return [self isComposition:compositionURL compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageFilter)];
725}
726
730+ (BOOL)canOpenCompositionString:(NSString *)compositionString
731{
732 return [self isCompositionString:compositionString compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageFilter)];
733}
734
741- (id)initWithComposition:(NSURL *)aCompositionURL
742{
743 if (!(self = [super initWithComposition:aCompositionURL protocol:VuoProtocol::getProtocol(VuoProtocol::imageFilter)]))
744 return nil;
745
746 [self compileAndRun];
747 if (! self.runner)
748 return nil;
749
750 return self;
751}
752
760- (id)initWithCompositionString:(NSString *)aCompositionString name:(NSString *)name sourcePath:(NSString *)sourcePath
761{
762 if (!(self = [super initWithCompositionString:aCompositionString name:name sourcePath:sourcePath protocol:VuoProtocol::getProtocol(VuoProtocol::imageFilter)]))
763 return nil;
764
765 [self compileAndRun];
766 if (! self.runner)
767 return nil;
768
769 return self;
770}
771
775static void VuoRunnerCocoa_doNothingCallback(VuoImage imageToFree)
776{
777}
778
782- (BOOL)executeWithGLTexture:(GLuint)textureName target:(GLuint)target pixelsWide:(unsigned long)pixelsWide pixelsHigh:(unsigned long)pixelsHigh atTime:(NSTimeInterval)time
783{
784 if ([self isStopped])
785 return NO;
786
787 {
788 VuoRunner::Port *port = self.runner->getPublishedInputPortWithName("image");
789 VuoImage image = VuoImage_makeClientOwned(textureName, GL_RGBA, pixelsWide, pixelsHigh, VuoRunnerCocoa_doNothingCallback, NULL);
790 image->glTextureTarget = target;
791 VuoRetain(image);
792 json_object *valueJson = VuoImage_getInterprocessJson(image);
793 VuoRelease(image);
794 map<VuoRunner::Port *, json_object *> m;
795 m[port] = valueJson;
796 self.runner->setPublishedInputPortValues(m);
797 json_object_put(valueJson);
798
799 self.changedPorts->insert(port);
800 }
801
802 return [self executeAtTime:time];
803}
804
808- (BOOL)executeAtTime:(NSTimeInterval)time
809{
810 if ([self isStopped])
811 return NO;
812
813 VuoRunner::Port *timePort = self.runner->getPublishedInputPortWithName("time");
814
815 {
816 json_object *valueJson = VuoReal_getJson(time);
817 map<VuoRunner::Port *, json_object *> m;
818 m[timePort] = valueJson;
819 self.runner->setPublishedInputPortValues(m);
820 json_object_put(valueJson);
821
822 self.changedPorts->insert(timePort);
823 }
824
825 self.runner->firePublishedInputPortEvent(*self.changedPorts);
826 self.changedPorts->clear();
827
828 self.runner->waitForFiredPublishedInputPortEvent();
829 return YES;
830}
831
845- (NSImage *)filterNSImage:(NSImage *)image atTime:(NSTimeInterval)time
846{
847 [self setInputValues:@{@"image":image}];
848
849 if (![self executeAtTime:time])
850 return nil;
851
852 return [self valueForOutputPort:@"outputImage"];
853}
854
869- (GLuint)filterGLTexture:(GLuint)textureName target:(GLuint)target pixelsWide:(NSUInteger)pixelsWide pixelsHigh:(NSUInteger)pixelsHigh atTime:(NSTimeInterval)time outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh
870{
871 if (![self executeWithGLTexture:textureName target:target pixelsWide:pixelsWide pixelsHigh:pixelsHigh atTime:time])
872 return 0;
873 return [self glTextureWithTarget:target forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh];
874}
875
905- (GLuint)filterGLTexture:(GLuint)textureName target:(GLuint)target pixelsWide:(NSUInteger)pixelsWide pixelsHigh:(NSUInteger)pixelsHigh atTime:(NSTimeInterval)time withTextureProvider:(GLuint (^)(NSUInteger pixelsWide, NSUInteger pixelsHigh))provider outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh ioSurface:(IOSurfaceRef *)outputIOSurface
906{
907 if (![self executeWithGLTexture:textureName target:target pixelsWide:pixelsWide pixelsHigh:pixelsHigh atTime:time])
908 return 0;
909
910 return [self glTextureFromProvider:provider forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh ioSurface:outputIOSurface];
911}
912
913@end
914
915
919@interface VuoImageGenerator ()
920@property NSUInteger previousSuggestedPixelsWide;
921@property NSUInteger previousSuggestedPixelsHigh;
922@end
923
924@implementation VuoImageGenerator
925@synthesize previousSuggestedPixelsWide;
926@synthesize previousSuggestedPixelsHigh;
927
931+ (BOOL)canOpenComposition:(NSURL *)compositionURL
932{
933 return [self isComposition:compositionURL compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageGenerator)];
934}
935
939+ (BOOL)canOpenCompositionString:(NSString *)compositionString
940{
941 return [self isCompositionString:compositionString compliantWithProtocol:VuoProtocol::getProtocol(VuoProtocol::imageGenerator)];
942}
943
950- (id)initWithComposition:(NSURL *)aCompositionURL
951{
952 if (!(self = [super initWithComposition:aCompositionURL protocol:VuoProtocol::getProtocol(VuoProtocol::imageGenerator)]))
953 return nil;
954
955 [self compileAndRun];
956 if (! self.runner)
957 return nil;
958
959 self.previousSuggestedPixelsWide = NSUIntegerMax;
960 self.previousSuggestedPixelsHigh = NSUIntegerMax;
961
962 return self;
963}
964
972- (id)initWithCompositionString:(NSString *)aCompositionString name:(NSString *)name sourcePath:(NSString *)sourcePath
973{
974 if (!(self = [super initWithCompositionString:aCompositionString name:name sourcePath:sourcePath protocol:VuoProtocol::getProtocol(VuoProtocol::imageGenerator)]))
975 return nil;
976
977 [self compileAndRun];
978 if (! self.runner)
979 return nil;
980
981 return self;
982}
983
987- (BOOL)executeWithSuggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time
988{
989 if ([self isStopped])
990 return NO;
991
992 VuoRunner::Port *timePort = self.runner->getPublishedInputPortWithName("time");
993 VuoRunner::Port *widthPort = self.runner->getPublishedInputPortWithName("width");
994 VuoRunner::Port *heightPort = self.runner->getPublishedInputPortWithName("height");
995
996 map<VuoRunner::Port *, json_object *> m;
997
998 m[timePort] = VuoReal_getJson(time);
999
1000 if (suggestedPixelsWide != self.previousSuggestedPixelsWide)
1001 {
1002 m[widthPort] = VuoInteger_getJson(suggestedPixelsWide);
1003 self.previousSuggestedPixelsWide = suggestedPixelsWide;
1004 }
1005 if (suggestedPixelsHigh != self.previousSuggestedPixelsHigh)
1006 {
1007 m[heightPort] = VuoInteger_getJson(suggestedPixelsHigh);
1008 self.previousSuggestedPixelsHigh = suggestedPixelsHigh;
1009 }
1010
1011 self.runner->setPublishedInputPortValues(m);
1012 for (auto &kv : m)
1013 {
1014 self.changedPorts->insert(kv.first);
1015 json_object_put(kv.second);
1016 }
1017
1018 self.runner->firePublishedInputPortEvent(*self.changedPorts);
1019 self.changedPorts->clear();
1020
1021 self.runner->waitForFiredPublishedInputPortEvent();
1022 return YES;
1023}
1024
1036- (NSImage *)generateNSImageWithSuggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time
1037{
1038 if (![self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1039 return nil;
1040 return [self valueForOutputPort:@"outputImage"];
1041}
1042
1053- (GLuint)generateGLTextureWithTarget:(GLuint)target suggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh
1054{
1055 if (![self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1056 return 0;
1057 return [self glTextureWithTarget:target forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh];
1058}
1059
1083- (GLuint)generateGLTextureWithProvider:(GLuint (^)(NSUInteger pixelsWide, NSUInteger pixelsHigh))provider suggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time outputPixelsWide:(NSUInteger *)outputPixelsWide pixelsHigh:(NSUInteger *)outputPixelsHigh ioSurface:(IOSurfaceRef *)outputIOSurface
1084{
1085 if (![self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1086 return 0;
1087 return [self glTextureFromProvider:provider forOutputPort:@"outputImage" outputPixelsWide:outputPixelsWide pixelsHigh:outputPixelsHigh ioSurface:outputIOSurface];
1088}
1089
1098- (VuoImage)generateVuoImageWithSuggestedPixelsWide:(NSUInteger)suggestedPixelsWide pixelsHigh:(NSUInteger)suggestedPixelsHigh atTime:(NSTimeInterval)time
1099{
1100 if (![self executeWithSuggestedPixelsWide:suggestedPixelsWide pixelsHigh:suggestedPixelsHigh atTime:time])
1101 return NULL;
1102
1103
1104 VuoRunner::Port *port = self.runner->getPublishedOutputPortWithName("outputImage");
1105 if (!port)
1106 return NULL;
1107
1108 json_object *valueJson = self.runner->getPublishedOutputPortValue(port);
1109 VuoImage image = VuoImage_makeFromJson(valueJson);
1110 json_object_put(valueJson);
1111
1112 return image;
1113}
1114
1115@end