PR #23096 opened by toots
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23096
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23096.patch


>From 404407b54fe59f8cf5f395c4eecbde3063082d5d Mon Sep 17 00:00:00 2001
From: Romain Beauxis <[email protected]>
Date: Wed, 13 May 2026 08:18:49 -0400
Subject: [PATCH] avdevice/alsa: auto-detect channel layout when none is
 requested

---
 libavdevice/alsa.c     | 22 +++++++++++++++++++---
 libavdevice/alsa.h     |  5 +++--
 libavdevice/alsa_dec.c |  2 +-
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/libavdevice/alsa.c b/libavdevice/alsa.c
index 966eea519a..ac790013db 100644
--- a/libavdevice/alsa.c
+++ b/libavdevice/alsa.c
@@ -173,7 +173,7 @@ static av_cold int find_reorder_func(AlsaData *s, int 
codec_id,
 
 av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode,
                          unsigned int *sample_rate,
-                         const AVChannelLayout *layout, enum AVCodecID 
*codec_id)
+                         AVChannelLayout *layout, enum AVCodecID *codec_id)
 {
     AlsaData *s = ctx->priv_data;
     const char *audio_device;
@@ -193,8 +193,6 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, 
snd_pcm_stream_t mode,
         av_log(ctx, AV_LOG_ERROR, "sample format 0x%04x is not supported\n", 
*codec_id);
         return AVERROR(ENOSYS);
     }
-    s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * 
layout->nb_channels;
-
     if (ctx->flags & AVFMT_FLAG_NONBLOCK) {
         flags = SND_PCM_NONBLOCK;
     }
@@ -240,6 +238,22 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, 
snd_pcm_stream_t mode,
         goto fail;
     }
 
+    if (layout->nb_channels == 0) {
+        unsigned int channels = 2;
+        if (snd_pcm_hw_params_test_channels(h, hw_params, channels) < 0) {
+            res = snd_pcm_hw_params_get_channels_min(hw_params, &channels);
+            if (res < 0) {
+                av_log(ctx, AV_LOG_ERROR, "cannot get minimum channel count 
(%s)\n",
+                       snd_strerror(res));
+                goto fail;
+            }
+            av_log(ctx, AV_LOG_VERBOSE,
+                   "stereo not supported, falling back to %u channel(s)\n", 
channels);
+        }
+        av_channel_layout_uninit(layout);
+        av_channel_layout_default(layout, channels);
+    }
+
     res = snd_pcm_hw_params_set_channels(h, hw_params, layout->nb_channels);
     if (res < 0) {
         av_log(ctx, AV_LOG_ERROR, "cannot set channel count to %d (%s)\n",
@@ -247,6 +261,8 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, 
snd_pcm_stream_t mode,
         goto fail;
     }
 
+    s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * 
layout->nb_channels;
+
     snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size);
     buffer_size = FFMIN(buffer_size, ALSA_BUFFER_SIZE_MAX);
     /* TODO: maybe use ctx->max_picture_buffer somehow */
diff --git a/libavdevice/alsa.h b/libavdevice/alsa.h
index d3dfa478c5..ed2ac66e93 100644
--- a/libavdevice/alsa.h
+++ b/libavdevice/alsa.h
@@ -72,7 +72,8 @@ typedef struct AlsaData {
  * @param mode either SND_PCM_STREAM_CAPTURE or SND_PCM_STREAM_PLAYBACK
  * @param sample_rate in: requested sample rate;
  *                    out: actually selected sample rate
- * @param layout channel layout
+ * @param layout in: requested channel layout, or nb_channels=0 for 
auto-detect;
+ *               out: actually selected channel layout
  * @param codec_id in: requested AVCodecID or AV_CODEC_ID_NONE;
  *                 out: actually selected AVCodecID, changed only if
  *                 AV_CODEC_ID_NONE was requested
@@ -82,7 +83,7 @@ typedef struct AlsaData {
 av_warn_unused_result
 int ff_alsa_open(AVFormatContext *s, snd_pcm_stream_t mode,
                  unsigned int *sample_rate,
-                 const AVChannelLayout *layout, enum AVCodecID *codec_id);
+                 AVChannelLayout *layout, enum AVCodecID *codec_id);
 
 /**
  * Close the ALSA PCM.
diff --git a/libavdevice/alsa_dec.c b/libavdevice/alsa_dec.c
index 63409a7785..54d9b3a783 100644
--- a/libavdevice/alsa_dec.c
+++ b/libavdevice/alsa_dec.c
@@ -160,7 +160,7 @@ static const AVOption options[] = {
 #if FF_API_ALSA_CHANNELS
     { "channels",    "", offsetof(AlsaData, channels),    AV_OPT_TYPE_INT, 
{.i64 = 0},     0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_DEPRECATED 
},
 #endif
-    { "ch_layout",   "", offsetof(AlsaData, ch_layout),   
AV_OPT_TYPE_CHLAYOUT, {.str = "2C"}, INT_MIN, INT_MAX, 
AV_OPT_FLAG_DECODING_PARAM },
+    { "ch_layout",   "", offsetof(AlsaData, ch_layout),   
AV_OPT_TYPE_CHLAYOUT, {.str = NULL}, INT_MIN, INT_MAX, 
AV_OPT_FLAG_DECODING_PARAM },
     { NULL },
 };
 
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to