30#import <AVFoundation/AVFoundation.h>
32# import <IOKit/IOKitLib.h>
36# if (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 120000) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 150000)
37# define AVF_IO_MAIN_PORT_DEFAULT kIOMainPortDefault
39# define AVF_IO_MAIN_PORT_DEFAULT kIOMasterPortDefault
93#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
155#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
156 AVCaptureDeviceTransportControlsPlaybackMode observed_mode;
181- (void) captureOutput:(AVCaptureOutput *)captureOutput
182 didOutputSampleBuffer:(CMSampleBufferRef)videoFrame
183 fromConnection:(AVCaptureConnection *)connection;
191 if (
self = [super
init]) {
195#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
197 NSString *keyPath = NSStringFromSelector(
@selector(transportControlsPlaybackMode));
198 NSKeyValueObservingOptions
options = NSKeyValueObservingOptionNew;
200 [
_context->observed_device addObserver:
self
212#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
214 NSString *keyPath = NSStringFromSelector(
@selector(transportControlsPlaybackMode));
215 [_context->observed_device removeObserver:
self forKeyPath: keyPath];
221- (void)observeValueForKeyPath:(NSString *)keyPath
223 change:(NSDictionary *)change
224 context:(
void *)context {
226#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
227 AVCaptureDeviceTransportControlsPlaybackMode
mode =
228 [change[NSKeyValueChangeNewKey] integerValue];
231 if (
mode == AVCaptureDeviceTransportControlsNotPlayingMode) {
243 [
super observeValueForKeyPath: keyPath
250- (void) captureOutput:(AVCaptureOutput *)captureOutput
251 didOutputSampleBuffer:(CMSampleBufferRef)videoFrame
252 fromConnection:(AVCaptureConnection *)connection
265 _context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame);
283- (void) captureOutput:(AVCaptureOutput *)captureOutput
284 didOutputSampleBuffer:(CMSampleBufferRef)audioFrame
285 fromConnection:(AVCaptureConnection *)connection;
293 if (
self = [super
init]) {
299- (void) captureOutput:(AVCaptureOutput *)captureOutput
300 didOutputSampleBuffer:(CMSampleBufferRef)audioFrame
301 fromConnection:(AVCaptureConnection *)connection
314 _context->current_audio_frame = (CMSampleBufferRef)CFRetain(audioFrame);
328 ctx->is_stopping = 1;
331 [
ctx->capture_session stopRunning];
333 [
ctx->capture_session release];
334 [
ctx->video_output release];
335 [
ctx->audio_output release];
336 [
ctx->avf_delegate release];
337 [
ctx->avf_audio_delegate release];
343 ctx->avf_audio_delegate =
NULL;
351 if (
ctx->current_frame) {
352 CFRelease(
ctx->current_frame);
353 ctx->current_frame = nil;
356 if (
ctx->current_audio_frame) {
357 CFRelease(
ctx->current_audio_frame);
358 ctx->current_audio_frame = nil;
371 if (
ctx->url[0] !=
':') {
395 NSObject *
range = nil;
397 NSObject *matching_size_format = nil;
398 NSObject *selected_range = nil;
399 NSObject *selected_format = nil;
405 for (
format in [video_device valueForKey:
@"formats"]) {
406 CMFormatDescriptionRef formatDescription;
407 CMVideoDimensions dimensions;
409 formatDescription = (CMFormatDescriptionRef) [
format performSelector:
@selector(formatDescription)];
410 dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
412 if ((
ctx->width == 0 &&
ctx->height == 0) ||
413 (dimensions.width ==
ctx->width && dimensions.height ==
ctx->height)) {
415 matching_size_format =
format;
417 for (
range in [
format valueForKey:
@"videoSupportedFrameRateRanges"]) {
418 double max_framerate;
420 [[range valueForKey:@"maxFrameRate"] getValue:&max_framerate];
423 selected_range =
range;
430 if (!matching_size_format) {
433 goto unsupported_format;
436 if (!selected_range) {
439 if (
ctx->video_is_muxed) {
440 selected_format = matching_size_format;
443 goto unsupported_format;
447 if ([video_device lockForConfiguration:
NULL] == YES) {
448 if (selected_format) {
449 [video_device setValue:selected_format forKey:@"activeFormat"];
451 if (selected_range) {
452 NSValue *min_frame_duration = [selected_range valueForKey:@"minFrameDuration"];
453 [video_device setValue:min_frame_duration forKey:@"activeVideoMinFrameDuration"];
454 [video_device setValue:min_frame_duration forKey:@"activeVideoMaxFrameDuration"];
460 }
@catch(NSException *e) {
469 for (
format in [video_device valueForKey:
@"formats"]) {
470 CMFormatDescriptionRef formatDescription;
471 CMVideoDimensions dimensions;
473 formatDescription = (CMFormatDescriptionRef) [
format performSelector:
@selector(formatDescription)];
474 dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
476 for (
range in [
format valueForKey:
@"videoSupportedFrameRateRanges"]) {
477 double min_framerate;
478 double max_framerate;
480 [[range valueForKey:@"minFrameRate"] getValue:&min_framerate];
481 [[range valueForKey:@"maxFrameRate"] getValue:&max_framerate];
483 dimensions.width, dimensions.height,
484 min_framerate, max_framerate);
494 NSError *
error = nil;
495 AVCaptureInput* capture_input = nil;
497 NSNumber *pixel_format;
498 NSDictionary *capture_dict;
499 dispatch_queue_t queue;
501 if (!
ctx->video_is_screen) {
502 capture_input = (AVCaptureInput*) [[[AVCaptureDeviceInput alloc] initWithDevice:video_device
error:&
error] autorelease];
504 capture_input = (AVCaptureInput*) video_device;
507 if (!capture_input) {
509 [[
error localizedDescription] UTF8String]);
513 if ([
ctx->capture_session canAddInput:capture_input]) {
514 [
ctx->capture_session addInput:capture_input];
521 ctx->video_output = [[AVCaptureVideoDataOutput alloc] init];
523 if (!
ctx->video_output) {
533 }
@catch (NSException *exception) {
534 if (![[exception
name] isEqualToString:NSUndefinedKeyException]) {
558 if ([[
ctx->video_output availableVideoCVPixelFormatTypes] indexOfObject:[NSNumber numberWithInt:pxl_fmt_spec.
avf_id]] == NSNotFound) {
559 av_log(
s,
AV_LOG_ERROR,
"Selected pixel format (%s) is not supported by the input device.\n",
565 for (NSNumber *pxl_fmt in [
ctx->video_output availableVideoCVPixelFormatTypes]) {
580 pxl_fmt_spec = pxl_fmt_dummy;
595 if (
ctx->capture_raw_data) {
596 ctx->pixel_format = pxl_fmt_spec.
ff_id;
597 ctx->video_output.videoSettings = @{ };
599 ctx->pixel_format = pxl_fmt_spec.
ff_id;
600 pixel_format = [NSNumber numberWithUnsignedInt:pxl_fmt_spec.avf_id];
601 capture_dict = [NSDictionary dictionaryWithObject:pixel_format
602 forKey:(id)kCVPixelBufferPixelFormatTypeKey];
604 [
ctx->video_output setVideoSettings:capture_dict];
606 [
ctx->video_output setAlwaysDiscardsLateVideoFrames:ctx->drop_late_frames];
608#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
610 if (!
ctx->video_is_screen) {
611 int trans_ctrl = [video_device transportControlsSupported];
612 AVCaptureDeviceTransportControlsPlaybackMode trans_mode = [video_device transportControlsPlaybackMode];
615 ctx->observed_mode = trans_mode;
616 ctx->observed_device = video_device;
623 queue = dispatch_queue_create(
"avf_queue",
NULL);
624 [
ctx->video_output setSampleBufferDelegate:ctx->avf_delegate queue:queue];
625 dispatch_release(queue);
627 if ([
ctx->capture_session canAddOutput:
ctx->video_output]) {
628 [
ctx->capture_session addOutput:ctx->video_output];
640 NSError *
error = nil;
641 AVCaptureDeviceInput* audio_dev_input = [[[AVCaptureDeviceInput alloc] initWithDevice:audio_device error:&error] autorelease];
642 dispatch_queue_t queue;
644 if (!audio_dev_input) {
646 [[
error localizedDescription] UTF8String]);
650 if ([
ctx->capture_session canAddInput:audio_dev_input]) {
651 [
ctx->capture_session addInput:audio_dev_input];
658 ctx->audio_output = [[AVCaptureAudioDataOutput alloc] init];
660 if (!
ctx->audio_output) {
667 queue = dispatch_queue_create(
"avf_audio_queue",
NULL);
668 [
ctx->audio_output setSampleBufferDelegate:ctx->avf_audio_delegate queue:queue];
669 dispatch_release(queue);
671 if ([
ctx->capture_session canAddOutput:
ctx->audio_output]) {
672 [
ctx->capture_session addOutput:ctx->audio_output];
684 CVImageBufferRef image_buffer;
685 CGSize image_buffer_size;
693 while (
ctx->frames_captured < 1) {
694 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
699 ctx->video_stream_index = stream->
index;
703 image_buffer = CMSampleBufferGetImageBuffer(
ctx->current_frame);
706 image_buffer_size = CVImageBufferGetEncodedSize(image_buffer);
719 CFRelease(
ctx->current_frame);
720 ctx->current_frame = nil;
730 CMFormatDescriptionRef format_desc;
738 while (
ctx->audio_frames_captured < 1) {
739 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
744 ctx->audio_stream_index = stream->
index;
748 format_desc = CMSampleBufferGetFormatDescription(
ctx->current_audio_frame);
749 const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc);
761 ctx->audio_channels = basic_desc->mChannelsPerFrame;
762 ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel;
763 ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat;
764 ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian;
765 ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger;
766 ctx->audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacked;
767 ctx->audio_non_interleaved = basic_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved;
769 if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
771 ctx->audio_bits_per_sample == 32 &&
774 }
else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
775 ctx->audio_signed_integer &&
776 ctx->audio_bits_per_sample == 16 &&
779 }
else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
780 ctx->audio_signed_integer &&
781 ctx->audio_bits_per_sample == 24 &&
784 }
else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
785 ctx->audio_signed_integer &&
786 ctx->audio_bits_per_sample == 32 &&
795 if (
ctx->audio_non_interleaved) {
796 CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(
ctx->current_audio_frame);
797 ctx->audio_buffer_size = CMBlockBufferGetDataLength(block_buffer);
799 if (!
ctx->audio_buffer) {
806 CFRelease(
ctx->current_audio_frame);
807 ctx->current_audio_frame = nil;
815#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500))
816 NSMutableArray *deviceTypes = nil;
817 if (mediaType == AVMediaTypeVideo) {
818 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeBuiltInWideAngleCamera]];
819 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000)
820 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInDualCamera];
821 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInTelephotoCamera];
823 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110100)
824 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInTrueDepthCamera];
826 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 130000)
827 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInTripleCamera];
828 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInDualWideCamera];
829 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInUltraWideCamera];
831 #if (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 130000)
832 [deviceTypes addObject: AVCaptureDeviceTypeDeskViewCamera];
834 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 150400)
835 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInLiDARDepthCamera];
837 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000 || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 140000))
838 [deviceTypes addObject: AVCaptureDeviceTypeContinuityCamera];
839 [deviceTypes addObject: AVCaptureDeviceTypeExternal];
840 #elif (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000)
841 [deviceTypes addObject: AVCaptureDeviceTypeExternalUnknown];
843 }
else if (mediaType == AVMediaTypeAudio) {
844 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000 || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 140000))
845 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeMicrophone]];
847 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeBuiltInMicrophone]];
849 }
else if (mediaType == AVMediaTypeMuxed) {
850 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000 || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 140000))
851 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeExternal]];
852 #elif (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000)
853 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeExternalUnknown]];
861 AVCaptureDeviceDiscoverySession *captureDeviceDiscoverySession =
862 [AVCaptureDeviceDiscoverySession
863 discoverySessionWithDeviceTypes:deviceTypes
865 position:AVCaptureDevicePositionUnspecified];
866 return [captureDeviceDiscoverySession devices];
868 return [AVCaptureDevice devicesWithMediaType:mediaType];
874#if HAVE_IOKIT && defined(AVF_IO_MAIN_PORT_DEFAULT)
875static int avf_io_get_string(io_service_t service, CFStringRef
key,
char *buf,
size_t size)
877 CFTypeRef
ref = IORegistryEntryCreateCFProperty(service,
key, kCFAllocatorDefault, 0);
878 int ok =
ref && CFGetTypeID(
ref) == CFStringGetTypeID() && CFStringGetCString(
ref, buf,
size, kCFStringEncodingUTF8);
884static int avf_io_get_uint32(io_service_t service, CFStringRef
key, uint32_t *
out)
886 CFTypeRef
ref = IORegistryEntryCreateCFProperty(service,
key, kCFAllocatorDefault, 0);
887 int ok =
ref && CFGetTypeID(
ref) == CFNumberGetTypeID() && CFNumberGetValue(
ref, kCFNumberSInt32Type,
out);
893static int64_t avf_usb_location_for_serial(
const char *serial)
896 io_iterator_t iterator = 0;
897 io_service_t service;
899 if (IOServiceGetMatchingServices(AVF_IO_MAIN_PORT_DEFAULT,
900 IOServiceMatching(
"IOUSBHostDevice"), &iterator) != KERN_SUCCESS)
903 while (location < 0 && (service = IOIteratorNext(iterator))) {
906 if (avf_io_get_string(service, CFSTR(
"USB Serial Number"), found,
sizeof(found)) &&
907 !strcmp(found, serial) &&
908 avf_io_get_uint32(service, CFSTR(
"locationID"), &loc))
910 IOObjectRelease(service);
912 IOObjectRelease(iterator);
919 NSString *serial = nil;
920 io_iterator_t iterator = 0;
921 io_service_t service;
923 if (IOServiceGetMatchingServices(AVF_IO_MAIN_PORT_DEFAULT,
924 IOServiceMatching(
"IOUSBHostDevice"), &iterator) != KERN_SUCCESS)
927 while (!serial && (service = IOIteratorNext(iterator))) {
930 if (avf_io_get_uint32(service, CFSTR(
"locationID"), &loc) && loc == location &&
931 avf_io_get_string(service, CFSTR(
"USB Serial Number"), found,
sizeof(found)))
932 serial = [NSString stringWithUTF8String:found];
933 IOObjectRelease(service);
935 IOObjectRelease(iterator);
942 NSArray *devices, NSArray *devices_muxed,
int *is_muxed)
944 int64_t location = avf_usb_location_for_serial(serial);
945 NSArray *lists[2] = { devices, devices_muxed };
950 for (
int i = 0;
i < 2;
i++) {
951 for (AVCaptureDevice *device in lists[
i]) {
952 NSString *
uid = [device uniqueID];
953 if ([
uid hasPrefix:
@"0x"] &&
954 (uint32_t)(strtoull([
uid UTF8String],
NULL, 16) >> 32) == (uint32_t)location) {
955 *is_muxed = (
i == 1);
967 if (![
uid hasPrefix:
@"AppleUSBAudioEngine:"])
969 NSArray<NSString *> *fields = [uid componentsSeparatedByString:@":"];
970 if (fields.count < 5)
972 NSString *serial = fields[fields.count - 2];
973 if (serial.length && avf_usb_location_for_serial([serial UTF8String]) >= 0)
985 NSArray *devices, NSArray *devices_muxed,
int *is_muxed)
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) {
1421 pkt->stream_index =
ctx->video_stream_index;
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) {
1467 pkt->stream_index =
ctx->audio_stream_index;
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) {
1528 }
while (!
pkt->data && !
ctx->is_stopping);
1530 if (
ctx->is_stopping) {
1564 .class_name =
"AVFoundation indev",
1572 .p.name =
"avfoundation",
static const char *const format[]
const FFInputFormat ff_avfoundation_demuxer
static AVFormatContext * ctx
Main libavdevice API header.
static int get_audio_config(AVFormatContext *s)
static void lock_frames(AVFContext *ctx)
static const AVClass avf_class
static AVCaptureDevice * avf_audio_device_with_serial(const char *serial, NSArray *devices)
static int parse_device_name(AVFormatContext *s)
static AVCaptureDevice * avf_device_with_uid(const char *uid, NSArray *devices, NSArray *devices_muxed, int *is_muxed)
static AVCaptureDevice * avf_video_device_with_serial(const char *serial, NSArray *devices, NSArray *devices_muxed, int *is_muxed)
static int avf_close(AVFormatContext *s)
static const AVOption options[]
static int add_video_device(AVFormatContext *s, AVCaptureDevice *video_device)
static void unlock_frames(AVFContext *ctx)
static const AVRational avf_time_base_q
static void avf_log_device_entry(AVFContext *ctx, int index, AVCaptureDevice *device)
static NSArray * getDevicesWithMediaType(AVMediaType mediaType)
static const struct AVFPixelFormatSpec avf_pixel_formats[]
static int add_audio_device(AVFormatContext *s, AVCaptureDevice *audio_device)
static void destroy_context(AVFContext *ctx)
static int avf_read_header(AVFormatContext *s)
static int copy_cvpixelbuffer(AVFormatContext *s, CVPixelBufferRef image_buffer, AVPacket *pkt)
static NSString * avf_audio_serial_for_uid(NSString *uid)
static const int avf_time_base
static int configure_video_device(AVFormatContext *s, AVCaptureDevice *video_device)
Configure the video device.
static NSString * avf_usb_serial_for_location(uint32_t location)
static int avf_device_from_id(AVFContext *ctx, AVMediaType media_type, NSArray *devices, NSArray *devices_muxed, const char *id, AVCaptureDevice **device, int *is_muxed)
static NSString * avf_device_listing_serial(AVCaptureDevice *device)
#define INTERLEAVE_OUTPUT(bps)
static int avf_read_packet(AVFormatContext *s, AVPacket *pkt)
static int get_video_config(AVFormatContext *s)
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
static int FUNC timing_info(CodedBitstreamContext *ctx, RWContext *rw, AV1RawTimingInfo *current)
#define i(width, name, range_min, range_max)
Public libavutil channel layout APIs header.
static __device__ float fabs(float a)
int(* init)(AVBSFContext *ctx)
mode
Use these values in ebur128_init (or'ed).
static int read_header(FFV1Context *f, RangeCoder *c)
#define AV_OPT_FLAG_DECODING_PARAM
A generic parameter which can be set by the user for demuxing or decoding.
@ AV_OPT_TYPE_IMAGE_SIZE
Underlying C type is two consecutive integers.
@ AV_OPT_TYPE_PIXEL_FMT
Underlying C type is enum AVPixelFormat.
@ AV_OPT_TYPE_VIDEO_RATE
Underlying C type is AVRational.
@ AV_OPT_TYPE_INT
Underlying C type is int.
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
Get the default channel layout for a given number of channels.
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
#define AVERROR_EXTERNAL
Generic error in an external library.
#define AVERROR_EOF
End of file.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
#define AV_LOG_WARNING
Something somehow does not look correct.
#define AV_LOG_INFO
Standard information.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
const char * av_default_item_name(void *ptr)
Return the context name.
static AVRational av_make_q(int num, int den)
Create an AVRational.
static double av_q2d(AVRational a)
Convert an AVRational to a double.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
int av_image_copy_to_buffer(uint8_t *dst, int dst_size, const uint8_t *const src_data[4], const int src_linesize[4], enum AVPixelFormat pix_fmt, int width, int height, int align)
Copy image data from an image into a buffer.
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
#define LIBAVUTIL_VERSION_INT
AudioReceiver class - delegate for AVCaptureSession.
FrameReceiver class - delegate for AVCaptureSession.
static int shift(int a, int b)
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
static av_cold int read_close(AVFormatContext *ctx)
@ AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT
Memory handling functions.
static av_always_inline int pthread_cond_broadcast(pthread_cond_t *cond)
static av_always_inline int pthread_mutex_lock(pthread_mutex_t *mutex)
static av_always_inline int pthread_cond_destroy(pthread_cond_t *cond)
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
static av_always_inline int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
static av_always_inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
#define AV_PIX_FMT_YUV422P10
AVPixelFormat
Pixel format.
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
@ AV_PIX_FMT_MONOBLACK
Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb.
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
@ AV_PIX_FMT_RGB555BE
packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), big-endian , X=unused/undefined
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
@ AV_PIX_FMT_BGR48BE
packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big...
@ AV_PIX_FMT_UYVY422
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
@ AV_PIX_FMT_0BGR
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
@ AV_PIX_FMT_YUVA444P16LE
planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian)
@ AV_PIX_FMT_RGB565LE
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian
@ AV_PIX_FMT_RGB555LE
packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), little-endian, X=unused/undefined
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
@ AV_PIX_FMT_RGB565BE
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian
@ AV_PIX_FMT_YUYV422
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
#define AV_PIX_FMT_YUV422P16
#define AV_PIX_FMT_YUV444P10
Describe the class of an AVClass context structure.
int height
The height of the video frame in pixels.
AVChannelLayout ch_layout
The channel layout and number of channels.
int width
The width of the video frame in pixels.
enum AVMediaType codec_type
General type of the encoded data.
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
int sample_rate
The number of audio samples per second.
CMSampleBufferRef current_frame
pthread_cond_t frame_wait_cond
AVCaptureAudioDataOutput * audio_output
int audio_bits_per_sample
pthread_mutex_t frame_lock
int audio_non_interleaved
AVCaptureVideoDataOutput * video_output
int audio_frames_captured
enum AVPixelFormat pixel_format
AVCaptureSession * capture_session
CMSampleBufferRef current_audio_frame
AVCaptureDevice * observed_device
This structure stores compressed data.
Rational number (pair of numerator and denominator).
AVCodecParameters * codecpar
Codec parameters associated with this stream.
int index
stream index in AVFormatContext
static void error(const char *err)
static int ref[MAX_W *MAX_W]