MythTV  0.26-pre
videoout_opengl.cpp
Go to the documentation of this file.
00001 #include "mythcontext.h"
00002 #include "mythmainwindow.h"
00003 #include "mythplayer.h"
00004 #include "videooutbase.h"
00005 #include "videoout_opengl.h"
00006 #include "videodisplayprofile.h"
00007 #include "filtermanager.h"
00008 #include "osd.h"
00009 #include "mythuihelper.h"
00010 
00011 #define LOC      QString("VidOutGL: ")
00012 
00013 void VideoOutputOpenGL::GetRenderOptions(render_opts &opts,
00014                                          QStringList &cpudeints)
00015 {
00016     // full featured profile
00017     opts.renderers->append("opengl");
00018     opts.deints->insert("opengl", cpudeints);
00019     (*opts.deints)["opengl"].append("opengllinearblend");
00020     (*opts.deints)["opengl"].append("openglonefield");
00021     (*opts.deints)["opengl"].append("openglkerneldeint");
00022     (*opts.deints)["opengl"].append("bobdeint");
00023     (*opts.deints)["opengl"].append("openglbobdeint");
00024     (*opts.deints)["opengl"].append("opengldoubleratelinearblend");
00025     (*opts.deints)["opengl"].append("opengldoubleratekerneldeint");
00026     (*opts.deints)["opengl"].append("opengldoubleratefieldorder");
00027     (*opts.osds)["opengl"].append("opengl2");
00028     (*opts.safe_renderers)["dummy"].append("opengl");
00029     (*opts.safe_renderers)["nuppel"].append("opengl");
00030     if (opts.decoders->contains("ffmpeg"))
00031         (*opts.safe_renderers)["ffmpeg"].append("opengl");
00032     if (opts.decoders->contains("vda"))
00033         (*opts.safe_renderers)["vda"].append("opengl");
00034     if (opts.decoders->contains("crystalhd"))
00035         (*opts.safe_renderers)["crystalhd"].append("opengl");
00036     opts.priorities->insert("opengl", 65);
00037 
00038     // lite profile - no colourspace control, GPU deinterlacing
00039     opts.renderers->append("opengl-lite");
00040     opts.deints->insert("opengl-lite", cpudeints);
00041     (*opts.deints)["opengl-lite"].append("bobdeint");
00042     (*opts.osds)["opengl-lite"].append("opengl2");
00043     (*opts.safe_renderers)["dummy"].append("opengl-lite");
00044     (*opts.safe_renderers)["nuppel"].append("opengl-lite");
00045     if (opts.decoders->contains("ffmpeg"))
00046         (*opts.safe_renderers)["ffmpeg"].append("opengl-lite");
00047     if (opts.decoders->contains("vda"))
00048         (*opts.safe_renderers)["vda"].append("opengl-lite");
00049     if (opts.decoders->contains("crystalhd"))
00050         (*opts.safe_renderers)["crystalhd"].append("opengl-lite");
00051     opts.priorities->insert("opengl", 60);
00052 }
00053 
00054 VideoOutputOpenGL::VideoOutputOpenGL(const QString &profile)
00055     : VideoOutput(),
00056     gl_context_lock(QMutex::Recursive), gl_context(NULL), gl_valid(true),
00057     gl_videochain(NULL), gl_pipchain_active(NULL),
00058     gl_parent_win(0),    gl_painter(NULL), gl_created_painter(false),
00059     gl_opengl_lite(false)
00060 {
00061     if (profile.contains("lite"))
00062         gl_opengl_lite = true;
00063 
00064     memset(&av_pause_frame, 0, sizeof(av_pause_frame));
00065     av_pause_frame.buf = NULL;
00066 
00067     if (gCoreContext->GetNumSetting("UseVideoModes", 0))
00068         display_res = DisplayRes::GetDisplayRes(true);
00069 }
00070 
00071 VideoOutputOpenGL::~VideoOutputOpenGL()
00072 {
00073     gl_context_lock.lock();
00074     TearDown();
00075 
00076     if (gl_context)
00077         gl_context->DownRef();
00078     gl_context = NULL;
00079     gl_context_lock.unlock();
00080 }
00081 
00082 void VideoOutputOpenGL::TearDown(void)
00083 {
00084     gl_context_lock.lock();
00085     DestroyCPUResources();
00086     DestroyVideoResources();
00087     DestroyGPUResources();
00088     gl_context_lock.unlock();
00089 }
00090 
00091 bool VideoOutputOpenGL::CreateCPUResources(void)
00092 {
00093     bool result = CreateBuffers();
00094     result &= CreatePauseFrame();
00095     return result;
00096 }
00097 
00098 bool VideoOutputOpenGL::CreateGPUResources(void)
00099 {
00100     bool result = SetupContext();
00101     QSize size = window.GetActualVideoDim();
00102     InitDisplayMeasurements(size.width(), size.height(), false);
00103     InitOSD();
00104     return result;
00105 }
00106 
00107 bool VideoOutputOpenGL::CreateVideoResources(void)
00108 {
00109     bool result = SetupOpenGL();
00110     MoveResize();
00111     return result;
00112 }
00113 
00114 void VideoOutputOpenGL::DestroyCPUResources(void)
00115 {
00116     gl_context_lock.lock();
00117     DiscardFrames(true);
00118     vbuffers.DeleteBuffers();
00119     vbuffers.Reset();
00120 
00121     if (av_pause_frame.buf)
00122     {
00123         delete [] av_pause_frame.buf;
00124         av_pause_frame.buf = NULL;
00125     }
00126     if (av_pause_frame.qscale_table)
00127     {
00128         delete [] av_pause_frame.qscale_table;
00129         av_pause_frame.qscale_table = NULL;
00130     }
00131     gl_context_lock.unlock();
00132 }
00133 
00134 void VideoOutputOpenGL::DestroyGPUResources(void)
00135 {
00136     gl_context_lock.lock();
00137     if (gl_context)
00138         gl_context->makeCurrent();
00139 
00140     if (gl_created_painter)
00141         delete gl_painter;
00142     else if (gl_painter)
00143         gl_painter->SetSwapControl(true);
00144 
00145     gl_painter = NULL;
00146     gl_created_painter = false;
00147 
00148     if (gl_context)
00149         gl_context->doneCurrent();
00150     gl_context_lock.unlock();
00151 }
00152 
00153 void VideoOutputOpenGL::DestroyVideoResources(void)
00154 {
00155     gl_context_lock.lock();
00156     if (gl_context)
00157         gl_context->makeCurrent();
00158 
00159     if (gl_videochain)
00160     {
00161         delete gl_videochain;
00162         gl_videochain = NULL;
00163     }
00164 
00165     while (!gl_pipchains.empty())
00166     {
00167         delete *gl_pipchains.begin();
00168         gl_pipchains.erase(gl_pipchains.begin());
00169     }
00170     gl_pip_ready.clear();
00171 
00172     if (gl_context)
00173         gl_context->doneCurrent();
00174     gl_context_lock.unlock();
00175 }
00176 
00177 bool VideoOutputOpenGL::Init(int width, int height, float aspect, WId winid,
00178                              const QRect &win_rect, MythCodecID codec_id)
00179 {
00180     QMutexLocker locker(&gl_context_lock);
00181     bool success = true;
00182     window.SetAllowPreviewEPG(true);
00183     gl_parent_win = winid;
00184     success &= VideoOutput::Init(width, height, aspect, winid,
00185                                  win_rect, codec_id);
00186     SetProfile();
00187     InitPictureAttributes();
00188 
00189     success &= CreateCPUResources();
00190 
00191     if (!gCoreContext->IsUIThread())
00192     {
00193         LOG(VB_GENERAL, LOG_NOTICE, LOC +
00194             "Deferring creation of OpenGL resources");
00195         gl_valid = false;
00196     }
00197     else
00198     {
00199         success &= CreateGPUResources();
00200         success &= CreateVideoResources();
00201     }
00202 
00203     if (!success)
00204         TearDown();
00205     return success;
00206 }
00207 
00208 void VideoOutputOpenGL::SetProfile(void)
00209 {
00210     if (db_vdisp_profile)
00211     {
00212         db_vdisp_profile->SetVideoRenderer(
00213                     gl_opengl_lite ? "opengl-lite" : "opengl");
00214     }
00215 }
00216 
00217 bool VideoOutputOpenGL::InputChanged(const QSize &input_size,
00218                                      float        aspect,
00219                                      MythCodecID  av_codec_id,
00220                                      void        *codec_private,
00221                                      bool        &aspect_only)
00222 {
00223     LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("InputChanged(%1,%2,%3) %4->%5")
00224             .arg(input_size.width()).arg(input_size.height()).arg(aspect)
00225             .arg(toString(video_codec_id)).arg(toString(av_codec_id)));
00226 
00227     QMutexLocker locker(&gl_context_lock);
00228 
00229     // Ensure we don't lose embedding through program changes. This duplicates
00230     // code in VideoOutput::Init but we need start here otherwise the embedding
00231     // is lost during window re-initialistion.
00232     bool wasembedding = window.IsEmbedding();
00233     QRect oldrect;
00234     if (wasembedding)
00235     {
00236         oldrect = window.GetEmbeddingRect();
00237         StopEmbedding();
00238     }
00239 
00240     if (!codec_is_std(av_codec_id))
00241     {
00242         LOG(VB_GENERAL, LOG_ERR, LOC + "New video codec is not supported.");
00243         errorState = kError_Unknown;
00244         return false;
00245     }
00246 
00247     bool cid_changed = (video_codec_id != av_codec_id);
00248     bool res_changed = input_size  != window.GetActualVideoDim();
00249     bool asp_changed = aspect      != window.GetVideoAspect();
00250 
00251     if (!res_changed && !cid_changed)
00252     {
00253         if (asp_changed)
00254         {
00255             aspect_only = true;
00256             VideoAspectRatioChanged(aspect);
00257             MoveResize();
00258         }
00259         if (wasembedding)
00260             EmbedInWidget(oldrect);
00261         return true;
00262     }
00263 
00264     if (gCoreContext->IsUIThread())
00265         TearDown();
00266     else
00267         DestroyCPUResources();
00268 
00269     QRect disp = window.GetDisplayVisibleRect();
00270     if (Init(input_size.width(), input_size.height(),
00271              aspect, gl_parent_win, disp, av_codec_id))
00272     {
00273         if (wasembedding)
00274             EmbedInWidget(oldrect);
00275         if (gCoreContext->IsUIThread())
00276             BestDeint();
00277         return true;
00278     }
00279 
00280     LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to re-initialise video output.");
00281     errorState = kError_Unknown;
00282 
00283     return false;
00284 }
00285 
00286 bool VideoOutputOpenGL::SetupContext(void)
00287 {
00288     QMutexLocker locker(&gl_context_lock);
00289 
00290     if (gl_context)
00291     {
00292         LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Re-using context"));
00293         return true;
00294     }
00295 
00296     MythMainWindow* win = MythMainWindow::getMainWindow();
00297     if (!win)
00298     {
00299         LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get MythMainWindow");
00300         return false;
00301     }
00302 
00303     gl_context = dynamic_cast<MythRenderOpenGL*>(win->GetRenderDevice());
00304     if (gl_context)
00305     {
00306         gl_context->UpRef();
00307         LOG(VB_PLAYBACK, LOG_INFO, LOC + "Using main UI render context");
00308         return true;
00309     }
00310 
00311     QGLWidget *device = (QGLWidget*)QWidget::find(gl_parent_win);
00312     if (!device)
00313     {
00314         LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to cast parent to QGLWidget");
00315         return false;
00316     }
00317 
00318     gl_context = MythRenderOpenGL::Create("", device);
00319     if (gl_context && gl_context->create())
00320     {
00321         gl_context->Init();
00322         LOG(VB_GENERAL, LOG_INFO, LOC + "Created MythRenderOpenGL device.");
00323         return true;
00324     }
00325 
00326     LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create MythRenderOpenGL device.");
00327     if (gl_context)
00328         gl_context->DownRef();
00329     gl_context = NULL;
00330     return false;
00331 }
00332 
00333 bool VideoOutputOpenGL::SetupOpenGL(void)
00334 {
00335     if (!gl_context)
00336         return false;
00337 
00338     const QRect dvr = window.GetDisplayVisibleRect();
00339 
00340     if (video_codec_id == kCodec_NONE)
00341     {
00342         gl_context->SetViewPort(QRect(QPoint(),dvr.size()));
00343         return true;
00344     }
00345 
00346     if (window.GetPIPState() >= kPIPStandAlone)
00347     {
00348         QRect tmprect = QRect(QPoint(0,0), dvr.size());
00349         ResizeDisplayWindow(tmprect, true);
00350     }
00351     bool success = false;
00352     OpenGLLocker ctx_lock(gl_context);
00353     gl_videochain = new OpenGLVideo();
00354     QString options = GetFilters();
00355     if (gl_opengl_lite)
00356         options += " preferycbcr";
00357     success = gl_videochain->Init(gl_context, &videoColourSpace,
00358                                   window.GetVideoDim(),
00359                                   window.GetVideoDispDim(), dvr,
00360                                   window.GetDisplayVideoRect(),
00361                                   window.GetVideoRect(), true,
00362                                   options, !codec_is_std(video_codec_id));
00363     if (success)
00364     {
00365         bool temp_deinterlacing = m_deinterlacing;
00366         if (!m_deintfiltername.isEmpty() &&
00367             !m_deintfiltername.contains("opengl"))
00368         {
00369             gl_videochain->SetSoftwareDeinterlacer(m_deintfiltername);
00370         }
00371         SetDeinterlacingEnabled(true);
00372         if (!temp_deinterlacing)
00373         {
00374             SetDeinterlacingEnabled(false);
00375         }
00376     }
00377 
00378     return success;
00379 }
00380 
00381 void VideoOutputOpenGL::InitOSD(void)
00382 {
00383     QMutexLocker locker(&gl_context_lock);
00384 
00385     gl_created_painter = false;
00386     MythMainWindow *win = MythMainWindow::getMainWindow();
00387     if (gl_context && !gl_context->IsShared())
00388     {
00389         QGLWidget *device = (QGLWidget*)QWidget::find(gl_parent_win);
00390         gl_painter = new MythOpenGLPainter(gl_context, device);
00391         if (!gl_painter)
00392         {
00393             LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create painter");
00394             return;
00395         }
00396         gl_created_painter = true;
00397     }
00398     else
00399     {
00400         gl_painter = (MythOpenGLPainter*)win->GetCurrentPainter();
00401         if (!gl_painter)
00402         {
00403             LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get painter");
00404             return;
00405         }
00406         LOG(VB_PLAYBACK, LOG_INFO, LOC + "Using main UI painter");
00407     }
00408     gl_painter->SetSwapControl(false);
00409 }
00410 
00411 bool VideoOutputOpenGL::CreateBuffers(void)
00412 {
00413     QMutexLocker locker(&gl_context_lock);
00414     vbuffers.Init(31, true, 1, 12, 4, 2);
00415     return vbuffers.CreateBuffers(FMT_YV12,
00416                                   window.GetVideoDim().width(),
00417                                   window.GetVideoDim().height());
00418 }
00419 
00420 bool VideoOutputOpenGL::CreatePauseFrame(void)
00421 {
00422     init(&av_pause_frame, FMT_YV12,
00423          new unsigned char[vbuffers.GetScratchFrame()->size + 128],
00424          vbuffers.GetScratchFrame()->width,
00425          vbuffers.GetScratchFrame()->height,
00426          vbuffers.GetScratchFrame()->size);
00427 
00428     av_pause_frame.frameNumber = vbuffers.GetScratchFrame()->frameNumber;
00429 
00430     if (!av_pause_frame.buf)
00431         return false;
00432 
00433     clear(&av_pause_frame);
00434     return true;
00435 }
00436 
00437 void VideoOutputOpenGL::ProcessFrame(VideoFrame *frame, OSD *osd,
00438                                      FilterChain *filterList,
00439                                      const PIPMap &pipPlayers,
00440                                      FrameScanType scan)
00441 {
00442     QMutexLocker locker(&gl_context_lock);
00443 
00444     if (!gl_context)
00445         return;
00446 
00447     if (!gl_valid)
00448     {
00449         if (!gCoreContext->IsUIThread())
00450         {
00451             LOG(VB_GENERAL, LOG_ERR, LOC +
00452                 "ProcessFrame called from wrong thread");
00453         }
00454         QSize size = window.GetActualVideoDim();
00455         InitDisplayMeasurements(size.width(), size.height(), false);
00456         DestroyVideoResources();
00457         CreateVideoResources();
00458         BestDeint();
00459         gl_valid = true;
00460     }
00461 
00462     bool sw_frame = codec_is_std(video_codec_id) &&
00463                     video_codec_id != kCodec_NONE;
00464     bool deint_proc = m_deinterlacing && (m_deintFilter != NULL);
00465     OpenGLLocker ctx_lock(gl_context);
00466 
00467     bool pauseframe = false;
00468     if (!frame)
00469     {
00470         frame = vbuffers.GetScratchFrame();
00471         CopyFrame(vbuffers.GetScratchFrame(), &av_pause_frame);
00472         pauseframe = true;
00473     }
00474 
00475     bool dummy = frame->dummy;
00476     if (filterList && sw_frame && !dummy)
00477         filterList->ProcessFrame(frame);
00478 
00479     bool safepauseframe = pauseframe && !IsBobDeint();
00480     if (sw_frame && deint_proc && m_deinterlaceBeforeOSD &&
00481        (!pauseframe || safepauseframe) && !dummy)
00482     {
00483         m_deintFilter->ProcessFrame(frame, scan);
00484     }
00485 
00486     if (!window.IsEmbedding())
00487     {
00488         gl_pipchain_active = NULL;
00489         ShowPIPs(frame, pipPlayers);
00490     }
00491 
00492     if (sw_frame && (!pauseframe || safepauseframe) &&
00493         deint_proc && !m_deinterlaceBeforeOSD && !dummy)
00494     {
00495         m_deintFilter->ProcessFrame(frame, scan);
00496     }
00497 
00498     if (gl_videochain && sw_frame && !dummy)
00499     {
00500         bool soft_bob = m_deinterlacing && (m_deintfiltername == "bobdeint");
00501         gl_videochain->UpdateInputFrame(frame, soft_bob);
00502     }
00503 }
00504 
00505 void VideoOutputOpenGL::PrepareFrame(VideoFrame *buffer, FrameScanType t,
00506                                      OSD *osd)
00507 {
00508     if (!gl_context)
00509         return;
00510 
00511     OpenGLLocker ctx_lock(gl_context);
00512 
00513     if (!buffer)
00514     {
00515         buffer = vbuffers.GetScratchFrame();
00516         if (m_deinterlacing && !IsBobDeint())
00517             t = kScan_Interlaced;
00518     }
00519 
00520     gl_context_lock.lock();
00521     framesPlayed = buffer->frameNumber + 1;
00522     gl_context_lock.unlock();
00523 
00524     gl_context->BindFramebuffer(0);
00525     if (db_letterbox_colour == kLetterBoxColour_Gray25)
00526         gl_context->SetBackground(127, 127, 127, 255);
00527     else
00528         gl_context->SetBackground(0, 0, 0, 255);
00529     gl_context->ClearFramebuffer();
00530 
00531     // stereoscopic views
00532     QRect main   = gl_context->GetViewPort();
00533     QRect first  = main;
00534     QRect second = main;
00535     bool twopass = (m_stereo == kStereoscopicModeSideBySide) ||
00536                    (m_stereo == kStereoscopicModeTopAndBottom);
00537 
00538     if (kStereoscopicModeSideBySide == m_stereo)
00539     {
00540         first  = QRect(main.left() / 2,  main.top(),
00541                        main.width() / 2, main.height());
00542         second = first.translated(main.width() / 2, 0);
00543     }
00544     else if (kStereoscopicModeTopAndBottom == m_stereo)
00545     {
00546         first  = QRect(main.left(),  main.top() / 2,
00547                        main.width(), main.height() / 2);
00548         second = first.translated(0, main.height() / 2);
00549     }
00550 
00551     // main UI when embedded
00552     MythMainWindow *mwnd = GetMythMainWindow();
00553     if (gl_context->IsShared() && mwnd && mwnd->GetPaintWindow() &&
00554         window.IsEmbedding())
00555     {
00556         if (twopass)
00557             gl_context->SetViewPort(first, true);
00558         mwnd->GetPaintWindow()->setMask(QRegion());
00559         mwnd->draw();
00560         if (twopass)
00561         {
00562             gl_context->SetViewPort(second, true);
00563             mwnd->GetPaintWindow()->setMask(QRegion());
00564             mwnd->draw();
00565             gl_context->SetViewPort(main, true);
00566         }
00567     }
00568 
00569     // video
00570     if (gl_videochain && !buffer->dummy)
00571     {
00572         gl_videochain->SetVideoRect(vsz_enabled ? vsz_desired_display_rect :
00573                                                   window.GetDisplayVideoRect(),
00574                                     window.GetVideoRect());
00575         gl_videochain->PrepareFrame(buffer->top_field_first, t,
00576                                     m_deinterlacing, framesPlayed, m_stereo);
00577     }
00578 
00579     // PiPs/PBPs
00580     if (gl_pipchains.size())
00581     {
00582         QMap<MythPlayer*,OpenGLVideo*>::iterator it = gl_pipchains.begin();
00583         for (; it != gl_pipchains.end(); ++it)
00584         {
00585             if (gl_pip_ready[it.key()])
00586             {
00587                 bool active = gl_pipchain_active == *it;
00588                 if (twopass)
00589                     gl_context->SetViewPort(first, true);
00590                 (*it)->PrepareFrame(buffer->top_field_first, t,
00591                                     m_deinterlacing, framesPlayed,
00592                                     kStereoscopicModeNone, active);
00593                 if (twopass)
00594                 {
00595                     gl_context->SetViewPort(second, true);
00596                     (*it)->PrepareFrame(buffer->top_field_first, t,
00597                                     m_deinterlacing, framesPlayed,
00598                                     kStereoscopicModeNone, active);
00599                     gl_context->SetViewPort(main);
00600                 }
00601             }
00602         }
00603     }
00604 
00605     // visualisation
00606     if (m_visual && gl_painter && !window.IsEmbedding())
00607     {
00608         if (twopass)
00609             gl_context->SetViewPort(first, true);
00610         m_visual->Draw(GetTotalOSDBounds(), gl_painter, NULL);
00611         if (twopass)
00612         {
00613             gl_context->SetViewPort(second, true);
00614             m_visual->Draw(GetTotalOSDBounds(), gl_painter, NULL);
00615             gl_context->SetViewPort(main);
00616         }
00617     }
00618 
00619     // OSD
00620     if (osd && gl_painter && !window.IsEmbedding())
00621     {
00622         if (twopass)
00623             gl_context->SetViewPort(first, true);
00624         osd->DrawDirect(gl_painter, GetTotalOSDBounds().size(), true);
00625         if (twopass)
00626         {
00627             gl_context->SetViewPort(second, true);
00628             osd->DrawDirect(gl_painter, GetTotalOSDBounds().size(), true);
00629             gl_context->SetViewPort(main);
00630         }
00631     }
00632 
00633     gl_context->Flush(false);
00634 
00635     if (vbuffers.GetScratchFrame() == buffer)
00636         vbuffers.SetLastShownFrameToScratch();
00637 }
00638 
00639 void VideoOutputOpenGL::Show(FrameScanType scan)
00640 {
00641     OpenGLLocker ctx_lock(gl_context);
00642     if (IsErrored())
00643     {
00644         LOG(VB_GENERAL, LOG_ERR, LOC + "IsErrored() is true in Show()");
00645         return;
00646     }
00647 
00648     if (gl_context)
00649         gl_context->swapBuffers();
00650 }
00651 
00652 QStringList VideoOutputOpenGL::GetAllowedRenderers(
00653     MythCodecID myth_codec_id, const QSize &video_dim)
00654 {
00655     (void) video_dim;
00656 
00657     QStringList list;
00658 
00659     if (codec_is_std(myth_codec_id) && !getenv("NO_OPENGL"))
00660     {
00661         list << "opengl" << "opengl-lite";
00662     }
00663 
00664     return list;
00665 }
00666 
00667 void VideoOutputOpenGL::Zoom(ZoomDirection direction)
00668 {
00669     QMutexLocker locker(&gl_context_lock);
00670     VideoOutput::Zoom(direction);
00671     MoveResize();
00672 }
00673 
00674 void VideoOutputOpenGL::MoveResize(void)
00675 {
00676     QMutexLocker locker(&gl_context_lock);
00677     VideoOutput::MoveResize();
00678     if (gl_videochain)
00679     {
00680         gl_videochain->SetVideoRect(vsz_enabled ? vsz_desired_display_rect :
00681                                                   window.GetDisplayVideoRect(),
00682                                     window.GetVideoRect());
00683     }
00684 }
00685 
00686 void VideoOutputOpenGL::UpdatePauseFrame(int64_t &disp_timecode)
00687 {
00688     QMutexLocker locker(&gl_context_lock);
00689     VideoFrame *used_frame = vbuffers.head(kVideoBuffer_used);
00690     if (!used_frame)
00691         used_frame = vbuffers.GetScratchFrame();
00692 
00693     CopyFrame(&av_pause_frame, used_frame);
00694     disp_timecode = av_pause_frame.disp_timecode;
00695 }
00696 
00697 void VideoOutputOpenGL::InitPictureAttributes(void)
00698 {
00699     if (video_codec_id == kCodec_NONE)
00700         return;
00701 
00702     videoColourSpace.SetSupportedAttributes((PictureAttributeSupported)
00703                                        (kPictureAttributeSupported_Brightness |
00704                                         kPictureAttributeSupported_Contrast |
00705                                         kPictureAttributeSupported_Colour |
00706                                         kPictureAttributeSupported_Hue |
00707                                         kPictureAttributeSupported_StudioLevels));
00708 }
00709 
00710 int VideoOutputOpenGL::SetPictureAttribute(PictureAttribute attribute,
00711                                            int newValue)
00712 {
00713     if (!gl_context)
00714         return -1;
00715 
00716     return VideoOutput::SetPictureAttribute(attribute, newValue);
00717 }
00718 
00719 bool VideoOutputOpenGL::SetupDeinterlace(
00720     bool interlaced, const QString &overridefilter)
00721 {
00722     if (!gl_videochain || !gl_context)
00723         return false;
00724 
00725     OpenGLLocker ctx_lock(gl_context);
00726 
00727     if (db_vdisp_profile)
00728         m_deintfiltername = db_vdisp_profile->GetFilteredDeint(overridefilter);
00729 
00730     if (!m_deintfiltername.contains("opengl"))
00731     {
00732         gl_videochain->SetDeinterlacing(false);
00733         gl_videochain->SetSoftwareDeinterlacer(QString::null);
00734         VideoOutput::SetupDeinterlace(interlaced, overridefilter);
00735         if (m_deinterlacing)
00736             gl_videochain->SetSoftwareDeinterlacer(m_deintfiltername);
00737 
00738         return m_deinterlacing;
00739     }
00740 
00741     // clear any non opengl filters
00742     if (m_deintFiltMan)
00743     {
00744         delete m_deintFiltMan;
00745         m_deintFiltMan = NULL;
00746     }
00747     if (m_deintFilter)
00748     {
00749         delete m_deintFilter;
00750         m_deintFilter = NULL;
00751     }
00752 
00753     MoveResize();
00754     m_deinterlacing = interlaced;
00755 
00756     if (m_deinterlacing && !m_deintfiltername.isEmpty())
00757     {
00758         if (gl_videochain->GetDeinterlacer() != m_deintfiltername)
00759         {
00760             if (!gl_videochain->AddDeinterlacer(m_deintfiltername))
00761             {
00762                 LOG(VB_GENERAL, LOG_ERR, LOC +
00763                     QString("Couldn't load deinterlace filter %1")
00764                         .arg(m_deintfiltername));
00765                 m_deinterlacing = false;
00766                 m_deintfiltername = "";
00767             }
00768             else
00769             {
00770                 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00771                     QString("Using deinterlace method %1")
00772                         .arg(m_deintfiltername));
00773             }
00774         }
00775     }
00776 
00777     gl_videochain->SetDeinterlacing(m_deinterlacing);
00778 
00779     return m_deinterlacing;
00780 }
00781 
00782 bool VideoOutputOpenGL::SetDeinterlacingEnabled(bool enable)
00783 {
00784     (void) enable;
00785 
00786     if (!gl_videochain || !gl_context)
00787         return false;
00788 
00789     OpenGLLocker ctx_lock(gl_context);
00790 
00791     if (enable)
00792     {
00793         if (m_deintfiltername.isEmpty())
00794             return SetupDeinterlace(enable);
00795         if (m_deintfiltername.contains("opengl"))
00796         {
00797             if (gl_videochain->GetDeinterlacer().isEmpty())
00798                 return SetupDeinterlace(enable);
00799         }
00800         else if (!m_deintfiltername.contains("opengl"))
00801         {
00802             // make sure opengl deinterlacing is disabled
00803             gl_videochain->SetDeinterlacing(false);
00804 
00805             if (!m_deintFiltMan || !m_deintFilter)
00806                 return VideoOutput::SetupDeinterlace(enable);
00807         }
00808     }
00809 
00810     MoveResize();
00811     gl_videochain->SetDeinterlacing(enable);
00812 
00813     m_deinterlacing = enable;
00814 
00815     return m_deinterlacing;
00816 }
00817 
00818 void VideoOutputOpenGL::ShowPIP(VideoFrame  *frame,
00819                                 MythPlayer  *pipplayer,
00820                                 PIPLocation  loc)
00821 {
00822     if (!pipplayer)
00823         return;
00824 
00825     int pipw, piph;
00826     VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
00827     const float pipVideoAspect = pipplayer->GetVideoAspect();
00828     const QSize pipVideoDim    = pipplayer->GetVideoBufferSize();
00829     const bool  pipActive      = pipplayer->IsPIPActive();
00830     const bool  pipVisible     = pipplayer->IsPIPVisible();
00831     const uint  pipVideoWidth  = pipVideoDim.width();
00832     const uint  pipVideoHeight = pipVideoDim.height();
00833 
00834     // If PiP is not initialized to values we like, silently ignore the frame.
00835     if ((pipVideoAspect <= 0) || !pipimage ||
00836         !pipimage->buf || pipimage->codec != FMT_YV12)
00837     {
00838         pipplayer->ReleaseCurrentFrame(pipimage);
00839         return;
00840     }
00841 
00842     if (!pipVisible)
00843     {
00844         pipplayer->ReleaseCurrentFrame(pipimage);
00845         return;
00846     }
00847 
00848     QRect position = GetPIPRect(loc, pipplayer);
00849     QRect dvr = window.GetDisplayVisibleRect();
00850 
00851     gl_pip_ready[pipplayer] = false;
00852     OpenGLVideo *gl_pipchain = gl_pipchains[pipplayer];
00853     if (!gl_pipchain)
00854     {
00855         LOG(VB_PLAYBACK, LOG_INFO, LOC + "Initialise PiP.");
00856         gl_pipchains[pipplayer] = gl_pipchain = new OpenGLVideo();
00857         QString options = GetFilters();
00858         if (gl_opengl_lite)
00859             options += " preferycbcr";
00860         bool success = gl_pipchain->Init(gl_context, &videoColourSpace,
00861                      pipVideoDim, pipVideoDim,
00862                      dvr, position,
00863                      QRect(0, 0, pipVideoWidth, pipVideoHeight),
00864                      false, options, false);
00865         QSize viewport = gl_videochain ? gl_videochain->GetViewPort() :
00866                                          window.GetDisplayVisibleRect().size();
00867         gl_pipchain->SetMasterViewport(viewport);
00868         if (!success)
00869         {
00870             pipplayer->ReleaseCurrentFrame(pipimage);
00871             return;
00872         }
00873     }
00874 
00875     QSize current = gl_pipchain->GetVideoSize();
00876     if ((uint)current.width()  != pipVideoWidth ||
00877         (uint)current.height() != pipVideoHeight)
00878     {
00879         LOG(VB_PLAYBACK, LOG_INFO, LOC + "Re-initialise PiP.");
00880         delete gl_pipchain;
00881         gl_pipchains[pipplayer] = gl_pipchain = new OpenGLVideo();
00882         QString options = GetFilters();
00883         if (gl_opengl_lite)
00884             options += " preferycbcr";
00885         bool success = gl_pipchain->Init(
00886             gl_context, &videoColourSpace,
00887             pipVideoDim, pipVideoDim, dvr, position,
00888             QRect(0, 0, pipVideoWidth, pipVideoHeight),
00889             false, options, false);
00890 
00891         QSize viewport = gl_videochain ? gl_videochain->GetViewPort() :
00892                                          window.GetDisplayVisibleRect().size();
00893         gl_pipchain->SetMasterViewport(viewport);
00894 
00895         if (!success)
00896         {
00897             pipplayer->ReleaseCurrentFrame(pipimage);
00898             return;
00899         }
00900 
00901     }
00902     gl_pipchain->SetVideoRect(position,
00903                               QRect(0, 0, pipVideoWidth, pipVideoHeight));
00904     gl_pipchain->UpdateInputFrame(pipimage);
00905 
00906     gl_pip_ready[pipplayer] = true;
00907 
00908     if (pipActive)
00909         gl_pipchain_active = gl_pipchain;
00910 
00911     pipplayer->ReleaseCurrentFrame(pipimage);
00912 }
00913 
00914 void VideoOutputOpenGL::RemovePIP(MythPlayer *pipplayer)
00915 {
00916     if (!gl_pipchains.contains(pipplayer))
00917         return;
00918 
00919     OpenGLLocker ctx_lock(gl_context);
00920 
00921     OpenGLVideo *gl_pipchain = gl_pipchains[pipplayer];
00922     if (gl_pipchain)
00923         delete gl_pipchain;
00924     gl_pip_ready.remove(pipplayer);
00925     gl_pipchains.remove(pipplayer);
00926 }
00927 
00928 void VideoOutputOpenGL::MoveResizeWindow(QRect new_rect)
00929 {
00930     if (gl_context)
00931         gl_context->MoveResizeWindow(new_rect);
00932 }
00933 
00934 void VideoOutputOpenGL::EmbedInWidget(const QRect &rect)
00935 {
00936     if (!window.IsEmbedding())
00937         VideoOutput::EmbedInWidget(rect);
00938 
00939     MoveResize();
00940 }
00941 
00942 void VideoOutputOpenGL::StopEmbedding(void)
00943 {
00944     if (!window.IsEmbedding())
00945         return;
00946 
00947     VideoOutput::StopEmbedding();
00948     MoveResize();
00949 }
00950 
00951 bool VideoOutputOpenGL::ApproveDeintFilter(const QString& filtername) const
00952 {
00953     if (filtername.contains("opengl") && !gl_opengl_lite)
00954         return true;
00955 
00956     if (filtername.contains("bobdeint"))
00957         return true;
00958 
00959     return VideoOutput::ApproveDeintFilter(filtername);
00960 }
00961 
00962 QStringList VideoOutputOpenGL::GetVisualiserList(void)
00963 {
00964     if (gl_context)
00965         return VideoVisual::GetVisualiserList(gl_context->Type());
00966     return VideoOutput::GetVisualiserList();
00967 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends