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
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
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
00230
00231
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
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
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
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
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
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
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
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
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
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 }