1 /*
2 * QTKit input device
3 * Copyright (c) 2013 Vadim Kalinsky <vadim@kalinsky.ru>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /**
23 * @file
24 * QTKit input device
25 * @author Vadim Kalinsky <vadim@kalinsky.ru>
26 */
27
28 #import <QTKit/QTKit.h>
29 #include <pthread.h>
30
37
38 #define QTKIT_TIMEBASE 100
39
43 };
44
46 {
48
55
58
63
65 {
67 }
68
70 {
72 }
73
74 /** FrameReciever class - delegate for QTCaptureSession
75 */
77 {
79 }
80
82
83 - (
void)captureOutput:(QTCaptureOutput *)captureOutput
84 didOutputVideoFrame:(CVImageBufferRef)videoFrame
85 withSampleBuffer:(QTSampleBuffer *)sampleBuffer
86 fromConnection:(QTCaptureConnection *)connection;
87
88 @end
89
91
93 {
94 if (
self = [super
init]) {
96 }
97 return self;
98 }
99
100 - (
void)captureOutput:(QTCaptureOutput *)captureOutput
101 didOutputVideoFrame:(CVImageBufferRef)videoFrame
102 withSampleBuffer:(QTSampleBuffer *)sampleBuffer
103 fromConnection:(QTCaptureConnection *)connection
104 {
108 }
109
111
113
115
117 }
118
119 @end
120
122 {
123 [ctx->capture_session stopRunning];
124
125 [ctx->capture_session release];
126 [ctx->video_output release];
127 [ctx->qt_delegate release];
128
132
135
138 }
139
141 {
142 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
143
145
147
150
151 // List devices if requested
154 NSArray *devices = [QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo];
155 for (QTCaptureDevice *device
in devices) {
156 const char *
name = [[device localizedDisplayName] UTF8String];
157 int index = [devices indexOfObject:device];
159 }
160 goto fail;
161 }
162
163 // Find capture device
164 QTCaptureDevice *video_device = nil;
165
166 // check for device index given in filename
169 }
170
172 NSArray *devices = [QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo];
173
176 goto fail;
177 }
178
179 video_device = [devices objectAtIndex:ctx->video_device_index];
180 }
else if (strncmp(s->
filename,
"", 1) &&
181 strncmp(s->
filename,
"default", 7)) {
182 NSArray *devices = [QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo];
183
184 for (QTCaptureDevice *device
in devices) {
185 if (!strncmp(s->
filename, [[device localizedDisplayName] UTF8String], strlen(s->
filename))) {
186 video_device = device;
187 break;
188 }
189 }
190 if (!video_device) {
192 goto fail;
193 }
194 } else {
195 video_device = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeMuxed];
196 }
197
198 BOOL success = [video_device open:nil];
199
200 // Video capture device not found, looking for QTMediaTypeVideo
201 if (!success) {
202 video_device = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];
203 success = [video_device open:nil];
204
205 if (!success) {
207 goto fail;
208 }
209 }
210
211 NSString* dev_display_name = [video_device localizedDisplayName];
213
214 // Initialize capture session
216
217 QTCaptureDeviceInput* capture_dev_input = [[[QTCaptureDeviceInput alloc] initWithDevice:video_device] autorelease];
218 success = [ctx->capture_session addInput:capture_dev_input error:nil];
219
220 if (!success) {
222 goto fail;
223 }
224
225 // Attaching output
226 // FIXME: Allow for a user defined pixel format
227 ctx->
video_output = [[QTCaptureDecompressedVideoOutput alloc] init];
228
229 NSDictionary *captureDictionary = [NSDictionary dictionaryWithObject:
230 [NSNumber numberWithUnsignedInt:kCVPixelFormatType_24RGB]
231 forKey:(id)kCVPixelBufferPixelFormatTypeKey];
232
233 [ctx->video_output setPixelBufferAttributes:captureDictionary];
234
236
237 [ctx->video_output setDelegate:ctx->qt_delegate];
238 [ctx->video_output setAutomaticallyDropsLateVideoFrames:YES];
239 [ctx->video_output setMinimumVideoFrameInterval:1.0/ctx->frame_rate];
240
241 success = [ctx->capture_session addOutput:ctx->video_output error:nil];
242
243 if (!success) {
245 goto fail;
246 }
247
248 [ctx->capture_session startRunning];
249
250 // Take stream info from the first frame.
252 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
253 }
254
256
258
259 if (!stream) {
260 goto fail;
261 }
262
264
270
273
275
276 [pool release];
277
278 return 0;
279
280 fail:
281 [pool release];
282
284
286 }
287
289 {
291
292 do {
294
298 }
299
303
305
308
312 } else {
315 }
316
319
320 return 0;
321 }
322
324 {
326
328
329 return 0;
330 }
331
333 {
"frame_rate",
"set frame rate", offsetof(
CaptureContext, frame_rate),
AV_OPT_TYPE_FLOAT, { .dbl = 30.0 }, 0.1, 30.0,
AV_OPT_TYPE_VIDEO_RATE,
NULL },
334 {
"list_devices",
"list available devices", offsetof(
CaptureContext, list_devices),
AV_OPT_TYPE_INT, {.i64=0}, 0, 1,
AV_OPT_FLAG_DECODING_PARAM,
"list_devices" },
339 };
340
347 };
348
357 .priv_class = &qtkit_class,
358 };