1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "media/base/channel_layout.h"
6
7#include "base/basictypes.h"
8#include "base/logging.h"
9
10namespace media {
11
12static const int kLayoutToChannels[] = {
13    0,   // CHANNEL_LAYOUT_NONE
14    0,   // CHANNEL_LAYOUT_UNSUPPORTED
15    1,   // CHANNEL_LAYOUT_MONO
16    2,   // CHANNEL_LAYOUT_STEREO
17    3,   // CHANNEL_LAYOUT_2_1
18    3,   // CHANNEL_LAYOUT_SURROUND
19    4,   // CHANNEL_LAYOUT_4_0
20    4,   // CHANNEL_LAYOUT_2_2
21    4,   // CHANNEL_LAYOUT_QUAD
22    5,   // CHANNEL_LAYOUT_5_0
23    6,   // CHANNEL_LAYOUT_5_1
24    5,   // CHANNEL_LAYOUT_5_0_BACK
25    6,   // CHANNEL_LAYOUT_5_1_BACK
26    7,   // CHANNEL_LAYOUT_7_0
27    8,   // CHANNEL_LAYOUT_7_1
28    8,   // CHANNEL_LAYOUT_7_1_WIDE
29    2,   // CHANNEL_LAYOUT_STEREO_DOWNMIX
30    3,   // CHANNEL_LAYOUT_2POINT1
31    4,   // CHANNEL_LAYOUT_3_1
32    5,   // CHANNEL_LAYOUT_4_1
33    6,   // CHANNEL_LAYOUT_6_0
34    6,   // CHANNEL_LAYOUT_6_0_FRONT
35    6,   // CHANNEL_LAYOUT_HEXAGONAL
36    7,   // CHANNEL_LAYOUT_6_1
37    7,   // CHANNEL_LAYOUT_6_1_BACK
38    7,   // CHANNEL_LAYOUT_6_1_FRONT
39    7,   // CHANNEL_LAYOUT_7_0_FRONT
40    8,   // CHANNEL_LAYOUT_7_1_WIDE_BACK
41    8,   // CHANNEL_LAYOUT_OCTAGONAL
42    0,   // CHANNEL_LAYOUT_DISCRETE
43};
44
45// The channel orderings for each layout as specified by FFmpeg.  Each value
46// represents the index of each channel in each layout.  Values of -1 mean the
47// channel at that index is not used for that layout.For example, the left side
48// surround sound channel in FFmpeg's 5.1 layout is in the 5th position (because
49// the order is L, R, C, LFE, LS, RS), so
50// kChannelOrderings[CHANNEL_LAYOUT_5POINT1][SIDE_LEFT] = 4;
51static const int kChannelOrderings[CHANNEL_LAYOUT_MAX][CHANNELS_MAX] = {
52    // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
53
54    // CHANNEL_LAYOUT_NONE
55    {  -1 , -1 , -1 , -1  , -1 , -1 , -1    , -1    , -1 , -1 , -1 },
56
57    // CHANNEL_LAYOUT_UNSUPPORTED
58    {  -1 , -1 , -1 , -1  , -1 , -1 , -1    , -1    , -1 , -1 , -1 },
59
60    // CHANNEL_LAYOUT_MONO
61    {  -1 , -1 , 0  , -1  , -1 , -1 , -1    , -1    , -1 , -1 , -1 },
62
63    // CHANNEL_LAYOUT_STEREO
64    {  0  , 1  , -1 , -1  , -1 , -1 , -1    , -1    , -1 , -1 , -1 },
65
66    // CHANNEL_LAYOUT_2_1
67    {  0  , 1  , -1 , -1  , -1 , -1 , -1    , -1    , 2  , -1 , -1 },
68
69    // CHANNEL_LAYOUT_SURROUND
70    {  0  , 1  , 2  , -1  , -1 , -1 , -1    , -1    , -1 , -1 , -1 },
71
72    // CHANNEL_LAYOUT_4_0
73    {  0  , 1  , 2  , -1  , -1 , -1 , -1    , -1    , 3  , -1 , -1 },
74
75    // CHANNEL_LAYOUT_2_2
76    {  0  , 1  , -1 , -1  , -1 , -1 , -1    , -1    , -1 , 2  ,  3 },
77
78    // CHANNEL_LAYOUT_QUAD
79    {  0  , 1  , -1 , -1  , 2  , 3  , -1    , -1    , -1 , -1 , -1 },
80
81    // CHANNEL_LAYOUT_5_0
82    {  0  , 1  , 2  , -1  , -1 , -1 , -1    , -1    , -1 , 3  ,  4 },
83
84    // CHANNEL_LAYOUT_5_1
85    {  0  , 1  , 2  , 3   , -1 , -1 , -1    , -1    , -1 , 4  ,  5 },
86
87    // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
88
89    // CHANNEL_LAYOUT_5_0_BACK
90    {  0  , 1  , 2  , -1  , 3  , 4  , -1    , -1    , -1 , -1 , -1 },
91
92    // CHANNEL_LAYOUT_5_1_BACK
93    {  0  , 1  , 2  , 3   , 4  , 5  , -1    , -1    , -1 , -1 , -1 },
94
95    // CHANNEL_LAYOUT_7_0
96    {  0  , 1  , 2  , -1  , 5  , 6  , -1    , -1    , -1 , 3  ,  4 },
97
98    // CHANNEL_LAYOUT_7_1
99    {  0  , 1  , 2  , 3   , 6  , 7  , -1    , -1    , -1 , 4  ,  5 },
100
101    // CHANNEL_LAYOUT_7_1_WIDE
102    {  0  , 1  , 2  , 3   , -1 , -1 , 6     , 7     , -1 , 4  ,  5 },
103
104    // CHANNEL_LAYOUT_STEREO_DOWNMIX
105    {  0  , 1  , -1 , -1  , -1 , -1 , -1    , -1    , -1 , -1 , -1 },
106
107    // CHANNEL_LAYOUT_2POINT1
108    {  0  , 1  , -1 ,  2  , -1 , -1 , -1    , -1    , -1 , -1 , -1 },
109
110    // CHANNEL_LAYOUT_3_1
111    {  0  , 1  ,  2 ,  3  , -1 , -1 , -1    , -1    , -1 , -1 , -1 },
112
113    // CHANNEL_LAYOUT_4_1
114    {  0  , 1  ,  2 ,  4  , -1 , -1 , -1    , -1    ,  3 , -1 , -1 },
115
116    // CHANNEL_LAYOUT_6_0
117    {  0  , 1  , 2  , -1  , -1 , -1 , -1    , -1    ,  5 , 3  ,  4 },
118
119    // CHANNEL_LAYOUT_6_0_FRONT
120    {  0  , 1  , -1 , -1  , -1 , -1 ,  4    ,  5    , -1 , 2  ,  3 },
121
122    // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
123
124    // CHANNEL_LAYOUT_HEXAGONAL
125    {  0  , 1  , 2  , -1  , 3  , 4  , -1    , -1    ,  5 , -1 , -1 },
126
127    // CHANNEL_LAYOUT_6_1
128    {  0  , 1  , 2  , 3   , -1 , -1 , -1    , -1    ,  6 , 4  ,  5 },
129
130    // CHANNEL_LAYOUT_6_1_BACK
131    {  0  , 1  , 2  , 3   , 4  , 5  , -1    , -1    ,  6 , -1 , -1 },
132
133    // CHANNEL_LAYOUT_6_1_FRONT
134    {  0  , 1  , -1 , 6   , -1 , -1 , 4     , 5     , -1 , 2  ,  3 },
135
136    // CHANNEL_LAYOUT_7_0_FRONT
137    {  0  , 1  , 2  , -1  , -1 , -1 , 5     , 6     , -1 , 3  ,  4 },
138
139    // CHANNEL_LAYOUT_7_1_WIDE_BACK
140    {  0  , 1  , 2  , 3   , 4  , 5  , 6     , 7     , -1 , -1 , -1 },
141
142    // CHANNEL_LAYOUT_OCTAGONAL
143    {  0  , 1  , 2  , -1  , 5  , 6  , -1    , -1    ,  7 , 3  ,  4 },
144
145    // CHANNEL_LAYOUT_DISCRETE
146    {  -1 , -1 , -1 , -1  , -1 , -1 , -1    , -1    , -1 , -1 , -1 },
147
148    // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
149};
150
151int ChannelLayoutToChannelCount(ChannelLayout layout) {
152  DCHECK_LT(static_cast<size_t>(layout), arraysize(kLayoutToChannels));
153  return kLayoutToChannels[layout];
154}
155
156// Converts a channel count into a channel layout.
157ChannelLayout GuessChannelLayout(int channels) {
158  switch (channels) {
159    case 1:
160      return CHANNEL_LAYOUT_MONO;
161    case 2:
162      return CHANNEL_LAYOUT_STEREO;
163    case 3:
164      return CHANNEL_LAYOUT_SURROUND;
165    case 4:
166      return CHANNEL_LAYOUT_QUAD;
167    case 5:
168      return CHANNEL_LAYOUT_5_0;
169    case 6:
170      return CHANNEL_LAYOUT_5_1;
171    case 7:
172      return CHANNEL_LAYOUT_6_1;
173    case 8:
174      return CHANNEL_LAYOUT_7_1;
175    default:
176      DVLOG(1) << "Unsupported channel count: " << channels;
177  }
178  return CHANNEL_LAYOUT_UNSUPPORTED;
179}
180
181int ChannelOrder(ChannelLayout layout, Channels channel) {
182  DCHECK_LT(static_cast<size_t>(layout), arraysize(kChannelOrderings));
183  DCHECK_LT(static_cast<size_t>(channel), arraysize(kChannelOrderings[0]));
184  return kChannelOrderings[layout][channel];
185}
186
187const char* ChannelLayoutToString(ChannelLayout layout) {
188  switch (layout) {
189    case CHANNEL_LAYOUT_NONE:
190      return "NONE";
191    case CHANNEL_LAYOUT_UNSUPPORTED:
192      return "UNSUPPORTED";
193    case CHANNEL_LAYOUT_MONO:
194      return "MONO";
195    case CHANNEL_LAYOUT_STEREO:
196      return "STEREO";
197    case CHANNEL_LAYOUT_2_1:
198      return "2.1";
199    case CHANNEL_LAYOUT_SURROUND:
200      return "SURROUND";
201    case CHANNEL_LAYOUT_4_0:
202      return "4.0";
203    case CHANNEL_LAYOUT_2_2:
204      return "2.2";
205    case CHANNEL_LAYOUT_QUAD:
206      return "QUAD";
207    case CHANNEL_LAYOUT_5_0:
208      return "5.0";
209    case CHANNEL_LAYOUT_5_1:
210      return "5.1";
211    case CHANNEL_LAYOUT_5_0_BACK:
212      return "5.0_BACK";
213    case CHANNEL_LAYOUT_5_1_BACK:
214      return "5.1_BACK";
215    case CHANNEL_LAYOUT_7_0:
216      return "7.0";
217    case CHANNEL_LAYOUT_7_1:
218      return "7.1";
219    case CHANNEL_LAYOUT_7_1_WIDE:
220      return "7.1_WIDE";
221    case CHANNEL_LAYOUT_STEREO_DOWNMIX:
222      return "STEREO_DOWNMIX";
223    case CHANNEL_LAYOUT_2POINT1:
224      return "2POINT1";
225    case CHANNEL_LAYOUT_3_1:
226      return "3.1";
227    case CHANNEL_LAYOUT_4_1:
228      return "4.1";
229    case CHANNEL_LAYOUT_6_0:
230      return "6.0";
231    case CHANNEL_LAYOUT_6_0_FRONT:
232      return "6.0_FRONT";
233    case CHANNEL_LAYOUT_HEXAGONAL:
234      return "HEXAGONAL";
235    case CHANNEL_LAYOUT_6_1:
236      return "6.1";
237    case CHANNEL_LAYOUT_6_1_BACK:
238      return "6.1_BACK";
239    case CHANNEL_LAYOUT_6_1_FRONT:
240      return "6.1_FRONT";
241    case CHANNEL_LAYOUT_7_0_FRONT:
242      return "7.0_FRONT";
243    case CHANNEL_LAYOUT_7_1_WIDE_BACK:
244      return "7.1_WIDE_BACK";
245    case CHANNEL_LAYOUT_OCTAGONAL:
246      return "OCTAGONAL";
247    case CHANNEL_LAYOUT_DISCRETE:
248      return "DISCRETE";
249    case CHANNEL_LAYOUT_MAX:
250      break;
251  }
252  NOTREACHED() << "Invalid channel layout provided: " << layout;
253  return "";
254}
255
256}  // namespace media
257