bool VideoOutputVDPAU::Init(int width, int height, float aspect, WId winid, const QRect &win_rect, MythCodecID codec_id) { // Attempt to free up as much video memory as possible // only works when using the VDPAU painter for the UI MythPainter *painter = GetMythPainter(); if (painter) painter->FreeResources(); m_win = winid; QMutexLocker locker(&m_lock); window.SetNeedRepaint(true); bool ok = VideoOutput::Init(width, height, aspect, winid, win_rect,codec_id); if (db_vdisp_profile) db_vdisp_profile->SetVideoRenderer("vdpau"); InitDisplayMeasurements(width, height, true); ParseOptions(); if (ok) ok = InitRender(); if (ok) ok = InitBuffers(); if (!ok) { TearDown(); return ok; } InitPictureAttributes(); MoveResize(); LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created VDPAU context (%1 decode)") .arg(codec_is_std(video_codec_id) ? "software" : "GPU")); return ok; }
QStringList VideoOutputOpenGLVAAPI::GetAllowedRenderers( MythCodecID myth_codec_id, const QSize &video_dim) { (void) video_dim; QStringList list; if ((codec_is_std(myth_codec_id) || (codec_is_vaapi(myth_codec_id))) && !getenv("NO_VAAPI")) { list += "openglvaapi"; } return list; }
QStringList VideoOutputOpenGL::GetAllowedRenderers( MythCodecID myth_codec_id, const QSize &video_dim) { (void) video_dim; QStringList list; if (codec_is_std(myth_codec_id) && !getenv("NO_OPENGL")) { list << "opengl" << "opengl-lite"; } return list; }
void VideoOutputOpenGL::ProcessFrame(VideoFrame *frame, OSD *osd, FilterChain *filterList, const PIPMap &pipPlayers, FrameScanType scan) { QMutexLocker locker(&gl_context_lock); if (!gl_context) return; bool sw_frame = codec_is_std(video_codec_id) && video_codec_id != kCodec_NONE; bool deint_proc = m_deinterlacing && (m_deintFilter != NULL); OpenGLLocker ctx_lock(gl_context); bool pauseframe = false; if (!frame) { frame = vbuffers.GetScratchFrame(); CopyFrame(vbuffers.GetScratchFrame(), &av_pause_frame); pauseframe = true; } if (filterList && sw_frame) filterList->ProcessFrame(frame); bool safepauseframe = pauseframe && !IsBobDeint(); if (sw_frame && deint_proc && m_deinterlaceBeforeOSD && (!pauseframe || safepauseframe)) { m_deintFilter->ProcessFrame(frame, scan); } if (!window.IsEmbedding()) { gl_pipchain_active = NULL; ShowPIPs(frame, pipPlayers); } if (sw_frame && (!pauseframe || safepauseframe) && deint_proc && !m_deinterlaceBeforeOSD) { m_deintFilter->ProcessFrame(frame, scan); } if (gl_videochain && sw_frame) { bool soft_bob = m_deinterlacing && (m_deintfiltername == "bobdeint"); gl_videochain->UpdateInputFrame(frame, soft_bob); } }
bool VideoOutputOpenGL::SetupOpenGL(void) { if (!gl_context) return false; const QRect dvr = window.GetDisplayVisibleRect(); if (video_codec_id == kCodec_NONE) { gl_context->SetViewPort(QRect(QPoint(),dvr.size())); return true; } if (window.GetPIPState() >= kPIPStandAlone) { QRect tmprect = QRect(QPoint(0,0), dvr.size()); ResizeDisplayWindow(tmprect, true); } bool success = false; OpenGLLocker ctx_lock(gl_context); gl_videochain = new OpenGLVideo(); QString options = GetFilters(); if (gl_opengl_lite) options += " preferycbcr"; success = gl_videochain->Init(gl_context, &videoColourSpace, window.GetVideoDim(), window.GetVideoDispDim(), dvr, window.GetDisplayVideoRect(), window.GetVideoRect(), true, options, !codec_is_std(video_codec_id)); if (success) { bool temp_deinterlacing = m_deinterlacing; if (!m_deintfiltername.isEmpty() && !m_deintfiltername.contains("opengl")) { gl_videochain->SetSoftwareDeinterlacer(m_deintfiltername); } SetDeinterlacingEnabled(true); if (!temp_deinterlacing) { SetDeinterlacingEnabled(false); } } return success; }
void VideoOutputOpenGLVAAPI::UpdatePauseFrame(int64_t &disp_timecode) { if (codec_is_std(video_codec_id)) { VideoOutputOpenGL::UpdatePauseFrame(disp_timecode); return; } vbuffers.begin_lock(kVideoBuffer_used); if (vbuffers.size(kVideoBuffer_used)) { VideoFrame *frame = vbuffers.head(kVideoBuffer_used); m_pauseBuffer = frame->buf; disp_timecode = frame->disp_timecode; } else LOG(VB_PLAYBACK, LOG_WARNING, LOC + "Could not update pause frame - no used frames."); vbuffers.end_lock(); }
bool VideoOutputVDPAU::CreateVideoSurfaces(uint num) { if (!m_render || num < 1) return false; bool ret = true; const QSize size = codec_is_std(video_codec_id) ? window.GetVideoDim() : window.GetActualVideoDim(); for (uint i = 0; i < num; i++) { uint tmp = m_render->CreateVideoSurface(size); if (tmp) { m_video_surfaces.push_back(tmp); m_render->ClearVideoSurface(tmp); } else { ret = false; break; } } return ret; }
bool VideoOutputVDPAU::InitBuffers(void) { QMutexLocker locker(&m_lock); if (!m_render) return false; uint buffer_size = m_decoder_buffer_size + m_process_buffer_size; const QSize video_dim = codec_is_std(video_codec_id) ? window.GetVideoDim() : window.GetActualVideoDim(); vbuffers.Init(buffer_size, false, 2, 1, 4, 1); bool ok = false; if (codec_is_vdpau(video_codec_id)) { ok = CreateVideoSurfaces(buffer_size); if (ok) { for (int i = 0; i < m_video_surfaces.size(); i++) ok &= vbuffers.CreateBuffer(video_dim.width(), video_dim.height(), i, m_render->GetRender(m_video_surfaces[i]), FMT_VDPAU); } } else if (codec_is_std(video_codec_id)) { ok = CreateVideoSurfaces(NUM_REFERENCE_FRAMES); if (ok) ok = vbuffers.CreateBuffers(FMT_YV12, video_dim.width(), video_dim.height()); } if (!ok) { LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to create VDPAU buffers"); } else { m_video_mixer = m_render->CreateVideoMixer(video_dim, 2, m_mixer_features); ok = m_video_mixer; m_pause_surface = m_video_surfaces[0]; if (ok && (m_mixer_features & kVDPFeatSharpness)) m_render->SetMixerAttribute(m_video_mixer, kVDPAttribSharpness, m_sharpen); if (ok && (m_mixer_features & kVDPFeatDenoise)) m_render->SetMixerAttribute(m_video_mixer, kVDPAttribNoiseReduction, m_denoise); if (ok && m_skip_chroma) m_render->SetMixerAttribute(m_video_mixer, kVDPAttribSkipChroma, 1); if (ok && (db_letterbox_colour == kLetterBoxColour_Gray25)) m_render->SetMixerAttribute(m_video_mixer, kVDPAttribBackground, 0x7F7F7FFF); } if (!ok) { LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to create VDPAU mixer"); DeleteBuffers(); } return ok; }
bool VideoOutputOpenGL::InputChanged(const QSize &video_dim_buf, const QSize &video_dim_disp, float aspect, MythCodecID av_codec_id, void */*codec_private*/, bool &aspect_only) { LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("InputChanged(%1,%2,%3) %4->%5") .arg(video_dim_disp.width()).arg(video_dim_disp.height()) .arg(aspect) .arg(toString(video_codec_id)).arg(toString(av_codec_id))); QMutexLocker locker(&gl_context_lock); // Ensure we don't lose embedding through program changes. This duplicates // code in VideoOutput::Init but we need start here otherwise the embedding // is lost during window re-initialistion. bool wasembedding = window.IsEmbedding(); QRect oldrect; if (wasembedding) { oldrect = window.GetEmbeddingRect(); StopEmbedding(); } if (!codec_is_std(av_codec_id) && !codec_is_mediacodec(av_codec_id) && !codec_is_vaapi2(av_codec_id)) { LOG(VB_GENERAL, LOG_ERR, LOC + "New video codec is not supported."); errorState = kError_Unknown; return false; } bool cid_changed = (video_codec_id != av_codec_id); bool res_changed = video_dim_disp != window.GetActualVideoDim(); bool asp_changed = aspect != window.GetVideoAspect(); if (!res_changed && !cid_changed) { if (asp_changed) { aspect_only = true; VideoAspectRatioChanged(aspect); MoveResize(); } if (wasembedding) EmbedInWidget(oldrect); return true; } if (gCoreContext->IsUIThread()) TearDown(); else DestroyCPUResources(); QRect disp = window.GetDisplayVisibleRect(); if (Init(video_dim_buf, video_dim_disp, aspect, gl_parent_win, disp, av_codec_id)) { if (wasembedding) EmbedInWidget(oldrect); if (gCoreContext->IsUIThread()) BestDeint(); return true; } LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to re-initialise video output."); errorState = kError_Unknown; return false; }
void VideoOutputOpenGL::ProcessFrame(VideoFrame *frame, OSD *osd, FilterChain *filterList, const PIPMap &pipPlayers, FrameScanType scan) { QMutexLocker locker(&gl_context_lock); if (!gl_context) return; if (!gl_valid) { if (!gCoreContext->IsUIThread()) { LOG(VB_GENERAL, LOG_ERR, LOC + "ProcessFrame called from wrong thread"); } QSize size = window.GetActualVideoDim(); InitDisplayMeasurements(size.width(), size.height(), false); DestroyVideoResources(); CreateVideoResources(); BestDeint(); gl_valid = true; } bool sw_frame = codec_is_std(video_codec_id) && video_codec_id != kCodec_NONE; bool deint_proc = m_deinterlacing && (m_deintFilter != NULL); OpenGLLocker ctx_lock(gl_context); bool pauseframe = false; if (!frame) { frame = vbuffers.GetScratchFrame(); CopyFrame(vbuffers.GetScratchFrame(), &av_pause_frame); pauseframe = true; } if (sw_frame) { CropToDisplay(frame); } bool dummy = frame->dummy; if (filterList && sw_frame && !dummy) filterList->ProcessFrame(frame); bool safepauseframe = pauseframe && !IsBobDeint(); if (sw_frame && deint_proc && m_deinterlaceBeforeOSD && (!pauseframe || safepauseframe) && !dummy) { m_deintFilter->ProcessFrame(frame, scan); } if (!window.IsEmbedding()) { gl_pipchain_active = NULL; ShowPIPs(frame, pipPlayers); } if (sw_frame && (!pauseframe || safepauseframe) && deint_proc && !m_deinterlaceBeforeOSD && !dummy) { m_deintFilter->ProcessFrame(frame, scan); } if (gl_videochain && sw_frame && !dummy) { bool soft_bob = m_deinterlacing && (m_deintfiltername == "bobdeint"); gl_videochain->UpdateInputFrame(frame, soft_bob); } }
bool VideoOutputOpenGL::InputChanged(const QSize &input_size, float aspect, MythCodecID av_codec_id, void *codec_private, bool &aspect_only) { VERBOSE(VB_PLAYBACK, LOC + QString("InputChanged(%1,%2,%3) %4->%5") .arg(input_size.width()).arg(input_size.height()).arg(aspect) .arg(toString(video_codec_id)).arg(toString(av_codec_id))); QMutexLocker locker(&gl_context_lock); // Ensure we don't lose embedding through program changes. This duplicates // code in VideoOutput::Init but we need start here otherwise the embedding // is lost during window re-initialistion. bool wasembedding = window.IsEmbedding(); QRect oldrect; if (wasembedding) { oldrect = window.GetEmbeddingRect(); StopEmbedding(); } if (!codec_is_std(av_codec_id)) { VERBOSE(VB_IMPORTANT, LOC_ERR + QString("New video codec is not supported.")); errorState = kError_Unknown; return false; } if (input_size == window.GetActualVideoDim()) { aspect_only = video_codec_id == av_codec_id; if (window.GetVideoAspect() != aspect) { VideoAspectRatioChanged(aspect); MoveResize(); if (wasembedding) EmbedInWidget(oldrect); } return true; } TearDown(); QRect disp = window.GetDisplayVisibleRect(); if (Init(input_size.width(), input_size.height(), aspect, gl_parent_win, disp, av_codec_id)) { if (wasembedding) EmbedInWidget(oldrect); BestDeint(); return true; } VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Failed to re-initialise video output.")); errorState = kError_Unknown; return false; }