[videodb] remove unused seasons table from episode_view
[xbmc.git] / xbmc / cores / VideoPlayer / VideoRenderers / BaseRenderer.cpp
bloba3dca38a3b8ce6d5fe070c68c6e30c58bfc399f3
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "BaseRenderer.h"
11 #include "ServiceBroker.h"
12 #include "cores/VideoPlayer/VideoRenderers/RenderFlags.h"
13 #include "guilib/GUIComponent.h"
14 #include "guilib/GUIWindowManager.h"
15 #include "guilib/LocalizeStrings.h"
16 #include "settings/DisplaySettings.h"
17 #include "settings/Settings.h"
18 #include "settings/SettingsComponent.h"
19 #include "settings/lib/SettingDefinitions.h"
20 #include "utils/MathUtils.h"
21 #include "utils/log.h"
22 #include "windowing/GraphicContext.h"
24 #include <algorithm>
25 #include <cstdlib> // std::abs(int) prototype
28 CBaseRenderer::CBaseRenderer()
30 for (int i=0; i < 4; i++)
32 m_rotatedDestCoords[i].x = 0;
33 m_rotatedDestCoords[i].y = 0;
34 m_savedRotatedDestCoords[i].x = 0;
35 m_savedRotatedDestCoords[i].y = 0;
39 CBaseRenderer::~CBaseRenderer() = default;
41 float CBaseRenderer::GetAspectRatio() const
43 return m_sourceFrameRatio;
46 void CBaseRenderer::GetVideoRect(CRect& source, CRect& dest, CRect& view) const
48 source = m_sourceRect;
49 dest = m_destRect;
50 view = m_viewRect;
53 inline void CBaseRenderer::ReorderDrawPoints()
55 // 0 - top left, 1 - top right, 2 - bottom right, 3 - bottom left
56 float origMat[4][2] = {{m_destRect.x1, m_destRect.y1},
57 {m_destRect.x2, m_destRect.y1},
58 {m_destRect.x2, m_destRect.y2},
59 {m_destRect.x1, m_destRect.y2}};
61 int pointOffset = m_renderOrientation / 90;
63 // if renderer doesn't support rotation
64 // treat orientation as 0 degree so that
65 // ffmpeg might handle it.
66 if (!Supports(RENDERFEATURE_ROTATION))
68 pointOffset = 0;
71 for (int destIdx=0, srcIdx=pointOffset; destIdx < 4; destIdx++)
73 m_rotatedDestCoords[destIdx].x = origMat[srcIdx][0];
74 m_rotatedDestCoords[destIdx].y = origMat[srcIdx][1];
76 srcIdx++;
77 srcIdx = srcIdx % 4;
81 void CBaseRenderer::saveRotatedCoords()
83 for (int i = 0; i < 4; i++)
84 m_savedRotatedDestCoords[i] = m_rotatedDestCoords[i];
87 void CBaseRenderer::syncDestRectToRotatedPoints()
89 m_rotatedDestCoords[0].x = m_destRect.x1;
90 m_rotatedDestCoords[0].y = m_destRect.y1;
91 m_rotatedDestCoords[1].x = m_destRect.x2;
92 m_rotatedDestCoords[1].y = m_destRect.y1;
93 m_rotatedDestCoords[2].x = m_destRect.x2;
94 m_rotatedDestCoords[2].y = m_destRect.y2;
95 m_rotatedDestCoords[3].x = m_destRect.x1;
96 m_rotatedDestCoords[3].y = m_destRect.y2;
99 void CBaseRenderer::restoreRotatedCoords()
101 for (int i = 0; i < 4; i++)
102 m_rotatedDestCoords[i] = m_savedRotatedDestCoords[i];
105 void CBaseRenderer::CalcDestRect(float offsetX,
106 float offsetY,
107 float width,
108 float height,
109 float inputFrameRatio,
110 float zoomAmount,
111 float verticalShift,
112 CRect& destRect)
114 // if view window is empty, set empty destination
115 if (height == 0 || width == 0)
117 destRect.SetRect(0.0f, 0.0f, 0.0f, 0.0f);
118 return;
121 // scale up image as much as possible
122 // and keep the aspect ratio (introduces with black bars)
123 // calculate the correct output frame ratio (using the users pixel ratio setting
124 // and the output pixel ratio setting)
126 float outputFrameRatio = inputFrameRatio / CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo().fPixelRatio;
128 // allow a certain error to maximize size of render area
129 float fCorrection = width / height / outputFrameRatio - 1.0f;
130 float fAllowed = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_ERRORINASPECT) * 0.01f;
131 if (fCorrection > fAllowed)
132 fCorrection = fAllowed;
133 if (fCorrection < -fAllowed)
134 fCorrection = - fAllowed;
136 outputFrameRatio *= 1.0f + fCorrection;
138 bool isRotated = false;
139 if (m_renderOrientation == 90 ||
140 m_renderOrientation == 270)
141 isRotated = true;
143 float newWidth;
144 float newHeight;
146 if (!isRotated)
148 // maximize the movie width
149 newWidth = width;
150 newHeight = newWidth / outputFrameRatio;
151 if (newHeight > height)
153 newHeight = height;
154 newWidth = newHeight * outputFrameRatio;
157 else
159 // maximize the movie height
160 newHeight = std::min(width, height);
161 newWidth = newHeight / outputFrameRatio;
162 if (newWidth > width)
164 newWidth = std::min(width, height);
165 newHeight = newWidth * outputFrameRatio;
169 // Scale the movie up by set zoom amount
170 newWidth *= zoomAmount;
171 newHeight *= zoomAmount;
173 // if we are less than one pixel off use the complete screen instead
174 if (std::abs(newWidth - width) < 1.0f)
175 newWidth = width;
176 if (std::abs(newHeight - height) < 1.0f)
177 newHeight = height;
179 // Centre the movie
180 float posY = (height - newHeight) / 2;
181 float posX = (width - newWidth) / 2;
183 // vertical shift range -1 to 1 shifts within the top and bottom black bars
184 // if there are no top and bottom black bars, this range does nothing
185 float blackBarSize = std::max((height - newHeight) / 2.0f, 0.0f);
186 posY += blackBarSize * std::max(std::min(verticalShift, 1.0f), -1.0f);
188 // vertical shift ranges -2 to -1 and 1 to 2 will shift the image out of the screen
189 // if vertical shift is -2 it will be completely shifted out the top,
190 // if it's 2 it will be completely shifted out the bottom
191 float shiftRange = std::min(newHeight, newHeight - (newHeight - height) / 2.0f);
192 if (verticalShift > 1.0f)
193 posY += shiftRange * (verticalShift - 1.0f);
194 else if (verticalShift < -1.0f)
195 posY += shiftRange * (verticalShift + 1.0f);
197 destRect.x1 = static_cast<float>(MathUtils::round_int(static_cast<double>(posX + offsetX)));
198 destRect.x2 = destRect.x1 + MathUtils::round_int(static_cast<double>(newWidth));
199 destRect.y1 = static_cast<float>(MathUtils::round_int(static_cast<double>(posY + offsetY)));
200 destRect.y2 = destRect.y1 + MathUtils::round_int(static_cast<double>(newHeight));
203 void CBaseRenderer::CalcNormalRenderRect(float offsetX,
204 float offsetY,
205 float width,
206 float height,
207 float inputFrameRatio,
208 float zoomAmount,
209 float verticalShift)
211 CalcDestRect(offsetX, offsetY, width, height, inputFrameRatio, zoomAmount, verticalShift,
212 m_destRect);
214 // bail out if view window is empty
215 if (height == 0 || width == 0)
216 return;
218 // clip as needed
219 if (m_alwaysClip || !(CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenVideo() ||
220 CServiceBroker::GetWinSystem()->GetGfxContext().IsCalibrating()))
222 CRect original(m_destRect);
223 m_destRect.Intersect(CRect(offsetX, offsetY, offsetX + width, offsetY + height));
224 if (m_destRect != original)
226 float scaleX = m_sourceRect.Width() / original.Width();
227 float scaleY = m_sourceRect.Height() / original.Height();
228 m_sourceRect.x1 += (m_destRect.x1 - original.x1) * scaleX;
229 m_sourceRect.y1 += (m_destRect.y1 - original.y1) * scaleY;
230 m_sourceRect.x2 += (m_destRect.x2 - original.x2) * scaleX;
231 m_sourceRect.y2 += (m_destRect.y2 - original.y2) * scaleY;
235 ReorderDrawPoints();
238 //***************************************************************************************
239 // CalculateFrameAspectRatio()
241 // Considers the source frame size and output frame size (as suggested by mplayer)
242 // to determine if the pixels in the source are not square. It calculates the aspect
243 // ratio of the output frame. We consider the cases of VCD, SVCD and DVD separately,
244 // as these are intended to be viewed on a non-square pixel TV set, so the pixels are
245 // defined to be the same ratio as the intended display pixels.
246 // These formats are determined by frame size.
247 //***************************************************************************************
248 void CBaseRenderer::CalculateFrameAspectRatio(unsigned int desired_width, unsigned int desired_height)
250 m_sourceFrameRatio = (float)desired_width / desired_height;
252 // Check whether mplayer has decided that the size of the video file should be changed
253 // This indicates either a scaling has taken place (which we didn't ask for) or it has
254 // found an aspect ratio parameter from the file, and is changing the frame size based
255 // on that.
256 if (m_sourceWidth == desired_width && m_sourceHeight == desired_height)
257 return ;
259 // mplayer is scaling in one or both directions. We must alter our Source Pixel Ratio
260 float imageFrameRatio = (float)m_sourceWidth / m_sourceHeight;
262 // OK, most sources will be correct now, except those that are intended
263 // to be displayed on non-square pixel based output devices (ie PAL or NTSC TVs)
264 // This includes VCD, SVCD, and DVD (and possibly others that we are not doing yet)
265 // For this, we can base the pixel ratio on the pixel ratios of PAL and NTSC,
266 // though we will need to adjust for anamorphic sources (ie those whose
267 // output frame ratio is not 4:3) and for SVCDs which have 2/3rds the
268 // horizontal resolution of the default NTSC or PAL frame sizes
270 // The following are the defined standard ratios for PAL and NTSC pixels
271 // NOTE: These aren't technically (in terms of BT601) correct - the commented values are,
272 // but it seems that many DVDs nowadays are mastered incorrectly, so two wrongs
273 // may indeed make a right. The "wrong" values here ensure the output frame is
274 // 4x3 (or 16x9)
275 const float PALPixelRatio = 16.0f / 15.0f; // 128.0f / 117.0f;
276 const float NTSCPixelRatio = 8.0f / 9.0f; // 4320.0f / 4739.0f;
278 // Calculate the correction needed for anamorphic sources
279 float Non4by3Correction = m_sourceFrameRatio / (4.0f / 3.0f);
281 // Finally, check for a VCD, SVCD or DVD frame size as these need special aspect ratios
282 if (m_sourceWidth == 352)
283 { // VCD?
284 if (m_sourceHeight == 240) // NTSC
285 m_sourceFrameRatio = imageFrameRatio * NTSCPixelRatio;
286 if (m_sourceHeight == 288) // PAL
287 m_sourceFrameRatio = imageFrameRatio * PALPixelRatio;
289 if (m_sourceWidth == 480)
290 { // SVCD?
291 if (m_sourceHeight == 480) // NTSC
292 m_sourceFrameRatio = imageFrameRatio * 3.0f / 2.0f * NTSCPixelRatio * Non4by3Correction;
293 if (m_sourceHeight == 576) // PAL
294 m_sourceFrameRatio = imageFrameRatio * 3.0f / 2.0f * PALPixelRatio * Non4by3Correction;
296 if (m_sourceWidth == 720)
297 { // DVD?
298 if (m_sourceHeight == 480) // NTSC
299 m_sourceFrameRatio = imageFrameRatio * NTSCPixelRatio * Non4by3Correction;
300 if (m_sourceHeight == 576) // PAL
301 m_sourceFrameRatio = imageFrameRatio * PALPixelRatio * Non4by3Correction;
305 void CBaseRenderer::ManageRenderArea()
307 m_viewRect = CServiceBroker::GetWinSystem()->GetGfxContext().GetViewWindow();
309 m_sourceRect.x1 = 0.0f;
310 m_sourceRect.y1 = 0.0f;
311 m_sourceRect.x2 = (float)m_sourceWidth;
312 m_sourceRect.y2 = (float)m_sourceHeight;
314 unsigned int stereo_mode = CONF_FLAGS_STEREO_MODE_MASK(m_iFlags);
315 int stereo_view = CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoView();
317 if(CONF_FLAGS_STEREO_CADENCE(m_iFlags) == CONF_FLAGS_STEREO_CADANCE_RIGHT_LEFT)
319 if (stereo_view == RENDER_STEREO_VIEW_LEFT) stereo_view = RENDER_STEREO_VIEW_RIGHT;
320 else if(stereo_view == RENDER_STEREO_VIEW_RIGHT) stereo_view = RENDER_STEREO_VIEW_LEFT;
323 switch(stereo_mode)
325 case CONF_FLAGS_STEREO_MODE_TAB:
326 if (stereo_view == RENDER_STEREO_VIEW_LEFT)
327 m_sourceRect.y2 *= 0.5f;
328 else if(stereo_view == RENDER_STEREO_VIEW_RIGHT)
329 m_sourceRect.y1 += m_sourceRect.y2*0.5f;
330 break;
332 case CONF_FLAGS_STEREO_MODE_SBS:
333 if (stereo_view == RENDER_STEREO_VIEW_LEFT)
334 m_sourceRect.x2 *= 0.5f;
335 else if(stereo_view == RENDER_STEREO_VIEW_RIGHT)
336 m_sourceRect.x1 += m_sourceRect.x2*0.5f;
337 break;
339 default:
340 break;
343 CalcNormalRenderRect(m_viewRect.x1, m_viewRect.y1, m_viewRect.Width(), m_viewRect.Height(),
344 GetAspectRatio() * CDisplaySettings::GetInstance().GetPixelRatio(),
345 CDisplaySettings::GetInstance().GetZoomAmount(),
346 CDisplaySettings::GetInstance().GetVerticalShift());
349 EShaderFormat CBaseRenderer::GetShaderFormat()
351 EShaderFormat ret = SHADER_NONE;
353 if (m_format == AV_PIX_FMT_YUV420P)
354 ret = SHADER_YV12;
355 else if (m_format == AV_PIX_FMT_YUV420P9)
356 ret = SHADER_YV12_9;
357 else if (m_format == AV_PIX_FMT_YUV420P10)
358 ret = SHADER_YV12_10;
359 else if (m_format == AV_PIX_FMT_YUV420P12)
360 ret = SHADER_YV12_12;
361 else if (m_format == AV_PIX_FMT_YUV420P14)
362 ret = SHADER_YV12_14;
363 else if (m_format == AV_PIX_FMT_YUV420P16)
364 ret = SHADER_YV12_16;
365 else if (m_format == AV_PIX_FMT_NV12)
366 ret = SHADER_NV12;
367 else if (m_format == AV_PIX_FMT_YUYV422)
368 ret = SHADER_YUY2;
369 else if (m_format == AV_PIX_FMT_UYVY422)
370 ret = SHADER_UYVY;
371 else
372 CLog::Log(LOGERROR, "CBaseRenderer::GetShaderFormat - unsupported format {}", m_format);
374 return ret;
377 void CBaseRenderer::SetViewMode(int viewMode)
379 if (viewMode < ViewModeNormal || viewMode > ViewModeZoom110Width)
380 viewMode = ViewModeNormal;
382 m_videoSettings.m_ViewMode = viewMode;
384 // get our calibrated full screen resolution
385 RESOLUTION_INFO info = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo();
386 float screenWidth = (float)(info.Overscan.right - info.Overscan.left);
387 float screenHeight = (float)(info.Overscan.bottom - info.Overscan.top);
389 // and the source frame ratio
390 float sourceFrameRatio = GetAspectRatio();
392 bool is43 = (sourceFrameRatio < 8.f/(3.f*sqrt(3.f)) &&
393 m_videoSettings.m_ViewMode == ViewModeNormal);
395 // Splitres scaling factor
396 float xscale = (float)info.iScreenWidth / (float)info.iWidth;
397 float yscale = (float)info.iScreenHeight / (float)info.iHeight;
399 screenWidth *= xscale;
400 screenHeight *= yscale;
402 CDisplaySettings::GetInstance().SetVerticalShift(0.0f);
403 CDisplaySettings::GetInstance().SetNonLinearStretched(false);
405 if (m_videoSettings.m_ViewMode == ViewModeZoom ||
406 (is43 && CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_STRETCH43) == ViewModeZoom))
407 { // zoom image so no black bars
408 CDisplaySettings::GetInstance().SetPixelRatio(1.0);
409 // calculate the desired output ratio
410 float outputFrameRatio = sourceFrameRatio * CDisplaySettings::GetInstance().GetPixelRatio() / info.fPixelRatio;
411 // now calculate the correct zoom amount. First zoom to full height.
412 float newHeight = screenHeight;
413 float newWidth = newHeight * outputFrameRatio;
414 CDisplaySettings::GetInstance().SetZoomAmount(newWidth / screenWidth);
415 if (newWidth < screenWidth)
416 { // zoom to full width
417 newWidth = screenWidth;
418 newHeight = newWidth / outputFrameRatio;
419 CDisplaySettings::GetInstance().SetZoomAmount(newHeight / screenHeight);
422 else if (m_videoSettings.m_ViewMode == ViewModeStretch4x3)
423 { // stretch image to 4:3 ratio
424 CDisplaySettings::GetInstance().SetZoomAmount(1.0);
425 // now we need to set CDisplaySettings::GetInstance().GetPixelRatio() so that
426 // fOutputFrameRatio = 4:3.
427 CDisplaySettings::GetInstance().SetPixelRatio((4.0f / 3.0f) / sourceFrameRatio);
429 else if (m_videoSettings.m_ViewMode == ViewModeWideZoom ||
430 (is43 && CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_STRETCH43) == ViewModeWideZoom))
431 { // super zoom
432 float stretchAmount = (screenWidth / screenHeight) * info.fPixelRatio / sourceFrameRatio;
433 CDisplaySettings::GetInstance().SetPixelRatio(pow(stretchAmount, float(2.0/3.0)));
434 CDisplaySettings::GetInstance().SetZoomAmount(
435 pow(stretchAmount, float((stretchAmount < 1.0f) ? -1.0 / 3.0 : 1.0 / 3.0)));
436 CDisplaySettings::GetInstance().SetNonLinearStretched(true);
438 else if (m_videoSettings.m_ViewMode == ViewModeStretch16x9 ||
439 m_videoSettings.m_ViewMode == ViewModeStretch16x9Nonlin ||
440 (is43 && (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_STRETCH43) == ViewModeStretch16x9 ||
441 CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_STRETCH43) == ViewModeStretch16x9Nonlin)))
442 { // stretch image to 16:9 ratio
443 CDisplaySettings::GetInstance().SetZoomAmount(1.0);
444 // stretch to the limits of the 16:9 screen.
445 // incorrect behaviour, but it's what the users want, so...
446 CDisplaySettings::GetInstance().SetPixelRatio((screenWidth / screenHeight) * info.fPixelRatio / sourceFrameRatio);
447 bool nonlin = (is43 && CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_STRETCH43) == ViewModeStretch16x9Nonlin) ||
448 m_videoSettings.m_ViewMode == ViewModeStretch16x9Nonlin;
449 CDisplaySettings::GetInstance().SetNonLinearStretched(nonlin);
451 else if (m_videoSettings.m_ViewMode == ViewModeOriginal)
452 { // zoom image so that the height is the original size
453 CDisplaySettings::GetInstance().SetPixelRatio(1.0);
454 // get the size of the media file
455 // calculate the desired output ratio
456 float outputFrameRatio = sourceFrameRatio * CDisplaySettings::GetInstance().GetPixelRatio() / info.fPixelRatio;
457 // now calculate the correct zoom amount. First zoom to full width.
458 float newHeight = screenWidth / outputFrameRatio;
459 if (newHeight > screenHeight)
460 { // zoom to full height
461 newHeight = screenHeight;
463 // now work out the zoom amount so that no zoom is done
464 CDisplaySettings::GetInstance().SetZoomAmount(m_sourceHeight / newHeight);
466 else if (m_videoSettings.m_ViewMode == ViewModeCustom)
468 CDisplaySettings::GetInstance().SetZoomAmount(m_videoSettings.m_CustomZoomAmount);
469 CDisplaySettings::GetInstance().SetPixelRatio(m_videoSettings.m_CustomPixelRatio);
470 CDisplaySettings::GetInstance().SetNonLinearStretched(m_videoSettings.m_CustomNonLinStretch);
471 CDisplaySettings::GetInstance().SetVerticalShift(m_videoSettings.m_CustomVerticalShift);
473 else if (m_videoSettings.m_ViewMode == ViewModeZoom120Width)
475 float fitHeightZoom = sourceFrameRatio * screenHeight / (info.fPixelRatio * screenWidth);
476 CDisplaySettings::GetInstance().SetPixelRatio(1.0f);
477 CDisplaySettings::GetInstance().SetZoomAmount(fitHeightZoom < 1.0f ? 1.0f : (fitHeightZoom > 1.2f ? 1.2f : fitHeightZoom));
479 else if (m_videoSettings.m_ViewMode == ViewModeZoom110Width)
481 float fitHeightZoom = sourceFrameRatio * screenHeight / (info.fPixelRatio * screenWidth);
482 CDisplaySettings::GetInstance().SetPixelRatio(1.0f);
483 CDisplaySettings::GetInstance().SetZoomAmount(fitHeightZoom < 1.0f ? 1.0f : (fitHeightZoom > 1.1f ? 1.1f : fitHeightZoom));
485 else // if (CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ViewMode == ViewModeNormal)
487 CDisplaySettings::GetInstance().SetPixelRatio(1.0);
488 CDisplaySettings::GetInstance().SetZoomAmount(1.0);
491 //@TODO
492 m_videoSettings.m_CustomZoomAmount = CDisplaySettings::GetInstance().GetZoomAmount();
493 m_videoSettings.m_CustomPixelRatio = CDisplaySettings::GetInstance().GetPixelRatio();
494 m_videoSettings.m_CustomNonLinStretch = CDisplaySettings::GetInstance().IsNonLinearStretched();
495 m_videoSettings.m_CustomVerticalShift = CDisplaySettings::GetInstance().GetVerticalShift();
498 void CBaseRenderer::MarkDirty()
500 CServiceBroker::GetGUI()->GetWindowManager().MarkDirty(m_destRect);
503 void CBaseRenderer::EnableAlwaysClip()
505 m_alwaysClip = true;
508 void CBaseRenderer::SetVideoSettings(const CVideoSettings &settings)
510 m_videoSettings = settings;
513 void CBaseRenderer::SettingOptionsRenderMethodsFiller(
514 const std::shared_ptr<const CSetting>& setting,
515 std::vector<IntegerSettingOption>& list,
516 int& current,
517 void* data)
519 list.emplace_back(g_localizeStrings.Get(13416), RENDER_METHOD_AUTO);
521 #ifdef HAS_DX
522 list.push_back(IntegerSettingOption(g_localizeStrings.Get(16319), RENDER_METHOD_DXVA));
523 list.push_back(IntegerSettingOption(g_localizeStrings.Get(13431), RENDER_METHOD_D3D_PS));
524 list.push_back(IntegerSettingOption(g_localizeStrings.Get(13419), RENDER_METHOD_SOFTWARE));
525 #endif