Skip to content

Commit

Permalink
refactor resolution switching - WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
FernetMenta committed Sep 20, 2015
1 parent 411303b commit 6071f8e
Show file tree
Hide file tree
Showing 6 changed files with 336 additions and 280 deletions.
8 changes: 8 additions & 0 deletions Kodi.xcodeproj/project.pbxproj
Expand Up @@ -443,6 +443,9 @@
7C973CFB1B5038580002A874 /* GUIDialogAudioDSPSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C973CF81B5038580002A874 /* GUIDialogAudioDSPSettings.cpp */; };
7C99B6A4133D342100FC2B16 /* CircularCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C99B6A2133D342100FC2B16 /* CircularCache.cpp */; };
7C99B7951340723F00FC2B16 /* GUIDialogPlayEject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C99B7931340723F00FC2B16 /* GUIDialogPlayEject.cpp */; };
7CA1E0EA1BADE1A7008A3F86 /* Resolution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CA1E0E91BADE1A7008A3F86 /* Resolution.cpp */; settings = {ASSET_TAGS = (); }; };
7CA1E0EB1BADE1A7008A3F86 /* Resolution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CA1E0E91BADE1A7008A3F86 /* Resolution.cpp */; settings = {ASSET_TAGS = (); }; };
7CA1E0EC1BADE1A7008A3F86 /* Resolution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CA1E0E91BADE1A7008A3F86 /* Resolution.cpp */; settings = {ASSET_TAGS = (); }; };
7CAA25351085963B0096DE39 /* PasswordManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CAA25331085963B0096DE39 /* PasswordManager.cpp */; };
7CAA469019427AED00008885 /* PosixDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CAA468E19427AED00008885 /* PosixDirectory.cpp */; };
7CAA469119427AED00008885 /* PosixDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CAA468E19427AED00008885 /* PosixDirectory.cpp */; };
Expand Down Expand Up @@ -3940,6 +3943,7 @@
7C99B6A3133D342100FC2B16 /* CircularCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircularCache.h; sourceTree = "<group>"; };
7C99B7931340723F00FC2B16 /* GUIDialogPlayEject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogPlayEject.cpp; sourceTree = "<group>"; };
7C99B7941340723F00FC2B16 /* GUIDialogPlayEject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogPlayEject.h; sourceTree = "<group>"; };
7CA1E0E91BADE1A7008A3F86 /* Resolution.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Resolution.cpp; sourceTree = "<group>"; };
7CAA205B107AFC280096DE39 /* Job.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Job.h; sourceTree = "<group>"; };
7CAA25331085963B0096DE39 /* PasswordManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PasswordManager.cpp; sourceTree = "<group>"; };
7CAA25341085963B0096DE39 /* PasswordManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PasswordManager.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -6138,6 +6142,7 @@
18B7C3AA1294219F009E7A26 /* guilib */ = {
isa = PBXGroup;
children = (
7CA1E0E91BADE1A7008A3F86 /* Resolution.cpp */,
391416BE1B4A3EFA00BBF0AA /* guiinfo */,
DF404A3416B9896C00D8023E /* cximage.cpp */,
DF404A3516B9896C00D8023E /* cximage.h */,
Expand Down Expand Up @@ -10843,6 +10848,7 @@
E4DC97550FFE5BA8008E0C07 /* SAPFile.cpp in Sources */,
7CDAEA7D1001CD6E0040B25F /* karaokelyricstextustar.cpp in Sources */,
E49ACD8C100745C400A86ECD /* ZeroconfDirectory.cpp in Sources */,
7CA1E0EA1BADE1A7008A3F86 /* Resolution.cpp in Sources */,
B5101B5819DFF8DD00294D1E /* BlurayFile.cpp in Sources */,
E49ACD9F10074A4000A86ECD /* ZeroconfBrowserOSX.cpp in Sources */,
DF6F52AE1AF6D03F001BC57D /* dacp.cpp in Sources */,
Expand Down Expand Up @@ -11893,6 +11899,7 @@
DFF0F27617528350002DA3A4 /* DirtyRegionSolvers.cpp in Sources */,
DFF0F27717528350002DA3A4 /* DirtyRegionTracker.cpp in Sources */,
DFF0F27817528350002DA3A4 /* FrameBufferObject.cpp in Sources */,
7CA1E0EC1BADE1A7008A3F86 /* Resolution.cpp in Sources */,
DFF0F27917528350002DA3A4 /* GraphicContext.cpp in Sources */,
DFF0F27A17528350002DA3A4 /* GUIAction.cpp in Sources */,
DFF0F27B17528350002DA3A4 /* GUIAudioManager.cpp in Sources */,
Expand Down Expand Up @@ -13030,6 +13037,7 @@
E499130A174E5DAD00741B6D /* GUIRenderingControl.cpp in Sources */,
E499130B174E5DAD00741B6D /* GUIResizeControl.cpp in Sources */,
395897161AAD94F00033D27C /* KeyboardLayoutManager.cpp in Sources */,
7CA1E0EB1BADE1A7008A3F86 /* Resolution.cpp in Sources */,
395C2A251AA4C32100EBC7AD /* AudioDecoder.cpp in Sources */,
E499130C174E5DAD00741B6D /* GUIRSSControl.cpp in Sources */,
E499130D174E5DAD00741B6D /* GUIScrollBarControl.cpp in Sources */,
Expand Down
248 changes: 3 additions & 245 deletions xbmc/cores/VideoPlayer/VideoRenderers/BaseRenderer.cpp
Expand Up @@ -80,263 +80,21 @@ void CBaseRenderer::RegisterRenderFeaturesCallBack(const void *ctx, RenderFeatur

void CBaseRenderer::ChooseBestResolution(float fps)
{
if (fps == 0.0) return;
if (fps == 0.0)
return;

// Adjust refreshrate to match source fps
#if !defined(TARGET_DARWIN_IOS)
if (CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE) != ADJUST_REFRESHRATE_OFF)
{
float weight;
if (!FindResolutionFromOverride(fps, weight, false)) //find a refreshrate from overrides
{
if (!FindResolutionFromOverride(fps, weight, true))//if that fails find it from a fallback
FindResolutionFromFpsMatch(fps, weight);//if that fails use automatic refreshrate selection
}

CLog::Log(LOGNOTICE, "Display resolution ADJUST : %s (%d) (weight: %.3f)",
g_graphicsContext.GetResInfo(m_resolution).strMode.c_str(), m_resolution, weight);
m_resolution = CResolutionUtils::ChooseBestResolution(fps, m_sourceWidth, CONF_FLAGS_STEREO_MODE_MASK(m_iFlags));
}
else
#endif
CLog::Log(LOGNOTICE, "Display resolution %s : %s (%d)",
m_resolution == RES_DESKTOP ? "DESKTOP" : "USER", g_graphicsContext.GetResInfo(m_resolution).strMode.c_str(), m_resolution);
}

bool CBaseRenderer::FindResolutionFromOverride(float fps, float& weight, bool fallback)
{
RESOLUTION_INFO curr = g_graphicsContext.GetResInfo(m_resolution);

//try to find a refreshrate from the override
for (int i = 0; i < (int)g_advancedSettings.m_videoAdjustRefreshOverrides.size(); i++)
{
RefreshOverride& override = g_advancedSettings.m_videoAdjustRefreshOverrides[i];

if (override.fallback != fallback)
continue;

//if we're checking for overrides, check if the fps matches
if (!fallback && (fps < override.fpsmin || fps > override.fpsmax))
continue;

for (size_t j = (int)RES_DESKTOP; j < CDisplaySettings::GetInstance().ResolutionInfoSize(); j++)
{
RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)j);

if (info.iScreenWidth == curr.iScreenWidth
&& info.iScreenHeight == curr.iScreenHeight
&& (info.dwFlags & D3DPRESENTFLAG_MODEMASK) == (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)
&& info.iScreen == curr.iScreen)
{
if (info.fRefreshRate <= override.refreshmax
&& info.fRefreshRate >= override.refreshmin)
{
m_resolution = (RESOLUTION)j;

if (fallback)
{
CLog::Log(LOGDEBUG, "Found Resolution %s (%d) from fallback (refreshmin:%.3f refreshmax:%.3f)",
info.strMode.c_str(), m_resolution,
override.refreshmin, override.refreshmax);
}
else
{
CLog::Log(LOGDEBUG, "Found Resolution %s (%d) from override of fps %.3f (fpsmin:%.3f fpsmax:%.3f refreshmin:%.3f refreshmax:%.3f)",
info.strMode.c_str(), m_resolution, fps,
override.fpsmin, override.fpsmax, override.refreshmin, override.refreshmax);
}

weight = RefreshWeight(info.fRefreshRate, fps);

return true; //fps and refresh match with this override, use this resolution
}
}
}
}

return false; //no override found
}

void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight)
{
const float maxWeight = 0.0021f;
RESOLUTION_INFO curr;

m_resolution = FindClosestResolution(fps, 1.0, m_resolution, weight);
curr = g_graphicsContext.GetResInfo(m_resolution);

if (weight >= maxWeight) //not a very good match, try a 2:3 cadence instead
{
CLog::Log(LOGDEBUG, "Resolution %s (%d) not a very good match for fps %.3f (weight: %.3f), trying 2:3 cadence",
curr.strMode.c_str(), m_resolution, fps, weight);

m_resolution = FindClosestResolution(fps, 2.5, m_resolution, weight);
curr = g_graphicsContext.GetResInfo(m_resolution);

if (weight >= maxWeight) //2:3 cadence not a good match
{
CLog::Log(LOGDEBUG, "Resolution %s (%d) not a very good match for fps %.3f with 2:3 cadence (weight: %.3f), choosing 60 hertz",
curr.strMode.c_str(), m_resolution, fps, weight);

//get the resolution with the refreshrate closest to 60 hertz
for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::GetInstance().ResolutionInfoSize(); i++)
{
RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);

if (MathUtils::round_int(info.fRefreshRate) == 60
&& info.iScreenWidth == curr.iScreenWidth
&& info.iScreenHeight == curr.iScreenHeight
&& (info.dwFlags & D3DPRESENTFLAG_MODEMASK) == (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)
&& info.iScreen == curr.iScreen)
{
if (fabs(info.fRefreshRate - 60.0) < fabs(curr.fRefreshRate - 60.0)) {
m_resolution = (RESOLUTION)i;
curr = info;
}
}
}

//60 hertz not available, get the highest refreshrate
if (MathUtils::round_int(curr.fRefreshRate) != 60)
{
CLog::Log(LOGDEBUG, "60 hertz refreshrate not available, choosing highest");
for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::GetInstance().ResolutionInfoSize(); i++)
{
RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);

if (info.fRefreshRate > curr.fRefreshRate
&& info.iScreenWidth == curr.iScreenWidth
&& info.iScreenHeight == curr.iScreenHeight
&& (info.dwFlags & D3DPRESENTFLAG_MODEMASK) == (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)
&& info.iScreen == curr.iScreen)
{
m_resolution = (RESOLUTION)i;
curr = info;
}
}
}

weight = RefreshWeight(curr.fRefreshRate, fps);
}
}
}

RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RESOLUTION current, float& weight)
{
RESOLUTION_INFO curr = g_graphicsContext.GetResInfo(current);
RESOLUTION orig_res = CDisplaySettings::GetInstance().GetCurrentResolution();

if (orig_res <= RES_DESKTOP)
orig_res = RES_DESKTOP;

RESOLUTION_INFO orig = g_graphicsContext.GetResInfo(orig_res);

float fRefreshRate = fps;

float last_diff = fRefreshRate;

int curr_diff = std::abs((int) m_sourceWidth - curr.iScreenWidth);
int loop_diff = 0;

// Find closest refresh rate
for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::GetInstance().ResolutionInfoSize(); i++)
{
const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);

//discard resolutions that are not the same width and height (and interlaced/3D flags)
//or have a too low refreshrate
if (info.iScreenWidth != curr.iScreenWidth
|| info.iScreenHeight != curr.iScreenHeight
|| info.iScreen != curr.iScreen
|| (info.dwFlags & D3DPRESENTFLAG_MODEMASK) != (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)
|| info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001)
{
// evaluate all higher modes and evalute them
// concerning dimension and refreshrate weight
// skip lower resolutions
if (((int) m_sourceWidth < orig.iScreenWidth) // orig res large enough
|| (info.iScreenWidth < orig.iScreenWidth) // new width would be smaller
|| (info.iScreenHeight < orig.iScreenHeight) // new height would be smaller
|| (info.dwFlags & D3DPRESENTFLAG_MODEMASK) != (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)) // don't switch to interlaced modes
{
continue;
}
}

// Allow switching to larger resolution:
// e.g. if m_sourceWidth == 3840 and we have a 3840 mode - use this one
// if it has a matching fps mode, which is evaluated below

loop_diff = std::abs((int) m_sourceWidth - info.iScreenWidth);
curr_diff = std::abs((int) m_sourceWidth - curr.iScreenWidth);

// For 3D choose the closest refresh rate
if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags))
{
float diff = (info.fRefreshRate - fRefreshRate);
if(diff < 0)
diff *= -1.0f;

if(diff < last_diff)
{
last_diff = diff;
current = (RESOLUTION)i;
curr = info;
}
}
else
{
int c_weight = MathUtils::round_int(RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
int i_weight = MathUtils::round_int(RefreshWeight(info.fRefreshRate, fRefreshRate * multiplier) * 1000.0);

RESOLUTION current_bak = current;
RESOLUTION_INFO curr_bak = curr;

// Closer the better, prefer higher refresh rate if the same
if ((i_weight < c_weight)
|| (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate))
{
current = (RESOLUTION)i;
curr = info;
}
// use case 1080p50 vs 3840x2160@25 for 3840@25 content
// prefer the higher resolution of 3840
if (i_weight == c_weight && (loop_diff < curr_diff))
{
current = (RESOLUTION)i;
curr = info;
}
// same as above but iterating with 3840@25 set and overwritten
// by e.g. 1080@50 - restore backup in that case
// to give priority to the better matching width
if (i_weight == c_weight && (loop_diff > curr_diff))
{
current = current_bak;
curr = curr_bak;
}
}
}

// For 3D overwrite weight
if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags))
weight = 0;
else
weight = RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier);

return current;
}

//distance of refresh to the closest multiple of fps (multiple is 1 or higher), as a multiplier of fps
float CBaseRenderer::RefreshWeight(float refresh, float fps)
{
float div = refresh / fps;
int round = MathUtils::round_int(div);

if (round < 1)
return (fps - refresh) / fps;
else
return (float)fabs(div / round - 1.0);
}

RESOLUTION CBaseRenderer::GetResolution() const
{
if (g_graphicsContext.IsFullScreenRoot() && (g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating()))
Expand Down
4 changes: 0 additions & 4 deletions xbmc/cores/VideoPlayer/VideoRenderers/BaseRenderer.h
Expand Up @@ -129,10 +129,6 @@ class CBaseRenderer

protected:
void ChooseBestResolution(float fps);
bool FindResolutionFromOverride(float fps, float& weight, bool fallback);
void FindResolutionFromFpsMatch(float fps, float& weight);
RESOLUTION FindClosestResolution(float fps, float multiplier, RESOLUTION current, float& weight);
static float RefreshWeight(float refresh, float fps);
void CalcNormalDisplayRect(float offsetX, float offsetY, float screenWidth, float screenHeight, float inputFrameRatio, float zoomAmount, float verticalShift);
void CalculateFrameAspectRatio(unsigned int desired_width, unsigned int desired_height);
void ManageDisplay();
Expand Down
1 change: 1 addition & 0 deletions xbmc/guilib/Makefile.in
Expand Up @@ -66,6 +66,7 @@ SRCS += imagefactory.cpp
SRCS += IWindowManagerCallback.cpp
SRCS += JpegIO.cpp
SRCS += LocalizeStrings.cpp
SRCS += Resolution.cpp
SRCS += Shader.cpp
SRCS += StereoscopicsManager.cpp
SRCS += Texture.cpp
Expand Down

0 comments on commit 6071f8e

Please sign in to comment.