00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <cmath>
00024
00025 #include <QDesktopWidget>
00026 #include <QApplication>
00027
00028 #include "mythconfig.h"
00029
00030 #include "videooutwindow.h"
00031 #include "osd.h"
00032 #include "mythplayer.h"
00033 #include "videodisplayprofile.h"
00034 #include "decoderbase.h"
00035 #include "mythcorecontext.h"
00036 #include "dithertable.h"
00037
00038 extern "C" {
00039 #include "libavcodec/avcodec.h"
00040 }
00041
00042 #include "filtermanager.h"
00043
00044 static QSize fix_1080i(QSize raw);
00045 static QSize fix_alignment(QSize raw);
00046 static float fix_aspect(float raw);
00047 static float snap(float value, float snapto, float diff);
00048
00049 const float VideoOutWindow::kManualZoomMaxHorizontalZoom = 2.0f;
00050 const float VideoOutWindow::kManualZoomMaxVerticalZoom = 2.0f;
00051 const float VideoOutWindow::kManualZoomMinHorizontalZoom = 0.5f;
00052 const float VideoOutWindow::kManualZoomMinVerticalZoom = 0.5f;
00053 const int VideoOutWindow::kManualZoomMaxMove = 50;
00054
00055 VideoOutWindow::VideoOutWindow() :
00056
00057 db_move(0, 0), db_scale_horiz(0.0f), db_scale_vert(0.0f),
00058 db_pip_size(26),
00059 db_scaling_allowed(true),
00060
00061 using_xinerama(false), screen_num(0), screen_geom(0, 0, 1024, 768),
00062
00063
00064 mz_scale_v(1.0f), mz_scale_h(1.0f), mz_move(0, 0),
00065
00066
00067 display_dim(400, 300), display_aspect(1.3333f),
00068
00069
00070 video_dim(640, 480), video_disp_dim(640, 480),
00071 video_dim_act(640, 480), video_aspect(1.3333f),
00072
00073
00074 overriden_video_aspect(1.3333f), aspectoverride(kAspect_Off),
00075
00076
00077 adjustfill(kAdjustFill_Off),
00078
00079
00080 video_rect(0, 0, 0, 0),
00081 display_video_rect(0, 0, 0, 0),
00082 display_visible_rect(0, 0, 0, 0),
00083 tmp_display_visible_rect(0, 0, 0, 0),
00084 embedding_rect(QRect()),
00085
00086
00087 embedding(false), needrepaint(false),
00088 allowpreviewepg(true), pip_state(kPIPOff)
00089 {
00090 db_pip_size = gCoreContext->GetNumSetting("PIPSize", 26);
00091
00092 db_move = QPoint(gCoreContext->GetNumSetting("xScanDisplacement", 0),
00093 gCoreContext->GetNumSetting("yScanDisplacement", 0));
00094 db_use_gui_size = gCoreContext->GetNumSetting("GuiSizeForTV", 0);
00095
00096 QDesktopWidget *desktop = NULL;
00097 if (QApplication::type() == QApplication::GuiClient)
00098 desktop = QApplication::desktop();
00099
00100 if (desktop)
00101 {
00102 screen_num = desktop->primaryScreen();
00103 using_xinerama = MythDisplay::GetNumberXineramaScreens() > 1;
00104 if (using_xinerama)
00105 {
00106 screen_num = gCoreContext->GetNumSetting("XineramaScreen", screen_num);
00107 if (screen_num >= desktop->numScreens())
00108 screen_num = 0;
00109 }
00110
00111 screen_geom = desktop->geometry();
00112 if (screen_num >= 0)
00113 screen_geom = desktop->screenGeometry(screen_num);
00114 }
00115 }
00116
00127 void VideoOutWindow::MoveResize(void)
00128 {
00129
00130 video_rect = QRect(QPoint(0, 0), video_disp_dim);
00131 display_video_rect = display_visible_rect;
00132
00133
00134 if ((video_rect.width() <= 0) || (video_rect.height() <= 0))
00135 {
00136 video_disp_dim = video_dim_act = display_visible_rect.size();
00137 video_dim = fix_alignment(display_visible_rect.size());
00138 video_rect = QRect(QPoint(0, 0), video_dim);
00139 }
00140
00141
00142 ApplyDBScaleAndMove();
00143 ApplyLetterboxing();
00144 ApplyManualScaleAndMove();
00145 if ((db_scale_vert == 0) && (db_scale_horiz == 0) &&
00146 (mz_scale_v == 1.0f) && (mz_scale_h == 1.0f))
00147 {
00148 ApplySnapToVideoRect();
00149 }
00150 PrintMoveResizeDebug();
00151 needrepaint = true;
00152 }
00153
00164 void VideoOutWindow::ApplyDBScaleAndMove(void)
00165 {
00166 if (db_scale_vert > 0)
00167 {
00168
00169 float tmp = 1.0f - 2.0f * db_scale_vert;
00170 video_rect.moveTop((int) round(video_rect.height() * db_scale_vert));
00171 video_rect.setHeight((int) round(video_rect.height() * tmp));
00172
00173
00174 int yoff = db_move.y();
00175 if (yoff > 0)
00176 {
00177
00178
00179 yoff = min(video_rect.top(), yoff);
00180 video_rect.moveTop(video_rect.top() - yoff);
00181 }
00182 else if (yoff < 0)
00183 {
00184
00185
00186 if (abs(yoff) > video_rect.top())
00187 yoff = 0 - video_rect.top();
00188 video_rect.moveTop(video_rect.top() - yoff);
00189 }
00190 }
00191 else if (db_scale_vert < 0)
00192 {
00193
00194
00195 float vscanf = fabs(db_scale_vert);
00196 float tmp = 1.0f - 2.0f * vscanf;
00197
00198 display_video_rect.moveTop(
00199 (int) round(display_visible_rect.height() * vscanf) +
00200 display_visible_rect.top());
00201
00202 display_video_rect.setHeight(
00203 (int) round(display_visible_rect.height() * tmp));
00204
00205
00206
00207
00208 int yoff = db_move.y();
00209 if (yoff > 0)
00210 {
00211
00212 yoff = min(display_video_rect.top(), yoff);
00213 display_video_rect.moveTop(display_video_rect.top() + yoff);
00214 }
00215 else if (yoff < 0)
00216 {
00217
00218 if (abs(yoff) > display_video_rect.top())
00219 yoff = 0 - display_video_rect.top();
00220 display_video_rect.moveTop(display_video_rect.top() + yoff);
00221 }
00222 }
00223
00224
00225 if (db_scale_horiz > 0)
00226 {
00227 float tmp = 1.0f - 2.0f * db_scale_horiz;
00228 video_rect.moveLeft(
00229 (int) round(video_disp_dim.width() * db_scale_horiz));
00230 video_rect.setWidth((int) round(video_disp_dim.width() * tmp));
00231
00232 int xoff = db_move.x();
00233 if (xoff > 0)
00234 {
00235 xoff = min(video_rect.left(), xoff);
00236 video_rect.moveLeft(video_rect.left() - xoff);
00237 }
00238 else if (xoff < 0)
00239 {
00240 if (abs(xoff) > video_rect.left())
00241 xoff = 0 - video_rect.left();
00242 video_rect.moveLeft(video_rect.left() - xoff);
00243 }
00244 }
00245 else if (db_scale_horiz < 0)
00246 {
00247 float hscanf = fabs(db_scale_horiz);
00248 float tmp = 1.0f - 2.0f * hscanf;
00249
00250 display_video_rect.moveLeft(
00251 (int) round(display_visible_rect.width() * hscanf) +
00252 display_visible_rect.left());
00253
00254 display_video_rect.setWidth(
00255 (int) round(display_visible_rect.width() * tmp));
00256
00257 int xoff = db_move.x();
00258 if (xoff > 0)
00259 {
00260 xoff = min(display_video_rect.left(), xoff);
00261 display_video_rect.moveLeft(display_video_rect.left() + xoff);
00262 }
00263 else if (xoff < 0)
00264 {
00265 if (abs(xoff) > display_video_rect.left())
00266 xoff = 0 - display_video_rect.left();
00267 display_video_rect.moveLeft(display_video_rect.left() + xoff);
00268 }
00269 }
00270
00271 }
00272
00276 void VideoOutWindow::ApplyManualScaleAndMove(void)
00277 {
00278 if ((mz_scale_v != 1.0f) || (mz_scale_h != 1.0f))
00279 {
00280 QSize newsz = QSize((int) (display_video_rect.width() * mz_scale_h),
00281 (int) (display_video_rect.height() * mz_scale_v));
00282 QSize tmp = (display_video_rect.size() - newsz) / 2;
00283 QPoint chgloc = QPoint(tmp.width(), tmp.height());
00284 QPoint newloc = display_video_rect.topLeft() + chgloc;
00285
00286 display_video_rect = QRect(newloc, newsz);
00287 }
00288
00289 if (mz_move.y())
00290 {
00291 int move_vert = mz_move.y() * display_video_rect.height() / 100;
00292 display_video_rect.moveTop(display_video_rect.top() + move_vert);
00293 }
00294
00295 if (mz_move.x())
00296 {
00297 int move_horiz = mz_move.x() * display_video_rect.width() / 100;
00298 display_video_rect.moveLeft(display_video_rect.left() + move_horiz);
00299 }
00300 }
00301
00302
00303
00304 void VideoOutWindow::ApplyLetterboxing(void)
00305 {
00306 float disp_aspect = fix_aspect(GetDisplayAspect());
00307 float aspect_diff = disp_aspect - overriden_video_aspect;
00308 bool aspects_match = abs(aspect_diff / disp_aspect) <= 0.02f;
00309 bool nomatch_with_fill =
00310 !aspects_match && ((kAdjustFill_HorizontalStretch == adjustfill) ||
00311 (kAdjustFill_VerticalStretch == adjustfill));
00312 bool nomatch_without_fill = (!aspects_match) && !nomatch_with_fill;
00313
00314
00315 if (nomatch_with_fill && (disp_aspect > overriden_video_aspect))
00316 {
00317 float pixNeeded = ((disp_aspect / overriden_video_aspect)
00318 * (float) display_video_rect.height()) + 0.5f;
00319
00320 display_video_rect.moveTop(
00321 display_video_rect.top() +
00322 (display_video_rect.height() - (int) pixNeeded) / 2);
00323
00324 display_video_rect.setHeight((int) pixNeeded);
00325 }
00326 else if (nomatch_with_fill)
00327 {
00328 float pixNeeded =
00329 ((overriden_video_aspect / disp_aspect) *
00330 (float) display_video_rect.width()) + 0.5f;
00331
00332 display_video_rect.moveLeft(
00333 display_video_rect.left() +
00334 (display_video_rect.width() - (int) pixNeeded) / 2);
00335
00336 display_video_rect.setWidth((int) pixNeeded);
00337 }
00338 else if (nomatch_without_fill && (disp_aspect > overriden_video_aspect))
00339 {
00340 float pixNeeded =
00341 ((overriden_video_aspect / disp_aspect) *
00342 (float) display_video_rect.width()) + 0.5f;
00343
00344 display_video_rect.moveLeft(
00345 display_video_rect.left() +
00346 (display_video_rect.width() - (int) pixNeeded) / 2);
00347
00348 display_video_rect.setWidth((int) pixNeeded);
00349 }
00350 else if (nomatch_without_fill)
00351 {
00352 float pixNeeded = ((disp_aspect / overriden_video_aspect) *
00353 (float) display_video_rect.height()) + 0.5f;
00354
00355 display_video_rect.moveTop(
00356 display_video_rect.top() +
00357 (display_video_rect.height() - (int) pixNeeded) / 2);
00358
00359 display_video_rect.setHeight((int) pixNeeded);
00360 }
00361
00362
00363 if (adjustfill == kAdjustFill_Full)
00364 {
00365
00366
00367 display_video_rect = QRect(
00368 display_video_rect.left() - (display_video_rect.width() / 6),
00369 display_video_rect.top() - (display_video_rect.height() / 6),
00370 display_video_rect.width() * 4 / 3,
00371 display_video_rect.height() * 4 / 3);
00372 }
00373 else if (adjustfill == kAdjustFill_Half)
00374 {
00375
00376
00377
00378
00379
00380 display_video_rect = QRect(
00381 display_video_rect.left() - (display_video_rect.width() / 12),
00382 display_video_rect.top() - (display_video_rect.height() / 12),
00383 display_video_rect.width() * 7 / 6,
00384 display_video_rect.height() * 7 / 6);
00385 }
00386 else if (adjustfill == kAdjustFill_HorizontalStretch)
00387 {
00388
00389
00390
00391 display_video_rect.moveLeft(
00392 display_video_rect.left() - (display_video_rect.width() / 6));
00393
00394 display_video_rect.setWidth(display_video_rect.width() * 4 / 3);
00395 }
00396 else if (adjustfill == kAdjustFill_VerticalStretch)
00397 {
00398
00399
00400
00401 display_video_rect.moveTop(
00402 display_video_rect.top() - (display_video_rect.height() / 6));
00403
00404 display_video_rect.setHeight(display_video_rect.height() * 4 / 3);
00405 }
00406 else if (adjustfill == kAdjustFill_VerticalFill &&
00407 display_video_rect.height() > 0)
00408 {
00409
00410 float factor = (float)display_visible_rect.height() /
00411 (float)display_video_rect.height();
00412 QSize newsize = QSize((int) (display_video_rect.width() * factor),
00413 (int) (display_video_rect.height() * factor));
00414 QSize temp = (display_video_rect.size() - newsize) / 2;
00415 QPoint newloc = display_video_rect.topLeft() +
00416 QPoint(temp.width(), temp.height());
00417 display_video_rect = QRect(newloc, newsize);
00418 }
00419 else if (adjustfill == kAdjustFill_HorizontalFill &&
00420 display_video_rect.width() > 0)
00421 {
00422
00423 float factor = (float)display_visible_rect.width() /
00424 (float)display_video_rect.width();
00425 QSize newsize = QSize((int) (display_video_rect.width() * factor),
00426 (int) (display_video_rect.height() * factor));
00427 QSize temp = (display_video_rect.size() - newsize) / 2;
00428 QPoint newloc = display_video_rect.topLeft() +
00429 QPoint(temp.width(), temp.height());
00430 display_video_rect = QRect(newloc, newsize);
00431 }
00432 }
00433
00442 void VideoOutWindow::ApplySnapToVideoRect(void)
00443 {
00444 if (pip_state > kPIPOff)
00445 return;
00446
00447 if (display_video_rect.height() == 0 || display_video_rect.width() == 0)
00448 return;
00449
00450 float ydiff = abs(display_video_rect.height() - video_rect.height());
00451 if ((ydiff / display_video_rect.height()) < 0.05)
00452 {
00453 display_video_rect.moveTop(
00454 display_video_rect.top() +
00455 (display_video_rect.height() - video_rect.height()) / 2);
00456
00457 display_video_rect.setHeight(video_rect.height());
00458
00459 LOG(VB_PLAYBACK, LOG_INFO,
00460 QString("Snapping height to avoid scaling: height: %1, top: %2")
00461 .arg(display_video_rect.height())
00462 .arg(display_video_rect.top()));
00463 }
00464
00465 float xdiff = abs(display_video_rect.width() - video_rect.width());
00466 if ((xdiff / display_video_rect.width()) < 0.05)
00467 {
00468 display_video_rect.moveLeft(
00469 display_video_rect.left() +
00470 (display_video_rect.width() - video_rect.width()) / 2);
00471
00472 display_video_rect.setWidth(video_rect.width());
00473
00474 LOG(VB_PLAYBACK, LOG_INFO,
00475 QString("Snapping width to avoid scaling: width: %1, left: %2")
00476 .arg(display_video_rect.width())
00477 .arg(display_video_rect.left()));
00478 }
00479 }
00480
00481 bool VideoOutWindow::Init(const QSize &new_video_dim, float new_video_aspect,
00482 const QRect &new_display_visible_rect,
00483 AspectOverrideMode new_aspectoverride,
00484 AdjustFillMode new_adjustfill)
00485 {
00486 display_visible_rect = db_use_gui_size ? new_display_visible_rect :
00487 screen_geom;
00488
00489 int pbp_width = display_visible_rect.width() / 2;
00490 if (pip_state == kPBPLeft || pip_state == kPBPRight)
00491 display_visible_rect.setWidth(pbp_width);
00492
00493 if (pip_state == kPBPRight)
00494 display_visible_rect.moveLeft(pbp_width);
00495
00496 video_dim_act = new_video_dim;
00497 video_disp_dim = fix_1080i(new_video_dim);
00498 video_dim = fix_alignment(new_video_dim);
00499 video_rect = QRect(display_visible_rect.topLeft(), video_disp_dim);
00500
00501 if (pip_state > kPIPOff)
00502 {
00503 aspectoverride = kAspect_Off;
00504 adjustfill = kAdjustFill_Off;
00505 }
00506 else
00507 {
00508 aspectoverride = new_aspectoverride;
00509 adjustfill = new_adjustfill;
00510 }
00511
00512
00513 VideoAspectRatioChanged(new_video_aspect);
00514
00515 embedding = false;
00516
00517 return true;
00518 }
00519
00520 void VideoOutWindow::PrintMoveResizeDebug(void)
00521 {
00522 #if 0
00523 LOG(VB_PLAYBACK, LOG_DEBUG, "VideoOutWindow::MoveResize:");
00524 LOG(VB_PLAYBACK, LOG_DEBUG, QString("Img(%1,%2 %3,%4)")
00525 .arg(video_rect.left()).arg(video_rect.top())
00526 .arg(video_rect.width()).arg(video_rect.height()));
00527 LOG(VB_PLAYBACK, LOG_DEBUG, QString("Disp(%1,%1 %2,%4)")
00528 .arg(display_video_rect.left()).arg(display_video_rect.top())
00529 .arg(display_video_rect.width()).arg(display_video_rect.height()));
00530 LOG(VB_PLAYBACK, LOG_DEBUG, QString("Offset(%1,%2)")
00531 .arg(xoff).arg(yoff));
00532 LOG(VB_PLAYBACK, LOG_DEBUG, QString("Vscan(%1, %2)")
00533 .arg(db_scale_vert).arg(db_scale_vert));
00534 LOG(VB_PLAYBACK, LOG_DEBUG, QString("DisplayAspect: %1")
00535 .arg(GetDisplayAspect()));
00536 LOG(VB_PLAYBACK, LOG_DEBUG, QString("VideoAspect(%1)")
00537 .arg(video_aspect));
00538 LOG(VB_PLAYBACK, LOG_DEBUG, QString("overriden_video_aspect(%1)")
00539 .arg(overriden_video_aspect));
00540 LOG(VB_PLAYBACK, LOG_DEBUG, QString("CDisplayAspect: %1")
00541 .arg(fix_aspect(GetDisplayAspect())));
00542 LOG(VB_PLAYBACK, LOG_DEBUG, QString("AspectOverride: %1")
00543 .arg(aspectoverride));
00544 LOG(VB_PLAYBACK, LOG_DEBUG, QString("AdjustFill: %d") .arg(adjustfill));
00545 #endif
00546
00547 LOG(VB_PLAYBACK, LOG_INFO,
00548 QString("Display Rect left: %1, top: %2, width: %3, "
00549 "height: %4, aspect: %5")
00550 .arg(display_video_rect.left())
00551 .arg(display_video_rect.top())
00552 .arg(display_video_rect.width())
00553 .arg(display_video_rect.height())
00554 .arg(fix_aspect(GetDisplayAspect())));
00555
00556 LOG(VB_PLAYBACK, LOG_INFO,
00557 QString("Video Rect left: %1, top: %2, width: %3, "
00558 "height: %4, aspect: %5")
00559 .arg(video_rect.left())
00560 .arg(video_rect.top())
00561 .arg(video_rect.width())
00562 .arg(video_rect.height())
00563 .arg(overriden_video_aspect));
00564 }
00565
00574 void VideoOutWindow::SetVideoAspectRatio(float aspect)
00575 {
00576 video_aspect = aspect;
00577 overriden_video_aspect = get_aspect_override(aspectoverride, aspect);
00578 }
00579
00586 void VideoOutWindow::VideoAspectRatioChanged(float aspect)
00587 {
00588 SetVideoAspectRatio(aspect);
00589 MoveResize();
00590 }
00591
00598 bool VideoOutWindow::InputChanged(const QSize &input_size, float aspect,
00599 MythCodecID myth_codec_id, void *codec_private)
00600 {
00601 (void) myth_codec_id;
00602 (void) codec_private;
00603
00604 video_dim_act = input_size;
00605 video_disp_dim = fix_1080i(input_size);
00606 video_dim = fix_alignment(input_size);
00607
00608
00609
00610
00611 SetVideoAspectRatio(aspect);
00612
00613
00614
00615 return true;
00616 }
00617
00622 QRect VideoOutWindow::GetTotalOSDBounds(void) const
00623 {
00624 return QRect(QPoint(0, 0), video_disp_dim);
00625 }
00626
00634 void VideoOutWindow::ToggleAdjustFill(AdjustFillMode adjustFill)
00635 {
00636 if (adjustFill == kAdjustFill_Toggle)
00637 adjustFill = (AdjustFillMode) ((int) (adjustfill + 1) % kAdjustFill_END);
00638
00639 adjustfill = adjustFill;
00640
00641 MoveResize();
00642 }
00643
00647 void VideoOutWindow::SetVideoScalingAllowed(bool change)
00648 {
00649 if (change)
00650 {
00651 db_scale_vert =
00652 gCoreContext->GetNumSetting("VertScanPercentage", 0) * 0.01f;
00653 db_scale_horiz =
00654 gCoreContext->GetNumSetting("HorizScanPercentage", 0) * 0.01f;
00655 db_scaling_allowed = true;
00656 }
00657 else
00658 {
00659 db_scale_vert = 0.0f;
00660 db_scale_horiz = 0.0f;
00661 db_scaling_allowed = false;
00662 }
00663
00664 LOG(VB_PLAYBACK, LOG_INFO, QString("Over/underscan. V: %1, H: %2")
00665 .arg(db_scale_vert).arg(db_scale_horiz));
00666
00667 MoveResize();
00668 }
00669
00673 void VideoOutWindow::ResizeDisplayWindow(const QRect &rect,
00674 bool save_visible_rect)
00675 {
00676 if (save_visible_rect)
00677 tmp_display_visible_rect = display_visible_rect;
00678 display_visible_rect = rect;
00679 MoveResize();
00680 }
00681
00688 void VideoOutWindow::EmbedInWidget(const QRect &new_video_rect)
00689 {
00690 if (!allowpreviewepg && pip_state == kPIPOff)
00691 return;
00692
00693 embedding_rect = new_video_rect;
00694 bool save_visible_rect = !embedding;
00695
00696 embedding = true;
00697
00698 display_video_rect = new_video_rect;
00699 ResizeDisplayWindow(display_video_rect, save_visible_rect);
00700 }
00701
00707 void VideoOutWindow::StopEmbedding(void)
00708 {
00709 embedding_rect = QRect();
00710 display_visible_rect = tmp_display_visible_rect;
00711
00712 MoveResize();
00713
00714 embedding = false;
00715 }
00716
00723 QRect VideoOutWindow::GetVisibleOSDBounds(
00724 float &visible_aspect, float &font_scaling, float themeaspect) const
00725 {
00726 float dv_w = (((float)video_disp_dim.width()) /
00727 display_video_rect.width());
00728 float dv_h = (((float)video_disp_dim.height()) /
00729 display_video_rect.height());
00730
00731 uint right_overflow = max(
00732 (display_video_rect.width() + display_video_rect.left()) -
00733 display_visible_rect.width(), 0);
00734 uint lower_overflow = max(
00735 (display_video_rect.height() + display_video_rect.top()) -
00736 display_visible_rect.height(), 0);
00737
00738 bool isPBP = (kPBPLeft == pip_state || kPBPRight == pip_state);
00739 if (isPBP)
00740 {
00741 right_overflow = 0;
00742 lower_overflow = 0;
00743 }
00744
00745
00746 QPoint tl = QPoint((uint) ceil(max(-display_video_rect.left(),0)*dv_w),
00747 (uint) ceil(max(-display_video_rect.top(),0)*dv_h));
00748 QPoint br = QPoint(
00749 (uint) floor(video_disp_dim.width() - (right_overflow * dv_w)),
00750 (uint) floor(video_disp_dim.height() - (lower_overflow * dv_h)));
00751
00752 if ((db_scale_vert > 0.0f) || (db_scale_horiz > 0.0f))
00753 {
00754 QRect v(tl, br);
00755 float xs = (db_scale_horiz > 0.0f) ? db_scale_horiz : 0.0f;
00756 float ys = (db_scale_vert > 0.0f) ? db_scale_vert : 0.0f;
00757 QPoint s((int)(v.width() * xs), (int)(v.height() * ys));
00758 tl += s;
00759 br -= s;
00760 }
00761
00762 QRect vb(tl.x(), tl.y(), br.x() - tl.x(), br.y() - tl.y());
00763
00764
00765
00766
00767 vb = QRect(vb.x(), vb.y(), abs(vb.width()), abs(vb.height()));
00768
00769
00770 float dispPixelAdj = 1.0f;
00771 if (display_visible_rect.width())
00772 {
00773 dispPixelAdj = GetDisplayAspect() * display_visible_rect.height();
00774 dispPixelAdj /= display_visible_rect.width();
00775 }
00776
00777 if ((vb.height() >= 0) && overriden_video_aspect >= 0.0f)
00778 {
00779
00780 float vs = ((float)vb.width())/vb.height();
00781 visible_aspect =
00782 themeaspect * (vs/overriden_video_aspect) * dispPixelAdj;
00783 }
00784
00785 if (themeaspect >= 0.0f)
00786 {
00787
00788 float tmp = sqrtf(2.0f/(sq(visible_aspect / themeaspect) + 1.0f));
00789 if (tmp >= 0.0f)
00790 font_scaling = 1.0f / tmp;
00791
00792
00793 font_scaling *= sqrtf(overriden_video_aspect / themeaspect);
00794 }
00795
00796 if (isPBP)
00797 font_scaling *= 0.65f;
00798
00799 return vb;
00800 }
00801
00809 void VideoOutWindow::ToggleAspectOverride(AspectOverrideMode aspectMode)
00810 {
00811 if (pip_state > kPIPOff)
00812 {
00813 aspectMode = kAspect_Off;
00814 return;
00815 }
00816
00817 if (aspectMode == kAspect_Toggle)
00818 {
00819 aspectMode = (AspectOverrideMode) ((int) (aspectoverride + 1)
00820 % kAspect_END);
00821 }
00822
00823 aspectoverride = aspectMode;
00824
00825 VideoAspectRatioChanged(video_aspect);
00826 }
00827
00828
00829
00830
00831 QRect VideoOutWindow::GetPIPRect(
00832 PIPLocation location, MythPlayer *pipplayer, bool do_pixel_adj) const
00833 {
00834 QRect position;
00835
00836 float pipVideoAspect = pipplayer ? (float) pipplayer->GetVideoAspect()
00837 : (4.0f / 3.0f);
00838 int tmph = (display_visible_rect.height() * db_pip_size) / 100;
00839 float pixel_adj = 1;
00840 if (do_pixel_adj)
00841 {
00842 pixel_adj = ((float) display_visible_rect.width() /
00843 (float) display_visible_rect.height()) / display_aspect;
00844 }
00845 position.setHeight(tmph);
00846 position.setWidth((int) (tmph * pipVideoAspect * pixel_adj));
00847
00848 int xoff = (int) (display_visible_rect.width() * 0.06);
00849 int yoff = (int) (display_visible_rect.height() * 0.06);
00850 switch (location)
00851 {
00852 case kPIP_END:
00853 case kPIPTopLeft:
00854 break;
00855 case kPIPBottomLeft:
00856 yoff = display_visible_rect.height() - position.height() - yoff;
00857 break;
00858 case kPIPTopRight:
00859 xoff = display_visible_rect.width() - position.width() - xoff;
00860 break;
00861 case kPIPBottomRight:
00862 xoff = display_visible_rect.width() - position.width() - xoff;
00863 yoff = display_visible_rect.height() - position.height() - yoff;
00864 break;
00865 }
00866 position.translate(xoff, yoff);
00867 return position;
00868 }
00869
00876 void VideoOutWindow::Zoom(ZoomDirection direction)
00877 {
00878 if (kZoomHome == direction)
00879 {
00880 mz_scale_v = 1.0f;
00881 mz_scale_h = 1.0f;
00882 mz_move = QPoint(0, 0);
00883 }
00884 else if (kZoomIn == direction)
00885 {
00886 if ((mz_scale_h < kManualZoomMaxHorizontalZoom) &&
00887 (mz_scale_v < kManualZoomMaxVerticalZoom))
00888 {
00889 mz_scale_h *= 1.05f;
00890 mz_scale_v *= 1.05f;
00891 }
00892 else
00893 {
00894 float ratio = mz_scale_v / mz_scale_h;
00895 mz_scale_h = 1.0f;
00896 mz_scale_v = ratio * mz_scale_h;
00897 }
00898 }
00899 else if (kZoomOut == direction)
00900 {
00901 if ((mz_scale_h > kManualZoomMinHorizontalZoom) &&
00902 (mz_scale_v > kManualZoomMinVerticalZoom))
00903 {
00904 mz_scale_h *= 1.0f / 1.05f;
00905 mz_scale_v *= 1.0f / 1.05f;
00906 }
00907 else
00908 {
00909 float ratio = mz_scale_v / mz_scale_h;
00910 mz_scale_h = 1.0f;
00911 mz_scale_v = ratio * mz_scale_h;
00912 }
00913 }
00914 else if (kZoomAspectUp == direction)
00915 {
00916 if ((mz_scale_h < kManualZoomMaxHorizontalZoom) &&
00917 (mz_scale_v > kManualZoomMinVerticalZoom))
00918 {
00919 mz_scale_h *= 1.05f;
00920 mz_scale_v *= 1.0 / 1.05f;
00921 }
00922 }
00923 else if (kZoomAspectDown == direction)
00924 {
00925 if ((mz_scale_h > kManualZoomMinHorizontalZoom) &&
00926 (mz_scale_v < kManualZoomMaxVerticalZoom))
00927 {
00928 mz_scale_h *= 1.0 / 1.05f;
00929 mz_scale_v *= 1.05f;
00930 }
00931 }
00932 else if (kZoomUp == direction && (mz_move.y() <= +kManualZoomMaxMove))
00933 mz_move.setY(mz_move.y() + 2);
00934 else if (kZoomDown == direction && (mz_move.y() >= -kManualZoomMaxMove))
00935 mz_move.setY(mz_move.y() - 2);
00936 else if (kZoomLeft == direction && (mz_move.x() <= +kManualZoomMaxMove))
00937 mz_move.setX(mz_move.x() + 2);
00938 else if (kZoomRight == direction && (mz_move.x() >= -kManualZoomMaxMove))
00939 mz_move.setX(mz_move.x() - 2);
00940
00941 mz_scale_v = snap(mz_scale_v, 1.0f, 0.03f);
00942 mz_scale_h = snap(mz_scale_h, 1.0f, 0.03f);
00943 }
00944
00946 static float fix_aspect(float raw)
00947 {
00948
00949 if (fabs(raw - 1.333333f) < 0.05f)
00950 raw = 1.333333f;
00951
00952
00953 if (fabs(raw - 1.777777f) < 0.05f)
00954 raw = 1.777777f;
00955
00956 return raw;
00957 }
00958
00959 void VideoOutWindow::SetPIPState(PIPState setting)
00960 {
00961 LOG(VB_PLAYBACK, LOG_INFO,
00962 QString("VideoOutWindow::SetPIPState. pip_state: %1]") .arg(setting));
00963
00964 pip_state = setting;
00965 }
00966
00968 static QSize fix_1080i(QSize raw)
00969 {
00970 if (QSize(1920, 1088) == raw)
00971 return QSize(1920, 1080);
00972 if (QSize(1440, 1088) == raw)
00973 return QSize(1440, 1080);
00974 return raw;
00975 }
00976
00978 static QSize fix_alignment(QSize raw)
00979 {
00980 return QSize((raw.width() + 15) & (~0xf), (raw.height() + 15) & (~0xf));
00981 }
00982
00983 static float snap(float value, float snapto, float diff)
00984 {
00985 if ((value + diff > snapto) && (value - diff < snapto))
00986 return snapto;
00987 return value;
00988 }