Skip to content

Commit 66d8049

Browse files
committed
Support CameraFeed format on macOS
1 parent ef34c3d commit 66d8049

File tree

1 file changed

+89
-2
lines changed

1 file changed

+89
-2
lines changed

modules/camera/camera_macos.mm

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
148148
// do Y
149149
size_t new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);
150150
size_t new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);
151+
size_t row_stride = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
151152

152153
if ((width[0] != new_width) || (height[0] != new_height)) {
153154
width[0] = new_width;
@@ -156,7 +157,15 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
156157
}
157158

158159
uint8_t *w = img_data[0].ptrw();
159-
memcpy(w, dataY, new_width * new_height);
160+
if (new_width == row_stride) {
161+
memcpy(w, dataY, new_width * new_height);
162+
} else {
163+
for (size_t i = 0; i < new_height; i++) {
164+
memcpy(w, dataY, new_width);
165+
w += new_width;
166+
dataY += row_stride;
167+
}
168+
}
160169

161170
img[0].instantiate();
162171
img[0]->set_data(new_width, new_height, 0, Image::FORMAT_R8, img_data[0]);
@@ -166,6 +175,7 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
166175
// do CbCr
167176
size_t new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1);
168177
size_t new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1);
178+
size_t row_stride = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1);
169179

170180
if ((width[1] != new_width) || (height[1] != new_height)) {
171181
width[1] = new_width;
@@ -174,7 +184,15 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
174184
}
175185

176186
uint8_t *w = img_data[1].ptrw();
177-
memcpy(w, dataCbCr, 2 * new_width * new_height);
187+
if (new_width * 2 == row_stride) {
188+
memcpy(w, dataCbCr, 2 * new_width * new_height);
189+
} else {
190+
for (size_t i = 0; i < new_height; i++) {
191+
memcpy(w, dataCbCr, new_width * 2);
192+
w += new_width * 2;
193+
dataCbCr += row_stride;
194+
}
195+
}
178196

179197
///TODO OpenGL doesn't support FORMAT_RG8, need to do some form of conversion
180198
img[1].instantiate();
@@ -200,6 +218,7 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
200218
private:
201219
AVCaptureDevice *device;
202220
MyCaptureSession *capture_session;
221+
bool device_locked;
203222

204223
public:
205224
AVCaptureDevice *get_device() const;
@@ -210,6 +229,9 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
210229

211230
bool activate_feed() override;
212231
void deactivate_feed() override;
232+
233+
bool set_format(int p_index, const Dictionary &p_parameters) override;
234+
Array get_formats() const override;
213235
};
214236

215237
AVCaptureDevice *CameraFeedMacOS::get_device() const {
@@ -219,6 +241,7 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
219241
CameraFeedMacOS::CameraFeedMacOS() {
220242
device = nullptr;
221243
capture_session = nullptr;
244+
device_locked = false;
222245
}
223246

224247
void CameraFeedMacOS::set_device(AVCaptureDevice *p_device) {
@@ -239,6 +262,15 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
239262
if (capture_session) {
240263
// Already recording!
241264
} else {
265+
// Configure device format if specified.
266+
if (selected_format != -1) {
267+
NSError *error;
268+
if (!device_locked) {
269+
device_locked = [device lockForConfiguration:&error];
270+
ERR_FAIL_COND_V_MSG(!device_locked, false, error.localizedFailureReason.UTF8String);
271+
}
272+
[device setActiveFormat:device.formats[selected_format]];
273+
}
242274
// Start camera capture, check permission.
243275
if (@available(macOS 10.14, *)) {
244276
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
@@ -267,6 +299,61 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
267299
[capture_session cleanup];
268300
capture_session = nullptr;
269301
};
302+
if (device_locked) {
303+
[device unlockForConfiguration];
304+
device_locked = false;
305+
}
306+
}
307+
308+
bool CameraFeedMacOS::set_format(int p_index, const Dictionary &p_parameters) {
309+
if (p_index == -1) {
310+
selected_format = p_index;
311+
if (is_active()) {
312+
[capture_session beginConfiguration];
313+
}
314+
if (device_locked) {
315+
[device unlockForConfiguration];
316+
device_locked = false;
317+
}
318+
if (is_active()) {
319+
[capture_session commitConfiguration];
320+
}
321+
return true;
322+
}
323+
ERR_FAIL_INDEX_V((unsigned int)p_index, device.formats.count, false);
324+
if (is_active()) {
325+
if (!device_locked) {
326+
NSError *error;
327+
device_locked = [device lockForConfiguration:&error];
328+
ERR_FAIL_COND_V_MSG(!device_locked, false, error.localizedFailureReason.UTF8String);
329+
}
330+
[capture_session beginConfiguration];
331+
[device setActiveFormat:device.formats[p_index]];
332+
}
333+
selected_format = p_index;
334+
if (is_active()) {
335+
[capture_session commitConfiguration];
336+
}
337+
return true;
338+
}
339+
340+
Array CameraFeedMacOS::get_formats() const {
341+
Array result;
342+
for (AVCaptureDeviceFormat *format in device.formats) {
343+
Dictionary dictionary;
344+
CMFormatDescriptionRef formatDescription = format.formatDescription;
345+
CMVideoDimensions dimension = CMVideoFormatDescriptionGetDimensions(formatDescription);
346+
dictionary["width"] = dimension.width;
347+
dictionary["height"] = dimension.height;
348+
FourCharCode fourcc = CMFormatDescriptionGetMediaSubType(formatDescription);
349+
dictionary["format"] =
350+
String::chr((char)(fourcc >> 24) & 0xFF) +
351+
String::chr((char)(fourcc >> 16) & 0xFF) +
352+
String::chr((char)(fourcc >> 8) & 0xFF) +
353+
String::chr((char)(fourcc >> 0) & 0xFF);
354+
result.push_back(dictionary);
355+
}
356+
return result;
270357
}
271358

272359
//////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)