From a6555f88aaf0730e64240136fb19d8effb3a0738 Mon Sep 17 00:00:00 2001 From: Thilo Borgmann Date: Sat, 25 Oct 2014 17:02:28 +0200 Subject: [PATCH] lavd/avfoundation: Add support for screen capturing. Patch based on pull-request by Joseph Benden Signed-off-by: Michael Niedermayer --- configure | 2 +- libavdevice/avfoundation.m | 70 ++++++++++++++++++++++++++++++-------- 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/configure b/configure index 3e181aa4b1..3eb1aa08a1 100755 --- a/configure +++ b/configure @@ -2452,7 +2452,7 @@ xwma_demuxer_select="riffdec" # indevs / outdevs alsa_indev_deps="alsa_asoundlib_h snd_pcm_htimestamp" alsa_outdev_deps="alsa_asoundlib_h" -avfoundation_indev_extralibs="-framework CoreVideo -framework Foundation -framework AVFoundation -framework CoreMedia" +avfoundation_indev_extralibs="-framework CoreVideo -framework Foundation -framework AVFoundation -framework CoreMedia -framework CoreGraphics" avfoundation_indev_select="avfoundation" bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" caca_outdev_deps="libcaca" diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 8c00a0ee73..75c62ed263 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -99,6 +99,8 @@ typedef struct char *video_filename; char *audio_filename; + int num_video_devices; + int audio_channels; int audio_bits_per_sample; int audio_float; @@ -264,16 +266,22 @@ static int add_video_device(AVFormatContext *s, AVCaptureDevice *video_device) { AVFContext *ctx = (AVFContext*)s->priv_data; NSError *error = nil; - AVCaptureDeviceInput* capture_dev_input = [[[AVCaptureDeviceInput alloc] initWithDevice:video_device error:&error] autorelease]; + AVCaptureInput* capture_input = nil; - if (!capture_dev_input) { + if (ctx->video_device_index < ctx->num_video_devices) { + capture_input = (AVCaptureInput*) [[[AVCaptureDeviceInput alloc] initWithDevice:video_device error:&error] autorelease]; + } else { + capture_input = (AVCaptureInput*) video_device; + } + + if (!capture_input) { av_log(s, AV_LOG_ERROR, "Failed to create AV capture input device: %s\n", [[error localizedDescription] UTF8String]); return 1; } - if ([ctx->capture_session canAddInput:capture_dev_input]) { - [ctx->capture_session addInput:capture_dev_input]; + if ([ctx->capture_session canAddInput:capture_input]) { + [ctx->capture_session addInput:capture_input]; } else { av_log(s, AV_LOG_ERROR, "can't add video input to capture session\n"); return 1; @@ -522,19 +530,32 @@ static int avf_read_header(AVFormatContext *s) AVFContext *ctx = (AVFContext*)s->priv_data; ctx->first_pts = av_gettime(); ctx->first_audio_pts = av_gettime(); + uint32_t num_screens = 0; pthread_mutex_init(&ctx->frame_lock, NULL); pthread_cond_init(&ctx->frame_wait_cond, NULL); + CGGetActiveDisplayList(0, NULL, &num_screens); + // List devices if requested if (ctx->list_devices) { av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n"); NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + int index = 0; for (AVCaptureDevice *device in devices) { const char *name = [[device localizedName] UTF8String]; - int index = [devices indexOfObject:device]; + index = [devices indexOfObject:device]; av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); + index++; } + if (num_screens > 0) { + CGDirectDisplayID screens[num_screens]; + CGGetActiveDisplayList(num_screens, screens, &num_screens); + for (int i = 0; i < num_screens; i++) { + av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d\n", index + i, i); + } + } + av_log(ctx, AV_LOG_INFO, "AVFoundation audio devices:\n"); devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]; for (AVCaptureDevice *device in devices) { @@ -549,6 +570,9 @@ static int avf_read_header(AVFormatContext *s) AVCaptureDevice *video_device = nil; AVCaptureDevice *audio_device = nil; + NSArray *video_devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + ctx->num_video_devices = [video_devices count]; + // parse input filename for video and audio device parse_device_name(s); @@ -561,25 +585,39 @@ static int avf_read_header(AVFormatContext *s) } if (ctx->video_device_index >= 0) { - NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; - - if (ctx->video_device_index >= [devices count]) { + if (ctx->video_device_index < ctx->num_video_devices) { + video_device = [video_devices objectAtIndex:ctx->video_device_index]; + } else if (ctx->video_device_index < ctx->num_video_devices + num_screens) { + CGDirectDisplayID screens[num_screens]; + CGGetActiveDisplayList(num_screens, screens, &num_screens); + AVCaptureScreenInput* capture_screen_input = [[[AVCaptureScreenInput alloc] initWithDisplayID:screens[ctx->video_device_index - ctx->num_video_devices]] autorelease]; + video_device = (AVCaptureDevice*) capture_screen_input; + } else { av_log(ctx, AV_LOG_ERROR, "Invalid device index\n"); goto fail; } - - video_device = [devices objectAtIndex:ctx->video_device_index]; } else if (ctx->video_filename && strncmp(ctx->video_filename, "default", 7)) { - NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; - - for (AVCaptureDevice *device in devices) { + // looking for video inputs + for (AVCaptureDevice *device in video_devices) { if (!strncmp(ctx->video_filename, [[device localizedName] UTF8String], strlen(ctx->video_filename))) { video_device = device; break; } } + // looking for screen inputs + if (!video_device) { + int idx; + if(sscanf(ctx->video_filename, "Capture screen %d", &idx) && idx < num_screens) { + CGDirectDisplayID screens[num_screens]; + CGGetActiveDisplayList(num_screens, screens, &num_screens); + AVCaptureScreenInput* capture_screen_input = [[[AVCaptureScreenInput alloc] initWithDisplayID:screens[idx]] autorelease]; + video_device = (AVCaptureDevice*) capture_screen_input; + ctx->video_device_index = ctx->num_video_devices + idx; + } + } + if (!video_device) { av_log(ctx, AV_LOG_ERROR, "Video device not found\n"); goto fail; @@ -624,7 +662,11 @@ static int avf_read_header(AVFormatContext *s) } if (video_device) { - av_log(s, AV_LOG_DEBUG, "'%s' opened\n", [[video_device localizedName] UTF8String]); + if (ctx->video_device_index < ctx->num_video_devices) { + av_log(s, AV_LOG_DEBUG, "'%s' opened\n", [[video_device localizedName] UTF8String]); + } else { + av_log(s, AV_LOG_DEBUG, "'%s' opened\n", [[video_device description] UTF8String]); + } } if (audio_device) { av_log(s, AV_LOG_DEBUG, "audio device '%s' opened\n", [[audio_device localizedName] UTF8String]);