Add audio channel layout API to libavcodec.
authorPeter Ross <pross@xvid.org>
Sat, 1 Nov 2008 05:03:42 +0000 (05:03 +0000)
committerPeter Ross <pross@xvid.org>
Sat, 1 Nov 2008 05:03:42 +0000 (05:03 +0000)
Originally committed as revision 15762 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavcodec/audioconvert.c
libavcodec/audioconvert.h
libavcodec/avcodec.h
libavcodec/utils.c

index f6a22bf..9f147a1 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "avcodec.h"
 #include "audioconvert.h"
 
 #include "avcodec.h"
 #include "audioconvert.h"
+#include <libavutil/avstring.h>
 
 typedef struct SampleFmtInfo {
     const char *name;
 
 typedef struct SampleFmtInfo {
     const char *name;
@@ -70,6 +71,85 @@ void avcodec_sample_fmt_string (char *buf, int buf_size, int sample_fmt)
     }
 }
 
     }
 }
 
+static const char* const channel_names[]={
+    "FL", "FR", "FC", "LFE", "BL",  "BR",  "FLC", "FRC",
+    "BC", "SL", "SR", "TC",  "TFL", "TFC", "TFR", "TBL",
+    "TBC", "TBR",
+    [29] = "DL",
+    [30] = "DR",
+};
+
+const char *get_channel_name(int channel_id)
+{
+    if (channel_id<0 || channel_id>=FF_ARRAY_ELEMS(channel_names))
+        return NULL;
+    return channel_names[channel_id];
+}
+
+int64_t avcodec_guess_channel_layout(int nb_channels, enum CodecID codec_id, const char *fmt_name)
+{
+    switch(nb_channels) {
+    case 1: return CHANNEL_LAYOUT_MONO;
+    case 2: return CHANNEL_LAYOUT_STEREO;
+    case 3: return CHANNEL_LAYOUT_SURROUND;
+    case 4: return CHANNEL_LAYOUT_QUAD;
+    case 5: return CHANNEL_LAYOUT_5POINT0;
+    case 6: return CHANNEL_LAYOUT_5POINT1;
+    case 8: return CHANNEL_LAYOUT_7POINT1;
+    default: return 0;
+    }
+}
+
+static const struct {
+    const char *name;
+    int         nb_channels;
+    int64_t     layout;
+} const channel_layout_map[] = {
+    { "mono",        1,  CHANNEL_LAYOUT_MONO },
+    { "stereo",      2,  CHANNEL_LAYOUT_STEREO },
+    { "surround",    3,  CHANNEL_LAYOUT_SURROUND },
+    { "quad",        4,  CHANNEL_LAYOUT_QUAD },
+    { "5.0",         5,  CHANNEL_LAYOUT_5POINT0 },
+    { "5.1",         6,  CHANNEL_LAYOUT_5POINT1 },
+    { "5.1+downmix", 8,  CHANNEL_LAYOUT_5POINT1|CHANNEL_LAYOUT_STEREO_DOWNMIX, },
+    { "7.1",         8,  CHANNEL_LAYOUT_7POINT1 },
+    { "7.1(wide)",   8,  CHANNEL_LAYOUT_7POINT1_WIDE },
+    { "7.1+downmix", 10, CHANNEL_LAYOUT_7POINT1|CHANNEL_LAYOUT_STEREO_DOWNMIX, },
+    { 0 }
+};
+
+void avcodec_get_channel_layout_string(char *buf, int buf_size, int nb_channels, int64_t channel_layout)
+{
+    int i;
+
+    if (channel_layout==0)
+        channel_layout = avcodec_guess_channel_layout(nb_channels, CODEC_ID_NONE, NULL);
+
+    for (i=0; channel_layout_map[i].name; i++)
+        if (nb_channels    == channel_layout_map[i].nb_channels &&
+            channel_layout == channel_layout_map[i].layout) {
+            snprintf(buf, buf_size, channel_layout_map[i].name);
+            return;
+        }
+
+    snprintf(buf, buf_size, "%d channels", nb_channels);
+    if (channel_layout) {
+        int i,ch;
+        av_strlcat(buf, " (", buf_size);
+        for(i=0,ch=0; i<64; i++) {
+            if ((channel_layout & (1L<<i))) {
+                const char *name = get_channel_name(i);
+                if (name) {
+                    if (ch>0) av_strlcat(buf, "|", buf_size);
+                    av_strlcat(buf, name, buf_size);
+                }
+                ch++;
+            }
+        }
+        av_strlcat(buf, ")", buf_size);
+    }
+}
+
 struct AVAudioConvert {
     int in_channels, out_channels;
     int fmt_pair;
 struct AVAudioConvert {
     int in_channels, out_channels;
     int fmt_pair;
index c391759..4b76710 100644 (file)
@@ -54,6 +54,26 @@ const char *avcodec_get_sample_fmt_name(int sample_fmt);
  */
 enum SampleFormat avcodec_get_sample_fmt(const char* name);
 
  */
 enum SampleFormat avcodec_get_sample_fmt(const char* name);
 
+/**
+ * @return NULL on error
+ */
+const char *avcodec_get_channel_name(int channel_id);
+
+/**
+ * Return description of channel layout
+ */
+void avcodec_get_channel_layout_string(char *buf, int buf_size, int nb_channels, int64_t channel_layout);
+
+/**
+ * Guess the channel layout
+ * @param nb_channels
+ * @param codec_id Codec identifier, or CODEC_ID_NONE if unknown
+ * @param fmt_name Format name, or NULL if unknown
+ * @return Channel layout mask
+ */
+int64_t avcodec_guess_channel_layout(int nb_channels, enum CodecID codec_id, const char *fmt_name);
+
+
 struct AVAudioConvert;
 typedef struct AVAudioConvert AVAudioConvert;
 
 struct AVAudioConvert;
 typedef struct AVAudioConvert AVAudioConvert;
 
index 3be9402..cf6385f 100644 (file)
@@ -30,7 +30,7 @@
 #include "libavutil/avutil.h"
 
 #define LIBAVCODEC_VERSION_MAJOR 52
 #include "libavutil/avutil.h"
 
 #define LIBAVCODEC_VERSION_MAJOR 52
-#define LIBAVCODEC_VERSION_MINOR  1
+#define LIBAVCODEC_VERSION_MINOR  2
 #define LIBAVCODEC_VERSION_MICRO  0
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
 #define LIBAVCODEC_VERSION_MICRO  0
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
@@ -346,6 +346,41 @@ enum SampleFormat {
     SAMPLE_FMT_NB               ///< Number of sample formats. DO NOT USE if dynamically linking to libavcodec
 };
 
     SAMPLE_FMT_NB               ///< Number of sample formats. DO NOT USE if dynamically linking to libavcodec
 };
 
+/* Audio channel masks */
+#define CHANNEL_FRONT_LEFT             0x00000001
+#define CHANNEL_FRONT_RIGHT            0x00000002
+#define CHANNEL_FRONT_CENTER           0x00000004
+#define CHANNEL_LOW_FREQUENCY          0x00000008
+#define CHANNEL_BACK_LEFT              0x00000010
+#define CHANNEL_BACK_RIGHT             0x00000020
+#define CHANNEL_FRONT_LEFT_OF_CENTER   0x00000040
+#define CHANNEL_FRONT_RIGHT_OF_CENTER  0x00000080
+#define CHANNEL_BACK_CENTER            0x00000100
+#define CHANNEL_SIDE_LEFT              0x00000200
+#define CHANNEL_SIDE_RIGHT             0x00000400
+#define CHANNEL_TOP_CENTER             0x00000800
+#define CHANNEL_TOP_FRONT_LEFT         0x00001000
+#define CHANNEL_TOP_FRONT_CENTER       0x00002000
+#define CHANNEL_TOP_FRONT_RIGHT        0x00004000
+#define CHANNEL_TOP_BACK_LEFT          0x00008000
+#define CHANNEL_TOP_BACK_CENTER        0x00010000
+#define CHANNEL_TOP_BACK_RIGHT         0x00020000
+#define CHANNEL_STEREO_LEFT            0x20000000  ///< Stereo downmix.
+#define CHANNEL_STEREO_RIGHT           0x40000000  ///< See CHANNEL_STEREO_LEFT.
+
+/* Audio channel convenience macros */
+#define CHANNEL_LAYOUT_MONO              (CHANNEL_FRONT_CENTER)
+#define CHANNEL_LAYOUT_STEREO            (CHANNEL_FRONT_LEFT|CHANNEL_FRONT_RIGHT)
+#define CHANNEL_LAYOUT_SURROUND          (CHANNEL_LAYOUT_STEREO|CHANNEL_FRONT_CENTER)
+#define CHANNEL_LAYOUT_QUAD              (CHANNEL_LAYOUT_STEREO|CHANNEL_BACK_LEFT|CHANNEL_BACK_RIGHT)
+#define CHANNEL_LAYOUT_5POINT0           (CHANNEL_LAYOUT_SURROUND|CHANNEL_SIDE_LEFT|CHANNEL_SIDE_RIGHT)
+#define CHANNEL_LAYOUT_5POINT1           (CHANNEL_LAYOUT_5POINT0|CHANNEL_LOW_FREQUENCY)
+#define CHANNEL_LAYOUT_7POINT1           (CHANNEL_LAYOUT_5POINT1|CHANNEL_BACK_LEFT|CHANNEL_BACK_RIGHT)
+#define CHANNEL_LAYOUT_7POINT1_WIDE      (CHANNEL_LAYOUT_SURROUND|CHANNEL_LOW_FREQUENCY|\
+                                          CHANNEL_BACK_LEFT|CHANNEL_BACK_RIGHT|\
+                                          CHANNEL_FRONT_LEFT_OF_CENTER|CHANNEL_FRONT_RIGHT_OF_CENTER)
+#define CHANNEL_LAYOUT_STEREO_DOWNMIX    (CHANNEL_STEREO_LEFT|CHANNEL_STEREO_RIGHT)
+
 /* in bytes */
 #define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
 
 /* in bytes */
 #define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
 
@@ -2198,12 +2233,15 @@ typedef struct AVCodecContext {
      */
     int64_t timecode_frame_start;
 
      */
     int64_t timecode_frame_start;
 
+#if LIBAVCODEC_VERSION_MAJOR < 53
     /**
      * Decoder should decode to this many channels if it can (0 for default)
      * - encoding: unused
      * - decoding: Set by user.
     /**
      * Decoder should decode to this many channels if it can (0 for default)
      * - encoding: unused
      * - decoding: Set by user.
+     * @deprecated Deprecated in favor of request_channel_layout.
      */
     int request_channels;
      */
     int request_channels;
+#endif
 
     /**
      * Percentage of dynamic range compression to be applied by the decoder.
 
     /**
      * Percentage of dynamic range compression to be applied by the decoder.
@@ -2228,6 +2266,20 @@ typedef struct AVCodecContext {
      * - decoding: set by libavcodec.
      */
     int bits_per_raw_sample;
      * - decoding: set by libavcodec.
      */
     int bits_per_raw_sample;
+
+    /**
+     * Audio channel layout.
+     * - encoding: set by user.
+     * - decoding: set by libavcodec.
+     */
+    int64_t channel_layout;
+
+    /**
+     * Request decoder to use this channel layout if it can (0 for default)
+     * - encoding: unused
+     * - decoding: Set by user.
+     */
+    int64_t request_channel_layout;
 } AVCodecContext;
 
 /**
 } AVCodecContext;
 
 /**
@@ -2269,6 +2321,7 @@ typedef struct AVCodec {
     const char *long_name;
     const int *supported_samplerates;       ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0
     const enum SampleFormat *sample_fmts;   ///< array of supported sample formats, or NULL if unknown, array is terminated by -1
     const char *long_name;
     const int *supported_samplerates;       ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0
     const enum SampleFormat *sample_fmts;   ///< array of supported sample formats, or NULL if unknown, array is terminated by -1
+    const int64_t *channel_layouts;         ///< array of support channel layouts, or NULL if unknown. array is terminated by 0
 } AVCodec;
 
 /**
 } AVCodec;
 
 /**
index 5df4d18..9f60a79 100644 (file)
@@ -740,6 +740,8 @@ static const AVOption options[]={
 {"drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), FF_OPT_TYPE_FLOAT, 1.0, 0.0, 1.0, A|D},
 {"reservoir", "use bit reservoir", 0, FF_OPT_TYPE_CONST, CODEC_FLAG2_BIT_RESERVOIR, INT_MIN, INT_MAX, A|E, "flags2"},
 {"bits_per_raw_sample", NULL, OFFSET(bits_per_raw_sample), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX},
 {"drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), FF_OPT_TYPE_FLOAT, 1.0, 0.0, 1.0, A|D},
 {"reservoir", "use bit reservoir", 0, FF_OPT_TYPE_CONST, CODEC_FLAG2_BIT_RESERVOIR, INT_MIN, INT_MAX, A|E, "flags2"},
 {"bits_per_raw_sample", NULL, OFFSET(bits_per_raw_sample), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX},
+{"channel_layout", NULL, OFFSET(channel_layout), FF_OPT_TYPE_INT64, DEFAULT, 0, INT64_MAX, A|E|D, "channel_layout"},
+{"request_channel_layout", NULL, OFFSET(request_channel_layout), FF_OPT_TYPE_INT64, DEFAULT, 0, INT64_MAX, A|D, "request_channel_layout"},
 {NULL},
 };
 
 {NULL},
 };
 
@@ -1051,7 +1053,6 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
     const char *codec_name;
     AVCodec *p;
     char buf1[32];
     const char *codec_name;
     AVCodec *p;
     char buf1[32];
-    char channels_str[100];
     int bitrate;
     AVRational display_aspect_ratio;
 
     int bitrate;
     AVRational display_aspect_ratio;
 
@@ -1131,26 +1132,12 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
         snprintf(buf, buf_size,
                  "Audio: %s",
                  codec_name);
         snprintf(buf, buf_size,
                  "Audio: %s",
                  codec_name);
-        switch (enc->channels) {
-            case 1:
-                strcpy(channels_str, "mono");
-                break;
-            case 2:
-                strcpy(channels_str, "stereo");
-                break;
-            case 6:
-                strcpy(channels_str, "5:1");
-                break;
-            default:
-                snprintf(channels_str, sizeof(channels_str), "%d channels", enc->channels);
-                break;
-        }
         if (enc->sample_rate) {
             snprintf(buf + strlen(buf), buf_size - strlen(buf),
         if (enc->sample_rate) {
             snprintf(buf + strlen(buf), buf_size - strlen(buf),
-                     ", %d Hz, %s",
-                     enc->sample_rate,
-                     channels_str);
+                     ", %d Hz", enc->sample_rate);
         }
         }
+        av_strlcat(buf, ", ", buf_size);
+        avcodec_get_channel_layout_string(buf + strlen(buf), buf_size - strlen(buf), enc->channels, enc->channel_layout);
         if (enc->sample_fmt != SAMPLE_FMT_NONE) {
             snprintf(buf + strlen(buf), buf_size - strlen(buf),
                      ", %s", avcodec_get_sample_fmt_name(enc->sample_fmt));
         if (enc->sample_fmt != SAMPLE_FMT_NONE) {
             snprintf(buf + strlen(buf), buf_size - strlen(buf),
                      ", %s", avcodec_get_sample_fmt_name(enc->sample_fmt));