OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "media/video/capture/mac/video_capture_device_qtkit_mac.h" | 5 #import "media/video/capture/mac/video_capture_device_qtkit_mac.h" |
6 | 6 |
7 #import <QTKit/QTKit.h> | 7 #import <QTKit/QTKit.h> |
8 | 8 |
9 #include "base/debug/crash_logging.h" | 9 #include "base/debug/crash_logging.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
71 } | 71 } |
72 | 72 |
73 - (BOOL)setCaptureDevice:(NSString*)deviceId { | 73 - (BOOL)setCaptureDevice:(NSString*)deviceId { |
74 if (deviceId) { | 74 if (deviceId) { |
75 // Set the capture device. | 75 // Set the capture device. |
76 if (captureDeviceInput_) { | 76 if (captureDeviceInput_) { |
77 DLOG(ERROR) << "Video capture device already set."; | 77 DLOG(ERROR) << "Video capture device already set."; |
78 return NO; | 78 return NO; |
79 } | 79 } |
80 | 80 |
81 // TODO(mcasas): Consider using [QTCaptureDevice deviceWithUniqueID] instead | |
82 // of explicitly forcing reenumeration of devices. | |
81 NSArray *captureDevices = | 83 NSArray *captureDevices = |
82 [QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo]; | 84 [QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo]; |
83 NSArray *captureDevicesNames = | 85 NSArray *captureDevicesNames = |
84 [captureDevices valueForKey:@"uniqueID"]; | 86 [captureDevices valueForKey:@"uniqueID"]; |
85 NSUInteger index = [captureDevicesNames indexOfObject:deviceId]; | 87 NSUInteger index = [captureDevicesNames indexOfObject:deviceId]; |
86 if (index == NSNotFound) { | 88 if (index == NSNotFound) { |
87 DLOG(ERROR) << "Video capture device not found."; | 89 [self sendErrorString:[NSString |
90 stringWithUTF8String:"Video capture device not found."]]; | |
88 return NO; | 91 return NO; |
89 } | 92 } |
90 QTCaptureDevice *device = [captureDevices objectAtIndex:index]; | 93 QTCaptureDevice *device = [captureDevices objectAtIndex:index]; |
91 if ([[device attributeForKey:QTCaptureDeviceSuspendedAttribute] | 94 if ([[device attributeForKey:QTCaptureDeviceSuspendedAttribute] |
92 boolValue]) { | 95 boolValue]) { |
93 DLOG(ERROR) << "Cannot open suspended video capture device."; | 96 [self sendErrorString:[NSString |
97 stringWithUTF8String:"Cannot open suspended video capture device."]]; | |
94 return NO; | 98 return NO; |
95 } | 99 } |
96 NSError *error; | 100 NSError *error; |
97 if (![device open:&error]) { | 101 if (![device open:&error]) { |
98 DLOG(ERROR) << "Could not open video capture device." | 102 [self sendErrorString:[NSString |
99 << [[error localizedDescription] UTF8String]; | 103 stringWithFormat:@"Could not open video capture device: %@ %@", |
Henrik Grunell
2014/05/30 11:48:32
Clarify by for example "...: %@, reason: %@". Here
mcasas
2014/05/30 12:15:27
Used the original "Big error (%@): %@", this shoul
Henrik Grunell
2014/05/30 12:30:48
SGTM
| |
104 [error localizedDescription], | |
105 [error localizedFailureReason]]]; | |
100 return NO; | 106 return NO; |
101 } | 107 } |
102 captureDeviceInput_ = [[QTCaptureDeviceInput alloc] initWithDevice:device]; | 108 captureDeviceInput_ = [[QTCaptureDeviceInput alloc] initWithDevice:device]; |
103 captureSession_ = [[QTCaptureSession alloc] init]; | 109 captureSession_ = [[QTCaptureSession alloc] init]; |
104 | 110 |
105 QTCaptureDecompressedVideoOutput *captureDecompressedOutput = | 111 QTCaptureDecompressedVideoOutput *captureDecompressedOutput = |
106 [[[QTCaptureDecompressedVideoOutput alloc] init] autorelease]; | 112 [[[QTCaptureDecompressedVideoOutput alloc] init] autorelease]; |
107 [captureDecompressedOutput setDelegate:self]; | 113 [captureDecompressedOutput setDelegate:self]; |
108 if (![captureSession_ addOutput:captureDecompressedOutput error:&error]) { | 114 if (![captureSession_ addOutput:captureDecompressedOutput error:&error]) { |
109 DLOG(ERROR) << "Could not connect video capture output." | 115 [self sendErrorString:[NSString |
110 << [[error localizedDescription] UTF8String]; | 116 stringWithFormat:@"Could not connect video capture output: %@ %@", |
117 [error localizedDescription], | |
118 [error localizedFailureReason]]]; | |
111 return NO; | 119 return NO; |
112 } | 120 } |
113 | 121 |
114 // This key can be used to check if video capture code was related to a | 122 // This key can be used to check if video capture code was related to a |
115 // particular crash. | 123 // particular crash. |
116 base::debug::SetCrashKeyValue("VideoCaptureDeviceQTKit", "OpenedDevice"); | 124 base::debug::SetCrashKeyValue("VideoCaptureDeviceQTKit", "OpenedDevice"); |
117 | 125 |
118 // Set the video pixel format to 2VUY (a.k.a UYVY, packed 4:2:2). | 126 // Set the video pixel format to 2VUY (a.k.a UYVY, packed 4:2:2). |
119 NSDictionary *captureDictionary = [NSDictionary | 127 NSDictionary *captureDictionary = [NSDictionary |
120 dictionaryWithObject: | 128 dictionaryWithObject: |
121 [NSNumber numberWithUnsignedInt:kCVPixelFormatType_422YpCbCr8] | 129 [NSNumber numberWithUnsignedInt:kCVPixelFormatType_422YpCbCr8] |
122 forKey:(id)kCVPixelBufferPixelFormatTypeKey]; | 130 forKey:(id)kCVPixelBufferPixelFormatTypeKey]; |
123 [captureDecompressedOutput setPixelBufferAttributes:captureDictionary]; | 131 [captureDecompressedOutput setPixelBufferAttributes:captureDictionary]; |
124 | 132 |
125 return YES; | 133 return YES; |
126 } else { | 134 } else { |
127 // Remove the previously set capture device. | 135 // Remove the previously set capture device. |
128 if (!captureDeviceInput_) { | 136 if (!captureDeviceInput_) { |
129 DLOG(ERROR) << "No video capture device set."; | 137 [self sendErrorString:[NSString |
138 stringWithUTF8String:"No video capture device set, on removal."]]; | |
130 return YES; | 139 return YES; |
131 } | 140 } |
132 if ([[captureSession_ inputs] count] > 0) { | 141 if ([[captureSession_ inputs] count] > 0) { |
133 // The device is still running. | 142 // The device is still running. |
134 [self stopCapture]; | 143 [self stopCapture]; |
135 } | 144 } |
136 if ([[captureSession_ outputs] count] > 0) { | 145 if ([[captureSession_ outputs] count] > 0) { |
137 // Only one output is set for |captureSession_|. | 146 // Only one output is set for |captureSession_|. |
138 DCHECK_EQ([[captureSession_ outputs] count], 1u); | 147 DCHECK_EQ([[captureSession_ outputs] count], 1u); |
139 id output = [[captureSession_ outputs] objectAtIndex:0]; | 148 id output = [[captureSession_ outputs] objectAtIndex:0]; |
140 [output setDelegate:nil]; | 149 [output setDelegate:nil]; |
141 | 150 |
142 // TODO(shess): QTKit achieves thread safety by posting messages | 151 // TODO(shess): QTKit achieves thread safety by posting messages to the |
143 // to the main thread. As part of -addOutput:, it posts a | 152 // main thread. As part of -addOutput:, it posts a message to the main |
144 // message to the main thread which in turn posts a notification | 153 // thread which in turn posts a notification which will run in a future |
145 // which will run in a future spin after the original method | 154 // spin after the original method returns. -removeOutput: can post a |
146 // returns. -removeOutput: can post a main-thread message in | 155 // main-thread message in between while holding a lock which the |
147 // between while holding a lock which the notification handler | 156 // notification handler will need. Posting either -addOutput: or |
148 // will need. Posting either -addOutput: or -removeOutput: to | 157 // -removeOutput: to the main thread should fix it, remove is likely |
149 // the main thread should fix it, remove is likely safer. | 158 // safer. http://crbug.com/152757 |
150 // http://crbug.com/152757 | |
151 [captureSession_ performSelectorOnMainThread:@selector(removeOutput:) | 159 [captureSession_ performSelectorOnMainThread:@selector(removeOutput:) |
152 withObject:output | 160 withObject:output |
153 waitUntilDone:YES]; | 161 waitUntilDone:YES]; |
154 } | 162 } |
155 [captureSession_ release]; | 163 [captureSession_ release]; |
156 captureSession_ = nil; | 164 captureSession_ = nil; |
157 [captureDeviceInput_ release]; | 165 [captureDeviceInput_ release]; |
158 captureDeviceInput_ = nil; | 166 captureDeviceInput_ = nil; |
159 return YES; | 167 return YES; |
160 } | 168 } |
161 } | 169 } |
162 | 170 |
163 - (BOOL)setCaptureHeight:(int)height width:(int)width frameRate:(int)frameRate { | 171 - (BOOL)setCaptureHeight:(int)height width:(int)width frameRate:(int)frameRate { |
164 if (!captureDeviceInput_) { | 172 if (!captureDeviceInput_) { |
165 DLOG(ERROR) << "No video capture device set."; | 173 [self sendErrorString:[NSString |
174 stringWithUTF8String:"No video capture device set."]]; | |
166 return NO; | 175 return NO; |
167 } | 176 } |
168 if ([[captureSession_ outputs] count] != 1) { | 177 if ([[captureSession_ outputs] count] != 1) { |
169 DLOG(ERROR) << "Video capture capabilities already set."; | 178 [self sendErrorString:[NSString |
179 stringWithUTF8String:"Video capture capabilities already set."]]; | |
170 return NO; | 180 return NO; |
171 } | 181 } |
172 if (frameRate <= 0) { | 182 if (frameRate <= 0) { |
173 DLOG(ERROR) << "Wrong frame rate."; | 183 [self sendErrorString:[NSString stringWithUTF8String: "Wrong frame rate."]]; |
174 return NO; | 184 return NO; |
175 } | 185 } |
176 | 186 |
177 frameRate_ = frameRate; | 187 frameRate_ = frameRate; |
178 | 188 |
179 QTCaptureDecompressedVideoOutput *output = | 189 QTCaptureDecompressedVideoOutput *output = |
180 [[captureSession_ outputs] objectAtIndex:0]; | 190 [[captureSession_ outputs] objectAtIndex:0]; |
181 | 191 |
182 // Set up desired output properties. The old capture dictionary is used to | 192 // Set up desired output properties. The old capture dictionary is used to |
183 // retrieve the initial pixel format, which must be maintained. | 193 // retrieve the initial pixel format, which must be maintained. |
184 NSDictionary* videoSettingsDictionary = @{ | 194 NSDictionary* videoSettingsDictionary = @{ |
185 (id)kCVPixelBufferWidthKey : @(width), | 195 (id)kCVPixelBufferWidthKey : @(width), |
186 (id)kCVPixelBufferHeightKey : @(height), | 196 (id)kCVPixelBufferHeightKey : @(height), |
187 (id)kCVPixelBufferPixelFormatTypeKey : [[output pixelBufferAttributes] | 197 (id)kCVPixelBufferPixelFormatTypeKey : [[output pixelBufferAttributes] |
188 valueForKey:(id)kCVPixelBufferPixelFormatTypeKey] | 198 valueForKey:(id)kCVPixelBufferPixelFormatTypeKey] |
189 }; | 199 }; |
190 [output setPixelBufferAttributes:videoSettingsDictionary]; | 200 [output setPixelBufferAttributes:videoSettingsDictionary]; |
191 | 201 |
192 [output setMinimumVideoFrameInterval:(NSTimeInterval)1/(float)frameRate]; | 202 [output setMinimumVideoFrameInterval:(NSTimeInterval)1/(float)frameRate]; |
193 return YES; | 203 return YES; |
194 } | 204 } |
195 | 205 |
196 - (BOOL)startCapture { | 206 - (BOOL)startCapture { |
197 if ([[captureSession_ outputs] count] == 0) { | 207 if ([[captureSession_ outputs] count] == 0) { |
198 // Capture properties not set. | 208 // Capture properties not set. |
199 DLOG(ERROR) << "Video capture device not initialized."; | 209 [self sendErrorString:[NSString |
210 stringWithUTF8String:"Video capture device not initialized."]]; | |
200 return NO; | 211 return NO; |
201 } | 212 } |
202 if ([[captureSession_ inputs] count] == 0) { | 213 if ([[captureSession_ inputs] count] == 0) { |
203 NSError *error; | 214 NSError *error; |
204 if (![captureSession_ addInput:captureDeviceInput_ error:&error]) { | 215 if (![captureSession_ addInput:captureDeviceInput_ error:&error]) { |
205 DLOG(ERROR) << "Could not connect video capture device." | 216 [self sendErrorString:[NSString |
206 << [[error localizedDescription] UTF8String]; | 217 stringWithFormat:@"Could not connect video capture device: %@ %@", |
218 [error localizedDescription], | |
219 [error localizedFailureReason]]]; | |
220 | |
207 return NO; | 221 return NO; |
208 } | 222 } |
209 NSNotificationCenter * notificationCenter = | 223 NSNotificationCenter * notificationCenter = |
210 [NSNotificationCenter defaultCenter]; | 224 [NSNotificationCenter defaultCenter]; |
211 [notificationCenter addObserver:self | 225 [notificationCenter addObserver:self |
212 selector:@selector(handleNotification:) | 226 selector:@selector(handleNotification:) |
213 name:QTCaptureSessionRuntimeErrorNotification | 227 name:QTCaptureSessionRuntimeErrorNotification |
214 object:captureSession_]; | 228 object:captureSession_]; |
215 [captureSession_ startRunning]; | 229 [captureSession_ startRunning]; |
216 } | 230 } |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
302 aspectNumerator, aspectDenominator); | 316 aspectNumerator, aspectDenominator); |
303 | 317 |
304 CVPixelBufferUnlockBaseAddress(videoFrame, kLockFlags); | 318 CVPixelBufferUnlockBaseAddress(videoFrame, kLockFlags); |
305 } | 319 } |
306 [lock_ unlock]; | 320 [lock_ unlock]; |
307 } | 321 } |
308 | 322 |
309 - (void)handleNotification:(NSNotification*)errorNotification { | 323 - (void)handleNotification:(NSNotification*)errorNotification { |
310 NSError * error = (NSError*)[[errorNotification userInfo] | 324 NSError * error = (NSError*)[[errorNotification userInfo] |
311 objectForKey:QTCaptureSessionErrorKey]; | 325 objectForKey:QTCaptureSessionErrorKey]; |
312 NSString* str_error = | 326 [self sendErrorString:[NSString stringWithFormat:@"%@: %@", |
313 [NSString stringWithFormat:@"%@: %@", | 327 [error localizedDescription], |
Henrik Grunell
2014/05/30 11:48:32
Fix indentation.
mcasas
2014/05/30 12:15:27
Done.
Henrik Grunell
2014/05/30 12:30:48
Nit: Same here.
| |
314 [error localizedDescription], | 328 [error localizedFailureReason]]]; |
315 [error localizedFailureReason]]; | 329 } |
316 | 330 |
317 frameReceiver_->ReceiveError([str_error UTF8String]); | 331 - (void)sendErrorString:(NSString*)error { |
332 [lock_ lock]; | |
333 if (frameReceiver_) | |
334 frameReceiver_->ReceiveError([error UTF8String]); | |
335 [lock_ unlock]; | |
318 } | 336 } |
319 | 337 |
320 @end | 338 @end |
OLD | NEW |