2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
24 #include "windowing/WindowingFactory.h"
26 #include "guilib/GraphicContext.h"
27 #include "guilib/TextureManager.h"
28 #include "cores/VideoRenderers/RenderManager.h"
29 #include "DVDVideoCodecFFmpeg.h"
31 #include "settings/Settings.h"
32 #include "settings/AdvancedSettings.h"
33 #include "settings/MediaSettings.h"
34 #include "Application.h"
35 #include "utils/MathUtils.h"
36 #include "utils/TimeUtils.h"
37 #include "DVDCodecs/DVDCodecUtils.h"
38 #include "cores/VideoRenderers/RenderFlags.h"
40 using namespace VDPAU;
41 #define NUM_RENDER_PICS 7
42 #define NUM_CROP_PIX 3
44 #define ARSIZE(x) (sizeof(x) / sizeof((x)[0]))
46 // settings codecs mapping
47 DVDCodecAvailableType g_vdpau_available[] = {
48 { AV_CODEC_ID_H263, "videoplayer.usevdpaumpeg4" },
49 { AV_CODEC_ID_MPEG4, "videoplayer.usevdpaumpeg4" },
50 { AV_CODEC_ID_WMV3, "videoplayer.usevdpauvc1" },
51 { AV_CODEC_ID_VC1, "videoplayer.usevdpauvc1" },
52 { AV_CODEC_ID_MPEG2VIDEO, "videoplayer.usevdpaumpeg2" },
54 const size_t settings_count = sizeof(g_vdpau_available) / sizeof(DVDCodecAvailableType);
56 CDecoder::Desc decoder_profiles[] = {
57 {"MPEG1", VDP_DECODER_PROFILE_MPEG1},
58 {"MPEG2_SIMPLE", VDP_DECODER_PROFILE_MPEG2_SIMPLE},
59 {"MPEG2_MAIN", VDP_DECODER_PROFILE_MPEG2_MAIN},
60 {"H264_BASELINE",VDP_DECODER_PROFILE_H264_BASELINE},
61 {"H264_MAIN", VDP_DECODER_PROFILE_H264_MAIN},
62 {"H264_HIGH", VDP_DECODER_PROFILE_H264_HIGH},
63 {"VC1_SIMPLE", VDP_DECODER_PROFILE_VC1_SIMPLE},
64 {"VC1_MAIN", VDP_DECODER_PROFILE_VC1_MAIN},
65 {"VC1_ADVANCED", VDP_DECODER_PROFILE_VC1_ADVANCED},
66 {"MPEG4_PART2_ASP", VDP_DECODER_PROFILE_MPEG4_PART2_ASP},
68 const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CDecoder::Desc);
70 static struct SInterlaceMapping
72 const EINTERLACEMETHOD method;
73 const VdpVideoMixerFeature feature;
74 } g_interlace_mapping[] =
75 { {VS_INTERLACEMETHOD_VDPAU_TEMPORAL , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
76 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
77 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
78 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
79 , {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE}
80 , {VS_INTERLACEMETHOD_NONE , (VdpVideoMixerFeature)-1}
83 static float studioCSCKCoeffs601[3] = {0.299, 0.587, 0.114}; //BT601 {Kr, Kg, Kb}
84 static float studioCSCKCoeffs709[3] = {0.2126, 0.7152, 0.0722}; //BT709 {Kr, Kg, Kb}
86 //-----------------------------------------------------------------------------
87 //-----------------------------------------------------------------------------
89 CVDPAUContext *CVDPAUContext::m_context = 0;
90 CCriticalSection CVDPAUContext::m_section;
91 Display *CVDPAUContext::m_display = 0;
92 void *CVDPAUContext::m_dlHandle = 0;
94 CVDPAUContext::CVDPAUContext()
100 void CVDPAUContext::Release()
102 CSingleLock lock(m_section);
113 void CVDPAUContext::Close()
115 CLog::Log(LOGNOTICE, "VDPAU::Close - closing decoder context");
119 bool CVDPAUContext::EnsureContext(CVDPAUContext **ctx)
121 CSingleLock lock(m_section);
125 m_context->m_refCount++;
130 m_context = new CVDPAUContext();
133 CSingleLock gLock(g_graphicsContext);
134 if (!m_context->LoadSymbols() || !m_context->CreateContext())
143 m_context->m_refCount++;
149 VDPAU_procs& CVDPAUContext::GetProcs()
154 VdpVideoMixerFeature* CVDPAUContext::GetFeatures()
156 return m_vdpFeatures;
159 int CVDPAUContext::GetFeatureCount()
161 return m_featureCount;
164 bool CVDPAUContext::LoadSymbols()
168 m_dlHandle = dlopen("libvdpau.so.1", RTLD_LAZY);
171 const char* error = dlerror();
173 error = "dlerror() returned NULL";
175 CLog::Log(LOGERROR,"VDPAU::LoadSymbols: Unable to get handle to lib: %s", error);
182 dl_vdp_device_create_x11 = (VdpStatus (*)(Display*, int, VdpDevice*, VdpStatus (**)(VdpDevice, VdpFuncId, void**)))dlsym(m_dlHandle, (const char*)"vdp_device_create_x11");
186 CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__);
187 m_vdpDevice = VDP_INVALID_HANDLE;
193 bool CVDPAUContext::CreateContext()
195 CLog::Log(LOGNOTICE,"VDPAU::CreateContext - creating decoder context");
198 { CSingleLock lock(g_graphicsContext);
200 m_display = XOpenDisplay(NULL);
201 mScreen = g_Windowing.GetCurrentScreen();
206 vdp_st = dl_vdp_device_create_x11(m_display,
209 &m_vdpProcs.vdp_get_proc_address);
211 CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",m_vdpDevice,vdp_st);
212 if (vdp_st != VDP_STATUS_OK)
214 CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x. Falling back.",vdp_st);
215 m_vdpDevice = VDP_INVALID_HANDLE;
220 SpewHardwareAvailable();
224 void CVDPAUContext::QueryProcs()
228 #define VDP_PROC(id, proc) \
230 vdp_st = m_vdpProcs.vdp_get_proc_address(m_vdpDevice, id, (void**)&proc); \
231 if (vdp_st != VDP_STATUS_OK) \
233 CLog::Log(LOGERROR, "CVDPAUContext::GetProcs - failed to get proc id"); \
237 VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING , m_vdpProcs.vdp_get_error_string);
238 VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY , m_vdpProcs.vdp_device_destroy);
239 VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX , m_vdpProcs.vdp_generate_csc_matrix);
240 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE , m_vdpProcs.vdp_video_surface_create);
241 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , m_vdpProcs.vdp_video_surface_destroy);
242 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , m_vdpProcs.vdp_video_surface_put_bits_y_cb_cr);
243 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , m_vdpProcs.vdp_video_surface_get_bits_y_cb_cr);
244 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , m_vdpProcs.vdp_output_surface_put_bits_y_cb_cr);
245 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , m_vdpProcs.vdp_output_surface_put_bits_native);
246 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , m_vdpProcs.vdp_output_surface_create);
247 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , m_vdpProcs.vdp_output_surface_destroy);
248 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , m_vdpProcs.vdp_output_surface_get_bits_native);
249 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, m_vdpProcs.vdp_output_surface_render_output_surface);
250 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , m_vdpProcs.vdp_output_surface_put_bits_indexed);
251 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE , m_vdpProcs.vdp_video_mixer_create);
252 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , m_vdpProcs.vdp_video_mixer_set_feature_enables);
253 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY , m_vdpProcs.vdp_video_mixer_destroy);
254 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER , m_vdpProcs.vdp_video_mixer_render);
255 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , m_vdpProcs.vdp_video_mixer_set_attribute_values);
256 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , m_vdpProcs.vdp_video_mixer_query_parameter_support);
257 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , m_vdpProcs.vdp_video_mixer_query_feature_support);
258 VDP_PROC(VDP_FUNC_ID_DECODER_CREATE , m_vdpProcs.vdp_decoder_create);
259 VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY , m_vdpProcs.vdp_decoder_destroy);
260 VDP_PROC(VDP_FUNC_ID_DECODER_RENDER , m_vdpProcs.vdp_decoder_render);
261 VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , m_vdpProcs.vdp_decoder_query_caps);
265 VdpDevice CVDPAUContext::GetDevice()
270 void CVDPAUContext::DestroyContext()
272 if (!m_vdpProcs.vdp_device_destroy)
275 m_vdpProcs.vdp_device_destroy(m_vdpDevice);
276 m_vdpDevice = VDP_INVALID_HANDLE;
279 void CVDPAUContext::SpewHardwareAvailable() //CopyrighVDPAUt (c) 2008 Wladimir J. van der Laan -- VDPInfo
282 CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:");
283 CLog::Log(LOGNOTICE,"name level macbs width height");
284 CLog::Log(LOGNOTICE,"------------------------------------");
285 for(unsigned int x=0; x<decoder_profile_count; ++x)
287 VdpBool is_supported = false;
288 uint32_t max_level, max_macroblocks, max_width, max_height;
289 rv = m_vdpProcs.vdp_decoder_query_caps(m_vdpDevice, decoder_profiles[x].id,
290 &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
291 if(rv == VDP_STATUS_OK && is_supported)
293 CLog::Log(LOGNOTICE,"%-16s %2i %5i %5i %5i\n", decoder_profiles[x].name,
294 max_level, max_macroblocks, max_width, max_height);
297 CLog::Log(LOGNOTICE,"------------------------------------");
299 #define CHECK_SUPPORT(feature) \
302 if(m_vdpProcs.vdp_video_mixer_query_feature_support(m_vdpDevice, feature, &supported) == VDP_STATUS_OK && supported) { \
303 CLog::Log(LOGNOTICE, "Mixer feature: "#feature); \
304 m_vdpFeatures[m_featureCount++] = feature; \
308 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION);
309 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_SHARPNESS);
310 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL);
311 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL);
312 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE);
313 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
314 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1);
315 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2);
316 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3);
317 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4);
318 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5);
319 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6);
320 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7);
321 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8);
322 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9);
327 bool CVDPAUContext::Supports(VdpVideoMixerFeature feature)
329 for(int i = 0; i < m_featureCount; i++)
331 if(m_vdpFeatures[i] == feature)
337 //-----------------------------------------------------------------------------
338 // VDPAU Video Surface states
339 //-----------------------------------------------------------------------------
341 #define SURFACE_USED_FOR_REFERENCE 0x01
342 #define SURFACE_USED_FOR_RENDER 0x02
344 void CVideoSurfaces::AddSurface(VdpVideoSurface surf)
346 CSingleLock lock(m_section);
347 m_state[surf] = SURFACE_USED_FOR_REFERENCE;
350 void CVideoSurfaces::ClearReference(VdpVideoSurface surf)
352 CSingleLock lock(m_section);
353 if (m_state.find(surf) == m_state.end())
355 CLog::Log(LOGWARNING, "CVideoSurfaces::ClearReference - surface invalid");
358 m_state[surf] &= ~SURFACE_USED_FOR_REFERENCE;
359 if (m_state[surf] == 0)
361 m_freeSurfaces.push_back(surf);
365 bool CVideoSurfaces::MarkRender(VdpVideoSurface surf)
367 CSingleLock lock(m_section);
368 if (m_state.find(surf) == m_state.end())
370 CLog::Log(LOGWARNING, "CVideoSurfaces::MarkRender - surface invalid");
373 std::list<VdpVideoSurface>::iterator it;
374 it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
375 if (it != m_freeSurfaces.end())
377 m_freeSurfaces.erase(it);
379 m_state[surf] |= SURFACE_USED_FOR_RENDER;
383 void CVideoSurfaces::ClearRender(VdpVideoSurface surf)
385 CSingleLock lock(m_section);
386 if (m_state.find(surf) == m_state.end())
388 CLog::Log(LOGWARNING, "CVideoSurfaces::ClearRender - surface invalid");
391 m_state[surf] &= ~SURFACE_USED_FOR_RENDER;
392 if (m_state[surf] == 0)
394 m_freeSurfaces.push_back(surf);
398 bool CVideoSurfaces::IsValid(VdpVideoSurface surf)
400 CSingleLock lock(m_section);
401 if (m_state.find(surf) != m_state.end())
407 VdpVideoSurface CVideoSurfaces::GetFree(VdpVideoSurface surf)
409 CSingleLock lock(m_section);
410 if (m_state.find(surf) != m_state.end())
412 std::list<VdpVideoSurface>::iterator it;
413 it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
414 if (it == m_freeSurfaces.end())
416 CLog::Log(LOGWARNING, "CVideoSurfaces::GetFree - surface not free");
420 m_freeSurfaces.erase(it);
421 m_state[surf] = SURFACE_USED_FOR_REFERENCE;
426 if (!m_freeSurfaces.empty())
428 VdpVideoSurface freeSurf = m_freeSurfaces.front();
429 m_freeSurfaces.pop_front();
430 m_state[freeSurf] = SURFACE_USED_FOR_REFERENCE;
434 return VDP_INVALID_HANDLE;
437 VdpVideoSurface CVideoSurfaces::GetAtIndex(int idx)
439 if (idx >= m_state.size())
440 return VDP_INVALID_HANDLE;
442 std::map<VdpVideoSurface, int>::iterator it = m_state.begin();
443 for(int i = 0; i < idx; i++)
448 VdpVideoSurface CVideoSurfaces::RemoveNext(bool skiprender)
450 CSingleLock lock(m_section);
451 VdpVideoSurface surf;
452 std::map<VdpVideoSurface, int>::iterator it;
453 for(it = m_state.begin(); it != m_state.end(); ++it)
455 if (skiprender && it->second & SURFACE_USED_FOR_RENDER)
460 std::list<VdpVideoSurface>::iterator it2;
461 it2 = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
462 if (it2 != m_freeSurfaces.end())
463 m_freeSurfaces.erase(it2);
466 return VDP_INVALID_HANDLE;
469 void CVideoSurfaces::Reset()
471 CSingleLock lock(m_section);
472 m_freeSurfaces.clear();
476 int CVideoSurfaces::Size()
478 CSingleLock lock(m_section);
479 return m_state.size();
482 //-----------------------------------------------------------------------------
484 //-----------------------------------------------------------------------------
486 CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent)
488 m_vdpauConfig.videoSurfaces = &m_videoSurfaces;
490 m_vdpauConfigured = false;
491 m_hwContext.bitstream_buffers_allocated = 0;
492 m_DisplayState = VDPAU_OPEN;
493 m_vdpauConfig.context = 0;
496 bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned int surfaces)
498 // check if user wants to decode this format with VDPAU
499 std::string gpuvendor = g_Windowing.GetRenderVendor();
500 std::transform(gpuvendor.begin(), gpuvendor.end(), gpuvendor.begin(), ::tolower);
501 // nvidia is whitelisted despite for mpeg-4 we need to query user settings
502 if ((gpuvendor.compare(0, 6, "nvidia") != 0) || (avctx->codec_id == AV_CODEC_ID_MPEG4) || (avctx->codec_id == AV_CODEC_ID_H263))
504 if (CDVDVideoCodec::IsCodecDisabled(g_vdpau_available, settings_count, avctx->codec_id))
508 #ifndef GL_NV_vdpau_interop
509 CLog::Log(LOGNOTICE, "VDPAU: compilation without required extension GL_NV_vdpau_interop");
512 if (!g_Windowing.IsExtSupported("GL_NV_vdpau_interop"))
514 CLog::Log(LOGNOTICE, "VDPAU::Open: required extension GL_NV_vdpau_interop not found");
518 if(avctx->coded_width == 0
519 || avctx->coded_height == 0)
521 CLog::Log(LOGWARNING,"VDPAU::Open: no width/height available, can't init");
524 m_vdpauConfig.numRenderBuffers = surfaces;
525 m_decoderThread = CThread::GetCurrentThreadId();
527 if (!CVDPAUContext::EnsureContext(&m_vdpauConfig.context))
530 m_DisplayState = VDPAU_OPEN;
531 m_vdpauConfigured = false;
533 if (!m_dllAvUtil.Load())
536 m_presentPicture = 0;
539 VdpDecoderProfile profile = 0;
541 // convert FFMPEG codec ID to VDPAU profile.
542 ReadFormatOf(avctx->codec_id, profile, m_vdpauConfig.vdpChromaType);
546 VdpBool is_supported = false;
547 uint32_t max_level, max_macroblocks, max_width, max_height;
549 // query device capabilities to ensure that VDPAU can handle the requested codec
550 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_query_caps(m_vdpauConfig.context->GetDevice(),
551 profile, &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
553 // test to make sure there is a possibility the codec will work
554 if (CheckStatus(vdp_st, __LINE__))
556 CLog::Log(LOGERROR, "VDPAU::Open: error %s(%d) checking for decoder support", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st);
560 if (max_width < avctx->coded_width || max_height < avctx->coded_height)
562 CLog::Log(LOGWARNING,"VDPAU::Open: requested picture dimensions (%i, %i) exceed hardware capabilities ( %i, %i).",
563 avctx->coded_width, avctx->coded_height, max_width, max_height);
567 if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width))
568 CLog::Log(LOGWARNING,"VDPAU::Open width %i might not be supported because of hardware bug", avctx->width);
570 // attempt to create a decoder with this width/height, some sizes are not supported by hw
571 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_create(m_vdpauConfig.context->GetDevice(), profile, avctx->coded_width, avctx->coded_height, 5, &m_vdpauConfig.vdpDecoder);
573 if (CheckStatus(vdp_st, __LINE__))
575 CLog::Log(LOGERROR, "VDPAU::Open: error: %s(%d) checking for decoder support", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st);
579 m_vdpauConfig.context->GetProcs().vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
580 CheckStatus(vdp_st, __LINE__);
582 // finally setup ffmpeg
583 memset(&m_hwContext, 0, sizeof(AVVDPAUContext));
584 m_hwContext.render = CDecoder::Render;
585 m_hwContext.bitstream_buffers_allocated = 0;
586 avctx->get_buffer = CDecoder::FFGetBuffer;
587 avctx->reget_buffer = CDecoder::FFGetBuffer;
588 avctx->release_buffer = CDecoder::FFReleaseBuffer;
589 avctx->draw_horiz_band = CDecoder::FFDrawSlice;
590 avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
591 avctx->hwaccel_context = &m_hwContext;
592 avctx->thread_count = 1;
594 g_Windowing.Register(this);
601 CDecoder::~CDecoder()
606 void CDecoder::Close()
608 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
610 g_Windowing.Unregister(this);
612 CSingleLock lock(m_DecoderSection);
615 m_vdpauOutput.Dispose();
617 if (m_hwContext.bitstream_buffers_allocated)
619 m_dllAvUtil.av_freep(&m_hwContext.bitstream_buffers);
622 m_dllAvUtil.Unload();
624 if (m_vdpauConfig.context)
625 m_vdpauConfig.context->Release();
626 m_vdpauConfig.context = 0;
629 long CDecoder::Release()
631 // check if we should do some pre-cleanup here
632 // a second decoder might need resources
633 if (m_vdpauConfigured == true)
635 CSingleLock lock(m_DecoderSection);
636 CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup");
639 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP,
643 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
647 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup returned error", __FUNCTION__);
648 m_DisplayState = VDPAU_ERROR;
653 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup timed out", __FUNCTION__);
654 m_DisplayState = VDPAU_ERROR;
657 VdpVideoSurface surf;
658 while((surf = m_videoSurfaces.RemoveNext(true)) != VDP_INVALID_HANDLE)
660 m_vdpauConfig.context->GetProcs().vdp_video_surface_destroy(surf);
663 return IHardwareDecoder::Release();
666 long CDecoder::ReleasePicReference()
668 return IHardwareDecoder::Release();
671 void CDecoder::SetWidthHeight(int width, int height)
673 m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling;
675 //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate
676 //this requires the least amount of gpu memory bandwidth
677 if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || m_vdpauConfig.upscale >= 0)
679 //scale width to desktop size if the aspect ratio is the same or bigger than the desktop
680 if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight())
682 m_vdpauConfig.outWidth = g_graphicsContext.GetWidth();
683 m_vdpauConfig.outHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width);
685 else //scale height to the desktop size if the aspect ratio is smaller than the desktop
687 m_vdpauConfig.outHeight = g_graphicsContext.GetHeight();
688 m_vdpauConfig.outWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height);
693 m_vdpauConfig.outWidth = width;
694 m_vdpauConfig.outHeight = height;
696 CLog::Log(LOGDEBUG, "CVDPAU::SetWidthHeight Setting OutWidth: %i OutHeight: %i", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight);
699 void CDecoder::OnLostDevice()
701 CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event");
703 int count = g_graphicsContext.exit();
705 CSingleLock lock(m_DecoderSection);
707 if (m_vdpauConfig.context)
708 m_vdpauConfig.context->Release();
709 m_vdpauConfig.context = 0;
711 m_DisplayState = VDPAU_LOST;
713 m_DisplayEvent.Reset();
715 g_graphicsContext.restore(count);
718 void CDecoder::OnResetDevice()
720 CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event");
722 int count = g_graphicsContext.exit();
724 CSingleLock lock(m_DecoderSection);
725 if (m_DisplayState == VDPAU_LOST)
727 m_DisplayState = VDPAU_RESET;
729 m_DisplayEvent.Set();
732 g_graphicsContext.restore(count);
735 int CDecoder::Check(AVCodecContext* avctx)
739 { CSingleLock lock(m_DecoderSection);
740 state = m_DisplayState;
743 if (state == VDPAU_LOST)
745 CLog::Log(LOGNOTICE,"CVDPAU::Check waiting for display reset event");
746 if (!m_DisplayEvent.WaitMSec(4000))
748 CLog::Log(LOGERROR, "CVDPAU::Check - device didn't reset in reasonable time");
753 CSingleLock lock(m_DecoderSection);
754 state = m_DisplayState;
757 if (state == VDPAU_RESET || state == VDPAU_ERROR)
759 CSingleLock lock(m_DecoderSection);
762 if (m_vdpauConfig.context)
763 m_vdpauConfig.context->Release();
764 m_vdpauConfig.context = 0;
766 if (CVDPAUContext::EnsureContext(&m_vdpauConfig.context))
768 m_DisplayState = VDPAU_OPEN;
769 m_vdpauConfigured = false;
772 if (state == VDPAU_RESET)
780 bool CDecoder::IsVDPAUFormat(PixelFormat format)
782 if (format == AV_PIX_FMT_VDPAU)
788 bool CDecoder::Supports(VdpVideoMixerFeature feature)
790 return m_vdpauConfig.context->Supports(feature);
793 bool CDecoder::Supports(EINTERLACEMETHOD method)
795 if(method == VS_INTERLACEMETHOD_VDPAU_BOB
796 || method == VS_INTERLACEMETHOD_AUTO)
799 if (method == VS_INTERLACEMETHOD_RENDER_BOB)
802 if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE)
805 for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++)
807 if(p->method == method)
808 return Supports(p->feature);
813 EINTERLACEMETHOD CDecoder::AutoInterlaceMethod()
815 return VS_INTERLACEMETHOD_RENDER_BOB;
818 void CDecoder::FiniVDPAUOutput()
820 if (!m_vdpauConfigured)
823 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
826 m_vdpauOutput.Dispose();
827 m_vdpauConfigured = false;
831 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
832 if (CheckStatus(vdp_st, __LINE__))
834 m_vdpauConfig.vdpDecoder = VDP_INVALID_HANDLE;
836 CLog::Log(LOGDEBUG, "CVDPAU::FiniVDPAUOutput destroying %d video surfaces", m_videoSurfaces.Size());
838 VdpVideoSurface surf;
839 while((surf = m_videoSurfaces.RemoveNext()) != VDP_INVALID_HANDLE)
841 m_vdpauConfig.context->GetProcs().vdp_video_surface_destroy(surf);
842 if (CheckStatus(vdp_st, __LINE__))
845 m_videoSurfaces.Reset();
848 void CDecoder::ReadFormatOf( AVCodecID codec
849 , VdpDecoderProfile &vdp_decoder_profile
850 , VdpChromaType &vdp_chroma_type)
854 case AV_CODEC_ID_MPEG1VIDEO:
855 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
856 vdp_chroma_type = VDP_CHROMA_TYPE_420;
858 case AV_CODEC_ID_MPEG2VIDEO:
859 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
860 vdp_chroma_type = VDP_CHROMA_TYPE_420;
862 case AV_CODEC_ID_H264:
863 vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
864 vdp_chroma_type = VDP_CHROMA_TYPE_420;
866 case AV_CODEC_ID_WMV3:
867 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
868 vdp_chroma_type = VDP_CHROMA_TYPE_420;
870 case AV_CODEC_ID_VC1:
871 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
872 vdp_chroma_type = VDP_CHROMA_TYPE_420;
874 case AV_CODEC_ID_MPEG4:
875 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
876 vdp_chroma_type = VDP_CHROMA_TYPE_420;
879 vdp_decoder_profile = 0;
885 bool CDecoder::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
890 VdpDecoderProfile vdp_decoder_profile;
892 m_vdpauConfig.vidWidth = avctx->width;
893 m_vdpauConfig.vidHeight = avctx->height;
894 m_vdpauConfig.surfaceWidth = avctx->coded_width;
895 m_vdpauConfig.surfaceHeight = avctx->coded_height;
897 SetWidthHeight(avctx->width,avctx->height);
899 CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",m_vdpauConfig.outWidth,m_vdpauConfig.vidWidth,m_vdpauConfig.surfaceWidth);
900 CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",m_vdpauConfig.outHeight,m_vdpauConfig.vidHeight,m_vdpauConfig.surfaceHeight);
902 ReadFormatOf(avctx->codec_id, vdp_decoder_profile, m_vdpauConfig.vdpChromaType);
904 if(avctx->codec_id == AV_CODEC_ID_H264)
906 m_vdpauConfig.maxReferences = ref_frames;
907 if (m_vdpauConfig.maxReferences > 16) m_vdpauConfig.maxReferences = 16;
908 if (m_vdpauConfig.maxReferences < 5) m_vdpauConfig.maxReferences = 5;
911 m_vdpauConfig.maxReferences = 2;
913 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_create(m_vdpauConfig.context->GetDevice(),
915 m_vdpauConfig.surfaceWidth,
916 m_vdpauConfig.surfaceHeight,
917 m_vdpauConfig.maxReferences,
918 &m_vdpauConfig.vdpDecoder);
919 if (CheckStatus(vdp_st, __LINE__))
923 CSingleLock lock(g_graphicsContext);
924 m_vdpauConfig.stats = &m_bufferStats;
925 m_vdpauConfig.vdpau = this;
926 m_bufferStats.Reset();
927 m_vdpauOutput.Start();
929 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT,
933 sizeof(m_vdpauConfig)))
935 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
939 CLog::Log(LOGERROR, "VDPAU::%s - vdpau output returned error", __FUNCTION__);
940 m_vdpauOutput.Dispose();
946 CLog::Log(LOGERROR, "VDPAU::%s - failed to init output", __FUNCTION__);
947 m_vdpauOutput.Dispose();
951 m_inMsgEvent.Reset();
952 m_vdpauConfigured = true;
957 int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
959 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
960 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
961 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
963 // while we are waiting to recover we can't do anything
964 CSingleLock lock(vdp->m_DecoderSection);
966 if(vdp->m_DisplayState != VDPAU_OPEN)
968 CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
972 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
973 surf = vdp->m_videoSurfaces.GetFree(surf != 0 ? surf : VDP_INVALID_HANDLE);
975 VdpStatus vdp_st = VDP_STATUS_ERROR;
976 if (surf == VDP_INVALID_HANDLE)
978 // create a new surface
979 VdpDecoderProfile profile;
980 ReadFormatOf(avctx->codec_id, profile, vdp->m_vdpauConfig.vdpChromaType);
982 vdp_st = vdp->m_vdpauConfig.context->GetProcs().vdp_video_surface_create(vdp->m_vdpauConfig.context->GetDevice(),
983 vdp->m_vdpauConfig.vdpChromaType,
987 vdp->CheckStatus(vdp_st, __LINE__);
988 if (vdp_st != VDP_STATUS_OK)
990 CLog::Log(LOGERROR, "CVDPAU::FFGetBuffer - No Video surface available could be created");
993 vdp->m_videoSurfaces.AddSurface(surf);
996 pic->data[1] = pic->data[2] = NULL;
997 pic->data[0] = (uint8_t*)(uintptr_t)surf;
998 pic->data[3] = (uint8_t*)(uintptr_t)surf;
1000 pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0;
1002 pic->type= FF_BUFFER_TYPE_USER;
1004 pic->reordered_opaque= avctx->reordered_opaque;
1008 void CDecoder::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
1010 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
1011 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
1013 VdpVideoSurface surf;
1016 CSingleLock lock(vdp->m_DecoderSection);
1018 surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
1020 vdp->m_videoSurfaces.ClearReference(surf);
1026 VdpStatus CDecoder::Render( VdpDecoder decoder, VdpVideoSurface target,
1027 VdpPictureInfo const *picture_info,
1028 uint32_t bitstream_buffer_count,
1029 VdpBitstreamBuffer const * bitstream_buffers)
1031 return VDP_STATUS_OK;
1034 void CDecoder::FFDrawSlice(struct AVCodecContext *s,
1035 const AVFrame *src, int offset[4],
1036 int y, int type, int height)
1038 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque;
1039 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
1041 // while we are waiting to recover we can't do anything
1042 CSingleLock lock(vdp->m_DecoderSection);
1044 if(vdp->m_DisplayState != VDPAU_OPEN)
1047 if(src->linesize[0] || src->linesize[1] || src->linesize[2]
1048 || offset[0] || offset[1] || offset[2])
1050 CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid linesizes or offsets provided");
1055 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)src->data[3];
1057 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1058 if (!vdp->m_videoSurfaces.IsValid(surf))
1060 CLog::Log(LOGWARNING, "CVDPAU::FFDrawSlice - ignoring invalid buffer");
1064 uint32_t max_refs = 0;
1065 if(s->codec_id == AV_CODEC_ID_H264)
1066 max_refs = vdp->m_hwContext.info.h264.num_ref_frames;
1068 if(vdp->m_vdpauConfig.vdpDecoder == VDP_INVALID_HANDLE
1069 || vdp->m_vdpauConfigured == false
1070 || vdp->m_vdpauConfig.maxReferences < max_refs)
1072 if(!vdp->ConfigVDPAU(s, max_refs))
1076 uint64_t startTime = CurrentHostCounter();
1077 uint16_t decoded, processed, rend;
1078 vdp->m_bufferStats.Get(decoded, processed, rend);
1079 vdp_st = vdp->m_vdpauConfig.context->GetProcs().vdp_decoder_render(vdp->m_vdpauConfig.vdpDecoder,
1081 (VdpPictureInfo const *)&(vdp->m_hwContext.info),
1082 vdp->m_hwContext.bitstream_buffers_used,
1083 vdp->m_hwContext.bitstream_buffers);
1084 if (vdp->CheckStatus(vdp_st, __LINE__))
1085 vdp->m_DecoderError = true;
1087 vdp->m_DecoderError = false;
1089 uint64_t diff = CurrentHostCounter() - startTime;
1090 if (diff*1000/CurrentHostFrequency() > 30)
1091 CLog::Log(LOGDEBUG, "CVDPAU::DrawSlice - VdpDecoderRender long decoding: %d ms, dec: %d, proc: %d, rend: %d", (int)((diff*1000)/CurrentHostFrequency()), decoded, processed, rend);
1095 int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame)
1097 int result = Check(avctx);
1101 CSingleLock lock(m_DecoderSection);
1103 if (m_DecoderError && pFrame)
1106 if (!m_vdpauConfigured)
1110 { // we have a new frame from decoder
1112 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pFrame->data[3];
1113 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1114 if (!m_videoSurfaces.IsValid(surf))
1116 CLog::Log(LOGWARNING, "CVDPAU::Decode - ignoring invalid buffer");
1119 m_videoSurfaces.MarkRender(surf);
1121 // send frame to output for processing
1122 CVdpauDecodedPicture pic;
1123 memset(&pic.DVDPic, 0, sizeof(pic.DVDPic));
1124 ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic);
1125 pic.videoSurface = surf;
1126 pic.DVDPic.color_matrix = avctx->colorspace;
1127 m_bufferStats.IncDecoded();
1128 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic));
1131 // m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC);
1135 uint16_t decoded, processed, render;
1137 while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1139 if (msg->signal == COutputControlProtocol::ERROR)
1141 m_DisplayState = VDPAU_ERROR;
1147 m_bufferStats.Get(decoded, processed, render);
1149 uint64_t startTime = CurrentHostCounter();
1152 // first fill the buffers to keep vdpau busy
1153 // mixer will run with decoded >= 2. output is limited by number of output surfaces
1154 // In case mixer is bypassed we limit by looking at processed
1155 if (decoded < 3 && processed < 3)
1157 retval |= VC_BUFFER;
1159 else if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg))
1161 if (msg->signal == COutputDataProtocol::PICTURE)
1163 if (m_presentPicture)
1165 m_presentPicture->ReturnUnused();
1166 m_presentPicture = 0;
1169 m_presentPicture = *(CVdpauRenderPicture**)msg->data;
1170 m_presentPicture->vdpau = this;
1171 m_bufferStats.DecRender();
1172 m_bufferStats.Get(decoded, processed, render);
1173 retval |= VC_PICTURE;
1179 else if (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1181 if (msg->signal == COutputControlProtocol::STATS)
1183 m_bufferStats.Get(decoded, processed, render);
1187 m_DisplayState = VDPAU_ERROR;
1193 if (decoded < 3 && processed < 3)
1195 retval |= VC_BUFFER;
1198 if (!retval && !m_inMsgEvent.WaitMSec(2000))
1201 uint64_t diff = CurrentHostCounter() - startTime;
1202 if (retval & VC_PICTURE)
1204 m_bufferStats.SetParams(diff, m_codecControl);
1206 if (diff*1000/CurrentHostFrequency() > 50)
1207 CLog::Log(LOGDEBUG,"CVDPAU::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency()));
1211 CLog::Log(LOGERROR, "VDPAU::%s - timed out waiting for output message", __FUNCTION__);
1212 m_DisplayState = VDPAU_ERROR;
1219 bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
1221 CSingleLock lock(m_DecoderSection);
1223 if (m_DisplayState != VDPAU_OPEN)
1226 *picture = m_presentPicture->DVDPic;
1227 picture->vdpau = m_presentPicture;
1232 void CDecoder::Reset()
1234 CSingleLock lock(m_DecoderSection);
1236 if (!m_vdpauConfigured)
1240 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH,
1244 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
1248 CLog::Log(LOGERROR, "VDPAU::%s - flush returned error", __FUNCTION__);
1249 m_DisplayState = VDPAU_ERROR;
1252 m_bufferStats.Reset();
1256 CLog::Log(LOGERROR, "VDPAU::%s - flush timed out", __FUNCTION__);
1257 m_DisplayState = VDPAU_ERROR;
1261 bool CDecoder::CanSkipDeint()
1263 return m_bufferStats.CanSkipDeint();
1266 void CDecoder::ReturnRenderPicture(CVdpauRenderPicture *renderPic)
1268 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic));
1271 bool CDecoder::CheckStatus(VdpStatus vdp_st, int line)
1273 if (vdp_st != VDP_STATUS_OK)
1275 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
1279 if(m_DisplayState == VDPAU_OPEN)
1281 if (vdp_st == VDP_STATUS_DISPLAY_PREEMPTED)
1283 m_DisplayEvent.Reset();
1284 m_DisplayState = VDPAU_LOST;
1286 else if (m_ErrorCount > 2)
1287 m_DisplayState = VDPAU_ERROR;
1296 //-----------------------------------------------------------------------------
1298 //-----------------------------------------------------------------------------
1300 CVdpauRenderPicture* CVdpauRenderPicture::Acquire()
1302 CSingleLock lock(renderPicSection);
1311 long CVdpauRenderPicture::Release()
1313 CSingleLock lock(renderPicSection);
1320 vdpau->ReturnRenderPicture(this);
1321 vdpau->ReleasePicReference();
1326 void CVdpauRenderPicture::ReturnUnused()
1328 { CSingleLock lock(renderPicSection);
1333 vdpau->ReturnRenderPicture(this);
1336 void CVdpauRenderPicture::Sync()
1339 CSingleLock lock(renderPicSection);
1344 glDeleteSync(fence);
1347 fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1352 //-----------------------------------------------------------------------------
1354 //-----------------------------------------------------------------------------
1355 CMixer::CMixer(CEvent *inMsgEvent) :
1356 CThread("Vdpau Mixer"),
1357 m_controlPort("ControlPort", inMsgEvent, &m_outMsgEvent),
1358 m_dataPort("DataPort", inMsgEvent, &m_outMsgEvent)
1360 m_inMsgEvent = inMsgEvent;
1368 void CMixer::Start()
1373 void CMixer::Dispose()
1376 m_outMsgEvent.Set();
1379 m_controlPort.Purge();
1383 bool CMixer::IsActive()
1388 void CMixer::OnStartup()
1390 CLog::Log(LOGNOTICE, "CMixer::OnStartup: Output Thread created");
1393 void CMixer::OnExit()
1395 CLog::Log(LOGNOTICE, "CMixer::OnExit: Output Thread terminated");
1402 M_TOP_UNCONFIGURED, // 2
1403 M_TOP_CONFIGURED, // 3
1404 M_TOP_CONFIGURED_WAIT1, // 4
1405 M_TOP_CONFIGURED_STEP1, // 5
1406 M_TOP_CONFIGURED_WAIT2, // 6
1407 M_TOP_CONFIGURED_STEP2, // 7
1410 int MIXER_parentStates[] = {
1413 0, //TOP_UNCONFIGURED
1415 3, //TOP_CONFIGURED_WAIT1
1416 3, //TOP_CONFIGURED_STEP1
1417 3, //TOP_CONFIGURED_WAIT2
1418 3, //TOP_CONFIGURED_STEP2
1421 void CMixer::StateMachine(int signal, Protocol *port, Message *msg)
1423 for (int state = m_state; ; state = MIXER_parentStates[state])
1428 if (port == &m_controlPort)
1432 case CMixerControlProtocol::FLUSH:
1434 msg->Reply(CMixerControlProtocol::ACC);
1441 std::string portName = port == NULL ? "timer" : port->portName;
1442 CLog::Log(LOGWARNING, "CMixer::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
1446 case M_TOP_ERROR: // TOP
1449 case M_TOP_UNCONFIGURED:
1450 if (port == &m_controlPort)
1454 case CMixerControlProtocol::INIT:
1456 data = (CVdpauConfig*)msg->data;
1464 m_state = M_TOP_CONFIGURED_WAIT1;
1465 msg->Reply(CMixerControlProtocol::ACC);
1469 msg->Reply(CMixerControlProtocol::ERROR);
1478 case M_TOP_CONFIGURED:
1479 if (port == &m_dataPort)
1483 case CMixerDataProtocol::FRAME:
1484 CVdpauDecodedPicture *frame;
1485 frame = (CVdpauDecodedPicture*)msg->data;
1488 m_decodedPics.push(*frame);
1492 case CMixerDataProtocol::BUFFER:
1493 VdpOutputSurface *surf;
1494 surf = (VdpOutputSurface*)msg->data;
1497 m_outputSurfaces.push(*surf);
1507 case M_TOP_CONFIGURED_WAIT1:
1508 if (port == NULL) // timeout
1512 case CMixerControlProtocol::TIMEOUT:
1513 if (!m_decodedPics.empty() && !m_outputSurfaces.empty())
1515 m_state = M_TOP_CONFIGURED_STEP1;
1516 m_bStateMachineSelfTrigger = true;
1529 case M_TOP_CONFIGURED_STEP1:
1530 if (port == NULL) // timeout
1534 case CMixerControlProtocol::TIMEOUT:
1535 m_mixerInput.push_front(m_decodedPics.front());
1536 m_decodedPics.pop();
1537 if (m_mixerInput.size() < 2)
1539 m_state = M_TOP_CONFIGURED_WAIT1;
1547 m_state = M_TOP_CONFIGURED_WAIT1;
1548 m_extTimeout = 1000;
1551 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1552 m_outputSurfaces.pop();
1553 m_config.stats->IncProcessed();
1554 m_config.stats->DecDecoded();
1555 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1556 if (m_mixersteps > 1)
1558 m_state = M_TOP_CONFIGURED_WAIT2;
1564 m_state = M_TOP_CONFIGURED_WAIT1;
1574 case M_TOP_CONFIGURED_WAIT2:
1575 if (port == NULL) // timeout
1579 case CMixerControlProtocol::TIMEOUT:
1580 if (!m_outputSurfaces.empty())
1582 m_state = M_TOP_CONFIGURED_STEP2;
1583 m_bStateMachineSelfTrigger = true;
1596 case M_TOP_CONFIGURED_STEP2:
1597 if (port == NULL) // timeout
1601 case CMixerControlProtocol::TIMEOUT:
1602 m_processPicture.outputSurface = m_outputSurfaces.front();
1607 m_state = M_TOP_CONFIGURED_WAIT1;
1608 m_extTimeout = 1000;
1611 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1612 m_outputSurfaces.pop();
1613 m_config.stats->IncProcessed();
1614 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1616 m_state = M_TOP_CONFIGURED_WAIT1;
1625 default: // we are in no state, should not happen
1626 CLog::Log(LOGERROR, "CMixer::%s - no valid state: %d", __FUNCTION__, m_state);
1632 void CMixer::Process()
1634 Message *msg = NULL;
1635 Protocol *port = NULL;
1638 m_state = M_TOP_UNCONFIGURED;
1639 m_extTimeout = 1000;
1640 m_bStateMachineSelfTrigger = false;
1646 if (m_bStateMachineSelfTrigger)
1648 m_bStateMachineSelfTrigger = false;
1649 // self trigger state machine
1650 StateMachine(msg->signal, port, msg);
1651 if (!m_bStateMachineSelfTrigger)
1658 // check control port
1659 else if (m_controlPort.ReceiveOutMessage(&msg))
1662 port = &m_controlPort;
1665 else if (m_dataPort.ReceiveOutMessage(&msg))
1673 StateMachine(msg->signal, port, msg);
1674 if (!m_bStateMachineSelfTrigger)
1683 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
1690 msg = m_controlPort.GetMessage();
1691 msg->signal = CMixerControlProtocol::TIMEOUT;
1693 // signal timeout to state machine
1694 StateMachine(msg->signal, port, msg);
1695 if (!m_bStateMachineSelfTrigger)
1705 void CMixer::CreateVdpauMixer()
1707 CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer");
1709 InitCSCMatrix(m_config.vidWidth);
1711 VdpVideoMixerParameter parameters[] = {
1712 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
1713 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
1714 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE};
1716 void const * parameter_values[] = {
1717 &m_config.surfaceWidth,
1718 &m_config.surfaceHeight,
1719 &m_config.vdpChromaType};
1721 VdpStatus vdp_st = VDP_STATUS_ERROR;
1722 vdp_st = m_config.context->GetProcs().vdp_video_mixer_create(m_config.context->GetDevice(),
1723 m_config.context->GetFeatureCount(),
1724 m_config.context->GetFeatures(),
1729 CheckStatus(vdp_st, __LINE__);
1733 void CMixer::InitCSCMatrix(int Width)
1735 m_Procamp.struct_version = VDP_PROCAMP_VERSION;
1736 m_Procamp.brightness = 0.0;
1737 m_Procamp.contrast = 1.0;
1738 m_Procamp.saturation = 1.0;
1742 void CMixer::CheckFeatures()
1744 if (m_Upscale != m_config.upscale)
1747 m_Upscale = m_config.upscale;
1749 if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness ||
1750 m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast ||
1751 m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix)
1754 m_Brightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness;
1755 m_Contrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast;
1756 m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix;
1758 if (m_NoiseReduction != CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1760 m_NoiseReduction = CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction;
1761 SetNoiseReduction();
1763 if (m_Sharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1765 m_Sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
1768 if (m_DeintMode != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode ||
1769 m_Deint != CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod)
1771 m_DeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1772 m_Deint = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1777 void CMixer::SetPostProcFeatures(bool postProcEnabled)
1779 if (m_PostProc != postProcEnabled)
1781 if (postProcEnabled)
1783 SetNoiseReduction();
1790 m_PostProc = postProcEnabled;
1794 void CMixer::PostProcOff()
1798 if (m_videoMixer == VDP_INVALID_HANDLE)
1801 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
1802 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
1803 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE};
1805 VdpBool enabled[]={0,0,0};
1806 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1807 CheckStatus(vdp_st, __LINE__);
1809 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1811 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION};
1813 VdpBool enabled[]={0};
1814 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1815 CheckStatus(vdp_st, __LINE__);
1818 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1820 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS};
1822 VdpBool enabled[]={0};
1823 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1824 CheckStatus(vdp_st, __LINE__);
1830 bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix)
1832 // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4])
1833 // m00 = mRY = red: luma factor (contrast factor) (1.0)
1834 // m10 = mGY = green: luma factor (contrast factor) (1.0)
1835 // m20 = mBY = blue: luma factor (contrast factor) (1.0)
1837 // m01 = mRB = red: blue color diff coeff (0.0)
1838 // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg))
1839 // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5)
1841 // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5)
1842 // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg))
1843 // m22 = mBR = blue: red color diff coeff (0.0)
1845 // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255))
1846 // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg)
1847 // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255))
1858 // colour standard coefficients for red, geen, blue
1860 // colour diff zero position (use standard 8-bit coding precision)
1861 double CDZ = 128; //256*0.5
1862 // range excursion (use standard 8-bit coding precision)
1863 double EXC = 255; //256-1
1865 if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601)
1867 Kr = studioCSCKCoeffs601[0];
1868 Kg = studioCSCKCoeffs601[1];
1869 Kb = studioCSCKCoeffs601[2];
1871 else // assume VDP_COLOR_STANDARD_ITUR_BT_709
1873 Kr = studioCSCKCoeffs709[0];
1874 Kg = studioCSCKCoeffs709[1];
1875 Kb = studioCSCKCoeffs709[2];
1877 // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235
1878 studioCSCMatrix[R][Y] = 1.0;
1879 studioCSCMatrix[G][Y] = 1.0;
1880 studioCSCMatrix[B][Y] = 1.0;
1882 studioCSCMatrix[R][Cb] = 0.0;
1883 studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg;
1884 studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5;
1886 studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5;
1887 studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg;
1888 studioCSCMatrix[B][Cr] = 0.0;
1890 studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC;
1891 studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC;
1892 studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC;
1897 void CMixer::SetColor()
1901 if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)
1902 m_Procamp.brightness = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)-50) / 100;
1903 if (m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)
1904 m_Procamp.contrast = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)+50) / 100;
1906 VdpColorStandard colorStandard;
1907 switch(m_mixerInput[1].DVDPic.color_matrix)
1909 case AVCOL_SPC_BT709:
1910 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1912 case AVCOL_SPC_BT470BG:
1913 case AVCOL_SPC_SMPTE170M:
1914 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1916 case AVCOL_SPC_SMPTE240M:
1917 colorStandard = VDP_COLOR_STANDARD_SMPTE_240M;
1920 case AVCOL_SPC_UNSPECIFIED:
1923 if(m_config.surfaceWidth > 1000)
1924 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1926 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1929 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
1930 if (CSettings::Get().GetBool("videoscreen.limitedrange"))
1932 float studioCSC[3][4];
1933 GenerateStudioCSCMatrix(colorStandard, studioCSC);
1934 void const * pm_CSCMatix[] = { &studioCSC };
1935 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1939 vdp_st = m_config.context->GetProcs().vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix);
1940 void const * pm_CSCMatix[] = { &m_CSCMatrix };
1941 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1944 CheckStatus(vdp_st, __LINE__);
1947 void CMixer::SetNoiseReduction()
1949 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1952 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION };
1953 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL };
1956 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1958 VdpBool enabled[]= {0};
1959 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1960 CheckStatus(vdp_st, __LINE__);
1963 VdpBool enabled[]={1};
1964 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1965 CheckStatus(vdp_st, __LINE__);
1966 void* nr[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction };
1967 CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction);
1968 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, nr);
1969 CheckStatus(vdp_st, __LINE__);
1972 void CMixer::SetSharpness()
1974 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1977 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS };
1978 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL };
1981 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1983 VdpBool enabled[]={0};
1984 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1985 CheckStatus(vdp_st, __LINE__);
1988 VdpBool enabled[]={1};
1989 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1990 CheckStatus(vdp_st, __LINE__);
1991 void* sh[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness };
1992 CLog::Log(LOGNOTICE,"Setting Sharpness to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness);
1993 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, sh);
1994 CheckStatus(vdp_st, __LINE__);
1997 EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */)
1999 EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
2000 if (method == VS_INTERLACEMETHOD_AUTO)
2003 // if (m_config.outHeight >= 720)
2004 // deint = g_advancedSettings.m_videoVDPAUdeintHD;
2006 // deint = g_advancedSettings.m_videoVDPAUdeintSD;
2010 if (m_config.vdpau->Supports(EINTERLACEMETHOD(deint)))
2012 method = EINTERLACEMETHOD(deint);
2014 CLog::Log(LOGNOTICE, "CVDPAU::GetDeinterlacingMethod: set de-interlacing to %d", deint);
2019 CLog::Log(LOGWARNING, "CVDPAU::GetDeinterlacingMethod: method for de-interlacing (advanced settings) not supported");
2026 void CMixer::SetDeinterlacing()
2030 if (m_videoMixer == VDP_INVALID_HANDLE)
2033 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
2034 EINTERLACEMETHOD method = GetDeinterlacingMethod(true);
2036 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
2037 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
2038 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE };
2040 if (mode == VS_DEINTERLACEMODE_OFF)
2042 VdpBool enabled[] = {0,0,0};
2043 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2047 if (method == VS_INTERLACEMETHOD_AUTO)
2049 VdpBool enabled[] = {1,0,0};
2050 if (g_advancedSettings.m_videoVDPAUtelecine)
2052 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2054 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2055 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF)
2057 VdpBool enabled[] = {1,0,0};
2058 if (g_advancedSettings.m_videoVDPAUtelecine)
2060 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2062 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2063 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF)
2065 VdpBool enabled[] = {1,1,0};
2066 if (g_advancedSettings.m_videoVDPAUtelecine)
2068 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2072 VdpBool enabled[]={0,0,0};
2073 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2076 CheckStatus(vdp_st, __LINE__);
2078 SetDeintSkipChroma();
2080 m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
2083 void CMixer::SetDeintSkipChroma()
2085 VdpVideoMixerAttribute attribute[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE};
2089 if (g_advancedSettings.m_videoVDPAUdeintSkipChromaHD && m_config.outHeight >= 720)
2094 void const *values[]={&val};
2095 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attribute), attribute, values);
2097 CheckStatus(vdp_st, __LINE__);
2100 void CMixer::SetHWUpscaling()
2102 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
2105 VdpBool enabled[]={1};
2106 switch (m_config.upscale)
2109 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
2111 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
2112 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2116 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
2118 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
2119 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2123 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2125 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2126 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2130 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2132 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2133 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2137 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2139 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2140 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2144 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2146 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2147 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2151 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2153 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2154 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2158 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2160 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2161 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2165 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2167 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2168 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2175 CheckStatus(vdp_st, __LINE__);
2179 void CMixer::DisableHQScaling()
2183 if (m_videoMixer == VDP_INVALID_HANDLE)
2186 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2188 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2189 VdpBool enabled[]={0};
2190 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2191 CheckStatus(vdp_st, __LINE__);
2194 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2196 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2197 VdpBool enabled[]={0};
2198 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2199 CheckStatus(vdp_st, __LINE__);
2202 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2204 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2205 VdpBool enabled[]={0};
2206 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2207 CheckStatus(vdp_st, __LINE__);
2210 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2212 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2213 VdpBool enabled[]={0};
2214 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2215 CheckStatus(vdp_st, __LINE__);
2218 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2220 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2221 VdpBool enabled[]={0};
2222 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2223 CheckStatus(vdp_st, __LINE__);
2226 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2228 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2229 VdpBool enabled[]={0};
2230 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2231 CheckStatus(vdp_st, __LINE__);
2234 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2236 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2237 VdpBool enabled[]={0};
2238 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2239 CheckStatus(vdp_st, __LINE__);
2242 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
2244 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
2245 VdpBool enabled[]={0};
2246 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2247 CheckStatus(vdp_st, __LINE__);
2250 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
2252 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
2253 VdpBool enabled[]={0};
2254 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2255 CheckStatus(vdp_st, __LINE__);
2263 m_NoiseReduction = 0.0;
2268 m_SeenInterlaceFlag = false;
2273 m_config.upscale = g_advancedSettings.m_videoVDPAUScaling;
2274 m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
2279 void CMixer::Uninit()
2282 while (!m_outputSurfaces.empty())
2284 m_outputSurfaces.pop();
2286 m_config.context->GetProcs().vdp_video_mixer_destroy(m_videoMixer);
2289 void CMixer::Flush()
2291 while (!m_mixerInput.empty())
2293 CVdpauDecodedPicture pic = m_mixerInput.back();
2294 m_mixerInput.pop_back();
2295 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2297 while (!m_decodedPics.empty())
2299 CVdpauDecodedPicture pic = m_decodedPics.front();
2300 m_decodedPics.pop();
2301 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2304 while (m_dataPort.ReceiveOutMessage(&msg))
2306 if (msg->signal == CMixerDataProtocol::FRAME)
2308 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2309 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2311 else if (msg->signal == CMixerDataProtocol::BUFFER)
2313 VdpOutputSurface *surf;
2314 surf = (VdpOutputSurface*)msg->data;
2315 m_outputSurfaces.push(*surf);
2321 void CMixer::InitCycle()
2326 m_config.stats->GetParams(latency, flags);
2328 if (0) //flags & DVP_FLAG_NO_POSTPROC)
2329 SetPostProcFeatures(false);
2331 SetPostProcFeatures(true);
2333 m_config.stats->SetCanSkipDeint(false);
2335 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
2336 EINTERLACEMETHOD method = GetDeinterlacingMethod();
2337 bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED;
2338 m_SeenInterlaceFlag |= interlaced;
2341 if (//!(flags & DVP_FLAG_NO_POSTPROC) &&
2342 (mode == VS_DEINTERLACEMODE_FORCE ||
2343 (mode == VS_DEINTERLACEMODE_AUTO && interlaced)))
2345 if((method == VS_INTERLACEMETHOD_AUTO && interlaced)
2346 || method == VS_INTERLACEMETHOD_VDPAU_BOB
2347 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2348 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2349 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2350 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2351 || method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE )
2353 if(method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2354 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2355 || !g_graphicsContext.IsFullScreenVideo())
2360 m_config.stats->SetCanSkipDeint(true);
2364 if (0) //m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_DROPDEINT)
2369 if(m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST)
2370 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2372 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2374 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2375 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2376 DVP_FLAG_REPEAT_TOP_FIELD |
2377 DVP_FLAG_INTERLACED);
2378 m_config.useInteropYuv = false;
2380 else if (method == VS_INTERLACEMETHOD_RENDER_BOB)
2383 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2384 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2385 m_config.useInteropYuv = true;
2389 CLog::Log(LOGERROR, "CMixer::%s - interlace method: %d not supported, setting to AUTO", __FUNCTION__, method);
2391 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2392 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2393 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2394 DVP_FLAG_REPEAT_TOP_FIELD |
2395 DVP_FLAG_INTERLACED);
2397 CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod = VS_INTERLACEMETHOD_AUTO;
2403 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2405 if (m_config.useInteropYuv)
2406 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2409 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2410 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2411 DVP_FLAG_REPEAT_TOP_FIELD |
2412 DVP_FLAG_INTERLACED);
2417 m_processPicture.crop = false;
2418 if (m_mixerInput[1].DVDPic.format == RENDER_FMT_VDPAU)
2420 m_processPicture.outputSurface = m_outputSurfaces.front();
2421 m_mixerInput[1].DVDPic.iWidth = m_config.outWidth;
2422 m_mixerInput[1].DVDPic.iHeight = m_config.outHeight;
2423 if (m_SeenInterlaceFlag)
2425 double ratio = (double)m_mixerInput[1].DVDPic.iDisplayHeight / m_mixerInput[1].DVDPic.iHeight;
2426 m_mixerInput[1].DVDPic.iDisplayHeight = lrint(ratio*(m_mixerInput[1].DVDPic.iHeight-NUM_CROP_PIX*2));
2427 m_processPicture.crop = true;
2432 m_mixerInput[1].DVDPic.iWidth = m_config.vidWidth;
2433 m_mixerInput[1].DVDPic.iHeight = m_config.vidHeight;
2436 m_processPicture.DVDPic = m_mixerInput[1].DVDPic;
2437 m_processPicture.videoSurface = m_mixerInput[1].videoSurface;
2440 void CMixer::FiniCycle()
2442 // Keep video surfaces for one 2 cycles longer than used
2443 // by mixer. This avoids blocking in decoder.
2444 // NVidia recommends num_ref + 5
2445 while (m_mixerInput.size() > 5)
2447 CVdpauDecodedPicture &tmp = m_mixerInput.back();
2448 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
2450 m_config.videoSurfaces->ClearRender(tmp.videoSurface);
2452 m_mixerInput.pop_back();
2456 void CMixer::ProcessPicture()
2458 if (m_processPicture.DVDPic.format == RENDER_FMT_VDPAU_420)
2463 if (m_mixerstep == 1)
2465 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD)
2466 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2468 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2471 VdpVideoSurface past_surfaces[4] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2472 VdpVideoSurface futu_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2473 uint32_t pastCount = 4;
2474 uint32_t futuCount = 2;
2476 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
2478 // use only 2 past 1 future for progressive/weave
2479 // (only used for postproc anyway eg noise reduction)
2480 if (m_mixerInput.size() > 3)
2481 past_surfaces[1] = m_mixerInput[3].videoSurface;
2482 if (m_mixerInput.size() > 2)
2483 past_surfaces[0] = m_mixerInput[2].videoSurface;
2484 futu_surfaces[0] = m_mixerInput[0].videoSurface;
2490 if(m_mixerstep == 0)
2492 if (m_mixerInput.size() > 3)
2494 past_surfaces[3] = m_mixerInput[3].videoSurface;
2495 past_surfaces[2] = m_mixerInput[3].videoSurface;
2497 if (m_mixerInput.size() > 2)
2499 past_surfaces[1] = m_mixerInput[2].videoSurface;
2500 past_surfaces[0] = m_mixerInput[2].videoSurface;
2502 futu_surfaces[0] = m_mixerInput[1].videoSurface;
2503 futu_surfaces[1] = m_mixerInput[0].videoSurface;
2507 if (m_mixerInput.size() > 3)
2509 past_surfaces[3] = m_mixerInput[3].videoSurface;
2511 if (m_mixerInput.size() > 2)
2513 past_surfaces[2] = m_mixerInput[2].videoSurface;
2514 past_surfaces[1] = m_mixerInput[2].videoSurface;
2516 past_surfaces[0] = m_mixerInput[1].videoSurface;
2517 futu_surfaces[0] = m_mixerInput[0].videoSurface;
2518 futu_surfaces[1] = m_mixerInput[0].videoSurface;
2520 if (m_mixerInput[0].DVDPic.pts != DVD_NOPTS_VALUE &&
2521 m_mixerInput[1].DVDPic.pts != DVD_NOPTS_VALUE)
2523 m_processPicture.DVDPic.pts = m_mixerInput[1].DVDPic.pts +
2524 (m_mixerInput[0].DVDPic.pts -
2525 m_mixerInput[1].DVDPic.pts) / 2;
2528 m_processPicture.DVDPic.pts = DVD_NOPTS_VALUE;
2529 m_processPicture.DVDPic.dts = DVD_NOPTS_VALUE;
2531 m_processPicture.DVDPic.iRepeatPicture = 0.0;
2537 sourceRect.x1 = m_config.vidWidth;
2538 sourceRect.y1 = m_config.vidHeight;
2543 destRect.x1 = m_config.outWidth;
2544 destRect.y1 = m_config.outHeight;
2546 // start vdpau video mixer
2547 vdp_st = m_config.context->GetProcs().vdp_video_mixer_render(m_videoMixer,
2553 m_mixerInput[1].videoSurface,
2557 m_processPicture.outputSurface,
2562 CheckStatus(vdp_st, __LINE__);
2566 bool CMixer::CheckStatus(VdpStatus vdp_st, int line)
2568 if (vdp_st != VDP_STATUS_OK)
2570 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
2577 //-----------------------------------------------------------------------------
2579 //-----------------------------------------------------------------------------
2581 VdpauBufferPool::VdpauBufferPool()
2583 CVdpauRenderPicture *pic;
2584 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2586 pic = new CVdpauRenderPicture(renderPicSec);
2587 allRenderPics.push_back(pic);
2591 VdpauBufferPool::~VdpauBufferPool()
2593 CVdpauRenderPicture *pic;
2594 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2596 pic = allRenderPics[i];
2599 allRenderPics.clear();
2602 //-----------------------------------------------------------------------------
2604 //-----------------------------------------------------------------------------
2605 COutput::COutput(CEvent *inMsgEvent) :
2606 CThread("Vdpau Output"),
2607 m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent),
2608 m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent),
2609 m_mixer(&m_outMsgEvent)
2611 m_inMsgEvent = inMsgEvent;
2613 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i)
2615 m_bufferPool.freeRenderPics.push_back(i);
2619 void COutput::Start()
2628 m_bufferPool.freeRenderPics.clear();
2629 m_bufferPool.usedRenderPics.clear();
2632 void COutput::Dispose()
2634 CSingleLock lock(g_graphicsContext);
2636 m_outMsgEvent.Set();
2638 m_controlPort.Purge();
2642 void COutput::OnStartup()
2644 CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created");
2647 void COutput::OnExit()
2649 CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated");
2656 O_TOP_UNCONFIGURED, // 2
2657 O_TOP_CONFIGURED, // 3
2658 O_TOP_CONFIGURED_IDLE, // 4
2659 O_TOP_CONFIGURED_WORK, // 5
2662 int VDPAU_OUTPUT_parentStates[] = {
2665 0, //TOP_UNCONFIGURED
2667 3, //TOP_CONFIGURED_IDLE
2668 3, //TOP_CONFIGURED_WORK
2671 void COutput::StateMachine(int signal, Protocol *port, Message *msg)
2673 for (int state = m_state; ; state = VDPAU_OUTPUT_parentStates[state])
2678 if (port == &m_controlPort)
2682 case COutputControlProtocol::FLUSH:
2683 msg->Reply(COutputControlProtocol::ACC);
2685 case COutputControlProtocol::PRECLEANUP:
2686 msg->Reply(COutputControlProtocol::ACC);
2692 else if (port == &m_dataPort)
2696 case COutputDataProtocol::RETURNPIC:
2697 CVdpauRenderPicture *pic;
2698 pic = *((CVdpauRenderPicture**)msg->data);
2699 QueueReturnPicture(pic);
2706 std::string portName = port == NULL ? "timer" : port->portName;
2707 CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
2714 case O_TOP_UNCONFIGURED:
2715 if (port == &m_controlPort)
2719 case COutputControlProtocol::INIT:
2721 data = (CVdpauConfig*)msg->data;
2728 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::INIT,
2729 &reply, 1000, &m_config, sizeof(m_config)))
2731 if (reply->signal != CMixerControlProtocol::ACC)
2736 // set initial number of
2737 m_bufferPool.numOutputSurfaces = 4;
2741 m_state = O_TOP_CONFIGURED_IDLE;
2742 msg->Reply(COutputControlProtocol::ACC, &m_config, sizeof(m_config));
2746 m_state = O_TOP_ERROR;
2747 msg->Reply(COutputControlProtocol::ERROR);
2756 case O_TOP_CONFIGURED:
2757 if (port == &m_controlPort)
2761 case COutputControlProtocol::FLUSH:
2763 msg->Reply(COutputControlProtocol::ACC);
2765 case COutputControlProtocol::PRECLEANUP:
2768 msg->Reply(COutputControlProtocol::ACC);
2774 else if (port == &m_dataPort)
2778 case COutputDataProtocol::NEWFRAME:
2779 CVdpauDecodedPicture *frame;
2780 frame = (CVdpauDecodedPicture*)msg->data;
2783 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::FRAME,
2784 frame,sizeof(CVdpauDecodedPicture));
2787 case COutputDataProtocol::RETURNPIC:
2788 CVdpauRenderPicture *pic;
2789 pic = *((CVdpauRenderPicture**)msg->data);
2790 QueueReturnPicture(pic);
2791 m_controlPort.SendInMessage(COutputControlProtocol::STATS);
2792 m_state = O_TOP_CONFIGURED_WORK;
2799 else if (port == &m_mixer.m_dataPort)
2803 case CMixerDataProtocol::PICTURE:
2804 CVdpauProcessedPicture *pic;
2805 pic = (CVdpauProcessedPicture*)msg->data;
2806 m_bufferPool.processedPics.push(*pic);
2807 m_state = O_TOP_CONFIGURED_WORK;
2816 case O_TOP_CONFIGURED_IDLE:
2817 if (port == NULL) // timeout
2821 case COutputControlProtocol::TIMEOUT:
2822 if (ProcessSyncPicture())
2828 m_state = O_TOP_CONFIGURED_WORK;
2838 case O_TOP_CONFIGURED_WORK:
2839 if (port == NULL) // timeout
2843 case COutputControlProtocol::TIMEOUT:
2846 CVdpauRenderPicture *pic;
2847 pic = ProcessMixerPicture();
2850 m_config.stats->DecProcessed();
2851 m_config.stats->IncRender();
2852 m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic));
2858 m_state = O_TOP_CONFIGURED_IDLE;
2868 default: // we are in no state, should not happen
2869 CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state);
2875 void COutput::Process()
2877 Message *msg = NULL;
2878 Protocol *port = NULL;
2881 m_state = O_TOP_UNCONFIGURED;
2882 m_extTimeout = 1000;
2883 m_bStateMachineSelfTrigger = false;
2889 if (m_bStateMachineSelfTrigger)
2891 m_bStateMachineSelfTrigger = false;
2892 // self trigger state machine
2893 StateMachine(msg->signal, port, msg);
2894 if (!m_bStateMachineSelfTrigger)
2901 // check control port
2902 else if (m_controlPort.ReceiveOutMessage(&msg))
2905 port = &m_controlPort;
2908 else if (m_dataPort.ReceiveOutMessage(&msg))
2913 // check mixer data port
2914 else if (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2917 port = &m_mixer.m_dataPort;
2921 StateMachine(msg->signal, port, msg);
2922 if (!m_bStateMachineSelfTrigger)
2931 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
2938 msg = m_controlPort.GetMessage();
2939 msg->signal = COutputControlProtocol::TIMEOUT;
2941 // signal timeout to state machine
2942 StateMachine(msg->signal, port, msg);
2943 if (!m_bStateMachineSelfTrigger)
2954 bool COutput::Init()
2956 if (!CreateGlxContext())
2968 bool COutput::Uninit()
2972 while(ProcessSyncPicture())
2977 ReleaseBufferPool();
2978 DestroyGlxContext();
2982 void COutput::Flush()
2984 if (m_mixer.IsActive())
2987 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH,
2994 CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__);
2998 while (m_mixer.m_dataPort.ReceiveInMessage(&msg))
3000 if (msg->signal == CMixerDataProtocol::PICTURE)
3002 CVdpauProcessedPicture pic = *(CVdpauProcessedPicture*)msg->data;
3003 m_bufferPool.processedPics.push(pic);
3008 while (m_dataPort.ReceiveOutMessage(&msg))
3010 if (msg->signal == COutputDataProtocol::NEWFRAME)
3012 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
3013 m_config.videoSurfaces->ClearRender(pic.videoSurface);
3015 else if (msg->signal == COutputDataProtocol::RETURNPIC)
3017 CVdpauRenderPicture *pic;
3018 pic = *((CVdpauRenderPicture**)msg->data);
3019 QueueReturnPicture(pic);
3024 while (m_dataPort.ReceiveInMessage(&msg))
3026 if (msg->signal == COutputDataProtocol::PICTURE)
3028 CVdpauRenderPicture *pic;
3029 pic = *((CVdpauRenderPicture**)msg->data);
3030 QueueReturnPicture(pic);
3034 // reset used render flag which was cleared on mixer flush
3035 std::deque<int>::iterator it;
3036 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3038 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[*it];
3039 if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3041 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it2;
3042 it2 = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3043 if (it2 == m_bufferPool.glVideoSurfaceMap.end())
3045 CLog::Log(LOGDEBUG, "COutput::Flush - gl surface not found");
3048 m_config.videoSurfaces->MarkRender(it2->second.sourceVuv);
3052 // clear processed pics
3053 while(!m_bufferPool.processedPics.empty())
3055 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
3056 if (procPic.DVDPic.format == RENDER_FMT_VDPAU)
3058 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &procPic.outputSurface, sizeof(procPic.outputSurface));
3060 else if (procPic.DVDPic.format == RENDER_FMT_VDPAU_420)
3062 m_config.videoSurfaces->ClearRender(procPic.videoSurface);
3064 m_bufferPool.processedPics.pop();
3068 bool COutput::HasWork()
3070 if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
3075 CVdpauRenderPicture* COutput::ProcessMixerPicture()
3077 CVdpauRenderPicture *retPic = NULL;
3079 if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
3081 int idx = m_bufferPool.freeRenderPics.front();
3082 retPic = m_bufferPool.allRenderPics[idx];
3083 m_bufferPool.freeRenderPics.pop_front();
3084 m_bufferPool.usedRenderPics.push_back(idx);
3085 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
3086 m_bufferPool.processedPics.pop();
3088 retPic->DVDPic = procPic.DVDPic;
3089 retPic->valid = true;
3090 if (retPic->DVDPic.format == RENDER_FMT_VDPAU)
3092 m_config.useInteropYuv = false;
3093 m_bufferPool.numOutputSurfaces = NUM_RENDER_PICS;
3095 GLMapSurface(false, procPic.outputSurface);
3096 retPic->sourceIdx = procPic.outputSurface;
3097 retPic->texture[0] = m_bufferPool.glOutputSurfaceMap[procPic.outputSurface].texture[0];
3098 retPic->texWidth = m_config.outWidth;
3099 retPic->texHeight = m_config.outHeight;
3100 retPic->crop.x1 = 0;
3101 retPic->crop.y1 = procPic.crop ? NUM_CROP_PIX : 0;
3102 retPic->crop.x2 = m_config.outWidth;
3103 retPic->crop.y2 = m_config.outHeight - retPic->crop.y1;
3107 m_config.useInteropYuv = true;
3108 GLMapSurface(true, procPic.videoSurface);
3109 retPic->sourceIdx = procPic.videoSurface;
3110 for (unsigned int i=0; i<4; ++i)
3111 retPic->texture[i] = m_bufferPool.glVideoSurfaceMap[procPic.videoSurface].texture[i];
3112 retPic->texWidth = m_config.surfaceWidth;
3113 retPic->texHeight = m_config.surfaceHeight;
3114 retPic->crop.x1 = 0;
3115 retPic->crop.y1 = 0;
3116 retPic->crop.x2 = m_config.surfaceWidth - m_config.vidWidth;
3117 retPic->crop.y2 = m_config.surfaceHeight - m_config.vidHeight;
3123 void COutput::QueueReturnPicture(CVdpauRenderPicture *pic)
3125 std::deque<int>::iterator it;
3126 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3128 if (m_bufferPool.allRenderPics[*it] == pic)
3134 if (it == m_bufferPool.usedRenderPics.end())
3136 CLog::Log(LOGWARNING, "COutput::QueueReturnPicture - pic not found");
3140 // check if already queued
3141 std::deque<int>::iterator it2 = find(m_bufferPool.syncRenderPics.begin(),
3142 m_bufferPool.syncRenderPics.end(),
3144 if (it2 == m_bufferPool.syncRenderPics.end())
3146 m_bufferPool.syncRenderPics.push_back(*it);
3149 ProcessSyncPicture();
3152 bool COutput::ProcessSyncPicture()
3154 CVdpauRenderPicture *pic;
3157 std::deque<int>::iterator it;
3158 for (it = m_bufferPool.syncRenderPics.begin(); it != m_bufferPool.syncRenderPics.end(); )
3160 pic = m_bufferPool.allRenderPics[*it];
3165 if (glIsSync(pic->fence))
3169 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3170 if(state == GL_SIGNALED)
3172 glDeleteSync(pic->fence);
3185 m_bufferPool.freeRenderPics.push_back(*it);
3187 std::deque<int>::iterator it2 = find(m_bufferPool.usedRenderPics.begin(),
3188 m_bufferPool.usedRenderPics.end(),
3190 if (it2 == m_bufferPool.usedRenderPics.end())
3192 CLog::Log(LOGERROR, "COutput::ProcessSyncPicture - pic not found in queue");
3196 m_bufferPool.usedRenderPics.erase(it2);
3198 it = m_bufferPool.syncRenderPics.erase(it);
3202 ProcessReturnPicture(pic);
3206 CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__);
3212 void COutput::ProcessReturnPicture(CVdpauRenderPicture *pic)
3214 if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3216 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3217 it = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3218 if (it == m_bufferPool.glVideoSurfaceMap.end())
3220 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3223 #ifdef GL_NV_vdpau_interop
3224 glVDPAUUnmapSurfacesNV(1, &(it->second.glVdpauSurface));
3226 VdpVideoSurface surf = it->second.sourceVuv;
3227 m_config.videoSurfaces->ClearRender(surf);
3229 else if (pic->DVDPic.format == RENDER_FMT_VDPAU)
3231 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3232 it = m_bufferPool.glOutputSurfaceMap.find(pic->sourceIdx);
3233 if (it == m_bufferPool.glOutputSurfaceMap.end())
3235 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3238 #ifdef GL_NV_vdpau_interop
3239 glVDPAUUnmapSurfacesNV(1, &(it->second.glVdpauSurface));
3241 VdpOutputSurface outSurf = it->second.sourceRgb;
3242 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &outSurf, sizeof(outSurf));
3246 bool COutput::EnsureBufferPool()
3250 // Creation of outputSurfaces
3251 VdpOutputSurface outputSurface;
3252 for (int i = m_bufferPool.outputSurfaces.size(); i < m_bufferPool.numOutputSurfaces; i++)
3254 vdp_st = m_config.context->GetProcs().vdp_output_surface_create(m_config.context->GetDevice(),
3255 VDP_RGBA_FORMAT_B8G8R8A8,
3259 if (CheckStatus(vdp_st, __LINE__))
3261 m_bufferPool.outputSurfaces.push_back(outputSurface);
3263 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3265 sizeof(VdpOutputSurface));
3266 CLog::Log(LOGNOTICE, "VDPAU::COutput::InitBufferPool - Output Surface created");
3271 void COutput::ReleaseBufferPool()
3275 CSingleLock lock(m_bufferPool.renderPicSec);
3277 // release all output surfaces
3278 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3280 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3282 vdp_st = m_config.context->GetProcs().vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3283 CheckStatus(vdp_st, __LINE__);
3285 m_bufferPool.outputSurfaces.clear();
3287 // wait for all fences
3288 XbmcThreads::EndTime timeout(1000);
3289 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3291 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[i];
3295 while (glIsSync(pic->fence))
3299 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3300 if(state == GL_SIGNALED || timeout.IsTimePast())
3302 glDeleteSync(pic->fence);
3313 if (timeout.IsTimePast())
3315 CLog::Log(LOGERROR, "COutput::%s - timeout waiting for fence", __FUNCTION__);
3317 ProcessSyncPicture();
3319 // invalidate all used render pictures
3320 for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i)
3322 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[m_bufferPool.usedRenderPics[i]];
3327 void COutput::PreCleanup()
3333 ProcessSyncPicture();
3335 CSingleLock lock(m_bufferPool.renderPicSec);
3336 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3338 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3341 // check if output surface is in use
3343 std::deque<int>::iterator it;
3344 CVdpauRenderPicture *pic;
3345 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3347 pic = m_bufferPool.allRenderPics[*it];
3348 if ((pic->sourceIdx == m_bufferPool.outputSurfaces[i]) && pic->valid)
3357 #ifdef GL_NV_vdpau_interop
3359 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it_map;
3360 it_map = m_bufferPool.glOutputSurfaceMap.find(m_bufferPool.outputSurfaces[i]);
3361 if (it_map == m_bufferPool.glOutputSurfaceMap.end())
3363 CLog::Log(LOGERROR, "%s - could not find gl surface", __FUNCTION__);
3366 glVDPAUUnregisterSurfaceNV(it_map->second.glVdpauSurface);
3367 glDeleteTextures(1, it_map->second.texture);
3368 m_bufferPool.glOutputSurfaceMap.erase(it_map);
3371 vdp_st = m_config.context->GetProcs().vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3372 CheckStatus(vdp_st, __LINE__);
3374 m_bufferPool.outputSurfaces[i] = VDP_INVALID_HANDLE;
3376 CLog::Log(LOGDEBUG, "VDPAU::PreCleanup - released output surface");
3381 void COutput::InitMixer()
3383 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3385 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3386 &m_bufferPool.outputSurfaces[i],
3387 sizeof(VdpOutputSurface));
3391 bool COutput::GLInit()
3393 #ifdef GL_NV_vdpau_interop
3394 glVDPAUInitNV = NULL;
3395 glVDPAUFiniNV = NULL;
3396 glVDPAURegisterOutputSurfaceNV = NULL;
3397 glVDPAURegisterVideoSurfaceNV = NULL;
3398 glVDPAUIsSurfaceNV = NULL;
3399 glVDPAUUnregisterSurfaceNV = NULL;
3400 glVDPAUSurfaceAccessNV = NULL;
3401 glVDPAUMapSurfacesNV = NULL;
3402 glVDPAUUnmapSurfacesNV = NULL;
3403 glVDPAUGetSurfaceivNV = NULL;
3406 #ifdef GL_NV_vdpau_interop
3408 glVDPAUInitNV = (PFNGLVDPAUINITNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUInitNV");
3410 glVDPAUFiniNV = (PFNGLVDPAUFININVPROC)glXGetProcAddress((GLubyte *) "glVDPAUFiniNV");
3411 if (!glVDPAURegisterOutputSurfaceNV)
3412 glVDPAURegisterOutputSurfaceNV = (PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterOutputSurfaceNV");
3413 if (!glVDPAURegisterVideoSurfaceNV)
3414 glVDPAURegisterVideoSurfaceNV = (PFNGLVDPAUREGISTERVIDEOSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterVideoSurfaceNV");
3415 if (!glVDPAUIsSurfaceNV)
3416 glVDPAUIsSurfaceNV = (PFNGLVDPAUISSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUIsSurfaceNV");
3417 if (!glVDPAUUnregisterSurfaceNV)
3418 glVDPAUUnregisterSurfaceNV = (PFNGLVDPAUUNREGISTERSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnregisterSurfaceNV");
3419 if (!glVDPAUSurfaceAccessNV)
3420 glVDPAUSurfaceAccessNV = (PFNGLVDPAUSURFACEACCESSNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUSurfaceAccessNV");
3421 if (!glVDPAUMapSurfacesNV)
3422 glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUMapSurfacesNV");
3423 if (!glVDPAUUnmapSurfacesNV)
3424 glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnmapSurfacesNV");
3425 if (!glVDPAUGetSurfaceivNV)
3426 glVDPAUGetSurfaceivNV = (PFNGLVDPAUGETSURFACEIVNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUGetSurfaceivNV");
3428 while (glGetError() != GL_NO_ERROR);
3429 glVDPAUInitNV(reinterpret_cast<void*>(m_config.context->GetDevice()), reinterpret_cast<void*>(m_config.context->GetProcs().vdp_get_proc_address));
3430 if (glGetError() != GL_NO_ERROR)
3432 CLog::Log(LOGERROR, "VDPAU::COutput - GLInitInterop glVDPAUInitNV failed");
3436 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop initialized");
3440 bool hasfence = glewIsSupported("GL_ARB_sync");
3441 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3443 m_bufferPool.allRenderPics[i]->usefence = hasfence;
3450 void COutput::GLMapSurface(bool yuv, uint32_t source)
3452 #ifdef GL_NV_vdpau_interop
3456 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3457 it = m_bufferPool.glVideoSurfaceMap.find(source);
3458 if (it == m_bufferPool.glVideoSurfaceMap.end())
3460 VdpauBufferPool::GLVideoSurface glSurface;
3461 VdpVideoSurface surf = source;
3463 if (surf == VDP_INVALID_HANDLE)
3466 glSurface.sourceVuv = surf;
3467 while (glGetError() != GL_NO_ERROR) ;
3468 glGenTextures(4, glSurface.texture);
3469 if (glGetError() != GL_NO_ERROR)
3471 CLog::Log(LOGERROR, "VDPAU::COutput error creating texture");
3474 glSurface.glVdpauSurface = glVDPAURegisterVideoSurfaceNV(reinterpret_cast<void*>(surf),
3475 GL_TEXTURE_2D, 4, glSurface.texture);
3477 if (glGetError() != GL_NO_ERROR)
3479 CLog::Log(LOGERROR, "VDPAU::COutput error register video surface");
3482 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3483 if (glGetError() != GL_NO_ERROR)
3485 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3488 m_bufferPool.glVideoSurfaceMap[surf] = glSurface;
3490 CLog::Log(LOGNOTICE, "VDPAU::COutput registered surface");
3493 while (glGetError() != GL_NO_ERROR) ;
3494 glVDPAUMapSurfacesNV(1, &m_bufferPool.glVideoSurfaceMap[source].glVdpauSurface);
3495 if (glGetError() != GL_NO_ERROR)
3497 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3506 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3507 it = m_bufferPool.glOutputSurfaceMap.find(source);
3508 if (it == m_bufferPool.glOutputSurfaceMap.end())
3510 unsigned int idx = 0;
3511 for (idx = 0; idx<m_bufferPool.outputSurfaces.size(); idx++)
3513 if (m_bufferPool.outputSurfaces[idx] == source)
3517 VdpauBufferPool::GLVideoSurface glSurface;
3518 glSurface.sourceRgb = m_bufferPool.outputSurfaces[idx];
3519 glGenTextures(1, glSurface.texture);
3520 glSurface.glVdpauSurface = glVDPAURegisterOutputSurfaceNV(reinterpret_cast<void*>(m_bufferPool.outputSurfaces[idx]),
3521 GL_TEXTURE_2D, 1, glSurface.texture);
3522 if (glGetError() != GL_NO_ERROR)
3524 CLog::Log(LOGERROR, "VDPAU::COutput error register output surface");
3527 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3528 if (glGetError() != GL_NO_ERROR)
3530 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3533 m_bufferPool.glOutputSurfaceMap[source] = glSurface;
3534 CLog::Log(LOGNOTICE, "VDPAU::COutput registered output surfaces");
3537 while (glGetError() != GL_NO_ERROR) ;
3538 glVDPAUMapSurfacesNV(1, &m_bufferPool.glOutputSurfaceMap[source].glVdpauSurface);
3539 if (glGetError() != GL_NO_ERROR)
3541 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3551 void COutput::GLUnmapSurfaces()
3553 #ifdef GL_NV_vdpau_interop
3556 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3557 for (it = m_bufferPool.glVideoSurfaceMap.begin(); it != m_bufferPool.glVideoSurfaceMap.end(); ++it)
3559 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3560 glDeleteTextures(4, it->second.texture);
3562 m_bufferPool.glVideoSurfaceMap.clear();
3565 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3566 for (it = m_bufferPool.glOutputSurfaceMap.begin(); it != m_bufferPool.glOutputSurfaceMap.end(); ++it)
3568 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3569 glDeleteTextures(1, it->second.texture);
3571 m_bufferPool.glOutputSurfaceMap.clear();
3575 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop finished");
3580 bool COutput::CheckStatus(VdpStatus vdp_st, int line)
3582 if (vdp_st != VDP_STATUS_OK)
3584 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
3591 bool COutput::CreateGlxContext()
3593 GLXContext glContext;
3595 m_Display = g_Windowing.GetDisplay();
3596 glContext = g_Windowing.GetGlxContext();
3597 m_Window = g_Windowing.GetWindow();
3599 // Get our window attribs.
3600 XWindowAttributes wndattribs;
3601 XGetWindowAttributes(m_Display, m_Window, &wndattribs);
3604 XVisualInfo visInfo;
3605 visInfo.visualid = wndattribs.visual->visualid;
3607 XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals);
3610 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - could not find visual");
3613 visInfo = visuals[0];
3616 m_pixmap = XCreatePixmap(m_Display,
3623 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - Unable to create XPixmap");
3628 m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap);
3632 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not create glPixmap");
3636 m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True);
3638 if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext))
3640 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not make Pixmap current");
3644 CLog::Log(LOGNOTICE, "VDPAU::COutput::CreateGlxContext - created context");
3648 bool COutput::DestroyGlxContext()
3652 glXMakeCurrent(m_Display, None, NULL);
3653 glXDestroyContext(m_Display, m_glContext);
3658 glXDestroyPixmap(m_Display, m_glPixmap);
3662 XFreePixmap(m_Display, m_pixmap);