|
MythTV
0.26-pre
|
00001 #include "mythcontext.h" 00002 #include "mythplayer.h" 00003 #include "videooutbase.h" 00004 #include "videoout_vdpau.h" 00005 #include "videodisplayprofile.h" 00006 #include "osd.h" 00007 #include "mythxdisplay.h" 00008 #include "mythmainwindow.h" 00009 #include "mythuihelper.h" 00010 #include "mythpainter_vdpau.h" 00011 00012 #define LOC QString("VidOutVDPAU: ") 00013 00014 #define MIN_REFERENCE_FRAMES 2 00015 #define MAX_REFERENCE_FRAMES 16 00016 #define MIN_PROCESS_BUFFER 6 00017 #define MAX_PROCESS_BUFFER 50 00018 #define DEF_PROCESS_BUFFER 12 00019 00020 #define CHECK_ERROR(Loc) \ 00021 if (m_render && m_render->IsErrored()) \ 00022 errorState = kError_Unknown; \ 00023 if (IsErrored()) \ 00024 { \ 00025 LOG(VB_GENERAL, LOG_ERR, LOC + QString("IsErrored() in %1").arg(Loc)); \ 00026 return; \ 00027 } while(0) 00028 00029 void VideoOutputVDPAU::GetRenderOptions(render_opts &opts) 00030 { 00031 opts.renderers->append("vdpau"); 00032 (*opts.osds)["vdpau"].append("vdpau"); 00033 if (opts.decoders->contains("vdpau")) 00034 (*opts.safe_renderers)["vdpau"].append("vdpau"); 00035 if (opts.decoders->contains("ffmpeg")) 00036 (*opts.safe_renderers)["ffmpeg"].append("vdpau"); 00037 if (opts.decoders->contains("crystalhd")) 00038 (*opts.safe_renderers)["crystalhd"].append("vdpau"); 00039 (*opts.safe_renderers)["dummy"].append("vdpau"); 00040 (*opts.safe_renderers)["nuppel"].append("vdpau"); 00041 00042 opts.priorities->insert("vdpau", 120); 00043 QStringList deints; 00044 deints += "none"; 00045 deints += "vdpauonefield"; 00046 deints += "vdpaubobdeint"; 00047 deints += "vdpaubasic"; 00048 deints += "vdpauadvanced"; 00049 deints += "vdpaubasicdoublerate"; 00050 deints += "vdpauadvanceddoublerate"; 00051 opts.deints->insert("vdpau", deints); 00052 } 00053 00054 VideoOutputVDPAU::VideoOutputVDPAU() 00055 : m_win(0), m_render(NULL), 00056 m_decoder_buffer_size(MAX_REFERENCE_FRAMES), 00057 m_process_buffer_size(DEF_PROCESS_BUFFER), m_pause_surface(0), 00058 m_need_deintrefs(false), m_video_mixer(0), m_mixer_features(kVDPFeatNone), 00059 m_checked_surface_ownership(false), 00060 m_checked_output_surfaces(false), 00061 m_decoder(0), m_pix_fmt(-1), 00062 m_lock(QMutex::Recursive), m_pip_layer(0), m_pip_surface(0), 00063 m_pip_ready(false), m_osd_painter(NULL), 00064 m_skip_chroma(false), m_denoise(0.0f), 00065 m_sharpen(0.0f), 00066 m_colorspace(VDP_COLOR_STANDARD_ITUR_BT_601) 00067 { 00068 if (gCoreContext->GetNumSetting("UseVideoModes", 0)) 00069 display_res = DisplayRes::GetDisplayRes(true); 00070 } 00071 00072 VideoOutputVDPAU::~VideoOutputVDPAU() 00073 { 00074 QMutexLocker locker(&m_lock); 00075 TearDown(); 00076 } 00077 00078 void VideoOutputVDPAU::TearDown(void) 00079 { 00080 QMutexLocker locker(&m_lock); 00081 DeinitPIPS(); 00082 DeinitPIPLayer(); 00083 DeleteBuffers(); 00084 RestoreDisplay(); 00085 DeleteRender(); 00086 } 00087 00088 bool VideoOutputVDPAU::Init(int width, int height, float aspect, 00089 WId winid, const QRect &win_rect, 00090 MythCodecID codec_id) 00091 { 00092 // Attempt to free up as much video memory as possible 00093 // only works when using the VDPAU painter for the UI 00094 MythPainter *painter = GetMythPainter(); 00095 if (painter) 00096 painter->FreeResources(); 00097 00098 m_win = winid; 00099 QMutexLocker locker(&m_lock); 00100 window.SetNeedRepaint(true); 00101 bool ok = VideoOutput::Init(width, height, aspect, winid, win_rect,codec_id); 00102 if (db_vdisp_profile) 00103 db_vdisp_profile->SetVideoRenderer("vdpau"); 00104 00105 InitDisplayMeasurements(width, height, true); 00106 ParseOptions(); 00107 if (ok) ok = InitRender(); 00108 if (ok) ok = InitBuffers(); 00109 if (!ok) 00110 { 00111 TearDown(); 00112 return ok; 00113 } 00114 00115 InitPictureAttributes(); 00116 MoveResize(); 00117 LOG(VB_PLAYBACK, LOG_INFO, LOC + 00118 QString("Created VDPAU context (%1 decode)") 00119 .arg(codec_is_std(video_codec_id) ? "software" : "GPU")); 00120 00121 return ok; 00122 } 00123 00124 bool VideoOutputVDPAU::InitRender(void) 00125 { 00126 QMutexLocker locker(&m_lock); 00127 00128 const QSize size = window.GetDisplayVisibleRect().size(); 00129 const QRect rect = QRect(QPoint(0,0), size); 00130 m_render = new MythRenderVDPAU(); 00131 00132 if (m_render && m_render->Create(size, m_win)) 00133 { 00134 m_osd_painter = new MythVDPAUPainter(m_render); 00135 if (m_osd_painter) 00136 { 00137 m_osd_painter->SetSwapControl(false); 00138 LOG(VB_PLAYBACK, LOG_INFO, LOC + 00139 QString("Created VDPAU osd (%1x%2)") 00140 .arg(size.width()).arg(size.height())); 00141 } 00142 else 00143 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create VDPAU osd."); 00144 return true; 00145 } 00146 00147 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise VDPAU"); 00148 00149 return false; 00150 } 00151 00152 void VideoOutputVDPAU::DeleteRender(void) 00153 { 00154 QMutexLocker locker(&m_lock); 00155 00156 if (m_osd_painter) 00157 delete m_osd_painter; 00158 00159 if (m_render) 00160 { 00161 if (m_decoder) 00162 m_render->DestroyDecoder(m_decoder); 00163 00164 delete m_render; 00165 } 00166 00167 m_checked_output_surfaces = false; 00168 m_osd_painter = NULL; 00169 m_decoder = 0; 00170 m_render = NULL; 00171 m_pix_fmt = -1; 00172 } 00173 00174 bool VideoOutputVDPAU::InitBuffers(void) 00175 { 00176 QMutexLocker locker(&m_lock); 00177 if (!m_render) 00178 return false; 00179 00180 uint buffer_size = m_decoder_buffer_size + m_process_buffer_size; 00181 const QSize video_dim = codec_is_std(video_codec_id) ? 00182 window.GetVideoDim() : window.GetActualVideoDim(); 00183 00184 vbuffers.Init(buffer_size, false, 2, 1, 4, 1); 00185 00186 bool ok = false; 00187 if (codec_is_vdpau(video_codec_id)) 00188 { 00189 ok = CreateVideoSurfaces(buffer_size); 00190 if (ok) 00191 { 00192 for (int i = 0; i < m_video_surfaces.size(); i++) 00193 ok &= vbuffers.CreateBuffer(video_dim.width(), 00194 video_dim.height(), i, 00195 m_render->GetRender(m_video_surfaces[i]), 00196 FMT_VDPAU); 00197 } 00198 } 00199 else if (codec_is_std(video_codec_id)) 00200 { 00201 ok = CreateVideoSurfaces(NUM_REFERENCE_FRAMES); 00202 if (ok) 00203 ok = vbuffers.CreateBuffers(FMT_YV12, 00204 video_dim.width(), video_dim.height()); 00205 } 00206 00207 if (!ok) 00208 { 00209 LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to create VDPAU buffers"); 00210 } 00211 else 00212 { 00213 m_video_mixer = m_render->CreateVideoMixer(video_dim, 2, 00214 m_mixer_features); 00215 ok = m_video_mixer; 00216 m_pause_surface = m_video_surfaces[0]; 00217 00218 if (ok && (m_mixer_features & kVDPFeatSharpness)) 00219 m_render->SetMixerAttribute(m_video_mixer, 00220 kVDPAttribSharpness, 00221 m_sharpen); 00222 if (ok && (m_mixer_features & kVDPFeatDenoise)) 00223 m_render->SetMixerAttribute(m_video_mixer, 00224 kVDPAttribNoiseReduction, 00225 m_denoise); 00226 if (ok && m_skip_chroma) 00227 m_render->SetMixerAttribute(m_video_mixer, 00228 kVDPAttribSkipChroma, 1); 00229 00230 if (ok && (db_letterbox_colour == kLetterBoxColour_Gray25)) 00231 m_render->SetMixerAttribute(m_video_mixer, 00232 kVDPAttribBackground, 0x7F7F7FFF); 00233 } 00234 00235 if (!ok) 00236 { 00237 LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to create VDPAU mixer"); 00238 DeleteBuffers(); 00239 } 00240 00241 return ok; 00242 } 00243 00244 bool VideoOutputVDPAU::CreateVideoSurfaces(uint num) 00245 { 00246 if (!m_render || num < 1) 00247 return false; 00248 00249 bool ret = true; 00250 const QSize size = codec_is_std(video_codec_id) ? 00251 window.GetVideoDim() : window.GetActualVideoDim(); 00252 for (uint i = 0; i < num; i++) 00253 { 00254 uint tmp = m_render->CreateVideoSurface(size); 00255 if (tmp) 00256 { 00257 m_video_surfaces.push_back(tmp); 00258 m_render->ClearVideoSurface(tmp); 00259 } 00260 else 00261 { 00262 ret = false; 00263 break; 00264 } 00265 } 00266 return ret; 00267 } 00268 00269 void VideoOutputVDPAU::DeleteVideoSurfaces(void) 00270 { 00271 if (!m_render || !m_video_surfaces.size()) 00272 return; 00273 00274 for (int i = 0; i < m_video_surfaces.size(); i++) 00275 m_render->DestroyVideoSurface(m_video_surfaces[i]); 00276 m_video_surfaces.clear(); 00277 } 00278 00279 void VideoOutputVDPAU::DeleteBuffers(void) 00280 { 00281 QMutexLocker locker(&m_lock); 00282 if (m_render && m_video_mixer) 00283 m_render->DestroyVideoMixer(m_video_mixer); 00284 m_video_mixer = 0; 00285 m_checked_surface_ownership = false; 00286 DiscardFrames(true); 00287 DeleteVideoSurfaces(); 00288 vbuffers.Reset(); 00289 vbuffers.DeleteBuffers(); 00290 } 00291 00292 void VideoOutputVDPAU::RestoreDisplay(void) 00293 { 00294 QMutexLocker locker(&m_lock); 00295 00296 const QRect tmp_display_visible_rect = 00297 window.GetTmpDisplayVisibleRect(); 00298 if (window.GetPIPState() == kPIPStandAlone && 00299 !tmp_display_visible_rect.isEmpty()) 00300 { 00301 window.SetDisplayVisibleRect(tmp_display_visible_rect); 00302 } 00303 const QRect display_visible_rect = window.GetDisplayVisibleRect(); 00304 00305 if (m_render) 00306 m_render->DrawDisplayRect(display_visible_rect); 00307 } 00308 00309 bool VideoOutputVDPAU::SetDeinterlacingEnabled(bool interlaced) 00310 { 00311 if ((interlaced && m_deinterlacing) || 00312 (!interlaced && !m_deinterlacing)) 00313 return m_deinterlacing; 00314 00315 return SetupDeinterlace(interlaced); 00316 } 00317 00318 bool VideoOutputVDPAU::SetupDeinterlace(bool interlaced, 00319 const QString &override) 00320 { 00321 m_lock.lock(); 00322 if (!m_render) 00323 return false; 00324 00325 bool enable = interlaced; 00326 if (enable) 00327 { 00328 m_deintfiltername = db_vdisp_profile->GetFilteredDeint(override); 00329 if (m_deintfiltername.contains("vdpau")) 00330 { 00331 uint features = kVDPFeatNone; 00332 bool spatial = m_deintfiltername.contains("advanced"); 00333 bool temporal = m_deintfiltername.contains("basic") || spatial; 00334 m_need_deintrefs = spatial || temporal; 00335 00336 if (temporal) 00337 features += kVDPFeatTemporal; 00338 00339 if (spatial) 00340 features += kVDPFeatSpatial; 00341 00342 enable = m_render->SetDeinterlacing(m_video_mixer, features); 00343 if (enable) 00344 { 00345 m_deinterlacing = true; 00346 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Enabled deinterlacing."); 00347 } 00348 else 00349 { 00350 enable = false; 00351 LOG(VB_PLAYBACK, LOG_INFO, LOC + 00352 "Failed to enable deinterlacing."); 00353 } 00354 } 00355 else 00356 { 00357 enable = false; 00358 } 00359 } 00360 00361 if (!enable) 00362 { 00363 ClearReferenceFrames(); 00364 m_render->SetDeinterlacing(m_video_mixer); 00365 m_deintfiltername = QString(); 00366 m_deinterlacing = false; 00367 m_need_deintrefs = false; 00368 } 00369 m_lock.unlock(); 00370 return enable; 00371 } 00372 00373 bool VideoOutputVDPAU::ApproveDeintFilter(const QString &filtername) const 00374 { 00375 return filtername.contains("vdpau"); 00376 } 00377 00378 void VideoOutputVDPAU::ProcessFrame(VideoFrame *frame, OSD *osd, 00379 FilterChain *filterList, 00380 const PIPMap &pipPlayers, 00381 FrameScanType scan) 00382 { 00383 QMutexLocker locker(&m_lock); 00384 CHECK_ERROR("ProcessFrame"); 00385 00386 if (!m_checked_surface_ownership && codec_is_std(video_codec_id)) 00387 ClaimVideoSurfaces(); 00388 00389 m_pip_ready = false; 00390 ShowPIPs(frame, pipPlayers); 00391 } 00392 00393 void VideoOutputVDPAU::ClearDummyFrame(VideoFrame *frame) 00394 { 00395 if (frame && m_render && !codec_is_std(video_codec_id)) 00396 { 00397 struct vdpau_render_state *render = 00398 (struct vdpau_render_state *)frame->buf; 00399 if (render) 00400 m_render->ClearVideoSurface(render->surface); 00401 } 00402 VideoOutput::ClearDummyFrame(frame); 00403 } 00404 00405 void VideoOutputVDPAU::PrepareFrame(VideoFrame *frame, FrameScanType scan, 00406 OSD *osd) 00407 { 00408 QMutexLocker locker(&m_lock); 00409 (void)osd; 00410 CHECK_ERROR("PrepareFrame"); 00411 00412 if (!m_render) 00413 return; 00414 00415 if (!m_checked_output_surfaces && 00416 !(!codec_is_std(video_codec_id) && !m_decoder)) 00417 { 00418 m_render->CheckOutputSurfaces(); 00419 m_checked_output_surfaces = true; 00420 } 00421 00422 bool new_frame = false; 00423 bool dummy = false; 00424 if (frame) 00425 { 00426 // FIXME for 0.23. This should be triggered from AFD by a seek 00427 if ((abs(frame->frameNumber - framesPlayed) > 8)) 00428 ClearReferenceFrames(); 00429 new_frame = (framesPlayed != frame->frameNumber + 1); 00430 framesPlayed = frame->frameNumber + 1; 00431 dummy = frame->dummy; 00432 } 00433 00434 uint video_surface = m_video_surfaces[0]; 00435 bool deint = (m_deinterlacing && m_need_deintrefs && 00436 frame && !dummy); 00437 00438 if (deint) 00439 { 00440 if (new_frame) 00441 UpdateReferenceFrames(frame); 00442 if (m_reference_frames.size() != NUM_REFERENCE_FRAMES) 00443 deint = false; 00444 } 00445 00446 if (!codec_is_std(video_codec_id) && frame) 00447 { 00448 struct vdpau_render_state *render = 00449 (struct vdpau_render_state *)frame->buf; 00450 if (!render) 00451 return; 00452 video_surface = m_render->GetSurfaceOwner(render->surface); 00453 } 00454 else if (new_frame && frame && !dummy) 00455 { 00456 // FIXME - reference frames for software decode 00457 if (deint) 00458 video_surface = m_video_surfaces[(framesPlayed + 1) % 00459 NUM_REFERENCE_FRAMES]; 00460 00461 uint32_t pitches[3] = { 00462 frame->pitches[0], 00463 frame->pitches[2], 00464 frame->pitches[1] 00465 }; 00466 void* const planes[3] = { 00467 frame->buf, 00468 frame->buf + frame->offsets[2], 00469 frame->buf + frame->offsets[1] 00470 }; 00471 00472 if (!m_render->UploadYUVFrame(video_surface, planes, pitches)) 00473 return; 00474 } 00475 else if (!frame) 00476 { 00477 deint = false; 00478 video_surface = m_pause_surface; 00479 } 00480 00481 VdpVideoMixerPictureStructure field = 00482 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; 00483 00484 if (scan == kScan_Interlaced && m_deinterlacing && frame) 00485 { 00486 field = frame->top_field_first ? 00487 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD : 00488 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; 00489 } 00490 else if (scan == kScan_Intr2ndField && m_deinterlacing && frame) 00491 { 00492 field = frame->top_field_first ? 00493 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD : 00494 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; 00495 } 00496 else if (!frame && m_deinterlacing) 00497 { 00498 field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; 00499 } 00500 00501 m_render->WaitForFlip(); 00502 00503 QSize size = window.GetDisplayVisibleRect().size(); 00504 if (size != m_render->GetSize()) 00505 LOG(VB_GENERAL, LOG_ERR, LOC + "Unexpected display size."); 00506 00507 if (dummy) 00508 { 00509 m_render->DrawBitmap(0, 0, NULL, NULL, kVDPBlendNormal, 255); 00510 } 00511 else 00512 { 00513 if (!m_render->MixAndRend(m_video_mixer, field, video_surface, 0, 00514 deint ? &m_reference_frames : NULL, 00515 scan == kScan_Interlaced, 00516 window.GetVideoRect(), 00517 QRect(QPoint(0,0), size), 00518 vsz_enabled ? vsz_desired_display_rect : 00519 window.GetDisplayVideoRect(), 00520 0, 0)) 00521 { 00522 LOG(VB_PLAYBACK, LOG_ERR, LOC + "Prepare frame failed."); 00523 } 00524 } 00525 00526 if (m_pip_ready) 00527 m_render->DrawLayer(m_pip_layer, 0); 00528 if (m_visual) 00529 m_visual->Draw(GetTotalOSDBounds(), m_osd_painter, NULL); 00530 00531 if (osd && m_osd_painter && !window.IsEmbedding()) 00532 osd->DrawDirect(m_osd_painter, GetTotalOSDBounds().size(), true); 00533 00534 if (!frame) 00535 { 00536 VideoFrame *buf = GetLastShownFrame(); 00537 if (buf) 00538 buf->timecode = 0; 00539 } 00540 } 00541 00542 void VideoOutputVDPAU::ClaimVideoSurfaces(void) 00543 { 00544 if (!m_render) 00545 return; 00546 00547 QVector<uint>::iterator it; 00548 for (it = m_video_surfaces.begin(); it != m_video_surfaces.end(); ++it) 00549 m_render->ChangeVideoSurfaceOwner(*it); 00550 m_checked_surface_ownership = true; 00551 } 00552 00553 void VideoOutputVDPAU::DrawSlice(VideoFrame *frame, int x, int y, int w, int h) 00554 { 00555 (void)x; 00556 (void)y; 00557 (void)w; 00558 (void)h; 00559 00560 CHECK_ERROR("DrawSlice"); 00561 00562 if (codec_is_std(video_codec_id) || !m_render) 00563 return; 00564 00565 if (!m_checked_surface_ownership) 00566 ClaimVideoSurfaces(); 00567 00568 struct vdpau_render_state *render = (struct vdpau_render_state *)frame->buf; 00569 if (!render) 00570 { 00571 LOG(VB_GENERAL, LOG_ERR, LOC + "No video surface to decode to."); 00572 errorState = kError_Unknown; 00573 return; 00574 } 00575 00576 if (frame->pix_fmt != m_pix_fmt) 00577 { 00578 if (m_decoder) 00579 { 00580 LOG(VB_GENERAL, LOG_ERR, LOC + "Picture format has changed."); 00581 errorState = kError_Unknown; 00582 return; 00583 } 00584 00585 uint max_refs = MIN_REFERENCE_FRAMES; 00586 if (frame->pix_fmt == PIX_FMT_VDPAU_H264) 00587 { 00588 max_refs = render->info.h264.num_ref_frames; 00589 if (max_refs < 1 || max_refs > MAX_REFERENCE_FRAMES) 00590 { 00591 uint32_t round_width = (frame->width + 15) & ~15; 00592 uint32_t round_height = (frame->height + 15) & ~15; 00593 uint32_t surf_size = (round_width * round_height * 3) / 2; 00594 max_refs = (12 * 1024 * 1024) / surf_size; 00595 } 00596 if (max_refs > MAX_REFERENCE_FRAMES) 00597 max_refs = MAX_REFERENCE_FRAMES; 00598 00599 // Add extra buffers as necessary 00600 int needed = max_refs - m_decoder_buffer_size; 00601 if (needed > 0) 00602 { 00603 QMutexLocker locker(&m_lock); 00604 const QSize size = window.GetActualVideoDim(); 00605 uint created = 0; 00606 for (int i = 0; i < needed; i++) 00607 { 00608 uint tmp = m_render->CreateVideoSurface(size); 00609 if (tmp) 00610 { 00611 m_video_surfaces.push_back(tmp); 00612 m_render->ClearVideoSurface(tmp); 00613 if (vbuffers.AddBuffer(size.width(), size.height(), 00614 m_render->GetRender(tmp), 00615 FMT_VDPAU)) 00616 { 00617 created++; 00618 } 00619 } 00620 } 00621 m_decoder_buffer_size += created; 00622 LOG(VB_GENERAL, LOG_INFO, LOC + 00623 QString("Added %1 new buffers. New buffer size %2 " 00624 "(%3 decode and %4 process)") 00625 .arg(created).arg(vbuffers.Size()) 00626 .arg(m_decoder_buffer_size) 00627 .arg(m_process_buffer_size)); 00628 } 00629 } 00630 00631 VdpDecoderProfile vdp_decoder_profile; 00632 switch (frame->pix_fmt) 00633 { 00634 case PIX_FMT_VDPAU_MPEG1: 00635 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1; 00636 break; 00637 case PIX_FMT_VDPAU_MPEG2: 00638 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN; 00639 break; 00640 case PIX_FMT_VDPAU_MPEG4: 00641 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; 00642 break; 00643 case PIX_FMT_VDPAU_H264: 00644 vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH; 00645 break; 00646 case PIX_FMT_VDPAU_WMV3: 00647 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN; 00648 break; 00649 case PIX_FMT_VDPAU_VC1: 00650 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED; 00651 break; 00652 default: 00653 LOG(VB_GENERAL, LOG_ERR, LOC + 00654 "Picture format is not supported."); 00655 errorState = kError_Unknown; 00656 return; 00657 } 00658 00659 m_decoder = m_render->CreateDecoder(window.GetActualVideoDim(), 00660 vdp_decoder_profile, max_refs); 00661 if (m_decoder) 00662 { 00663 m_pix_fmt = frame->pix_fmt; 00664 LOG(VB_PLAYBACK, LOG_INFO, LOC + 00665 QString("Created VDPAU decoder (%1 ref frames)") 00666 .arg(max_refs)); 00667 } 00668 else 00669 { 00670 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create decoder."); 00671 errorState = kError_Unknown; 00672 return; 00673 } 00674 } 00675 else if (!m_decoder) 00676 { 00677 LOG(VB_GENERAL, LOG_ERR, LOC + 00678 "Pix format already set but no VDPAU decoder."); 00679 errorState = kError_Unknown; 00680 return; 00681 } 00682 00683 m_render->Decode(m_decoder, render); 00684 } 00685 00686 void VideoOutputVDPAU::Show(FrameScanType scan) 00687 { 00688 QMutexLocker locker(&m_lock); 00689 CHECK_ERROR("Show"); 00690 00691 if (window.IsRepaintNeeded()) 00692 DrawUnusedRects(false); 00693 00694 if (m_render) 00695 m_render->Flip(); 00696 CheckFrameStates(); 00697 } 00698 00699 void VideoOutputVDPAU::ClearAfterSeek(void) 00700 { 00701 m_lock.lock(); 00702 LOG(VB_PLAYBACK, LOG_INFO, LOC + "ClearAfterSeek()"); 00703 DiscardFrames(false); 00704 m_lock.unlock(); 00705 } 00706 00707 bool VideoOutputVDPAU::InputChanged(const QSize &input_size, 00708 float aspect, 00709 MythCodecID av_codec_id, 00710 void *codec_private, 00711 bool &aspect_only) 00712 { 00713 LOG(VB_PLAYBACK, LOG_INFO, LOC + 00714 QString("InputChanged(%1,%2,%3) '%4'->'%5'") 00715 .arg(input_size.width()).arg(input_size.height()).arg(aspect) 00716 .arg(toString(video_codec_id)).arg(toString(av_codec_id))); 00717 00718 QMutexLocker locker(&m_lock); 00719 00720 // Ensure we don't lose embedding through program changes. This duplicates 00721 // code in VideoOutput::Init but we need start here otherwise the embedding 00722 // is lost during window re-initialistion. 00723 bool wasembedding = window.IsEmbedding(); 00724 QRect oldrect; 00725 if (wasembedding) 00726 { 00727 oldrect = window.GetEmbeddingRect(); 00728 StopEmbedding(); 00729 } 00730 00731 bool cid_changed = (video_codec_id != av_codec_id); 00732 bool res_changed = input_size != window.GetActualVideoDim(); 00733 bool asp_changed = aspect != window.GetVideoAspect(); 00734 00735 if (!res_changed && !cid_changed) 00736 { 00737 aspect_only = true; 00738 if (asp_changed) 00739 { 00740 VideoAspectRatioChanged(aspect); 00741 MoveResize(); 00742 } 00743 if (wasembedding) 00744 EmbedInWidget(oldrect); 00745 return true; 00746 } 00747 00748 TearDown(); 00749 QRect disp = window.GetDisplayVisibleRect(); 00750 if (Init(input_size.width(), input_size.height(), 00751 aspect, m_win, disp, av_codec_id)) 00752 { 00753 if (wasembedding) 00754 EmbedInWidget(oldrect); 00755 BestDeint(); 00756 return true; 00757 } 00758 00759 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to re-initialise video output."); 00760 errorState = kError_Unknown; 00761 00762 return false; 00763 } 00764 00765 void VideoOutputVDPAU::Zoom(ZoomDirection direction) 00766 { 00767 QMutexLocker locker(&m_lock); 00768 VideoOutput::Zoom(direction); 00769 MoveResize(); 00770 } 00771 00772 void VideoOutputVDPAU::VideoAspectRatioChanged(float aspect) 00773 { 00774 QMutexLocker locker(&m_lock); 00775 VideoOutput::VideoAspectRatioChanged(aspect); 00776 } 00777 00778 void VideoOutputVDPAU::EmbedInWidget(const QRect &rect) 00779 { 00780 QMutexLocker locker(&m_lock); 00781 if (!window.IsEmbedding()) 00782 { 00783 VideoOutput::EmbedInWidget(rect); 00784 MoveResize(); 00785 window.SetDisplayVisibleRect(window.GetTmpDisplayVisibleRect()); 00786 } 00787 } 00788 00789 void VideoOutputVDPAU::StopEmbedding(void) 00790 { 00791 if (!window.IsEmbedding()) 00792 return; 00793 QMutexLocker locker(&m_lock); 00794 VideoOutput::StopEmbedding(); 00795 MoveResize(); 00796 } 00797 00798 void VideoOutputVDPAU::MoveResizeWindow(QRect new_rect) 00799 { 00800 m_lock.lock(); 00801 if (m_render) 00802 m_render->MoveResizeWin(new_rect); 00803 m_lock.unlock(); 00804 } 00805 00806 void VideoOutputVDPAU::DrawUnusedRects(bool sync) 00807 { 00808 m_lock.lock(); 00809 if (window.IsRepaintNeeded() && m_render) 00810 { 00811 const QRect dvr = window.GetDisplayVisibleRect(); 00812 m_render->DrawDisplayRect(dvr, true); 00813 window.SetNeedRepaint(false); 00814 if (sync) 00815 m_render->SyncDisplay(); 00816 } 00817 m_lock.unlock(); 00818 } 00819 00820 void VideoOutputVDPAU::UpdatePauseFrame(int64_t &disp_timecode) 00821 { 00822 QMutexLocker locker(&m_lock); 00823 00824 LOG(VB_PLAYBACK, LOG_INFO, LOC + "UpdatePauseFrame() " + 00825 vbuffers.GetStatus()); 00826 00827 vbuffers.begin_lock(kVideoBuffer_used); 00828 00829 if (vbuffers.size(kVideoBuffer_used) && m_render) 00830 { 00831 VideoFrame *frame = vbuffers.head(kVideoBuffer_used); 00832 disp_timecode = frame->disp_timecode; 00833 if (codec_is_std(video_codec_id)) 00834 { 00835 m_pause_surface = m_video_surfaces[0]; 00836 uint32_t pitches[3] = { frame->pitches[0], 00837 frame->pitches[2], 00838 frame->pitches[1] }; 00839 void* const planes[3] = { frame->buf, 00840 frame->buf + frame->offsets[2], 00841 frame->buf + frame->offsets[1] }; 00842 m_render->UploadYUVFrame(m_video_surfaces[0], planes, pitches); 00843 } 00844 else 00845 { 00846 struct vdpau_render_state *render = 00847 (struct vdpau_render_state *)frame->buf; 00848 if (render) 00849 m_pause_surface = m_render->GetSurfaceOwner(render->surface); 00850 } 00851 } 00852 else 00853 LOG(VB_PLAYBACK, LOG_WARNING, LOC + 00854 "Could not update pause frame - no used frames."); 00855 00856 vbuffers.end_lock(); 00857 } 00858 00859 void VideoOutputVDPAU::InitPictureAttributes(void) 00860 { 00861 videoColourSpace.SetSupportedAttributes((PictureAttributeSupported) 00862 (kPictureAttributeSupported_Brightness | 00863 kPictureAttributeSupported_Contrast | 00864 kPictureAttributeSupported_Colour | 00865 kPictureAttributeSupported_Hue | 00866 kPictureAttributeSupported_StudioLevels)); 00867 00868 m_lock.lock(); 00869 if (m_render && m_video_mixer) 00870 { 00871 if (m_colorspace < 0) 00872 { 00873 QSize size = window.GetVideoDim(); 00874 m_colorspace = (size.width() > 720 || size.height() > 576) ? 00875 VDP_COLOR_STANDARD_ITUR_BT_709 : 00876 VDP_COLOR_STANDARD_ITUR_BT_601; 00877 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Using ITU %1 colorspace") 00878 .arg((m_colorspace == VDP_COLOR_STANDARD_ITUR_BT_601) ? 00879 "BT.601" : "BT.709")); 00880 } 00881 00882 if (m_colorspace != VDP_COLOR_STANDARD_ITUR_BT_601) 00883 { 00884 videoColourSpace.SetColourSpace((m_colorspace == VDP_COLOR_STANDARD_ITUR_BT_601) 00885 ? kCSTD_ITUR_BT_601 : kCSTD_ITUR_BT_709); 00886 } 00887 m_render->SetCSCMatrix(m_video_mixer, videoColourSpace.GetMatrix()); 00888 } 00889 m_lock.unlock(); 00890 } 00891 00892 int VideoOutputVDPAU::SetPictureAttribute(PictureAttribute attribute, 00893 int newValue) 00894 { 00895 if (!m_render || !m_video_mixer) 00896 return -1; 00897 00898 m_lock.lock(); 00899 newValue = videoColourSpace.SetPictureAttribute(attribute, newValue); 00900 if (newValue >= 0) 00901 m_render->SetCSCMatrix(m_video_mixer, videoColourSpace.GetMatrix()); 00902 m_lock.unlock(); 00903 return newValue; 00904 } 00905 00906 QStringList VideoOutputVDPAU::GetAllowedRenderers( 00907 MythCodecID myth_codec_id, const QSize &video_dim) 00908 { 00909 (void) video_dim; 00910 QStringList list; 00911 if ((codec_is_std(myth_codec_id) || codec_is_vdpau_hw(myth_codec_id)) && 00912 !getenv("NO_VDPAU")) 00913 { 00914 list += "vdpau"; 00915 } 00916 00917 return list; 00918 } 00919 00920 MythCodecID VideoOutputVDPAU::GetBestSupportedCodec( 00921 uint width, uint height, const QString &decoder, 00922 uint stream_type, bool no_acceleration) 00923 { 00924 bool use_cpu = no_acceleration; 00925 00926 MythCodecID test_cid = (MythCodecID)(kCodec_MPEG1_VDPAU + (stream_type-1)); 00927 use_cpu |= !codec_is_vdpau_hw(test_cid); 00928 if (test_cid == kCodec_MPEG4_VDPAU) 00929 use_cpu |= !MythRenderVDPAU::IsMPEG4Available(); 00930 if (test_cid == kCodec_H264_VDPAU) 00931 use_cpu |= !MythRenderVDPAU::H264DecoderSizeSupported(width, height); 00932 if ((decoder != "vdpau") || getenv("NO_VDPAU") || use_cpu) 00933 return (MythCodecID)(kCodec_MPEG1 + (stream_type-1)); 00934 00935 return test_cid; 00936 } 00937 00938 void VideoOutputVDPAU::UpdateReferenceFrames(VideoFrame *frame) 00939 { 00940 while (m_reference_frames.size() > (NUM_REFERENCE_FRAMES - 1)) 00941 m_reference_frames.pop_front(); 00942 00943 uint ref = m_video_surfaces[(framesPlayed +1) % NUM_REFERENCE_FRAMES]; 00944 if (!codec_is_std(video_codec_id)) 00945 { 00946 struct vdpau_render_state *render = 00947 (struct vdpau_render_state *)frame->buf; 00948 if (render) 00949 ref = m_render->GetSurfaceOwner(render->surface); 00950 } 00951 00952 m_reference_frames.push_back(ref); 00953 } 00954 00955 bool VideoOutputVDPAU::FrameIsInUse(VideoFrame *frame) 00956 { 00957 if (!frame || codec_is_std(video_codec_id)) 00958 return false; 00959 00960 uint ref = 0; 00961 struct vdpau_render_state *render = (struct vdpau_render_state *)frame->buf; 00962 if (render) 00963 ref = m_render->GetSurfaceOwner(render->surface); 00964 return m_reference_frames.contains(ref); 00965 } 00966 00967 void VideoOutputVDPAU::ClearReferenceFrames(void) 00968 { 00969 m_lock.lock(); 00970 m_reference_frames.clear(); 00971 m_lock.unlock(); 00972 } 00973 00974 void VideoOutputVDPAU::DiscardFrame(VideoFrame *frame) 00975 { 00976 if (!frame) 00977 return; 00978 00979 m_lock.lock(); 00980 if (FrameIsInUse(frame)) 00981 vbuffers.safeEnqueue(kVideoBuffer_displayed, frame); 00982 else 00983 { 00984 vbuffers.DoneDisplayingFrame(frame); 00985 } 00986 m_lock.unlock(); 00987 } 00988 00989 void VideoOutputVDPAU::DiscardFrames(bool next_frame_keyframe) 00990 { 00991 m_lock.lock(); 00992 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("DiscardFrames(%1)") 00993 .arg(next_frame_keyframe)); 00994 CheckFrameStates(); 00995 ClearReferenceFrames(); 00996 vbuffers.DiscardFrames(next_frame_keyframe); 00997 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("DiscardFrames() 3: %1 -- done()") 00998 .arg(vbuffers.GetStatus())); 00999 m_lock.unlock(); 01000 } 01001 01002 void VideoOutputVDPAU::DoneDisplayingFrame(VideoFrame *frame) 01003 { 01004 m_lock.lock(); 01005 if (vbuffers.contains(kVideoBuffer_used, frame)) 01006 DiscardFrame(frame); 01007 CheckFrameStates(); 01008 m_lock.unlock(); 01009 } 01010 01011 void VideoOutputVDPAU::CheckFrameStates(void) 01012 { 01013 m_lock.lock(); 01014 frame_queue_t::iterator it; 01015 it = vbuffers.begin_lock(kVideoBuffer_displayed); 01016 while (it != vbuffers.end(kVideoBuffer_displayed)) 01017 { 01018 VideoFrame* frame = *it; 01019 if (!FrameIsInUse(frame)) 01020 { 01021 if (vbuffers.contains(kVideoBuffer_decode, frame)) 01022 { 01023 LOG(VB_PLAYBACK, LOG_INFO, LOC + 01024 QString("Frame %1 is in use by avlib and so is " 01025 "being held for later discarding.") 01026 .arg(DebugString(frame, true))); 01027 } 01028 else 01029 { 01030 vbuffers.safeEnqueue(kVideoBuffer_avail, frame); 01031 vbuffers.end_lock(); 01032 it = vbuffers.begin_lock(kVideoBuffer_displayed); 01033 continue; 01034 } 01035 } 01036 ++it; 01037 } 01038 vbuffers.end_lock(); 01039 m_lock.unlock(); 01040 } 01041 01042 bool VideoOutputVDPAU::InitPIPLayer(QSize size) 01043 { 01044 if (!m_render) 01045 return false; 01046 01047 if (!m_pip_surface) 01048 m_pip_surface = m_render->CreateOutputSurface(size); 01049 01050 if (!m_pip_layer && m_pip_surface) 01051 m_pip_layer = m_render->CreateLayer(m_pip_surface); 01052 01053 return (m_pip_surface && m_pip_layer); 01054 } 01055 01056 void VideoOutputVDPAU::DeinitPIPS(void) 01057 { 01058 while (!m_pips.empty()) 01059 { 01060 RemovePIP(m_pips.begin().key()); 01061 m_pips.erase(m_pips.begin()); 01062 } 01063 01064 m_pip_ready = false; 01065 } 01066 01067 void VideoOutputVDPAU::DeinitPIPLayer(void) 01068 { 01069 if (m_render) 01070 { 01071 if (m_pip_surface) 01072 { 01073 m_render->DestroyOutputSurface(m_pip_surface); 01074 m_pip_surface = 0; 01075 } 01076 01077 if (m_pip_layer) 01078 { 01079 m_render->DestroyLayer(m_pip_layer); 01080 m_pip_layer = 0; 01081 } 01082 } 01083 01084 m_pip_ready = false; 01085 } 01086 01087 void VideoOutputVDPAU::ShowPIP(VideoFrame *frame, MythPlayer *pipplayer, 01088 PIPLocation loc) 01089 { 01090 (void) frame; 01091 if (!pipplayer || !m_render) 01092 return; 01093 01094 int pipw, piph; 01095 VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph); 01096 const bool pipActive = pipplayer->IsPIPActive(); 01097 const bool pipVisible = pipplayer->IsPIPVisible(); 01098 const float pipVideoAspect = pipplayer->GetVideoAspect(); 01099 const QSize pipVideoDim = pipplayer->GetVideoBufferSize(); 01100 01101 if ((pipVideoAspect <= 0) || !pipimage || 01102 !pipimage->buf || pipimage->codec != FMT_YV12 || !pipVisible) 01103 { 01104 pipplayer->ReleaseCurrentFrame(pipimage); 01105 return; 01106 } 01107 01108 if (InitPIPLayer(window.GetDisplayVisibleRect().size())) 01109 { 01110 if (m_pips.contains(pipplayer) && 01111 m_pips[pipplayer].videoSize != pipVideoDim) 01112 RemovePIP(pipplayer); 01113 01114 if (!m_pips.contains(pipplayer)) 01115 { 01116 uint mixer = m_render->CreateVideoMixer(pipVideoDim, 0, 0); 01117 uint surf = m_render->CreateVideoSurface(pipVideoDim); 01118 vdpauPIP tmp = { pipVideoDim, surf, mixer}; 01119 m_pips.insert(pipplayer, tmp); 01120 if (!mixer || !surf) 01121 RemovePIP(pipplayer); 01122 else 01123 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Created pip %1x%2") 01124 .arg(pipVideoDim.width()).arg(pipVideoDim.height())); 01125 } 01126 01127 if (m_pips.contains(pipplayer)) 01128 { 01129 QRect rect = GetPIPRect(loc, pipplayer); 01130 01131 if (!m_pip_ready) 01132 m_render->DrawBitmap(0, m_pip_surface, NULL, NULL, 01133 kVDPBlendNull); 01134 01135 uint32_t pitches[] = { 01136 pipimage->pitches[0], 01137 pipimage->pitches[2], 01138 pipimage->pitches[1] }; 01139 void* const planes[] = { 01140 pipimage->buf, 01141 pipimage->buf + pipimage->offsets[2], 01142 pipimage->buf + pipimage->offsets[1] }; 01143 01144 bool ok; 01145 ok = m_render->UploadYUVFrame(m_pips[pipplayer].videoSurface, 01146 planes, pitches); 01147 ok &= m_render->MixAndRend(m_pips[pipplayer].videoMixer, 01148 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME, 01149 m_pips[pipplayer].videoSurface, 01150 m_pip_surface, NULL, false, 01151 QRect(QPoint(0,0), pipVideoDim), 01152 rect, rect); 01153 ok &= m_render->DrawBitmap(0, m_pip_surface, NULL, &rect, 01154 kVDPBlendPiP, 255); 01155 01156 if (pipActive) 01157 { 01158 // TODO this could be one rect rendered before the video frame 01159 QRect l = QRect(QPoint(rect.x() - 10, rect.y() - 10), 01160 QSize(10, rect.height() + 20)); 01161 QRect t = QRect(QPoint(rect.x(), rect.y() - 10), 01162 QSize(rect.width(), 10)); 01163 QRect b = QRect(QPoint(rect.x(), rect.y() + rect.height()), 01164 QSize(rect.width(), 10)); 01165 QRect r = QRect(QPoint(rect.x() + rect.width(), rect.y() -10), 01166 QSize(10, rect.height() + 20)); 01167 m_render->DrawBitmap(0, m_pip_surface, NULL, &l, kVDPBlendNormal, 255, 127); 01168 m_render->DrawBitmap(0, m_pip_surface, NULL, &t, kVDPBlendNormal, 255, 127); 01169 m_render->DrawBitmap(0, m_pip_surface, NULL, &b, kVDPBlendNormal, 255, 127); 01170 m_render->DrawBitmap(0, m_pip_surface, NULL, &r, kVDPBlendNormal, 255, 127); 01171 } 01172 01173 m_pip_ready = ok; 01174 } 01175 } 01176 pipplayer->ReleaseCurrentFrame(pipimage); 01177 } 01178 01179 void VideoOutputVDPAU::RemovePIP(MythPlayer *pipplayer) 01180 { 01181 if (!m_pips.contains(pipplayer)) 01182 return; 01183 01184 if (m_pips[pipplayer].videoSurface && m_render) 01185 m_render->DestroyVideoSurface(m_pips[pipplayer].videoSurface); 01186 01187 if (m_pips[pipplayer].videoMixer) 01188 m_render->DestroyVideoMixer(m_pips[pipplayer].videoMixer); 01189 01190 m_pips.remove(pipplayer); 01191 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Removed 1 PIP"); 01192 01193 if (m_pips.empty()) 01194 DeinitPIPLayer(); 01195 } 01196 01197 void VideoOutputVDPAU::ParseOptions(void) 01198 { 01199 m_skip_chroma = false; 01200 m_denoise = 0.0f; 01201 m_sharpen = 0.0f; 01202 m_colorspace = VDP_COLOR_STANDARD_ITUR_BT_601; 01203 m_mixer_features = kVDPFeatNone; 01204 01205 m_decoder_buffer_size = MAX_REFERENCE_FRAMES; 01206 m_process_buffer_size = DEF_PROCESS_BUFFER; 01207 if (codec_is_vdpau(video_codec_id)) 01208 m_decoder_buffer_size = MIN_REFERENCE_FRAMES; 01209 01210 QStringList list = GetFilters().split(","); 01211 if (list.empty()) 01212 return; 01213 01214 for (QStringList::Iterator i = list.begin(); i != list.end(); ++i) 01215 { 01216 QString name = (*i).section('=', 0, 0).toLower(); 01217 QString opts = (*i).section('=', 1).toLower(); 01218 01219 if (!name.contains("vdpau")) 01220 continue; 01221 01222 if (name.contains("vdpaubuffercount")) 01223 { 01224 uint num = opts.toUInt(); 01225 if (MIN_PROCESS_BUFFER <= num && num <= MAX_PROCESS_BUFFER) 01226 { 01227 LOG(VB_PLAYBACK, LOG_INFO, LOC + 01228 QString("VDPAU process buffer size set to %1 (was %2)") 01229 .arg(num).arg(m_process_buffer_size)); 01230 m_process_buffer_size = num; 01231 } 01232 } 01233 else if (name.contains("vdpauivtc")) 01234 { 01235 LOG(VB_PLAYBACK, LOG_INFO, LOC + 01236 "Enabling VDPAU inverse telecine " 01237 "(requires Basic or Advanced deinterlacer)"); 01238 m_mixer_features |= kVDPFeatIVTC; 01239 } 01240 else if (name.contains("vdpauskipchroma")) 01241 { 01242 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Enabling SkipChromaDeinterlace."); 01243 m_skip_chroma = true; 01244 } 01245 else if (name.contains("vdpaudenoise")) 01246 { 01247 float tmp = std::max(0.0f, std::min(1.0f, opts.toFloat())); 01248 if (tmp != 0.0) 01249 { 01250 LOG(VB_PLAYBACK, LOG_INFO, LOC + 01251 QString("VDPAU Denoise %1").arg(tmp,4,'f',2,'0')); 01252 m_denoise = tmp; 01253 m_mixer_features |= kVDPFeatDenoise; 01254 } 01255 } 01256 else if (name.contains("vdpausharpen")) 01257 { 01258 float tmp = std::max(-1.0f, std::min(1.0f, opts.toFloat())); 01259 if (tmp != 0.0) 01260 { 01261 LOG(VB_PLAYBACK, LOG_INFO, LOC + 01262 QString("VDPAU Sharpen %1").arg(tmp,4,'f',2,'0')); 01263 m_sharpen = tmp; 01264 m_mixer_features |= kVDPFeatSharpness; 01265 } 01266 } 01267 else if (name.contains("vdpaucolorspace")) 01268 { 01269 if (opts.contains("auto")) 01270 m_colorspace = -1; 01271 else if (opts.contains("601")) 01272 m_colorspace = VDP_COLOR_STANDARD_ITUR_BT_601; 01273 else if (opts.contains("709")) 01274 m_colorspace = VDP_COLOR_STANDARD_ITUR_BT_709; 01275 01276 if (m_colorspace > -1) 01277 { 01278 LOG(VB_PLAYBACK, LOG_INFO, LOC + 01279 QString("Forcing ITU BT.%1 colorspace") 01280 .arg((m_colorspace == VDP_COLOR_STANDARD_ITUR_BT_601) ? 01281 "BT.601" : "BT.709")); 01282 } 01283 } 01284 else if (name.contains("vdpauhqscaling")) 01285 { 01286 m_mixer_features |= kVDPFeatHQScaling; 01287 LOG(VB_PLAYBACK, LOG_INFO, LOC + 01288 "Requesting high quality scaling."); 01289 } 01290 } 01291 } 01292 01293 MythPainter *VideoOutputVDPAU::GetOSDPainter(void) 01294 { 01295 return m_osd_painter; 01296 } 01297 01298 bool VideoOutputVDPAU::GetScreenShot(int width, int height, QString filename) 01299 { 01300 if (m_render) 01301 return m_render->GetScreenShot(width, height, filename); 01302 return false; 01303 } 01304 01305 QStringList VideoOutputVDPAU::GetVisualiserList(void) 01306 { 01307 if (m_render) 01308 return VideoVisual::GetVisualiserList(m_render->Type()); 01309 return VideoOutput::GetVisualiserList(); 01310 }
1.7.6.1