MythTV  master
mythvideobounds.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Daniel Kristjansson, Jens Rehaag 2008
3  *
4  * This class encapsulates some of the video framing information,
5  * so that a VideoOutput class can have multiple concurrent video
6  * windows displayed at any one time.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 // Qt
24 #include <QApplication>
25 
26 // MythtTV
27 #include "mythconfig.h"
28 #include "mythmiscutil.h"
29 #include "mythplayer.h"
30 #include "mythcorecontext.h"
31 #include "mythmainwindow.h"
32 #include "mythvideobounds.h"
33 
34 // Std
35 #include <cmath>
36 
37 #define LOC QString("VideoBounds: ")
38 
39 #define SCALED_RECT(SRC, SCALE) QRect{ static_cast<int>((SRC).left() * (SCALE)), \
40  static_cast<int>((SRC).top() * (SCALE)), \
41  static_cast<int>((SRC).width() * (SCALE)), \
42  static_cast<int>((SRC).height() * (SCALE)) }
43 
44 static float fix_aspect(float raw);
45 static float snap(float value, float snapto, float diff);
46 
52 
54  : m_dbMove( { gCoreContext->GetNumSetting("xScanDisplacement", 0),
55  gCoreContext->GetNumSetting("yScanDisplacement", 0) }),
56  m_dbUseGUISize(gCoreContext->GetBoolSetting("GuiSizeForTV", false)),
57  m_dbAspectOverride(static_cast<AspectOverrideMode>(gCoreContext->GetNumSetting("AspectOverride", 0))),
58  m_dbAdjustFill(static_cast<AdjustFillMode>(gCoreContext->GetNumSetting("AdjustFill", 0)))
59 {
60 }
61 
68 {
71 }
72 
74 {
75  if (m_display)
76  {
77  LOG(VB_GENERAL, LOG_WARNING, LOC + "Already have a display");
78  return;
79  }
80 
81  m_display = mDisplay;
83 #ifdef Q_OS_MACOS
85 #endif
86 }
87 
88 void MythVideoBounds::ScreenChanged(QScreen */*screen*/)
89 {
91  MoveResize();
92 }
93 
95 {
96  // PopulateGeometry will update m_devicePixelRatio
99  MoveResize();
100 }
101 
103 {
104  if (!m_display)
105  return;
106 
107  QScreen *screen = m_display->GetCurrentScreen();
108  if (!screen)
109  return;
110 
111 #ifdef Q_OS_MACOS
112  m_devicePixelRatio = screen->devicePixelRatio();
113 #endif
114 
116  {
117  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Window using all screens %1x%2")
118  .arg(screen->virtualGeometry().width()).arg(screen->virtualGeometry().height()));
119  return;
120  }
121 
122  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Window using screen '%1' %2x%3")
123  .arg(screen->name()).arg(screen->geometry().width()).arg(screen->geometry().height()));
124 }
125 
137 {
138  // for 'portrait' mode, rotate the 'screen' dimensions
139  float tempdisplayaspect = m_displayAspect;
140  bool rotate = (m_rotation == 90) || (m_rotation == -90);
141  if (rotate)
142  Rotate();
143 
144  // Preset all image placement and sizing variables.
145  m_videoRect = QRect(QPoint(0, 0), m_videoDispDim);
147 
148  // Apply various modifications
152 
153  // Interactive TV (MHEG) embedding
154  if (m_itvResizing)
156 
157  // and switch back
158  if (rotate)
159  Rotate();
160  m_displayAspect = tempdisplayaspect;
161 
163 
164  // TODO fine tune when these are emitted - it is not enough to just check whether the values
165  // have changed
170 
172 }
173 
184 {
185  m_dbMove = QPoint(m_dbMove.y(), m_dbMove.x());
186  float temp = m_dbHorizScale;
188  m_dbVertScale = temp;
189  temp = m_manualHorizScale;
191  m_manualVertScale = temp;
192  m_manualMove = QPoint(m_manualMove.y(), m_manualMove.x());
194 
195  m_displayVisibleRect = QRect(QPoint(m_displayVisibleRect.top(), m_displayVisibleRect.left()),
196  QSize(m_displayVisibleRect.height(), m_displayVisibleRect.width()));
197  m_displayVideoRect = QRect(QPoint(m_displayVideoRect.top(), m_displayVideoRect.left()),
198  QSize(m_displayVideoRect.height(), m_displayVideoRect.width()));
207 }
208 
219 {
220  if (m_dbVertScale > 0)
221  {
222  // Veritcal overscan. Move the Y start point in original image.
223  float tmp = 1.0F - 2.0F * m_dbVertScale;
224  m_videoRect.moveTop(qRound(m_videoRect.height() * m_dbVertScale));
225  m_videoRect.setHeight(qRound(m_videoRect.height() * tmp));
226 
227  // If there is an offset, apply it now that we have a room.
228  int yoff = m_dbMove.y();
229  if (yoff > 0)
230  {
231  // To move the image down, move the start point up.
232  // Don't offset the image more than we have overscanned.
233  yoff = std::min(m_videoRect.top(), yoff);
234  m_videoRect.moveTop(m_videoRect.top() - yoff);
235  }
236  else if (yoff < 0)
237  {
238  // To move the image up, move the start point down.
239  // Don't offset the image more than we have overscanned.
240  if (abs(yoff) > m_videoRect.top())
241  yoff = 0 - m_videoRect.top();
242  m_videoRect.moveTop(m_videoRect.top() - yoff);
243  }
244  }
245  else if (m_dbVertScale < 0)
246  {
247  // Vertical underscan. Move the starting Y point in the display window.
248  // Use the abolute value of scan factor.
249  float vscanf = fabs(m_dbVertScale);
250  float tmp = 1.0F - 2.0F * vscanf;
251 
252  m_displayVideoRect.moveTop(qRound(m_displayVisibleRect.height() * vscanf) + m_displayVisibleRect.top());
253  m_displayVideoRect.setHeight(qRound(m_displayVisibleRect.height() * tmp));
254 
255  // Now offset the image within the extra blank space created by
256  // underscanning. To move the image down, increase the Y offset
257  // inside the display window.
258  int yoff = m_dbMove.y();
259  if (yoff > 0)
260  {
261  // Don't offset more than we have underscanned.
262  yoff = std::min(m_displayVideoRect.top(), yoff);
263  m_displayVideoRect.moveTop(m_displayVideoRect.top() + yoff);
264  }
265  else if (yoff < 0)
266  {
267  // Don't offset more than we have underscanned.
268  if (abs(yoff) > m_displayVideoRect.top())
269  yoff = 0 - m_displayVideoRect.top();
270  m_displayVideoRect.moveTop(m_displayVideoRect.top() + yoff);
271  }
272  }
273 
274  // Horizontal.. comments, same as vertical...
275  if (m_dbHorizScale > 0)
276  {
277  float tmp = 1.0F - 2.0F * m_dbHorizScale;
278  m_videoRect.moveLeft(qRound(m_videoDispDim.width() * m_dbHorizScale));
279  m_videoRect.setWidth(qRound(m_videoDispDim.width() * tmp));
280 
281  int xoff = m_dbMove.x();
282  if (xoff > 0)
283  {
284  xoff = std::min(m_videoRect.left(), xoff);
285  m_videoRect.moveLeft(m_videoRect.left() - xoff);
286  }
287  else if (xoff < 0)
288  {
289  if (abs(xoff) > m_videoRect.left())
290  xoff = 0 - m_videoRect.left();
291  m_videoRect.moveLeft(m_videoRect.left() - xoff);
292  }
293  }
294  else if (m_dbHorizScale < 0)
295  {
296  float hscanf = fabs(m_dbHorizScale);
297  float tmp = 1.0F - 2.0F * hscanf;
298 
299  m_displayVideoRect.moveLeft(qRound(m_displayVisibleRect.width() * hscanf) + m_displayVisibleRect.left());
300  m_displayVideoRect.setWidth(qRound(m_displayVisibleRect.width() * tmp));
301 
302  int xoff = m_dbMove.x();
303  if (xoff > 0)
304  {
305  xoff = std::min(m_displayVideoRect.left(), xoff);
306  m_displayVideoRect.moveLeft(m_displayVideoRect.left() + xoff);
307  }
308  else if (xoff < 0)
309  {
310  if (abs(xoff) > m_displayVideoRect.left())
311  xoff = 0 - m_displayVideoRect.left();
312  m_displayVideoRect.moveLeft(m_displayVideoRect.left() + xoff);
313  }
314  }
315 
316 }
317 
322 {
323  if ((m_manualVertScale != 1.0F) || (m_manualHorizScale != 1.0F))
324  {
325  QSize newsz = QSize(qRound(m_displayVideoRect.width() * m_manualHorizScale),
326  qRound(m_displayVideoRect.height() * m_manualVertScale));
327  QSize tmp = (m_displayVideoRect.size() - newsz) / 2;
328  QPoint chgloc = QPoint(tmp.width(), tmp.height());
329  QPoint newloc = m_displayVideoRect.topLeft() + chgloc;
330 
331  m_displayVideoRect = QRect(newloc, newsz);
332  }
333 
334  if (m_manualMove.y())
335  {
336  int move_vert = m_manualMove.y() * m_displayVideoRect.height() / 100;
337  m_displayVideoRect.moveTop(m_displayVideoRect.top() + move_vert);
338  }
339 
340  if (m_manualMove.x())
341  {
342  int move_horiz = m_manualMove.x() * m_displayVideoRect.width() / 100;
343  m_displayVideoRect.moveLeft(m_displayVideoRect.left() + move_horiz);
344  }
345 }
346 
347 // Code should take into account the aspect ratios of both the video as
348 // well as the actual screen to allow proper letterboxing to take place.
350 {
351  float disp_aspect = fix_aspect(GetDisplayAspect());
352  float aspect_diff = disp_aspect - m_videoAspectOverride;
353  bool aspects_match = abs(aspect_diff / disp_aspect) <= 0.02F;
354  bool nomatch_with_fill = !aspects_match && ((kAdjustFill_HorizontalStretch == m_adjustFill) ||
356  bool nomatch_without_fill = (!aspects_match) && !nomatch_with_fill;
357 
358  // Adjust for video/display aspect ratio mismatch
359  if (nomatch_with_fill && (disp_aspect > m_videoAspectOverride))
360  {
361  int pixNeeded = qRound(((disp_aspect / m_videoAspectOverride) * static_cast<float>(m_displayVideoRect.height())));
362  m_displayVideoRect.moveTop(m_displayVideoRect.top() + (m_displayVideoRect.height() - pixNeeded) / 2);
363  m_displayVideoRect.setHeight(pixNeeded);
364  }
365  else if (nomatch_with_fill)
366  {
367  int pixNeeded = qRound(((m_videoAspectOverride / disp_aspect) * static_cast<float>(m_displayVideoRect.width())));
368  m_displayVideoRect.moveLeft(m_displayVideoRect.left() + (m_displayVideoRect.width() - pixNeeded) / 2);
369  m_displayVideoRect.setWidth(pixNeeded);
370  }
371  else if (nomatch_without_fill && (disp_aspect > m_videoAspectOverride))
372  {
373  int pixNeeded = qRound(((m_videoAspectOverride / disp_aspect) * static_cast<float>(m_displayVideoRect.width())));
374  m_displayVideoRect.moveLeft(m_displayVideoRect.left() + (m_displayVideoRect.width() - pixNeeded) / 2);
375  m_displayVideoRect.setWidth(pixNeeded);
376  }
377  else if (nomatch_without_fill)
378  {
379  int pixNeeded = qRound(((disp_aspect / m_videoAspectOverride) * static_cast<float>(m_displayVideoRect.height())));
380  m_displayVideoRect.moveTop(m_displayVideoRect.top() + (m_displayVideoRect.height() - pixNeeded) / 2);
381  m_displayVideoRect.setHeight(pixNeeded);
382  }
383 
384  // Process letterbox zoom modes
386  {
387  // Zoom mode -- Expand by 4/3 and overscan.
388  // 1/6 of original is 1/8 of new
389  m_displayVideoRect = QRect(
390  m_displayVideoRect.left() - (m_displayVideoRect.width() / 6),
391  m_displayVideoRect.top() - (m_displayVideoRect.height() / 6),
392  m_displayVideoRect.width() * 4 / 3,
393  m_displayVideoRect.height() * 4 / 3);
394  }
395  else if (m_adjustFill == kAdjustFill_Half)
396  {
397  // Zoom mode -- Expand by 7/6 and overscan.
398  // Intended for eliminating the top bars on 14:9 material.
399  // Also good compromise for 4:3 material on 16:9 screen.
400  // Expanding by 7/6, so remove 1/6 of original from overscan;
401  // take half from each side, so remove 1/12.
402  m_displayVideoRect = QRect(
403  m_displayVideoRect.left() - (m_displayVideoRect.width() / 12),
404  m_displayVideoRect.top() - (m_displayVideoRect.height() / 12),
405  m_displayVideoRect.width() * 7 / 6,
406  m_displayVideoRect.height() * 7 / 6);
407  }
409  {
410  // Horizontal Stretch mode -- 1/6 of original is 1/8 of new
411  // Intended to be used to eliminate side bars on 4:3 material
412  // encoded to 16:9.
413  m_displayVideoRect.moveLeft(
414  m_displayVideoRect.left() - (m_displayVideoRect.width() / 6));
415 
416  m_displayVideoRect.setWidth(m_displayVideoRect.width() * 4 / 3);
417  }
419  {
420  // Vertical Stretch mode -- 1/6 of original is 1/8 of new
421  // Intended to be used to eliminate top/bottom bars on 16:9
422  // material encoded to 4:3.
423  m_displayVideoRect.moveTop(
424  m_displayVideoRect.top() - (m_displayVideoRect.height() / 6));
425 
426  m_displayVideoRect.setHeight(m_displayVideoRect.height() * 4 / 3);
427  }
428  else if (m_adjustFill == kAdjustFill_VerticalFill && m_displayVideoRect.height() > 0)
429  {
430  // Video fills screen vertically. May be cropped left and right
431  float factor = static_cast<float>(m_displayVisibleRect.height()) / static_cast<float>(m_displayVideoRect.height());
432  QSize newsize = QSize(qRound(m_displayVideoRect.width() * factor),
433  qRound(m_displayVideoRect.height() * factor));
434  QSize temp = (m_displayVideoRect.size() - newsize) / 2;
435  QPoint newloc = m_displayVideoRect.topLeft() + QPoint(temp.width(), temp.height());
436  m_displayVideoRect = QRect(newloc, newsize);
437  }
439  {
440  // Video fills screen horizontally. May be cropped top and bottom
441  float factor = static_cast<float>(m_displayVisibleRect.width()) /
442  static_cast<float>(m_displayVideoRect.width());
443  QSize newsize = QSize(qRound(m_displayVideoRect.width() * factor),
444  qRound(m_displayVideoRect.height() * factor));
445  QSize temp = (m_displayVideoRect.size() - newsize) / 2;
446  QPoint newloc = m_displayVideoRect.topLeft() + QPoint(temp.width(), temp.height());
447  m_displayVideoRect = QRect(newloc, newsize);
448  }
449 }
450 
451 bool MythVideoBounds::InitBounds(QSize VideoDim, QSize VideoDispDim,
452  float Aspect, QRect WindowRect)
453 {
454  if (m_display)
455  {
456  QString dummy;
457  m_displayAspect = static_cast<float>(m_display->GetAspectRatio(dummy));
458  }
459 
460  // Refresh the geometry in case the video mode has changed
462 
463  // N.B. we are always confined to the window size so use that for the initial
464  // displayVisibleRect
465  m_rawWindowRect = WindowRect;
467  m_videoDispDim = Fix1088(VideoDispDim);
468  m_videoDim = VideoDim;
469  m_videoRect = QRect(m_displayVisibleRect.topLeft(), m_videoDispDim);
470 
473  m_embedding = false;
474  SetVideoAspectRatio(Aspect);
475  MoveResize();
476  return true;
477 }
478 
480 {
481  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Window Rect: %1x%2+%3+%4")
482  .arg(m_windowRect.width()).arg(m_windowRect.height())
483  .arg(m_windowRect.left()).arg(m_windowRect.top()));
484  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Display Rect: %1x%2+%3+%4 Aspect: %5")
485  .arg(m_displayVideoRect.width()).arg(m_displayVideoRect.height())
486  .arg(m_displayVideoRect.left()).arg(m_displayVideoRect.top())
487  .arg(static_cast<qreal>(fix_aspect(GetDisplayAspect()))));
488  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Video Rect: %1x%2+%3+%4 Aspect: %5")
489  .arg(m_videoRect.width()).arg(m_videoRect.height())
490  .arg(m_videoRect.left()).arg(m_videoRect.top())
491  .arg(static_cast<qreal>(m_videoAspectOverride)));
492 }
493 
502 {
503  m_videoAspect = aspect;
505 }
506 
513 {
514  if (!qFuzzyCompare(Aspect, m_videoAspect))
515  {
516  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New video aspect ratio: '%1'")
517  .arg(static_cast<double>(Aspect)));
518  SetVideoAspectRatio(Aspect);
519  MoveResize();
520  }
521 }
522 
524 void MythVideoBounds::SourceChanged(QSize VideoDim, QSize VideoDispDim, float Aspect)
525 {
526  if (Aspect < 0.0F)
527  Aspect = m_videoAspect;
528 
529  QSize newvideodispdim = Fix1088(VideoDispDim);
530 
531  if (!((VideoDim == m_videoDim) && (newvideodispdim == m_videoDispDim) &&
532  qFuzzyCompare(Aspect + 100.0F, m_videoAspect + 100.0F)))
533  {
534  m_videoDispDim = newvideodispdim;
535  m_videoDim = VideoDim;
536  SetVideoAspectRatio(Aspect);
537  LOG(VB_PLAYBACK, LOG_INFO, LOC +
538  QString("New video parameters: Size %1x%2 DisplaySize: %3x%4 Aspect: %5")
539  .arg(m_videoDim.width()).arg(m_videoDim.height())
540  .arg(m_videoDispDim.width()).arg(m_videoDispDim.height())
541  .arg(static_cast<double>(m_videoAspect)));
542  MoveResize();
543  }
544 }
545 
546 QSize MythVideoBounds::Fix1088(QSize Dimensions)
547 {
548  QSize result = Dimensions;
549  // 544 represents a 1088 field
550  if (result.width() == 1920 || result.width() == 1440)
551  {
552  if (result.height() == 1088)
553  result.setHeight(1080);
554  else if (result.height() == 544)
555  result.setHeight(540);
556  }
557  return result;
558 }
559 
566 {
568  AdjustFill = static_cast<AdjustFillMode>((m_adjustFill + 1) % kAdjustFill_END);
569  if (m_adjustFill != AdjustFill)
570  {
572  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New fill mode: '%1'").arg(toString(m_adjustFill)));
573  MoveResize();
574  }
575 }
576 
581 {
582  float oldvert = m_dbVertScale;
583  float oldhoriz = m_dbHorizScale;
584 
585  if (Change)
586  {
587  m_dbVertScale = gCoreContext->GetNumSetting("VertScanPercentage", 0) * 0.01F;
588  m_dbHorizScale = gCoreContext->GetNumSetting("HorizScanPercentage", 0) * 0.01F;
589  m_dbScalingAllowed = true;
590  }
591  else
592  {
593  m_dbVertScale = 0.0F;
594  m_dbHorizScale = 0.0F;
595  m_dbScalingAllowed = false;
596  }
597 
598  if (!(qFuzzyCompare(oldvert + 100.0F, m_dbVertScale + 100.0F) &&
599  qFuzzyCompare(oldhoriz + 100.0F, m_dbHorizScale + 100.0F)))
600  {
601  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Over/underscan. V: %1, H: %2")
602  .arg(static_cast<double>(m_dbVertScale)).arg(static_cast<double>(m_dbHorizScale)));
603  MoveResize();
604  }
605 }
606 
607 void MythVideoBounds::SetDisplayAspect(float DisplayAspect)
608 {
609  if (!qFuzzyCompare(DisplayAspect + 10.0F, m_displayAspect + 10.0F))
610  {
611  LOG(VB_GENERAL, LOG_INFO, LOC + QString("New display aspect: %1")
612  .arg(static_cast<double>(DisplayAspect)));
613  m_displayAspect = DisplayAspect;
614  MoveResize();
615  }
616 }
617 
619 {
620  if (Size != m_rawWindowRect.size())
621  {
622  QRect rect(m_rawWindowRect.topLeft(), Size);
623  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New window rect: %1x%2+%3+%4")
624  .arg(rect.width()).arg(rect.height()).arg(rect.left()).arg(rect.top()));
625  m_rawWindowRect = rect;
627  MoveResize();
628  }
629 }
630 
632 {
633  QRect oldrect = m_rawItvDisplayVideoRect;
634  if (Rect.isEmpty())
635  {
636  m_itvResizing = false;
637  m_itvDisplayVideoRect = QRect();
638  m_rawItvDisplayVideoRect = QRect();
639  }
640  else
641  {
642  m_itvResizing = true;
645  }
646  if (m_rawItvDisplayVideoRect != oldrect)
647  {
648  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New ITV display rect: %1x%2+%3+%4 (Scale: %5)")
649  .arg(m_itvDisplayVideoRect.width()).arg(m_itvDisplayVideoRect.height())
650  .arg(m_itvDisplayVideoRect.left()).arg(m_itvDisplayVideoRect.right())
651  .arg(m_devicePixelRatio));
652  MoveResize();
653  }
654 }
655 
661 {
662  if (Rotation == m_rotation)
663  return;
664  if ((Rotation < -180) || (Rotation > 180))
665  return;
666 
667  m_rotation = Rotation;
668  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New rotation: %1").arg(m_rotation));
669  MoveResize();
670 }
671 
675 void MythVideoBounds::ResizeDisplayWindow(QRect Rect, bool SaveVisibleRect)
676 {
677  if (SaveVisibleRect)
679  m_displayVisibleRect = Rect;
680  MoveResize();
681 }
682 
683 void MythVideoBounds::EmbedPlayback(bool Embed, QRect Rect)
684 {
685  if (Embed)
686  {
687  if (m_embedding && (Rect == m_rawEmbeddingRect))
688  return;
689 
690  m_rawEmbeddingRect = Rect;
692  bool savevisiblerect = !m_embedding;
693  m_embedding = true;
694  m_embeddingHidden = Rect.isEmpty();
696  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New embedding rect: %1x%2+%3+%4 (Scale: %5)")
697  .arg(m_embeddingRect.width()).arg(m_embeddingRect.height())
698  .arg(m_embeddingRect.left()).arg(m_embeddingRect.top())
699  .arg(m_devicePixelRatio));
700  ResizeDisplayWindow(m_displayVideoRect, savevisiblerect);
701  return;
702  }
703 
704  if (!m_embedding)
705  return;
706  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Stopped embedding");
707  m_rawEmbeddingRect = QRect();
708  m_embeddingRect = QRect();
710  m_embedding = false;
711  m_embeddingHidden = false;
712  MoveResize();
713 }
714 
722 {
723  if (AspectMode == kAspect_Toggle)
724  AspectMode = static_cast<AspectOverrideMode>(((m_videoAspectOverrideMode + 1) % kAspect_END));
725 
726  if (m_videoAspectOverrideMode != AspectMode)
727  {
728  m_videoAspectOverrideMode = AspectMode;
729  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New video aspect override: '%1'")
732  MoveResize();
733  }
734 
736 }
737 
743 {
744  if (IsEmbedding())
745  return false;
746 
747  return m_displayVideoRect.contains(m_windowRect);
748 }
749 
755 {
756  QRegion visible(m_windowRect);
757  QRegion video(m_displayVideoRect);
758  return visible.subtracted(video);
759 }
760 
766 {
767  float oldvertscale = m_manualVertScale;
768  float oldhorizscale = m_manualHorizScale;
769  QPoint oldmove = m_manualMove;
770 
771  const float zf = 0.02F;
772  if (kZoomHome == Direction)
773  {
774  m_manualVertScale = 1.0F;
775  m_manualHorizScale = 1.0F;
776  m_manualMove = QPoint(0, 0);
777  }
778  else if (kZoomIn == Direction)
779  {
782  {
783  m_manualHorizScale += zf;
784  m_manualVertScale += zf;
785  }
786  }
787  else if (kZoomOut == Direction)
788  {
791  {
792  m_manualHorizScale -= zf;
793  m_manualVertScale -= zf;
794  }
795  }
796  else if (kZoomAspectUp == Direction)
797  {
800  {
801  m_manualHorizScale += zf;
802  m_manualVertScale -= zf;
803  }
804  }
805  else if (kZoomAspectDown == Direction)
806  {
809  {
810  m_manualHorizScale -= zf;
811  m_manualVertScale += zf;
812  }
813  }
814  else if (kZoomVerticalIn == Direction)
815  {
817  m_manualVertScale += zf;
818  }
819  else if (kZoomVerticalOut == Direction)
820  {
822  m_manualVertScale -= zf;
823  }
824  else if (kZoomHorizontalIn == Direction)
825  {
827  m_manualHorizScale += zf;
828  }
829  else if (kZoomHorizontalOut == Direction)
830  {
832  m_manualHorizScale -= zf;
833  }
834  else if (kZoomUp == Direction && (m_manualMove.y() < +kManualZoomMaxMove))
835  m_manualMove.setY(m_manualMove.y() + 1);
836  else if (kZoomDown == Direction && (m_manualMove.y() > -kManualZoomMaxMove))
837  m_manualMove.setY(m_manualMove.y() - 1);
838  else if (kZoomLeft == Direction && (m_manualMove.x() < +kManualZoomMaxMove))
839  m_manualMove.setX(m_manualMove.x() + 2);
840  else if (kZoomRight == Direction && (m_manualMove.x() > -kManualZoomMaxMove))
841  m_manualMove.setX(m_manualMove.x() - 2);
842 
843  m_manualVertScale = snap(m_manualVertScale, 1.0F, zf / 2);
844  m_manualHorizScale = snap(m_manualHorizScale, 1.0F, zf / 2);
845 
846  if (!((oldmove == m_manualMove) && qFuzzyCompare(m_manualVertScale + 100.0F, oldvertscale + 100.0F) &&
847  qFuzzyCompare(m_manualHorizScale + 100.0F, oldhorizscale + 100.0F)))
848  {
849  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New zoom: Offset %1x%2 HScale %3 VScale %4")
850  .arg(m_manualMove.x()).arg(m_manualMove.y())
851  .arg(static_cast<double>(m_manualHorizScale))
852  .arg(static_cast<double>(m_manualVertScale)));
853  MoveResize();
854  }
855 }
856 
858 {
859  float oldvertscale = m_manualVertScale;
860  float oldhorizscale = m_manualHorizScale;
861  QPoint oldmove = m_manualMove;
862 
863  if (m_bottomLine)
864  {
865  m_manualMove.setX(0);
866  m_manualMove.setY(0);
867  m_manualHorizScale = 1.0;
868  m_manualVertScale = 1.0;
869  m_bottomLine = false;
870  }
871  else
872  {
873  const float zf = 0.02F;
874  m_manualMove.setX(gCoreContext->GetNumSetting("OSDMoveXBottomLine", 0));
875  m_manualMove.setY(gCoreContext->GetNumSetting("OSDMoveYBottomLine", 5));
876  float h = static_cast<float>(gCoreContext->GetNumSetting("OSDScaleHBottomLine", 100)) / 100.0F;
877  m_manualHorizScale = snap(h, 1.0F, zf / 2.0F);
878  float v = static_cast<float>(gCoreContext->GetNumSetting("OSDScaleVBottomLine", 112)) / 100.0F;
879  m_manualVertScale = snap(v, 1.0F, zf / 2.0F);
880  m_bottomLine = true;
881  }
882 
883  if (!((oldmove == m_manualMove) && qFuzzyCompare(m_manualVertScale + 100.0F, oldvertscale + 100.0F) &&
884  qFuzzyCompare(m_manualHorizScale + 100.0F, oldhorizscale + 100.0F)))
885  {
886  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New custom zoom: Offset %1x%2 HScale %3 VScale %4")
887  .arg(m_manualMove.x()).arg(m_manualMove.y())
888  .arg(static_cast<double>(m_manualHorizScale))
889  .arg(static_cast<double>(m_manualVertScale)));
890  MoveResize();
891  }
892 
894 }
895 
897 {
898  gCoreContext->SaveSetting("OSDMoveXBottomLine", m_manualMove.x());
899  gCoreContext->SaveSetting("OSDMoveYBottomLine", m_manualMove.y());
900  gCoreContext->SaveSetting("OSDScaleHBottomLine", static_cast<int>(m_manualHorizScale * 100.0F));
901  gCoreContext->SaveSetting("OSDScaleVBottomLine", static_cast<int>(m_manualVertScale * 100.0F));
902 
903  emit UpdateOSDMessage("Current 'Manual Zoom' saved for 'BottomLine'.");
904 }
905 
907 static float fix_aspect(float raw)
908 {
909  // Check if close to 4:3
910  if (fabs(raw - 1.333333F) < 0.05F)
911  raw = 1.333333F;
912 
913  // Check if close to 16:9
914  if (fabs(raw - 1.777777F) < 0.05F)
915  raw = 1.777777F;
916 
917  return raw;
918 }
919 
920 static float snap(float value, float snapto, float diff)
921 {
922  if ((value + diff > snapto) && (value - diff < snapto))
923  return snapto;
924  return value;
925 }
926 
928 {
929  if (Mode != m_stereoOverride)
930  {
931  m_stereoOverride = Mode;
933  }
934 }
kAspect_Toggle
@ kAspect_Toggle
Definition: videoouttypes.h:62
StereoscopictoString
QString StereoscopictoString(StereoscopicMode Mode)
Definition: videoouttypes.h:170
kAdjustFill_Toggle
@ kAdjustFill_Toggle
Definition: videoouttypes.h:73
MythVideoBounds::kManualZoomMaxVerticalZoom
static const float kManualZoomMaxVerticalZoom
Definition: mythvideobounds.h:164
MythVideoBounds::IsEmbedding
bool IsEmbedding(void) const
Definition: mythvideobounds.h:68
kZoomHorizontalIn
@ kZoomHorizontalIn
Definition: videoouttypes.h:49
MythVideoBounds::VideoAspectRatioChanged
void VideoAspectRatioChanged(float Aspect)
Calls SetVideoAspectRatio(float aspect), then calls MoveResize() to apply changes.
Definition: mythvideobounds.cpp:512
MythVideoBounds::PhysicalDPIChanged
void PhysicalDPIChanged(qreal)
Definition: mythvideobounds.cpp:94
MythVideoBounds::m_rawWindowRect
QRect m_rawWindowRect
Rectangle describing QWidget bounds - not adjusted for high DPI scaling (macos)
Definition: mythvideobounds.h:144
kZoomIn
@ kZoomIn
Definition: videoouttypes.h:45
MythVideoBounds::m_displayVideoRect
QRect m_displayVideoRect
Pixel rectangle in display window into which video_rect maps to.
Definition: mythvideobounds.h:137
MythVideoBounds::m_tmpDisplayVisibleRect
QRect m_tmpDisplayVisibleRect
Used to save the display_visible_rect for restoration after video embedding ends.
Definition: mythvideobounds.h:147
kAdjustFill_HorizontalStretch
@ kAdjustFill_HorizontalStretch
Definition: videoouttypes.h:77
MythVideoBounds::m_dbVertScale
float m_dbVertScale
Vertical Overscan/Underscan percentage.
Definition: mythvideobounds.h:104
MythVideoBounds::EmbedPlayback
virtual void EmbedPlayback(bool Embed, QRect Rect)
Definition: mythvideobounds.cpp:683
GetZoomString
QString GetZoomString(float HorizScale, float VertScale, QPoint Move)
Definition: videoouttypes.h:359
MythVideoBounds::MythVideoBounds
MythVideoBounds()
Definition: mythvideobounds.cpp:53
kZoomAspectUp
@ kZoomAspectUp
Definition: videoouttypes.h:55
AdjustFill
static HostComboBoxSetting * AdjustFill()
Definition: globalsettings.cpp:2172
MythVideoBounds::ApplyDBScaleAndMove
void ApplyDBScaleAndMove(void)
Apply scales and moves for "Overscan" and "Underscan" DB settings.
Definition: mythvideobounds.cpp:218
MythVideoBounds::GetDisplayAspect
float GetDisplayAspect(void) const
Definition: mythvideobounds.h:82
kZoomUp
@ kZoomUp
Definition: videoouttypes.h:51
MythVideoBounds::RefreshVideoBoundsState
void RefreshVideoBoundsState()
Send out latest state to listeners.
Definition: mythvideobounds.cpp:67
MythVideoBounds::m_videoAspect
float m_videoAspect
Physical aspect ratio of video.
Definition: mythvideobounds.h:122
arg
arg(title).arg(filename).arg(doDelete))
MythVideoBounds::m_rawItvDisplayVideoRect
QRect m_rawItvDisplayVideoRect
Definition: mythvideobounds.h:155
kZoomHome
@ kZoomHome
Definition: videoouttypes.h:44
MythVideoBounds::m_devicePixelRatio
qreal m_devicePixelRatio
Definition: mythvideobounds.h:109
MythVideoBounds::m_itvResizing
bool m_itvResizing
Definition: mythvideobounds.h:153
kAdjustFill_VerticalStretch
@ kAdjustFill_VerticalStretch
Definition: videoouttypes.h:78
kZoomRight
@ kZoomRight
Definition: videoouttypes.h:54
MythDisplay::GetAspectRatio
double GetAspectRatio(QString &Source, bool IgnoreModeOverride=false)
Returns current screen aspect ratio.
Definition: mythdisplay.cpp:778
MythDisplay::SpanAllScreens
static bool SpanAllScreens()
Return true if the MythTV windows should span all screens.
Definition: mythdisplay.cpp:447
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythVideoBounds::VideoRectsChanged
void VideoRectsChanged(const QRect &DisplayVideoRect, const QRect &VideoRect)
mythplayer.h
MythDisplay::GetCurrentScreen
QScreen * GetCurrentScreen()
Return a pointer to the screen to use.
Definition: mythdisplay.cpp:280
kZoomVerticalOut
@ kZoomVerticalOut
Definition: videoouttypes.h:48
MythVideoBounds::m_dbScalingAllowed
bool m_dbScalingAllowed
disable this to prevent overscan/underscan
Definition: mythvideobounds.h:105
MythVideoBounds::PrintMoveResizeDebug
void PrintMoveResizeDebug(void)
Definition: mythvideobounds.cpp:479
MythDisplay::PhysicalDPIChanged
void PhysicalDPIChanged(qreal DPI)
Definition: mythdisplay.cpp:389
MythVideoBounds::UpdateOSDMessage
void UpdateOSDMessage(const QString &Message)
get_aspect_override
float get_aspect_override(AspectOverrideMode Aspectmode, float Original)
Definition: videoouttypes.h:250
video
QDomElement video
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:661
MythDisplay::CurrentScreenChanged
void CurrentScreenChanged(QScreen *qScreen)
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
MythVideoBounds::SaveBottomLine
void SaveBottomLine(void)
Definition: mythvideobounds.cpp:896
MythVideoBounds::m_embedding
bool m_embedding
State variables.
Definition: mythvideobounds.h:158
MythVideoBounds::m_dbAspectOverride
AspectOverrideMode m_dbAspectOverride
Definition: mythvideobounds.h:107
kZoomLeft
@ kZoomLeft
Definition: videoouttypes.h:53
MythVideoBounds::kManualZoomMaxMove
static const int kManualZoomMaxMove
Definition: mythvideobounds.h:167
MythVideoBounds::SetDisplayAspect
void SetDisplayAspect(float DisplayAspect)
Definition: mythvideobounds.cpp:607
toString
QString toString(MarkTypes type)
Definition: programtypes.cpp:26
kAspect_END
@ kAspect_END
Definition: videoouttypes.h:68
MythVideoBounds::m_adjustFill
AdjustFillMode m_adjustFill
Zoom mode.
Definition: mythvideobounds.h:130
MythVideoBounds::SetDisplay
void SetDisplay(MythDisplay *mDisplay)
Definition: mythvideobounds.cpp:73
kAdjustFill_END
@ kAdjustFill_END
Definition: videoouttypes.h:81
MythVideoBounds::ResizeDisplayWindow
void ResizeDisplayWindow(QRect Rect, bool SaveVisibleRect)
Resize Display Window.
Definition: mythvideobounds.cpp:675
MythVideoBounds::VisibleRectChanged
void VisibleRectChanged(const QRect &DisplayVisibleRect)
MythVideoBounds::m_dbHorizScale
float m_dbHorizScale
Horizontal Overscan/Underscan percentage.
Definition: mythvideobounds.h:103
MythVideoBounds::kManualZoomMaxHorizontalZoom
static const float kManualZoomMaxHorizontalZoom
Definition: mythvideobounds.h:163
MythVideoBounds::SourceChanged
void SourceChanged(QSize VideoDim, QSize VideoDispDim, float Aspect)
Update for new source video dimensions and aspect ratio.
Definition: mythvideobounds.cpp:524
fix_aspect
static float fix_aspect(float raw)
Correct for rounding errors.
Definition: mythvideobounds.cpp:907
MythVideoBounds::SetStereoOverride
void SetStereoOverride(StereoscopicMode Mode)
Definition: mythvideobounds.cpp:927
MythVideoBounds::Fix1088
static QSize Fix1088(QSize Dimensions)
Definition: mythvideobounds.cpp:546
MythDisplay::GetScreenCount
static int GetScreenCount()
Definition: mythdisplay.cpp:244
AspectOverrideMode
AspectOverrideMode
Definition: videoouttypes.h:61
MythVideoBounds::ToggleAspectOverride
void ToggleAspectOverride(AspectOverrideMode AspectMode=kAspect_Toggle)
Enforce different aspect ratio than detected, then calls VideoAspectRatioChanged(float) to apply them...
Definition: mythvideobounds.cpp:721
MythVideoBounds::PopulateGeometry
void PopulateGeometry(void)
Definition: mythvideobounds.cpp:102
MythVideoBounds::m_windowRect
QRect m_windowRect
Rectangle describing QWidget bounds.
Definition: mythvideobounds.h:142
kZoomAspectDown
@ kZoomAspectDown
Definition: videoouttypes.h:56
MythVideoBounds::m_videoAspectOverrideMode
AspectOverrideMode m_videoAspectOverrideMode
AspectOverrideMode to use to modify overriden_video_aspect.
Definition: mythvideobounds.h:128
MythVideoBounds::m_dbAdjustFill
AdjustFillMode m_dbAdjustFill
Definition: mythvideobounds.h:108
MythVideoBounds::m_videoAspectOverride
float m_videoAspectOverride
Normally this is the same as videoAspect, but may not be if the user has toggled the aspect override ...
Definition: mythvideobounds.h:126
kZoomOut
@ kZoomOut
Definition: videoouttypes.h:46
MythVideoBounds::m_bottomLine
bool m_bottomLine
Definition: mythvideobounds.h:160
MythVideoBounds::m_manualHorizScale
float m_manualHorizScale
Manually applied horizontal scaling.
Definition: mythvideobounds.h:113
MythVideoBounds::m_displayVisibleRect
QRect m_displayVisibleRect
Visible portion of display window in pixels.
Definition: mythvideobounds.h:140
MythVideoBounds::ApplyLetterboxing
void ApplyLetterboxing(void)
Definition: mythvideobounds.cpp:349
kZoomDown
@ kZoomDown
Definition: videoouttypes.h:52
MythVideoBounds::ToggleAdjustFill
void ToggleAdjustFill(AdjustFillMode AdjustFillMode=kAdjustFill_Toggle)
Sets up letterboxing for various standard video frame and monitor dimensions, then calls MoveResize()...
Definition: mythvideobounds.cpp:565
MythVideoBounds::SetRotation
void SetRotation(int Rotation)
Set the rotation in degrees.
Definition: mythvideobounds.cpp:660
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
MythVideoBounds::VideoSizeChanged
void VideoSizeChanged(const QSize &VideoDim, const QSize &VideoDispDim)
MythDisplay
Definition: mythdisplay.h:19
MythVideoBounds::kManualZoomMinVerticalZoom
static const float kManualZoomMinVerticalZoom
Definition: mythvideobounds.h:166
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:933
kAdjustFill_VerticalFill
@ kAdjustFill_VerticalFill
Definition: videoouttypes.h:80
MythVideoBounds::ToggleMoveBottomLine
void ToggleMoveBottomLine(void)
Definition: mythvideobounds.cpp:857
kAdjustFill_HorizontalFill
@ kAdjustFill_HorizontalFill
Definition: videoouttypes.h:79
StereoscopicMode
StereoscopicMode
Definition: videoouttypes.h:135
LOC
#define LOC
Definition: mythvideobounds.cpp:37
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:927
MythVideoBounds::SetITVResize
void SetITVResize(QRect Rect)
Definition: mythvideobounds.cpp:631
MythVideoBounds::MoveResize
void MoveResize(void)
performs all the calculations for video framing and any resizing.
Definition: mythvideobounds.cpp:136
mythmiscutil.h
MythVideoBounds::GetBoundingRegion
QRegion GetBoundingRegion(void) const
Return the region of DisplayVisibleRect that lies outside of DisplayVideoRect.
Definition: mythvideobounds.cpp:754
mythcorecontext.h
MythVideoBounds::Zoom
void Zoom(ZoomDirection Direction)
Sets up zooming into to different parts of the video.
Definition: mythvideobounds.cpp:765
MythVideoBounds::m_rotation
int m_rotation
Definition: mythvideobounds.h:131
MythVideoBounds::m_itvDisplayVideoRect
QRect m_itvDisplayVideoRect
Definition: mythvideobounds.h:154
AdjustFillMode
AdjustFillMode
Definition: videoouttypes.h:72
MythVideoBounds::SetVideoAspectRatio
void SetVideoAspectRatio(float Aspect)
Sets MythVideoBounds::video_aspect to aspect, and sets MythVideoBounds::overriden_video_aspect if asp...
Definition: mythvideobounds.cpp:501
MythVideoBounds::ScreenChanged
void ScreenChanged(QScreen *screen)
Definition: mythvideobounds.cpp:88
MythVideoBounds::kManualZoomMinHorizontalZoom
static const float kManualZoomMinHorizontalZoom
Definition: mythvideobounds.h:165
MythVideoBounds::InitBounds
bool InitBounds(QSize VideoDim, QSize VideoDispDim, float Aspect, QRect WindowRect)
Definition: mythvideobounds.cpp:451
MythVideoBounds::SetVideoScalingAllowed
void SetVideoScalingAllowed(bool Change)
Disable or enable underscan/overscan.
Definition: mythvideobounds.cpp:580
kZoomVerticalIn
@ kZoomVerticalIn
Definition: videoouttypes.h:47
kAdjustFill_Half
@ kAdjustFill_Half
Definition: videoouttypes.h:75
MythVideoBounds::m_manualMove
QPoint m_manualMove
Manually applied percentage move.
Definition: mythvideobounds.h:114
MythVideoBounds::m_videoDim
QSize m_videoDim
Pixel dimensions of video buffer.
Definition: mythvideobounds.h:120
MythVideoBounds::Rotate
void Rotate(void)
Adjust various settings to facilitate portrait mode calculations.
Definition: mythvideobounds.cpp:183
MythVideoBounds::ApplyManualScaleAndMove
void ApplyManualScaleAndMove(void)
Apply scales and moves from "Zoom Mode" settings.
Definition: mythvideobounds.cpp:321
snap
static float snap(float value, float snapto, float diff)
Definition: mythvideobounds.cpp:920
MythVideoBounds::WindowRectChanged
void WindowRectChanged(const QRect &WindowRect)
MythVideoBounds::m_embeddingRect
QRect m_embeddingRect
Embedded video rectangle.
Definition: mythvideobounds.h:149
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:902
mythmainwindow.h
MythVideoBounds::m_videoRect
QRect m_videoRect
Pixel rectangle in video frame to display.
Definition: mythvideobounds.h:135
mythvideobounds.h
MythVideoBounds::VideoIsFullScreen
bool VideoIsFullScreen(void) const
Check whether the video display rect covers the entire window/framebuffer.
Definition: mythvideobounds.cpp:742
MythVideoBounds::VideoBoundsStateChanged
void VideoBoundsStateChanged(MythVideoBoundsState VideoState)
kZoomHorizontalOut
@ kZoomHorizontalOut
Definition: videoouttypes.h:50
MythVideoBounds::m_stereoOverride
StereoscopicMode m_stereoOverride
Definition: mythvideobounds.h:132
MythVideoBounds::m_dbMove
QPoint m_dbMove
Percentage move from database.
Definition: mythvideobounds.h:102
MythVideoBounds::m_manualVertScale
float m_manualVertScale
Manually applied vertical scaling.
Definition: mythvideobounds.h:112
MythVideoBounds::m_embeddingHidden
bool m_embeddingHidden
Definition: mythvideobounds.h:159
MythVideoBounds::m_videoDispDim
QSize m_videoDispDim
Pixel dimensions of video display area.
Definition: mythvideobounds.h:121
MythVideoBounds::m_displayAspect
float m_displayAspect
Physical aspect ratio of playback window.
Definition: mythvideobounds.h:117
ZoomDirection
ZoomDirection
Definition: videoouttypes.h:43
kAdjustFill_Full
@ kAdjustFill_Full
Definition: videoouttypes.h:76
MythVideoBounds::m_rawEmbeddingRect
QRect m_rawEmbeddingRect
Definition: mythvideobounds.h:150
MythVideoBounds::SetWindowSize
void SetWindowSize(QSize Size)
Definition: mythvideobounds.cpp:618
SCALED_RECT
#define SCALED_RECT(SRC, SCALE)
Definition: mythvideobounds.cpp:39
MythVideoBounds::m_display
MythDisplay * m_display
Definition: mythvideobounds.h:99