[FFmpeg-devel] [PATCH v2 2/2] libavdevice/avfoundation: add option to set audio sample rate and use native device formats
mindmark at gmail.com
mindmark at gmail.com
Mon Apr 12 05:31:42 EEST 2021
From: Mark Reid <mindmark at gmail.com>
This also seems to prevent the audio format changing after format has been identified.
This can happen in ffplay and might have something to do with sdl configuring the audio devices.
---
libavdevice/avfoundation.m | 123 ++++++++++++++++++++++++++++---------
1 file changed, 94 insertions(+), 29 deletions(-)
diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m
index 5ac6ec4183..70226cfdc8 100644
--- a/libavdevice/avfoundation.m
+++ b/libavdevice/avfoundation.m
@@ -118,11 +118,8 @@ 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;
+ int audio_sample_rate;
int32_t *audio_buffer;
int audio_buffer_size;
@@ -632,12 +629,47 @@ static int add_video_device(AVFormatContext *s, AVCaptureDevice *video_device)
return 0;
}
+static enum AVCodecID find_audio_codec_id(const AudioStreamBasicDescription *basic_desc)
+{
+ int audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat;
+ int audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger;
+ int audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian;
+ int audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacked;
+ int audio_bits_per_sample = basic_desc->mBitsPerChannel;
+
+ if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
+ audio_float &&
+ audio_bits_per_sample == 32 &&
+ audio_packed) {
+ return audio_be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE;
+ } else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
+ audio_signed_integer &&
+ audio_bits_per_sample == 16 &&
+ audio_packed) {
+ return audio_be ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE;
+ } else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
+ audio_signed_integer &&
+ audio_bits_per_sample == 24 &&
+ audio_packed) {
+ return audio_be ? AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE;
+ } else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
+ audio_signed_integer &&
+ audio_bits_per_sample == 32 &&
+ audio_packed) {
+ return audio_be ? AV_CODEC_ID_PCM_S32BE : AV_CODEC_ID_PCM_S32LE;
+ } else {
+ return AV_CODEC_ID_NONE;
+ }
+}
+
static int add_audio_device(AVFormatContext *s, AVCaptureDevice *audio_device)
{
AVFContext *ctx = (AVFContext*)s->priv_data;
NSError *error = nil;
AVCaptureDeviceInput* audio_dev_input = [[[AVCaptureDeviceInput alloc] initWithDevice:audio_device error:&error] autorelease];
dispatch_queue_t queue;
+ NSObject *format = nil;
+ const AudioStreamBasicDescription *format_desc = NULL;
if (!audio_dev_input) {
av_log(s, AV_LOG_ERROR, "Failed to create AV capture input device: %s\n",
@@ -660,6 +692,61 @@ static int add_audio_device(AVFormatContext *s, AVCaptureDevice *audio_device)
return 1;
}
+#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+
+ for (format in [audio_device valueForKey:@"formats"]) {
+ CMFormatDescriptionRef formatDescription;
+ formatDescription = (CMFormatDescriptionRef) [format performSelector:@selector(formatDescription)];
+ const AudioStreamBasicDescription *desc = CMAudioFormatDescriptionGetStreamBasicDescription(formatDescription);
+
+ if (desc->mSampleRate == ctx->audio_sample_rate) {
+ format_desc = desc;
+ break;
+ }
+ }
+
+ if(!format_desc) {
+ av_log(s, AV_LOG_ERROR, "Selected audio sample rate (%d Hz) is not supported\n", ctx->audio_sample_rate);
+ av_log(s, AV_LOG_ERROR, "Supported audio formats:\n");
+ for (format in [audio_device valueForKey:@"formats"]) {
+ const char *codec_name;
+ CMFormatDescriptionRef formatDescription;
+ formatDescription = (CMFormatDescriptionRef) [format performSelector:@selector(formatDescription)];
+ const AudioStreamBasicDescription *desc = CMAudioFormatDescriptionGetStreamBasicDescription(formatDescription);
+
+ enum AVCodecID codec_id = find_audio_codec_id(desc);
+ if (codec_id == AV_CODEC_ID_NONE) {
+ continue;
+ }
+
+ codec_name = avcodec_get_name(codec_id);
+ av_log(s, AV_LOG_ERROR, " %s, %d ch, %0.0f Hz \n", codec_name, desc->mChannelsPerFrame, desc->mSampleRate);
+ }
+
+ format_desc = CMAudioFormatDescriptionGetStreamBasicDescription(audio_device.activeFormat.formatDescription);
+ if (format_desc)
+ av_log(s, AV_LOG_WARNING, "Overriding selected sample rate with active sample rate: %0.0f Hz instead\n", format_desc->mSampleRate);
+ }
+
+ if (format_desc) {
+ int is_float = format_desc->mFormatFlags & kAudioFormatFlagIsFloat;
+ int audio_non_interleaved = format_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved;
+ int audio_be = format_desc->mFormatFlags & kAudioFormatFlagIsBigEndian;
+
+ NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithUnsignedInt:kAudioFormatLinearPCM], AVFormatIDKey,
+ [NSNumber numberWithFloat:format_desc->mSampleRate], AVSampleRateKey,
+ [NSNumber numberWithUnsignedInteger:format_desc->mChannelsPerFrame], AVNumberOfChannelsKey,
+ [NSNumber numberWithInt:format_desc->mBitsPerChannel], AVLinearPCMBitDepthKey,
+ [NSNumber numberWithBool:is_float], AVLinearPCMIsFloatKey,
+ [NSNumber numberWithBool:audio_non_interleaved], AVLinearPCMIsNonInterleaved,
+ [NSNumber numberWithBool:audio_be], AVLinearPCMIsBigEndianKey,
+ nil];
+
+ ctx->audio_output.audioSettings = settings;
+ }
+#endif
+
ctx->avf_audio_delegate = [[AVFAudioReceiver alloc] initWithContext:ctx];
queue = dispatch_queue_create("avf_audio_queue", NULL);
@@ -769,33 +856,10 @@ static int get_audio_config(AVFormatContext *s)
ctx->audio_channels = basic_desc->mChannelsPerFrame;
ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel;
- ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat;
- ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian;
- ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger;
- ctx->audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacked;
ctx->audio_non_interleaved = basic_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved;
- if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
- ctx->audio_float &&
- ctx->audio_bits_per_sample == 32 &&
- ctx->audio_packed) {
- stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE;
- } else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
- ctx->audio_signed_integer &&
- ctx->audio_bits_per_sample == 16 &&
- ctx->audio_packed) {
- stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE;
- } else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
- ctx->audio_signed_integer &&
- ctx->audio_bits_per_sample == 24 &&
- ctx->audio_packed) {
- stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE;
- } else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
- ctx->audio_signed_integer &&
- ctx->audio_bits_per_sample == 32 &&
- ctx->audio_packed) {
- stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_S32BE : AV_CODEC_ID_PCM_S32LE;
- } else {
+ stream->codecpar->codec_id = find_audio_codec_id(basic_desc);
+ if (stream->codecpar->codec_id == AV_CODEC_ID_NONE) {
av_log(s, AV_LOG_ERROR, "audio format is not supported\n");
return 1;
}
@@ -1286,6 +1350,7 @@ static const AVOption options[] = {
{ "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, INT_MAX, 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 },
+ { "audio_sample_rate", "set audio sample rate in Hz", offsetof(AVFContext, audio_sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
{ "capture_cursor", "capture the screen cursor", offsetof(AVFContext, capture_cursor), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
{ "capture_mouse_clicks", "capture the screen mouse clicks", offsetof(AVFContext, capture_mouse_clicks), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
{ "capture_raw_data", "capture the raw data from device connection", offsetof(AVFContext, capture_raw_data), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
--
2.29.2
More information about the ffmpeg-devel
mailing list