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 // Std
24 #include <cmath>
25 
26 // Qt
27 #include <QApplication>
28 
29 // MythtTV
30 #include "libmythbase/mythconfig.h"
34 #include "mythplayer.h"
35 #include "mythvideobounds.h"
36 
37 #define LOC QString("VideoBounds: ")
38 
39 static inline QRect SCALED_RECT(QRect src, qreal scale)
40 { return {static_cast<int>(src.left() * scale),
41  static_cast<int>(src.top() * scale),
42  static_cast<int>(src.width() * scale),
43  static_cast<int>(src.height() * scale) }; }
44 
45 static float fix_aspect(float raw);
46 static float snap(float value, float snapto, float diff);
47 
53 
55  : m_dbMove( { gCoreContext->GetNumSetting("xScanDisplacement", 0),
56  gCoreContext->GetNumSetting("yScanDisplacement", 0) }),
57  m_dbUseGUISize(gCoreContext->GetBoolSetting("GuiSizeForTV", false)),
58  m_dbAspectOverride(static_cast<AspectOverrideMode>(gCoreContext->GetNumSetting("AspectOverride", 0))),
59  m_dbAdjustFill(static_cast<AdjustFillMode>(gCoreContext->GetNumSetting("AdjustFill", 0)))
60 {
61 }
62 
69 {
72 }
73 
75 {
76  if (m_display)
77  {
78  LOG(VB_GENERAL, LOG_WARNING, LOC + "Already have a display");
79  return;
80  }
81 
82  m_display = mDisplay;
84 #ifdef Q_OS_MACOS
86 #endif
87 }
88 
89 void MythVideoBounds::ScreenChanged(QScreen */*screen*/)
90 {
92  MoveResize();
93 }
94 
96 {
97  // PopulateGeometry will update m_devicePixelRatio
100  MoveResize();
101 }
102 
104 {
105  if (!m_display)
106  return;
107 
108  QScreen *screen = m_display->GetCurrentScreen();
109  if (!screen)
110  return;
111 
112 #ifdef Q_OS_MACOS
113  m_devicePixelRatio = screen->devicePixelRatio();
114 #endif
115 
117  {
118  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Window using all screens %1x%2")
119  .arg(screen->virtualGeometry().width()).arg(screen->virtualGeometry().height()));
120  return;
121  }
122 
123  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Window using screen '%1' %2x%3")
124  .arg(screen->name()).arg(screen->geometry().width()).arg(screen->geometry().height()));
125 }
126 
138 {
139  // for 'portrait' mode, rotate the 'screen' dimensions
140  float tempdisplayaspect = m_displayAspect;
141  bool rotate = (m_rotation == 90) || (m_rotation == -90);
142  if (rotate)
143  Rotate();
144 
145  // Preset all image placement and sizing variables.
146  m_videoRect = QRect(QPoint(0, 0), m_videoDispDim);
148 
149  // Apply various modifications
153 
154  // Interactive TV (MHEG) embedding
155  if (m_itvResizing)
157 
158  // and switch back
159  if (rotate)
160  Rotate();
161  m_displayAspect = tempdisplayaspect;
162 
164 
165  // TODO fine tune when these are emitted - it is not enough to just check whether the values
166  // have changed
171 
173 }
174 
185 {
186  m_dbMove = QPoint(m_dbMove.y(), m_dbMove.x());
187  float temp = m_dbHorizScale;
189  m_dbVertScale = temp;
190  temp = m_manualHorizScale;
192  m_manualVertScale = temp;
193  m_manualMove = QPoint(m_manualMove.y(), m_manualMove.x());
195 
196  m_displayVisibleRect = QRect(QPoint(m_displayVisibleRect.top(), m_displayVisibleRect.left()),
197  QSize(m_displayVisibleRect.height(), m_displayVisibleRect.width()));
198  m_displayVideoRect = QRect(QPoint(m_displayVideoRect.top(), m_displayVideoRect.left()),
199  QSize(m_displayVideoRect.height(), m_displayVideoRect.width()));
208 }
209 
220 {
221  if (m_dbVertScale > 0)
222  {
223  // Veritcal overscan. Move the Y start point in original image.
224  float tmp = 1.0F - 2.0F * m_dbVertScale;
225  m_videoRect.moveTop(qRound(m_videoRect.height() * m_dbVertScale));
226  m_videoRect.setHeight(qRound(m_videoRect.height() * tmp));
227 
228  // If there is an offset, apply it now that we have a room.
229  int yoff = m_dbMove.y();
230  if (yoff > 0)
231  {
232  // To move the image down, move the start point up.
233  // Don't offset the image more than we have overscanned.
234  yoff = std::min(m_videoRect.top(), yoff);
235  m_videoRect.moveTop(m_videoRect.top() - yoff);
236  }
237  else if (yoff < 0)
238  {
239  // To move the image up, move the start point down.
240  // Don't offset the image more than we have overscanned.
241  if (abs(yoff) > m_videoRect.top())
242  yoff = 0 - m_videoRect.top();
243  m_videoRect.moveTop(m_videoRect.top() - yoff);
244  }
245  }
246  else if (m_dbVertScale < 0)
247  {
248  // Vertical underscan. Move the starting Y point in the display window.
249  // Use the abolute value of scan factor.
250  float vscanf = fabs(m_dbVertScale);
251  float tmp = 1.0F - 2.0F * vscanf;
252 
253  m_displayVideoRect.moveTop(qRound(m_displayVisibleRect.height() * vscanf) + m_displayVisibleRect.top());
254  m_displayVideoRect.setHeight(qRound(m_displayVisibleRect.height() * tmp));
255 
256  // Now offset the image within the extra blank space created by
257  // underscanning. To move the image down, increase the Y offset
258  // inside the display window.
259  int yoff = m_dbMove.y();
260  if (yoff > 0)
261  {
262  // Don't offset more than we have underscanned.
263  yoff = std::min(m_displayVideoRect.top(), yoff);
264  m_displayVideoRect.moveTop(m_displayVideoRect.top() + yoff);
265  }
266  else if (yoff < 0)
267  {
268  // Don't offset more than we have underscanned.
269  if (abs(yoff) > m_displayVideoRect.top())
270  yoff = 0 - m_displayVideoRect.top();
271  m_displayVideoRect.moveTop(m_displayVideoRect.top() + yoff);
272  }
273  }
274 
275  // Horizontal.. comments, same as vertical...
276  if (m_dbHorizScale > 0)
277  {
278  float tmp = 1.0F - 2.0F * m_dbHorizScale;
279  m_videoRect.moveLeft(qRound(m_videoDispDim.width() * m_dbHorizScale));
280  m_videoRect.setWidth(qRound(m_videoDispDim.width() * tmp));
281 
282  int xoff = m_dbMove.x();
283  if (xoff > 0)
284  {
285  xoff = std::min(m_videoRect.left(), xoff);
286  m_videoRect.moveLeft(m_videoRect.left() - xoff);
287  }
288  else if (xoff < 0)
289  {
290  if (abs(xoff) > m_videoRect.left())
291  xoff = 0 - m_videoRect.left();
292  m_videoRect.moveLeft(m_videoRect.left() - xoff);
293  }
294  }
295  else if (m_dbHorizScale < 0)
296  {
297  float hscanf = fabs(m_dbHorizScale);
298  float tmp = 1.0F - 2.0F * hscanf;
299 
300  m_displayVideoRect.moveLeft(qRound(m_displayVisibleRect.width() * hscanf) + m_displayVisibleRect.left());
301  m_displayVideoRect.setWidth(qRound(m_displayVisibleRect.width() * tmp));
302 
303  int xoff = m_dbMove.x();
304  if (xoff > 0)
305  {
306  xoff = std::min(m_displayVideoRect.left(), xoff);
307  m_displayVideoRect.moveLeft(m_displayVideoRect.left() + xoff);
308  }
309  else if (xoff < 0)
310  {
311  if (abs(xoff) > m_displayVideoRect.left())
312  xoff = 0 - m_displayVideoRect.left();
313  m_displayVideoRect.moveLeft(m_displayVideoRect.left() + xoff);
314  }
315  }
316 
317 }
318 
323 {
324  if ((m_manualVertScale != 1.0F) || (m_manualHorizScale != 1.0F))
325  {
326  QSize newsz = QSize(qRound(m_displayVideoRect.width() * m_manualHorizScale),
327  qRound(m_displayVideoRect.height() * m_manualVertScale));
328  QSize tmp = (m_displayVideoRect.size() - newsz) / 2;
329  QPoint chgloc = QPoint(tmp.width(), tmp.height());
330  QPoint newloc = m_displayVideoRect.topLeft() + chgloc;
331 
332  m_displayVideoRect = QRect(newloc, newsz);
333  }
334 
335  if (m_manualMove.y())
336  {
337  int move_vert = m_manualMove.y() * m_displayVideoRect.height() / 100;
338  m_displayVideoRect.moveTop(m_displayVideoRect.top() + move_vert);
339  }
340 
341  if (m_manualMove.x())
342  {
343  int move_horiz = m_manualMove.x() * m_displayVideoRect.width() / 100;
344  m_displayVideoRect.moveLeft(m_displayVideoRect.left() + move_horiz);
345  }
346 }
347 
348 // Code should take into account the aspect ratios of both the video as
349 // well as the actual screen to allow proper letterboxing to take place.
351 {
352  float disp_aspect = fix_aspect(GetDisplayAspect());
353  float aspect_diff = disp_aspect - m_videoAspectOverride;
354  bool aspects_match = abs(aspect_diff / disp_aspect) <= 0.02F;
355  bool nomatch_with_fill = !aspects_match && ((kAdjustFill_HorizontalStretch == m_adjustFill) ||
357  bool nomatch_without_fill = (!aspects_match) && !nomatch_with_fill;
358 
359  // Adjust for video/display aspect ratio mismatch
360  if (nomatch_with_fill && (disp_aspect > m_videoAspectOverride))
361  {
362  int pixNeeded = qRound(((disp_aspect / m_videoAspectOverride) * static_cast<float>(m_displayVideoRect.height())));
363  m_displayVideoRect.moveTop(m_displayVideoRect.top() + (m_displayVideoRect.height() - pixNeeded) / 2);
364  m_displayVideoRect.setHeight(pixNeeded);
365  }
366  else if (nomatch_with_fill)
367  {
368  int pixNeeded = qRound(((m_videoAspectOverride / disp_aspect) * static_cast<float>(m_displayVideoRect.width())));
369  m_displayVideoRect.moveLeft(m_displayVideoRect.left() + (m_displayVideoRect.width() - pixNeeded) / 2);
370  m_displayVideoRect.setWidth(pixNeeded);
371  }
372  else if (nomatch_without_fill && (disp_aspect > m_videoAspectOverride))
373  {
374  int pixNeeded = qRound(((m_videoAspectOverride / disp_aspect) * static_cast<float>(m_displayVideoRect.width())));
375  m_displayVideoRect.moveLeft(m_displayVideoRect.left() + (m_displayVideoRect.width() - pixNeeded) / 2);
376  m_displayVideoRect.setWidth(pixNeeded);
377  }
378  else if (nomatch_without_fill)
379  {
380  int pixNeeded = qRound(((disp_aspect / m_videoAspectOverride) * static_cast<float>(m_displayVideoRect.height())));
381  m_displayVideoRect.moveTop(m_displayVideoRect.top() + (m_displayVideoRect.height() - pixNeeded) / 2);
382  m_displayVideoRect.setHeight(pixNeeded);
383  }
384 
385  // Process letterbox zoom modes
387  {
388  // Zoom mode -- Expand by 4/3 and overscan.
389  // 1/6 of original is 1/8 of new
390  m_displayVideoRect = QRect(
391  m_displayVideoRect.left() - (m_displayVideoRect.width() / 6),
392  m_displayVideoRect.top() - (m_displayVideoRect.height() / 6),
393  m_displayVideoRect.width() * 4 / 3,
394  m_displayVideoRect.height() * 4 / 3);
395  }
396  else if (m_adjustFill == kAdjustFill_Half)
397  {
398  // Zoom mode -- Expand by 7/6 and overscan.
399  // Intended for eliminating the top bars on 14:9 material.
400  // Also good compromise for 4:3 material on 16:9 screen.
401  // Expanding by 7/6, so remove 1/6 of original from overscan;
402  // take half from each side, so remove 1/12.
403  m_displayVideoRect = QRect(
404  m_displayVideoRect.left() - (m_displayVideoRect.width() / 12),
405  m_displayVideoRect.top() - (m_displayVideoRect.height() / 12),
406  m_displayVideoRect.width() * 7 / 6,
407  m_displayVideoRect.height() * 7 / 6);
408  }
410  {
411  // Horizontal Stretch mode -- 1/6 of original is 1/8 of new
412  // Intended to be used to eliminate side bars on 4:3 material
413  // encoded to 16:9.
414  m_displayVideoRect.moveLeft(
415  m_displayVideoRect.left() - (m_displayVideoRect.width() / 6));
416 
417  m_displayVideoRect.setWidth(m_displayVideoRect.width() * 4 / 3);
418  }
420  {
421  // Vertical Stretch mode -- 1/6 of original is 1/8 of new
422  // Intended to be used to eliminate top/bottom bars on 16:9
423  // material encoded to 4:3.
424  m_displayVideoRect.moveTop(
425  m_displayVideoRect.top() - (m_displayVideoRect.height() / 6));
426 
427  m_displayVideoRect.setHeight(m_displayVideoRect.height() * 4 / 3);
428  }
429  else if (m_adjustFill == kAdjustFill_VerticalFill && m_displayVideoRect.height() > 0)
430  {
431  // Video fills screen vertically. May be cropped left and right
432  float factor = static_cast<float>(m_displayVisibleRect.height()) / static_cast<float>(m_displayVideoRect.height());
433  QSize newsize = QSize(qRound(m_displayVideoRect.width() * factor),
434  qRound(m_displayVideoRect.height() * factor));
435  QSize temp = (m_displayVideoRect.size() - newsize) / 2;
436  QPoint newloc = m_displayVideoRect.topLeft() + QPoint(temp.width(), temp.height());
437  m_displayVideoRect = QRect(newloc, newsize);
438  }
440  {
441  // Video fills screen horizontally. May be cropped top and bottom
442  float factor = static_cast<float>(m_displayVisibleRect.width()) /
443  static_cast<float>(m_displayVideoRect.width());
444  QSize newsize = QSize(qRound(m_displayVideoRect.width() * factor),
445  qRound(m_displayVideoRect.height() * factor));
446  QSize temp = (m_displayVideoRect.size() - newsize) / 2;
447  QPoint newloc = m_displayVideoRect.topLeft() + QPoint(temp.width(), temp.height());
448  m_displayVideoRect = QRect(newloc, newsize);
449  }
450 }
451 
452 bool MythVideoBounds::InitBounds(QSize VideoDim, QSize VideoDispDim,
453  float Aspect, QRect WindowRect)
454 {
455  if (m_display)
456  {
457  QString dummy;
458  m_displayAspect = static_cast<float>(m_display->GetAspectRatio(dummy));
459  }
460 
461  // Refresh the geometry in case the video mode has changed
463 
464  // N.B. we are always confined to the window size so use that for the initial
465  // displayVisibleRect
466  m_rawWindowRect = WindowRect;
468  m_videoDispDim = Fix1088(VideoDispDim);
469  m_videoDim = VideoDim;
470  m_videoRect = QRect(m_displayVisibleRect.topLeft(), m_videoDispDim);
471 
474  m_embedding = false;
475  SetVideoAspectRatio(Aspect);
476  MoveResize();
477  return true;
478 }
479 
481 {
482  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Window Rect: %1x%2+%3+%4")
483  .arg(m_windowRect.width()).arg(m_windowRect.height())
484  .arg(m_windowRect.left()).arg(m_windowRect.top()));
485  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Display Rect: %1x%2+%3+%4 Aspect: %5")
486  .arg(m_displayVideoRect.width()).arg(m_displayVideoRect.height())
487  .arg(m_displayVideoRect.left()).arg(m_displayVideoRect.top())
488  .arg(static_cast<qreal>(fix_aspect(GetDisplayAspect()))));
489  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Video Rect: %1x%2+%3+%4 Aspect: %5")
490  .arg(m_videoRect.width()).arg(m_videoRect.height())
491  .arg(m_videoRect.left()).arg(m_videoRect.top())
492  .arg(static_cast<qreal>(m_videoAspectOverride)));
493 }
494 
503 {
504  m_videoAspect = aspect;
506 }
507 
514 {
515  if (!qFuzzyCompare(Aspect, m_videoAspect))
516  {
517  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New video aspect ratio: '%1'")
518  .arg(static_cast<double>(Aspect)));
519  SetVideoAspectRatio(Aspect);
520  MoveResize();
521  }
522 }
523 
525 void MythVideoBounds::SourceChanged(QSize VideoDim, QSize VideoDispDim, float Aspect)
526 {
527  if (Aspect < 0.0F)
528  Aspect = m_videoAspect;
529 
530  QSize newvideodispdim = Fix1088(VideoDispDim);
531 
532  if (!((VideoDim == m_videoDim) && (newvideodispdim == m_videoDispDim) &&
533  qFuzzyCompare(Aspect + 100.0F, m_videoAspect + 100.0F)))
534  {
535  m_videoDispDim = newvideodispdim;
536  m_videoDim = VideoDim;
537  SetVideoAspectRatio(Aspect);
538  LOG(VB_PLAYBACK, LOG_INFO, LOC +
539  QString("New video parameters: Size %1x%2 DisplaySize: %3x%4 Aspect: %5")
540  .arg(m_videoDim.width()).arg(m_videoDim.height())
541  .arg(m_videoDispDim.width()).arg(m_videoDispDim.height())
542  .arg(static_cast<double>(m_videoAspect)));
543  MoveResize();
544  }
545 }
546 
547 QSize MythVideoBounds::Fix1088(QSize Dimensions)
548 {
549  QSize result = Dimensions;
550  // 544 represents a 1088 field
551  if (result.width() == 1920 || result.width() == 1440)
552  {
553  if (result.height() == 1088)
554  result.setHeight(1080);
555  else if (result.height() == 544)
556  result.setHeight(540);
557  }
558  return result;
559 }
560 
567 {
569  AdjustFill = static_cast<AdjustFillMode>((m_adjustFill + 1) % kAdjustFill_END);
570  if (m_adjustFill != AdjustFill)
571  {
573  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New fill mode: '%1'").arg(toString(m_adjustFill)));
574  MoveResize();
575  }
576 }
577 
582 {
583  float oldvert = m_dbVertScale;
584  float oldhoriz = m_dbHorizScale;
585 
586  if (Change)
587  {
588  m_dbVertScale = gCoreContext->GetNumSetting("VertScanPercentage", 0) * 0.01F;
589  m_dbHorizScale = gCoreContext->GetNumSetting("HorizScanPercentage", 0) * 0.01F;
590  m_dbScalingAllowed = true;
591  }
592  else
593  {
594  m_dbVertScale = 0.0F;
595  m_dbHorizScale = 0.0F;
596  m_dbScalingAllowed = false;
597  }
598 
599  if (!(qFuzzyCompare(oldvert + 100.0F, m_dbVertScale + 100.0F) &&
600  qFuzzyCompare(oldhoriz + 100.0F, m_dbHorizScale + 100.0F)))
601  {
602  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Over/underscan. V: %1, H: %2")
603  .arg(static_cast<double>(m_dbVertScale)).arg(static_cast<double>(m_dbHorizScale)));
604  MoveResize();
605  }
606 }
607 
608 void MythVideoBounds::SetDisplayAspect(float DisplayAspect)
609 {
610  if (!qFuzzyCompare(DisplayAspect + 10.0F, m_displayAspect + 10.0F))
611  {
612  LOG(VB_GENERAL, LOG_INFO, LOC + QString("New display aspect: %1")
613  .arg(static_cast<double>(DisplayAspect)));
614  m_displayAspect = DisplayAspect;
615  MoveResize();
616  }
617 }
618 
620 {
621  if (Size != m_rawWindowRect.size())
622  {
623  QRect rect(m_rawWindowRect.topLeft(), Size);
624  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New window rect: %1x%2+%3+%4")
625  .arg(rect.width()).arg(rect.height()).arg(rect.left()).arg(rect.top()));
626  m_rawWindowRect = rect;
628  MoveResize();
629  }
630 }
631 
633 {
634  QRect oldrect = m_rawItvDisplayVideoRect;
635  if (Rect.isEmpty())
636  {
637  m_itvResizing = false;
638  m_itvDisplayVideoRect = QRect();
639  m_rawItvDisplayVideoRect = QRect();
640  }
641  else
642  {
643  m_itvResizing = true;
646  }
647  if (m_rawItvDisplayVideoRect != oldrect)
648  {
649  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New ITV display rect: %1x%2+%3+%4 (Scale: %5)")
650  .arg(m_itvDisplayVideoRect.width()).arg(m_itvDisplayVideoRect.height())
651  .arg(m_itvDisplayVideoRect.left()).arg(m_itvDisplayVideoRect.right())
652  .arg(m_devicePixelRatio));
653  MoveResize();
654  }
655 }
656 
662 {
663  if (Rotation == m_rotation)
664  return;
665  if ((Rotation < -180) || (Rotation > 180))
666  return;
667 
668  m_rotation = Rotation;
669  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New rotation: %1").arg(m_rotation));
670  MoveResize();
671 }
672 
676 void MythVideoBounds::ResizeDisplayWindow(QRect Rect, bool SaveVisibleRect)
677 {
678  if (SaveVisibleRect)
680  m_displayVisibleRect = Rect;
681  MoveResize();
682 }
683 
684 void MythVideoBounds::EmbedPlayback(bool Embed, QRect Rect)
685 {
686  if (Embed)
687  {
688  if (m_embedding && (Rect == m_rawEmbeddingRect))
689  return;
690 
691  m_rawEmbeddingRect = Rect;
693  bool savevisiblerect = !m_embedding;
694  m_embedding = true;
695  m_embeddingHidden = Rect.isEmpty();
697  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New embedding rect: %1x%2+%3+%4 (Scale: %5)")
698  .arg(m_embeddingRect.width()).arg(m_embeddingRect.height())
699  .arg(m_embeddingRect.left()).arg(m_embeddingRect.top())
700  .arg(m_devicePixelRatio));
701  ResizeDisplayWindow(m_displayVideoRect, savevisiblerect);
702  return;
703  }
704 
705  if (!m_embedding)
706  return;
707  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Stopped embedding");
708  m_rawEmbeddingRect = QRect();
709  m_embeddingRect = QRect();
711  m_embedding = false;
712  m_embeddingHidden = false;
713  MoveResize();
714 }
715 
723 {
724  if (AspectMode == kAspect_Toggle)
725  AspectMode = static_cast<AspectOverrideMode>(((m_videoAspectOverrideMode + 1) % kAspect_END));
726 
727  if (m_videoAspectOverrideMode != AspectMode)
728  {
729  m_videoAspectOverrideMode = AspectMode;
730  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New video aspect override: '%1'")
733  MoveResize();
734  }
735 
737 }
738 
744 {
745  if (IsEmbedding())
746  return false;
747 
748  return m_displayVideoRect.contains(m_windowRect);
749 }
750 
756 {
757  QRegion visible(m_windowRect);
758  QRegion video(m_displayVideoRect);
759  return visible.subtracted(video);
760 }
761 
767 {
768  float oldvertscale = m_manualVertScale;
769  float oldhorizscale = m_manualHorizScale;
770  QPoint oldmove = m_manualMove;
771 
772  const float zf = 0.02F;
773  if (kZoomHome == Direction)
774  {
775  m_manualVertScale = 1.0F;
776  m_manualHorizScale = 1.0F;
777  m_manualMove = QPoint(0, 0);
778  }
779  else if (kZoomIn == Direction)
780  {
783  {
784  m_manualHorizScale += zf;
785  m_manualVertScale += zf;
786  }
787  }
788  else if (kZoomOut == Direction)
789  {
792  {
793  m_manualHorizScale -= zf;
794  m_manualVertScale -= zf;
795  }
796  }
797  else if (kZoomAspectUp == Direction)
798  {
801  {
802  m_manualHorizScale += zf;
803  m_manualVertScale -= zf;
804  }
805  }
806  else if (kZoomAspectDown == Direction)
807  {
810  {
811  m_manualHorizScale -= zf;
812  m_manualVertScale += zf;
813  }
814  }
815  else if (kZoomVerticalIn == Direction)
816  {
818  m_manualVertScale += zf;
819  }
820  else if (kZoomVerticalOut == Direction)
821  {
823  m_manualVertScale -= zf;
824  }
825  else if (kZoomHorizontalIn == Direction)
826  {
828  m_manualHorizScale += zf;
829  }
830  else if (kZoomHorizontalOut == Direction)
831  {
833  m_manualHorizScale -= zf;
834  }
835  else if (kZoomUp == Direction && (m_manualMove.y() < +kManualZoomMaxMove))
836  m_manualMove.setY(m_manualMove.y() + 1);
837  else if (kZoomDown == Direction && (m_manualMove.y() > -kManualZoomMaxMove))
838  m_manualMove.setY(m_manualMove.y() - 1);
839  else if (kZoomLeft == Direction && (m_manualMove.x() < +kManualZoomMaxMove))
840  m_manualMove.setX(m_manualMove.x() + 2);
841  else if (kZoomRight == Direction && (m_manualMove.x() > -kManualZoomMaxMove))
842  m_manualMove.setX(m_manualMove.x() - 2);
843 
844  m_manualVertScale = snap(m_manualVertScale, 1.0F, zf / 2);
845  m_manualHorizScale = snap(m_manualHorizScale, 1.0F, zf / 2);
846 
847  if (!((oldmove == m_manualMove) && qFuzzyCompare(m_manualVertScale + 100.0F, oldvertscale + 100.0F) &&
848  qFuzzyCompare(m_manualHorizScale + 100.0F, oldhorizscale + 100.0F)))
849  {
850  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New zoom: Offset %1x%2 HScale %3 VScale %4")
851  .arg(m_manualMove.x()).arg(m_manualMove.y())
852  .arg(static_cast<double>(m_manualHorizScale))
853  .arg(static_cast<double>(m_manualVertScale)));
854  MoveResize();
855  }
856 }
857 
859 {
860  float oldvertscale = m_manualVertScale;
861  float oldhorizscale = m_manualHorizScale;
862  QPoint oldmove = m_manualMove;
863 
864  if (m_bottomLine)
865  {
866  m_manualMove.setX(0);
867  m_manualMove.setY(0);
868  m_manualHorizScale = 1.0;
869  m_manualVertScale = 1.0;
870  m_bottomLine = false;
871  }
872  else
873  {
874  const float zf = 0.02F;
875  m_manualMove.setX(gCoreContext->GetNumSetting("OSDMoveXBottomLine", 0));
876  m_manualMove.setY(gCoreContext->GetNumSetting("OSDMoveYBottomLine", 5));
877  float h = static_cast<float>(gCoreContext->GetNumSetting("OSDScaleHBottomLine", 100)) / 100.0F;
878  m_manualHorizScale = snap(h, 1.0F, zf / 2.0F);
879  float v = static_cast<float>(gCoreContext->GetNumSetting("OSDScaleVBottomLine", 112)) / 100.0F;
880  m_manualVertScale = snap(v, 1.0F, zf / 2.0F);
881  m_bottomLine = true;
882  }
883 
884  if (!((oldmove == m_manualMove) && qFuzzyCompare(m_manualVertScale + 100.0F, oldvertscale + 100.0F) &&
885  qFuzzyCompare(m_manualHorizScale + 100.0F, oldhorizscale + 100.0F)))
886  {
887  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("New custom zoom: Offset %1x%2 HScale %3 VScale %4")
888  .arg(m_manualMove.x()).arg(m_manualMove.y())
889  .arg(static_cast<double>(m_manualHorizScale))
890  .arg(static_cast<double>(m_manualVertScale)));
891  MoveResize();
892  }
893 
895 }
896 
898 {
899  gCoreContext->SaveSetting("OSDMoveXBottomLine", m_manualMove.x());
900  gCoreContext->SaveSetting("OSDMoveYBottomLine", m_manualMove.y());
901  gCoreContext->SaveSetting("OSDScaleHBottomLine", static_cast<int>(m_manualHorizScale * 100.0F));
902  gCoreContext->SaveSetting("OSDScaleVBottomLine", static_cast<int>(m_manualVertScale * 100.0F));
903 
904  emit UpdateOSDMessage("Current 'Manual Zoom' saved for 'BottomLine'.");
905 }
906 
908 static float fix_aspect(float raw)
909 {
910  // Check if close to 4:3
911  if (fabs(raw - 1.333333F) < 0.05F)
912  raw = 1.333333F;
913 
914  // Check if close to 16:9
915  if (fabs(raw - 1.777777F) < 0.05F)
916  raw = 1.777777F;
917 
918  return raw;
919 }
920 
921 static float snap(float value, float snapto, float diff)
922 {
923  if ((value + diff > snapto) && (value - diff < snapto))
924  return snapto;
925  return value;
926 }
927 
929 {
930  if (Mode != m_stereoOverride)
931  {
935  }
936 }
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
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
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:513
MythVideoBounds::PhysicalDPIChanged
void PhysicalDPIChanged(qreal)
Definition: mythvideobounds.cpp:95
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:684
GetZoomString
QString GetZoomString(float HorizScale, float VertScale, QPoint Move)
Definition: videoouttypes.h:359
MythVideoBounds::MythVideoBounds
MythVideoBounds()
Definition: mythvideobounds.cpp:54
kZoomAspectUp
@ kZoomAspectUp
Definition: videoouttypes.h:55
AdjustFill
static HostComboBoxSetting * AdjustFill()
Definition: globalsettings.cpp:2235
Mode
Mode
Definition: synaesthesia.h:23
MythVideoBounds::ApplyDBScaleAndMove
void ApplyDBScaleAndMove(void)
Apply scales and moves for "Overscan" and "Underscan" DB settings.
Definition: mythvideobounds.cpp:219
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:68
MythVideoBounds::m_videoAspect
float m_videoAspect
Physical aspect ratio of video.
Definition: mythvideobounds.h:122
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:871
MythDisplay::SpanAllScreens
static bool SpanAllScreens()
Return true if the MythTV windows should span all screens.
Definition: mythdisplay.cpp:495
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
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:328
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:480
MythDisplay::PhysicalDPIChanged
void PhysicalDPIChanged(qreal DPI)
Definition: mythdisplay.cpp:437
MythVideoBounds::UpdateOSDMessage
void UpdateOSDMessage(const QString &Message)
get_aspect_override
float get_aspect_override(AspectOverrideMode Aspectmode, float Original)
Definition: videoouttypes.h:250
MythDisplay::CurrentScreenChanged
void CurrentScreenChanged(QScreen *qScreen)
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
MythVideoBounds::SaveBottomLine
void SaveBottomLine(void)
Definition: mythvideobounds.cpp:897
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:608
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:74
kAdjustFill_END
@ kAdjustFill_END
Definition: videoouttypes.h:81
MythVideoBounds::ResizeDisplayWindow
void ResizeDisplayWindow(QRect Rect, bool SaveVisibleRect)
Resize Display Window.
Definition: mythvideobounds.cpp:676
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:525
fix_aspect
static float fix_aspect(float raw)
Correct for rounding errors.
Definition: mythvideobounds.cpp:908
MythVideoBounds::SetStereoOverride
void SetStereoOverride(StereoscopicMode Mode)
Definition: mythvideobounds.cpp:928
MythVideoBounds::Fix1088
static QSize Fix1088(QSize Dimensions)
Definition: mythvideobounds.cpp:547
MythDisplay::GetScreenCount
static int GetScreenCount()
Definition: mythdisplay.cpp:288
AspectOverrideMode
AspectOverrideMode
Definition: videoouttypes.h:60
MythVideoBounds::ToggleAspectOverride
void ToggleAspectOverride(AspectOverrideMode AspectMode=kAspect_Toggle)
Enforce different aspect ratio than detected, then calls VideoAspectRatioChanged(float) to apply them...
Definition: mythvideobounds.cpp:722
MythVideoBounds::PopulateGeometry
void PopulateGeometry(void)
Definition: mythvideobounds.cpp:103
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
SCALED_RECT
static QRect SCALED_RECT(QRect src, qreal scale)
Definition: mythvideobounds.cpp:39
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:350
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:566
MythVideoBounds::SetRotation
void SetRotation(int Rotation)
Set the rotation in degrees.
Definition: mythvideobounds.cpp:661
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
MythVideoBounds::VideoSizeChanged
void VideoSizeChanged(const QSize &VideoDim, const QSize &VideoDispDim)
MythDisplay
Definition: mythdisplay.h:22
MythVideoBounds::kManualZoomMinVerticalZoom
static const float kManualZoomMinVerticalZoom
Definition: mythvideobounds.h:166
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:912
kAdjustFill_VerticalFill
@ kAdjustFill_VerticalFill
Definition: videoouttypes.h:80
MythVideoBounds::ToggleMoveBottomLine
void ToggleMoveBottomLine(void)
Definition: mythvideobounds.cpp:858
kAdjustFill_HorizontalFill
@ kAdjustFill_HorizontalFill
Definition: videoouttypes.h:79
StereoscopicMode
StereoscopicMode
Definition: videoouttypes.h:134
LOC
#define LOC
Definition: mythvideobounds.cpp:37
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:906
MythVideoBounds::SetITVResize
void SetITVResize(QRect Rect)
Definition: mythvideobounds.cpp:632
MythVideoBounds::MoveResize
void MoveResize(void)
performs all the calculations for video framing and any resizing.
Definition: mythvideobounds.cpp:137
mythmiscutil.h
MythVideoBounds::GetBoundingRegion
QRegion GetBoundingRegion(void) const
Return the region of DisplayVisibleRect that lies outside of DisplayVideoRect.
Definition: mythvideobounds.cpp:755
mythcorecontext.h
MythVideoBounds::Zoom
void Zoom(ZoomDirection Direction)
Sets up zooming into to different parts of the video.
Definition: mythvideobounds.cpp:766
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:71
MythVideoBounds::SetVideoAspectRatio
void SetVideoAspectRatio(float Aspect)
Sets MythVideoBounds::video_aspect to aspect, and sets MythVideoBounds::overriden_video_aspect if asp...
Definition: mythvideobounds.cpp:502
MythVideoBounds::ScreenChanged
void ScreenChanged(QScreen *screen)
Definition: mythvideobounds.cpp:89
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:452
MythVideoBounds::SetVideoScalingAllowed
void SetVideoScalingAllowed(bool Change)
Disable or enable underscan/overscan.
Definition: mythvideobounds.cpp:581
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:184
MythVideoBounds::ApplyManualScaleAndMove
void ApplyManualScaleAndMove(void)
Apply scales and moves from "Zoom Mode" settings.
Definition: mythvideobounds.cpp:322
snap
static float snap(float value, float snapto, float diff)
Definition: mythvideobounds.cpp:921
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:881
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:743
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:42
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:619
MythVideoBounds::m_display
MythDisplay * m_display
Definition: mythvideobounds.h:99