[release] version bump to 13.0 beta1
[vuplus_xbmc] / xbmc / guilib / StereoscopicsManager.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2.1 of the License, or (at your option) any later version.
9  *
10  *  This library 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 GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20
21 /*!
22  * @file StereoscopicsManager.cpp
23  * @brief This class acts as container for stereoscopic related functions
24  */
25
26 #include <stdlib.h>
27 #include "StereoscopicsManager.h"
28
29 #include "Application.h"
30 #include "ApplicationMessenger.h"
31 #include "dialogs/GUIDialogKaiToast.h"
32 #include "dialogs/GUIDialogSelect.h"
33 #include "FileItem.h"
34 #include "GUIInfoManager.h"
35 #include "GUIUserMessages.h"
36 #include "guilib/LocalizeStrings.h"
37 #include "guilib/Key.h"
38 #include "guilib/GUIWindowManager.h"
39 #include "settings/AdvancedSettings.h"
40 #include "settings/lib/ISettingCallback.h"
41 #include "settings/lib/Setting.h"
42 #include "settings/Settings.h"
43 #include "rendering/RenderSystem.h"
44 #include "utils/log.h"
45 #include "utils/StringUtils.h"
46 #include "URL.h"
47 #include "windowing/WindowingFactory.h"
48
49
50 struct StereoModeMap
51 {
52   const char*          name;
53   RENDER_STEREO_MODE   mode;
54 };
55
56 static const struct StereoModeMap VideoModeToGuiModeMap[] =
57 {
58   { "mono",                     RENDER_STEREO_MODE_OFF },
59   { "left_right",               RENDER_STEREO_MODE_SPLIT_VERTICAL },
60   { "right_left",               RENDER_STEREO_MODE_SPLIT_VERTICAL },
61   { "top_bottom",               RENDER_STEREO_MODE_SPLIT_HORIZONTAL },
62   { "bottom_top",               RENDER_STEREO_MODE_SPLIT_HORIZONTAL },
63   { "checkerboard_rl",          RENDER_STEREO_MODE_OFF }, // unsupported
64   { "checkerboard_lr",          RENDER_STEREO_MODE_OFF }, // unsupported
65   { "row_interleaved_rl",       RENDER_STEREO_MODE_INTERLACED },
66   { "row_interleaved_lr",       RENDER_STEREO_MODE_INTERLACED },
67   { "col_interleaved_rl",       RENDER_STEREO_MODE_OFF }, // unsupported
68   { "col_interleaved_lr",       RENDER_STEREO_MODE_OFF }, // unsupported
69   { "anaglyph_cyan_red",        RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN },
70   { "anaglyph_green_magenta",   RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA },
71   { "block_lr",                 RENDER_STEREO_MODE_OFF }, // unsupported
72   { "block_rl",                 RENDER_STEREO_MODE_OFF }, // unsupported
73   {}
74 };
75
76 static const struct StereoModeMap StringToGuiModeMap[] =
77 {
78   { "off",                      RENDER_STEREO_MODE_OFF },
79   { "split_vertical",           RENDER_STEREO_MODE_SPLIT_VERTICAL },
80   { "side_by_side",             RENDER_STEREO_MODE_SPLIT_VERTICAL }, // alias
81   { "sbs",                      RENDER_STEREO_MODE_SPLIT_VERTICAL }, // alias
82   { "split_horizontal",         RENDER_STEREO_MODE_SPLIT_HORIZONTAL },
83   { "over_under",               RENDER_STEREO_MODE_SPLIT_HORIZONTAL }, // alias
84   { "tab",                      RENDER_STEREO_MODE_SPLIT_HORIZONTAL }, // alias
85   { "row_interleaved",          RENDER_STEREO_MODE_INTERLACED },
86   { "interlaced",               RENDER_STEREO_MODE_INTERLACED }, // alias
87   { "anaglyph_cyan_red",        RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN },
88   { "anaglyph_green_magenta",   RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA },
89   { "hardware_based",           RENDER_STEREO_MODE_HARDWAREBASED },
90   { "monoscopic",               RENDER_STEREO_MODE_MONO },
91   {}
92 };
93
94
95 CStereoscopicsManager::CStereoscopicsManager(void)
96 {
97   m_lastStereoMode = RENDER_STEREO_MODE_OFF;
98 }
99
100 CStereoscopicsManager::~CStereoscopicsManager(void)
101 {
102 }
103
104 CStereoscopicsManager& CStereoscopicsManager::Get(void)
105 {
106   static CStereoscopicsManager sStereoscopicsManager;
107   return sStereoscopicsManager;
108 }
109
110 void CStereoscopicsManager::Initialize(void)
111 {
112   m_lastStereoMode = GetStereoMode();
113   // turn off stereo mode on XBMC startup
114   SetStereoMode(RENDER_STEREO_MODE_OFF);
115 }
116
117 RENDER_STEREO_MODE CStereoscopicsManager::GetStereoMode(void)
118 {
119   return (RENDER_STEREO_MODE) CSettings::Get().GetInt("videoscreen.stereoscopicmode");
120 }
121
122 void CStereoscopicsManager::SetStereoMode(const RENDER_STEREO_MODE &mode)
123 {
124   RENDER_STEREO_MODE currentMode = GetStereoMode();
125   if (mode != currentMode && mode >= RENDER_STEREO_MODE_OFF)
126   {
127     if(!g_Windowing.SupportsStereo(mode))
128       return;
129
130     m_lastStereoMode = currentMode;
131     CSettings::Get().SetInt("videoscreen.stereoscopicmode", mode);
132   }
133 }
134
135 RENDER_STEREO_MODE CStereoscopicsManager::GetNextSupportedStereoMode(const RENDER_STEREO_MODE &currentMode, int step)
136 {
137   RENDER_STEREO_MODE mode = currentMode;
138   do {
139     mode = (RENDER_STEREO_MODE) ((mode + step) % RENDER_STEREO_MODE_COUNT);
140     if(g_Windowing.SupportsStereo(mode))
141       break;
142    } while (mode != currentMode);
143   return mode;
144 }
145
146 std::string CStereoscopicsManager::DetectStereoModeByString(const std::string &needle)
147 {
148   std::string stereoMode;
149   CStdString searchString(needle);
150   CStdStringArray tags;
151   StringUtils::ToUpper(searchString);
152
153   CStdString tag( g_advancedSettings.m_stereoscopicflags_sbs );
154   if (stereoMode.empty() && !tag.empty())
155   {
156     StringUtils::ToUpper(tag);
157     StringUtils::SplitString(tag, "|", tags);
158     if (StringUtils::ContainsKeyword(searchString, tags))
159       stereoMode = "left_right";
160   }
161
162   tag = g_advancedSettings.m_stereoscopicflags_tab;
163   if (stereoMode.empty() && !tag.empty())
164   {
165     StringUtils::ToUpper(tag);
166     StringUtils::SplitString(tag, "|", tags);
167     if (StringUtils::ContainsKeyword(searchString, tags))
168       stereoMode = "top_bottom";
169   }
170
171   if (stereoMode.empty())
172     stereoMode = "mono";
173   else
174     CLog::Log(LOGDEBUG, "StereoscopicsManager: Detected stereo mode in string '%s' is '%s'", CURL::GetRedacted(needle).c_str(), stereoMode.c_str());
175
176   return stereoMode;
177 }
178
179 RENDER_STEREO_MODE CStereoscopicsManager::GetStereoModeByUserChoice(const CStdString &heading)
180 {
181   RENDER_STEREO_MODE mode = GetStereoMode();
182   // if no stereo mode is set already, suggest mode of current video by preselecting it
183   if (mode == RENDER_STEREO_MODE_OFF && g_infoManager.EvaluateBool("videoplayer.isstereoscopic"))
184     mode = GetStereoModeOfPlayingVideo();
185
186   CGUIDialogSelect* pDlgSelect = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
187   pDlgSelect->Reset();
188   if (heading.empty())
189     pDlgSelect->SetHeading(g_localizeStrings.Get(36528).c_str());
190   else
191     pDlgSelect->SetHeading(heading.c_str());
192
193   // prepare selectable stereo modes
194   std::vector<RENDER_STEREO_MODE> selectableModes;
195   for (int i = RENDER_STEREO_MODE_OFF; i < RENDER_STEREO_MODE_COUNT; i++)
196   {
197     RENDER_STEREO_MODE selectableMode = (RENDER_STEREO_MODE) i;
198     if (g_Windowing.SupportsStereo(selectableMode))
199     {
200       selectableModes.push_back(selectableMode);
201       CStdString label = g_localizeStrings.Get(36502+i);
202       pDlgSelect->Add( label );
203       if (mode == selectableMode)
204         pDlgSelect->SetSelected( label );
205     }
206   }
207
208   pDlgSelect->DoModal();
209
210   int iItem = pDlgSelect->GetSelectedLabel();
211   if (iItem > -1 && pDlgSelect->IsConfirmed())
212     mode = (RENDER_STEREO_MODE) selectableModes[iItem];
213   else
214     mode = GetStereoMode();
215
216   return mode;
217 }
218
219 RENDER_STEREO_MODE CStereoscopicsManager::GetStereoModeOfPlayingVideo(void)
220 {
221   RENDER_STEREO_MODE mode = RENDER_STEREO_MODE_OFF;
222
223   CStdString playerMode = g_infoManager.GetLabel(VIDEOPLAYER_STEREOSCOPIC_MODE);
224   if (!playerMode.empty())
225   {
226     int convertedMode = ConvertVideoToGuiStereoMode(playerMode);
227     if (convertedMode > -1)
228       mode = (RENDER_STEREO_MODE) convertedMode;
229   }
230
231   CLog::Log(LOGDEBUG, "StereoscopicsManager: autodetected GUI stereo mode for movie mode %s is: %s", playerMode.c_str(), GetLabelForStereoMode(mode).c_str());
232   return mode;
233 }
234
235 CStdString CStereoscopicsManager::GetLabelForStereoMode(const RENDER_STEREO_MODE &mode)
236 {
237   return g_localizeStrings.Get(36502 + mode);
238 }
239
240 RENDER_STEREO_MODE CStereoscopicsManager::GetPreferredPlaybackMode(void)
241 {
242   RENDER_STEREO_MODE playbackMode = m_lastStereoMode;
243   int preferredMode = CSettings::Get().GetInt("videoscreen.preferedstereoscopicmode");
244   if (preferredMode == RENDER_STEREO_MODE_AUTO) // automatic mode, detect by movie
245   {
246     if (g_infoManager.EvaluateBool("videoplayer.isstereoscopic"))
247       playbackMode = GetStereoModeOfPlayingVideo();
248     else if (playbackMode == RENDER_STEREO_MODE_OFF)
249       playbackMode = GetNextSupportedStereoMode(RENDER_STEREO_MODE_OFF);
250   }
251   else // predefined mode
252   {
253     playbackMode = (RENDER_STEREO_MODE) preferredMode;
254   }
255   return playbackMode;
256 }
257
258 int CStereoscopicsManager::ConvertVideoToGuiStereoMode(const std::string &mode)
259 {
260   size_t i = 0;
261   while (VideoModeToGuiModeMap[i].name)
262   {
263     if (mode == VideoModeToGuiModeMap[i].name)
264       return VideoModeToGuiModeMap[i].mode;
265     i++;
266   }
267   return -1;
268 }
269
270 int CStereoscopicsManager::ConvertStringToGuiStereoMode(const std::string &mode)
271 {
272   size_t i = 0;
273   while (StringToGuiModeMap[i].name)
274   {
275     if (mode == StringToGuiModeMap[i].name)
276       return StringToGuiModeMap[i].mode;
277     i++;
278   }
279   return ConvertVideoToGuiStereoMode(mode);
280 }
281
282 const char* CStereoscopicsManager::ConvertGuiStereoModeToString(const RENDER_STEREO_MODE &mode)
283 {
284   size_t i = 0;
285   while (StringToGuiModeMap[i].name)
286   {
287     if (StringToGuiModeMap[i].mode == mode)
288       return StringToGuiModeMap[i].name;
289     i++;
290   }
291   return "";
292 }
293
294 std::string CStereoscopicsManager::NormalizeStereoMode(const std::string &mode)
295 {
296   if (!mode.empty() && mode != "mono")
297   {
298     int guiMode = ConvertStringToGuiStereoMode(mode);
299     if (guiMode > -1)
300       return ConvertGuiStereoModeToString((RENDER_STEREO_MODE) guiMode);
301     else
302       return mode;
303   }
304   return "mono";
305 }
306
307 CAction CStereoscopicsManager::ConvertActionCommandToAction(const std::string &command, const std::string &parameter)
308 {
309   if (command == "SetStereoMode")
310   {
311     int actionId = -1;
312     if (parameter == "next")
313       actionId = ACTION_STEREOMODE_NEXT;
314     else if (parameter == "previous")
315       actionId = ACTION_STEREOMODE_PREVIOUS;
316     else if (parameter == "toggle")
317       actionId = ACTION_STEREOMODE_TOGGLE;
318     else if (parameter == "select")
319       actionId = ACTION_STEREOMODE_SELECT;
320     else if (parameter == "tomono")
321       actionId = ACTION_STEREOMODE_TOMONO;
322
323     // already have a valid actionID return it
324     if (actionId > -1)
325       return CAction(actionId);
326
327     // still no valid action ID, check if parameter is a supported stereomode
328     if (ConvertStringToGuiStereoMode(parameter) > -1)
329       return CAction(ACTION_STEREOMODE_SET, parameter);
330   }
331   return CAction(ACTION_NONE);
332 }
333
334 void CStereoscopicsManager::OnSettingChanged(const CSetting *setting)
335 {
336   if (setting == NULL)
337     return;
338
339   const std::string &settingId = setting->GetId();
340
341   if (settingId == "videoscreen.stereoscopicmode")
342   {
343     RENDER_STEREO_MODE mode = GetStereoMode();
344     CLog::Log(LOGDEBUG, "StereoscopicsManager: stereo mode setting changed to %s", GetLabelForStereoMode(mode).c_str());
345     ApplyStereoMode(mode);
346   }
347 }
348
349 bool CStereoscopicsManager::OnMessage(CGUIMessage &message)
350 {
351   switch (message.GetMessage())
352   {
353   case GUI_MSG_PLAYBACK_STARTED:
354     OnPlaybackStarted();
355     break;
356   case GUI_MSG_PLAYBACK_STOPPED:
357   case GUI_MSG_PLAYLISTPLAYER_STOPPED:
358     OnPlaybackStopped();
359     break;
360   }
361
362   return false;
363 }
364
365 bool CStereoscopicsManager::OnAction(const CAction &action)
366 {
367   RENDER_STEREO_MODE mode = GetStereoMode();
368
369   if (action.GetID() == ACTION_STEREOMODE_NEXT)
370   {
371     SetStereoMode(GetNextSupportedStereoMode(mode));
372     return true;
373   }
374   else if (action.GetID() == ACTION_STEREOMODE_PREVIOUS)
375   {
376     SetStereoMode(GetNextSupportedStereoMode(mode, RENDER_STEREO_MODE_COUNT - 1));
377     return true;
378   }
379   else if (action.GetID() == ACTION_STEREOMODE_TOGGLE)
380   {
381     if (mode == RENDER_STEREO_MODE_OFF)
382     {
383       RENDER_STEREO_MODE targetMode = m_lastStereoMode;
384       if (targetMode == RENDER_STEREO_MODE_OFF)
385         targetMode = GetPreferredPlaybackMode();
386       SetStereoMode(targetMode);
387     }
388     else
389     {
390       SetStereoMode(RENDER_STEREO_MODE_OFF);
391     }
392     return true;
393   }
394   else if (action.GetID() == ACTION_STEREOMODE_SELECT)
395   {
396     SetStereoMode(GetStereoModeByUserChoice());
397     return true;
398   }
399   else if (action.GetID() == ACTION_STEREOMODE_TOMONO)
400   {
401     if (mode == RENDER_STEREO_MODE_MONO)
402     {
403       RENDER_STEREO_MODE targetMode = m_lastStereoMode;
404       if (targetMode == RENDER_STEREO_MODE_OFF)
405         targetMode = GetPreferredPlaybackMode();
406       SetStereoMode(targetMode);
407     }
408     else
409     {
410       SetStereoMode(RENDER_STEREO_MODE_MONO);
411     }
412   }
413   else if (action.GetID() == ACTION_STEREOMODE_SET)
414   {
415     int stereoMode = ConvertStringToGuiStereoMode(action.GetName());
416     if (stereoMode > -1)
417       SetStereoMode( (RENDER_STEREO_MODE) stereoMode);
418   }
419
420   return false;
421 }
422
423 void CStereoscopicsManager::ApplyStereoMode(const RENDER_STEREO_MODE &mode, bool notify)
424 {
425   RENDER_STEREO_MODE currentMode = g_graphicsContext.GetStereoMode();
426   CLog::Log(LOGDEBUG, "StereoscopicsManager::ApplyStereoMode: trying to apply stereo mode. Current: %s | Target: %s", GetLabelForStereoMode(currentMode).c_str(), GetLabelForStereoMode(mode).c_str());
427   if (currentMode != mode)
428   {
429     g_graphicsContext.SetStereoMode(mode);
430     CLog::Log(LOGDEBUG, "StereoscopicsManager: stereo mode changed to %s", GetLabelForStereoMode(mode).c_str());
431     if (notify)
432       CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(36501), GetLabelForStereoMode(mode));
433   }
434 }
435
436 void CStereoscopicsManager::OnPlaybackStarted(void)
437 {
438   if (!g_infoManager.EvaluateBool("videoplayer.isstereoscopic"))
439     return;
440
441   // only change stereo mode if not yet in stereo mode
442   RENDER_STEREO_MODE mode = GetStereoMode();
443   if (mode != RENDER_STEREO_MODE_OFF)
444     return;
445
446   int playbackMode = CSettings::Get().GetInt("videoplayer.stereoscopicplaybackmode");
447   switch (playbackMode)
448   {
449   case 0: // Ask
450     {
451       CApplicationMessenger::Get().MediaPause();
452
453       CGUIDialogSelect* pDlgSelect = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
454       pDlgSelect->Reset();
455       pDlgSelect->SetHeading(g_localizeStrings.Get(36527).c_str());
456
457       RENDER_STEREO_MODE preferred = GetPreferredPlaybackMode();
458       RENDER_STEREO_MODE playing   = GetStereoModeOfPlayingVideo();
459
460       int idx_playing   = -1
461         , idx_mono      = -1;
462         
463
464       // add choices
465       int idx_preferred = pDlgSelect->Add( g_localizeStrings.Get(36530)
466                                      + " ("
467                                      + GetLabelForStereoMode(preferred)
468                                      + ")");
469
470       if(preferred != RENDER_STEREO_MODE_MONO)
471         idx_mono = pDlgSelect->Add( g_localizeStrings.Get(36529) ); // mono / 2d
472
473
474       if(playing != RENDER_STEREO_MODE_OFF && g_Windowing.SupportsStereo(playing))
475         idx_playing = pDlgSelect->Add( g_localizeStrings.Get(36532)
476                                     + " ("
477                                     + GetLabelForStereoMode(playing)
478                                     + ")");
479
480       int idx_select = pDlgSelect->Add( g_localizeStrings.Get(36531) ); // other / select
481
482       pDlgSelect->DoModal();
483
484       if(pDlgSelect->IsConfirmed())
485       {
486         int iItem = pDlgSelect->GetSelectedLabel();
487         if      (iItem == idx_preferred) mode = preferred;
488         else if (iItem == idx_mono)      mode = RENDER_STEREO_MODE_MONO;
489         else if (iItem == idx_playing)   mode = playing;
490         else if (iItem == idx_select)    mode = GetStereoModeByUserChoice();
491
492         SetStereoMode(mode);
493       }
494
495       CApplicationMessenger::Get().MediaUnPause();
496     }
497     break;
498   case 1: // Stereoscopic
499     SetStereoMode( GetPreferredPlaybackMode() );
500     break;
501   default:
502     break;
503   }
504 }
505
506 void CStereoscopicsManager::OnPlaybackStopped(void)
507 {
508   RENDER_STEREO_MODE mode = GetStereoMode();
509   if (CSettings::Get().GetBool("videoplayer.quitstereomodeonstop") == true && mode != RENDER_STEREO_MODE_OFF)
510   {
511     SetStereoMode(RENDER_STEREO_MODE_OFF);
512   }
513 }