-
Notifications
You must be signed in to change notification settings - Fork 49
/
main.m
225 lines (188 loc) · 7.25 KB
/
main.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#import <Foundation/Foundation.h>
#import "ImageSnap.h"
int processArguments(int argc, const char * argv[]);
void printUsage(int argc, const char * argv[]);
unsigned long listDevices(void);
NSString *generateFilename(void);
AVCaptureDevice *getDefaultDevice(void);
int main(int argc, const char * argv[]) {
NSApplicationLoad(); // May be necessary for 10.5 not to crash.
@autoreleasepool {
[NSApplication sharedApplication];
int result = processArguments(argc, argv);
return result;
}
}
/**
* Process command line arguments and execute program.
*/
int processArguments(int argc, const char * argv[]) {
NSString *filename;
AVCaptureDevice *device;
NSNumber *warmup = [NSNumber numberWithInt:DEFAULT_WARMUP];
NSNumber *timelapse;
NSNumber *limit;
for (int i = 1; i < argc; ++i) {
// Handle command line switches
if (argv[i][0] == '-') {
// Dash only? Means write image to stdout
// This is no longer supported.
if (argv[i][1] == 0) {
filename = @"-";
g_quiet = YES;
} else {
// Which switch was given
switch (argv[i][1]) {
// Help
case '?':
case 'h':
printUsage(argc, argv);
return 0;
break;
// Verbose
case 'v':
g_verbose = YES;
[ImageSnap setVerbose:g_verbose];
verbose("Verbose mode\n");
break;
case 'q':
g_quiet = YES;
[ImageSnap setQuiet:g_quiet];
break;
// List devices
case 'l':
listDevices();
return 0;
break;
// Specify device
case 'd':
if (i+1 < argc) {
device = [ImageSnap deviceNamed:@(argv[i+1])];
if (device == nil) {
error("Device \"%s\" not found.\n", argv[i+1]);
return 11;
}
++i; // Account for "follow on" argument
} else {
error("Not enough arguments given with 'd' flag.\n");
return (int)'d';
}
break;
// Specify a warmup period before picture snaps
case 'w':
if (i+1 < argc) {
warmup = @(@(argv[i+1]).floatValue);
++i; // Account for "follow on" argument
} else {
error("Not enough arguments given with 'w' flag.\n");
return (int)'w';
}
break;
// Timelapse
case 't':
if (i+1 < argc) {
timelapse = @(@(argv[i+1]).doubleValue);
++i; // Account for "follow on" argument
} else {
error("Not enough arguments given with 't' flag.\n");
return (int)'t';
}
break;
// Timestamp image limit
case 'n':
if (i+1 < argc) {
limit = @(@(argv[i+1]).doubleValue);
++i; // Account for "follow on" argument
} else {
error("Not enough arguments given with 'n' flag.\n");
return (int)'n';
}
break;
}
}
} else {
// assume it's a filename
filename = @(argv[i]);
}
}
// Make sure we have a filename
if (filename == nil) {
if( timelapse == nil ){
filename = generateFilename();
verbose("No filename specified. Using %s\n", [filename UTF8String]);
} else {
// If doing timelapse and no directory is specified, use current directory
filename = @"./";
}
}
if (filename == nil) {
error("No suitable filename could be determined.\n");
return 1;
}
if (limit != nil && timelapse == nil) {
error("Cannot use -n without -t\n");
return 3;
}
// Make sure we have a device
if (device == nil) {
device = getDefaultDevice();
verbose("No device specified. Using %s\n", [device.localizedName UTF8String]);
}
if (device == nil) {
error("No video devices found.\n");
return 2;
} else {
console("Capturing image from device \"%s\"...", [device.localizedName UTF8String]);
}
// Image capture
ImageSnap *imageSnap = [ImageSnap new];
[imageSnap setUpSessionWithDevice:device];
[imageSnap saveSingleSnapshotFrom:device
toFile:filename
withWarmup:warmup
withTimelapse:timelapse
withLimit:limit];
return 0;
}
void printUsage(int argc, const char * argv[]) {
printf("USAGE: %s [options] [filename-or-dir]\n", argv[0]);
printf("Version: %s\n", VERSION.UTF8String);
printf("Captures an image from a video device and saves it in a file.\n");
printf("If no device is specified, the system default will be used.\n");
printf("If no filename is specfied, snapshot.jpg will be used.\n");
printf("If timelapse is used, the filename argument can be a directory where files will be saved.\n");
printf("JPEG is the only supported output type.\n");
printf(" -h This help message\n");
printf(" -v Verbose mode\n");
printf(" -l List available video devices\n");
printf(" -t x.xx Take a picture every x.xx seconds\n");
printf(" -n num Limit to <num> snapshots in -t timelapse mode\n");
printf(" -q Quiet mode. Do not output any text\n");
printf(" -w x.xx Warmup. Delay snapshot x.xx seconds after turning on camera (default 3sec)\n");
printf(" -d device Use named video device\n");
}
/**
* Prints a list of video capture devices to standard out.
*/
unsigned long listDevices() {
NSArray *devices = [ImageSnap videoDevices];
printf(devices.count > 0 ? "Video Devices:\n" : "No video devices found.\n");
for (AVCaptureDevice *device in devices) {
printf("=> %s\n", device.localizedName.UTF8String);
}
return devices.count;
}
/**
* Generates a filename for saving the image, presumably
* because the user didn't specify a filename.
*/
NSString *generateFilename() {
return @"snapshot.jpg";
}
/**
* Gets a default video device, or nil if none is found.
* For now, simply queries ImageSnap.
*/
AVCaptureDevice *getDefaultDevice() {
return [ImageSnap defaultVideoDevice];
}