[FFmpeg-devel] [PATCH 2/3] lavd/avfoundation: Allow selection of audio format and list audio formats for specific devices.
Thilo Borgmann
thilo.borgmann at mail.de
Tue Nov 24 19:31:55 CET 2015
-------------- next part --------------
From 735e26a0f525d94a31db56d4a25a3d15d021cca6 Mon Sep 17 00:00:00 2001
From: Thilo Borgmann <thilo.borgmann at 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)
More information about the ffmpeg-devel
mailing list