audioconvert.c 8.44 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
 * @file
 * audio conversion routines
 */

26 27
#include "avstring.h"
#include "avutil.h"
28
#include "audioconvert.h"
29
#include "bprint.h"
30
#include "common.h"
31

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
struct channel_name {
    const char *name;
    const char *description;
};

static const struct channel_name channel_names[] = {
     [0] = { "FL",        "front left"            },
     [1] = { "FR",        "front right"           },
     [2] = { "FC",        "front center"          },
     [3] = { "LFE",       "low frequency"         },
     [4] = { "BL",        "back left"             },
     [5] = { "BR",        "back right"            },
     [6] = { "FLC",       "front left-of-center"  },
     [7] = { "FRC",       "front right-of-center" },
     [8] = { "BC",        "back center"           },
     [9] = { "SL",        "side left"             },
    [10] = { "SR",        "side right"            },
    [11] = { "TC",        "top center"            },
    [12] = { "TFL",       "top front left"        },
    [13] = { "TFC",       "top front center"      },
    [14] = { "TFR",       "top front right"       },
    [15] = { "TBL",       "top back left"         },
    [16] = { "TBC",       "top back center"       },
    [17] = { "TBR",       "top back right"        },
    [29] = { "DL",        "downmix left"          },
    [30] = { "DR",        "downmix right"         },
    [31] = { "WL",        "wide left"             },
    [32] = { "WR",        "wide right"            },
    [33] = { "SDL",       "surround direct left"  },
    [34] = { "SDR",       "surround direct right" },
62 63 64 65 66 67
};

static const char *get_channel_name(int channel_id)
{
    if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names))
        return NULL;
68
    return channel_names[channel_id].name;
69 70 71 72 73
}

static const struct {
    const char *name;
    int         nb_channels;
74
    uint64_t     layout;
75 76 77
} channel_layout_map[] = {
    { "mono",        1,  AV_CH_LAYOUT_MONO },
    { "stereo",      2,  AV_CH_LAYOUT_STEREO },
78
    { "2.1",         3,  AV_CH_LAYOUT_2POINT1 },
79 80
    { "3.0",         3,  AV_CH_LAYOUT_SURROUND },
    { "3.0(back)",   3,  AV_CH_LAYOUT_2_1 },
81 82
    { "4.0",         4,  AV_CH_LAYOUT_4POINT0 },
    { "quad",        4,  AV_CH_LAYOUT_QUAD },
83
    { "quad(side)",  4,  AV_CH_LAYOUT_2_2 },
84
    { "3.1",         4,  AV_CH_LAYOUT_3POINT1 },
85
    { "5.0",         5,  AV_CH_LAYOUT_5POINT0_BACK },
86
    { "5.0(side)",   5,  AV_CH_LAYOUT_5POINT0 },
87
    { "4.1",         5,  AV_CH_LAYOUT_4POINT1 },
88
    { "5.1",         6,  AV_CH_LAYOUT_5POINT1_BACK },
89
    { "5.1(side)",   6,  AV_CH_LAYOUT_5POINT1 },
90 91 92 93 94 95 96 97
    { "6.0",         6,  AV_CH_LAYOUT_6POINT0 },
    { "6.0(front)",  6,  AV_CH_LAYOUT_6POINT0_FRONT },
    { "hexagonal",   6,  AV_CH_LAYOUT_HEXAGONAL },
    { "6.1",         7,  AV_CH_LAYOUT_6POINT1 },
    { "6.1",         7,  AV_CH_LAYOUT_6POINT1_BACK },
    { "6.1(front)",  7,  AV_CH_LAYOUT_6POINT1_FRONT },
    { "7.0",         7,  AV_CH_LAYOUT_7POINT0 },
    { "7.0(front)",  7,  AV_CH_LAYOUT_7POINT0_FRONT },
98 99
    { "7.1",         8,  AV_CH_LAYOUT_7POINT1 },
    { "7.1(wide)",   8,  AV_CH_LAYOUT_7POINT1_WIDE },
100
    { "octagonal",   8,  AV_CH_LAYOUT_OCTAGONAL },
101
    { "downmix",     2,  AV_CH_LAYOUT_STEREO_DOWNMIX, },
102 103
};

104
static uint64_t get_channel_layout_single(const char *name, int name_len)
105
{
106 107 108
    int i;
    char *end;
    int64_t layout;
109

110
    for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
111 112 113 114 115
        if (strlen(channel_layout_map[i].name) == name_len &&
            !memcmp(channel_layout_map[i].name, name, name_len))
            return channel_layout_map[i].layout;
    }
    for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
116 117 118
        if (channel_names[i].name &&
            strlen(channel_names[i].name) == name_len &&
            !memcmp(channel_names[i].name, name, name_len))
119 120 121 122 123 124 125 126
            return (int64_t)1 << i;
    i = strtol(name, &end, 10);
    if (end - name == name_len ||
        (end + 1 - name == name_len && *end  == 'c'))
        return av_get_default_channel_layout(i);
    layout = strtoll(name, &end, 0);
    if (end - name == name_len)
        return FFMAX(layout, 0);
127 128 129
    return 0;
}

130
uint64_t av_get_channel_layout(const char *name)
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
{
    const char *n, *e;
    const char *name_end = name + strlen(name);
    int64_t layout = 0, layout_single;

    for (n = name; n < name_end; n = e + 1) {
        for (e = n; e < name_end && *e != '+' && *e != '|'; e++);
        layout_single = get_channel_layout_single(n, e - n);
        if (!layout_single)
            return 0;
        layout |= layout_single;
    }
    return layout;
}

146 147
void av_bprint_channel_layout(struct AVBPrint *bp,
                              int nb_channels, uint64_t channel_layout)
148 149 150
{
    int i;

151 152 153
    if (nb_channels <= 0)
        nb_channels = av_get_channel_layout_nb_channels(channel_layout);

154
    for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
155 156
        if (nb_channels    == channel_layout_map[i].nb_channels &&
            channel_layout == channel_layout_map[i].layout) {
157
            av_bprintf(bp, "%s", channel_layout_map[i].name);
158 159 160
            return;
        }

161
    av_bprintf(bp, "%d channels", nb_channels);
162
    if (channel_layout) {
163
        int i, ch;
164
        av_bprintf(bp, " (");
165
        for (i = 0, ch = 0; i < 64; i++) {
166
            if ((channel_layout & (UINT64_C(1) << i))) {
167 168
                const char *name = get_channel_name(i);
                if (name) {
169
                    if (ch > 0)
170 171
                        av_bprintf(bp, "+");
                    av_bprintf(bp, "%s", name);
172 173 174 175
                }
                ch++;
            }
        }
176
        av_bprintf(bp, ")");
177 178 179
    }
}

180 181 182 183 184 185 186 187 188
void av_get_channel_layout_string(char *buf, int buf_size,
                                  int nb_channels, uint64_t channel_layout)
{
    AVBPrint bp;

    av_bprint_init_for_buffer(&bp, buf, buf_size);
    av_bprint_channel_layout(&bp, nb_channels, channel_layout);
}

189
int av_get_channel_layout_nb_channels(uint64_t channel_layout)
190
{
191
    return av_popcount64(channel_layout);
192
}
193

194
int64_t av_get_default_channel_layout(int nb_channels) {
195
    int i;
196
    for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
197 198 199 200
        if (nb_channels == channel_layout_map[i].nb_channels)
            return channel_layout_map[i].layout;
    return 0;
}
201 202 203 204 205 206 207 208 209 210

int av_get_channel_layout_channel_index(uint64_t channel_layout,
                                        uint64_t channel)
{
    if (!(channel_layout & channel) ||
        av_get_channel_layout_nb_channels(channel) != 1)
        return AVERROR(EINVAL);
    channel_layout &= channel - 1;
    return av_get_channel_layout_nb_channels(channel_layout);
}
211 212 213 214 215 216 217 218 219 220 221

const char *av_get_channel_name(uint64_t channel)
{
    int i;
    if (av_get_channel_layout_nb_channels(channel) != 1)
        return NULL;
    for (i = 0; i < 64; i++)
        if ((1ULL<<i) & channel)
            return get_channel_name(i);
    return NULL;
}
222

223 224 225 226 227 228 229 230 231 232 233
const char *av_get_channel_description(uint64_t channel)
{
    int i;
    if (av_get_channel_layout_nb_channels(channel) != 1)
        return NULL;
    for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
        if ((1ULL<<i) & channel)
            return channel_names[i].description;
    return NULL;
}

234 235 236 237 238 239 240 241 242 243 244 245 246
uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index)
{
    int i;

    if (av_get_channel_layout_nb_channels(channel_layout) <= index)
        return 0;

    for (i = 0; i < 64; i++) {
        if ((1ULL << i) & channel_layout && !index--)
            return 1ULL << i;
    }
    return 0;
}
247 248 249 250 251 252 253 254 255 256

int av_get_standard_channel_layout(unsigned index, uint64_t *layout,
                                   const char **name)
{
    if (index >= FF_ARRAY_ELEMS(channel_layout_map))
        return AVERROR_EOF;
    if (layout) *layout = channel_layout_map[index].layout;
    if (name)   *name   = channel_layout_map[index].name;
    return 0;
}