00001 #include <cmath>
00002 #include <cstdlib>
00003
00004 #include <QDesktopWidget>
00005
00006 #include "osd.h"
00007 #include "mythplayer.h"
00008 #include "videodisplayprofile.h"
00009 #include "decoderbase.h"
00010
00011 #include "mythcorecontext.h"
00012 #include "mythlogging.h"
00013 #include "mythmainwindow.h"
00014 #include "mythuihelper.h"
00015 #include "mythxdisplay.h"
00016 #include "mythpainter_yuva.h"
00017 #include "util-osd.h"
00018
00019 #ifdef USING_XV
00020 #include "videoout_xv.h"
00021 #endif
00022
00023 #ifdef USING_MINGW
00024 #include "videoout_d3d.h"
00025 #endif
00026
00027 #ifdef USING_QUARTZ_VIDEO
00028 #include "videoout_quartz.h"
00029 #endif
00030
00031 #ifdef USING_OPENGL_VIDEO
00032 #include "videoout_opengl.h"
00033 #endif
00034
00035 #ifdef USING_VDPAU
00036 #include "videoout_vdpau.h"
00037 #include "videoout_nullvdpau.h"
00038 #endif
00039
00040 #ifdef USING_VAAPI
00041 #include "videoout_nullvaapi.h"
00042 #endif
00043 #ifdef USING_GLVAAPI
00044 #include "videoout_openglvaapi.h"
00045 #endif
00046 #include "videoout_null.h"
00047 #include "dithertable.h"
00048
00049 extern "C" {
00050 #include "libavcodec/avcodec.h"
00051 #include "libswscale/swscale.h"
00052 }
00053
00054 #include "filtermanager.h"
00055
00056 #include "videooutbase.h"
00057
00058 #define LOC QString("VideoOutput: ")
00059
00060 static QString to_comma_list(const QStringList &list);
00061
00062 void VideoOutput::GetRenderOptions(render_opts &opts)
00063 {
00064 QStringList cpudeints;
00065 cpudeints += "onefield";
00066 cpudeints += "linearblend";
00067 cpudeints += "kerneldeint";
00068 cpudeints += "kerneldoubleprocessdeint";
00069 cpudeints += "greedyhdeint";
00070 cpudeints += "greedyhdoubleprocessdeint";
00071 cpudeints += "yadifdeint";
00072 cpudeints += "yadifdoubleprocessdeint";
00073 cpudeints += "fieldorderdoubleprocessdeint";
00074 cpudeints += "none";
00075
00076 VideoOutputNull::GetRenderOptions(opts, cpudeints);
00077
00078 #ifdef USING_MINGW
00079 VideoOutputD3D::GetRenderOptions(opts, cpudeints);
00080 #endif
00081
00082 #ifdef USING_XV
00083 VideoOutputXv::GetRenderOptions(opts, cpudeints);
00084 #endif // USING_XV
00085
00086 #ifdef USING_QUARTZ_VIDEO
00087 VideoOutputQuartz::GetRenderOptions(opts, cpudeints);
00088 #endif // USING_QUARTZ_VIDEO
00089
00090 #ifdef USING_OPENGL_VIDEO
00091 VideoOutputOpenGL::GetRenderOptions(opts, cpudeints);
00092 #endif // USING_OPENGL_VIDEO
00093
00094 #ifdef USING_VDPAU
00095 VideoOutputVDPAU::GetRenderOptions(opts);
00096 VideoOutputNullVDPAU::GetRenderOptions(opts);
00097 #endif // USING_VDPAU
00098
00099 #ifdef USING_VAAPI
00100 VideoOutputNullVAAPI::GetRenderOptions(opts);
00101 #endif // USING_VAAPI
00102 #ifdef USING_GLVAAPI
00103 VideoOutputOpenGLVAAPI::GetRenderOptions(opts);
00104 #endif // USING_GLVAAPI
00105 }
00106
00112 VideoOutput *VideoOutput::Create(
00113 const QString &decoder, MythCodecID codec_id, void *codec_priv,
00114 PIPState pipState, const QSize &video_dim, float video_aspect,
00115 QWidget *parentwidget, const QRect &embed_rect, float video_prate,
00116 uint playerFlags)
00117 {
00118 (void) codec_priv;
00119 QStringList renderers;
00120 #ifdef USING_XV
00121 QStringList xvlist;
00122 #endif
00123 #ifdef USING_QUARTZ_VIDEO
00124 QStringList osxlist;
00125 #endif
00126
00127
00128 if (playerFlags & kVideoIsNull)
00129 {
00130
00131 renderers += "null";
00132
00133 if (playerFlags & kDecodeAllowGPU)
00134 {
00135 #ifdef USING_VDPAU
00136 renderers += VideoOutputNullVDPAU::GetAllowedRenderers(codec_id);
00137 #endif // USING_VDPAU
00138 #ifdef USING_VAAPI
00139 renderers += VideoOutputNullVAAPI::GetAllowedRenderers(codec_id);
00140 #endif
00141 }
00142 }
00143 else
00144 {
00145 #ifdef USING_MINGW
00146 renderers += VideoOutputD3D::GetAllowedRenderers(codec_id, video_dim);
00147 #endif
00148
00149 #ifdef USING_XV
00150 xvlist = VideoOutputXv::GetAllowedRenderers(codec_id, video_dim);
00151 renderers += xvlist;
00152 #endif // USING_XV
00153
00154 #ifdef USING_QUARTZ_VIDEO
00155 osxlist = VideoOutputQuartz::GetAllowedRenderers(codec_id, video_dim);
00156 renderers += osxlist;
00157 #endif // Q_OS_MACX
00158
00159 #ifdef USING_OPENGL_VIDEO
00160 renderers += VideoOutputOpenGL::GetAllowedRenderers(codec_id, video_dim);
00161 #endif // USING_OPENGL_VIDEO
00162
00163 #ifdef USING_VDPAU
00164 renderers += VideoOutputVDPAU::GetAllowedRenderers(codec_id, video_dim);
00165 #endif // USING_VDPAU
00166
00167 #ifdef USING_GLVAAPI
00168 renderers += VideoOutputOpenGLVAAPI::GetAllowedRenderers(codec_id, video_dim);
00169 #endif // USING_GLVAAPI
00170 }
00171
00172 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Allowed renderers: " +
00173 to_comma_list(renderers));
00174
00175 renderers = VideoDisplayProfile::GetFilteredRenderers(decoder, renderers);
00176
00177 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Allowed renderers (filt: " + decoder +
00178 "): " + to_comma_list(renderers));
00179
00180 QString renderer = QString::null;
00181 if (renderers.size() > 0)
00182 {
00183 VideoDisplayProfile vprof;
00184 vprof.SetInput(video_dim);
00185
00186 QString tmp = vprof.GetVideoRenderer();
00187 if (vprof.IsDecoderCompatible(decoder) && renderers.contains(tmp))
00188 {
00189 renderer = tmp;
00190 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Preferred renderer: " + renderer);
00191 }
00192 }
00193
00194 if (renderer.isEmpty())
00195 renderer = VideoDisplayProfile::GetBestVideoRenderer(renderers);
00196
00197 while (!renderers.empty())
00198 {
00199 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00200 QString("Trying video renderer: '%1'").arg(renderer));
00201 int index = renderers.indexOf(renderer);
00202 if (index >= 0)
00203 renderers.removeAt(index);
00204 else
00205 break;
00206
00207 VideoOutput *vo = NULL;
00208
00209 #ifdef USING_MINGW
00210 if (renderer == "direct3d")
00211 vo = new VideoOutputD3D();
00212 #endif // USING_MINGW
00213
00214 #ifdef USING_QUARTZ_VIDEO
00215 if (osxlist.contains(renderer))
00216 vo = new VideoOutputQuartz();
00217 #endif // Q_OS_MACX
00218
00219 #ifdef USING_OPENGL_VIDEO
00220 if (renderer.contains("opengl"))
00221 vo = new VideoOutputOpenGL(renderer);
00222 #endif // USING_OPENGL_VIDEO
00223
00224 #ifdef USING_VDPAU
00225 if (renderer == "vdpau")
00226 vo = new VideoOutputVDPAU();
00227 if (renderer == "nullvdpau")
00228 vo = new VideoOutputNullVDPAU();
00229 #endif // USING_VDPAU
00230
00231 #ifdef USING_VAAPI
00232 if (renderer == "nullvaapi")
00233 vo = new VideoOutputNullVAAPI();
00234 #endif // USING_VAAPI
00235 #ifdef USING_GLVAAPI
00236 if (renderer == "openglvaapi")
00237 vo = new VideoOutputOpenGLVAAPI();
00238 #endif // USING_GLVAAPI
00239 #ifdef USING_XV
00240 if (xvlist.contains(renderer))
00241 vo = new VideoOutputXv();
00242 #endif // USING_XV
00243
00244 if (renderer == "null")
00245 vo = new VideoOutputNull();
00246
00247 if (vo && !(playerFlags & kVideoIsNull))
00248 {
00249
00250 QWidget *widget = parentwidget;
00251 MythMainWindow *window = GetMythMainWindow();
00252 if (!widget && window)
00253 widget = window->findChild<QWidget*>("video playback window");
00254
00255 if (!widget)
00256 {
00257 LOG(VB_GENERAL, LOG_ERR, LOC + "No window for video output.");
00258 delete vo;
00259 vo = NULL;
00260 return NULL;
00261 }
00262
00263 if (!widget->winId())
00264 {
00265 LOG(VB_GENERAL, LOG_ERR, LOC + "No window for video output.");
00266 delete vo;
00267 vo = NULL;
00268 return NULL;
00269 }
00270
00271
00272 QRect display_rect = QRect(0, 0, widget->width(), widget->height());
00273 if (pipState == kPIPStandAlone)
00274 display_rect = embed_rect;
00275
00276 vo->SetPIPState(pipState);
00277 vo->SetVideoFrameRate(video_prate);
00278 if (vo->Init(
00279 video_dim.width(), video_dim.height(), video_aspect,
00280 widget->winId(), display_rect, codec_id))
00281 {
00282 vo->SetVideoScalingAllowed(true);
00283 return vo;
00284 }
00285
00286 delete vo;
00287 vo = NULL;
00288 }
00289 else if (vo && (playerFlags & kVideoIsNull))
00290 {
00291 if (vo->Init(video_dim.width(), video_dim.height(),
00292 video_aspect, 0, QRect(), codec_id))
00293 {
00294 return vo;
00295 }
00296
00297 delete vo;
00298 vo = NULL;
00299 }
00300
00301 renderer = VideoDisplayProfile::GetBestVideoRenderer(renderers);
00302 }
00303
00304 LOG(VB_GENERAL, LOG_ERR, LOC +
00305 "Not compiled with any useable video output method.");
00306
00307 return NULL;
00308 }
00309
00379 VideoOutput::VideoOutput() :
00380
00381 db_display_dim(0,0),
00382 db_aspectoverride(kAspect_Off), db_adjustfill(kAdjustFill_Off),
00383 db_letterbox_colour(kLetterBoxColour_Black),
00384 db_deint_filtername(QString::null),
00385
00386
00387 video_codec_id(kCodec_NONE), db_vdisp_profile(NULL),
00388
00389
00390 pip_desired_display_size(160,128), pip_display_size(0,0),
00391 pip_video_size(0,0),
00392 pip_tmp_buf(NULL), pip_tmp_buf2(NULL),
00393 pip_scaling_context(NULL),
00394
00395
00396 vsz_enabled(false),
00397 vsz_desired_display_rect(0,0,0,0), vsz_display_size(0,0),
00398 vsz_video_size(0,0),
00399 vsz_tmp_buf(NULL), vsz_scale_context(NULL),
00400
00401
00402 m_deinterlacing(false), m_deintfiltername("linearblend"),
00403 m_deintFiltMan(NULL), m_deintFilter(NULL),
00404 m_deinterlaceBeforeOSD(true),
00405
00406
00407 errorState(kError_None), framesPlayed(0),
00408
00409
00410 display_res(NULL),
00411
00412
00413 monitor_sz(640,480), monitor_dim(400,300),
00414
00415
00416 osd_painter(NULL), osd_image(NULL),
00417
00418
00419 m_visual(NULL),
00420
00421
00422 m_stereo(kStereoscopicModeNone)
00423 {
00424 memset(&pip_tmp_image, 0, sizeof(pip_tmp_image));
00425 db_display_dim = QSize(gCoreContext->GetNumSetting("DisplaySizeWidth", 0),
00426 gCoreContext->GetNumSetting("DisplaySizeHeight", 0));
00427
00428 db_aspectoverride = (AspectOverrideMode)
00429 gCoreContext->GetNumSetting("AspectOverride", 0);
00430 db_adjustfill = (AdjustFillMode)
00431 gCoreContext->GetNumSetting("AdjustFill", 0);
00432 db_letterbox_colour = (LetterBoxColour)
00433 gCoreContext->GetNumSetting("LetterboxColour", 0);
00434
00435 if (!gCoreContext->IsDatabaseIgnored())
00436 db_vdisp_profile = new VideoDisplayProfile();
00437 }
00438
00443 VideoOutput::~VideoOutput()
00444 {
00445 if (osd_image)
00446 osd_image->DownRef();
00447 if (osd_painter)
00448 delete osd_painter;
00449
00450 ShutdownPipResize();
00451
00452 ShutdownVideoResize();
00453
00454 if (m_deintFilter)
00455 delete m_deintFilter;
00456 if (m_deintFiltMan)
00457 delete m_deintFiltMan;
00458 if (db_vdisp_profile)
00459 delete db_vdisp_profile;
00460
00461 ResizeForGui();
00462 if (display_res)
00463 display_res->Unlock();
00464 }
00465
00471 bool VideoOutput::Init(int width, int height, float aspect, WId winid,
00472 const QRect &win_rect, MythCodecID codec_id)
00473 {
00474 (void)winid;
00475
00476 video_codec_id = codec_id;
00477 bool wasembedding = window.IsEmbedding();
00478 QRect oldrect;
00479 if (wasembedding)
00480 {
00481 oldrect = window.GetEmbeddingRect();
00482 StopEmbedding();
00483 }
00484
00485 bool mainSuccess = window.Init(QSize(width, height), aspect, win_rect,
00486 db_aspectoverride, db_adjustfill);
00487
00488 if (db_vdisp_profile)
00489 db_vdisp_profile->SetInput(window.GetVideoDim());
00490
00491 if (wasembedding)
00492 EmbedInWidget(oldrect);
00493
00494 VideoAspectRatioChanged(aspect);
00495
00496 return mainSuccess;
00497 }
00498
00499 void VideoOutput::InitOSD(OSD *osd)
00500 {
00501 if (db_vdisp_profile && !db_vdisp_profile->IsOSDFadeEnabled())
00502 osd->DisableFade();
00503 }
00504
00505 QString VideoOutput::GetFilters(void) const
00506 {
00507 if (db_vdisp_profile)
00508 return db_vdisp_profile->GetFilters();
00509 return QString::null;
00510 }
00511
00512 bool VideoOutput::IsPreferredRenderer(QSize video_size)
00513 {
00514 if (!db_vdisp_profile || (video_size == window.GetVideoDispDim()))
00515 return true;
00516
00517 VideoDisplayProfile vdisp;
00518 vdisp.SetInput(video_size);
00519 QString new_rend = vdisp.GetVideoRenderer();
00520 if (new_rend.isEmpty())
00521 return true;
00522
00523 return db_vdisp_profile->CheckVideoRendererGroup(new_rend);
00524 }
00525
00526 void VideoOutput::SetVideoFrameRate(float playback_fps)
00527 {
00528 if (db_vdisp_profile)
00529 db_vdisp_profile->SetOutput(playback_fps);
00530 }
00531
00537 bool VideoOutput::SetDeinterlacingEnabled(bool enable)
00538 {
00539 if (enable && m_deinterlacing)
00540 return m_deinterlacing;
00541
00542
00543 if (enable && (!m_deintFiltMan || !m_deintFilter))
00544 return SetupDeinterlace(enable);
00545
00546 m_deinterlacing = enable;
00547 return m_deinterlacing;
00548 }
00549
00556 bool VideoOutput::SetupDeinterlace(bool interlaced,
00557 const QString& overridefilter)
00558 {
00559 PIPState pip_state = window.GetPIPState();
00560
00561 if (pip_state > kPIPOff && pip_state < kPBPLeft)
00562 return false;
00563
00564 if (m_deinterlacing == interlaced)
00565 return m_deinterlacing;
00566
00567 if (m_deintFiltMan)
00568 {
00569 delete m_deintFiltMan;
00570 m_deintFiltMan = NULL;
00571 }
00572 if (m_deintFilter)
00573 {
00574 delete m_deintFilter;
00575 m_deintFilter = NULL;
00576 }
00577
00578 m_deinterlacing = interlaced;
00579
00580 if (m_deinterlacing)
00581 {
00582 m_deinterlaceBeforeOSD = true;
00583
00584 VideoFrameType itmp = FMT_YV12;
00585 VideoFrameType otmp = FMT_YV12;
00586 int btmp;
00587
00588 if (db_vdisp_profile)
00589 m_deintfiltername =
00590 db_vdisp_profile->GetFilteredDeint(overridefilter);
00591 else
00592 m_deintfiltername = "";
00593
00594 m_deintFiltMan = new FilterManager;
00595 m_deintFilter = NULL;
00596
00597 if (!m_deintfiltername.isEmpty())
00598 {
00599 if (!ApproveDeintFilter(m_deintfiltername))
00600 {
00601 LOG(VB_GENERAL, LOG_ERR,
00602 QString("Failed to approve '%1' deinterlacer "
00603 "as a software deinterlacer")
00604 .arg(m_deintfiltername));
00605 m_deintfiltername = QString::null;
00606 }
00607 else
00608 {
00609 int threads = db_vdisp_profile ?
00610 db_vdisp_profile->GetMaxCPUs() : 1;
00611 const QSize video_dim = window.GetVideoDim();
00612 int width = video_dim.width();
00613 int height = video_dim.height();
00614 m_deintFilter = m_deintFiltMan->LoadFilters(
00615 m_deintfiltername, itmp, otmp,
00616 width, height, btmp, threads);
00617 window.SetVideoDim(QSize(width, height));
00618 }
00619 }
00620
00621 if (m_deintFilter == NULL)
00622 {
00623 LOG(VB_GENERAL, LOG_ERR, LOC +
00624 QString("Couldn't load deinterlace filter %1")
00625 .arg(m_deintfiltername));
00626 m_deinterlacing = false;
00627 m_deintfiltername = "";
00628 }
00629
00630 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Using deinterlace method %1")
00631 .arg(m_deintfiltername));
00632
00633 if (m_deintfiltername == "bobdeint")
00634 m_deinterlaceBeforeOSD = false;
00635 }
00636
00637 return m_deinterlacing;
00638 }
00639
00643 void VideoOutput::FallbackDeint(void)
00644 {
00645 SetupDeinterlace(false);
00646 if (db_vdisp_profile)
00647 SetupDeinterlace(true, db_vdisp_profile->GetFallbackDeinterlacer());
00648 }
00649
00653 void VideoOutput::BestDeint(void)
00654 {
00655 SetupDeinterlace(false);
00656 SetupDeinterlace(true);
00657 }
00658
00668 bool VideoOutput::IsExtraProcessingRequired(void) const
00669 {
00670 return (m_deintfiltername.contains("doubleprocess")) && m_deinterlacing;
00671 }
00678 bool VideoOutput::NeedsDoubleFramerate() const
00679 {
00680
00681 return ((m_deintfiltername.contains("bobdeint") ||
00682 m_deintfiltername.contains("doublerate") ||
00683 m_deintfiltername.contains("doubleprocess")) &&
00684 m_deinterlacing);
00685 }
00686
00687 bool VideoOutput::IsBobDeint(void) const
00688 {
00689 return (m_deinterlacing && m_deintfiltername == "bobdeint");
00690 }
00691
00697 bool VideoOutput::ApproveDeintFilter(const QString& filtername) const
00698 {
00699
00700 return (!filtername.contains("bobdeint") &&
00701 !filtername.contains("doublerate") &&
00702 !filtername.contains("opengl") &&
00703 !filtername.contains("vdpau"));
00704 }
00705
00706 void VideoOutput::GetDeinterlacers(QStringList &deinterlacers)
00707 {
00708 if (!db_vdisp_profile)
00709 return;
00710 QString rend = db_vdisp_profile->GetActualVideoRenderer();
00711 deinterlacers = db_vdisp_profile->GetDeinterlacers(rend);
00712 }
00713
00714 QString VideoOutput::GetDeinterlacer(void)
00715 {
00716 QString res = m_deintfiltername;
00717 res.detach();
00718 return res;
00719 }
00720
00727 void VideoOutput::VideoAspectRatioChanged(float aspect)
00728 {
00729 window.VideoAspectRatioChanged(aspect);
00730 }
00731
00737 bool VideoOutput::InputChanged(const QSize &input_size,
00738 float aspect,
00739 MythCodecID myth_codec_id,
00740 void *codec_private,
00741 bool &aspect_only)
00742 {
00743 window.InputChanged(input_size, aspect, myth_codec_id, codec_private);
00744
00745 if (db_vdisp_profile)
00746 db_vdisp_profile->SetInput(window.GetVideoDim());
00747 video_codec_id = myth_codec_id;
00748 BestDeint();
00749
00750 DiscardFrames(true);
00751
00752 return true;
00753 }
00757 void VideoOutput::ResizeDisplayWindow(const QRect &rect, bool save_visible_rect)
00758 {
00759 window.ResizeDisplayWindow(rect, save_visible_rect);
00760 }
00761
00766 void VideoOutput::EmbedInWidget(const QRect &rect)
00767 {
00768 window.EmbedInWidget(rect);
00769 }
00770
00776 void VideoOutput::StopEmbedding(void)
00777 {
00778 window.StopEmbedding();
00779 }
00780
00786 void VideoOutput::DrawSlice(VideoFrame *frame, int x, int y, int w, int h)
00787 {
00788 (void)frame;
00789 (void)x;
00790 (void)y;
00791 (void)w;
00792 (void)h;
00793 }
00794
00795 void VideoOutput::GetOSDBounds(QRect &total, QRect &visible,
00796 float &visible_aspect,
00797 float &font_scaling,
00798 float themeaspect) const
00799 {
00800 total = GetTotalOSDBounds();
00801 visible = GetVisibleOSDBounds(visible_aspect, font_scaling, themeaspect);
00802 }
00803
00810 QRect VideoOutput::GetVisibleOSDBounds(
00811 float &visible_aspect, float &font_scaling, float themeaspect) const
00812 {
00813 if (!hasFullScreenOSD())
00814 {
00815 return window.GetVisibleOSDBounds(
00816 visible_aspect, font_scaling, themeaspect);
00817 }
00818
00819 QRect dvr = window.GetDisplayVisibleRect();
00820
00821
00822 QSize dvr2 = QSize(dvr.width() & ~0x3,
00823 dvr.height() & ~0x1);
00824
00825 float dispPixelAdj = 1.0f;
00826 if (dvr2.height() && dvr2.width())
00827 dispPixelAdj = (GetDisplayAspect() * dvr2.height()) / dvr2.width();
00828 visible_aspect = themeaspect / dispPixelAdj;
00829 font_scaling = 1.0f;
00830 return QRect(QPoint(0,0), dvr2);
00831 }
00832
00837 QRect VideoOutput::GetTotalOSDBounds(void) const
00838 {
00839 if (!hasFullScreenOSD())
00840 return window.GetTotalOSDBounds();
00841
00842 QRect dvr = window.GetDisplayVisibleRect();
00843 QSize dvr2 = QSize(dvr.width() & ~0x3,
00844 dvr.height() & ~0x1);
00845
00846 return QRect(QPoint(0,0), dvr2);
00847 }
00848
00849 QRect VideoOutput::GetMHEGBounds(void)
00850 {
00851 if (!hasFullScreenOSD())
00852 return window.GetTotalOSDBounds();
00853
00854 QRect dvr = window.GetDisplayVideoRect();
00855 return QRect(QPoint(dvr.left() & ~0x1, dvr.top() & ~0x1),
00856 QSize(dvr.width() & ~0x1, dvr.height() & ~0x1));
00857 }
00858
00859 bool VideoOutput::AllowPreviewEPG(void) const
00860 {
00861 return window.IsPreviewEPGAllowed();
00862 }
00863
00874 void VideoOutput::MoveResize(void)
00875 {
00876 window.MoveResize();
00877 }
00878
00885 void VideoOutput::Zoom(ZoomDirection direction)
00886 {
00887 window.Zoom(direction);
00888 }
00889
00897 void VideoOutput::ToggleAspectOverride(AspectOverrideMode aspectMode)
00898 {
00899 window.ToggleAspectOverride(aspectMode);
00900 }
00901
00909 void VideoOutput::ToggleAdjustFill(AdjustFillMode adjustFill)
00910 {
00911 window.ToggleAdjustFill(adjustFill);
00912 }
00913
00914 int VideoOutput::ChangePictureAttribute(
00915 PictureAttribute attributeType, bool direction)
00916 {
00917 int curVal = GetPictureAttribute(attributeType);
00918 if (curVal < 0)
00919 return -1;
00920
00921 int newVal = curVal + ((direction) ? +1 : -1);
00922
00923 if (kPictureAttribute_Hue == attributeType)
00924 newVal = newVal % 100;
00925
00926 if ((kPictureAttribute_StudioLevels == attributeType) && newVal > 1)
00927 newVal = 1;
00928
00929 newVal = min(max(newVal, 0), 100);
00930
00931 return SetPictureAttribute(attributeType, newVal);
00932 }
00933
00941 int VideoOutput::SetPictureAttribute(PictureAttribute attribute, int newValue)
00942 {
00943 return videoColourSpace.SetPictureAttribute(attribute, newValue);
00944 }
00945
00946 int VideoOutput::GetPictureAttribute(PictureAttribute attributeType)
00947 {
00948 return videoColourSpace.GetPictureAttribute(attributeType);
00949 }
00950
00954 QString VideoOutput::GetOSDRenderer(void) const
00955 {
00956 return db_vdisp_profile->GetOSDRenderer();
00957 }
00958
00959
00960
00961
00962 QRect VideoOutput::GetPIPRect(
00963 PIPLocation location, MythPlayer *pipplayer, bool do_pixel_adj) const
00964 {
00965 return window.GetPIPRect(location, pipplayer, do_pixel_adj);
00966 }
00967
00975 void VideoOutput::DoPipResize(int pipwidth, int pipheight)
00976 {
00977 QSize vid_size = QSize(pipwidth, pipheight);
00978 if (vid_size == pip_desired_display_size)
00979 return;
00980
00981 ShutdownPipResize();
00982
00983 pip_video_size = vid_size;
00984 pip_display_size = pip_desired_display_size;
00985
00986 int sz = pip_display_size.height() * pip_display_size.width() * 3 / 2;
00987 pip_tmp_buf = new unsigned char[sz];
00988 pip_tmp_buf2 = new unsigned char[sz];
00989
00990 pip_scaling_context = sws_getCachedContext(pip_scaling_context,
00991 pip_video_size.width(), pip_video_size.height(),
00992 PIX_FMT_YUV420P,
00993 pip_display_size.width(),
00994 pip_display_size.height(),
00995 PIX_FMT_YUV420P, SWS_FAST_BILINEAR,
00996 NULL, NULL, NULL);
00997 }
00998
01005 void VideoOutput::ShutdownPipResize(void)
01006 {
01007 if (pip_tmp_buf)
01008 {
01009 delete [] pip_tmp_buf;
01010 pip_tmp_buf = NULL;
01011 }
01012
01013 if (pip_tmp_buf2)
01014 {
01015 delete [] pip_tmp_buf2;
01016 pip_tmp_buf2 = NULL;
01017 }
01018
01019 if (pip_scaling_context)
01020 {
01021 sws_freeContext(pip_scaling_context);
01022 pip_scaling_context = NULL;
01023 }
01024
01025 pip_video_size = QSize(0,0);
01026 pip_display_size = QSize(0,0);
01027 }
01028
01029 void VideoOutput::ShowPIPs(VideoFrame *frame, const PIPMap &pipPlayers)
01030 {
01031 PIPMap::const_iterator it = pipPlayers.begin();
01032 for (; it != pipPlayers.end(); ++it)
01033 ShowPIP(frame, it.key(), *it);
01034 }
01035
01046 void VideoOutput::ShowPIP(VideoFrame *frame,
01047 MythPlayer *pipplayer,
01048 PIPLocation loc)
01049 {
01050 if (!pipplayer)
01051 return;
01052
01053 const float video_aspect = window.GetVideoAspect();
01054
01055
01056
01057
01058
01059 int pipw, piph;
01060 VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
01061 const bool pipActive = pipplayer->IsPIPActive();
01062 const bool pipVisible = pipplayer->IsPIPVisible();
01063 const float pipVideoAspect = pipplayer->GetVideoAspect();
01064
01065
01066
01067 if ((video_aspect <= 0) || (pipVideoAspect <= 0) ||
01068 (frame->height <= 0) || (frame->width <= 0) ||
01069 !pipimage || !pipimage->buf || pipimage->codec != FMT_YV12)
01070 {
01071 pipplayer->ReleaseCurrentFrame(pipimage);
01072 return;
01073 }
01074
01075 if (!pipVisible)
01076 {
01077 pipplayer->ReleaseCurrentFrame(pipimage);
01078 return;
01079 }
01080
01081 QRect position = GetPIPRect(loc, pipplayer);
01082 pip_desired_display_size = position.size();
01083
01084
01085 unsigned char *pipbuf = pipimage->buf;
01086 if (pipw != pip_desired_display_size.width() ||
01087 piph != pip_desired_display_size.height())
01088 {
01089 DoPipResize(pipw, piph);
01090
01091 memset(&pip_tmp_image, 0, sizeof(pip_tmp_image));
01092
01093 if (pip_tmp_buf && pip_scaling_context)
01094 {
01095 AVPicture img_in, img_out;
01096
01097 avpicture_fill(
01098 &img_out, (uint8_t *)pip_tmp_buf, PIX_FMT_YUV420P,
01099 pip_display_size.width(), pip_display_size.height());
01100
01101 avpicture_fill(&img_in, (uint8_t *)pipimage->buf, PIX_FMT_YUV420P,
01102 pipw, piph);
01103
01104 sws_scale(pip_scaling_context, img_in.data, img_in.linesize, 0,
01105 piph, img_out.data, img_out.linesize);
01106
01107 if (pipActive)
01108 {
01109 AVPicture img_padded;
01110 avpicture_fill(
01111 &img_padded, (uint8_t *)pip_tmp_buf2, PIX_FMT_YUV420P,
01112 pip_display_size.width(), pip_display_size.height());
01113
01114 int color[3] = { 20, 0, 200 };
01115 av_picture_pad(&img_padded, &img_out,
01116 pip_display_size.height(),
01117 pip_display_size.width(),
01118 PIX_FMT_YUV420P, 10, 10, 10, 10, color);
01119
01120 pipbuf = pip_tmp_buf2;
01121 }
01122 else
01123 {
01124 pipbuf = pip_tmp_buf;
01125 }
01126
01127 pipw = pip_display_size.width();
01128 piph = pip_display_size.height();
01129
01130 init(&pip_tmp_image, FMT_YV12, pipbuf, pipw, piph, sizeof(*pipbuf));
01131 }
01132 }
01133
01134 int xoff = position.left();
01135 int yoff = position.top();
01136 uint xoff2[3] = { xoff, xoff>>1, xoff>>1 };
01137 uint yoff2[3] = { yoff, yoff>>1, yoff>>1 };
01138
01139 uint pip_height = pip_tmp_image.height;
01140 uint height[3] = { pip_height, pip_height>>1, pip_height>>1 };
01141
01142 for (int p = 0; p < 3; p++)
01143 {
01144 for (uint h = 2; h < height[p]; h++)
01145 {
01146 memcpy((frame->buf + frame->offsets[p]) + (h + yoff2[p]) *
01147 frame->pitches[p] + xoff2[p],
01148 (pip_tmp_image.buf + pip_tmp_image.offsets[p]) + h *
01149 pip_tmp_image.pitches[p], pip_tmp_image.pitches[p]);
01150 }
01151 }
01152
01153
01154 pipplayer->ReleaseCurrentFrame(pipimage);
01155 }
01156
01163 void VideoOutput::DoVideoResize(const QSize &inDim, const QSize &outDim)
01164 {
01165 if ((inDim == vsz_video_size) && (outDim == vsz_display_size))
01166 return;
01167
01168 ShutdownVideoResize();
01169
01170 vsz_enabled = true;
01171 vsz_video_size = inDim;
01172 vsz_display_size = outDim;
01173
01174 int sz = vsz_display_size.height() * vsz_display_size.width() * 3 / 2;
01175 vsz_tmp_buf = new unsigned char[sz];
01176
01177 vsz_scale_context = sws_getCachedContext(vsz_scale_context,
01178 vsz_video_size.width(), vsz_video_size.height(),
01179 PIX_FMT_YUV420P,
01180 vsz_display_size.width(),
01181 vsz_display_size.height(),
01182 PIX_FMT_YUV420P, SWS_FAST_BILINEAR,
01183 NULL, NULL, NULL);
01184 }
01185
01186 void VideoOutput::ResizeVideo(VideoFrame *frame)
01187 {
01188 if (vsz_desired_display_rect.isNull() || frame->codec != FMT_YV12)
01189 return;
01190
01191 QRect resize = vsz_desired_display_rect;
01192 QSize frameDim(frame->width, frame->height);
01193
01194
01195 bool abort =
01196 (resize.right() > frame->width || resize.bottom() > frame->height ||
01197 resize.width() > frame->width || resize.height() > frame->height);
01198
01199 abort |= !resize.left() && !resize.top() && (resize.size() == frameDim);
01200
01201 if (abort)
01202 {
01203 ShutdownVideoResize();
01204 vsz_desired_display_rect = QRect();
01205 return;
01206 }
01207
01208 DoVideoResize(frameDim, resize.size());
01209 if (!vsz_tmp_buf)
01210 {
01211 ShutdownVideoResize();
01212 vsz_desired_display_rect = QRect();
01213 return;
01214 }
01215
01216 if (vsz_tmp_buf && vsz_scale_context)
01217 {
01218 AVPicture img_in, img_out;
01219
01220 avpicture_fill(&img_out, (uint8_t *)vsz_tmp_buf, PIX_FMT_YUV420P,
01221 resize.width(), resize.height());
01222 avpicture_fill(&img_in, (uint8_t *)frame->buf, PIX_FMT_YUV420P,
01223 frame->width, frame->height);
01224 sws_scale(vsz_scale_context, img_in.data, img_in.linesize, 0,
01225 frame->height, img_out.data, img_out.linesize);
01226 }
01227
01228 int xoff = resize.left();
01229 int yoff = resize.top();
01230 int resw = resize.width();
01231
01232
01233 for (int i = 0; i < resize.height(); i++)
01234 {
01235 memcpy(frame->buf + (i + yoff) * frame->width + xoff,
01236 vsz_tmp_buf + i * resw, resw);
01237 }
01238
01239
01240 xoff /= 2;
01241 yoff /= 2;
01242
01243 unsigned char *uptr = frame->buf + frame->width * frame->height;
01244 unsigned char *vptr = frame->buf + frame->width * frame->height * 5 / 4;
01245 int vidw = frame->width / 2;
01246
01247 unsigned char *videouptr = vsz_tmp_buf + resw * resize.height();
01248 unsigned char *videovptr = vsz_tmp_buf + resw * resize.height() * 5 / 4;
01249 resw /= 2;
01250 for (int i = 0; i < resize.height() / 2; i ++)
01251 {
01252 memcpy(uptr + (i + yoff) * vidw + xoff, videouptr + i * resw, resw);
01253 memcpy(vptr + (i + yoff) * vidw + xoff, videovptr + i * resw, resw);
01254 }
01255 }
01256
01257 AspectOverrideMode VideoOutput::GetAspectOverride(void) const
01258 {
01259 return window.GetAspectOverride();
01260 }
01261
01262 AdjustFillMode VideoOutput::GetAdjustFill(void) const
01263 {
01264 return window.GetAdjustFill();
01265 }
01266
01267 float VideoOutput::GetDisplayAspect(void) const
01268 {
01269 return window.GetDisplayAspect();
01270 }
01271
01272 bool VideoOutput::IsVideoScalingAllowed(void) const
01273 {
01274 return window.IsVideoScalingAllowed();
01275 }
01276
01277 void VideoOutput::ShutdownVideoResize(void)
01278 {
01279 if (vsz_tmp_buf)
01280 {
01281 delete [] vsz_tmp_buf;
01282 vsz_tmp_buf = NULL;
01283 }
01284
01285 if (vsz_scale_context)
01286 {
01287 sws_freeContext(vsz_scale_context);
01288 vsz_scale_context = NULL;
01289 }
01290
01291 vsz_video_size = QSize(0,0);
01292 vsz_display_size = QSize(0,0);
01293 vsz_enabled = false;
01294 }
01295
01296 void VideoOutput::ClearDummyFrame(VideoFrame *frame)
01297 {
01298
01299 if (frame)
01300 frame->dummy = 1;
01301
01302 clear(frame);
01303 }
01304
01305 void VideoOutput::SetVideoResize(const QRect &videoRect)
01306 {
01307 if (!videoRect.isValid() ||
01308 videoRect.width() < 1 || videoRect.height() < 1 ||
01309 videoRect.left() < 0 || videoRect.top() < 0)
01310 {
01311 ShutdownVideoResize();
01312 vsz_desired_display_rect = QRect();
01313 }
01314 else
01315 {
01316 vsz_enabled = true;
01317 vsz_desired_display_rect = videoRect;
01318 }
01319 }
01320
01324 void VideoOutput::SetVideoScalingAllowed(bool change)
01325 {
01326 window.SetVideoScalingAllowed(change);
01327 }
01328
01339 bool VideoOutput::DisplayOSD(VideoFrame *frame, OSD *osd)
01340 {
01341 if (!osd || !frame)
01342 return false;
01343
01344 if (vsz_enabled)
01345 ResizeVideo(frame);
01346
01347 if (!osd_painter)
01348 {
01349 osd_painter = new MythYUVAPainter();
01350 if (!osd_painter)
01351 return false;
01352 }
01353
01354 QSize osd_size = GetTotalOSDBounds().size();
01355 if (osd_image && (osd_image->size() != osd_size))
01356 {
01357 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("OSD size changed."));
01358 osd_image->DownRef();
01359 osd_image = NULL;
01360 }
01361
01362 if (!osd_image)
01363 {
01364 osd_image = osd_painter->GetFormatImage();
01365 if (osd_image)
01366 {
01367 QImage blank = QImage(osd_size,
01368 QImage::Format_ARGB32_Premultiplied);
01369 osd_image->Assign(blank);
01370 osd_image->ConvertToYUV();
01371 osd_painter->Clear(osd_image,
01372 QRegion(QRect(QPoint(0,0), osd_size)));
01373 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Created YV12 OSD."));
01374 }
01375 else
01376 return false;
01377 }
01378
01379 if (m_visual)
01380 {
01381 LOG(VB_GENERAL, LOG_ERR, LOC + "Visualiser not supported here");
01382
01383 m_visual->Draw(QRect(), NULL, NULL);
01384 }
01385
01386 QRegion dirty = QRegion();
01387 QRegion visible = osd->Draw(osd_painter, osd_image, osd_size, dirty,
01388 frame->codec == FMT_YV12 ? ALIGN_X_MMX : 0,
01389 frame->codec == FMT_YV12 ? ALIGN_C : 0);
01390 bool changed = !dirty.isEmpty();
01391 bool show = !visible.isEmpty();
01392
01393 if (!show)
01394 return show;
01395
01396 if (!changed && frame->codec != FMT_YV12)
01397 return show;
01398
01399 QSize video_dim = window.GetVideoDim();
01400
01401 QVector<QRect> vis = visible.rects();
01402 for (int i = 0; i < vis.size(); i++)
01403 {
01404 int left = min(vis[i].left(), osd_image->width());
01405 int top = min(vis[i].top(), osd_image->height());
01406 int right = min(left + vis[i].width(), osd_image->width());
01407 int bottom = min(top + vis[i].height(), osd_image->height());
01408
01409 if (FMT_YV12 == frame->codec)
01410 {
01411 yuv888_to_yv12(frame, osd_image, left, top, right, bottom);
01412 }
01413 else if (FMT_AI44 == frame->codec)
01414 {
01415 memset(frame->buf, 0, video_dim.width() * video_dim.height());
01416 yuv888_to_i44(frame->buf, osd_image, video_dim,
01417 left, top, right, bottom, true);
01418 }
01419 else if (FMT_IA44 == frame->codec)
01420 {
01421 memset(frame->buf, 0, video_dim.width() * video_dim.height());
01422 yuv888_to_i44(frame->buf, osd_image, video_dim,
01423 left, top, right, bottom, false);
01424 }
01425 else
01426 {
01427 LOG(VB_GENERAL, LOG_ERR, LOC +
01428 "Display OSD: Frame format not supported.");
01429 }
01430 }
01431 return show;
01432 }
01433
01434 bool VideoOutput::EnableVisualisation(AudioPlayer *audio, bool enable,
01435 const QString &name)
01436 {
01437 if (!enable)
01438 {
01439 DestroyVisualisation();
01440 return false;
01441 }
01442 return SetupVisualisation(audio, NULL, name);
01443 }
01444
01445 bool VideoOutput::CanVisualise(AudioPlayer *audio, MythRender *render)
01446 {
01447 return VideoVisual::CanVisualise(audio, render);
01448 }
01449
01450 bool VideoOutput::SetupVisualisation(AudioPlayer *audio, MythRender *render,
01451 const QString &name)
01452 {
01453 DestroyVisualisation();
01454 m_visual = VideoVisual::Create(name, audio, render);
01455 return m_visual;
01456 }
01457
01458 QString VideoOutput::GetVisualiserName(void)
01459 {
01460 if (m_visual)
01461 return m_visual->Name();
01462 return QString("");
01463 }
01464
01465 QStringList VideoOutput::GetVisualiserList(void)
01466 {
01467 return QStringList();
01468 }
01469
01470 void VideoOutput::DestroyVisualisation(void)
01471 {
01472 delete m_visual;
01473 m_visual = NULL;
01474 }
01475
01484 void VideoOutput::CopyFrame(VideoFrame *to, const VideoFrame *from)
01485 {
01486 if (to == NULL || from == NULL)
01487 return;
01488
01489 to->frameNumber = from->frameNumber;
01490 to->disp_timecode = from->disp_timecode;
01491
01492
01493 if (from->size == to->size)
01494 memcpy(to->buf, from->buf, from->size);
01495 else if ((to->pitches[0] == from->pitches[0]) &&
01496 (to->pitches[1] == from->pitches[1]) &&
01497 (to->pitches[2] == from->pitches[2]))
01498 {
01499 memcpy(to->buf + to->offsets[0], from->buf + from->offsets[0],
01500 from->pitches[0] * from->height);
01501 memcpy(to->buf + to->offsets[1], from->buf + from->offsets[1],
01502 from->pitches[1] * (from->height>>1));
01503 memcpy(to->buf + to->offsets[2], from->buf + from->offsets[2],
01504 from->pitches[2] * (from->height>>1));
01505 }
01506 else
01507 {
01508 uint f[3] = { from->height, from->height>>1, from->height>>1, };
01509 uint t[3] = { to->height, to->height>>1, to->height>>1, };
01510 uint h[3] = { min(f[0],t[0]), min(f[1],t[1]), min(f[2],t[2]), };
01511 for (uint i = 0; i < 3; i++)
01512 {
01513 for (uint j = 0; j < h[i]; j++)
01514 {
01515 memcpy(to->buf + to->offsets[i] + (j * to->pitches[i]),
01516 from->buf + from->offsets[i] + (j * from->pitches[i]),
01517 min(from->pitches[i], to->pitches[i]));
01518 }
01519 }
01520 }
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539 }
01540
01541 QRect VideoOutput::GetImageRect(const QRect &rect, QRect *display)
01542 {
01543 float hscale, vscale, tmp;
01544 tmp = 0.0;
01545 QRect visible_osd = GetVisibleOSDBounds(tmp, tmp, tmp);
01546 QSize video_size = window.GetVideoDispDim();
01547 int image_height = video_size.height();
01548 int image_width = (image_height > 720) ? 1920 :
01549 (image_height > 576) ? 1280 : 720;
01550 float image_aspect = (float)image_width / (float)image_height;
01551 float pixel_aspect = (float)video_size.width() /
01552 (float)video_size.height();
01553
01554 QRect rect1 = rect;
01555 if (display && display->isValid())
01556 {
01557 QMatrix m0;
01558 m0.scale((float)image_width / (float)display->width(),
01559 (float)image_height / (float)display->height());
01560 rect1 = m0.mapRect(rect1);
01561 rect1.translate(display->left(), display->top());
01562 }
01563 QRect result = rect1;
01564
01565 if (hasFullScreenOSD())
01566 {
01567 QRect dvr_rec = window.GetDisplayVideoRect();
01568 QRect vid_rec = window.GetVideoRect();
01569
01570 hscale = image_aspect / pixel_aspect;
01571 if (hscale < 0.99f || hscale > 1.01f)
01572 {
01573 vid_rec.setLeft((int)(((float)vid_rec.left() * hscale) + 0.5f));
01574 vid_rec.setWidth((int)(((float)vid_rec.width() * hscale) + 0.5f));
01575 }
01576
01577 vscale = (float)dvr_rec.width() / (float)image_width;
01578 hscale = (float)dvr_rec.height() / (float)image_height;
01579 QMatrix m1;
01580 m1.translate(dvr_rec.left(), dvr_rec.top());
01581 m1.scale(vscale, hscale);
01582
01583 vscale = (float)image_width / (float)vid_rec.width();
01584 hscale = (float)image_height / (float)vid_rec.height();
01585 QMatrix m2;
01586 m2.scale(vscale, hscale);
01587 m2.translate(-vid_rec.left(), -vid_rec.top());
01588
01589 result = m2.mapRect(result);
01590 result = m1.mapRect(result);
01591 return result;
01592 }
01593
01594 hscale = pixel_aspect / image_aspect;
01595 if (hscale < 0.99f || hscale > 1.01f)
01596 {
01597 result.setLeft((int)(((float)rect1.left() * hscale) + 0.5f));
01598 result.setWidth((int)(((float)rect1.width() * hscale) + 0.5f));
01599 }
01600
01601 result.translate(-visible_osd.left(), -visible_osd.top());
01602 return result;
01603 }
01604
01611 QRect VideoOutput::GetSafeRect(void)
01612 {
01613 static const float safeMargin = 0.05f;
01614 float dummy;
01615 QRect result = GetVisibleOSDBounds(dummy, dummy, 1.0f);
01616 int safex = (int)((float)result.width() * safeMargin);
01617 int safey = (int)((float)result.height() * safeMargin);
01618 return QRect(result.left() + safex, result.top() + safey,
01619 result.width() - (2 * safex), result.height() - (2 * safey));
01620 }
01621
01622 void VideoOutput::SetPIPState(PIPState setting)
01623 {
01624 window.SetPIPState(setting);
01625 }
01626
01627
01628 static QString to_comma_list(const QStringList &list)
01629 {
01630 QString ret = "";
01631 for (QStringList::const_iterator it = list.begin(); it != list.end(); ++it)
01632 ret += *it + ",";
01633
01634 if (ret.length())
01635 return ret.left(ret.length()-1);
01636
01637 return "";
01638 }
01639
01640 bool VideoOutput::IsEmbedding(void)
01641 {
01642 return window.IsEmbedding();
01643 }
01644
01645 void VideoOutput::ExposeEvent(void)
01646 {
01647 window.SetNeedRepaint(true);
01648 }
01649
01655 void VideoOutput::ResizeForGui(void)
01656 {
01657 if (display_res)
01658 display_res->SwitchToGUI();
01659 }
01660
01672 void VideoOutput::ResizeForVideo(uint width, uint height)
01673 {
01674 if (!display_res)
01675 return;
01676
01677 if (!width || !height)
01678 {
01679 width = window.GetVideoDispDim().width();
01680 height = window.GetVideoDispDim().height();
01681 if (!width || !height)
01682 return;
01683 }
01684
01685 if ((width == 1920 || width == 1440) && height == 1088)
01686 height = 1080;
01687
01688 float rate = db_vdisp_profile ? db_vdisp_profile->GetOutput() : 0.0f;
01689 if (display_res && display_res->SwitchToVideo(width, height, rate))
01690 {
01691
01692
01693 window.SetDisplayDim(QSize(display_res->GetPhysicalWidth(),
01694 display_res->GetPhysicalHeight()));
01695 window.SetDisplayAspect(display_res->GetAspectRatio());
01696
01697 bool fullscreen = !window.UsingGuiSize();
01698
01699
01700 if (!fullscreen)
01701 {
01702 int gui_width = 0, gui_height = 0;
01703 gCoreContext->GetResolutionSetting("Gui", gui_width, gui_height);
01704 fullscreen |= (0 == gui_width && 0 == gui_height);
01705 }
01706
01707 if (fullscreen)
01708 {
01709 QSize sz(display_res->GetWidth(), display_res->GetHeight());
01710 const QRect display_visible_rect =
01711 QRect(GetMythMainWindow()->geometry().topLeft(), sz);
01712 window.SetDisplayVisibleRect(display_visible_rect);
01713 MoveResize();
01714
01715 MoveResizeWindow(display_visible_rect);
01716 }
01717 }
01718 }
01719
01724 void VideoOutput::InitDisplayMeasurements(uint width, uint height, bool resize)
01725 {
01726 DisplayInfo disp = MythDisplay::GetDisplayInfo();
01727 QString source = "Actual";
01728
01729
01730
01731
01732 QSize sz1 = disp.res;
01733 QSize sz2 = window.GetScreenGeometry().size();
01734 QSize max_size = sz1.expandedTo(sz2);
01735
01736 if (window.UsingGuiSize())
01737 max_size = GetMythMainWindow()->geometry().size();
01738
01739 if (display_res)
01740 {
01741 max_size.setWidth(display_res->GetMaxWidth());
01742 max_size.setHeight(display_res->GetMaxHeight());
01743 }
01744
01745 if (resize)
01746 {
01747 MoveResizeWindow(QRect(GetMythMainWindow()->geometry().x(),
01748 GetMythMainWindow()->geometry().y(),
01749 max_size.width(), max_size.height()));
01750 }
01751
01752
01753
01754 if (db_display_dim.isEmpty())
01755 {
01756 window.SetDisplayDim(disp.size);
01757 }
01758 else
01759 {
01760 window.SetDisplayDim(db_display_dim);
01761 source = "Database";
01762 }
01763
01764
01765 if (display_res)
01766 ResizeForVideo(width, height);
01767
01768
01769 QSize screen_size = window.GetScreenGeometry().size();
01770 QSize window_size = window.GetDisplayVisibleRect().size();
01771
01772 float pixel_aspect = (float)screen_size.width() /
01773 (float)screen_size.height();
01774
01775 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01776 QString("Pixel dimensions: Screen %1x%2, window %3x%4")
01777 .arg(screen_size.width()).arg(screen_size.height())
01778 .arg(window_size.width()).arg(window_size.height()));
01779
01780
01781 QSize disp_dim = window.GetDisplayDim();
01782 float disp_aspect;
01783
01784
01785
01786
01787
01788 if (window.UsingXinerama())
01789 {
01790 source = "Xinerama";
01791 disp_aspect = gCoreContext->GetFloatSettingOnHost(
01792 "XineramaMonitorAspectRatio",
01793 gCoreContext->GetHostName(), pixel_aspect);
01794 if (disp_dim.height() <= 0)
01795 disp_dim.setHeight(300);
01796 disp_dim.setWidth((int) ((disp_dim.height() * disp_aspect) + 0.5));
01797 }
01798
01799 if (disp_dim.isEmpty())
01800 {
01801 source = "Guessed!";
01802 LOG(VB_GENERAL, LOG_WARNING, LOC + "Physical size of display unknown."
01803 "\n\t\t\tAssuming 17\" monitor with square pixels.");
01804 disp_dim = QSize((int) ((300 * pixel_aspect) + 0.5), 300);
01805 }
01806
01807 disp_aspect = (float) disp_dim.width() / (float) disp_dim.height();
01808 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01809 QString("%1 display dimensions: %2x%3 mm Aspect: %4")
01810 .arg(source).arg(disp_dim.width()).arg(disp_dim.height())
01811 .arg(disp_aspect));
01812
01813
01814 monitor_sz = screen_size;
01815 monitor_dim = disp_dim;
01816
01817
01818
01819 disp_dim = QSize((disp_dim.width() * window_size.width()) /
01820 screen_size.width(),
01821 (disp_dim.height() * window_size.height()) /
01822 screen_size.height());
01823 disp_aspect = (float) disp_dim.width() / (float) disp_dim.height();
01824 window.SetDisplayDim(disp_dim);
01825 window.SetDisplayAspect(disp_aspect);
01826
01827
01828 if (display_res)
01829 window.SetDisplayAspect(display_res->GetAspectRatio());
01830
01831 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01832 QString("Estimated window dimensions: %1x%2 mm Aspect: %3")
01833 .arg(window.GetDisplayDim().width())
01834 .arg(window.GetDisplayDim().height())
01835 .arg(window.GetDisplayAspect()));
01836 }
01837
01838 int VideoOutput::CalcHueBase(const QString &adaptor_name)
01839 {
01840 int hue_adj = 50;
01841
01842
01843 if ((adaptor_name == "ATI Radeon Video Overlay") ||
01844 (adaptor_name == "XA G3D Textured Video") ||
01845 (adaptor_name == "Radeon Textured Video") ||
01846 (adaptor_name == "AMD Radeon AVIVO Video") ||
01847 (adaptor_name == "XV_SWOV" ) ||
01848 (adaptor_name == "Savage Streams Engine" ) ||
01849 (adaptor_name == "SIS 300/315/330 series Video Overlay") ||
01850 adaptor_name.toLower().contains("xvba"))
01851 {
01852 hue_adj = 50;
01853 }
01854 else if (adaptor_name.left(4) == "NV17")
01855 {
01856 hue_adj = 0;
01857 }
01858 else
01859 {
01860 LOG(VB_GENERAL, LOG_INFO, LOC +
01861 QString("CalcHueBase(%1): Unknown adaptor, hue may be wrong.")
01862 .arg(adaptor_name));
01863 LOG(VB_GENERAL, LOG_INFO, LOC +
01864 "Please open a ticket if you need to adjust the hue.");
01865 }
01866
01867 return hue_adj;
01868 }