2 * Copyright (C) 2005-2013 Team XBMC
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.
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.
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
22 * @file StereoscopicsManager.cpp
23 * @brief This class acts as container for stereoscopic related functions
27 #include "StereoscopicsManager.h"
29 #include "Application.h"
30 #include "ApplicationMessenger.h"
31 #include "dialogs/GUIDialogKaiToast.h"
32 #include "dialogs/GUIDialogSelect.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"
47 #include "windowing/WindowingFactory.h"
53 RENDER_STEREO_MODE mode;
56 static const struct StereoModeMap VideoModeToGuiModeMap[] =
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
76 static const struct StereoModeMap StringToGuiModeMap[] =
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 },
95 CStereoscopicsManager::CStereoscopicsManager(void)
97 m_lastStereoMode = RENDER_STEREO_MODE_OFF;
100 CStereoscopicsManager::~CStereoscopicsManager(void)
104 CStereoscopicsManager& CStereoscopicsManager::Get(void)
106 static CStereoscopicsManager sStereoscopicsManager;
107 return sStereoscopicsManager;
110 void CStereoscopicsManager::Initialize(void)
112 m_lastStereoMode = GetStereoMode();
113 // turn off stereo mode on XBMC startup
114 SetStereoMode(RENDER_STEREO_MODE_OFF);
117 RENDER_STEREO_MODE CStereoscopicsManager::GetStereoMode(void)
119 return (RENDER_STEREO_MODE) CSettings::Get().GetInt("videoscreen.stereoscopicmode");
122 void CStereoscopicsManager::SetStereoMode(const RENDER_STEREO_MODE &mode)
124 RENDER_STEREO_MODE currentMode = GetStereoMode();
125 if (mode != currentMode && mode >= RENDER_STEREO_MODE_OFF)
127 if(!g_Windowing.SupportsStereo(mode))
130 m_lastStereoMode = currentMode;
131 CSettings::Get().SetInt("videoscreen.stereoscopicmode", mode);
135 RENDER_STEREO_MODE CStereoscopicsManager::GetNextSupportedStereoMode(const RENDER_STEREO_MODE ¤tMode, int step)
137 RENDER_STEREO_MODE mode = currentMode;
139 mode = (RENDER_STEREO_MODE) ((mode + step) % RENDER_STEREO_MODE_COUNT);
140 if(g_Windowing.SupportsStereo(mode))
142 } while (mode != currentMode);
146 std::string CStereoscopicsManager::DetectStereoModeByString(const std::string &needle)
148 std::string stereoMode;
149 CStdString searchString(needle);
150 CStdStringArray tags;
151 StringUtils::ToUpper(searchString);
153 CStdString tag( g_advancedSettings.m_stereoscopicflags_sbs );
154 if (stereoMode.empty() && !tag.empty())
156 StringUtils::ToUpper(tag);
157 StringUtils::SplitString(tag, "|", tags);
158 if (StringUtils::ContainsKeyword(searchString, tags))
159 stereoMode = "left_right";
162 tag = g_advancedSettings.m_stereoscopicflags_tab;
163 if (stereoMode.empty() && !tag.empty())
165 StringUtils::ToUpper(tag);
166 StringUtils::SplitString(tag, "|", tags);
167 if (StringUtils::ContainsKeyword(searchString, tags))
168 stereoMode = "top_bottom";
171 if (stereoMode.empty())
174 CLog::Log(LOGDEBUG, "StereoscopicsManager: Detected stereo mode in string '%s' is '%s'", CURL::GetRedacted(needle).c_str(), stereoMode.c_str());
179 RENDER_STEREO_MODE CStereoscopicsManager::GetStereoModeByUserChoice(const CStdString &heading)
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();
186 CGUIDialogSelect* pDlgSelect = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
189 pDlgSelect->SetHeading(g_localizeStrings.Get(36528).c_str());
191 pDlgSelect->SetHeading(heading.c_str());
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++)
197 RENDER_STEREO_MODE selectableMode = (RENDER_STEREO_MODE) i;
198 if (g_Windowing.SupportsStereo(selectableMode))
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 );
208 pDlgSelect->DoModal();
210 int iItem = pDlgSelect->GetSelectedLabel();
211 if (iItem > -1 && pDlgSelect->IsConfirmed())
212 mode = (RENDER_STEREO_MODE) selectableModes[iItem];
214 mode = GetStereoMode();
219 RENDER_STEREO_MODE CStereoscopicsManager::GetStereoModeOfPlayingVideo(void)
221 RENDER_STEREO_MODE mode = RENDER_STEREO_MODE_OFF;
223 CStdString playerMode = g_infoManager.GetLabel(VIDEOPLAYER_STEREOSCOPIC_MODE);
224 if (!playerMode.empty())
226 int convertedMode = ConvertVideoToGuiStereoMode(playerMode);
227 if (convertedMode > -1)
228 mode = (RENDER_STEREO_MODE) convertedMode;
231 CLog::Log(LOGDEBUG, "StereoscopicsManager: autodetected GUI stereo mode for movie mode %s is: %s", playerMode.c_str(), GetLabelForStereoMode(mode).c_str());
235 CStdString CStereoscopicsManager::GetLabelForStereoMode(const RENDER_STEREO_MODE &mode)
237 return g_localizeStrings.Get(36502 + mode);
240 RENDER_STEREO_MODE CStereoscopicsManager::GetPreferredPlaybackMode(void)
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
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);
251 else // predefined mode
253 playbackMode = (RENDER_STEREO_MODE) preferredMode;
258 int CStereoscopicsManager::ConvertVideoToGuiStereoMode(const std::string &mode)
261 while (VideoModeToGuiModeMap[i].name)
263 if (mode == VideoModeToGuiModeMap[i].name)
264 return VideoModeToGuiModeMap[i].mode;
270 int CStereoscopicsManager::ConvertStringToGuiStereoMode(const std::string &mode)
273 while (StringToGuiModeMap[i].name)
275 if (mode == StringToGuiModeMap[i].name)
276 return StringToGuiModeMap[i].mode;
279 return ConvertVideoToGuiStereoMode(mode);
282 const char* CStereoscopicsManager::ConvertGuiStereoModeToString(const RENDER_STEREO_MODE &mode)
285 while (StringToGuiModeMap[i].name)
287 if (StringToGuiModeMap[i].mode == mode)
288 return StringToGuiModeMap[i].name;
294 std::string CStereoscopicsManager::NormalizeStereoMode(const std::string &mode)
296 if (!mode.empty() && mode != "mono")
298 int guiMode = ConvertStringToGuiStereoMode(mode);
300 return ConvertGuiStereoModeToString((RENDER_STEREO_MODE) guiMode);
307 CAction CStereoscopicsManager::ConvertActionCommandToAction(const std::string &command, const std::string ¶meter)
309 if (command == "SetStereoMode")
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;
323 // already have a valid actionID return it
325 return CAction(actionId);
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);
331 return CAction(ACTION_NONE);
334 void CStereoscopicsManager::OnSettingChanged(const CSetting *setting)
339 const std::string &settingId = setting->GetId();
341 if (settingId == "videoscreen.stereoscopicmode")
343 RENDER_STEREO_MODE mode = GetStereoMode();
344 CLog::Log(LOGDEBUG, "StereoscopicsManager: stereo mode setting changed to %s", GetLabelForStereoMode(mode).c_str());
345 ApplyStereoMode(mode);
349 bool CStereoscopicsManager::OnMessage(CGUIMessage &message)
351 switch (message.GetMessage())
353 case GUI_MSG_PLAYBACK_STARTED:
356 case GUI_MSG_PLAYBACK_STOPPED:
357 case GUI_MSG_PLAYLISTPLAYER_STOPPED:
365 bool CStereoscopicsManager::OnAction(const CAction &action)
367 RENDER_STEREO_MODE mode = GetStereoMode();
369 if (action.GetID() == ACTION_STEREOMODE_NEXT)
371 SetStereoMode(GetNextSupportedStereoMode(mode));
374 else if (action.GetID() == ACTION_STEREOMODE_PREVIOUS)
376 SetStereoMode(GetNextSupportedStereoMode(mode, RENDER_STEREO_MODE_COUNT - 1));
379 else if (action.GetID() == ACTION_STEREOMODE_TOGGLE)
381 if (mode == RENDER_STEREO_MODE_OFF)
383 RENDER_STEREO_MODE targetMode = m_lastStereoMode;
384 if (targetMode == RENDER_STEREO_MODE_OFF)
385 targetMode = GetPreferredPlaybackMode();
386 SetStereoMode(targetMode);
390 SetStereoMode(RENDER_STEREO_MODE_OFF);
394 else if (action.GetID() == ACTION_STEREOMODE_SELECT)
396 SetStereoMode(GetStereoModeByUserChoice());
399 else if (action.GetID() == ACTION_STEREOMODE_TOMONO)
401 if (mode == RENDER_STEREO_MODE_MONO)
403 RENDER_STEREO_MODE targetMode = m_lastStereoMode;
404 if (targetMode == RENDER_STEREO_MODE_OFF)
405 targetMode = GetPreferredPlaybackMode();
406 SetStereoMode(targetMode);
410 SetStereoMode(RENDER_STEREO_MODE_MONO);
413 else if (action.GetID() == ACTION_STEREOMODE_SET)
415 int stereoMode = ConvertStringToGuiStereoMode(action.GetName());
417 SetStereoMode( (RENDER_STEREO_MODE) stereoMode);
423 void CStereoscopicsManager::ApplyStereoMode(const RENDER_STEREO_MODE &mode, bool notify)
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)
429 g_graphicsContext.SetStereoMode(mode);
430 CLog::Log(LOGDEBUG, "StereoscopicsManager: stereo mode changed to %s", GetLabelForStereoMode(mode).c_str());
432 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(36501), GetLabelForStereoMode(mode));
436 void CStereoscopicsManager::OnPlaybackStarted(void)
438 if (!g_infoManager.EvaluateBool("videoplayer.isstereoscopic"))
441 // only change stereo mode if not yet in stereo mode
442 RENDER_STEREO_MODE mode = GetStereoMode();
443 if (mode != RENDER_STEREO_MODE_OFF)
446 int playbackMode = CSettings::Get().GetInt("videoplayer.stereoscopicplaybackmode");
447 switch (playbackMode)
451 CApplicationMessenger::Get().MediaPause();
453 CGUIDialogSelect* pDlgSelect = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
455 pDlgSelect->SetHeading(g_localizeStrings.Get(36527).c_str());
457 RENDER_STEREO_MODE preferred = GetPreferredPlaybackMode();
458 RENDER_STEREO_MODE playing = GetStereoModeOfPlayingVideo();
465 int idx_preferred = pDlgSelect->Add( g_localizeStrings.Get(36530)
467 + GetLabelForStereoMode(preferred)
470 if(preferred != RENDER_STEREO_MODE_MONO)
471 idx_mono = pDlgSelect->Add( g_localizeStrings.Get(36529) ); // mono / 2d
474 if(playing != RENDER_STEREO_MODE_OFF && g_Windowing.SupportsStereo(playing))
475 idx_playing = pDlgSelect->Add( g_localizeStrings.Get(36532)
477 + GetLabelForStereoMode(playing)
480 int idx_select = pDlgSelect->Add( g_localizeStrings.Get(36531) ); // other / select
482 pDlgSelect->DoModal();
484 if(pDlgSelect->IsConfirmed())
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();
495 CApplicationMessenger::Get().MediaUnPause();
498 case 1: // Stereoscopic
499 SetStereoMode( GetPreferredPlaybackMode() );
506 void CStereoscopicsManager::OnPlaybackStopped(void)
508 RENDER_STEREO_MODE mode = GetStereoMode();
509 if (CSettings::Get().GetBool("videoplayer.quitstereomodeonstop") == true && mode != RENDER_STEREO_MODE_OFF)
511 SetStereoMode(RENDER_STEREO_MODE_OFF);