a0593832fc52239dc1e3fbc826909ac678e0166b
[vuplus_xbmc] / xbmc / cores / VideoRenderers / BaseRenderer.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://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
23 #include <algorithm>
24 #include "BaseRenderer.h"
25 #include "settings/DisplaySettings.h"
26 #include "settings/MediaSettings.h"
27 #include "settings/Settings.h"
28 #include "guilib/GraphicContext.h"
29 #include "guilib/GUIWindowManager.h"
30 #include "guilib/LocalizeStrings.h"
31 #include "utils/log.h"
32 #include "utils/MathUtils.h"
33 #include "utils/SystemInfo.h"
34 #include "settings/AdvancedSettings.h"
35 #include "cores/VideoRenderers/RenderFlags.h"
36
37
38 CBaseRenderer::CBaseRenderer()
39 {
40   m_sourceFrameRatio = 1.0f;
41   m_sourceWidth = 720;
42   m_sourceHeight = 480;
43   m_resolution = RES_DESKTOP;
44   m_fps = 0.0f;
45   m_renderOrientation = 0;
46   m_oldRenderOrientation = 0;
47   m_oldDestRect.SetRect(0.0f, 0.0f, 0.0f, 0.0f);
48   m_iFlags = 0;
49
50   for(int i=0; i < 4; i++)
51   {
52     m_rotatedDestCoords[i].x = 0;
53     m_rotatedDestCoords[i].y = 0;
54     m_savedRotatedDestCoords[i].x = 0;
55     m_savedRotatedDestCoords[i].y = 0;    
56   }
57
58   m_RenderUpdateCallBackFn = NULL;
59   m_RenderUpdateCallBackCtx = NULL;
60 }
61
62 CBaseRenderer::~CBaseRenderer()
63 {
64 }
65
66 void CBaseRenderer::RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn)
67 {
68   m_RenderUpdateCallBackFn = fn;
69   m_RenderUpdateCallBackCtx = ctx;
70 }
71
72 void CBaseRenderer::RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn)
73 {
74   m_RenderFeaturesCallBackFn = fn;
75   m_RenderFeaturesCallBackCtx = ctx;
76 }
77
78 void CBaseRenderer::ChooseBestResolution(float fps)
79 {
80   if (fps == 0.0) return;
81
82   // Adjust refreshrate to match source fps
83 #if !defined(TARGET_DARWIN_IOS)
84   if (CSettings::Get().GetInt("videoplayer.adjustrefreshrate") != ADJUST_REFRESHRATE_OFF)
85   {
86     float weight;
87     if (!FindResolutionFromOverride(fps, weight, false)) //find a refreshrate from overrides
88     {
89       if (!FindResolutionFromOverride(fps, weight, true))//if that fails find it from a fallback
90         FindResolutionFromFpsMatch(fps, weight);//if that fails use automatic refreshrate selection
91     }
92
93     CLog::Log(LOGNOTICE, "Display resolution ADJUST : %s (%d) (weight: %.3f)",
94         g_graphicsContext.GetResInfo(m_resolution).strMode.c_str(), m_resolution, weight);
95   }
96   else
97 #endif
98     CLog::Log(LOGNOTICE, "Display resolution %s : %s (%d)",
99         m_resolution == RES_DESKTOP ? "DESKTOP" : "USER", g_graphicsContext.GetResInfo(m_resolution).strMode.c_str(), m_resolution);
100 }
101
102 bool CBaseRenderer::FindResolutionFromOverride(float fps, float& weight, bool fallback)
103 {
104   RESOLUTION_INFO curr = g_graphicsContext.GetResInfo(m_resolution);
105
106   //try to find a refreshrate from the override
107   for (int i = 0; i < (int)g_advancedSettings.m_videoAdjustRefreshOverrides.size(); i++)
108   {
109     RefreshOverride& override = g_advancedSettings.m_videoAdjustRefreshOverrides[i];
110
111     if (override.fallback != fallback)
112       continue;
113
114     //if we're checking for overrides, check if the fps matches
115     if (!fallback && (fps < override.fpsmin || fps > override.fpsmax))
116       continue;
117
118     for (size_t j = (int)RES_DESKTOP; j < CDisplaySettings::Get().ResolutionInfoSize(); j++)
119     {
120       RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)j);
121
122       if (info.iScreenWidth  == curr.iScreenWidth
123        && info.iScreenHeight == curr.iScreenHeight
124        && (info.dwFlags & D3DPRESENTFLAG_MODEMASK) == (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)
125        && info.iScreen       == curr.iScreen)
126       {
127         if (info.fRefreshRate <= override.refreshmax
128          && info.fRefreshRate >= override.refreshmin)
129         {
130           m_resolution = (RESOLUTION)j;
131
132           if (fallback)
133           {
134             CLog::Log(LOGDEBUG, "Found Resolution %s (%d) from fallback (refreshmin:%.3f refreshmax:%.3f)",
135                       info.strMode.c_str(), m_resolution,
136                       override.refreshmin, override.refreshmax);
137           }
138           else
139           {
140             CLog::Log(LOGDEBUG, "Found Resolution %s (%d) from override of fps %.3f (fpsmin:%.3f fpsmax:%.3f refreshmin:%.3f refreshmax:%.3f)",
141                       info.strMode.c_str(), m_resolution, fps,
142                       override.fpsmin, override.fpsmax, override.refreshmin, override.refreshmax);
143           }
144
145           weight = RefreshWeight(info.fRefreshRate, fps);
146
147           return true; //fps and refresh match with this override, use this resolution
148         }
149       }
150     }
151   }
152
153   return false; //no override found
154 }
155
156 void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight)
157 {
158   const float maxWeight = 0.0021f;
159   RESOLUTION_INFO curr;
160
161   m_resolution = FindClosestResolution(fps, 1.0, m_resolution, weight);
162   curr = g_graphicsContext.GetResInfo(m_resolution);
163
164   if (weight >= maxWeight) //not a very good match, try a 2:3 cadence instead
165   {
166     CLog::Log(LOGDEBUG, "Resolution %s (%d) not a very good match for fps %.3f (weight: %.3f), trying 2:3 cadence",
167         curr.strMode.c_str(), m_resolution, fps, weight);
168
169     m_resolution = FindClosestResolution(fps, 2.5, m_resolution, weight);
170     curr = g_graphicsContext.GetResInfo(m_resolution);
171
172     if (weight >= maxWeight) //2:3 cadence not a good match
173     {
174       CLog::Log(LOGDEBUG, "Resolution %s (%d) not a very good match for fps %.3f with 2:3 cadence (weight: %.3f), choosing 60 hertz",
175           curr.strMode.c_str(), m_resolution, fps, weight);
176
177       //get the resolution with the refreshrate closest to 60 hertz
178       for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
179       {
180         RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);
181
182         if (MathUtils::round_int(info.fRefreshRate) == 60
183          && info.iScreenWidth  == curr.iScreenWidth
184          && info.iScreenHeight == curr.iScreenHeight
185          && (info.dwFlags & D3DPRESENTFLAG_MODEMASK) == (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)
186          && info.iScreen       == curr.iScreen)
187         {
188           if (fabs(info.fRefreshRate - 60.0) < fabs(curr.fRefreshRate - 60.0)) {
189             m_resolution = (RESOLUTION)i;
190             curr = info;
191           }
192         }
193       }
194
195       //60 hertz not available, get the highest refreshrate
196       if (MathUtils::round_int(curr.fRefreshRate) != 60)
197       {
198         CLog::Log(LOGDEBUG, "60 hertz refreshrate not available, choosing highest");
199         for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
200         {
201           RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);
202
203           if (info.fRefreshRate  >  curr.fRefreshRate
204            && info.iScreenWidth  == curr.iScreenWidth
205            && info.iScreenHeight == curr.iScreenHeight
206            && (info.dwFlags & D3DPRESENTFLAG_MODEMASK) == (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)
207            && info.iScreen       == curr.iScreen)
208           {
209             m_resolution = (RESOLUTION)i;
210             curr = info;
211           }
212         }
213       }
214
215       weight = RefreshWeight(curr.fRefreshRate, fps);
216     }
217   }
218 }
219
220 RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RESOLUTION current, float& weight)
221 {
222   RESOLUTION_INFO curr = g_graphicsContext.GetResInfo(current);
223
224   float fRefreshRate = fps;
225
226   float last_diff = fRefreshRate;
227
228   // Find closest refresh rate
229   for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
230   {
231     const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);
232
233     //discard resolutions that are not the same width and height (and interlaced/3D flags)
234     //or have a too low refreshrate
235     if (info.iScreenWidth  != curr.iScreenWidth
236     ||  info.iScreenHeight != curr.iScreenHeight
237     ||  info.iScreen       != curr.iScreen
238     ||  (info.dwFlags & D3DPRESENTFLAG_MODEMASK) != (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)
239     ||  info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001)
240       continue;
241
242     // For 3D choose the closest refresh rate 
243     if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags))
244     {
245       float diff = (info.fRefreshRate - fRefreshRate);
246       if(diff < 0)
247         diff *= -1.0f;
248
249       if(diff < last_diff)
250       {
251         last_diff = diff;
252         current = (RESOLUTION)i;
253         curr = info;
254       }
255     }
256     else
257     {
258       int c_weight = MathUtils::round_int(RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
259       int i_weight = MathUtils::round_int(RefreshWeight(info.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
260
261       // Closer the better, prefer higher refresh rate if the same
262       if ((i_weight <  c_weight)
263       ||  (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate))
264       {
265         current = (RESOLUTION)i;
266         curr    = info;
267       }
268     }
269   }
270
271   // For 3D overwrite weight
272   if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags))
273     weight = 0;
274   else
275     weight = RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier);
276
277   return current;
278 }
279
280 //distance of refresh to the closest multiple of fps (multiple is 1 or higher), as a multiplier of fps
281 float CBaseRenderer::RefreshWeight(float refresh, float fps)
282 {
283   float div   = refresh / fps;
284   int   round = MathUtils::round_int(div);
285
286   if (round < 1)
287     return (fps - refresh) / fps;
288   else
289     return (float)fabs(div / round - 1.0);
290 }
291
292 RESOLUTION CBaseRenderer::GetResolution() const
293 {
294   if (g_graphicsContext.IsFullScreenRoot() && (g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating()))
295     return m_resolution;
296
297   return g_graphicsContext.GetVideoResolution();
298 }
299
300 float CBaseRenderer::GetAspectRatio() const
301 {
302   float width = (float)m_sourceWidth - CMediaSettings::Get().GetCurrentVideoSettings().m_CropLeft - CMediaSettings::Get().GetCurrentVideoSettings().m_CropRight;
303   float height = (float)m_sourceHeight - CMediaSettings::Get().GetCurrentVideoSettings().m_CropTop - CMediaSettings::Get().GetCurrentVideoSettings().m_CropBottom;
304   return m_sourceFrameRatio * width / height * m_sourceHeight / m_sourceWidth;
305 }
306
307 void CBaseRenderer::GetVideoRect(CRect &source, CRect &dest)
308 {
309   source = m_sourceRect;
310   dest = m_destRect;
311 }
312
313 inline void CBaseRenderer::ReorderDrawPoints()
314 {
315   // 0 - top left, 1 - top right, 2 - bottom right, 3 - bottom left
316   float origMat[4][2] = {{m_destRect.x1, m_destRect.y1},
317                          {m_destRect.x2, m_destRect.y1},
318                          {m_destRect.x2, m_destRect.y2},
319                          {m_destRect.x1, m_destRect.y2}};
320   bool changeAspect = false;
321   int pointOffset = 0;
322
323   switch (m_renderOrientation)
324   {
325     case 90:
326       pointOffset = 1;
327       changeAspect = true;
328       break;
329     case 180:
330       pointOffset = 2;
331       break;
332     case 270:
333       pointOffset = 3;
334       changeAspect = true;
335       break;
336   }
337
338   // if renderer doesn't support rotation
339   // treat orientation as 0 degree so that
340   // ffmpeg might handle it.
341   if (!Supports(RENDERFEATURE_ROTATION))
342   {
343     pointOffset = 0;
344     changeAspect = false;
345   }
346
347
348   int diff = (int) ((m_destRect.Height() - m_destRect.Width()) / 2);
349
350   for (int destIdx=0, srcIdx=pointOffset; destIdx < 4; destIdx++)
351   {
352     m_rotatedDestCoords[destIdx].x = origMat[srcIdx][0];
353     m_rotatedDestCoords[destIdx].y = origMat[srcIdx][1];
354
355     if (changeAspect)
356     {
357       switch (srcIdx)
358       {
359         case 0:
360           m_rotatedDestCoords[destIdx].x -= diff;
361           m_rotatedDestCoords[destIdx].y += diff;
362           break;
363         case 1:
364           m_rotatedDestCoords[destIdx].x += diff;
365           m_rotatedDestCoords[destIdx].y += diff;
366           break;
367         case 2:
368           m_rotatedDestCoords[destIdx].x += diff;
369           m_rotatedDestCoords[destIdx].y -= diff;
370           break;
371         case 3:
372           m_rotatedDestCoords[destIdx].x -= diff;
373           m_rotatedDestCoords[destIdx].y -= diff;
374           break;
375       }
376     }
377     srcIdx++;
378     srcIdx = srcIdx % 4;
379   }
380 }
381
382 void CBaseRenderer::saveRotatedCoords()
383 {
384   for (int i = 0; i < 4; i++)
385     m_savedRotatedDestCoords[i] = m_rotatedDestCoords[i];
386 }
387
388 void CBaseRenderer::syncDestRectToRotatedPoints()
389 {
390   m_rotatedDestCoords[0].x = m_destRect.x1;
391   m_rotatedDestCoords[0].y = m_destRect.y1;  
392   m_rotatedDestCoords[1].x = m_destRect.x2;
393   m_rotatedDestCoords[1].y = m_destRect.y1;
394   m_rotatedDestCoords[2].x = m_destRect.x2;
395   m_rotatedDestCoords[2].y = m_destRect.y2;  
396   m_rotatedDestCoords[3].x = m_destRect.x1;
397   m_rotatedDestCoords[3].y = m_destRect.y2; 
398 }
399
400 void CBaseRenderer::restoreRotatedCoords()
401 {
402   for (int i = 0; i < 4; i++)
403     m_rotatedDestCoords[i] = m_savedRotatedDestCoords[i];
404 }
405
406 void CBaseRenderer::CalcNormalDisplayRect(float offsetX, float offsetY, float screenWidth, float screenHeight, float inputFrameRatio, float zoomAmount, float verticalShift)
407 {
408   // if view window is empty, set empty destination
409   if(screenHeight == 0 || screenWidth == 0)
410   {
411     m_destRect.SetRect(0.0f, 0.0f, 0.0f, 0.0f);
412     return;
413   }
414
415   // scale up image as much as possible
416   // and keep the aspect ratio (introduces with black bars)
417   // calculate the correct output frame ratio (using the users pixel ratio setting
418   // and the output pixel ratio setting)
419
420   float outputFrameRatio = inputFrameRatio / g_graphicsContext.GetResInfo(GetResolution()).fPixelRatio;
421
422   // allow a certain error to maximize screen size
423   float fCorrection = screenWidth / screenHeight / outputFrameRatio - 1.0f;
424   float fAllowed    = CSettings::Get().GetInt("videoplayer.errorinaspect") * 0.01f;
425   if(fCorrection >   fAllowed) fCorrection =   fAllowed;
426   if(fCorrection < - fAllowed) fCorrection = - fAllowed;
427
428   outputFrameRatio *= 1.0f + fCorrection;
429
430   // maximize the movie width
431   float newWidth = screenWidth;
432   float newHeight = newWidth / outputFrameRatio;
433
434   if (newHeight > screenHeight)
435   {
436     newHeight = screenHeight;
437     newWidth = newHeight * outputFrameRatio;
438   }
439
440   // Scale the movie up by set zoom amount
441   newWidth *= zoomAmount;
442   newHeight *= zoomAmount;
443
444   // Centre the movie
445   float posY = (screenHeight - newHeight) / 2;
446   float posX = (screenWidth - newWidth) / 2;
447
448   // vertical shift range -1 to 1 shifts within the top and bottom black bars
449   // if there are no top and bottom black bars, this range does nothing
450   float blackBarSize = std::max((screenHeight - newHeight) / 2.0f, 0.0f);
451   posY += blackBarSize * std::max(std::min(verticalShift, 1.0f), -1.0f);
452
453   // vertical shift ranges -2 to -1 and 1 to 2 will shift the image out of the screen
454   // if vertical shift is -2 it will be completely shifted out the top,
455   // if it's 2 it will be completely shifted out the bottom
456   float shiftRange = std::min(newHeight, newHeight - (newHeight - screenHeight) / 2.0f);
457   if (verticalShift > 1.0f)
458     posY += shiftRange * (verticalShift - 1.0f);
459   else if (verticalShift < -1.0f)
460     posY += shiftRange * (verticalShift + 1.0f);
461
462   m_destRect.x1 = (float)MathUtils::round_int(posX + offsetX);
463   m_destRect.x2 = m_destRect.x1 + MathUtils::round_int(newWidth);
464   m_destRect.y1 = (float)MathUtils::round_int(posY + offsetY);
465   m_destRect.y2 = m_destRect.y1 + MathUtils::round_int(newHeight);
466
467   // clip as needed
468   if (!(g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating()))
469   {
470     CRect original(m_destRect);
471     m_destRect.Intersect(CRect(offsetX, offsetY, offsetX + screenWidth, offsetY + screenHeight));
472     if (m_destRect != original)
473     {
474       float scaleX = m_sourceRect.Width() / original.Width();
475       float scaleY = m_sourceRect.Height() / original.Height();
476       m_sourceRect.x1 += (m_destRect.x1 - original.x1) * scaleX;
477       m_sourceRect.y1 += (m_destRect.y1 - original.y1) * scaleY;
478       m_sourceRect.x2 += (m_destRect.x2 - original.x2) * scaleX;
479       m_sourceRect.y2 += (m_destRect.y2 - original.y2) * scaleY;
480     }
481   }
482
483   if (m_oldDestRect != m_destRect || m_oldRenderOrientation != m_renderOrientation)
484   {
485     // adapt the drawing rect points if we have to rotate
486     // and either destrect or orientation changed
487     ReorderDrawPoints();
488     m_oldDestRect = m_destRect;
489     m_oldRenderOrientation = m_renderOrientation;
490   }
491 }
492
493 //***************************************************************************************
494 // CalculateFrameAspectRatio()
495 //
496 // Considers the source frame size and output frame size (as suggested by mplayer)
497 // to determine if the pixels in the source are not square.  It calculates the aspect
498 // ratio of the output frame.  We consider the cases of VCD, SVCD and DVD separately,
499 // as these are intended to be viewed on a non-square pixel TV set, so the pixels are
500 // defined to be the same ratio as the intended display pixels.
501 // These formats are determined by frame size.
502 //***************************************************************************************
503 void CBaseRenderer::CalculateFrameAspectRatio(unsigned int desired_width, unsigned int desired_height)
504 {
505   m_sourceFrameRatio = (float)desired_width / desired_height;
506
507   // Check whether mplayer has decided that the size of the video file should be changed
508   // This indicates either a scaling has taken place (which we didn't ask for) or it has
509   // found an aspect ratio parameter from the file, and is changing the frame size based
510   // on that.
511   if (m_sourceWidth == (unsigned int) desired_width && m_sourceHeight == (unsigned int) desired_height)
512     return ;
513
514   // mplayer is scaling in one or both directions.  We must alter our Source Pixel Ratio
515   float imageFrameRatio = (float)m_sourceWidth / m_sourceHeight;
516
517   // OK, most sources will be correct now, except those that are intended
518   // to be displayed on non-square pixel based output devices (ie PAL or NTSC TVs)
519   // This includes VCD, SVCD, and DVD (and possibly others that we are not doing yet)
520   // For this, we can base the pixel ratio on the pixel ratios of PAL and NTSC,
521   // though we will need to adjust for anamorphic sources (ie those whose
522   // output frame ratio is not 4:3) and for SVCDs which have 2/3rds the
523   // horizontal resolution of the default NTSC or PAL frame sizes
524
525   // The following are the defined standard ratios for PAL and NTSC pixels
526   // NOTE: These aren't technically (in terms of BT601) correct - the commented values are,
527   //       but it seems that many DVDs nowadays are mastered incorrectly, so two wrongs
528   //       may indeed make a right.  The "wrong" values here ensure the output frame is
529   //       4x3 (or 16x9)
530   const float PALPixelRatio = 16.0f / 15.0f;      // 128.0f / 117.0f;
531   const float NTSCPixelRatio = 8.0f / 9.0f;       // 4320.0f / 4739.0f;
532
533   // Calculate the correction needed for anamorphic sources
534   float Non4by3Correction = m_sourceFrameRatio / (4.0f / 3.0f);
535
536   // Finally, check for a VCD, SVCD or DVD frame size as these need special aspect ratios
537   if (m_sourceWidth == 352)
538   { // VCD?
539     if (m_sourceHeight == 240) // NTSC
540       m_sourceFrameRatio = imageFrameRatio * NTSCPixelRatio;
541     if (m_sourceHeight == 288) // PAL
542       m_sourceFrameRatio = imageFrameRatio * PALPixelRatio;
543   }
544   if (m_sourceWidth == 480)
545   { // SVCD?
546     if (m_sourceHeight == 480) // NTSC
547       m_sourceFrameRatio = imageFrameRatio * 3.0f / 2.0f * NTSCPixelRatio * Non4by3Correction;
548     if (m_sourceHeight == 576) // PAL
549       m_sourceFrameRatio = imageFrameRatio * 3.0f / 2.0f * PALPixelRatio * Non4by3Correction;
550   }
551   if (m_sourceWidth == 720)
552   { // DVD?
553     if (m_sourceHeight == 480) // NTSC
554       m_sourceFrameRatio = imageFrameRatio * NTSCPixelRatio * Non4by3Correction;
555     if (m_sourceHeight == 576) // PAL
556       m_sourceFrameRatio = imageFrameRatio * PALPixelRatio * Non4by3Correction;
557   }
558 }
559
560 void CBaseRenderer::ManageDisplay()
561 {
562   const CRect view = g_graphicsContext.GetViewWindow();
563
564   m_sourceRect.x1 = 0.0f;
565   m_sourceRect.y1 = 0.0f;
566   m_sourceRect.x2 = (float)m_sourceWidth;
567   m_sourceRect.y2 = (float)m_sourceHeight;
568
569   unsigned int stereo_mode  = CONF_FLAGS_STEREO_MODE_MASK(m_iFlags);
570   int          stereo_view  = g_graphicsContext.GetStereoView();
571
572   if(CONF_FLAGS_STEREO_CADENCE(m_iFlags) == CONF_FLAGS_STEREO_CADANCE_RIGHT_LEFT)
573   {
574     if     (stereo_view == RENDER_STEREO_VIEW_LEFT)  stereo_view = RENDER_STEREO_VIEW_RIGHT;
575     else if(stereo_view == RENDER_STEREO_VIEW_RIGHT) stereo_view = RENDER_STEREO_VIEW_LEFT;
576   }
577
578   switch(stereo_mode)
579   {
580     case CONF_FLAGS_STEREO_MODE_TAB:
581       if     (stereo_view == RENDER_STEREO_VIEW_LEFT)
582         m_sourceRect.y2 *= 0.5f;
583       else if(stereo_view == RENDER_STEREO_VIEW_RIGHT)
584         m_sourceRect.y1 += m_sourceRect.y2*0.5f;
585       break;
586
587     case CONF_FLAGS_STEREO_MODE_SBS:
588       if     (stereo_view == RENDER_STEREO_VIEW_LEFT)
589         m_sourceRect.x2 *= 0.5f;
590       else if(stereo_view == RENDER_STEREO_VIEW_RIGHT)
591         m_sourceRect.x1 += m_sourceRect.x2*0.5f;
592       break;
593
594     default:
595       break;
596   }
597
598   m_sourceRect.x1 += (float)CMediaSettings::Get().GetCurrentVideoSettings().m_CropLeft;
599   m_sourceRect.y1 += (float)CMediaSettings::Get().GetCurrentVideoSettings().m_CropTop;
600   m_sourceRect.x2 -= (float)CMediaSettings::Get().GetCurrentVideoSettings().m_CropRight;
601   m_sourceRect.y2 -= (float)CMediaSettings::Get().GetCurrentVideoSettings().m_CropBottom;
602
603   CalcNormalDisplayRect(view.x1, view.y1, view.Width(), view.Height(), GetAspectRatio() * CDisplaySettings::Get().GetPixelRatio(), CDisplaySettings::Get().GetZoomAmount(), CDisplaySettings::Get().GetVerticalShift());
604 }
605
606 void CBaseRenderer::SetViewMode(int viewMode)
607 {
608   if (viewMode < ViewModeNormal || viewMode > ViewModeCustom)
609     viewMode = ViewModeNormal;
610
611   CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode = viewMode;
612
613   // get our calibrated full screen resolution
614   RESOLUTION res = GetResolution();
615   RESOLUTION_INFO info = g_graphicsContext.GetResInfo(m_resolution);
616   float screenWidth  = (float)(info.Overscan.right  - info.Overscan.left);
617   float screenHeight = (float)(info.Overscan.bottom - info.Overscan.top);
618
619   // and the source frame ratio
620   float sourceFrameRatio = GetAspectRatio();
621
622   bool is43 = (sourceFrameRatio < 8.f/(3.f*sqrt(3.f)) &&
623               CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode == ViewModeNormal);
624
625   // Splitres scaling factor
626   float xscale = (float)info.iScreenWidth  / (float)info.iWidth;
627   float yscale = (float)info.iScreenHeight / (float)info.iHeight;
628
629   screenWidth   *= xscale;
630   screenHeight  *= yscale;
631
632   CDisplaySettings::Get().SetVerticalShift(0.0f);
633   CDisplaySettings::Get().SetNonLinearStretched(false);
634
635   if ( CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode == ViewModeZoom ||
636        (is43 && CSettings::Get().GetInt("videoplayer.stretch43") == ViewModeZoom))
637   { // zoom image so no black bars
638     CDisplaySettings::Get().SetPixelRatio(1.0);
639     // calculate the desired output ratio
640     float outputFrameRatio = sourceFrameRatio * CDisplaySettings::Get().GetPixelRatio() / info.fPixelRatio;
641     // now calculate the correct zoom amount.  First zoom to full height.
642     float newHeight = screenHeight;
643     float newWidth = newHeight * outputFrameRatio;
644     CDisplaySettings::Get().SetZoomAmount(newWidth / screenWidth);
645     if (newWidth < screenWidth)
646     { // zoom to full width
647       newWidth = screenWidth;
648       newHeight = newWidth / outputFrameRatio;
649       CDisplaySettings::Get().SetZoomAmount(newHeight / screenHeight);
650     }
651   }
652   else if (CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode == ViewModeStretch4x3)
653   { // stretch image to 4:3 ratio
654     CDisplaySettings::Get().SetZoomAmount(1.0);
655     if (res == RES_PAL_4x3 || res == RES_PAL60_4x3 || res == RES_NTSC_4x3 || res == RES_HDTV_480p_4x3)
656     { // stretch to the limits of the 4:3 screen.
657       // incorrect behaviour, but it's what the users want, so...
658       CDisplaySettings::Get().SetPixelRatio((screenWidth / screenHeight) * info.fPixelRatio / sourceFrameRatio);
659     }
660     else
661     {
662       // now we need to set CDisplaySettings::Get().GetPixelRatio() so that
663       // fOutputFrameRatio = 4:3.
664       CDisplaySettings::Get().SetPixelRatio((4.0f / 3.0f) / sourceFrameRatio);
665     }
666   }
667   else if ( CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode == ViewModeWideZoom ||
668            (is43 && CSettings::Get().GetInt("videoplayer.stretch43") == ViewModeWideZoom))
669   { // super zoom
670     float stretchAmount = (screenWidth / screenHeight) * info.fPixelRatio / sourceFrameRatio;
671     CDisplaySettings::Get().SetPixelRatio(pow(stretchAmount, float(2.0/3.0)));
672     CDisplaySettings::Get().SetZoomAmount(pow(stretchAmount, float((stretchAmount < 1.0) ? -1.0/3.0 : 1.0/3.0)));
673     CDisplaySettings::Get().SetNonLinearStretched(true);
674   }
675   else if ( CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode == ViewModeStretch16x9 ||
676            (is43 && CSettings::Get().GetInt("videoplayer.stretch43") == ViewModeStretch16x9))
677   { // stretch image to 16:9 ratio
678     CDisplaySettings::Get().SetZoomAmount(1.0);
679     if (res == RES_PAL_4x3 || res == RES_PAL60_4x3 || res == RES_NTSC_4x3 || res == RES_HDTV_480p_4x3)
680     { // now we need to set CDisplaySettings::Get().GetPixelRatio() so that
681       // outputFrameRatio = 16:9.
682       CDisplaySettings::Get().SetPixelRatio((16.0f / 9.0f) / sourceFrameRatio);
683     }
684     else
685     { // stretch to the limits of the 16:9 screen.
686       // incorrect behaviour, but it's what the users want, so...
687       CDisplaySettings::Get().SetPixelRatio((screenWidth / screenHeight) * info.fPixelRatio / sourceFrameRatio);
688     }
689   }
690   else  if (CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode == ViewModeOriginal)
691   { // zoom image so that the height is the original size
692     CDisplaySettings::Get().SetPixelRatio(1.0);
693     // get the size of the media file
694     // calculate the desired output ratio
695     float outputFrameRatio = sourceFrameRatio * CDisplaySettings::Get().GetPixelRatio() / info.fPixelRatio;
696     // now calculate the correct zoom amount.  First zoom to full width.
697     float newHeight = screenWidth / outputFrameRatio;
698     if (newHeight > screenHeight)
699     { // zoom to full height
700       newHeight = screenHeight;
701     }
702     // now work out the zoom amount so that no zoom is done
703     CDisplaySettings::Get().SetZoomAmount((m_sourceHeight - CMediaSettings::Get().GetCurrentVideoSettings().m_CropTop - CMediaSettings::Get().GetCurrentVideoSettings().m_CropBottom) / newHeight);
704   }
705   else if (CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode == ViewModeCustom)
706   {
707     CDisplaySettings::Get().SetZoomAmount(CMediaSettings::Get().GetCurrentVideoSettings().m_CustomZoomAmount);
708     CDisplaySettings::Get().SetPixelRatio(CMediaSettings::Get().GetCurrentVideoSettings().m_CustomPixelRatio);
709     CDisplaySettings::Get().SetNonLinearStretched(CMediaSettings::Get().GetCurrentVideoSettings().m_CustomNonLinStretch);
710     CDisplaySettings::Get().SetVerticalShift(CMediaSettings::Get().GetCurrentVideoSettings().m_CustomVerticalShift);
711   }
712   else // if (CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode == ViewModeNormal)
713   {
714     CDisplaySettings::Get().SetPixelRatio(1.0);
715     CDisplaySettings::Get().SetZoomAmount(1.0);
716   }
717
718   CMediaSettings::Get().GetCurrentVideoSettings().m_CustomZoomAmount = CDisplaySettings::Get().GetZoomAmount();
719   CMediaSettings::Get().GetCurrentVideoSettings().m_CustomPixelRatio = CDisplaySettings::Get().GetPixelRatio();
720   CMediaSettings::Get().GetCurrentVideoSettings().m_CustomNonLinStretch = CDisplaySettings::Get().IsNonLinearStretched();
721   CMediaSettings::Get().GetCurrentVideoSettings().m_CustomVerticalShift = CDisplaySettings::Get().GetVerticalShift();
722 }
723
724 void CBaseRenderer::MarkDirty()
725 {
726   g_windowManager.MarkDirty(m_destRect);
727 }
728
729 void CBaseRenderer::SettingOptionsRenderMethodsFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int &current)
730 {
731   list.push_back(make_pair(g_localizeStrings.Get(13416), RENDER_METHOD_AUTO));
732
733 #ifdef HAS_DX
734   if (g_sysinfo.IsWindowsVersionAtLeast(CSysInfo::WindowsVersionVista))
735     list.push_back(make_pair(g_localizeStrings.Get(16319), RENDER_METHOD_DXVA));
736   list.push_back(make_pair(g_localizeStrings.Get(13431), RENDER_METHOD_D3D_PS));
737   list.push_back(make_pair(g_localizeStrings.Get(13419), RENDER_METHOD_SOFTWARE));
738 #endif
739
740 #ifdef HAS_GL
741   list.push_back(make_pair(g_localizeStrings.Get(13417), RENDER_METHOD_ARB));
742   list.push_back(make_pair(g_localizeStrings.Get(13418), RENDER_METHOD_GLSL));
743   list.push_back(make_pair(g_localizeStrings.Get(13419), RENDER_METHOD_SOFTWARE));
744 #endif
745 }