[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