|
MythTV
0.26-pre
|
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 }
1.7.6.1