From 0d72e7d0aebb03db1010d3e3180b287f3d9fc581 Mon Sep 17 00:00:00 2001 From: Peter Ross Date: Sat, 1 Nov 2008 05:03:42 +0000 Subject: [PATCH] Add audio channel layout API to libavcodec. Originally committed as revision 15762 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/audioconvert.c | 80 +++++++++++++++++++++++++++++++++++++++ libavcodec/audioconvert.h | 20 ++++++++++ libavcodec/avcodec.h | 55 ++++++++++++++++++++++++++- libavcodec/utils.c | 23 +++-------- 4 files changed, 159 insertions(+), 19 deletions(-) diff --git a/libavcodec/audioconvert.c b/libavcodec/audioconvert.c index f6a22bf0a4..9f147a17ba 100644 --- a/libavcodec/audioconvert.c +++ b/libavcodec/audioconvert.c @@ -27,6 +27,7 @@ #include "avcodec.h" #include "audioconvert.h" +#include 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<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; diff --git a/libavcodec/audioconvert.h b/libavcodec/audioconvert.h index c391759ebe..4b767101a4 100644 --- a/libavcodec/audioconvert.h +++ b/libavcodec/audioconvert.h @@ -54,6 +54,26 @@ const char *avcodec_get_sample_fmt_name(int sample_fmt); */ 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; diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 3be94023a1..cf6385fbf6 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -30,7 +30,7 @@ #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, \ @@ -346,6 +346,41 @@ enum SampleFormat { 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 @@ -2198,12 +2233,15 @@ typedef struct AVCodecContext { */ 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. + * @deprecated Deprecated in favor of request_channel_layout. */ int request_channels; +#endif /** * 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; + + /** + * 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; /** @@ -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 int64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0 } AVCodec; /** diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 5df4d18b6b..9f60a79e94 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -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}, +{"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}, }; @@ -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]; - char channels_str[100]; 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); - 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), - ", %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)); -- GitLab