30#import <AVFoundation/AVFoundation.h>
32# import <IOKit/IOKitLib.h>
35# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 120000
36# define AVF_IO_MAIN_PORT_DEFAULT kIOMainPortDefault
38# define AVF_IO_MAIN_PORT_DEFAULT kIOMasterPortDefault
92#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
154#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
155 AVCaptureDeviceTransportControlsPlaybackMode observed_mode;
180- (void) captureOutput:(AVCaptureOutput *)captureOutput
181 didOutputSampleBuffer:(CMSampleBufferRef)videoFrame
182 fromConnection:(AVCaptureConnection *)connection;
190 if (
self = [super
init]) {
194#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
196 NSString *keyPath = NSStringFromSelector(
@selector(transportControlsPlaybackMode));
197 NSKeyValueObservingOptions
options = NSKeyValueObservingOptionNew;
199 [
_context->observed_device addObserver:
self
211#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
213 NSString *keyPath = NSStringFromSelector(
@selector(transportControlsPlaybackMode));
214 [_context->observed_device removeObserver:
self forKeyPath: keyPath];
220- (void)observeValueForKeyPath:(NSString *)keyPath
222 change:(NSDictionary *)change
223 context:(
void *)context {
225#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
226 AVCaptureDeviceTransportControlsPlaybackMode
mode =
227 [change[NSKeyValueChangeNewKey] integerValue];
230 if (
mode == AVCaptureDeviceTransportControlsNotPlayingMode) {
242 [
super observeValueForKeyPath: keyPath
249- (void) captureOutput:(AVCaptureOutput *)captureOutput
250 didOutputSampleBuffer:(CMSampleBufferRef)videoFrame
251 fromConnection:(AVCaptureConnection *)connection
264 _context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame);
282- (void) captureOutput:(AVCaptureOutput *)captureOutput
283 didOutputSampleBuffer:(CMSampleBufferRef)audioFrame
284 fromConnection:(AVCaptureConnection *)connection;
292 if (
self = [super
init]) {
298- (void) captureOutput:(AVCaptureOutput *)captureOutput
299 didOutputSampleBuffer:(CMSampleBufferRef)audioFrame
300 fromConnection:(AVCaptureConnection *)connection
313 _context->current_audio_frame = (CMSampleBufferRef)CFRetain(audioFrame);
327 ctx->is_stopping = 1;
330 [
ctx->capture_session stopRunning];
332 [
ctx->capture_session release];
333 [
ctx->video_output release];
334 [
ctx->audio_output release];
335 [
ctx->avf_delegate release];
336 [
ctx->avf_audio_delegate release];
342 ctx->avf_audio_delegate =
NULL;
350 if (
ctx->current_frame) {
351 CFRelease(
ctx->current_frame);
352 ctx->current_frame = nil;
355 if (
ctx->current_audio_frame) {
356 CFRelease(
ctx->current_audio_frame);
357 ctx->current_audio_frame = nil;
370 if (
ctx->url[0] !=
':') {
394 NSObject *
range = nil;
396 NSObject *selected_range = nil;
397 NSObject *selected_format = nil;
403 for (
format in [video_device valueForKey:
@"formats"]) {
404 CMFormatDescriptionRef formatDescription;
405 CMVideoDimensions dimensions;
407 formatDescription = (CMFormatDescriptionRef) [
format performSelector:
@selector(formatDescription)];
408 dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
410 if ((
ctx->width == 0 &&
ctx->height == 0) ||
411 (dimensions.width ==
ctx->width && dimensions.height ==
ctx->height)) {
415 for (
range in [
format valueForKey:
@"videoSupportedFrameRateRanges"]) {
416 double max_framerate;
418 [[range valueForKey:@"maxFrameRate"] getValue:&max_framerate];
420 selected_range =
range;
427 if (!selected_format) {
430 goto unsupported_format;
433 if (!selected_range) {
436 if (
ctx->video_is_muxed) {
439 goto unsupported_format;
443 if ([video_device lockForConfiguration:
NULL] == YES) {
444 if (selected_format) {
445 [video_device setValue:selected_format forKey:@"activeFormat"];
447 if (selected_range) {
448 NSValue *min_frame_duration = [selected_range valueForKey:@"minFrameDuration"];
449 [video_device setValue:min_frame_duration forKey:@"activeVideoMinFrameDuration"];
450 [video_device setValue:min_frame_duration forKey:@"activeVideoMaxFrameDuration"];
456 }
@catch(NSException *e) {
465 for (
format in [video_device valueForKey:
@"formats"]) {
466 CMFormatDescriptionRef formatDescription;
467 CMVideoDimensions dimensions;
469 formatDescription = (CMFormatDescriptionRef) [
format performSelector:
@selector(formatDescription)];
470 dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
472 for (
range in [
format valueForKey:
@"videoSupportedFrameRateRanges"]) {
473 double min_framerate;
474 double max_framerate;
476 [[range valueForKey:@"minFrameRate"] getValue:&min_framerate];
477 [[range valueForKey:@"maxFrameRate"] getValue:&max_framerate];
479 dimensions.width, dimensions.height,
480 min_framerate, max_framerate);
490 NSError *
error = nil;
491 AVCaptureInput* capture_input = nil;
493 NSNumber *pixel_format;
494 NSDictionary *capture_dict;
495 dispatch_queue_t queue;
497 if (!
ctx->video_is_screen) {
498 capture_input = (AVCaptureInput*) [[[AVCaptureDeviceInput alloc] initWithDevice:video_device
error:&
error] autorelease];
500 capture_input = (AVCaptureInput*) video_device;
503 if (!capture_input) {
505 [[
error localizedDescription] UTF8String]);
509 if ([
ctx->capture_session canAddInput:capture_input]) {
510 [
ctx->capture_session addInput:capture_input];
517 ctx->video_output = [[AVCaptureVideoDataOutput alloc] init];
519 if (!
ctx->video_output) {
529 }
@catch (NSException *exception) {
530 if (![[exception
name] isEqualToString:NSUndefinedKeyException]) {
554 if ([[
ctx->video_output availableVideoCVPixelFormatTypes] indexOfObject:[NSNumber numberWithInt:pxl_fmt_spec.
avf_id]] == NSNotFound) {
555 av_log(
s,
AV_LOG_ERROR,
"Selected pixel format (%s) is not supported by the input device.\n",
561 for (NSNumber *pxl_fmt in [
ctx->video_output availableVideoCVPixelFormatTypes]) {
576 pxl_fmt_spec = pxl_fmt_dummy;
591 if (
ctx->capture_raw_data) {
592 ctx->pixel_format = pxl_fmt_spec.
ff_id;
593 ctx->video_output.videoSettings = @{ };
595 ctx->pixel_format = pxl_fmt_spec.
ff_id;
596 pixel_format = [NSNumber numberWithUnsignedInt:pxl_fmt_spec.avf_id];
597 capture_dict = [NSDictionary dictionaryWithObject:pixel_format
598 forKey:(id)kCVPixelBufferPixelFormatTypeKey];
600 [
ctx->video_output setVideoSettings:capture_dict];
602 [
ctx->video_output setAlwaysDiscardsLateVideoFrames:ctx->drop_late_frames];
604#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
606 if (!
ctx->video_is_screen) {
607 int trans_ctrl = [video_device transportControlsSupported];
608 AVCaptureDeviceTransportControlsPlaybackMode trans_mode = [video_device transportControlsPlaybackMode];
611 ctx->observed_mode = trans_mode;
612 ctx->observed_device = video_device;
619 queue = dispatch_queue_create(
"avf_queue",
NULL);
620 [
ctx->video_output setSampleBufferDelegate:ctx->avf_delegate queue:queue];
621 dispatch_release(queue);
623 if ([
ctx->capture_session canAddOutput:
ctx->video_output]) {
624 [
ctx->capture_session addOutput:ctx->video_output];
636 NSError *
error = nil;
637 AVCaptureDeviceInput* audio_dev_input = [[[AVCaptureDeviceInput alloc] initWithDevice:audio_device error:&error] autorelease];
638 dispatch_queue_t queue;
640 if (!audio_dev_input) {
642 [[
error localizedDescription] UTF8String]);
646 if ([
ctx->capture_session canAddInput:audio_dev_input]) {
647 [
ctx->capture_session addInput:audio_dev_input];
654 ctx->audio_output = [[AVCaptureAudioDataOutput alloc] init];
656 if (!
ctx->audio_output) {
663 queue = dispatch_queue_create(
"avf_audio_queue",
NULL);
664 [
ctx->audio_output setSampleBufferDelegate:ctx->avf_audio_delegate queue:queue];
665 dispatch_release(queue);
667 if ([
ctx->capture_session canAddOutput:
ctx->audio_output]) {
668 [
ctx->capture_session addOutput:ctx->audio_output];
680 CVImageBufferRef image_buffer;
681 CGSize image_buffer_size;
689 while (
ctx->frames_captured < 1) {
690 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
695 ctx->video_stream_index = stream->
index;
699 image_buffer = CMSampleBufferGetImageBuffer(
ctx->current_frame);
702 image_buffer_size = CVImageBufferGetEncodedSize(image_buffer);
715 CFRelease(
ctx->current_frame);
716 ctx->current_frame = nil;
726 CMFormatDescriptionRef format_desc;
734 while (
ctx->audio_frames_captured < 1) {
735 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
740 ctx->audio_stream_index = stream->
index;
744 format_desc = CMSampleBufferGetFormatDescription(
ctx->current_audio_frame);
745 const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc);
757 ctx->audio_channels = basic_desc->mChannelsPerFrame;
758 ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel;
759 ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat;
760 ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian;
761 ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger;
762 ctx->audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacked;
763 ctx->audio_non_interleaved = basic_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved;
765 if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
767 ctx->audio_bits_per_sample == 32 &&
770 }
else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
771 ctx->audio_signed_integer &&
772 ctx->audio_bits_per_sample == 16 &&
775 }
else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
776 ctx->audio_signed_integer &&
777 ctx->audio_bits_per_sample == 24 &&
780 }
else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
781 ctx->audio_signed_integer &&
782 ctx->audio_bits_per_sample == 32 &&
791 if (
ctx->audio_non_interleaved) {
792 CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(
ctx->current_audio_frame);
793 ctx->audio_buffer_size = CMBlockBufferGetDataLength(block_buffer);
795 if (!
ctx->audio_buffer) {
802 CFRelease(
ctx->current_audio_frame);
803 ctx->current_audio_frame = nil;
811#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500))
812 NSMutableArray *deviceTypes = nil;
813 if (mediaType == AVMediaTypeVideo) {
814 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeBuiltInWideAngleCamera]];
815 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000)
816 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInDualCamera];
817 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInTelephotoCamera];
819 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110100)
820 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInTrueDepthCamera];
822 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 130000)
823 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInTripleCamera];
824 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInDualWideCamera];
825 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInUltraWideCamera];
827 #if (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 130000)
828 [deviceTypes addObject: AVCaptureDeviceTypeDeskViewCamera];
830 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 150400)
831 [deviceTypes addObject: AVCaptureDeviceTypeBuiltInLiDARDepthCamera];
833 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000 || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 140000))
834 [deviceTypes addObject: AVCaptureDeviceTypeContinuityCamera];
835 [deviceTypes addObject: AVCaptureDeviceTypeExternal];
836 #elif (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000)
837 [deviceTypes addObject: AVCaptureDeviceTypeExternalUnknown];
839 }
else if (mediaType == AVMediaTypeAudio) {
840 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000 || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 140000))
841 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeMicrophone]];
843 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeBuiltInMicrophone]];
845 }
else if (mediaType == AVMediaTypeMuxed) {
846 #if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000 || (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED >= 140000))
847 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeExternal]];
848 #elif (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000)
849 deviceTypes = [NSMutableArray arrayWithArray:@[AVCaptureDeviceTypeExternalUnknown]];
857 AVCaptureDeviceDiscoverySession *captureDeviceDiscoverySession =
858 [AVCaptureDeviceDiscoverySession
859 discoverySessionWithDeviceTypes:deviceTypes
861 position:AVCaptureDevicePositionUnspecified];
862 return [captureDeviceDiscoverySession devices];
864 return [AVCaptureDevice devicesWithMediaType:mediaType];
871static int avf_io_get_string(io_service_t service, CFStringRef
key,
char *buf,
size_t size)
873 CFTypeRef
ref = IORegistryEntryCreateCFProperty(service,
key, kCFAllocatorDefault, 0);
874 int ok =
ref && CFGetTypeID(
ref) == CFStringGetTypeID() && CFStringGetCString(
ref, buf,
size, kCFStringEncodingUTF8);
880static int avf_io_get_uint32(io_service_t service, CFStringRef
key, uint32_t *
out)
882 CFTypeRef
ref = IORegistryEntryCreateCFProperty(service,
key, kCFAllocatorDefault, 0);
883 int ok =
ref && CFGetTypeID(
ref) == CFNumberGetTypeID() && CFNumberGetValue(
ref, kCFNumberSInt32Type,
out);
894 io_iterator_t iterator = 0;
895 io_service_t service;
897 if (IOServiceGetMatchingServices(AVF_IO_MAIN_PORT_DEFAULT,
898 IOServiceMatching(
"IOUSBHostDevice"), &iterator) != KERN_SUCCESS)
901 while (location < 0 && (service = IOIteratorNext(iterator))) {
904 if (avf_io_get_string(service, CFSTR(
"USB Serial Number"), found,
sizeof(found)) &&
905 !strcmp(found, serial) &&
906 avf_io_get_uint32(service, CFSTR(
"locationID"), &loc))
908 IOObjectRelease(service);
910 IOObjectRelease(iterator);
924 NSString *serial = nil;
925 io_iterator_t iterator = 0;
926 io_service_t service;
928 if (IOServiceGetMatchingServices(AVF_IO_MAIN_PORT_DEFAULT,
929 IOServiceMatching(
"IOUSBHostDevice"), &iterator) != KERN_SUCCESS)
932 while (!serial && (service = IOIteratorNext(iterator))) {
935 if (avf_io_get_uint32(service, CFSTR(
"locationID"), &loc) && loc == location &&
936 avf_io_get_string(service, CFSTR(
"USB Serial Number"), found,
sizeof(found)))
937 serial = [NSString stringWithUTF8String:found];
938 IOObjectRelease(service);
940 IOObjectRelease(iterator);
953 NSArray *devices, NSArray *devices_muxed,
int *is_muxed)
956 NSArray *lists[2] = { devices, devices_muxed };
961 for (
int i = 0;
i < 2;
i++) {
962 for (AVCaptureDevice *device in lists[
i]) {
963 NSString *
uid = [device uniqueID];
964 if ([
uid hasPrefix:
@"0x"] &&
965 (uint32_t)(strtoull([
uid UTF8String],
NULL, 16) >> 32) == (uint32_t)location) {
966 *is_muxed = (
i == 1);
979 if (![
uid hasPrefix:
@"AppleUSBAudioEngine:"])
981 NSArray<NSString *> *fields = [uid componentsSeparatedByString:@":"];
982 if (fields.count < 5)
984 NSString *serial = fields[fields.count - 2];
998 NSString *want = [NSString stringWithUTF8String:serial];
1000 for (AVCaptureDevice *device in devices)
1008 NSArray *devices, NSArray *devices_muxed,
int *is_muxed)
1010 NSString *want = [NSString stringWithUTF8String:uid];
1011 NSArray *lists[2] = { devices, devices_muxed };
1013 for (
int i = 0;
i < 2;
i++) {
1014 for (AVCaptureDevice *device in lists[
i]) {
1015 if ([[device uniqueID] isEqualToString:want]) {
1017 *is_muxed = (
i == 1);
1029 NSString *
uid = [device uniqueID];
1031 if ([
uid hasPrefix:
@"0x"]) {
1032 unsigned long long value = strtoull([
uid UTF8String],
NULL, 16);
1034 return serial.length ? serial : nil;
1045 [[device localizedName] UTF8String], [[device uniqueID] UTF8String],
1046 [serial UTF8String]);
1049 [[device localizedName] UTF8String], [[device uniqueID] UTF8String]);
1054 NSArray *devices, NSArray *devices_muxed,
1055 const char *
id, AVCaptureDevice **device,
int *is_muxed)
1057 BOOL is_audio = [media_type isEqualToString:AVMediaTypeAudio];
1058 const char *kind = is_audio ?
"Audio" :
"Video";
1071 "%s capture device with serial number '%s' not found\n", kind,
value);
1076 "%s capture device with unique ID '%s' not found\n", kind,
value);
1079 "Invalid %s device id '%s': expected 'uid:<unique ID>' or 'serial:<serial number>'\n",
1080 is_audio ?
"audio" :
"video",
id);
1088 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1089 uint32_t num_screens = 0;
1091 AVCaptureDevice *video_device = nil;
1092 AVCaptureDevice *audio_device = nil;
1098 ctx->num_video_devices = [devices count] + [devices_muxed count];
1102 ctx->is_stopping = 0;
1104#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1105 CGGetActiveDisplayList(0,
NULL, &num_screens);
1109 if (
ctx->list_devices) {
1112 for (AVCaptureDevice *device in devices) {
1113 index = [devices indexOfObject:device];
1116 for (AVCaptureDevice *device in devices_muxed) {
1117 index = [devices count] + [devices_muxed indexOfObject:device];
1120#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1121 if (num_screens > 0) {
1122 CGDirectDisplayID screens[num_screens];
1123 CGGetActiveDisplayList(num_screens, screens, &num_screens);
1124 for (
int i = 0;
i < num_screens;
i++) {
1132 for (AVCaptureDevice *device in devices) {
1133 int index = [devices indexOfObject:device];
1145 if (
ctx->video_device_index == -1 &&
ctx->video_filename) {
1146 sscanf(
ctx->video_filename,
"%d", &
ctx->video_device_index);
1148 if (
ctx->audio_device_index == -1 &&
ctx->audio_filename) {
1149 sscanf(
ctx->audio_filename,
"%d", &
ctx->audio_device_index);
1153 ctx->video_device_id, &video_device, &
ctx->video_is_muxed)) {
1156 }
else if (
ctx->video_device_index >= 0) {
1157 if (
ctx->video_device_index <
ctx->num_video_devices) {
1158 if (
ctx->video_device_index < [devices count]) {
1159 video_device = [devices objectAtIndex:ctx->video_device_index];
1161 video_device = [devices_muxed objectAtIndex:(ctx->video_device_index - [devices count])];
1162 ctx->video_is_muxed = 1;
1164 }
else if (
ctx->video_device_index <
ctx->num_video_devices + num_screens) {
1165#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1166 CGDirectDisplayID screens[num_screens];
1167 CGGetActiveDisplayList(num_screens, screens, &num_screens);
1168 AVCaptureScreenInput* capture_screen_input = [[[AVCaptureScreenInput alloc] initWithDisplayID:screens[
ctx->video_device_index - ctx->num_video_devices]] autorelease];
1170 if (
ctx->framerate.num > 0) {
1171 capture_screen_input.minFrameDuration = CMTimeMake(
ctx->framerate.den,
ctx->framerate.num);
1174#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
1175 if (
ctx->capture_cursor) {
1176 capture_screen_input.capturesCursor = YES;
1178 capture_screen_input.capturesCursor = NO;
1182 if (
ctx->capture_mouse_clicks) {
1183 capture_screen_input.capturesMouseClicks = YES;
1185 capture_screen_input.capturesMouseClicks = NO;
1188 video_device = (AVCaptureDevice*) capture_screen_input;
1189 ctx->video_is_screen = 1;
1195 }
else if (
ctx->video_filename &&
1196 strncmp(
ctx->video_filename,
"none", 4)) {
1197 if (!strncmp(
ctx->video_filename,
"default", 7)) {
1198 video_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
1201 for (AVCaptureDevice *device in devices) {
1202 if (!strncmp(
ctx->video_filename, [[device localizedName] UTF8String], strlen(
ctx->video_filename))) {
1203 video_device = device;
1208 for (AVCaptureDevice *device in devices_muxed) {
1209 if (!strncmp(
ctx->video_filename, [[device localizedName] UTF8String], strlen(
ctx->video_filename))) {
1210 video_device = device;
1211 ctx->video_is_muxed = 1;
1216#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1218 if (!video_device) {
1220 if(sscanf(
ctx->video_filename,
"Capture screen %d", &idx) && idx < num_screens) {
1221 CGDirectDisplayID screens[num_screens];
1222 CGGetActiveDisplayList(num_screens, screens, &num_screens);
1223 AVCaptureScreenInput* capture_screen_input = [[[AVCaptureScreenInput alloc] initWithDisplayID:screens[idx]] autorelease];
1224 video_device = (AVCaptureDevice*) capture_screen_input;
1225 ctx->video_device_index =
ctx->num_video_devices + idx;
1226 ctx->video_is_screen = 1;
1228 if (
ctx->framerate.num > 0) {
1229 capture_screen_input.minFrameDuration = CMTimeMake(
ctx->framerate.den,
ctx->framerate.num);
1232#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
1233 if (
ctx->capture_cursor) {
1234 capture_screen_input.capturesCursor = YES;
1236 capture_screen_input.capturesCursor = NO;
1240 if (
ctx->capture_mouse_clicks) {
1241 capture_screen_input.capturesMouseClicks = YES;
1243 capture_screen_input.capturesMouseClicks = NO;
1250 if (!video_device) {
1258 ctx->audio_device_id, &audio_device,
NULL)) {
1261 }
else if (
ctx->audio_device_index >= 0) {
1262 if (
ctx->audio_device_index >= [audio_devices count]) {
1267 audio_device = [audio_devices objectAtIndex:ctx->audio_device_index];
1268 }
else if (
ctx->audio_filename &&
1269 strncmp(
ctx->audio_filename,
"none", 4)) {
1270 if (!strncmp(
ctx->audio_filename,
"default", 7)) {
1271 audio_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
1273 for (AVCaptureDevice *device in audio_devices) {
1274 if (!strncmp(
ctx->audio_filename, [[device localizedName] UTF8String], strlen(
ctx->audio_filename))) {
1275 audio_device = device;
1281 if (!audio_device) {
1288 if (!video_device && !audio_device) {
1294 if (!
ctx->video_is_screen) {
1301 av_log(
s,
AV_LOG_DEBUG,
"audio device '%s' opened\n", [[audio_device localizedName] UTF8String]);
1305 ctx->capture_session = [[AVCaptureSession alloc] init];
1313 [
ctx->capture_session startRunning];
1317 if (!
ctx->video_is_screen) {
1318 [video_device unlockForConfiguration];
1342 CVPixelBufferRef image_buffer,
1346 int src_linesize[4];
1347 const uint8_t *src_data[4];
1348 int width = CVPixelBufferGetWidth(image_buffer);
1349 int height = CVPixelBufferGetHeight(image_buffer);
1352 memset(src_linesize, 0,
sizeof(src_linesize));
1353 memset(src_data, 0,
sizeof(src_data));
1355 status = CVPixelBufferLockBaseAddress(image_buffer, 0);
1356 if (status != kCVReturnSuccess) {
1361 if (CVPixelBufferIsPlanar(image_buffer)) {
1362 size_t plane_count = CVPixelBufferGetPlaneCount(image_buffer);
1364 for(
i = 0;
i < plane_count;
i++){
1365 src_linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(image_buffer,
i);
1366 src_data[i] = CVPixelBufferGetBaseAddressOfPlane(image_buffer,
i);
1369 src_linesize[0] = CVPixelBufferGetBytesPerRow(image_buffer);
1370 src_data[0] = CVPixelBufferGetBaseAddress(image_buffer);
1374 src_data, src_linesize,
1379 CVPixelBufferUnlockBaseAddress(image_buffer, 0);
1390 CVImageBufferRef image_buffer;
1391 CMBlockBufferRef block_buffer;
1393 if (
ctx->current_frame != nil) {
1397 image_buffer = CMSampleBufferGetImageBuffer(
ctx->current_frame);
1398 block_buffer = CMSampleBufferGetDataBuffer(
ctx->current_frame);
1400 if (image_buffer != nil) {
1401 length = (int)CVPixelBufferGetDataSize(image_buffer);
1402 }
else if (block_buffer != nil) {
1403 length = (int)CMBlockBufferGetDataLength(block_buffer);
1417 if (CMSampleBufferGetOutputSampleTimingInfoArray(
ctx->current_frame, 1, &
timing_info, &count) == noErr) {
1422 pkt->stream_index =
ctx->video_stream_index;
1429 OSStatus ret = CMBlockBufferCopyDataBytes(block_buffer, 0,
pkt->size,
pkt->data);
1430 if (ret != kCMBlockBufferNoErr) {
1434 CFRelease(
ctx->current_frame);
1435 ctx->current_frame = nil;
1441 }
else if (
ctx->current_audio_frame != nil) {
1442 CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(
ctx->current_audio_frame);
1443 int block_buffer_size = CMBlockBufferGetDataLength(block_buffer);
1445 if (!block_buffer || !block_buffer_size) {
1450 if (
ctx->audio_non_interleaved && block_buffer_size >
ctx->audio_buffer_size) {
1463 if (CMSampleBufferGetOutputSampleTimingInfoArray(
ctx->current_audio_frame, 1, &
timing_info, &count) == noErr) {
1468 pkt->stream_index =
ctx->audio_stream_index;
1471 if (
ctx->audio_non_interleaved) {
1474 OSStatus ret = CMBlockBufferCopyDataBytes(block_buffer, 0,
pkt->size,
ctx->audio_buffer);
1475 if (ret != kCMBlockBufferNoErr) {
1480 num_samples =
pkt->size / (
ctx->audio_channels * (
ctx->audio_bits_per_sample >> 3));
1483 #define INTERLEAVE_OUTPUT(bps) \
1485 int##bps##_t **src; \
1486 int##bps##_t *dest; \
1487 src = av_malloc(ctx->audio_channels * sizeof(int##bps##_t*)); \
1489 unlock_frames(ctx); \
1490 return AVERROR(EIO); \
1493 for (c = 0; c < ctx->audio_channels; c++) { \
1494 src[c] = ((int##bps##_t*)ctx->audio_buffer) + c * num_samples; \
1496 dest = (int##bps##_t*)pkt->data; \
1497 shift = bps - ctx->audio_bits_per_sample; \
1498 for (sample = 0; sample < num_samples; sample++) \
1499 for (c = 0; c < ctx->audio_channels; c++) \
1500 *dest++ = src[c][sample] << shift; \
1504 if (
ctx->audio_bits_per_sample <= 16) {
1510 OSStatus ret = CMBlockBufferCopyDataBytes(block_buffer, 0,
pkt->size,
pkt->data);
1511 if (ret != kCMBlockBufferNoErr) {
1517 CFRelease(
ctx->current_audio_frame);
1518 ctx->current_audio_frame = nil;
1521 if (
ctx->observed_quit) {
1529 }
while (!
pkt->data && !
ctx->is_stopping);
1531 if (
ctx->is_stopping) {
1565 .class_name =
"AVFoundation indev",
1573 .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 int64_t avf_usb_location_for_serial(const char *serial)
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]