From 735e26a0f525d94a31db56d4a25a3d15d021cca6 Mon Sep 17 00:00:00 2001 From: Thilo Borgmann <thilo.borgm...@mail.de> Date: Tue, 24 Nov 2015 19:01:55 +0100 Subject: [PATCH 2/3] lavd/avfoundation: Allow selection of audio format and list audio formats for specific devices.
--- libavdevice/avfoundation.m | 150 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 115 insertions(+), 35 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 37f6be0..20341ef 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -95,10 +95,12 @@ typedef struct int capture_mouse_clicks; int list_devices; + int list_audio_formats; int video_device_index; int video_stream_index; int audio_device_index; int audio_stream_index; + int audio_format_index; char *video_filename; char *audio_filename; @@ -109,11 +111,6 @@ typedef struct int audio_channels; int audio_bits_per_sample; - int audio_float; - int audio_be; - int audio_signed_integer; - int audio_packed; - int audio_non_interleaved; int32_t *audio_buffer; int audio_buffer_size; @@ -259,7 +256,7 @@ static int configure_video_device(AVFormatContext *s, AVCaptureDevice *video_dev [video_device setValue:min_frame_duration forKey:@"activeVideoMinFrameDuration"]; [video_device setValue:min_frame_duration forKey:@"activeVideoMaxFrameDuration"]; } else { - av_log(s, AV_LOG_ERROR, "Could not lock device for configuration"); + av_log(s, AV_LOG_ERROR, "Could not lock video device for configuration"); return AVERROR(EINVAL); } @@ -333,8 +330,24 @@ static int add_video_device(AVFormatContext *s, AVCaptureDevice *video_device) } } @catch (NSException *exception) { if (![[exception name] isEqualToString:NSUndefinedKeyException]) { - av_log (s, AV_LOG_ERROR, "An error occurred: %s", [exception.reason UTF8String]); - return AVERROR_EXTERNAL; + av_log (s, AV_LOG_ERROR, "An error occurred: %s", [exception.reason UTF8String]); + return AVERROR_EXTERNAL; + } else { + // AVCaptureScreenInput does not contain formats property + // get the screen dimensions using CoreGraphics and display id +#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + uint32_t num_screens = 0; + CGGetActiveDisplayList(0, NULL, &num_screens); + if (ctx->video_device_index < ctx->num_video_devices + num_screens) { + CGDirectDisplayID screens[num_screens]; + CGGetActiveDisplayList(num_screens, screens, &num_screens); + int screen_idx = ctx->video_device_index - ctx->num_video_devices; + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(screens[screen_idx]); + ctx->width = CGDisplayModeGetWidth(mode); + ctx->height = CGDisplayModeGetHeight(mode); + CFRelease(mode); + } +#endif } } @@ -440,6 +453,12 @@ static int add_audio_device(AVFormatContext *s, AVCaptureDevice *audio_device) [ctx->audio_output setSampleBufferDelegate:ctx->avf_delegate queue:ctx->dispatch_queue]; + if ([audio_device lockForConfiguration:NULL] == YES) { + audio_device.activeFormat = ctx->audio_format; + } else { + av_log(s, AV_LOG_ERROR, "Could not lock audio device for configuration"); + return AVERROR(EINVAL); + } if ([ctx->capture_session canAddOutput:ctx->audio_output]) { [ctx->capture_session addOutput:ctx->audio_output]; @@ -570,17 +589,15 @@ static int avf_read_header(AVFormatContext *s) AVFContext *ctx = (AVFContext*)s->priv_data; AVCaptureDevice *video_device = nil; AVCaptureDevice *audio_device = nil; - // Find capture device - NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; - ctx->num_video_devices = [devices count]; - ctx->first_pts = av_gettime(); - ctx->first_audio_pts = av_gettime(); // Create dispatch queue and set delegate CMBufferQueueCreate(kCFAllocatorDefault, 0, CMBufferQueueGetCallbacksForSampleBuffersSortedByOutputPTS(), &ctx->frame_buffer); ctx->avf_delegate = [[AVFFrameReceiver alloc] initWithContext:ctx]; ctx->dispatch_queue = dispatch_queue_create("org.ffmpeg.dispatch_queue", NULL); + // Query video devices + NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + ctx->num_video_devices = [devices count]; #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 CGGetActiveDisplayList(0, NULL, &num_screens); @@ -661,21 +678,19 @@ static int avf_read_header(AVFormatContext *s) av_log(ctx, AV_LOG_ERROR, "Invalid device index\n"); goto fail; } - } else if (ctx->video_filename && - strncmp(ctx->video_filename, "none", 4)) { + } else if (ctx->video_filename && strncmp(ctx->video_filename, "none", 4)) { //select video device by name if (!strncmp(ctx->video_filename, "default", 7)) { - video_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + video_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; // XXX set device index } else { - // looking for video inputs - for (AVCaptureDevice *device in devices) { - if (!strncmp(ctx->video_filename, [[device localizedName] UTF8String], strlen(ctx->video_filename))) { - video_device = device; - break; - } + for (AVCaptureDevice *device in devices) { + if (!strncmp(ctx->video_filename, [[device localizedName] UTF8String], strlen(ctx->video_filename))) { + video_device = device; // XXX set device index + break; + } } #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 - // looking for screen inputs + // select video device for capture screen inputs if (!video_device) { int idx; if(sscanf(ctx->video_filename, "Capture screen %d", &idx) && idx < num_screens) { @@ -724,20 +739,20 @@ static int avf_read_header(AVFormatContext *s) } audio_device = [devices objectAtIndex:ctx->audio_device_index]; - } else if (ctx->audio_filename && + } else if (ctx->audio_filename && // select audio device by name strncmp(ctx->audio_filename, "none", 4)) { if (!strncmp(ctx->audio_filename, "default", 7)) { - audio_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; + audio_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; // XXX set device index } else { - NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]; + NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]; - for (AVCaptureDevice *device in devices) { - if (!strncmp(ctx->audio_filename, [[device localizedName] UTF8String], strlen(ctx->audio_filename))) { - audio_device = device; - break; + for (AVCaptureDevice *device in devices) { + if (!strncmp(ctx->audio_filename, [[device localizedName] UTF8String], strlen(ctx->audio_filename))) { + audio_device = device; // XXX set device index + break; + } } } - } if (!audio_device) { av_log(ctx, AV_LOG_ERROR, "Audio device not found\n"); @@ -745,7 +760,62 @@ static int avf_read_header(AVFormatContext *s) } } - // Video nor Audio capture device not found, looking for AVMediaTypeVideo/Audio + // list all audio formats if requested + if (ctx->list_audio_formats) { + int idx = 0; + for (AVCaptureDeviceFormat *format in audio_device.formats) { + if (get_audio_codec_id(format) != AV_CODEC_ID_NONE) { + AudioStreamBasicDescription *audio_format_desc = (AudioStreamBasicDescription*)CMAudioFormatDescriptionGetStreamBasicDescription(format.formatDescription); + av_log(ctx, AV_LOG_INFO, "Format %d:\n", idx++); + av_log(ctx, AV_LOG_INFO, "\tsample rate = %f\n", audio_format_desc->mSampleRate); + av_log(ctx, AV_LOG_INFO, "\tchannels = %d\n", audio_format_desc->mChannelsPerFrame); + av_log(ctx, AV_LOG_INFO, "\tbits per sample = %d\n", audio_format_desc->mBitsPerChannel); + av_log(ctx, AV_LOG_INFO, "\tfloat = %d\n", (bool)(audio_format_desc->mFormatFlags & kAudioFormatFlagIsFloat)); + av_log(ctx, AV_LOG_INFO, "\tbig endian = %d\n", (bool)(audio_format_desc->mFormatFlags & kAudioFormatFlagIsBigEndian)); + av_log(ctx, AV_LOG_INFO, "\tsigned integer = %d\n", (bool)(audio_format_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger)); + av_log(ctx, AV_LOG_INFO, "\tpacked = %d\n", (bool)(audio_format_desc->mFormatFlags & kAudioFormatFlagIsPacked)); + av_log(ctx, AV_LOG_INFO, "\tnon interleaved = %d\n", (bool)(audio_format_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved)); + } else { + av_log(ctx, AV_LOG_INFO, "Format %d: (unsupported)\n", idx++); + } + + } + + goto fail; + } + + // select audio format + if (ctx->audio_format_index >= 0) { + if (ctx->audio_format_index >= [audio_device.formats count]) { + av_log(ctx, AV_LOG_ERROR, "Invalid audio format index\n"); + goto fail; + } + + ctx->audio_format = [audio_device.formats objectAtIndex:ctx->audio_format_index]; + if (get_audio_codec_id(ctx->audio_format) == AV_CODEC_ID_NONE) { + av_log(ctx, AV_LOG_ERROR, "Unsupported audio format index\n"); + goto fail; + } + } else if (audio_device) { + int idx = 0; + + for (AVCaptureDeviceFormat *format in audio_device.formats) { + if (get_audio_codec_id(format) != AV_CODEC_ID_NONE) { + ctx->audio_format = format; + ctx->audio_format_index = idx; + break; + } + + idx++; + } + + if (!ctx->audio_format) { + av_log(ctx, AV_LOG_ERROR, "No supported audio format found\n"); + goto fail; + } + } + + // neither video nor audio capture device not found while looking for AVMediaTypeVideo/Audio if (!video_device && !audio_device) { av_log(s, AV_LOG_ERROR, "No AV capture device found\n"); goto fail; @@ -762,23 +832,29 @@ static int avf_read_header(AVFormatContext *s) av_log(s, AV_LOG_DEBUG, "audio device '%s' opened\n", [[audio_device localizedName] UTF8String]); } - // Initialize capture session + // initialize capture session ctx->capture_session = [[AVCaptureSession alloc] init]; if (video_device && add_video_device(s, video_device)) { goto fail; } if (audio_device && add_audio_device(s, audio_device)) { + goto fail; } + // start capture session [ctx->capture_session startRunning]; - /* Unlock device configuration only after the session is started so it - * does not reset the capture formats */ + // unlock device configuration only after the session is started so it + // does not reset the capture formats if (!capture_screen) { [video_device unlockForConfiguration]; } + if (audio_device) { + [audio_device unlockForConfiguration]; + } + if (video_device && get_video_config(s)) { goto fail; } @@ -965,8 +1041,12 @@ static const AVOption options[] = { { "list_devices", "list available devices", offsetof(AVFContext, list_devices), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM, "list_devices" }, { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" }, { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" }, + { "list_audio_formats", "list available audio formats", offsetof(AVFContext, list_audio_formats), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM, "list_audio_formats" }, + { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_audio_formats" }, + { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_audio_formats" }, { "video_device_index", "select video device by index for devices with same name (starts at 0)", offsetof(AVFContext, video_device_index), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, { "audio_device_index", "select audio device by index for devices with same name (starts at 0)", offsetof(AVFContext, audio_device_index), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, + { "audio_format_index", "select audio format by index (starts at 0)", offsetof(AVFContext, audio_format_index), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, { "pixel_format", "set pixel format", offsetof(AVFContext, pixel_format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_YUV420P}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM}, { "framerate", "set frame rate", offsetof(AVFContext, framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "ntsc"}, 0, 0, AV_OPT_FLAG_DECODING_PARAM }, { "video_size", "set video size", offsetof(AVFContext, width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM }, -- 2.3.2 (Apple Git-55)
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel