Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
52868 views
1
/*
2
* Copyright (c) 2006 Michael Niedermayer <[email protected]>
3
*
4
* This file is part of FFmpeg.
5
*
6
* FFmpeg is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* FFmpeg is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with FFmpeg; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
*/
20
21
/**
22
* @file
23
* audio channel layout utility functions
24
*/
25
26
#include <stdint.h>
27
28
#include "avstring.h"
29
#include "avutil.h"
30
#include "channel_layout.h"
31
#include "bprint.h"
32
#include "common.h"
33
34
struct channel_name {
35
const char *name;
36
const char *description;
37
};
38
39
static const struct channel_name channel_names[] = {
40
[0] = { "FL", "front left" },
41
[1] = { "FR", "front right" },
42
[2] = { "FC", "front center" },
43
[3] = { "LFE", "low frequency" },
44
[4] = { "BL", "back left" },
45
[5] = { "BR", "back right" },
46
[6] = { "FLC", "front left-of-center" },
47
[7] = { "FRC", "front right-of-center" },
48
[8] = { "BC", "back center" },
49
[9] = { "SL", "side left" },
50
[10] = { "SR", "side right" },
51
[11] = { "TC", "top center" },
52
[12] = { "TFL", "top front left" },
53
[13] = { "TFC", "top front center" },
54
[14] = { "TFR", "top front right" },
55
[15] = { "TBL", "top back left" },
56
[16] = { "TBC", "top back center" },
57
[17] = { "TBR", "top back right" },
58
[29] = { "DL", "downmix left" },
59
[30] = { "DR", "downmix right" },
60
[31] = { "WL", "wide left" },
61
[32] = { "WR", "wide right" },
62
[33] = { "SDL", "surround direct left" },
63
[34] = { "SDR", "surround direct right" },
64
[35] = { "LFE2", "low frequency 2" },
65
};
66
67
static const char *get_channel_name(int channel_id)
68
{
69
if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names))
70
return NULL;
71
return channel_names[channel_id].name;
72
}
73
74
static const struct {
75
const char *name;
76
int nb_channels;
77
uint64_t layout;
78
} channel_layout_map[] = {
79
{ "mono", 1, AV_CH_LAYOUT_MONO },
80
{ "stereo", 2, AV_CH_LAYOUT_STEREO },
81
{ "2.1", 3, AV_CH_LAYOUT_2POINT1 },
82
{ "3.0", 3, AV_CH_LAYOUT_SURROUND },
83
{ "3.0(back)", 3, AV_CH_LAYOUT_2_1 },
84
{ "4.0", 4, AV_CH_LAYOUT_4POINT0 },
85
{ "quad", 4, AV_CH_LAYOUT_QUAD },
86
{ "quad(side)", 4, AV_CH_LAYOUT_2_2 },
87
{ "3.1", 4, AV_CH_LAYOUT_3POINT1 },
88
{ "5.0", 5, AV_CH_LAYOUT_5POINT0_BACK },
89
{ "5.0(side)", 5, AV_CH_LAYOUT_5POINT0 },
90
{ "4.1", 5, AV_CH_LAYOUT_4POINT1 },
91
{ "5.1", 6, AV_CH_LAYOUT_5POINT1_BACK },
92
{ "5.1(side)", 6, AV_CH_LAYOUT_5POINT1 },
93
{ "6.0", 6, AV_CH_LAYOUT_6POINT0 },
94
{ "6.0(front)", 6, AV_CH_LAYOUT_6POINT0_FRONT },
95
{ "hexagonal", 6, AV_CH_LAYOUT_HEXAGONAL },
96
{ "6.1", 7, AV_CH_LAYOUT_6POINT1 },
97
{ "6.1", 7, AV_CH_LAYOUT_6POINT1_BACK },
98
{ "6.1(front)", 7, AV_CH_LAYOUT_6POINT1_FRONT },
99
{ "7.0", 7, AV_CH_LAYOUT_7POINT0 },
100
{ "7.0(front)", 7, AV_CH_LAYOUT_7POINT0_FRONT },
101
{ "7.1", 8, AV_CH_LAYOUT_7POINT1 },
102
{ "7.1(wide)", 8, AV_CH_LAYOUT_7POINT1_WIDE_BACK },
103
{ "7.1(wide-side)", 8, AV_CH_LAYOUT_7POINT1_WIDE },
104
{ "octagonal", 8, AV_CH_LAYOUT_OCTAGONAL },
105
{ "hexadecagonal", 16, AV_CH_LAYOUT_HEXADECAGONAL },
106
{ "downmix", 2, AV_CH_LAYOUT_STEREO_DOWNMIX, },
107
};
108
109
static uint64_t get_channel_layout_single(const char *name, int name_len)
110
{
111
int i;
112
char *end;
113
int64_t layout;
114
115
for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
116
if (strlen(channel_layout_map[i].name) == name_len &&
117
!memcmp(channel_layout_map[i].name, name, name_len))
118
return channel_layout_map[i].layout;
119
}
120
for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
121
if (channel_names[i].name &&
122
strlen(channel_names[i].name) == name_len &&
123
!memcmp(channel_names[i].name, name, name_len))
124
return (int64_t)1 << i;
125
126
errno = 0;
127
i = strtol(name, &end, 10);
128
129
if (!errno && (end + 1 - name == name_len && *end == 'c'))
130
return av_get_default_channel_layout(i);
131
132
errno = 0;
133
layout = strtoll(name, &end, 0);
134
if (!errno && end - name == name_len)
135
return FFMAX(layout, 0);
136
return 0;
137
}
138
139
uint64_t av_get_channel_layout(const char *name)
140
{
141
const char *n, *e;
142
const char *name_end = name + strlen(name);
143
int64_t layout = 0, layout_single;
144
145
for (n = name; n < name_end; n = e + 1) {
146
for (e = n; e < name_end && *e != '+' && *e != '|'; e++);
147
layout_single = get_channel_layout_single(n, e - n);
148
if (!layout_single)
149
return 0;
150
layout |= layout_single;
151
}
152
return layout;
153
}
154
155
void av_bprint_channel_layout(struct AVBPrint *bp,
156
int nb_channels, uint64_t channel_layout)
157
{
158
int i;
159
160
if (nb_channels <= 0)
161
nb_channels = av_get_channel_layout_nb_channels(channel_layout);
162
163
for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
164
if (nb_channels == channel_layout_map[i].nb_channels &&
165
channel_layout == channel_layout_map[i].layout) {
166
av_bprintf(bp, "%s", channel_layout_map[i].name);
167
return;
168
}
169
170
av_bprintf(bp, "%d channels", nb_channels);
171
if (channel_layout) {
172
int i, ch;
173
av_bprintf(bp, " (");
174
for (i = 0, ch = 0; i < 64; i++) {
175
if ((channel_layout & (UINT64_C(1) << i))) {
176
const char *name = get_channel_name(i);
177
if (name) {
178
if (ch > 0)
179
av_bprintf(bp, "+");
180
av_bprintf(bp, "%s", name);
181
}
182
ch++;
183
}
184
}
185
av_bprintf(bp, ")");
186
}
187
}
188
189
void av_get_channel_layout_string(char *buf, int buf_size,
190
int nb_channels, uint64_t channel_layout)
191
{
192
AVBPrint bp;
193
194
av_bprint_init_for_buffer(&bp, buf, buf_size);
195
av_bprint_channel_layout(&bp, nb_channels, channel_layout);
196
}
197
198
int av_get_channel_layout_nb_channels(uint64_t channel_layout)
199
{
200
return av_popcount64(channel_layout);
201
}
202
203
int64_t av_get_default_channel_layout(int nb_channels) {
204
int i;
205
for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
206
if (nb_channels == channel_layout_map[i].nb_channels)
207
return channel_layout_map[i].layout;
208
return 0;
209
}
210
211
int av_get_channel_layout_channel_index(uint64_t channel_layout,
212
uint64_t channel)
213
{
214
if (!(channel_layout & channel) ||
215
av_get_channel_layout_nb_channels(channel) != 1)
216
return AVERROR(EINVAL);
217
channel_layout &= channel - 1;
218
return av_get_channel_layout_nb_channels(channel_layout);
219
}
220
221
const char *av_get_channel_name(uint64_t channel)
222
{
223
int i;
224
if (av_get_channel_layout_nb_channels(channel) != 1)
225
return NULL;
226
for (i = 0; i < 64; i++)
227
if ((1ULL<<i) & channel)
228
return get_channel_name(i);
229
return NULL;
230
}
231
232
const char *av_get_channel_description(uint64_t channel)
233
{
234
int i;
235
if (av_get_channel_layout_nb_channels(channel) != 1)
236
return NULL;
237
for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
238
if ((1ULL<<i) & channel)
239
return channel_names[i].description;
240
return NULL;
241
}
242
243
uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index)
244
{
245
int i;
246
247
if (av_get_channel_layout_nb_channels(channel_layout) <= index)
248
return 0;
249
250
for (i = 0; i < 64; i++) {
251
if ((1ULL << i) & channel_layout && !index--)
252
return 1ULL << i;
253
}
254
return 0;
255
}
256
257
int av_get_standard_channel_layout(unsigned index, uint64_t *layout,
258
const char **name)
259
{
260
if (index >= FF_ARRAY_ELEMS(channel_layout_map))
261
return AVERROR_EOF;
262
if (layout) *layout = channel_layout_map[index].layout;
263
if (name) *name = channel_layout_map[index].name;
264
return 0;
265
}
266
267