MythTV  0.26-pre
videooutbase.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends