changed: Add logic to properly handle subtitles for stacked files
[vuplus_xbmc] / xbmc / cores / AudioEngine / Utils / AEChannelInfo.cpp
1 /*
2  *      Copyright (C) 2010-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "AEChannelInfo.h"
22 #include <string.h>
23
24 CAEChannelInfo::CAEChannelInfo()
25 {
26   Reset();
27 }
28
29 CAEChannelInfo::CAEChannelInfo(const enum AEChannel* rhs)
30 {
31   *this = rhs;
32 }
33
34 CAEChannelInfo::CAEChannelInfo(const AEStdChLayout rhs)
35 {
36   *this = rhs;
37 }
38
39 CAEChannelInfo::~CAEChannelInfo()
40 {
41 }
42
43 void CAEChannelInfo::ResolveChannels(const CAEChannelInfo& rhs)
44 {
45   /* mono gets upmixed to dual mono */
46   if (m_channelCount == 1 && m_channels[0] == AE_CH_FC)
47   {
48     Reset();
49     *this += AE_CH_FL;
50     *this += AE_CH_FR;
51     return;
52   }
53
54   bool srcHasSL = false;
55   bool srcHasSR = false;
56   bool srcHasRL = false;
57   bool srcHasRR = false;
58
59   bool dstHasSL = false;
60   bool dstHasSR = false;
61   bool dstHasRL = false;
62   bool dstHasRR = false;
63
64   for (unsigned int c = 0; c < rhs.m_channelCount; ++c)
65     switch(rhs.m_channels[c])
66     {
67       case AE_CH_SL: dstHasSL = true; break;
68       case AE_CH_SR: dstHasSR = true; break;
69       case AE_CH_BL: dstHasRL = true; break;
70       case AE_CH_BR: dstHasRR = true; break;
71       default:
72         break;
73     }
74
75   CAEChannelInfo newInfo;
76   for (unsigned int i = 0; i < m_channelCount; ++i)
77   {
78     switch (m_channels[i])
79     {
80       case AE_CH_SL: srcHasSL = true; break;
81       case AE_CH_SR: srcHasSR = true; break;
82       case AE_CH_BL: srcHasRL = true; break;
83       case AE_CH_BR: srcHasRR = true; break;
84       default:
85         break;
86     }
87
88     bool found = false;
89     for (unsigned int c = 0; c < rhs.m_channelCount; ++c)
90       if (m_channels[i] == rhs.m_channels[c])
91       {
92         found = true;
93         break;
94       }
95
96     if (found)
97       newInfo += m_channels[i];
98   }
99
100   /* we need to ensure we end up with rear or side channels for downmix to work */
101   if (srcHasSL && !dstHasSL && dstHasRL)
102     newInfo += AE_CH_BL;
103   if (srcHasSR && !dstHasSR && dstHasRR)
104     newInfo += AE_CH_BR;
105   if (srcHasRL && !dstHasRL && dstHasSL)
106     newInfo += AE_CH_SL;
107   if (srcHasRR && !dstHasRR && dstHasSR)
108     newInfo += AE_CH_SR;
109
110   *this = newInfo;
111 }
112
113 void CAEChannelInfo::Reset()
114 {
115   m_channelCount = 0;
116   for (unsigned int i = 0; i < AE_CH_MAX; ++i)
117     m_channels[i] = AE_CH_NULL;
118 }
119
120 CAEChannelInfo& CAEChannelInfo::operator=(const CAEChannelInfo& rhs)
121 {
122   if (this == &rhs)
123     return *this;
124
125   /* clone the information */
126   m_channelCount = rhs.m_channelCount;
127   memcpy(m_channels, rhs.m_channels, sizeof(enum AEChannel) * rhs.m_channelCount);
128
129   return *this;
130 }
131
132 CAEChannelInfo& CAEChannelInfo::operator=(const enum AEChannel* rhs)
133 {
134   Reset();
135   if (rhs == NULL)
136     return *this;
137
138   while (m_channelCount < AE_CH_MAX && rhs[m_channelCount] != AE_CH_NULL)
139   {
140     m_channels[m_channelCount] = rhs[m_channelCount];
141     ++m_channelCount;
142   }
143
144   /* the last entry should be NULL, if not we were passed a non null terminated list */
145   ASSERT(rhs[m_channelCount] == AE_CH_NULL);
146
147   return *this;
148 }
149
150 CAEChannelInfo& CAEChannelInfo::operator=(const enum AEStdChLayout rhs)
151 {
152   ASSERT(rhs > AE_CH_LAYOUT_INVALID && rhs < AE_CH_LAYOUT_MAX);
153
154   static enum AEChannel layouts[AE_CH_LAYOUT_MAX][9] = {
155     {AE_CH_FC, AE_CH_NULL},
156     {AE_CH_FL, AE_CH_FR, AE_CH_NULL},
157     {AE_CH_FL, AE_CH_FR, AE_CH_LFE, AE_CH_NULL},
158     {AE_CH_FL, AE_CH_FR, AE_CH_FC , AE_CH_NULL},
159     {AE_CH_FL, AE_CH_FR, AE_CH_FC , AE_CH_LFE, AE_CH_NULL},
160     {AE_CH_FL, AE_CH_FR, AE_CH_BL , AE_CH_BR , AE_CH_NULL},
161     {AE_CH_FL, AE_CH_FR, AE_CH_BL , AE_CH_BR , AE_CH_LFE, AE_CH_NULL},
162     {AE_CH_FL, AE_CH_FR, AE_CH_FC , AE_CH_BL , AE_CH_BR , AE_CH_NULL},
163     {AE_CH_FL, AE_CH_FR, AE_CH_FC , AE_CH_BL , AE_CH_BR , AE_CH_LFE, AE_CH_NULL},
164     {AE_CH_FL, AE_CH_FR, AE_CH_FC , AE_CH_BL , AE_CH_BR , AE_CH_SL , AE_CH_SR, AE_CH_NULL},
165     {AE_CH_FL, AE_CH_FR, AE_CH_FC , AE_CH_BL , AE_CH_BR , AE_CH_SL , AE_CH_SR, AE_CH_LFE, AE_CH_NULL}
166   };
167
168   *this = layouts[rhs];
169   return *this;
170 }
171
172 bool CAEChannelInfo::operator==(const CAEChannelInfo& rhs)
173 {
174   /* if the channel count doesnt match, no need to check further */
175   if (m_channelCount != rhs.m_channelCount)
176     return false;
177
178   /* make sure the channel order is the same */
179   for (unsigned int i = 0; i < m_channelCount; ++i)
180     if (m_channels[i] != rhs.m_channels[i])
181       return false;
182
183   return true;
184 }
185
186 bool CAEChannelInfo::operator!=(const CAEChannelInfo& rhs)
187 {
188   return !(*this == rhs);
189 }
190
191 CAEChannelInfo& CAEChannelInfo::operator+=(const enum AEChannel& rhs)
192 {
193   ASSERT(m_channelCount < AE_CH_MAX);
194   ASSERT(rhs > AE_CH_NULL && rhs < AE_CH_MAX);
195
196   m_channels[m_channelCount++] = rhs;
197   return *this;
198 }
199
200 CAEChannelInfo& CAEChannelInfo::operator-=(const enum AEChannel& rhs)
201 {
202   ASSERT(rhs > AE_CH_NULL && rhs < AE_CH_MAX);
203
204   unsigned int i = 0;
205   while(i < m_channelCount && m_channels[i] != rhs)
206     i++;
207   if (i >= m_channelCount)
208     return *this; // Channel not found
209
210   for(; i < m_channelCount-1; i++)
211     m_channels[i] = m_channels[i+1];
212
213   m_channels[i] = AE_CH_NULL;
214   m_channelCount--;
215   return *this;
216 }
217
218 const enum AEChannel CAEChannelInfo::operator[](unsigned int i) const
219 {
220   ASSERT(i < m_channelCount);
221   return m_channels[i];
222 }
223
224 CAEChannelInfo::operator std::string() const
225 {
226   if (m_channelCount == 0)
227     return "NULL";
228
229   std::string s;
230   for (unsigned int i = 0; i < m_channelCount - 1; ++i)
231   {
232     s.append(GetChName(m_channels[i]));
233     s.append(",");
234   }
235   s.append(GetChName(m_channels[m_channelCount-1]));
236
237   return s;
238 }
239
240 const char* CAEChannelInfo::GetChName(const enum AEChannel ch)
241 {
242   ASSERT(ch >= 0 && ch < AE_CH_MAX);
243
244   static const char* channels[AE_CH_MAX] =
245   {
246     "RAW" ,
247     "FL"  , "FR" , "FC" , "LFE", "BL"  , "BR"  , "FLOC",
248     "FROC", "BC" , "SL" , "SR" , "TFL" , "TFR" , "TFC" ,
249     "TC"  , "TBL", "TBR", "TBC", "BLOC", "BROC",
250
251     /* p16v devices */
252     "UNKNOWN1",
253     "UNKNOWN2",
254     "UNKNOWN3",
255     "UNKNOWN4",
256     "UNKNOWN5",
257     "UNKNOWN6",
258     "UNKNOWN7",
259     "UNKNOWN8"
260   };
261
262   return channels[ch];
263 }
264
265 bool CAEChannelInfo::HasChannel(const enum AEChannel ch) const
266 {
267   for (unsigned int i = 0; i < m_channelCount; ++i)
268     if (m_channels[i] == ch)
269       return true;
270   return false;
271 }
272
273 bool CAEChannelInfo::ContainsChannels(CAEChannelInfo& rhs) const
274 {
275   for (unsigned int i = 0; i < rhs.m_channelCount; ++i)
276   {
277     if (!HasChannel(rhs.m_channels[i]))
278       return false;
279   }
280   return true;
281 }