[bluray] Fix stream info/language retrieval for blurays in non-nav mode.
[vuplus_xbmc] / xbmc / video / dialogs / GUIDialogAudioSubtitleSettings.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.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 "system.h"
22 #include "GUIDialogAudioSubtitleSettings.h"
23 #include "dialogs/GUIDialogFileBrowser.h"
24 #include "GUIPassword.h"
25 #include "utils/URIUtils.h"
26 #include "Application.h"
27 #include "video/VideoDatabase.h"
28 #include "dialogs/GUIDialogYesNo.h"
29 #include "filesystem/Directory.h"
30 #include "filesystem/File.h"
31 #include "URL.h"
32 #include "FileItem.h"
33 #include "addons/Skin.h"
34 #include "profiles/ProfilesManager.h"
35 #include "settings/AdvancedSettings.h"
36 #include "settings/MediaSettings.h"
37 #include "settings/MediaSourceSettings.h"
38 #include "settings/Settings.h"
39 #include "guilib/LocalizeStrings.h"
40 #include "pvr/PVRManager.h"
41 #include "cores/AudioEngine/Utils/AEUtil.h"
42 #include "cores/IPlayer.h"
43 #include "utils/LangCodeExpander.h"
44
45 using namespace std;
46 using namespace XFILE;
47 using namespace PVR;
48
49 #ifdef HAS_VIDEO_PLAYBACK
50 extern void xbox_audio_switch_channel(int iAudioStream, bool bAudioOnAllSpeakers); //lowlevel audio
51 #endif
52
53 CGUIDialogAudioSubtitleSettings::CGUIDialogAudioSubtitleSettings(void)
54     : CGUIDialogSettings(WINDOW_DIALOG_AUDIO_OSD_SETTINGS, "VideoOSDSettings.xml")
55 {
56 }
57
58 CGUIDialogAudioSubtitleSettings::~CGUIDialogAudioSubtitleSettings(void)
59 {
60 }
61
62 #define AUDIO_SETTINGS_VOLUME             1
63 #define AUDIO_SETTINGS_VOLUME_AMPLIFICATION 2
64 #define AUDIO_SETTINGS_DELAY              3
65 #define AUDIO_SETTINGS_STREAM             4
66 #define AUDIO_SETTINGS_OUTPUT_TO_ALL_SPEAKERS 5
67 #define AUDIO_SETTINGS_DIGITAL_ANALOG     6
68
69 // separator 7
70 #define SUBTITLE_SETTINGS_ENABLE          8
71 #define SUBTITLE_SETTINGS_DELAY           9
72 #define SUBTITLE_SETTINGS_STREAM          10
73 #define SUBTITLE_SETTINGS_BROWSER         11
74 #define AUDIO_SETTINGS_MAKE_DEFAULT       12
75
76 void CGUIDialogAudioSubtitleSettings::CreateSettings()
77 {
78   m_usePopupSliders = g_SkinInfo->HasSkinFile("DialogSlider.xml");
79
80   if (g_application.m_pPlayer)
81   {
82     g_application.m_pPlayer->GetAudioCapabilities(m_audioCaps);
83     g_application.m_pPlayer->GetSubtitleCapabilities(m_subCaps);
84   }
85
86   // clear out any old settings
87   m_settings.clear();
88   // create our settings
89   m_volume = g_application.GetVolume(false);
90   AddSlider(AUDIO_SETTINGS_VOLUME, 13376, &m_volume, VOLUME_MINIMUM, VOLUME_MAXIMUM / 100.0f, VOLUME_MAXIMUM, PercentAsDecibel, false);
91   if (SupportsAudioFeature(IPC_AUD_AMP))
92     AddSlider(AUDIO_SETTINGS_VOLUME_AMPLIFICATION, 660, &CMediaSettings::Get().GetCurrentVideoSettings().m_VolumeAmplification, VOLUME_DRC_MINIMUM * 0.01f, (VOLUME_DRC_MAXIMUM - VOLUME_DRC_MINIMUM) / 6000.0f, VOLUME_DRC_MAXIMUM * 0.01f, FormatDecibel, false);
93   if (g_application.m_pPlayer && g_application.m_pPlayer->IsPassthrough())
94   {
95     EnableSettings(AUDIO_SETTINGS_VOLUME,false);
96     EnableSettings(AUDIO_SETTINGS_VOLUME_AMPLIFICATION,false);
97   }
98   if (SupportsAudioFeature(IPC_AUD_OFFSET))
99     AddSlider(AUDIO_SETTINGS_DELAY, 297, &CMediaSettings::Get().GetCurrentVideoSettings().m_AudioDelay, -g_advancedSettings.m_videoAudioDelayRange, .025f, g_advancedSettings.m_videoAudioDelayRange, FormatDelay);
100   if (SupportsAudioFeature(IPC_AUD_SELECT_STREAM))
101     AddAudioStreams(AUDIO_SETTINGS_STREAM);
102
103   // only show stuff available in digital mode if we have digital output
104   if (SupportsAudioFeature(IPC_AUD_OUTPUT_STEREO))
105     AddBool(AUDIO_SETTINGS_OUTPUT_TO_ALL_SPEAKERS, 252, &CMediaSettings::Get().GetCurrentVideoSettings().m_OutputToAllSpeakers, AUDIO_IS_BITSTREAM(CSettings::Get().GetInt("audiooutput.mode")));
106
107   int settings[3] = { 338, 339, 420 }; //ANALOG, IEC958, HDMI
108   m_outputmode = CSettings::Get().GetInt("audiooutput.mode");
109   if (SupportsAudioFeature(IPC_AUD_SELECT_OUTPUT))
110     AddSpin(AUDIO_SETTINGS_DIGITAL_ANALOG, 337, &m_outputmode, 3, settings);
111
112   AddSeparator(7);
113   m_subtitleVisible = g_application.m_pPlayer->GetSubtitleVisible();
114   AddBool(SUBTITLE_SETTINGS_ENABLE, 13397, &m_subtitleVisible);
115   if (SupportsSubtitleFeature(IPC_SUBS_OFFSET))
116     AddSlider(SUBTITLE_SETTINGS_DELAY, 22006, &CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleDelay, -g_advancedSettings.m_videoSubsDelayRange, 0.1f, g_advancedSettings.m_videoSubsDelayRange, FormatDelay);
117   if (SupportsSubtitleFeature(IPC_SUBS_SELECT))
118     AddSubtitleStreams(SUBTITLE_SETTINGS_STREAM);
119   if (SupportsSubtitleFeature(IPC_SUBS_EXTERNAL))
120     AddButton(SUBTITLE_SETTINGS_BROWSER,13250);
121   AddButton(AUDIO_SETTINGS_MAKE_DEFAULT, 12376);
122 }
123
124 void CGUIDialogAudioSubtitleSettings::AddAudioStreams(unsigned int id)
125 {
126   SettingInfo setting;
127   setting.id = id;
128   setting.name = g_localizeStrings.Get(460);
129   setting.type = SettingInfo::SPIN;
130   setting.min = 0;
131   setting.data = &m_audioStream;
132
133   // get the number of audio strams for the current movie
134   setting.max = (float)g_application.m_pPlayer->GetAudioStreamCount() - 1;
135   m_audioStream = g_application.m_pPlayer->GetAudioStream();
136
137   if( m_audioStream < 0 ) m_audioStream = 0;
138
139   // check if we have a single, stereo stream, and if so, allow us to split into
140   // left, right or both
141   if (!setting.max)
142   {
143     CStdString strAudioInfo;
144     g_application.m_pPlayer->GetAudioInfo(strAudioInfo);
145     int iNumChannels = atoi(strAudioInfo.Right(strAudioInfo.size() - strAudioInfo.Find("chns:") - 5).c_str());
146     CStdString strAudioCodec = strAudioInfo.Mid(7, strAudioInfo.Find(") VBR") - 5);
147     bool bDTS = strstr(strAudioCodec.c_str(), "DTS") != 0;
148     bool bAC3 = strstr(strAudioCodec.c_str(), "AC3") != 0;
149     if (iNumChannels == 2 && !(bDTS || bAC3))
150     { // ok, enable these options
151 /*      if (CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream == -1)
152       { // default to stereo stream
153         CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream = 0;
154       }*/
155       setting.max = 2;
156       for (int i = 0; i <= setting.max; i++)
157         setting.entry.push_back(make_pair(setting.entry.size(), g_localizeStrings.Get(13320 + i)));
158       m_audioStream = -CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream - 1;
159       m_settings.push_back(setting);
160       return;
161     }
162   }
163
164   // cycle through each audio stream and add it to our list control
165   for (int i = 0; i <= setting.max; ++i)
166   {
167     CStdString strItem;
168     CStdString strLanguage;
169
170     SPlayerAudioStreamInfo info;
171     g_application.m_pPlayer->GetAudioStreamInfo(i, info);
172
173     if (!g_LangCodeExpander.Lookup(strLanguage, info.language))
174       strLanguage = g_localizeStrings.Get(13205); // Unknown
175
176     if (info.name.length() == 0)
177       strItem = strLanguage;
178     else
179       strItem.Format("%s - %s", strLanguage.c_str(), info.name.c_str());
180
181     strItem.AppendFormat(" (%i/%i)", i + 1, (int)setting.max + 1);
182     setting.entry.push_back(make_pair(setting.entry.size(), strItem));
183   }
184
185   if( setting.max < 0 )
186   {
187     setting.max = 0;
188     setting.entry.push_back(make_pair(setting.entry.size(), g_localizeStrings.Get(231)));
189   }
190
191   m_settings.push_back(setting);
192 }
193
194 void CGUIDialogAudioSubtitleSettings::AddSubtitleStreams(unsigned int id)
195 {
196   SettingInfo setting;
197
198   setting.id = id;
199   setting.name = g_localizeStrings.Get(462);
200   setting.type = SettingInfo::SPIN;
201   setting.min = 0;
202   setting.data = &m_subtitleStream;
203   m_subtitleStream = CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream;
204
205   if(m_subtitleStream < 0) m_subtitleStream = 0;
206
207   // get the number of audio strams for the current movie
208   setting.max = (float)g_application.m_pPlayer->GetSubtitleCount() - 1;
209
210   // cycle through each subtitle and add it to our entry list
211   for (int i = 0; i <= setting.max; ++i)
212   {
213     SPlayerSubtitleStreamInfo info;
214     g_application.m_pPlayer->GetSubtitleStreamInfo(i, info);
215
216     CStdString strItem;
217     CStdString strLanguage;
218
219     if (!g_LangCodeExpander.Lookup(strLanguage, info.language))
220       strLanguage = g_localizeStrings.Get(13205); // Unknown
221
222     if (info.name.length() == 0)
223       strItem = strLanguage;
224     else
225       strItem.Format("%s - %s", strLanguage.c_str(), info.name.c_str());
226
227     strItem.AppendFormat(" (%i/%i)", i + 1, (int)setting.max + 1);
228
229     setting.entry.push_back(make_pair(setting.entry.size(), strItem));
230   }
231
232   if (setting.max < 0)
233   { // no subtitle streams - just add a "None" entry
234     m_subtitleStream = 0;
235     setting.max = 0;
236     setting.entry.push_back(make_pair(setting.entry.size(), g_localizeStrings.Get(231)));
237   }
238   m_settings.push_back(setting);
239 }
240
241 void CGUIDialogAudioSubtitleSettings::OnSettingChanged(SettingInfo &setting)
242 {
243   // check and update anything that needs it
244   if (setting.id == AUDIO_SETTINGS_VOLUME)
245     g_application.SetVolume(m_volume, false); //false - value is not in percent
246   else if (setting.id == AUDIO_SETTINGS_VOLUME_AMPLIFICATION)
247   {
248     if (g_application.m_pPlayer)
249       g_application.m_pPlayer->SetDynamicRangeCompression((long)(CMediaSettings::Get().GetCurrentVideoSettings().m_VolumeAmplification * 100));
250   }
251   else if (setting.id == AUDIO_SETTINGS_DELAY)
252   {
253     if (g_application.m_pPlayer)
254       g_application.m_pPlayer->SetAVDelay(CMediaSettings::Get().GetCurrentVideoSettings().m_AudioDelay);
255   }
256   else if (setting.id == AUDIO_SETTINGS_STREAM)
257   {
258     // first check if it's a stereo track that we can change between stereo, left and right
259     if (g_application.m_pPlayer->GetAudioStreamCount() == 1)
260     {
261       if (setting.max == 2)
262       { // we're in the case we want - call the code to switch channels etc.
263         // update the screen setting...
264         CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream = -1 - m_audioStream;
265         // call monkeyh1's code here...
266         //bool bAudioOnAllSpeakers = (CSettings::Get().GetInt("audiooutput.mode") == AUDIO_IEC958) && CMediaSettings::Get().GetCurrentVideoSettings().m_OutputToAllSpeakers;
267         return;
268       }
269     }
270     // only change the audio stream if a different one has been asked for
271     if (g_application.m_pPlayer->GetAudioStream() != m_audioStream)
272     {
273       CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream = m_audioStream;
274       g_application.m_pPlayer->SetAudioStream(m_audioStream);    // Set the audio stream to the one selected
275       EnableSettings(AUDIO_SETTINGS_VOLUME, !g_application.m_pPlayer->IsPassthrough());
276     }
277   }
278   else if (setting.id == AUDIO_SETTINGS_OUTPUT_TO_ALL_SPEAKERS)
279   {
280     g_application.Restart();
281   }
282   else if (setting.id == AUDIO_SETTINGS_DIGITAL_ANALOG)
283   {
284     bool bitstream = false;
285
286     switch(m_outputmode)
287     {
288       case 0: CSettings::Get().SetInt("audiooutput.mode", AUDIO_ANALOG ); break;
289       case 1: CSettings::Get().SetInt("audiooutput.mode", AUDIO_IEC958 ); bitstream = true; break;
290       case 2: CSettings::Get().SetInt("audiooutput.mode", AUDIO_HDMI   ); bitstream = true; break;
291     }
292
293     EnableSettings(AUDIO_SETTINGS_OUTPUT_TO_ALL_SPEAKERS, bitstream);
294     g_application.Restart();
295     EnableSettings(AUDIO_SETTINGS_VOLUME, !g_application.m_pPlayer->IsPassthrough());
296   }
297   else if (setting.id == SUBTITLE_SETTINGS_ENABLE)
298   {
299     CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn = m_subtitleVisible;
300     g_application.m_pPlayer->SetSubtitleVisible(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn);
301   }
302   else if (setting.id == SUBTITLE_SETTINGS_DELAY)
303   {
304     g_application.m_pPlayer->SetSubTitleDelay(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleDelay);
305   }
306   else if (setting.id == SUBTITLE_SETTINGS_STREAM && setting.max > 0)
307   {
308     CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream = m_subtitleStream;
309     g_application.m_pPlayer->SetSubtitle(m_subtitleStream);
310   }
311   else if (setting.id == SUBTITLE_SETTINGS_BROWSER)
312   {
313     CStdString strPath;
314     if (URIUtils::IsInRAR(g_application.CurrentFileItem().GetPath()) || URIUtils::IsInZIP(g_application.CurrentFileItem().GetPath()))
315     {
316       CURL url(g_application.CurrentFileItem().GetPath());
317       strPath = url.GetHostName();
318     }
319     else
320       strPath = g_application.CurrentFileItem().GetPath();
321
322     CStdString strMask = ".utf|.utf8|.utf-8|.sub|.srt|.smi|.rt|.txt|.ssa|.aqt|.jss|.ass|.idx|.rar|.zip";
323     if (g_application.GetCurrentPlayer() == EPC_DVDPLAYER)
324       strMask = ".srt|.rar|.zip|.ifo|.smi|.sub|.idx|.ass|.ssa|.txt";
325     VECSOURCES shares(*CMediaSourceSettings::Get().GetSources("video"));
326     if (CMediaSettings::Get().GetAdditionalSubtitleDirectoryChecked() != -1 && !CSettings::Get().GetString("subtitles.custompath").empty())
327     {
328       CMediaSource share;
329       std::vector<CStdString> paths;
330       CStdString strPath1;
331       URIUtils::GetDirectory(strPath,strPath1);
332       paths.push_back(strPath1);
333       strPath1 = CSettings::Get().GetString("subtitles.custompath");
334       paths.push_back(CSettings::Get().GetString("subtitles.custompath"));
335       share.FromNameAndPaths("video",g_localizeStrings.Get(21367),paths);
336       shares.push_back(share);
337       strPath = share.strPath;
338       URIUtils::AddSlashAtEnd(strPath);
339     }
340     if (CGUIDialogFileBrowser::ShowAndGetFile(shares,strMask,g_localizeStrings.Get(293),strPath,false,true)) // "subtitles"
341     {
342       if (URIUtils::HasExtension(strPath, ".sub"))
343         if (CFile::Exists(URIUtils::ReplaceExtension(strPath, ".idx")))
344           strPath = URIUtils::ReplaceExtension(strPath, ".idx");
345       
346       int id = g_application.m_pPlayer->AddSubtitle(strPath);
347       if(id >= 0)
348       {
349         m_subtitleStream = id;
350         g_application.m_pPlayer->SetSubtitle(m_subtitleStream);
351         g_application.m_pPlayer->SetSubtitleVisible(true);
352       }
353       CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleCached = true;
354       Close();
355     }
356   }
357   else if (setting.id == AUDIO_SETTINGS_MAKE_DEFAULT)
358   {
359     if (CProfilesManager::Get().GetCurrentProfile().settingsLocked() &&
360         CProfilesManager::Get().GetMasterProfile().getLockMode() != ::LOCK_MODE_EVERYONE)
361       if (!g_passwordManager.IsMasterLockUnlocked(true))
362         return;
363
364     // prompt user if they are sure
365     if (CGUIDialogYesNo::ShowAndGetInput(12376, 750, 0, 12377))
366     { // reset the settings
367       CVideoDatabase db;
368       db.Open();
369       db.EraseVideoSettings();
370       db.Close();
371       CMediaSettings::Get().GetDefaultVideoSettings() = CMediaSettings::Get().GetCurrentVideoSettings();
372       CMediaSettings::Get().GetDefaultVideoSettings().m_SubtitleStream = -1;
373       CMediaSettings::Get().GetDefaultVideoSettings().m_AudioStream = -1;
374       CSettings::Get().Save();
375     }
376   }
377
378   if (g_PVRManager.IsPlayingRadio() || g_PVRManager.IsPlayingTV())
379     g_PVRManager.TriggerSaveChannelSettings();
380 }
381
382 void CGUIDialogAudioSubtitleSettings::FrameMove()
383 {
384   m_volume = g_application.GetVolume(false);
385   UpdateSetting(AUDIO_SETTINGS_VOLUME);
386   if (g_application.m_pPlayer)
387   {
388     // these settings can change on the fly
389     UpdateSetting(AUDIO_SETTINGS_DELAY);
390     UpdateSetting(SUBTITLE_SETTINGS_ENABLE);
391     UpdateSetting(SUBTITLE_SETTINGS_DELAY);
392   }
393   CGUIDialogSettings::FrameMove();
394 }
395
396 CStdString CGUIDialogAudioSubtitleSettings::PercentAsDecibel(float value, float interval)
397 {
398   CStdString text;
399   text.Format("%2.1f dB", CAEUtil::PercentToGain(value));
400   return text;
401 }
402
403 CStdString CGUIDialogAudioSubtitleSettings::FormatDecibel(float value, float interval)
404 {
405   CStdString text;
406   text.Format("%2.1f dB", value);
407   return text;
408 }
409
410 CStdString CGUIDialogAudioSubtitleSettings::FormatDelay(float value, float interval)
411 {
412   CStdString text;
413   if (fabs(value) < 0.5f*interval)
414     text.Format(g_localizeStrings.Get(22003).c_str(), 0.0);
415   else if (value < 0)
416     text.Format(g_localizeStrings.Get(22004).c_str(), fabs(value));
417   else
418     text.Format(g_localizeStrings.Get(22005).c_str(), value);
419   return text;
420 }
421
422 bool CGUIDialogAudioSubtitleSettings::SupportsAudioFeature(int feature)
423 {
424   for (Features::iterator itr = m_audioCaps.begin(); itr != m_audioCaps.end(); itr++)
425   {
426     if(*itr == feature || *itr == IPC_AUD_ALL)
427       return true;
428   }
429   return false;
430 }
431
432 bool CGUIDialogAudioSubtitleSettings::SupportsSubtitleFeature(int feature)
433 {
434   for (Features::iterator itr = m_subCaps.begin(); itr != m_subCaps.end(); itr++)
435   {
436     if(*itr == feature || *itr == IPC_SUBS_ALL)
437       return true;
438   }
439   return false;
440 }