[FFmpeg-devel] [PATCH 3/3] lavd/oss: implement surround playback.

Nicolas George nicolas.george at normalesup.org
Thu Nov 22 19:13:59 CET 2012


Alter frame_size to contain an integer number of samples.
Implement channels reordering for playback
(and partially for capture, untested).

Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
---
 libavdevice/oss_audio.c |   48 ++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 39 insertions(+), 9 deletions(-)

diff --git a/libavdevice/oss_audio.c b/libavdevice/oss_audio.c
index aa40034..1705619 100644
--- a/libavdevice/oss_audio.c
+++ b/libavdevice/oss_audio.c
@@ -34,6 +34,7 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 
+#include "libavutil/channels_reorder.h"
 #include "libavutil/log.h"
 #include "libavutil/opt.h"
 #include "libavutil/time.h"
@@ -49,9 +50,11 @@ typedef struct {
     int sample_rate;
     int channels;
     int frame_size; /* in bytes ! */
+    int bytes_per_sample;
     enum AVCodecID codec_id;
     unsigned int flip_left : 1;
     uint8_t buffer[AUDIO_BLOCK_SIZE];
+    AVChannelsReorderFunc reorder_func;
     int buffer_ptr;
 } AudioData;
 
@@ -61,6 +64,8 @@ static int audio_open(AVFormatContext *s1, int is_output, const char *audio_devi
     int audio_fd;
     int tmp, err;
     char *flip = getenv("AUDIO_FLIP_LEFT");
+    enum AVSampleFormat sample_format;
+    int64_t channel_layout = s1->streams[0]->codec->channel_layout;
 
     if (is_output)
         audio_fd = open(audio_device, O_WRONLY);
@@ -82,8 +87,6 @@ static int audio_open(AVFormatContext *s1, int is_output, const char *audio_devi
         }
     }
 
-    s->frame_size = AUDIO_BLOCK_SIZE;
-
     /* select format : favour native format */
     err = ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &tmp);
 
@@ -117,16 +120,19 @@ static int audio_open(AVFormatContext *s1, int is_output, const char *audio_devi
         close(audio_fd);
         return AVERROR(EIO);
     }
+    sample_format = AV_SAMPLE_FMT_S16;
+    s->bytes_per_sample = 2 * s->channels;
+
     err=ioctl(audio_fd, SNDCTL_DSP_SETFMT, &tmp);
     if (err < 0) {
         av_log(s1, AV_LOG_ERROR, "SNDCTL_DSP_SETFMT: %s\n", strerror(errno));
         goto fail;
     }
 
-    tmp = (s->channels == 2);
-    err = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
+    tmp = s->channels;
+    err = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &tmp);
     if (err < 0) {
-        av_log(s1, AV_LOG_ERROR, "SNDCTL_DSP_STEREO: %s\n", strerror(errno));
+        av_log(s1, AV_LOG_ERROR, "SNDCTL_DSP_CHANNELS: %s\n", strerror(errno));
         goto fail;
     }
 
@@ -139,6 +145,25 @@ static int audio_open(AVFormatContext *s1, int is_output, const char *audio_devi
     s->sample_rate = tmp; /* store real sample rate */
     s->fd = audio_fd;
 
+    s->frame_size = AUDIO_BLOCK_SIZE - AUDIO_BLOCK_SIZE % s->bytes_per_sample;
+    if (s->channels > 2) {
+        err = av_get_channels_reorder_func(&s->reorder_func, sample_format,
+                                           s->channels, channel_layout,
+                                           AV_CH_ORDER_INTERNAL,
+                                           AV_CH_ORDER_ALSA, 0);
+        if (err < 0) {
+            char name[128];
+            av_get_channel_layout_string(name, sizeof(name),
+                                         s->channels, channel_layout);
+            av_log(s1, AV_LOG_WARNING,
+                   "OSS channel layout unknown or unimplemented for %s %s.\n",
+                   name, is_output ? "playback" : "capture");
+        }
+        if (s->reorder_func && !is_output)
+            av_log(s1, AV_LOG_WARNING,
+                   "Channels reordering not implemented for capture\n");
+    }
+
     return 0;
  fail:
     close(audio_fd);
@@ -177,12 +202,17 @@ static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt)
     uint8_t *buf= pkt->data;
 
     while (size > 0) {
-        len = FFMIN(AUDIO_BLOCK_SIZE - s->buffer_ptr, size);
-        memcpy(s->buffer + s->buffer_ptr, buf, len);
+        len = FFMIN(s->frame_size - s->buffer_ptr, size);
+        if (s->reorder_func) {
+            uint8_t *dst = s->buffer + s->buffer_ptr;
+            s->reorder_func(&dst, &buf, len / s->bytes_per_sample);
+        } else {
+            memcpy(s->buffer + s->buffer_ptr, buf, len);
+        }
         s->buffer_ptr += len;
-        if (s->buffer_ptr >= AUDIO_BLOCK_SIZE) {
+        if (s->buffer_ptr >= s->frame_size) {
             for(;;) {
-                ret = write(s->fd, s->buffer, AUDIO_BLOCK_SIZE);
+                ret = write(s->fd, s->buffer, s->frame_size);
                 if (ret > 0)
                     break;
                 if (ret < 0 && (errno != EAGAIN && errno != EINTR))
-- 
1.7.10.4



More information about the ffmpeg-devel mailing list