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