|
MythTV
0.26-pre
|
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 // select the best available output 00128 if (playerFlags & kVideoIsNull) 00129 { 00130 // plain null output 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 // ensure we have a window to display into 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 // determine the display rectangle 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 // DB Settings 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 // Video parameters 00387 video_codec_id(kCodec_NONE), db_vdisp_profile(NULL), 00388 00389 // Picture-in-Picture stuff 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 // Video resizing (for ITV) 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 // Deinterlacing 00402 m_deinterlacing(false), m_deintfiltername("linearblend"), 00403 m_deintFiltMan(NULL), m_deintFilter(NULL), 00404 m_deinterlaceBeforeOSD(true), 00405 00406 // Various state variables 00407 errorState(kError_None), framesPlayed(0), 00408 00409 // Custom display resolutions 00410 display_res(NULL), 00411 00412 // Physical display 00413 monitor_sz(640,480), monitor_dim(400,300), 00414 00415 // OSD 00416 osd_painter(NULL), osd_image(NULL), 00417 00418 // Visualisation 00419 m_visual(NULL), 00420 00421 // 3D TV 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); // apply aspect ratio and letterbox mode 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 // if enable and no deinterlacer allocated, attempt allocate one 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 // Bob deinterlace requires doubling framerate 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 // Default to not supporting bob deinterlace 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 // This rounding works for I420 video... 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 * \brief Determines PIP Window size and Position. 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 // const QRect display_video_rect = window.GetDisplayVideoRect(); 01055 // const QRect video_rect = window.GetVideoRect(); 01056 // const QRect display_visible_rect = window.GetDisplayVisibleRect(); 01057 // const QSize video_disp_dim = window.GetVideoDispDim(); 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 // const QSize pipVideoDim = pipplayer->GetVideoBufferSize(); 01065 01066 // If PiP is not initialized to values we like, silently ignore the frame. 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 // Scale the image if we have to... 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 }; //deep red YUV format 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 // we're done with the frame, release it 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 // if resize is outside existing frame, abort 01195 bool abort = 01196 (resize.right() > frame->width || resize.bottom() > frame->height || 01197 resize.width() > frame->width || resize.height() > frame->height); 01198 // if resize == existing frame, no need to carry on 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 // Copy Y (intensity values) 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 // Copy U & V (half plane chroma values) 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 // used by render devices to ignore frame rendering 01299 if (frame) 01300 frame->dummy = 1; 01301 // will only clear frame in main memory 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 // Clear the audio buffer 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 // guaranteed to be correct sizes. 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 /* XXX: Broken. 01523 if (from->qstride > 0 && from->qscale_table != NULL) 01524 { 01525 int tablesize = from->qstride * ((from->height + 15) / 16); 01526 01527 if (to->qstride != from->qstride || to->qscale_table == NULL) 01528 { 01529 to->qstride = from->qstride; 01530 if (to->qscale_table) 01531 delete [] to->qscale_table; 01532 01533 to->qscale_table = new unsigned char[tablesize]; 01534 } 01535 01536 memcpy(to->qscale_table, from->qscale_table, tablesize); 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; // ATSC 1920x1080 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 // Switching to custom display resolution succeeded 01692 // Make a note of the new size 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 // if width && height are zero users expect fullscreen playback 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 // Resize X window to fill new resolution 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 // The very first Resize needs to be the maximum possible 01730 // desired res, because X will mask off anything outside 01731 // the initial dimensions 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 // get the physical dimensions (in mm) of the display. If using 01753 // DisplayRes, this will be overridden when we call ResizeForVideo 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 // Set the display mode if required 01765 if (display_res) 01766 ResizeForVideo(width, height); 01767 01768 // Determine window and screen dimensions in pixels 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 // Check the display dimensions 01781 QSize disp_dim = window.GetDisplayDim(); 01782 float disp_aspect; 01783 01784 // If we are using Xinerama the display dimensions cannot be trusted. 01785 // We need to use the Xinerama monitor aspect ratio from the DB to set 01786 // the physical screen width. This assumes the height is correct, which 01787 // is more or less true in the typical side-by-side monitor setup. 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 // Save the unscaled size and dimensions for window resizing 01814 monitor_sz = screen_size; 01815 monitor_dim = disp_dim; 01816 01817 // We must now scale the display measurements to our window size and save 01818 // them. If we are running fullscreen this is a no-op. 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 // If we are using XRandR, use the aspect ratio from it 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 // XVideo adjustments 01843 if ((adaptor_name == "ATI Radeon Video Overlay") || 01844 (adaptor_name == "XA G3D Textured Video") || /* ATI in VMWare*/ 01845 (adaptor_name == "Radeon Textured Video") || /* ATI */ 01846 (adaptor_name == "AMD Radeon AVIVO Video") || /* ATI */ 01847 (adaptor_name == "XV_SWOV" /* VIA 10K & 12K */) || 01848 (adaptor_name == "Savage Streams Engine" /* S3 Prosavage DDR-K */) || 01849 (adaptor_name == "SIS 300/315/330 series Video Overlay") || 01850 adaptor_name.toLower().contains("xvba")) /* VAAPI */ 01851 { 01852 hue_adj = 50; 01853 } 01854 else if (adaptor_name.left(4) == "NV17") /* nVidia */ 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 }
1.7.6.1