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
43 #define ARSIZE(x) (sizeof(x) / sizeof((x)[0]))
45 // settings codecs mapping
46 DVDCodecAvailableType g_vdpau_available[] = {
47 { AV_CODEC_ID_H263, "videoplayer.usevdpaumpeg4" },
48 { AV_CODEC_ID_MPEG4, "videoplayer.usevdpaumpeg4" },
49 { AV_CODEC_ID_WMV3, "videoplayer.usevdpauvc1" },
50 { AV_CODEC_ID_VC1, "videoplayer.usevdpauvc1" },
51 { AV_CODEC_ID_MPEG2VIDEO, "videoplayer.usevdpaumpeg2" },
53 const size_t settings_count = sizeof(g_vdpau_available) / sizeof(DVDCodecAvailableType);
55 CDecoder::Desc decoder_profiles[] = {
56 {"MPEG1", VDP_DECODER_PROFILE_MPEG1},
57 {"MPEG2_SIMPLE", VDP_DECODER_PROFILE_MPEG2_SIMPLE},
58 {"MPEG2_MAIN", VDP_DECODER_PROFILE_MPEG2_MAIN},
59 {"H264_BASELINE",VDP_DECODER_PROFILE_H264_BASELINE},
60 {"H264_MAIN", VDP_DECODER_PROFILE_H264_MAIN},
61 {"H264_HIGH", VDP_DECODER_PROFILE_H264_HIGH},
62 {"VC1_SIMPLE", VDP_DECODER_PROFILE_VC1_SIMPLE},
63 {"VC1_MAIN", VDP_DECODER_PROFILE_VC1_MAIN},
64 {"VC1_ADVANCED", VDP_DECODER_PROFILE_VC1_ADVANCED},
65 {"MPEG4_PART2_ASP", VDP_DECODER_PROFILE_MPEG4_PART2_ASP},
67 const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CDecoder::Desc);
69 static struct SInterlaceMapping
71 const EINTERLACEMETHOD method;
72 const VdpVideoMixerFeature feature;
73 } g_interlace_mapping[] =
74 { {VS_INTERLACEMETHOD_VDPAU_TEMPORAL , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
75 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
76 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
77 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
78 , {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE}
79 , {VS_INTERLACEMETHOD_NONE , (VdpVideoMixerFeature)-1}
82 static float studioCSCKCoeffs601[3] = {0.299, 0.587, 0.114}; //BT601 {Kr, Kg, Kb}
83 static float studioCSCKCoeffs709[3] = {0.2126, 0.7152, 0.0722}; //BT709 {Kr, Kg, Kb}
85 //-----------------------------------------------------------------------------
86 //-----------------------------------------------------------------------------
88 CVDPAUContext *CVDPAUContext::m_context = 0;
89 CCriticalSection CVDPAUContext::m_section;
90 Display *CVDPAUContext::m_display = 0;
91 void *CVDPAUContext::m_dlHandle = 0;
93 CVDPAUContext::CVDPAUContext()
99 void CVDPAUContext::Release()
101 CSingleLock lock(m_section);
112 void CVDPAUContext::Close()
114 CLog::Log(LOGNOTICE, "VDPAU::Close - closing decoder context");
118 bool CVDPAUContext::EnsureContext(CVDPAUContext **ctx)
120 CSingleLock lock(m_section);
124 m_context->m_refCount++;
129 m_context = new CVDPAUContext();
132 CSingleLock gLock(g_graphicsContext);
133 if (!m_context->LoadSymbols() || !m_context->CreateContext())
141 m_context->m_refCount++;
147 VDPAU_procs& CVDPAUContext::GetProcs()
152 VdpVideoMixerFeature* CVDPAUContext::GetFeatures()
154 return m_vdpFeatures;
157 int CVDPAUContext::GetFeatureCount()
159 return m_featureCount;
162 bool CVDPAUContext::LoadSymbols()
166 m_dlHandle = dlopen("libvdpau.so.1", RTLD_LAZY);
169 const char* error = dlerror();
171 error = "dlerror() returned NULL";
173 CLog::Log(LOGERROR,"VDPAU::LoadSymbols: Unable to get handle to lib: %s", error);
180 dl_vdp_device_create_x11 = (VdpStatus (*)(Display*, int, VdpDevice*, VdpStatus (**)(VdpDevice, VdpFuncId, void**)))dlsym(m_dlHandle, (const char*)"vdp_device_create_x11");
184 CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__);
185 m_vdpDevice = VDP_INVALID_HANDLE;
191 bool CVDPAUContext::CreateContext()
193 CLog::Log(LOGNOTICE,"VDPAU::CreateContext - creating decoder context");
196 { CSingleLock lock(g_graphicsContext);
198 m_display = XOpenDisplay(NULL);
199 mScreen = g_Windowing.GetCurrentScreen();
204 vdp_st = dl_vdp_device_create_x11(m_display,
207 &m_vdpProcs.vdp_get_proc_address);
209 CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",m_vdpDevice,vdp_st);
210 if (vdp_st != VDP_STATUS_OK)
212 CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x. Falling back.",vdp_st);
213 m_vdpDevice = VDP_INVALID_HANDLE;
218 SpewHardwareAvailable();
222 void CVDPAUContext::QueryProcs()
226 #define VDP_PROC(id, proc) \
228 vdp_st = m_vdpProcs.vdp_get_proc_address(m_vdpDevice, id, (void**)&proc); \
229 if (vdp_st != VDP_STATUS_OK) \
231 CLog::Log(LOGERROR, "CVDPAUContext::GetProcs - failed to get proc id"); \
235 VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING , m_vdpProcs.vdp_get_error_string);
236 VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY , m_vdpProcs.vdp_device_destroy);
237 VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX , m_vdpProcs.vdp_generate_csc_matrix);
238 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE , m_vdpProcs.vdp_video_surface_create);
239 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , m_vdpProcs.vdp_video_surface_destroy);
240 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , m_vdpProcs.vdp_video_surface_put_bits_y_cb_cr);
241 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , m_vdpProcs.vdp_video_surface_get_bits_y_cb_cr);
242 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , m_vdpProcs.vdp_output_surface_put_bits_y_cb_cr);
243 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , m_vdpProcs.vdp_output_surface_put_bits_native);
244 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , m_vdpProcs.vdp_output_surface_create);
245 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , m_vdpProcs.vdp_output_surface_destroy);
246 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , m_vdpProcs.vdp_output_surface_get_bits_native);
247 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, m_vdpProcs.vdp_output_surface_render_output_surface);
248 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , m_vdpProcs.vdp_output_surface_put_bits_indexed);
249 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE , m_vdpProcs.vdp_video_mixer_create);
250 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , m_vdpProcs.vdp_video_mixer_set_feature_enables);
251 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY , m_vdpProcs.vdp_video_mixer_destroy);
252 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER , m_vdpProcs.vdp_video_mixer_render);
253 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , m_vdpProcs.vdp_video_mixer_set_attribute_values);
254 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , m_vdpProcs.vdp_video_mixer_query_parameter_support);
255 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , m_vdpProcs.vdp_video_mixer_query_feature_support);
256 VDP_PROC(VDP_FUNC_ID_DECODER_CREATE , m_vdpProcs.vdp_decoder_create);
257 VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY , m_vdpProcs.vdp_decoder_destroy);
258 VDP_PROC(VDP_FUNC_ID_DECODER_RENDER , m_vdpProcs.vdp_decoder_render);
259 VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , m_vdpProcs.vdp_decoder_query_caps);
263 VdpDevice CVDPAUContext::GetDevice()
268 void CVDPAUContext::DestroyContext()
270 if (!m_vdpProcs.vdp_device_destroy)
273 m_vdpProcs.vdp_device_destroy(m_vdpDevice);
274 m_vdpDevice = VDP_INVALID_HANDLE;
277 void CVDPAUContext::SpewHardwareAvailable() //CopyrighVDPAUt (c) 2008 Wladimir J. van der Laan -- VDPInfo
280 CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:");
281 CLog::Log(LOGNOTICE,"name level macbs width height");
282 CLog::Log(LOGNOTICE,"------------------------------------");
283 for(unsigned int x=0; x<decoder_profile_count; ++x)
285 VdpBool is_supported = false;
286 uint32_t max_level, max_macroblocks, max_width, max_height;
287 rv = m_vdpProcs.vdp_decoder_query_caps(m_vdpDevice, decoder_profiles[x].id,
288 &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
289 if(rv == VDP_STATUS_OK && is_supported)
291 CLog::Log(LOGNOTICE,"%-16s %2i %5i %5i %5i\n", decoder_profiles[x].name,
292 max_level, max_macroblocks, max_width, max_height);
295 CLog::Log(LOGNOTICE,"------------------------------------");
297 #define CHECK_SUPPORT(feature) \
300 if(m_vdpProcs.vdp_video_mixer_query_feature_support(m_vdpDevice, feature, &supported) == VDP_STATUS_OK && supported) { \
301 CLog::Log(LOGNOTICE, "Mixer feature: "#feature); \
302 m_vdpFeatures[m_featureCount++] = feature; \
306 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION);
307 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_SHARPNESS);
308 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL);
309 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL);
310 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE);
311 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
312 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1);
313 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2);
314 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3);
315 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4);
316 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5);
317 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6);
318 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7);
319 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8);
320 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9);
325 bool CVDPAUContext::Supports(VdpVideoMixerFeature feature)
327 for(int i = 0; i < m_featureCount; i++)
329 if(m_vdpFeatures[i] == feature)
335 //-----------------------------------------------------------------------------
336 // VDPAU Video Surface states
337 //-----------------------------------------------------------------------------
339 #define SURFACE_USED_FOR_REFERENCE 0x01
340 #define SURFACE_USED_FOR_RENDER 0x02
342 void CVideoSurfaces::AddSurface(VdpVideoSurface surf)
344 CSingleLock lock(m_section);
345 m_state[surf] = SURFACE_USED_FOR_REFERENCE;
348 void CVideoSurfaces::ClearReference(VdpVideoSurface surf)
350 CSingleLock lock(m_section);
351 if (m_state.find(surf) == m_state.end())
353 CLog::Log(LOGWARNING, "CVideoSurfaces::ClearReference - surface invalid");
356 m_state[surf] &= ~SURFACE_USED_FOR_REFERENCE;
357 if (m_state[surf] == 0)
359 m_freeSurfaces.push_back(surf);
363 bool CVideoSurfaces::MarkRender(VdpVideoSurface surf)
365 CSingleLock lock(m_section);
366 if (m_state.find(surf) == m_state.end())
368 CLog::Log(LOGWARNING, "CVideoSurfaces::MarkRender - surface invalid");
371 std::list<VdpVideoSurface>::iterator it;
372 it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
373 if (it != m_freeSurfaces.end())
375 m_freeSurfaces.erase(it);
377 m_state[surf] |= SURFACE_USED_FOR_RENDER;
381 void CVideoSurfaces::ClearRender(VdpVideoSurface surf)
383 CSingleLock lock(m_section);
384 if (m_state.find(surf) == m_state.end())
386 CLog::Log(LOGWARNING, "CVideoSurfaces::ClearRender - surface invalid");
389 m_state[surf] &= ~SURFACE_USED_FOR_RENDER;
390 if (m_state[surf] == 0)
392 m_freeSurfaces.push_back(surf);
396 bool CVideoSurfaces::IsValid(VdpVideoSurface surf)
398 CSingleLock lock(m_section);
399 if (m_state.find(surf) != m_state.end())
405 VdpVideoSurface CVideoSurfaces::GetFree(VdpVideoSurface surf)
407 CSingleLock lock(m_section);
408 if (m_state.find(surf) != m_state.end())
410 std::list<VdpVideoSurface>::iterator it;
411 it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
412 if (it == m_freeSurfaces.end())
414 CLog::Log(LOGWARNING, "CVideoSurfaces::GetFree - surface not free");
418 m_freeSurfaces.erase(it);
419 m_state[surf] = SURFACE_USED_FOR_REFERENCE;
424 if (!m_freeSurfaces.empty())
426 VdpVideoSurface freeSurf = m_freeSurfaces.front();
427 m_freeSurfaces.pop_front();
428 m_state[freeSurf] = SURFACE_USED_FOR_REFERENCE;
432 return VDP_INVALID_HANDLE;
435 VdpVideoSurface CVideoSurfaces::GetAtIndex(int idx)
437 if (idx >= m_state.size())
438 return VDP_INVALID_HANDLE;
440 std::map<VdpVideoSurface, int>::iterator it = m_state.begin();
441 for(int i = 0; i < idx; i++)
446 VdpVideoSurface CVideoSurfaces::RemoveNext(bool skiprender)
448 CSingleLock lock(m_section);
449 VdpVideoSurface surf;
450 std::map<VdpVideoSurface, int>::iterator it;
451 for(it = m_state.begin(); it != m_state.end(); ++it)
453 if (skiprender && it->second & SURFACE_USED_FOR_RENDER)
458 std::list<VdpVideoSurface>::iterator it2;
459 it2 = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
460 if (it2 != m_freeSurfaces.end())
461 m_freeSurfaces.erase(it2);
464 return VDP_INVALID_HANDLE;
467 void CVideoSurfaces::Reset()
469 CSingleLock lock(m_section);
470 m_freeSurfaces.clear();
474 int CVideoSurfaces::Size()
476 CSingleLock lock(m_section);
477 return m_state.size();
480 //-----------------------------------------------------------------------------
482 //-----------------------------------------------------------------------------
484 CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent)
486 m_vdpauConfig.videoSurfaces = &m_videoSurfaces;
488 m_vdpauConfigured = false;
489 m_hwContext.bitstream_buffers_allocated = 0;
490 m_DisplayState = VDPAU_OPEN;
491 m_vdpauConfig.context = 0;
494 bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned int surfaces)
496 // check if user wants to decode this format with VDPAU
497 std::string gpuvendor = g_Windowing.GetRenderVendor();
498 std::transform(gpuvendor.begin(), gpuvendor.end(), gpuvendor.begin(), ::tolower);
499 // nvidia is whitelisted despite for mpeg-4 we need to query user settings
500 if ((gpuvendor.compare(0, 6, "nvidia") != 0) || (avctx->codec_id == AV_CODEC_ID_MPEG4) || (avctx->codec_id == AV_CODEC_ID_H263))
502 if (CDVDVideoCodec::IsCodecDisabled(g_vdpau_available, settings_count, avctx->codec_id))
506 #ifndef GL_NV_vdpau_interop
507 CLog::Log(LOGNOTICE, "VDPAU: compilation without required extension GL_NV_vdpau_interop");
510 if (!g_Windowing.IsExtSupported("GL_NV_vdpau_interop"))
512 CLog::Log(LOGNOTICE, "VDPAU::Open: required extension GL_NV_vdpau_interop not found");
516 if(avctx->coded_width == 0
517 || avctx->coded_height == 0)
519 CLog::Log(LOGWARNING,"VDPAU::Open: no width/height available, can't init");
522 m_vdpauConfig.numRenderBuffers = surfaces;
523 m_decoderThread = CThread::GetCurrentThreadId();
525 if (!CVDPAUContext::EnsureContext(&m_vdpauConfig.context))
528 m_DisplayState = VDPAU_OPEN;
529 m_vdpauConfigured = false;
531 if (!m_dllAvUtil.Load())
534 m_presentPicture = 0;
537 VdpDecoderProfile profile = 0;
539 // convert FFMPEG codec ID to VDPAU profile.
540 ReadFormatOf(avctx->codec_id, profile, m_vdpauConfig.vdpChromaType);
544 VdpBool is_supported = false;
545 uint32_t max_level, max_macroblocks, max_width, max_height;
547 // query device capabilities to ensure that VDPAU can handle the requested codec
548 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_query_caps(m_vdpauConfig.context->GetDevice(),
549 profile, &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
551 // test to make sure there is a possibility the codec will work
552 if (CheckStatus(vdp_st, __LINE__))
554 CLog::Log(LOGERROR, "VDPAU::Open: error %s(%d) checking for decoder support", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st);
558 if (max_width < avctx->coded_width || max_height < avctx->coded_height)
560 CLog::Log(LOGWARNING,"VDPAU::Open: requested picture dimensions (%i, %i) exceed hardware capabilities ( %i, %i).",
561 avctx->coded_width, avctx->coded_height, max_width, max_height);
565 if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width))
566 CLog::Log(LOGWARNING,"VDPAU::Open width %i might not be supported because of hardware bug", avctx->width);
568 // attempt to create a decoder with this width/height, some sizes are not supported by hw
569 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_create(m_vdpauConfig.context->GetDevice(), profile, avctx->coded_width, avctx->coded_height, 5, &m_vdpauConfig.vdpDecoder);
571 if (CheckStatus(vdp_st, __LINE__))
573 CLog::Log(LOGERROR, "VDPAU::Open: error: %s(%d) checking for decoder support", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st);
577 m_vdpauConfig.context->GetProcs().vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
578 CheckStatus(vdp_st, __LINE__);
580 // finally setup ffmpeg
581 memset(&m_hwContext, 0, sizeof(AVVDPAUContext));
582 m_hwContext.render = CDecoder::Render;
583 m_hwContext.bitstream_buffers_allocated = 0;
584 avctx->get_buffer = CDecoder::FFGetBuffer;
585 avctx->reget_buffer = CDecoder::FFGetBuffer;
586 avctx->release_buffer = CDecoder::FFReleaseBuffer;
587 avctx->draw_horiz_band = CDecoder::FFDrawSlice;
588 avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
589 avctx->hwaccel_context = &m_hwContext;
590 avctx->thread_count = 1;
592 g_Windowing.Register(this);
599 CDecoder::~CDecoder()
604 void CDecoder::Close()
606 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
608 g_Windowing.Unregister(this);
610 CSingleLock lock(m_DecoderSection);
613 m_vdpauOutput.Dispose();
615 if (m_hwContext.bitstream_buffers_allocated)
617 m_dllAvUtil.av_freep(&m_hwContext.bitstream_buffers);
620 m_dllAvUtil.Unload();
622 if (m_vdpauConfig.context)
623 m_vdpauConfig.context->Release();
624 m_vdpauConfig.context = 0;
627 long CDecoder::Release()
629 // check if we should do some pre-cleanup here
630 // a second decoder might need resources
631 if (m_vdpauConfigured == true)
633 CSingleLock lock(m_DecoderSection);
634 CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup");
637 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP,
641 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
645 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup returned error", __FUNCTION__);
646 m_DisplayState = VDPAU_ERROR;
651 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup timed out", __FUNCTION__);
652 m_DisplayState = VDPAU_ERROR;
655 VdpVideoSurface surf;
656 while((surf = m_videoSurfaces.RemoveNext(true)) != VDP_INVALID_HANDLE)
658 m_vdpauConfig.context->GetProcs().vdp_video_surface_destroy(surf);
661 return IHardwareDecoder::Release();
664 long CDecoder::ReleasePicReference()
666 return IHardwareDecoder::Release();
669 void CDecoder::SetWidthHeight(int width, int height)
671 m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling;
673 //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate
674 //this requires the least amount of gpu memory bandwidth
675 if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || m_vdpauConfig.upscale >= 0)
677 //scale width to desktop size if the aspect ratio is the same or bigger than the desktop
678 if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight())
680 m_vdpauConfig.outWidth = g_graphicsContext.GetWidth();
681 m_vdpauConfig.outHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width);
683 else //scale height to the desktop size if the aspect ratio is smaller than the desktop
685 m_vdpauConfig.outHeight = g_graphicsContext.GetHeight();
686 m_vdpauConfig.outWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height);
691 m_vdpauConfig.outWidth = width;
692 m_vdpauConfig.outHeight = height;
694 CLog::Log(LOGDEBUG, "CVDPAU::SetWidthHeight Setting OutWidth: %i OutHeight: %i", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight);
697 void CDecoder::OnLostDevice()
699 CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event");
701 int count = g_graphicsContext.exit();
703 CSingleLock lock(m_DecoderSection);
705 if (m_vdpauConfig.context)
706 m_vdpauConfig.context->Release();
707 m_vdpauConfig.context = 0;
709 m_DisplayState = VDPAU_LOST;
711 m_DisplayEvent.Reset();
713 g_graphicsContext.restore(count);
716 void CDecoder::OnResetDevice()
718 CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event");
720 int count = g_graphicsContext.exit();
722 CSingleLock lock(m_DecoderSection);
723 if (m_DisplayState == VDPAU_LOST)
725 m_DisplayState = VDPAU_RESET;
727 m_DisplayEvent.Set();
730 g_graphicsContext.restore(count);
733 int CDecoder::Check(AVCodecContext* avctx)
737 { CSingleLock lock(m_DecoderSection);
738 state = m_DisplayState;
741 if (state == VDPAU_LOST)
743 CLog::Log(LOGNOTICE,"CVDPAU::Check waiting for display reset event");
744 if (!m_DisplayEvent.WaitMSec(4000))
746 CLog::Log(LOGERROR, "CVDPAU::Check - device didn't reset in reasonable time");
751 CSingleLock lock(m_DecoderSection);
752 state = m_DisplayState;
755 if (state == VDPAU_RESET || state == VDPAU_ERROR)
757 CSingleLock lock(m_DecoderSection);
760 if (m_vdpauConfig.context)
761 m_vdpauConfig.context->Release();
762 m_vdpauConfig.context = 0;
764 if (CVDPAUContext::EnsureContext(&m_vdpauConfig.context))
766 m_DisplayState = VDPAU_OPEN;
767 m_vdpauConfigured = false;
770 if (state == VDPAU_RESET)
778 bool CDecoder::IsVDPAUFormat(PixelFormat format)
780 if (format == AV_PIX_FMT_VDPAU)
786 bool CDecoder::Supports(VdpVideoMixerFeature feature)
788 return m_vdpauConfig.context->Supports(feature);
791 bool CDecoder::Supports(EINTERLACEMETHOD method)
793 if(method == VS_INTERLACEMETHOD_VDPAU_BOB
794 || method == VS_INTERLACEMETHOD_AUTO)
797 if (method == VS_INTERLACEMETHOD_RENDER_BOB)
800 if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE)
803 for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++)
805 if(p->method == method)
806 return Supports(p->feature);
811 EINTERLACEMETHOD CDecoder::AutoInterlaceMethod()
813 return VS_INTERLACEMETHOD_RENDER_BOB;
816 void CDecoder::FiniVDPAUOutput()
818 if (!m_vdpauConfigured)
821 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
824 m_vdpauOutput.Dispose();
825 m_vdpauConfigured = false;
829 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
830 if (CheckStatus(vdp_st, __LINE__))
832 m_vdpauConfig.vdpDecoder = VDP_INVALID_HANDLE;
834 CLog::Log(LOGDEBUG, "CVDPAU::FiniVDPAUOutput destroying %d video surfaces", m_videoSurfaces.Size());
836 VdpVideoSurface surf;
837 while((surf = m_videoSurfaces.RemoveNext()) != VDP_INVALID_HANDLE)
839 m_vdpauConfig.context->GetProcs().vdp_video_surface_destroy(surf);
840 if (CheckStatus(vdp_st, __LINE__))
843 m_videoSurfaces.Reset();
846 void CDecoder::ReadFormatOf( AVCodecID codec
847 , VdpDecoderProfile &vdp_decoder_profile
848 , VdpChromaType &vdp_chroma_type)
852 case AV_CODEC_ID_MPEG1VIDEO:
853 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
854 vdp_chroma_type = VDP_CHROMA_TYPE_420;
856 case AV_CODEC_ID_MPEG2VIDEO:
857 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
858 vdp_chroma_type = VDP_CHROMA_TYPE_420;
860 case AV_CODEC_ID_H264:
861 vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
862 vdp_chroma_type = VDP_CHROMA_TYPE_420;
864 case AV_CODEC_ID_WMV3:
865 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
866 vdp_chroma_type = VDP_CHROMA_TYPE_420;
868 case AV_CODEC_ID_VC1:
869 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
870 vdp_chroma_type = VDP_CHROMA_TYPE_420;
872 case AV_CODEC_ID_MPEG4:
873 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
874 vdp_chroma_type = VDP_CHROMA_TYPE_420;
877 vdp_decoder_profile = 0;
883 bool CDecoder::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
888 VdpDecoderProfile vdp_decoder_profile;
890 m_vdpauConfig.vidWidth = avctx->width;
891 m_vdpauConfig.vidHeight = avctx->height;
892 m_vdpauConfig.surfaceWidth = avctx->coded_width;
893 m_vdpauConfig.surfaceHeight = avctx->coded_height;
895 SetWidthHeight(avctx->width,avctx->height);
897 CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",m_vdpauConfig.outWidth,m_vdpauConfig.vidWidth,m_vdpauConfig.surfaceWidth);
898 CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",m_vdpauConfig.outHeight,m_vdpauConfig.vidHeight,m_vdpauConfig.surfaceHeight);
900 ReadFormatOf(avctx->codec_id, vdp_decoder_profile, m_vdpauConfig.vdpChromaType);
902 if(avctx->codec_id == AV_CODEC_ID_H264)
904 m_vdpauConfig.maxReferences = ref_frames;
905 if (m_vdpauConfig.maxReferences > 16) m_vdpauConfig.maxReferences = 16;
906 if (m_vdpauConfig.maxReferences < 5) m_vdpauConfig.maxReferences = 5;
909 m_vdpauConfig.maxReferences = 2;
911 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_create(m_vdpauConfig.context->GetDevice(),
913 m_vdpauConfig.surfaceWidth,
914 m_vdpauConfig.surfaceHeight,
915 m_vdpauConfig.maxReferences,
916 &m_vdpauConfig.vdpDecoder);
917 if (CheckStatus(vdp_st, __LINE__))
921 CSingleLock lock(g_graphicsContext);
922 m_vdpauConfig.stats = &m_bufferStats;
923 m_vdpauConfig.vdpau = this;
924 m_bufferStats.Reset();
925 m_vdpauOutput.Start();
927 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT,
931 sizeof(m_vdpauConfig)))
933 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
937 CLog::Log(LOGERROR, "VDPAU::%s - vdpau output returned error", __FUNCTION__);
938 m_vdpauOutput.Dispose();
944 CLog::Log(LOGERROR, "VDPAU::%s - failed to init output", __FUNCTION__);
945 m_vdpauOutput.Dispose();
949 m_inMsgEvent.Reset();
950 m_vdpauConfigured = true;
954 int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
956 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
957 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
958 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
960 // while we are waiting to recover we can't do anything
961 CSingleLock lock(vdp->m_DecoderSection);
963 if(vdp->m_DisplayState != VDPAU_OPEN)
965 CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
969 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
970 surf = vdp->m_videoSurfaces.GetFree(surf != 0 ? surf : VDP_INVALID_HANDLE);
972 VdpStatus vdp_st = VDP_STATUS_ERROR;
973 if (surf == VDP_INVALID_HANDLE)
975 // create a new surface
976 VdpDecoderProfile profile;
977 ReadFormatOf(avctx->codec_id, profile, vdp->m_vdpauConfig.vdpChromaType);
979 vdp_st = vdp->m_vdpauConfig.context->GetProcs().vdp_video_surface_create(vdp->m_vdpauConfig.context->GetDevice(),
980 vdp->m_vdpauConfig.vdpChromaType,
984 vdp->CheckStatus(vdp_st, __LINE__);
985 if (vdp_st != VDP_STATUS_OK)
987 CLog::Log(LOGERROR, "CVDPAU::FFGetBuffer - No Video surface available could be created");
990 vdp->m_videoSurfaces.AddSurface(surf);
993 pic->data[1] = pic->data[2] = NULL;
994 pic->data[0] = (uint8_t*)(uintptr_t)surf;
995 pic->data[3] = (uint8_t*)(uintptr_t)surf;
997 pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0;
999 pic->type= FF_BUFFER_TYPE_USER;
1001 pic->reordered_opaque= avctx->reordered_opaque;
1005 void CDecoder::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
1007 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
1008 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
1010 VdpVideoSurface surf;
1013 CSingleLock lock(vdp->m_DecoderSection);
1015 surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
1017 vdp->m_videoSurfaces.ClearReference(surf);
1023 VdpStatus CDecoder::Render( VdpDecoder decoder, VdpVideoSurface target,
1024 VdpPictureInfo const *picture_info,
1025 uint32_t bitstream_buffer_count,
1026 VdpBitstreamBuffer const * bitstream_buffers)
1028 return VDP_STATUS_OK;
1031 void CDecoder::FFDrawSlice(struct AVCodecContext *s,
1032 const AVFrame *src, int offset[4],
1033 int y, int type, int height)
1035 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque;
1036 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
1038 // while we are waiting to recover we can't do anything
1039 CSingleLock lock(vdp->m_DecoderSection);
1041 if(vdp->m_DisplayState != VDPAU_OPEN)
1044 if(src->linesize[0] || src->linesize[1] || src->linesize[2]
1045 || offset[0] || offset[1] || offset[2])
1047 CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid linesizes or offsets provided");
1052 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)src->data[3];
1054 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1055 if (!vdp->m_videoSurfaces.IsValid(surf))
1057 CLog::Log(LOGWARNING, "CVDPAU::FFDrawSlice - ignoring invalid buffer");
1061 uint32_t max_refs = 0;
1062 if(s->codec_id == AV_CODEC_ID_H264)
1063 max_refs = vdp->m_hwContext.info.h264.num_ref_frames;
1065 if(vdp->m_vdpauConfig.vdpDecoder == VDP_INVALID_HANDLE
1066 || vdp->m_vdpauConfigured == false
1067 || vdp->m_vdpauConfig.maxReferences < max_refs)
1069 if(!vdp->ConfigVDPAU(s, max_refs))
1073 uint64_t startTime = CurrentHostCounter();
1074 uint16_t decoded, processed, rend;
1075 vdp->m_bufferStats.Get(decoded, processed, rend);
1076 vdp_st = vdp->m_vdpauConfig.context->GetProcs().vdp_decoder_render(vdp->m_vdpauConfig.vdpDecoder,
1078 (VdpPictureInfo const *)&(vdp->m_hwContext.info),
1079 vdp->m_hwContext.bitstream_buffers_used,
1080 vdp->m_hwContext.bitstream_buffers);
1081 vdp->CheckStatus(vdp_st, __LINE__);
1082 uint64_t diff = CurrentHostCounter() - startTime;
1083 if (diff*1000/CurrentHostFrequency() > 30)
1084 CLog::Log(LOGDEBUG, "CVDPAU::DrawSlice - VdpDecoderRender long decoding: %d ms, dec: %d, proc: %d, rend: %d", (int)((diff*1000)/CurrentHostFrequency()), decoded, processed, rend);
1088 int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame)
1090 int result = Check(avctx);
1094 CSingleLock lock(m_DecoderSection);
1096 if (!m_vdpauConfigured)
1100 { // we have a new frame from decoder
1102 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pFrame->data[3];
1103 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1104 if (!m_videoSurfaces.IsValid(surf))
1106 CLog::Log(LOGWARNING, "CVDPAU::Decode - ignoring invalid buffer");
1109 m_videoSurfaces.MarkRender(surf);
1111 // send frame to output for processing
1112 CVdpauDecodedPicture pic;
1113 memset(&pic.DVDPic, 0, sizeof(pic.DVDPic));
1114 ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic);
1115 pic.videoSurface = surf;
1116 pic.DVDPic.color_matrix = avctx->colorspace;
1117 m_bufferStats.IncDecoded();
1118 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic));
1121 // m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC);
1125 uint16_t decoded, processed, render;
1127 while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1129 if (msg->signal == COutputControlProtocol::ERROR)
1131 m_DisplayState = VDPAU_ERROR;
1137 m_bufferStats.Get(decoded, processed, render);
1139 uint64_t startTime = CurrentHostCounter();
1142 // first fill the buffers to keep vdpau busy
1143 // mixer will run with decoded >= 2. output is limited by number of output surfaces
1144 // In case mixer is bypassed we limit by looking at processed
1145 if (decoded < 3 && processed < 3)
1147 retval |= VC_BUFFER;
1149 else if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg))
1151 if (msg->signal == COutputDataProtocol::PICTURE)
1153 if (m_presentPicture)
1155 m_presentPicture->ReturnUnused();
1156 m_presentPicture = 0;
1159 m_presentPicture = *(CVdpauRenderPicture**)msg->data;
1160 m_presentPicture->vdpau = this;
1161 m_bufferStats.DecRender();
1162 m_bufferStats.Get(decoded, processed, render);
1163 retval |= VC_PICTURE;
1169 else if (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1171 if (msg->signal == COutputControlProtocol::STATS)
1173 m_bufferStats.Get(decoded, processed, render);
1177 m_DisplayState = VDPAU_ERROR;
1183 if (decoded < 3 && processed < 3)
1185 retval |= VC_BUFFER;
1188 if (!retval && !m_inMsgEvent.WaitMSec(2000))
1191 uint64_t diff = CurrentHostCounter() - startTime;
1192 if (retval & VC_PICTURE)
1194 m_bufferStats.SetParams(diff, m_codecControl);
1196 if (diff*1000/CurrentHostFrequency() > 50)
1197 CLog::Log(LOGDEBUG,"CVDPAU::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency()));
1201 CLog::Log(LOGERROR, "VDPAU::%s - timed out waiting for output message", __FUNCTION__);
1202 m_DisplayState = VDPAU_ERROR;
1209 bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
1211 CSingleLock lock(m_DecoderSection);
1213 if (m_DisplayState != VDPAU_OPEN)
1216 *picture = m_presentPicture->DVDPic;
1217 picture->vdpau = m_presentPicture;
1222 void CDecoder::Reset()
1224 CSingleLock lock(m_DecoderSection);
1226 if (!m_vdpauConfigured)
1230 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH,
1234 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
1238 CLog::Log(LOGERROR, "VDPAU::%s - flush returned error", __FUNCTION__);
1239 m_DisplayState = VDPAU_ERROR;
1242 m_bufferStats.Reset();
1246 CLog::Log(LOGERROR, "VDPAU::%s - flush timed out", __FUNCTION__);
1247 m_DisplayState = VDPAU_ERROR;
1251 bool CDecoder::CanSkipDeint()
1253 return m_bufferStats.CanSkipDeint();
1256 void CDecoder::ReturnRenderPicture(CVdpauRenderPicture *renderPic)
1258 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic));
1261 bool CDecoder::CheckStatus(VdpStatus vdp_st, int line)
1263 if (vdp_st != VDP_STATUS_OK)
1265 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);
1267 if(m_DisplayState == VDPAU_OPEN)
1269 if (vdp_st == VDP_STATUS_DISPLAY_PREEMPTED)
1271 m_DisplayEvent.Reset();
1272 m_DisplayState = VDPAU_LOST;
1275 m_DisplayState = VDPAU_ERROR;
1283 //-----------------------------------------------------------------------------
1285 //-----------------------------------------------------------------------------
1287 CVdpauRenderPicture* CVdpauRenderPicture::Acquire()
1289 CSingleLock lock(renderPicSection);
1298 long CVdpauRenderPicture::Release()
1300 CSingleLock lock(renderPicSection);
1307 vdpau->ReturnRenderPicture(this);
1308 vdpau->ReleasePicReference();
1313 void CVdpauRenderPicture::ReturnUnused()
1315 { CSingleLock lock(renderPicSection);
1320 vdpau->ReturnRenderPicture(this);
1323 void CVdpauRenderPicture::Sync()
1326 CSingleLock lock(renderPicSection);
1331 glDeleteSync(fence);
1334 fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1339 //-----------------------------------------------------------------------------
1341 //-----------------------------------------------------------------------------
1342 CMixer::CMixer(CEvent *inMsgEvent) :
1343 CThread("Vdpau Mixer"),
1344 m_controlPort("ControlPort", inMsgEvent, &m_outMsgEvent),
1345 m_dataPort("DataPort", inMsgEvent, &m_outMsgEvent)
1347 m_inMsgEvent = inMsgEvent;
1355 void CMixer::Start()
1360 void CMixer::Dispose()
1363 m_outMsgEvent.Set();
1366 m_controlPort.Purge();
1370 bool CMixer::IsActive()
1375 void CMixer::OnStartup()
1377 CLog::Log(LOGNOTICE, "CMixer::OnStartup: Output Thread created");
1380 void CMixer::OnExit()
1382 CLog::Log(LOGNOTICE, "CMixer::OnExit: Output Thread terminated");
1389 M_TOP_UNCONFIGURED, // 2
1390 M_TOP_CONFIGURED, // 3
1391 M_TOP_CONFIGURED_WAIT1, // 4
1392 M_TOP_CONFIGURED_STEP1, // 5
1393 M_TOP_CONFIGURED_WAIT2, // 6
1394 M_TOP_CONFIGURED_STEP2, // 7
1397 int MIXER_parentStates[] = {
1400 0, //TOP_UNCONFIGURED
1402 3, //TOP_CONFIGURED_WAIT1
1403 3, //TOP_CONFIGURED_STEP1
1404 3, //TOP_CONFIGURED_WAIT2
1405 3, //TOP_CONFIGURED_STEP2
1408 void CMixer::StateMachine(int signal, Protocol *port, Message *msg)
1410 for (int state = m_state; ; state = MIXER_parentStates[state])
1415 if (port == &m_controlPort)
1419 case CMixerControlProtocol::FLUSH:
1421 msg->Reply(CMixerControlProtocol::ACC);
1428 std::string portName = port == NULL ? "timer" : port->portName;
1429 CLog::Log(LOGWARNING, "CMixer::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
1433 case M_TOP_ERROR: // TOP
1436 case M_TOP_UNCONFIGURED:
1437 if (port == &m_controlPort)
1441 case CMixerControlProtocol::INIT:
1443 data = (CVdpauConfig*)msg->data;
1451 m_state = M_TOP_CONFIGURED_WAIT1;
1452 msg->Reply(CMixerControlProtocol::ACC);
1456 msg->Reply(CMixerControlProtocol::ERROR);
1465 case M_TOP_CONFIGURED:
1466 if (port == &m_dataPort)
1470 case CMixerDataProtocol::FRAME:
1471 CVdpauDecodedPicture *frame;
1472 frame = (CVdpauDecodedPicture*)msg->data;
1475 m_decodedPics.push(*frame);
1479 case CMixerDataProtocol::BUFFER:
1480 VdpOutputSurface *surf;
1481 surf = (VdpOutputSurface*)msg->data;
1484 m_outputSurfaces.push(*surf);
1494 case M_TOP_CONFIGURED_WAIT1:
1495 if (port == NULL) // timeout
1499 case CMixerControlProtocol::TIMEOUT:
1500 if (!m_decodedPics.empty() && !m_outputSurfaces.empty())
1502 m_state = M_TOP_CONFIGURED_STEP1;
1503 m_bStateMachineSelfTrigger = true;
1516 case M_TOP_CONFIGURED_STEP1:
1517 if (port == NULL) // timeout
1521 case CMixerControlProtocol::TIMEOUT:
1522 m_mixerInput.push_front(m_decodedPics.front());
1523 m_decodedPics.pop();
1524 if (m_mixerInput.size() < 2)
1526 m_state = M_TOP_CONFIGURED_WAIT1;
1534 m_state = M_TOP_CONFIGURED_WAIT1;
1535 m_extTimeout = 1000;
1538 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1539 m_outputSurfaces.pop();
1540 m_config.stats->IncProcessed();
1541 m_config.stats->DecDecoded();
1542 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1543 if (m_mixersteps > 1)
1545 m_state = M_TOP_CONFIGURED_WAIT2;
1551 m_state = M_TOP_CONFIGURED_WAIT1;
1561 case M_TOP_CONFIGURED_WAIT2:
1562 if (port == NULL) // timeout
1566 case CMixerControlProtocol::TIMEOUT:
1567 if (!m_outputSurfaces.empty())
1569 m_state = M_TOP_CONFIGURED_STEP2;
1570 m_bStateMachineSelfTrigger = true;
1583 case M_TOP_CONFIGURED_STEP2:
1584 if (port == NULL) // timeout
1588 case CMixerControlProtocol::TIMEOUT:
1589 m_processPicture.outputSurface = m_outputSurfaces.front();
1594 m_state = M_TOP_CONFIGURED_WAIT1;
1595 m_extTimeout = 1000;
1598 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1599 m_outputSurfaces.pop();
1600 m_config.stats->IncProcessed();
1601 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1603 m_state = M_TOP_CONFIGURED_WAIT1;
1612 default: // we are in no state, should not happen
1613 CLog::Log(LOGERROR, "CMixer::%s - no valid state: %d", __FUNCTION__, m_state);
1619 void CMixer::Process()
1621 Message *msg = NULL;
1622 Protocol *port = NULL;
1625 m_state = M_TOP_UNCONFIGURED;
1626 m_extTimeout = 1000;
1627 m_bStateMachineSelfTrigger = false;
1633 if (m_bStateMachineSelfTrigger)
1635 m_bStateMachineSelfTrigger = false;
1636 // self trigger state machine
1637 StateMachine(msg->signal, port, msg);
1638 if (!m_bStateMachineSelfTrigger)
1645 // check control port
1646 else if (m_controlPort.ReceiveOutMessage(&msg))
1649 port = &m_controlPort;
1652 else if (m_dataPort.ReceiveOutMessage(&msg))
1660 StateMachine(msg->signal, port, msg);
1661 if (!m_bStateMachineSelfTrigger)
1670 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
1677 msg = m_controlPort.GetMessage();
1678 msg->signal = CMixerControlProtocol::TIMEOUT;
1680 // signal timeout to state machine
1681 StateMachine(msg->signal, port, msg);
1682 if (!m_bStateMachineSelfTrigger)
1692 void CMixer::CreateVdpauMixer()
1694 CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer");
1696 InitCSCMatrix(m_config.vidWidth);
1698 VdpVideoMixerParameter parameters[] = {
1699 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
1700 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
1701 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE};
1703 void const * parameter_values[] = {
1704 &m_config.surfaceWidth,
1705 &m_config.surfaceHeight,
1706 &m_config.vdpChromaType};
1708 VdpStatus vdp_st = VDP_STATUS_ERROR;
1709 vdp_st = m_config.context->GetProcs().vdp_video_mixer_create(m_config.context->GetDevice(),
1710 m_config.context->GetFeatureCount(),
1711 m_config.context->GetFeatures(),
1716 CheckStatus(vdp_st, __LINE__);
1720 void CMixer::InitCSCMatrix(int Width)
1722 m_Procamp.struct_version = VDP_PROCAMP_VERSION;
1723 m_Procamp.brightness = 0.0;
1724 m_Procamp.contrast = 1.0;
1725 m_Procamp.saturation = 1.0;
1729 void CMixer::CheckFeatures()
1731 if (m_Upscale != m_config.upscale)
1734 m_Upscale = m_config.upscale;
1736 if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness ||
1737 m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast ||
1738 m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix)
1741 m_Brightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness;
1742 m_Contrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast;
1743 m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix;
1745 if (m_NoiseReduction != CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1747 m_NoiseReduction = CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction;
1748 SetNoiseReduction();
1750 if (m_Sharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1752 m_Sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
1755 if (m_DeintMode != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode ||
1756 m_Deint != CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod)
1758 m_DeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1759 m_Deint = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1764 void CMixer::SetPostProcFeatures(bool postProcEnabled)
1766 if (m_PostProc != postProcEnabled)
1768 if (postProcEnabled)
1770 SetNoiseReduction();
1777 m_PostProc = postProcEnabled;
1781 void CMixer::PostProcOff()
1785 if (m_videoMixer == VDP_INVALID_HANDLE)
1788 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
1789 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
1790 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE};
1792 VdpBool enabled[]={0,0,0};
1793 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1794 CheckStatus(vdp_st, __LINE__);
1796 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1798 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION};
1800 VdpBool enabled[]={0};
1801 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1802 CheckStatus(vdp_st, __LINE__);
1805 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1807 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS};
1809 VdpBool enabled[]={0};
1810 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1811 CheckStatus(vdp_st, __LINE__);
1817 bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix)
1819 // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4])
1820 // m00 = mRY = red: luma factor (contrast factor) (1.0)
1821 // m10 = mGY = green: luma factor (contrast factor) (1.0)
1822 // m20 = mBY = blue: luma factor (contrast factor) (1.0)
1824 // m01 = mRB = red: blue color diff coeff (0.0)
1825 // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg))
1826 // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5)
1828 // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5)
1829 // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg))
1830 // m22 = mBR = blue: red color diff coeff (0.0)
1832 // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255))
1833 // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg)
1834 // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255))
1845 // colour standard coefficients for red, geen, blue
1847 // colour diff zero position (use standard 8-bit coding precision)
1848 double CDZ = 128; //256*0.5
1849 // range excursion (use standard 8-bit coding precision)
1850 double EXC = 255; //256-1
1852 if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601)
1854 Kr = studioCSCKCoeffs601[0];
1855 Kg = studioCSCKCoeffs601[1];
1856 Kb = studioCSCKCoeffs601[2];
1858 else // assume VDP_COLOR_STANDARD_ITUR_BT_709
1860 Kr = studioCSCKCoeffs709[0];
1861 Kg = studioCSCKCoeffs709[1];
1862 Kb = studioCSCKCoeffs709[2];
1864 // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235
1865 studioCSCMatrix[R][Y] = 1.0;
1866 studioCSCMatrix[G][Y] = 1.0;
1867 studioCSCMatrix[B][Y] = 1.0;
1869 studioCSCMatrix[R][Cb] = 0.0;
1870 studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg;
1871 studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5;
1873 studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5;
1874 studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg;
1875 studioCSCMatrix[B][Cr] = 0.0;
1877 studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC;
1878 studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC;
1879 studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC;
1884 void CMixer::SetColor()
1888 if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)
1889 m_Procamp.brightness = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)-50) / 100;
1890 if (m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)
1891 m_Procamp.contrast = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)+50) / 100;
1893 VdpColorStandard colorStandard;
1894 switch(m_mixerInput[1].DVDPic.color_matrix)
1896 case AVCOL_SPC_BT709:
1897 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1899 case AVCOL_SPC_BT470BG:
1900 case AVCOL_SPC_SMPTE170M:
1901 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1903 case AVCOL_SPC_SMPTE240M:
1904 colorStandard = VDP_COLOR_STANDARD_SMPTE_240M;
1907 case AVCOL_SPC_UNSPECIFIED:
1910 if(m_config.surfaceWidth > 1000)
1911 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1913 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1916 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
1917 if (CSettings::Get().GetBool("videoscreen.limitedrange"))
1919 float studioCSC[3][4];
1920 GenerateStudioCSCMatrix(colorStandard, studioCSC);
1921 void const * pm_CSCMatix[] = { &studioCSC };
1922 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1926 vdp_st = m_config.context->GetProcs().vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix);
1927 void const * pm_CSCMatix[] = { &m_CSCMatrix };
1928 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1931 CheckStatus(vdp_st, __LINE__);
1934 void CMixer::SetNoiseReduction()
1936 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1939 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION };
1940 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL };
1943 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1945 VdpBool enabled[]= {0};
1946 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1947 CheckStatus(vdp_st, __LINE__);
1950 VdpBool enabled[]={1};
1951 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1952 CheckStatus(vdp_st, __LINE__);
1953 void* nr[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction };
1954 CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction);
1955 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, nr);
1956 CheckStatus(vdp_st, __LINE__);
1959 void CMixer::SetSharpness()
1961 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1964 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS };
1965 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL };
1968 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1970 VdpBool enabled[]={0};
1971 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1972 CheckStatus(vdp_st, __LINE__);
1975 VdpBool enabled[]={1};
1976 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1977 CheckStatus(vdp_st, __LINE__);
1978 void* sh[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness };
1979 CLog::Log(LOGNOTICE,"Setting Sharpness to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness);
1980 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, sh);
1981 CheckStatus(vdp_st, __LINE__);
1984 EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */)
1986 EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1987 if (method == VS_INTERLACEMETHOD_AUTO)
1990 // if (m_config.outHeight >= 720)
1991 // deint = g_advancedSettings.m_videoVDPAUdeintHD;
1993 // deint = g_advancedSettings.m_videoVDPAUdeintSD;
1997 if (m_config.vdpau->Supports(EINTERLACEMETHOD(deint)))
1999 method = EINTERLACEMETHOD(deint);
2001 CLog::Log(LOGNOTICE, "CVDPAU::GetDeinterlacingMethod: set de-interlacing to %d", deint);
2006 CLog::Log(LOGWARNING, "CVDPAU::GetDeinterlacingMethod: method for de-interlacing (advanced settings) not supported");
2013 void CMixer::SetDeinterlacing()
2017 if (m_videoMixer == VDP_INVALID_HANDLE)
2020 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
2021 EINTERLACEMETHOD method = GetDeinterlacingMethod(true);
2023 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
2024 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
2025 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE };
2027 if (mode == VS_DEINTERLACEMODE_OFF)
2029 VdpBool enabled[] = {0,0,0};
2030 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2034 if (method == VS_INTERLACEMETHOD_AUTO)
2036 VdpBool enabled[] = {1,0,0};
2037 if (g_advancedSettings.m_videoVDPAUtelecine)
2039 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2041 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2042 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF)
2044 VdpBool enabled[] = {1,0,0};
2045 if (g_advancedSettings.m_videoVDPAUtelecine)
2047 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2049 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2050 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF)
2052 VdpBool enabled[] = {1,1,0};
2053 if (g_advancedSettings.m_videoVDPAUtelecine)
2055 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2059 VdpBool enabled[]={0,0,0};
2060 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2063 CheckStatus(vdp_st, __LINE__);
2065 SetDeintSkipChroma();
2067 m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
2070 void CMixer::SetDeintSkipChroma()
2072 VdpVideoMixerAttribute attribute[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE};
2076 if (g_advancedSettings.m_videoVDPAUdeintSkipChromaHD && m_config.outHeight >= 720)
2081 void const *values[]={&val};
2082 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attribute), attribute, values);
2084 CheckStatus(vdp_st, __LINE__);
2087 void CMixer::SetHWUpscaling()
2089 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
2092 VdpBool enabled[]={1};
2093 switch (m_config.upscale)
2096 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
2098 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
2099 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2103 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
2105 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
2106 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2110 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2112 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2113 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2117 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2119 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2120 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2124 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2126 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2127 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2131 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2133 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2134 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2138 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2140 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2141 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2145 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2147 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2148 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2152 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2154 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2155 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2162 CheckStatus(vdp_st, __LINE__);
2166 void CMixer::DisableHQScaling()
2170 if (m_videoMixer == VDP_INVALID_HANDLE)
2173 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2175 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2176 VdpBool enabled[]={0};
2177 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2178 CheckStatus(vdp_st, __LINE__);
2181 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2183 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2184 VdpBool enabled[]={0};
2185 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2186 CheckStatus(vdp_st, __LINE__);
2189 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2191 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2192 VdpBool enabled[]={0};
2193 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2194 CheckStatus(vdp_st, __LINE__);
2197 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2199 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2200 VdpBool enabled[]={0};
2201 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2202 CheckStatus(vdp_st, __LINE__);
2205 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2207 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2208 VdpBool enabled[]={0};
2209 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2210 CheckStatus(vdp_st, __LINE__);
2213 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2215 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2216 VdpBool enabled[]={0};
2217 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2218 CheckStatus(vdp_st, __LINE__);
2221 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2223 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2224 VdpBool enabled[]={0};
2225 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2226 CheckStatus(vdp_st, __LINE__);
2229 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
2231 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
2232 VdpBool enabled[]={0};
2233 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2234 CheckStatus(vdp_st, __LINE__);
2237 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
2239 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
2240 VdpBool enabled[]={0};
2241 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2242 CheckStatus(vdp_st, __LINE__);
2250 m_NoiseReduction = 0.0;
2255 m_SeenInterlaceFlag = false;
2260 m_config.upscale = g_advancedSettings.m_videoVDPAUScaling;
2261 m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
2266 void CMixer::Uninit()
2269 while (!m_outputSurfaces.empty())
2271 m_outputSurfaces.pop();
2273 m_config.context->GetProcs().vdp_video_mixer_destroy(m_videoMixer);
2276 void CMixer::Flush()
2278 while (!m_mixerInput.empty())
2280 CVdpauDecodedPicture pic = m_mixerInput.back();
2281 m_mixerInput.pop_back();
2282 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2284 while (!m_decodedPics.empty())
2286 CVdpauDecodedPicture pic = m_decodedPics.front();
2287 m_decodedPics.pop();
2288 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2291 while (m_dataPort.ReceiveOutMessage(&msg))
2293 if (msg->signal == CMixerDataProtocol::FRAME)
2295 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2296 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2298 else if (msg->signal == CMixerDataProtocol::BUFFER)
2300 VdpOutputSurface *surf;
2301 surf = (VdpOutputSurface*)msg->data;
2302 m_outputSurfaces.push(*surf);
2308 void CMixer::InitCycle()
2313 m_config.stats->GetParams(latency, flags);
2315 if (0) //flags & DVP_FLAG_NO_POSTPROC)
2316 SetPostProcFeatures(false);
2318 SetPostProcFeatures(true);
2320 m_config.stats->SetCanSkipDeint(false);
2322 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
2323 EINTERLACEMETHOD method = GetDeinterlacingMethod();
2324 bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED;
2325 m_SeenInterlaceFlag |= interlaced;
2328 if (//!(flags & DVP_FLAG_NO_POSTPROC) &&
2329 (mode == VS_DEINTERLACEMODE_FORCE ||
2330 (mode == VS_DEINTERLACEMODE_AUTO && interlaced)))
2332 if((method == VS_INTERLACEMETHOD_AUTO && interlaced)
2333 || method == VS_INTERLACEMETHOD_VDPAU_BOB
2334 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2335 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2336 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2337 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2338 || method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE )
2340 if(method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2341 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2342 || !g_graphicsContext.IsFullScreenVideo())
2347 m_config.stats->SetCanSkipDeint(true);
2351 if (0) //m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_DROPDEINT)
2356 if(m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST)
2357 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2359 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2361 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2362 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2363 DVP_FLAG_REPEAT_TOP_FIELD |
2364 DVP_FLAG_INTERLACED);
2365 m_config.useInteropYuv = false;
2367 else if (method == VS_INTERLACEMETHOD_RENDER_BOB)
2370 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2371 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2372 m_config.useInteropYuv = true;
2376 CLog::Log(LOGERROR, "CMixer::%s - interlace method: %d not supported, setting to AUTO", __FUNCTION__, method);
2378 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2379 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2380 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2381 DVP_FLAG_REPEAT_TOP_FIELD |
2382 DVP_FLAG_INTERLACED);
2384 CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod = VS_INTERLACEMETHOD_AUTO;
2390 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2392 if (m_config.useInteropYuv)
2393 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2396 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2397 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2398 DVP_FLAG_REPEAT_TOP_FIELD |
2399 DVP_FLAG_INTERLACED);
2404 if (m_mixerInput[1].DVDPic.format == RENDER_FMT_VDPAU)
2406 m_processPicture.outputSurface = m_outputSurfaces.front();
2407 m_mixerInput[1].DVDPic.iWidth = m_config.outWidth;
2408 m_mixerInput[1].DVDPic.iHeight = m_config.outHeight;
2409 if (m_SeenInterlaceFlag)
2411 double ratio = (double)m_mixerInput[1].DVDPic.iDisplayHeight / m_mixerInput[1].DVDPic.iHeight;
2412 m_mixerInput[1].DVDPic.iHeight -= 6;
2413 m_mixerInput[1].DVDPic.iDisplayHeight = lrint(ratio*m_mixerInput[1].DVDPic.iHeight);
2418 m_mixerInput[1].DVDPic.iWidth = m_config.vidWidth;
2419 m_mixerInput[1].DVDPic.iHeight = m_config.vidHeight;
2422 m_processPicture.DVDPic = m_mixerInput[1].DVDPic;
2423 m_processPicture.videoSurface = m_mixerInput[1].videoSurface;
2426 void CMixer::FiniCycle()
2428 // Keep video surfaces for one 2 cycles longer than used
2429 // by mixer. This avoids blocking in decoder.
2430 // NVidia recommends num_ref + 5
2431 while (m_mixerInput.size() > 5)
2433 CVdpauDecodedPicture &tmp = m_mixerInput.back();
2434 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
2436 m_config.videoSurfaces->ClearRender(tmp.videoSurface);
2438 m_mixerInput.pop_back();
2442 void CMixer::ProcessPicture()
2444 if (m_processPicture.DVDPic.format == RENDER_FMT_VDPAU_420)
2449 if (m_mixerstep == 1)
2451 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD)
2452 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2454 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2457 VdpVideoSurface past_surfaces[4] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2458 VdpVideoSurface futu_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2459 uint32_t pastCount = 4;
2460 uint32_t futuCount = 2;
2462 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
2464 // use only 2 past 1 future for progressive/weave
2465 // (only used for postproc anyway eg noise reduction)
2466 if (m_mixerInput.size() > 3)
2467 past_surfaces[1] = m_mixerInput[3].videoSurface;
2468 if (m_mixerInput.size() > 2)
2469 past_surfaces[0] = m_mixerInput[2].videoSurface;
2470 futu_surfaces[0] = m_mixerInput[0].videoSurface;
2476 if(m_mixerstep == 0)
2478 if (m_mixerInput.size() > 3)
2480 past_surfaces[3] = m_mixerInput[3].videoSurface;
2481 past_surfaces[2] = m_mixerInput[3].videoSurface;
2483 if (m_mixerInput.size() > 2)
2485 past_surfaces[1] = m_mixerInput[2].videoSurface;
2486 past_surfaces[0] = m_mixerInput[2].videoSurface;
2488 futu_surfaces[0] = m_mixerInput[1].videoSurface;
2489 futu_surfaces[1] = m_mixerInput[0].videoSurface;
2493 if (m_mixerInput.size() > 3)
2495 past_surfaces[3] = m_mixerInput[3].videoSurface;
2497 if (m_mixerInput.size() > 2)
2499 past_surfaces[2] = m_mixerInput[2].videoSurface;
2500 past_surfaces[1] = m_mixerInput[2].videoSurface;
2502 past_surfaces[0] = m_mixerInput[1].videoSurface;
2503 futu_surfaces[0] = m_mixerInput[0].videoSurface;
2504 futu_surfaces[1] = m_mixerInput[0].videoSurface;
2506 if (m_mixerInput[0].DVDPic.pts != DVD_NOPTS_VALUE &&
2507 m_mixerInput[1].DVDPic.pts != DVD_NOPTS_VALUE)
2509 m_processPicture.DVDPic.pts = m_mixerInput[1].DVDPic.pts +
2510 (m_mixerInput[0].DVDPic.pts -
2511 m_mixerInput[1].DVDPic.pts) / 2;
2514 m_processPicture.DVDPic.pts = DVD_NOPTS_VALUE;
2515 m_processPicture.DVDPic.dts = DVD_NOPTS_VALUE;
2517 m_processPicture.DVDPic.iRepeatPicture = 0.0;
2523 sourceRect.x1 = m_config.vidWidth;
2524 sourceRect.y1 = m_config.vidHeight;
2529 destRect.x1 = m_config.outWidth;
2530 destRect.y1 = m_config.outHeight;
2532 // start vdpau video mixer
2533 vdp_st = m_config.context->GetProcs().vdp_video_mixer_render(m_videoMixer,
2539 m_mixerInput[1].videoSurface,
2543 m_processPicture.outputSurface,
2548 CheckStatus(vdp_st, __LINE__);
2552 bool CMixer::CheckStatus(VdpStatus vdp_st, int line)
2554 if (vdp_st != VDP_STATUS_OK)
2556 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);
2563 //-----------------------------------------------------------------------------
2565 //-----------------------------------------------------------------------------
2567 VdpauBufferPool::VdpauBufferPool()
2569 CVdpauRenderPicture *pic;
2570 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2572 pic = new CVdpauRenderPicture(renderPicSec);
2573 allRenderPics.push_back(pic);
2577 VdpauBufferPool::~VdpauBufferPool()
2579 CVdpauRenderPicture *pic;
2580 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2582 pic = allRenderPics[i];
2585 allRenderPics.clear();
2588 //-----------------------------------------------------------------------------
2590 //-----------------------------------------------------------------------------
2591 COutput::COutput(CEvent *inMsgEvent) :
2592 CThread("Vdpau Output"),
2593 m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent),
2594 m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent),
2595 m_mixer(&m_outMsgEvent)
2597 m_inMsgEvent = inMsgEvent;
2599 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i)
2601 m_bufferPool.freeRenderPics.push_back(i);
2605 void COutput::Start()
2614 m_bufferPool.freeRenderPics.clear();
2615 m_bufferPool.usedRenderPics.clear();
2618 void COutput::Dispose()
2620 CSingleLock lock(g_graphicsContext);
2622 m_outMsgEvent.Set();
2624 m_controlPort.Purge();
2628 void COutput::OnStartup()
2630 CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created");
2633 void COutput::OnExit()
2635 CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated");
2642 O_TOP_UNCONFIGURED, // 2
2643 O_TOP_CONFIGURED, // 3
2644 O_TOP_CONFIGURED_IDLE, // 4
2645 O_TOP_CONFIGURED_WORK, // 5
2648 int VDPAU_OUTPUT_parentStates[] = {
2651 0, //TOP_UNCONFIGURED
2653 3, //TOP_CONFIGURED_IDLE
2654 3, //TOP_CONFIGURED_WORK
2657 void COutput::StateMachine(int signal, Protocol *port, Message *msg)
2659 for (int state = m_state; ; state = VDPAU_OUTPUT_parentStates[state])
2664 if (port == &m_controlPort)
2668 case COutputControlProtocol::FLUSH:
2669 msg->Reply(COutputControlProtocol::ACC);
2671 case COutputControlProtocol::PRECLEANUP:
2672 msg->Reply(COutputControlProtocol::ACC);
2678 else if (port == &m_dataPort)
2682 case COutputDataProtocol::RETURNPIC:
2683 CVdpauRenderPicture *pic;
2684 pic = *((CVdpauRenderPicture**)msg->data);
2685 QueueReturnPicture(pic);
2692 std::string portName = port == NULL ? "timer" : port->portName;
2693 CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
2700 case O_TOP_UNCONFIGURED:
2701 if (port == &m_controlPort)
2705 case COutputControlProtocol::INIT:
2707 data = (CVdpauConfig*)msg->data;
2714 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::INIT,
2715 &reply, 1000, &m_config, sizeof(m_config)))
2717 if (reply->signal != CMixerControlProtocol::ACC)
2722 // set initial number of
2723 m_bufferPool.numOutputSurfaces = 4;
2727 m_state = O_TOP_CONFIGURED_IDLE;
2728 msg->Reply(COutputControlProtocol::ACC, &m_config, sizeof(m_config));
2732 m_state = O_TOP_ERROR;
2733 msg->Reply(COutputControlProtocol::ERROR);
2742 case O_TOP_CONFIGURED:
2743 if (port == &m_controlPort)
2747 case COutputControlProtocol::FLUSH:
2749 msg->Reply(COutputControlProtocol::ACC);
2751 case COutputControlProtocol::PRECLEANUP:
2754 msg->Reply(COutputControlProtocol::ACC);
2760 else if (port == &m_dataPort)
2764 case COutputDataProtocol::NEWFRAME:
2765 CVdpauDecodedPicture *frame;
2766 frame = (CVdpauDecodedPicture*)msg->data;
2769 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::FRAME,
2770 frame,sizeof(CVdpauDecodedPicture));
2773 case COutputDataProtocol::RETURNPIC:
2774 CVdpauRenderPicture *pic;
2775 pic = *((CVdpauRenderPicture**)msg->data);
2776 QueueReturnPicture(pic);
2777 m_controlPort.SendInMessage(COutputControlProtocol::STATS);
2778 m_state = O_TOP_CONFIGURED_WORK;
2785 else if (port == &m_mixer.m_dataPort)
2789 case CMixerDataProtocol::PICTURE:
2790 CVdpauProcessedPicture *pic;
2791 pic = (CVdpauProcessedPicture*)msg->data;
2792 m_bufferPool.processedPics.push(*pic);
2793 m_state = O_TOP_CONFIGURED_WORK;
2802 case O_TOP_CONFIGURED_IDLE:
2803 if (port == NULL) // timeout
2807 case COutputControlProtocol::TIMEOUT:
2808 if (ProcessSyncPicture())
2814 m_state = O_TOP_CONFIGURED_WORK;
2824 case O_TOP_CONFIGURED_WORK:
2825 if (port == NULL) // timeout
2829 case COutputControlProtocol::TIMEOUT:
2832 CVdpauRenderPicture *pic;
2833 pic = ProcessMixerPicture();
2836 m_config.stats->DecProcessed();
2837 m_config.stats->IncRender();
2838 m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic));
2844 m_state = O_TOP_CONFIGURED_IDLE;
2854 default: // we are in no state, should not happen
2855 CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state);
2861 void COutput::Process()
2863 Message *msg = NULL;
2864 Protocol *port = NULL;
2867 m_state = O_TOP_UNCONFIGURED;
2868 m_extTimeout = 1000;
2869 m_bStateMachineSelfTrigger = false;
2875 if (m_bStateMachineSelfTrigger)
2877 m_bStateMachineSelfTrigger = false;
2878 // self trigger state machine
2879 StateMachine(msg->signal, port, msg);
2880 if (!m_bStateMachineSelfTrigger)
2887 // check control port
2888 else if (m_controlPort.ReceiveOutMessage(&msg))
2891 port = &m_controlPort;
2894 else if (m_dataPort.ReceiveOutMessage(&msg))
2899 // check mixer data port
2900 else if (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2903 port = &m_mixer.m_dataPort;
2907 StateMachine(msg->signal, port, msg);
2908 if (!m_bStateMachineSelfTrigger)
2917 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
2924 msg = m_controlPort.GetMessage();
2925 msg->signal = COutputControlProtocol::TIMEOUT;
2927 // signal timeout to state machine
2928 StateMachine(msg->signal, port, msg);
2929 if (!m_bStateMachineSelfTrigger)
2940 bool COutput::Init()
2942 if (!CreateGlxContext())
2954 bool COutput::Uninit()
2958 ReleaseBufferPool();
2959 DestroyGlxContext();
2963 void COutput::Flush()
2965 if (m_mixer.IsActive())
2968 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH,
2975 CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__);
2979 while (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2981 if (msg->signal == CMixerDataProtocol::PICTURE)
2983 CVdpauProcessedPicture pic = *(CVdpauProcessedPicture*)msg->data;
2984 m_bufferPool.processedPics.push(pic);
2989 while (m_dataPort.ReceiveOutMessage(&msg))
2991 if (msg->signal == COutputDataProtocol::NEWFRAME)
2993 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2994 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2996 else if (msg->signal == COutputDataProtocol::RETURNPIC)
2998 CVdpauRenderPicture *pic;
2999 pic = *((CVdpauRenderPicture**)msg->data);
3000 QueueReturnPicture(pic);
3005 while (m_dataPort.ReceiveInMessage(&msg))
3007 if (msg->signal == COutputDataProtocol::PICTURE)
3009 CVdpauRenderPicture *pic;
3010 pic = *((CVdpauRenderPicture**)msg->data);
3011 QueueReturnPicture(pic);
3015 // reset used render flag which was cleared on mixer flush
3016 std::deque<int>::iterator it;
3017 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3019 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[*it];
3020 if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3022 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it2;
3023 it2 = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3024 if (it2 == m_bufferPool.glVideoSurfaceMap.end())
3026 CLog::Log(LOGDEBUG, "COutput::Flush - gl surface not found");
3029 m_config.videoSurfaces->MarkRender(it2->second.sourceVuv);
3033 // clear processed pics
3034 while(!m_bufferPool.processedPics.empty())
3036 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
3037 if (procPic.DVDPic.format == RENDER_FMT_VDPAU)
3039 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &procPic.outputSurface, sizeof(procPic.outputSurface));
3041 else if (procPic.DVDPic.format == RENDER_FMT_VDPAU_420)
3043 m_config.videoSurfaces->ClearRender(procPic.videoSurface);
3045 m_bufferPool.processedPics.pop();
3049 bool COutput::HasWork()
3051 if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
3056 CVdpauRenderPicture* COutput::ProcessMixerPicture()
3058 CVdpauRenderPicture *retPic = NULL;
3060 if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
3062 int idx = m_bufferPool.freeRenderPics.front();
3063 retPic = m_bufferPool.allRenderPics[idx];
3064 m_bufferPool.freeRenderPics.pop_front();
3065 m_bufferPool.usedRenderPics.push_back(idx);
3066 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
3067 m_bufferPool.processedPics.pop();
3069 retPic->DVDPic = procPic.DVDPic;
3070 retPic->valid = true;
3071 if (retPic->DVDPic.format == RENDER_FMT_VDPAU)
3073 m_config.useInteropYuv = false;
3074 m_bufferPool.numOutputSurfaces = NUM_RENDER_PICS;
3076 GLMapSurface(false, procPic.outputSurface);
3077 retPic->sourceIdx = procPic.outputSurface;
3078 retPic->texture[0] = m_bufferPool.glOutputSurfaceMap[procPic.outputSurface].texture[0];
3079 retPic->texWidth = m_config.outWidth;
3080 retPic->texHeight = m_config.outHeight;
3081 retPic->crop.x1 = 0;
3082 retPic->crop.y1 = (m_config.outHeight - retPic->DVDPic.iHeight) / 2;
3083 retPic->crop.x2 = m_config.outWidth;
3084 retPic->crop.y2 = m_config.outHeight - retPic->crop.y1;
3088 m_config.useInteropYuv = true;
3089 GLMapSurface(true, procPic.videoSurface);
3090 retPic->sourceIdx = procPic.videoSurface;
3091 for (unsigned int i=0; i<4; ++i)
3092 retPic->texture[i] = m_bufferPool.glVideoSurfaceMap[procPic.videoSurface].texture[i];
3093 retPic->texWidth = m_config.surfaceWidth;
3094 retPic->texHeight = m_config.surfaceHeight;
3095 retPic->crop.x1 = 0;
3096 retPic->crop.y1 = 0;
3097 retPic->crop.x2 = m_config.surfaceWidth - m_config.vidWidth;
3098 retPic->crop.y2 = m_config.surfaceHeight - m_config.vidHeight;
3104 void COutput::QueueReturnPicture(CVdpauRenderPicture *pic)
3106 std::deque<int>::iterator it;
3107 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3109 if (m_bufferPool.allRenderPics[*it] == pic)
3115 if (it == m_bufferPool.usedRenderPics.end())
3117 CLog::Log(LOGWARNING, "COutput::QueueReturnPicture - pic not found");
3121 // check if already queued
3122 std::deque<int>::iterator it2 = find(m_bufferPool.syncRenderPics.begin(),
3123 m_bufferPool.syncRenderPics.end(),
3125 if (it2 == m_bufferPool.syncRenderPics.end())
3127 m_bufferPool.syncRenderPics.push_back(*it);
3130 ProcessSyncPicture();
3133 bool COutput::ProcessSyncPicture()
3135 CVdpauRenderPicture *pic;
3138 std::deque<int>::iterator it;
3139 for (it = m_bufferPool.syncRenderPics.begin(); it != m_bufferPool.syncRenderPics.end(); )
3141 pic = m_bufferPool.allRenderPics[*it];
3146 if (glIsSync(pic->fence))
3150 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3151 if(state == GL_SIGNALED)
3153 glDeleteSync(pic->fence);
3166 m_bufferPool.freeRenderPics.push_back(*it);
3168 std::deque<int>::iterator it2 = find(m_bufferPool.usedRenderPics.begin(),
3169 m_bufferPool.usedRenderPics.end(),
3171 if (it2 == m_bufferPool.usedRenderPics.end())
3173 CLog::Log(LOGERROR, "COutput::ProcessSyncPicture - pic not found in queue");
3177 m_bufferPool.usedRenderPics.erase(it2);
3179 it = m_bufferPool.syncRenderPics.erase(it);
3183 ProcessReturnPicture(pic);
3187 CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__);
3193 void COutput::ProcessReturnPicture(CVdpauRenderPicture *pic)
3195 if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3197 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3198 it = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3199 if (it == m_bufferPool.glVideoSurfaceMap.end())
3201 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3204 #ifdef GL_NV_vdpau_interop
3205 glVDPAUUnmapSurfacesNV(1, &(it->second.glVdpauSurface));
3207 VdpVideoSurface surf = it->second.sourceVuv;
3208 m_config.videoSurfaces->ClearRender(surf);
3210 else if (pic->DVDPic.format == RENDER_FMT_VDPAU)
3212 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3213 it = m_bufferPool.glOutputSurfaceMap.find(pic->sourceIdx);
3214 if (it == m_bufferPool.glOutputSurfaceMap.end())
3216 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3219 #ifdef GL_NV_vdpau_interop
3220 glVDPAUUnmapSurfacesNV(1, &(it->second.glVdpauSurface));
3222 VdpOutputSurface outSurf = it->second.sourceRgb;
3223 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &outSurf, sizeof(outSurf));
3227 bool COutput::EnsureBufferPool()
3231 // Creation of outputSurfaces
3232 VdpOutputSurface outputSurface;
3233 for (int i = m_bufferPool.outputSurfaces.size(); i < m_bufferPool.numOutputSurfaces; i++)
3235 vdp_st = m_config.context->GetProcs().vdp_output_surface_create(m_config.context->GetDevice(),
3236 VDP_RGBA_FORMAT_B8G8R8A8,
3240 if (CheckStatus(vdp_st, __LINE__))
3242 m_bufferPool.outputSurfaces.push_back(outputSurface);
3244 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3246 sizeof(VdpOutputSurface));
3247 CLog::Log(LOGNOTICE, "VDPAU::COutput::InitBufferPool - Output Surface created");
3252 void COutput::ReleaseBufferPool()
3256 CSingleLock lock(m_bufferPool.renderPicSec);
3258 // release all output surfaces
3259 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3261 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3263 vdp_st = m_config.context->GetProcs().vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3264 CheckStatus(vdp_st, __LINE__);
3266 m_bufferPool.outputSurfaces.clear();
3268 // wait for all fences
3269 XbmcThreads::EndTime timeout(1000);
3270 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3272 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[i];
3276 while (glIsSync(pic->fence))
3280 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3281 if(state == GL_SIGNALED || timeout.IsTimePast())
3283 glDeleteSync(pic->fence);
3294 if (timeout.IsTimePast())
3296 CLog::Log(LOGERROR, "COutput::%s - timeout waiting for fence", __FUNCTION__);
3298 ProcessSyncPicture();
3300 // invalidate all used render pictures
3301 for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i)
3303 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[m_bufferPool.usedRenderPics[i]];
3308 void COutput::PreCleanup()
3314 ProcessSyncPicture();
3316 CSingleLock lock(m_bufferPool.renderPicSec);
3317 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3319 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3322 // check if output surface is in use
3324 std::deque<int>::iterator it;
3325 CVdpauRenderPicture *pic;
3326 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3328 pic = m_bufferPool.allRenderPics[*it];
3329 if ((pic->sourceIdx == m_bufferPool.outputSurfaces[i]) && pic->valid)
3338 #ifdef GL_NV_vdpau_interop
3340 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it_map;
3341 it_map = m_bufferPool.glOutputSurfaceMap.find(m_bufferPool.outputSurfaces[i]);
3342 if (it_map == m_bufferPool.glOutputSurfaceMap.end())
3344 CLog::Log(LOGERROR, "%s - could not find gl surface", __FUNCTION__);
3347 glVDPAUUnregisterSurfaceNV(it_map->second.glVdpauSurface);
3348 glDeleteTextures(1, it_map->second.texture);
3349 m_bufferPool.glOutputSurfaceMap.erase(it_map);
3352 vdp_st = m_config.context->GetProcs().vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3353 CheckStatus(vdp_st, __LINE__);
3355 m_bufferPool.outputSurfaces[i] = VDP_INVALID_HANDLE;
3357 CLog::Log(LOGDEBUG, "VDPAU::PreCleanup - released output surface");
3362 void COutput::InitMixer()
3364 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3366 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3367 &m_bufferPool.outputSurfaces[i],
3368 sizeof(VdpOutputSurface));
3372 bool COutput::GLInit()
3374 #ifdef GL_NV_vdpau_interop
3375 glVDPAUInitNV = NULL;
3376 glVDPAUFiniNV = NULL;
3377 glVDPAURegisterOutputSurfaceNV = NULL;
3378 glVDPAURegisterVideoSurfaceNV = NULL;
3379 glVDPAUIsSurfaceNV = NULL;
3380 glVDPAUUnregisterSurfaceNV = NULL;
3381 glVDPAUSurfaceAccessNV = NULL;
3382 glVDPAUMapSurfacesNV = NULL;
3383 glVDPAUUnmapSurfacesNV = NULL;
3384 glVDPAUGetSurfaceivNV = NULL;
3387 #ifdef GL_NV_vdpau_interop
3389 glVDPAUInitNV = (PFNGLVDPAUINITNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUInitNV");
3391 glVDPAUFiniNV = (PFNGLVDPAUFININVPROC)glXGetProcAddress((GLubyte *) "glVDPAUFiniNV");
3392 if (!glVDPAURegisterOutputSurfaceNV)
3393 glVDPAURegisterOutputSurfaceNV = (PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterOutputSurfaceNV");
3394 if (!glVDPAURegisterVideoSurfaceNV)
3395 glVDPAURegisterVideoSurfaceNV = (PFNGLVDPAUREGISTERVIDEOSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterVideoSurfaceNV");
3396 if (!glVDPAUIsSurfaceNV)
3397 glVDPAUIsSurfaceNV = (PFNGLVDPAUISSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUIsSurfaceNV");
3398 if (!glVDPAUUnregisterSurfaceNV)
3399 glVDPAUUnregisterSurfaceNV = (PFNGLVDPAUUNREGISTERSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnregisterSurfaceNV");
3400 if (!glVDPAUSurfaceAccessNV)
3401 glVDPAUSurfaceAccessNV = (PFNGLVDPAUSURFACEACCESSNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUSurfaceAccessNV");
3402 if (!glVDPAUMapSurfacesNV)
3403 glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUMapSurfacesNV");
3404 if (!glVDPAUUnmapSurfacesNV)
3405 glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnmapSurfacesNV");
3406 if (!glVDPAUGetSurfaceivNV)
3407 glVDPAUGetSurfaceivNV = (PFNGLVDPAUGETSURFACEIVNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUGetSurfaceivNV");
3409 while (glGetError() != GL_NO_ERROR);
3410 glVDPAUInitNV(reinterpret_cast<void*>(m_config.context->GetDevice()), reinterpret_cast<void*>(m_config.context->GetProcs().vdp_get_proc_address));
3411 if (glGetError() != GL_NO_ERROR)
3413 CLog::Log(LOGERROR, "VDPAU::COutput - GLInitInterop glVDPAUInitNV failed");
3417 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop initialized");
3421 bool hasfence = glewIsSupported("GL_ARB_sync");
3422 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3424 m_bufferPool.allRenderPics[i]->usefence = hasfence;
3431 void COutput::GLMapSurface(bool yuv, uint32_t source)
3433 #ifdef GL_NV_vdpau_interop
3437 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3438 it = m_bufferPool.glVideoSurfaceMap.find(source);
3439 if (it == m_bufferPool.glVideoSurfaceMap.end())
3441 VdpauBufferPool::GLVideoSurface glSurface;
3442 VdpVideoSurface surf = source;
3444 if (surf == VDP_INVALID_HANDLE)
3447 glSurface.sourceVuv = surf;
3448 while (glGetError() != GL_NO_ERROR) ;
3449 glGenTextures(4, glSurface.texture);
3450 if (glGetError() != GL_NO_ERROR)
3452 CLog::Log(LOGERROR, "VDPAU::COutput error creating texture");
3455 glSurface.glVdpauSurface = glVDPAURegisterVideoSurfaceNV(reinterpret_cast<void*>(surf),
3456 GL_TEXTURE_2D, 4, glSurface.texture);
3458 if (glGetError() != GL_NO_ERROR)
3460 CLog::Log(LOGERROR, "VDPAU::COutput error register video surface");
3463 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3464 if (glGetError() != GL_NO_ERROR)
3466 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3469 m_bufferPool.glVideoSurfaceMap[surf] = glSurface;
3471 CLog::Log(LOGNOTICE, "VDPAU::COutput registered surface");
3474 while (glGetError() != GL_NO_ERROR) ;
3475 glVDPAUMapSurfacesNV(1, &m_bufferPool.glVideoSurfaceMap[source].glVdpauSurface);
3476 if (glGetError() != GL_NO_ERROR)
3478 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3487 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3488 it = m_bufferPool.glOutputSurfaceMap.find(source);
3489 if (it == m_bufferPool.glOutputSurfaceMap.end())
3491 unsigned int idx = 0;
3492 for (idx = 0; idx<m_bufferPool.outputSurfaces.size(); idx++)
3494 if (m_bufferPool.outputSurfaces[idx] == source)
3498 VdpauBufferPool::GLVideoSurface glSurface;
3499 glSurface.sourceRgb = m_bufferPool.outputSurfaces[idx];
3500 glGenTextures(1, glSurface.texture);
3501 glSurface.glVdpauSurface = glVDPAURegisterOutputSurfaceNV(reinterpret_cast<void*>(m_bufferPool.outputSurfaces[idx]),
3502 GL_TEXTURE_2D, 1, glSurface.texture);
3503 if (glGetError() != GL_NO_ERROR)
3505 CLog::Log(LOGERROR, "VDPAU::COutput error register output surface");
3508 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3509 if (glGetError() != GL_NO_ERROR)
3511 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3514 m_bufferPool.glOutputSurfaceMap[source] = glSurface;
3515 CLog::Log(LOGNOTICE, "VDPAU::COutput registered output surfaces");
3518 while (glGetError() != GL_NO_ERROR) ;
3519 glVDPAUMapSurfacesNV(1, &m_bufferPool.glOutputSurfaceMap[source].glVdpauSurface);
3520 if (glGetError() != GL_NO_ERROR)
3522 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3532 void COutput::GLUnmapSurfaces()
3534 #ifdef GL_NV_vdpau_interop
3537 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3538 for (it = m_bufferPool.glVideoSurfaceMap.begin(); it != m_bufferPool.glVideoSurfaceMap.end(); ++it)
3540 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3541 glDeleteTextures(4, it->second.texture);
3543 m_bufferPool.glVideoSurfaceMap.clear();
3546 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3547 for (it = m_bufferPool.glOutputSurfaceMap.begin(); it != m_bufferPool.glOutputSurfaceMap.end(); ++it)
3549 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3550 glDeleteTextures(1, it->second.texture);
3552 m_bufferPool.glOutputSurfaceMap.clear();
3556 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop finished");
3561 bool COutput::CheckStatus(VdpStatus vdp_st, int line)
3563 if (vdp_st != VDP_STATUS_OK)
3565 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);
3572 bool COutput::CreateGlxContext()
3574 GLXContext glContext;
3576 m_Display = g_Windowing.GetDisplay();
3577 glContext = g_Windowing.GetGlxContext();
3578 m_Window = g_Windowing.GetWindow();
3580 // Get our window attribs.
3581 XWindowAttributes wndattribs;
3582 XGetWindowAttributes(m_Display, m_Window, &wndattribs);
3585 XVisualInfo visInfo;
3586 visInfo.visualid = wndattribs.visual->visualid;
3588 XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals);
3591 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - could not find visual");
3594 visInfo = visuals[0];
3597 m_pixmap = XCreatePixmap(m_Display,
3604 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - Unable to create XPixmap");
3609 m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap);
3613 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not create glPixmap");
3617 m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True);
3619 if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext))
3621 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not make Pixmap current");
3625 CLog::Log(LOGNOTICE, "VDPAU::COutput::CreateGlxContext - created context");
3629 bool COutput::DestroyGlxContext()
3633 glXMakeCurrent(m_Display, None, NULL);
3634 glXDestroyContext(m_Display, m_glContext);
3639 glXDestroyPixmap(m_Display, m_glPixmap);
3643 XFreePixmap(m_Display, m_pixmap);