30 #import <AVFoundation/AVFoundation.h>
32 # import <IOKit/IOKitLib.h>
34 # if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 120000
35 # define AVF_IO_MAIN_PORT_DEFAULT kIOMainPortDefault
37 # define AVF_IO_MAIN_PORT_DEFAULT kIOMasterPortDefault
91 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
153 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
154 AVCaptureDeviceTransportControlsPlaybackMode observed_mode;
179 - (void) captureOutput:(AVCaptureOutput *)captureOutput
180 didOutputSampleBuffer:(CMSampleBufferRef)videoFrame
181 fromConnection:(AVCaptureConnection *)connection;
189 if (
self = [super
init]) {
193 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
195 NSString *keyPath = NSStringFromSelector(
@selector(transportControlsPlaybackMode));
196 NSKeyValueObservingOptions
options = NSKeyValueObservingOptionNew;
198 [
_context->observed_device addObserver: self
210 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
212 NSString *keyPath = NSStringFromSelector(
@selector(transportControlsPlaybackMode));
213 [_context->observed_device removeObserver: self forKeyPath: keyPath];
219 - (void)observeValueForKeyPath:(NSString *)keyPath
221 change:(NSDictionary *)change
222 context:(
void *)context {
224 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
225 AVCaptureDeviceTransportControlsPlaybackMode
mode =
226 [change[NSKeyValueChangeNewKey] integerValue];
229 if (
mode == AVCaptureDeviceTransportControlsNotPlayingMode) {
241 [
super observeValueForKeyPath: keyPath
248 - (void) captureOutput:(AVCaptureOutput *)captureOutput
249 didOutputSampleBuffer:(CMSampleBufferRef)videoFrame
250 fromConnection:(AVCaptureConnection *)connection
281 - (void) captureOutput:(AVCaptureOutput *)captureOutput
282 didOutputSampleBuffer:(CMSampleBufferRef)audioFrame
283 fromConnection:(AVCaptureConnection *)connection;
291 if (
self = [super
init]) {
297 - (void) captureOutput:(AVCaptureOutput *)captureOutput
298 didOutputSampleBuffer:(CMSampleBufferRef)audioFrame
299 fromConnection:(AVCaptureConnection *)connection
326 ctx->is_stopping = 1;
329 [ctx->capture_session stopRunning];
331 [ctx->capture_session release];
332 [ctx->video_output release];
333 [ctx->audio_output release];
334 [ctx->avf_delegate release];
335 [ctx->avf_audio_delegate release];
341 ctx->avf_audio_delegate =
NULL;
349 if (
ctx->current_frame) {
350 CFRelease(
ctx->current_frame);
351 ctx->current_frame = nil;
354 if (
ctx->current_audio_frame) {
355 CFRelease(
ctx->current_audio_frame);
356 ctx->current_audio_frame = nil;
393 NSObject *
range = nil;
395 NSObject *selected_range = nil;
396 NSObject *selected_format = nil;
402 for (
format in [video_device valueForKey:
@"formats"]) {
403 CMFormatDescriptionRef formatDescription;
404 CMVideoDimensions dimensions;
406 formatDescription = (CMFormatDescriptionRef) [
format performSelector:
@selector(formatDescription)];
407 dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
409 if ((
ctx->width == 0 &&
ctx->height == 0) ||
410 (dimensions.width ==
ctx->width && dimensions.height ==
ctx->height)) {
414 for (
range in [
format valueForKey:
@"videoSupportedFrameRateRanges"]) {
415 double max_framerate;
417 [[range valueForKey:@"maxFrameRate"] getValue:&max_framerate];
419 selected_range =
range;
426 if (!selected_format) {
429 goto unsupported_format;
432 if (!selected_range) {
435 if (
ctx->video_is_muxed) {
438 goto unsupported_format;
442 if ([video_device lockForConfiguration:
NULL] == YES) {
443 if (selected_format) {
444 [video_device setValue:selected_format forKey:@"activeFormat"];
446 if (selected_range) {
447 NSValue *min_frame_duration = [selected_range valueForKey:@"minFrameDuration"];
448 [video_device setValue:min_frame_duration forKey:@"activeVideoMinFrameDuration"];
449 [video_device setValue:min_frame_duration forKey:@"activeVideoMaxFrameDuration"];
455 }
@catch(NSException *e) {
464 for (
format in [video_device valueForKey:
@"formats"]) {
465 CMFormatDescriptionRef formatDescription;
466 CMVideoDimensions dimensions;
468 formatDescription = (CMFormatDescriptionRef) [
format performSelector:
@selector(formatDescription)];
469 dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
471 for (
range in [
format valueForKey:
@"videoSupportedFrameRateRanges"]) {
472 double min_framerate;
473 double max_framerate;
475 [[range valueForKey:@"minFrameRate"] getValue:&min_framerate];
476 [[range valueForKey:@"maxFrameRate"] getValue:&max_framerate];
478 dimensions.width, dimensions.height,
479 min_framerate, max_framerate);
489 NSError *
error = nil;
490 AVCaptureInput* capture_input = nil;
492 NSNumber *pixel_format;
493 NSDictionary *capture_dict;
494 dispatch_queue_t queue;
496 if (!
ctx->video_is_screen) {
497 capture_input = (AVCaptureInput*) [[[AVCaptureDeviceInput alloc] initWithDevice:video_device
error:&
error] autorelease];
499 capture_input = (AVCaptureInput*) video_device;
502 if (!capture_input) {
504 [[
error localizedDescription] UTF8String]);
508 if ([
ctx->capture_session canAddInput:capture_input]) {
509 [ctx->capture_session addInput:capture_input];
516 ctx->video_output = [[AVCaptureVideoDataOutput alloc] init];
518 if (!
ctx->video_output) {
528 }
@catch (NSException *exception) {
529 if (![[exception
name] isEqualToString:NSUndefinedKeyException]) {
553 if ([[
ctx->video_output availableVideoCVPixelFormatTypes] indexOfObject:[NSNumber numberWithInt:pxl_fmt_spec.avf_id]] == NSNotFound) {
554 av_log(
s,
AV_LOG_ERROR,
"Selected pixel format (%s) is not supported by the input device.\n",
560 for (NSNumber *pxl_fmt in [
ctx->video_output availableVideoCVPixelFormatTypes]) {
575 pxl_fmt_spec = pxl_fmt_dummy;
590 if (
ctx->capture_raw_data) {
591 ctx->pixel_format = pxl_fmt_spec.ff_id;
592 ctx->video_output.videoSettings = @{ };
594 ctx->pixel_format = pxl_fmt_spec.ff_id;
595 pixel_format = [NSNumber numberWithUnsignedInt:pxl_fmt_spec.avf_id];
596 capture_dict = [NSDictionary dictionaryWithObject:pixel_format
597 forKey:(id)kCVPixelBufferPixelFormatTypeKey];
599 [ctx->video_output setVideoSettings:capture_dict];
601 [ctx->video_output setAlwaysDiscardsLateVideoFrames:ctx->drop_late_frames];
603 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
605 if (!
ctx->video_is_screen) {
606 int trans_ctrl = [video_device transportControlsSupported];
607 AVCaptureDeviceTransportControlsPlaybackMode trans_mode = [video_device transportControlsPlaybackMode];
610 ctx->observed_mode = trans_mode;
611 ctx->observed_device = video_device;
618 queue = dispatch_queue_create(
"avf_queue",
NULL);
619 [ctx->video_output setSampleBufferDelegate:ctx->avf_delegate queue:queue];
620 dispatch_release(queue);
622 if ([
ctx->capture_session canAddOutput:
ctx->video_output]) {
623 [ctx->capture_session addOutput:ctx->video_output];
635 NSError *
error = nil;
636 AVCaptureDeviceInput* audio_dev_input = [[[AVCaptureDeviceInput alloc] initWithDevice:audio_device
error:&
error] autorelease];
637 dispatch_queue_t queue;
639 if (!audio_dev_input) {
641 [[
error localizedDescription] UTF8String]);
645 if ([
ctx->capture_session canAddInput:audio_dev_input]) {
646 [ctx->capture_session addInput:audio_dev_input];
653 ctx->audio_output = [[AVCaptureAudioDataOutput alloc] init];
655 if (!
ctx->audio_output) {
662 queue = dispatch_queue_create(
"avf_audio_queue",
NULL);
663 [ctx->audio_output setSampleBufferDelegate:ctx->avf_audio_delegate queue:queue];
664 dispatch_release(queue);
666 if ([
ctx->capture_session canAddOutput:
ctx->audio_output]) {
667 [ctx->capture_session addOutput:ctx->audio_output];
679 CVImageBufferRef image_buffer;
680 CGSize image_buffer_size;
688 while (
ctx->frames_captured < 1) {
689 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
694 ctx->video_stream_index = stream->index;
698 image_buffer = CMSampleBufferGetImageBuffer(
ctx->current_frame);
701 image_buffer_size = CVImageBufferGetEncodedSize(image_buffer);
705 stream->codecpar->width = (int)image_buffer_size.width;
706 stream->codecpar->height = (
int)image_buffer_size.height;
707 stream->codecpar->format =
ctx->pixel_format;
711 stream->codecpar->format =
ctx->pixel_format;
714 CFRelease(
ctx->current_frame);
715 ctx->current_frame = nil;
725 CMFormatDescriptionRef format_desc;
733 while (
ctx->audio_frames_captured < 1) {
734 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
739 ctx->audio_stream_index = stream->index;
743 format_desc = CMSampleBufferGetFormatDescription(
ctx->current_audio_frame);
744 const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc);
753 stream->codecpar->sample_rate = basic_desc->mSampleRate;
756 ctx->audio_channels = basic_desc->mChannelsPerFrame;
757 ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel;
758 ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat;
759 ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian;
760 ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger;
761 ctx->audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacked;
762 ctx->audio_non_interleaved = basic_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved;
764 if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
766 ctx->audio_bits_per_sample == 32 &&
769 }
else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
770 ctx->audio_signed_integer &&
771 ctx->audio_bits_per_sample == 16 &&
774 }
else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
775 ctx->audio_signed_integer &&
776 ctx->audio_bits_per_sample == 24 &&
779 }
else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
780 ctx->audio_signed_integer &&
781 ctx->audio_bits_per_sample == 32 &&
790 if (
ctx->audio_non_interleaved) {
791 CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(
ctx->current_audio_frame);
792 ctx->audio_buffer_size = CMBlockBufferGetDataLength(block_buffer);
794 if (!
ctx->audio_buffer) {
801 CFRelease(
ctx->current_audio_frame);
802 ctx->current_audio_frame = nil;
810 #if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500))
811 NSMutableArray *deviceTypes = nil;
812 if (mediaType == AVMediaTypeVideo) {
813 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeBuiltInWideAngleCamera]];
814 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000)
815 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInDualCamera];
816 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInTelephotoCamera];
818 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110100)
819 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInTrueDepthCamera];
821 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 130000)
822 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInTripleCamera];
823 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInDualWideCamera];
824 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInUltraWideCamera];
826 #if (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 130000)
827 [deviceTypes addObject: AVCaptureDeviceTypeDeskViewCamera];
829 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 150400)
830 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInLiDARDepthCamera];
832 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000 || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 140000))
833 [deviceTypes addObject: AVCaptureDeviceTypeContinuityCamera];
834 [deviceTypes addObject: AVCaptureDeviceTypeExternal];
835 #elif (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000)
836 [deviceTypes addObject: AVCaptureDeviceTypeExternalUnknown];
838 }
else if (mediaType == AVMediaTypeAudio) {
839 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000 || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 140000))
840 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeMicrophone]];
842 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeBuiltInMicrophone]];
844 }
else if (mediaType == AVMediaTypeMuxed) {
845 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000 || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 140000))
846 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeExternal]];
847 #elif (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000)
848 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeExternalUnknown]];
856 AVCaptureDeviceDiscoverySession *captureDeviceDiscoverySession =
857 [AVCaptureDeviceDiscoverySession
858 discoverySessionWithDeviceTypes:deviceTypes
860 position:AVCaptureDevicePositionUnspecified];
861 return [captureDeviceDiscoverySession devices];
863 return [AVCaptureDevice devicesWithMediaType:mediaType];
870 static int avf_io_get_string(io_service_t service, CFStringRef
key,
char *buf,
size_t size)
872 CFTypeRef
ref = IORegistryEntryCreateCFProperty(service,
key, kCFAllocatorDefault, 0);
873 int ok =
ref && CFGetTypeID(
ref) == CFStringGetTypeID() && CFStringGetCString(
ref, buf,
size, kCFStringEncodingUTF8);
879 static int avf_io_get_uint32(io_service_t service, CFStringRef
key, uint32_t *
out)
881 CFTypeRef
ref = IORegistryEntryCreateCFProperty(service,
key, kCFAllocatorDefault, 0);
882 int ok =
ref && CFGetTypeID(
ref) == CFNumberGetTypeID() && CFNumberGetValue(
ref, kCFNumberSInt32Type,
out);
893 io_iterator_t iterator = 0;
894 io_service_t service;
896 if (IOServiceGetMatchingServices(AVF_IO_MAIN_PORT_DEFAULT,
897 IOServiceMatching(
"IOUSBHostDevice"), &iterator) != KERN_SUCCESS)
900 while (location < 0 && (service = IOIteratorNext(iterator))) {
903 if (avf_io_get_string(service, CFSTR(
"USB Serial Number"), found,
sizeof(found)) &&
904 !strcmp(found, serial) &&
905 avf_io_get_uint32(service, CFSTR(
"locationID"), &loc))
907 IOObjectRelease(service);
909 IOObjectRelease(iterator);
923 NSString *serial = nil;
924 io_iterator_t iterator = 0;
925 io_service_t service;
927 if (IOServiceGetMatchingServices(AVF_IO_MAIN_PORT_DEFAULT,
928 IOServiceMatching(
"IOUSBHostDevice"), &iterator) != KERN_SUCCESS)
931 while (!serial && (service = IOIteratorNext(iterator))) {
934 if (avf_io_get_uint32(service, CFSTR(
"locationID"), &loc) && loc == location &&
935 avf_io_get_string(service, CFSTR(
"USB Serial Number"), found,
sizeof(found)))
936 serial = [NSString stringWithUTF8String:found];
937 IOObjectRelease(service);
939 IOObjectRelease(iterator);
952 NSArray *devices, NSArray *devices_muxed,
int *is_muxed)
955 NSArray *lists[2] = { devices, devices_muxed };
960 for (
int i = 0;
i < 2;
i++) {
961 for (AVCaptureDevice *device in lists[
i]) {
962 NSString *
uid = [device uniqueID];
963 if ([
uid hasPrefix:
@"0x"] &&
964 (uint32_t)(strtoull([
uid UTF8String],
NULL, 16) >> 32) == (uint32_t)location) {
965 *is_muxed = (
i == 1);
978 if (![
uid hasPrefix:
@"AppleUSBAudioEngine:"])
980 NSArray<NSString *> *
fields = [uid componentsSeparatedByString:@":"];
983 NSString *serial =
fields[fields.count - 2];
997 NSString *want = [NSString stringWithUTF8String:serial];
999 for (AVCaptureDevice *device in devices)
1007 NSArray *devices, NSArray *devices_muxed,
int *is_muxed)
1009 NSString *want = [NSString stringWithUTF8String:uid];
1010 NSArray *lists[2] = { devices, devices_muxed };
1012 for (
int i = 0;
i < 2;
i++) {
1013 for (AVCaptureDevice *device in lists[
i]) {
1014 if ([[device uniqueID] isEqualToString:want]) {
1016 *is_muxed = (
i == 1);
1028 NSString *
uid = [device uniqueID];
1030 if ([
uid hasPrefix:
@"0x"]) {
1031 unsigned long long value = strtoull([
uid UTF8String],
NULL, 16);
1033 return serial.length ? serial : nil;
1044 [[device localizedName] UTF8String], [[device uniqueID] UTF8String],
1045 [serial UTF8String]);
1048 [[device localizedName] UTF8String], [[device uniqueID] UTF8String]);
1053 NSArray *devices, NSArray *devices_muxed,
1054 const char *
id, AVCaptureDevice **device,
int *is_muxed)
1056 BOOL is_audio = [media_type isEqualToString:AVMediaTypeAudio];
1057 const char *kind = is_audio ?
"Audio" :
"Video";
1070 "%s capture device with serial number '%s' not found\n", kind,
value);
1075 "%s capture device with unique ID '%s' not found\n", kind,
value);
1078 "Invalid %s device id '%s': expected 'uid:<unique ID>' or 'serial:<serial number>'\n",
1079 is_audio ?
"audio" :
"video",
id);
1087 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1088 uint32_t num_screens = 0;
1090 AVCaptureDevice *video_device = nil;
1091 AVCaptureDevice *audio_device = nil;
1097 ctx->num_video_devices = [devices count] + [devices_muxed count];
1101 ctx->is_stopping = 0;
1103 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1104 CGGetActiveDisplayList(0,
NULL, &num_screens);
1108 if (
ctx->list_devices) {
1111 for (AVCaptureDevice *device in devices) {
1112 index = [devices indexOfObject:device];
1115 for (AVCaptureDevice *device in devices_muxed) {
1116 index = [devices count] + [devices_muxed indexOfObject:device];
1119 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1120 if (num_screens > 0) {
1121 CGDirectDisplayID screens[num_screens];
1122 CGGetActiveDisplayList(num_screens, screens, &num_screens);
1123 for (
int i = 0;
i < num_screens;
i++) {
1131 for (AVCaptureDevice *device in devices) {
1132 int index = [devices indexOfObject:device];
1144 if (
ctx->video_device_index == -1 &&
ctx->video_filename) {
1145 sscanf(
ctx->video_filename,
"%d", &
ctx->video_device_index);
1147 if (
ctx->audio_device_index == -1 &&
ctx->audio_filename) {
1148 sscanf(
ctx->audio_filename,
"%d", &
ctx->audio_device_index);
1152 ctx->video_device_id, &video_device, &
ctx->video_is_muxed)) {
1155 }
else if (
ctx->video_device_index >= 0) {
1156 if (
ctx->video_device_index <
ctx->num_video_devices) {
1157 if (
ctx->video_device_index < [devices count]) {
1158 video_device = [devices objectAtIndex:ctx->video_device_index];
1160 video_device = [devices_muxed objectAtIndex:(ctx->video_device_index - [devices count])];
1161 ctx->video_is_muxed = 1;
1163 }
else if (
ctx->video_device_index <
ctx->num_video_devices + num_screens) {
1164 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1165 CGDirectDisplayID screens[num_screens];
1166 CGGetActiveDisplayList(num_screens, screens, &num_screens);
1167 AVCaptureScreenInput* capture_screen_input = [[[AVCaptureScreenInput alloc] initWithDisplayID:screens[ctx->video_device_index - ctx->
num_video_devices]] autorelease];
1169 if (
ctx->framerate.num > 0) {
1170 capture_screen_input.minFrameDuration = CMTimeMake(
ctx->framerate.den,
ctx->framerate.num);
1173 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
1174 if (
ctx->capture_cursor) {
1175 capture_screen_input.capturesCursor = YES;
1177 capture_screen_input.capturesCursor = NO;
1181 if (
ctx->capture_mouse_clicks) {
1182 capture_screen_input.capturesMouseClicks = YES;
1184 capture_screen_input.capturesMouseClicks = NO;
1187 video_device = (AVCaptureDevice*) capture_screen_input;
1188 ctx->video_is_screen = 1;
1194 }
else if (
ctx->video_filename &&
1195 strncmp(
ctx->video_filename,
"none", 4)) {
1196 if (!strncmp(
ctx->video_filename,
"default", 7)) {
1197 video_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
1200 for (AVCaptureDevice *device in devices) {
1201 if (!strncmp(
ctx->video_filename, [[device localizedName] UTF8String], strlen(
ctx->video_filename))) {
1202 video_device = device;
1207 for (AVCaptureDevice *device in devices_muxed) {
1208 if (!strncmp(
ctx->video_filename, [[device localizedName] UTF8String], strlen(
ctx->video_filename))) {
1209 video_device = device;
1210 ctx->video_is_muxed = 1;
1215 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1217 if (!video_device) {
1219 if(sscanf(
ctx->video_filename,
"Capture screen %d", &idx) && idx < num_screens) {
1220 CGDirectDisplayID screens[num_screens];
1221 CGGetActiveDisplayList(num_screens, screens, &num_screens);
1222 AVCaptureScreenInput* capture_screen_input = [[[AVCaptureScreenInput alloc] initWithDisplayID:screens[idx]] autorelease];
1223 video_device = (AVCaptureDevice*) capture_screen_input;
1224 ctx->video_device_index =
ctx->num_video_devices + idx;
1225 ctx->video_is_screen = 1;
1227 if (
ctx->framerate.num > 0) {
1228 capture_screen_input.minFrameDuration = CMTimeMake(
ctx->framerate.den,
ctx->framerate.num);
1231 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
1232 if (
ctx->capture_cursor) {
1233 capture_screen_input.capturesCursor = YES;
1235 capture_screen_input.capturesCursor = NO;
1239 if (
ctx->capture_mouse_clicks) {
1240 capture_screen_input.capturesMouseClicks = YES;
1242 capture_screen_input.capturesMouseClicks = NO;
1249 if (!video_device) {
1257 ctx->audio_device_id, &audio_device,
NULL)) {
1260 }
else if (
ctx->audio_device_index >= 0) {
1261 if (
ctx->audio_device_index >= [audio_devices count]) {
1266 audio_device = [audio_devices objectAtIndex:ctx->audio_device_index];
1267 }
else if (
ctx->audio_filename &&
1268 strncmp(
ctx->audio_filename,
"none", 4)) {
1269 if (!strncmp(
ctx->audio_filename,
"default", 7)) {
1270 audio_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
1272 for (AVCaptureDevice *device in audio_devices) {
1273 if (!strncmp(
ctx->audio_filename, [[device localizedName] UTF8String], strlen(
ctx->audio_filename))) {
1274 audio_device = device;
1280 if (!audio_device) {
1287 if (!video_device && !audio_device) {
1293 if (!
ctx->video_is_screen) {
1300 av_log(
s,
AV_LOG_DEBUG,
"audio device '%s' opened\n", [[audio_device localizedName] UTF8String]);
1304 ctx->capture_session = [[AVCaptureSession alloc] init];
1312 [ctx->capture_session startRunning];
1316 if (!
ctx->video_is_screen) {
1317 [video_device unlockForConfiguration];
1341 CVPixelBufferRef image_buffer,
1345 int src_linesize[4];
1346 const uint8_t *src_data[4];
1347 int width = CVPixelBufferGetWidth(image_buffer);
1348 int height = CVPixelBufferGetHeight(image_buffer);
1351 memset(src_linesize, 0,
sizeof(src_linesize));
1352 memset(src_data, 0,
sizeof(src_data));
1354 status = CVPixelBufferLockBaseAddress(image_buffer, 0);
1355 if (
status != kCVReturnSuccess) {
1360 if (CVPixelBufferIsPlanar(image_buffer)) {
1361 size_t plane_count = CVPixelBufferGetPlaneCount(image_buffer);
1363 for(
i = 0;
i < plane_count;
i++){
1364 src_linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(image_buffer,
i);
1365 src_data[i] = CVPixelBufferGetBaseAddressOfPlane(image_buffer,
i);
1368 src_linesize[0] = CVPixelBufferGetBytesPerRow(image_buffer);
1369 src_data[0] = CVPixelBufferGetBaseAddress(image_buffer);
1373 src_data, src_linesize,
1378 CVPixelBufferUnlockBaseAddress(image_buffer, 0);
1389 CVImageBufferRef image_buffer;
1390 CMBlockBufferRef block_buffer;
1392 if (
ctx->current_frame != nil) {
1396 image_buffer = CMSampleBufferGetImageBuffer(
ctx->current_frame);
1397 block_buffer = CMSampleBufferGetDataBuffer(
ctx->current_frame);
1399 if (image_buffer != nil) {
1400 length = (int)CVPixelBufferGetDataSize(image_buffer);
1401 }
else if (block_buffer != nil) {
1402 length = (int)CMBlockBufferGetDataLength(block_buffer);
1416 if (CMSampleBufferGetOutputSampleTimingInfoArray(
ctx->current_frame, 1, &
timing_info, &count) == noErr) {
1428 OSStatus
ret = CMBlockBufferCopyDataBytes(block_buffer, 0,
pkt->
size,
pkt->
data);
1429 if (
ret != kCMBlockBufferNoErr) {
1433 CFRelease(
ctx->current_frame);
1434 ctx->current_frame = nil;
1440 }
else if (
ctx->current_audio_frame != nil) {
1441 CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(
ctx->current_audio_frame);
1442 int block_buffer_size = CMBlockBufferGetDataLength(block_buffer);
1444 if (!block_buffer || !block_buffer_size) {
1449 if (
ctx->audio_non_interleaved && block_buffer_size >
ctx->audio_buffer_size) {
1462 if (CMSampleBufferGetOutputSampleTimingInfoArray(
ctx->current_audio_frame, 1, &
timing_info, &count) == noErr) {
1470 if (
ctx->audio_non_interleaved) {
1473 OSStatus
ret = CMBlockBufferCopyDataBytes(block_buffer, 0,
pkt->
size,
ctx->audio_buffer);
1474 if (
ret != kCMBlockBufferNoErr) {
1479 num_samples =
pkt->
size / (
ctx->audio_channels * (
ctx->audio_bits_per_sample >> 3));
1482 #define INTERLEAVE_OUTPUT(bps) \
1484 int##bps##_t **src; \
1485 int##bps##_t *dest; \
1486 src = av_malloc(ctx->audio_channels * sizeof(int##bps##_t*)); \
1488 unlock_frames(ctx); \
1489 return AVERROR(EIO); \
1492 for (c = 0; c < ctx->audio_channels; c++) { \
1493 src[c] = ((int##bps##_t*)ctx->audio_buffer) + c * num_samples; \
1495 dest = (int##bps##_t*)pkt->data; \
1496 shift = bps - ctx->audio_bits_per_sample; \
1497 for (sample = 0; sample < num_samples; sample++) \
1498 for (c = 0; c < ctx->audio_channels; c++) \
1499 *dest++ = src[c][sample] << shift; \
1503 if (
ctx->audio_bits_per_sample <= 16) {
1509 OSStatus
ret = CMBlockBufferCopyDataBytes(block_buffer, 0,
pkt->
size,
pkt->
data);
1510 if (
ret != kCMBlockBufferNoErr) {
1516 CFRelease(
ctx->current_audio_frame);
1517 ctx->current_audio_frame = nil;
1520 if (
ctx->observed_quit) {
1530 if (
ctx->is_stopping) {
1572 .
p.
name =
"avfoundation",