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"
39 #include "utils/log.h"
41 using namespace Actor;
42 using namespace VDPAU;
43 #define NUM_RENDER_PICS 7
44 #define NUM_CROP_PIX 3
46 #define ARSIZE(x) (sizeof(x) / sizeof((x)[0]))
48 CDecoder::Desc decoder_profiles[] = {
49 {"MPEG1", VDP_DECODER_PROFILE_MPEG1},
50 {"MPEG2_SIMPLE", VDP_DECODER_PROFILE_MPEG2_SIMPLE},
51 {"MPEG2_MAIN", VDP_DECODER_PROFILE_MPEG2_MAIN},
52 {"H264_BASELINE",VDP_DECODER_PROFILE_H264_BASELINE},
53 {"H264_MAIN", VDP_DECODER_PROFILE_H264_MAIN},
54 {"H264_HIGH", VDP_DECODER_PROFILE_H264_HIGH},
55 {"VC1_SIMPLE", VDP_DECODER_PROFILE_VC1_SIMPLE},
56 {"VC1_MAIN", VDP_DECODER_PROFILE_VC1_MAIN},
57 {"VC1_ADVANCED", VDP_DECODER_PROFILE_VC1_ADVANCED},
58 {"MPEG4_PART2_ASP", VDP_DECODER_PROFILE_MPEG4_PART2_ASP},
59 #ifdef VDP_DECODER_PROFILE_HEVC_MAIN
60 {"HEVC_MAIN", VDP_DECODER_PROFILE_HEVC_MAIN},
63 const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CDecoder::Desc);
65 static struct SInterlaceMapping
67 const EINTERLACEMETHOD method;
68 const VdpVideoMixerFeature feature;
69 } g_interlace_mapping[] =
70 { {VS_INTERLACEMETHOD_VDPAU_TEMPORAL , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
71 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
72 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
73 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
74 , {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE}
75 , {VS_INTERLACEMETHOD_NONE , (VdpVideoMixerFeature)-1}
78 static float studioCSCKCoeffs601[3] = {0.299, 0.587, 0.114}; //BT601 {Kr, Kg, Kb}
79 static float studioCSCKCoeffs709[3] = {0.2126, 0.7152, 0.0722}; //BT709 {Kr, Kg, Kb}
81 //-----------------------------------------------------------------------------
82 //-----------------------------------------------------------------------------
84 CVDPAUContext *CVDPAUContext::m_context = 0;
85 CCriticalSection CVDPAUContext::m_section;
86 Display *CVDPAUContext::m_display = 0;
87 void *CVDPAUContext::m_dlHandle = 0;
89 CVDPAUContext::CVDPAUContext()
95 void CVDPAUContext::Release()
97 CSingleLock lock(m_section);
108 void CVDPAUContext::Close()
110 CLog::Log(LOGNOTICE, "VDPAU::Close - closing decoder context");
114 bool CVDPAUContext::EnsureContext(CVDPAUContext **ctx)
116 CSingleLock lock(m_section);
120 m_context->m_refCount++;
125 m_context = new CVDPAUContext();
128 CSingleLock gLock(g_graphicsContext);
129 if (!m_context->LoadSymbols() || !m_context->CreateContext())
138 m_context->m_refCount++;
144 VDPAU_procs& CVDPAUContext::GetProcs()
149 VdpVideoMixerFeature* CVDPAUContext::GetFeatures()
151 return m_vdpFeatures;
154 int CVDPAUContext::GetFeatureCount()
156 return m_featureCount;
159 bool CVDPAUContext::LoadSymbols()
163 m_dlHandle = dlopen("libvdpau.so.1", RTLD_LAZY);
166 const char* error = dlerror();
168 error = "dlerror() returned NULL";
170 CLog::Log(LOGERROR,"VDPAU::LoadSymbols: Unable to get handle to lib: %s", error);
177 dl_vdp_device_create_x11 = (VdpStatus (*)(Display*, int, VdpDevice*, VdpStatus (**)(VdpDevice, VdpFuncId, void**)))dlsym(m_dlHandle, (const char*)"vdp_device_create_x11");
181 CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__);
182 m_vdpDevice = VDP_INVALID_HANDLE;
188 bool CVDPAUContext::CreateContext()
190 CLog::Log(LOGNOTICE,"VDPAU::CreateContext - creating decoder context");
193 { CSingleLock lock(g_graphicsContext);
195 m_display = XOpenDisplay(NULL);
196 mScreen = g_Windowing.GetCurrentScreen();
201 vdp_st = dl_vdp_device_create_x11(m_display,
204 &m_vdpProcs.vdp_get_proc_address);
206 CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",m_vdpDevice,vdp_st);
207 if (vdp_st != VDP_STATUS_OK)
209 CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x. Falling back.",vdp_st);
210 m_vdpDevice = VDP_INVALID_HANDLE;
215 SpewHardwareAvailable();
219 void CVDPAUContext::QueryProcs()
223 #define VDP_PROC(id, proc) \
225 vdp_st = m_vdpProcs.vdp_get_proc_address(m_vdpDevice, id, (void**)&proc); \
226 if (vdp_st != VDP_STATUS_OK) \
228 CLog::Log(LOGERROR, "CVDPAUContext::GetProcs - failed to get proc id"); \
232 VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING , m_vdpProcs.vdp_get_error_string);
233 VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY , m_vdpProcs.vdp_device_destroy);
234 VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX , m_vdpProcs.vdp_generate_csc_matrix);
235 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE , m_vdpProcs.vdp_video_surface_create);
236 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , m_vdpProcs.vdp_video_surface_destroy);
237 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , m_vdpProcs.vdp_video_surface_put_bits_y_cb_cr);
238 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , m_vdpProcs.vdp_video_surface_get_bits_y_cb_cr);
239 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , m_vdpProcs.vdp_output_surface_put_bits_y_cb_cr);
240 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , m_vdpProcs.vdp_output_surface_put_bits_native);
241 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , m_vdpProcs.vdp_output_surface_create);
242 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , m_vdpProcs.vdp_output_surface_destroy);
243 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , m_vdpProcs.vdp_output_surface_get_bits_native);
244 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, m_vdpProcs.vdp_output_surface_render_output_surface);
245 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , m_vdpProcs.vdp_output_surface_put_bits_indexed);
246 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE , m_vdpProcs.vdp_video_mixer_create);
247 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , m_vdpProcs.vdp_video_mixer_set_feature_enables);
248 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY , m_vdpProcs.vdp_video_mixer_destroy);
249 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER , m_vdpProcs.vdp_video_mixer_render);
250 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , m_vdpProcs.vdp_video_mixer_set_attribute_values);
251 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , m_vdpProcs.vdp_video_mixer_query_parameter_support);
252 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , m_vdpProcs.vdp_video_mixer_query_feature_support);
253 VDP_PROC(VDP_FUNC_ID_DECODER_CREATE , m_vdpProcs.vdp_decoder_create);
254 VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY , m_vdpProcs.vdp_decoder_destroy);
255 VDP_PROC(VDP_FUNC_ID_DECODER_RENDER , m_vdpProcs.vdp_decoder_render);
256 VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , m_vdpProcs.vdp_decoder_query_caps);
260 VdpDevice CVDPAUContext::GetDevice()
265 void CVDPAUContext::DestroyContext()
267 if (!m_vdpProcs.vdp_device_destroy)
270 m_vdpProcs.vdp_device_destroy(m_vdpDevice);
271 m_vdpDevice = VDP_INVALID_HANDLE;
274 void CVDPAUContext::SpewHardwareAvailable() //CopyrighVDPAUt (c) 2008 Wladimir J. van der Laan -- VDPInfo
277 CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:");
278 CLog::Log(LOGNOTICE,"name level macbs width height");
279 CLog::Log(LOGNOTICE,"------------------------------------");
280 for(unsigned int x=0; x<decoder_profile_count; ++x)
282 VdpBool is_supported = false;
283 uint32_t max_level, max_macroblocks, max_width, max_height;
284 rv = m_vdpProcs.vdp_decoder_query_caps(m_vdpDevice, decoder_profiles[x].id,
285 &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
286 if(rv == VDP_STATUS_OK && is_supported)
288 CLog::Log(LOGNOTICE,"%-16s %2i %5i %5i %5i\n", decoder_profiles[x].name,
289 max_level, max_macroblocks, max_width, max_height);
292 CLog::Log(LOGNOTICE,"------------------------------------");
294 #define CHECK_SUPPORT(feature) \
297 if(m_vdpProcs.vdp_video_mixer_query_feature_support(m_vdpDevice, feature, &supported) == VDP_STATUS_OK && supported) { \
298 CLog::Log(LOGNOTICE, "Mixer feature: "#feature); \
299 m_vdpFeatures[m_featureCount++] = feature; \
303 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION);
304 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_SHARPNESS);
305 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL);
306 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL);
307 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE);
308 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
309 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1);
310 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2);
311 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3);
312 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4);
313 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5);
314 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6);
315 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7);
316 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8);
317 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9);
322 bool CVDPAUContext::Supports(VdpVideoMixerFeature feature)
324 for(int i = 0; i < m_featureCount; i++)
326 if(m_vdpFeatures[i] == feature)
332 //-----------------------------------------------------------------------------
333 // VDPAU Video Surface states
334 //-----------------------------------------------------------------------------
336 #define SURFACE_USED_FOR_REFERENCE 0x01
337 #define SURFACE_USED_FOR_RENDER 0x02
339 void CVideoSurfaces::AddSurface(VdpVideoSurface surf)
341 CSingleLock lock(m_section);
342 m_state[surf] = SURFACE_USED_FOR_REFERENCE;
345 void CVideoSurfaces::ClearReference(VdpVideoSurface surf)
347 CSingleLock lock(m_section);
348 if (m_state.find(surf) == m_state.end())
350 CLog::Log(LOGWARNING, "CVideoSurfaces::ClearReference - surface invalid");
353 m_state[surf] &= ~SURFACE_USED_FOR_REFERENCE;
354 if (m_state[surf] == 0)
356 m_freeSurfaces.push_back(surf);
360 bool CVideoSurfaces::MarkRender(VdpVideoSurface surf)
362 CSingleLock lock(m_section);
363 if (m_state.find(surf) == m_state.end())
365 CLog::Log(LOGWARNING, "CVideoSurfaces::MarkRender - surface invalid");
368 std::list<VdpVideoSurface>::iterator it;
369 it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
370 if (it != m_freeSurfaces.end())
372 m_freeSurfaces.erase(it);
374 m_state[surf] |= SURFACE_USED_FOR_RENDER;
378 void CVideoSurfaces::ClearRender(VdpVideoSurface surf)
380 CSingleLock lock(m_section);
381 if (m_state.find(surf) == m_state.end())
383 CLog::Log(LOGWARNING, "CVideoSurfaces::ClearRender - surface invalid");
386 m_state[surf] &= ~SURFACE_USED_FOR_RENDER;
387 if (m_state[surf] == 0)
389 m_freeSurfaces.push_back(surf);
393 bool CVideoSurfaces::IsValid(VdpVideoSurface surf)
395 CSingleLock lock(m_section);
396 if (m_state.find(surf) != m_state.end())
402 VdpVideoSurface CVideoSurfaces::GetFree(VdpVideoSurface surf)
404 CSingleLock lock(m_section);
405 if (m_state.find(surf) != m_state.end())
407 std::list<VdpVideoSurface>::iterator it;
408 it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
409 if (it == m_freeSurfaces.end())
411 CLog::Log(LOGWARNING, "CVideoSurfaces::GetFree - surface not free");
415 m_freeSurfaces.erase(it);
416 m_state[surf] = SURFACE_USED_FOR_REFERENCE;
421 if (!m_freeSurfaces.empty())
423 VdpVideoSurface freeSurf = m_freeSurfaces.front();
424 m_freeSurfaces.pop_front();
425 m_state[freeSurf] = SURFACE_USED_FOR_REFERENCE;
429 return VDP_INVALID_HANDLE;
432 VdpVideoSurface CVideoSurfaces::RemoveNext(bool skiprender)
434 CSingleLock lock(m_section);
435 VdpVideoSurface surf;
436 std::map<VdpVideoSurface, int>::iterator it;
437 for(it = m_state.begin(); it != m_state.end(); ++it)
439 if (skiprender && it->second & SURFACE_USED_FOR_RENDER)
444 std::list<VdpVideoSurface>::iterator it2;
445 it2 = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
446 if (it2 != m_freeSurfaces.end())
447 m_freeSurfaces.erase(it2);
450 return VDP_INVALID_HANDLE;
453 void CVideoSurfaces::Reset()
455 CSingleLock lock(m_section);
456 m_freeSurfaces.clear();
460 int CVideoSurfaces::Size()
462 CSingleLock lock(m_section);
463 return m_state.size();
466 //-----------------------------------------------------------------------------
468 //-----------------------------------------------------------------------------
470 CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent)
472 m_vdpauConfig.videoSurfaces = &m_videoSurfaces;
474 m_vdpauConfigured = false;
475 m_DisplayState = VDPAU_OPEN;
476 m_vdpauConfig.context = 0;
479 bool CDecoder::Open(AVCodecContext* avctx, AVCodecContext* mainctx, const enum PixelFormat fmt, unsigned int surfaces)
481 // check if user wants to decode this format with VDPAU
482 std::string gpuvendor = g_Windowing.GetRenderVendor();
483 std::transform(gpuvendor.begin(), gpuvendor.end(), gpuvendor.begin(), ::tolower);
484 // nvidia is whitelisted despite for mpeg-4 we need to query user settings
485 if ((gpuvendor.compare(0, 6, "nvidia") != 0) || (avctx->codec_id == AV_CODEC_ID_MPEG4) || (avctx->codec_id == AV_CODEC_ID_H263))
487 std::map<AVCodecID, std::string> settings_map = {
488 { AV_CODEC_ID_H263, CSettings::SETTING_VIDEOPLAYER_USEVDPAUMPEG4 },
489 { AV_CODEC_ID_MPEG4, CSettings::SETTING_VIDEOPLAYER_USEVDPAUMPEG4 },
490 { AV_CODEC_ID_WMV3, CSettings::SETTING_VIDEOPLAYER_USEVDPAUVC1 },
491 { AV_CODEC_ID_VC1, CSettings::SETTING_VIDEOPLAYER_USEVDPAUVC1 },
492 { AV_CODEC_ID_MPEG2VIDEO, CSettings::SETTING_VIDEOPLAYER_USEVDPAUMPEG2 },
494 if (CDVDVideoCodec::IsCodecDisabled(settings_map, avctx->codec_id))
498 #ifndef GL_NV_vdpau_interop
499 CLog::Log(LOGNOTICE, "VDPAU: compilation without required extension GL_NV_vdpau_interop");
502 if (!g_Windowing.IsExtSupported("GL_NV_vdpau_interop"))
504 CLog::Log(LOGNOTICE, "VDPAU::Open: required extension GL_NV_vdpau_interop not found");
508 if(avctx->coded_width == 0
509 || avctx->coded_height == 0)
511 CLog::Log(LOGWARNING,"VDPAU::Open: no width/height available, can't init");
514 m_vdpauConfig.numRenderBuffers = surfaces;
515 m_decoderThread = CThread::GetCurrentThreadId();
517 if (!CVDPAUContext::EnsureContext(&m_vdpauConfig.context))
520 m_DisplayState = VDPAU_OPEN;
521 m_vdpauConfigured = false;
523 m_presentPicture = 0;
526 VdpDecoderProfile profile = 0;
528 // convert FFMPEG codec ID to VDPAU profile.
529 ReadFormatOf(avctx->codec_id, profile, m_vdpauConfig.vdpChromaType);
533 VdpBool is_supported = false;
534 uint32_t max_level, max_macroblocks, max_width, max_height;
536 // query device capabilities to ensure that VDPAU can handle the requested codec
537 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_query_caps(m_vdpauConfig.context->GetDevice(),
538 profile, &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
540 // test to make sure there is a possibility the codec will work
541 if (CheckStatus(vdp_st, __LINE__))
543 CLog::Log(LOGERROR, "VDPAU::Open: error %s(%d) checking for decoder support", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st);
547 if (max_width < (uint32_t) avctx->coded_width || max_height < (uint32_t) avctx->coded_height)
549 CLog::Log(LOGWARNING,"VDPAU::Open: requested picture dimensions (%i, %i) exceed hardware capabilities ( %i, %i).",
550 avctx->coded_width, avctx->coded_height, max_width, max_height);
554 if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width))
555 CLog::Log(LOGWARNING,"VDPAU::Open width %i might not be supported because of hardware bug", avctx->width);
557 // attempt to create a decoder with this width/height, some sizes are not supported by hw
558 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_create(m_vdpauConfig.context->GetDevice(), profile, avctx->coded_width, avctx->coded_height, 5, &m_vdpauConfig.vdpDecoder);
560 if (CheckStatus(vdp_st, __LINE__))
562 CLog::Log(LOGERROR, "VDPAU::Open: error: %s(%d) checking for decoder support", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st);
566 m_vdpauConfig.context->GetProcs().vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
567 CheckStatus(vdp_st, __LINE__);
569 // finally setup ffmpeg
570 memset(&m_hwContext, 0, sizeof(AVVDPAUContext));
571 m_hwContext.render2 = CDecoder::Render;
572 avctx->get_buffer2 = CDecoder::FFGetBuffer;
573 avctx->slice_flags = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
574 avctx->hwaccel_context = &m_hwContext;
576 mainctx->get_buffer2 = CDecoder::FFGetBuffer;
577 mainctx->slice_flags = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
578 mainctx->hwaccel_context = &m_hwContext;
580 g_Windowing.Register(this);
587 CDecoder::~CDecoder()
592 void CDecoder::Close()
594 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
596 g_Windowing.Unregister(this);
598 CSingleLock lock(m_DecoderSection);
601 m_vdpauOutput.Dispose();
603 if (m_vdpauConfig.context)
604 m_vdpauConfig.context->Release();
605 m_vdpauConfig.context = 0;
608 long CDecoder::Release()
610 // check if we should do some pre-cleanup here
611 // a second decoder might need resources
612 if (m_vdpauConfigured == true)
614 CSingleLock lock(m_DecoderSection);
615 CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup");
618 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP,
622 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
626 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup returned error", __FUNCTION__);
627 m_DisplayState = VDPAU_ERROR;
632 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup timed out", __FUNCTION__);
633 m_DisplayState = VDPAU_ERROR;
636 VdpVideoSurface surf;
637 while((surf = m_videoSurfaces.RemoveNext(true)) != VDP_INVALID_HANDLE)
639 m_vdpauConfig.context->GetProcs().vdp_video_surface_destroy(surf);
642 return IHardwareDecoder::Release();
645 long CDecoder::ReleasePicReference()
647 return IHardwareDecoder::Release();
650 void CDecoder::SetWidthHeight(int width, int height)
652 m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling;
654 //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate
655 //this requires the least amount of gpu memory bandwidth
656 if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || m_vdpauConfig.upscale >= 0)
658 //scale width to desktop size if the aspect ratio is the same or bigger than the desktop
659 if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight())
661 m_vdpauConfig.outWidth = g_graphicsContext.GetWidth();
662 m_vdpauConfig.outHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width);
664 else //scale height to the desktop size if the aspect ratio is smaller than the desktop
666 m_vdpauConfig.outHeight = g_graphicsContext.GetHeight();
667 m_vdpauConfig.outWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height);
672 m_vdpauConfig.outWidth = width;
673 m_vdpauConfig.outHeight = height;
675 if (g_advancedSettings.CanLogComponent(LOGVIDEO))
676 CLog::Log(LOGDEBUG, "CVDPAU::SetWidthHeight Setting OutWidth: %i OutHeight: %i", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight);
679 void CDecoder::OnLostDevice()
681 CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event");
683 int count = g_graphicsContext.exit();
685 CSingleLock lock(m_DecoderSection);
687 if (m_vdpauConfig.context)
688 m_vdpauConfig.context->Release();
689 m_vdpauConfig.context = 0;
691 m_DisplayState = VDPAU_LOST;
693 m_DisplayEvent.Reset();
695 g_graphicsContext.restore(count);
698 void CDecoder::OnResetDevice()
700 CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event");
702 int count = g_graphicsContext.exit();
704 CSingleLock lock(m_DecoderSection);
705 if (m_DisplayState == VDPAU_LOST)
707 m_DisplayState = VDPAU_RESET;
709 m_DisplayEvent.Set();
712 g_graphicsContext.restore(count);
715 int CDecoder::Check(AVCodecContext* avctx)
719 { CSingleLock lock(m_DecoderSection);
720 state = m_DisplayState;
723 if (state == VDPAU_LOST)
725 CLog::Log(LOGNOTICE,"CVDPAU::Check waiting for display reset event");
726 if (!m_DisplayEvent.WaitMSec(4000))
728 CLog::Log(LOGERROR, "CVDPAU::Check - device didn't reset in reasonable time");
733 CSingleLock lock(m_DecoderSection);
734 state = m_DisplayState;
737 if (state == VDPAU_RESET || state == VDPAU_ERROR)
739 CSingleLock lock(m_DecoderSection);
742 if (m_vdpauConfig.context)
743 m_vdpauConfig.context->Release();
744 m_vdpauConfig.context = 0;
746 if (CVDPAUContext::EnsureContext(&m_vdpauConfig.context))
748 m_DisplayState = VDPAU_OPEN;
749 m_vdpauConfigured = false;
752 if (state == VDPAU_RESET)
760 bool CDecoder::IsVDPAUFormat(PixelFormat format)
762 if (format == AV_PIX_FMT_VDPAU)
768 bool CDecoder::Supports(VdpVideoMixerFeature feature)
770 return m_vdpauConfig.context->Supports(feature);
773 bool CDecoder::Supports(EINTERLACEMETHOD method)
775 if(method == VS_INTERLACEMETHOD_VDPAU_BOB
776 || method == VS_INTERLACEMETHOD_AUTO)
779 if (method == VS_INTERLACEMETHOD_RENDER_BOB)
782 if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE)
785 for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++)
787 if(p->method == method)
788 return Supports(p->feature);
793 EINTERLACEMETHOD CDecoder::AutoInterlaceMethod()
795 return VS_INTERLACEMETHOD_RENDER_BOB;
798 void CDecoder::FiniVDPAUOutput()
800 if (!m_vdpauConfigured)
803 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
806 m_vdpauOutput.Dispose();
807 m_vdpauConfigured = false;
811 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
812 if (CheckStatus(vdp_st, __LINE__))
814 m_vdpauConfig.vdpDecoder = VDP_INVALID_HANDLE;
816 if (g_advancedSettings.CanLogComponent(LOGVIDEO))
817 CLog::Log(LOGDEBUG, "CVDPAU::FiniVDPAUOutput destroying %d video surfaces", m_videoSurfaces.Size());
819 VdpVideoSurface surf;
820 while((surf = m_videoSurfaces.RemoveNext()) != VDP_INVALID_HANDLE)
822 m_vdpauConfig.context->GetProcs().vdp_video_surface_destroy(surf);
823 if (CheckStatus(vdp_st, __LINE__))
826 m_videoSurfaces.Reset();
829 void CDecoder::ReadFormatOf( AVCodecID codec
830 , VdpDecoderProfile &vdp_decoder_profile
831 , VdpChromaType &vdp_chroma_type)
835 case AV_CODEC_ID_MPEG1VIDEO:
836 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
837 vdp_chroma_type = VDP_CHROMA_TYPE_420;
839 case AV_CODEC_ID_MPEG2VIDEO:
840 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
841 vdp_chroma_type = VDP_CHROMA_TYPE_420;
843 case AV_CODEC_ID_H264:
844 vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
845 vdp_chroma_type = VDP_CHROMA_TYPE_420;
847 #ifdef VDP_DECODER_PROFILE_HEVC_MAIN
848 case AV_CODEC_ID_HEVC:
849 vdp_decoder_profile = VDP_DECODER_PROFILE_HEVC_MAIN;
850 vdp_chroma_type = VDP_CHROMA_TYPE_420;
853 case AV_CODEC_ID_WMV3:
854 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
855 vdp_chroma_type = VDP_CHROMA_TYPE_420;
857 case AV_CODEC_ID_VC1:
858 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
859 vdp_chroma_type = VDP_CHROMA_TYPE_420;
861 case AV_CODEC_ID_MPEG4:
862 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
863 vdp_chroma_type = VDP_CHROMA_TYPE_420;
866 vdp_decoder_profile = 0;
872 bool CDecoder::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
877 VdpDecoderProfile vdp_decoder_profile;
879 m_vdpauConfig.vidWidth = avctx->width;
880 m_vdpauConfig.vidHeight = avctx->height;
881 m_vdpauConfig.surfaceWidth = avctx->coded_width;
882 m_vdpauConfig.surfaceHeight = avctx->coded_height;
884 SetWidthHeight(avctx->width,avctx->height);
886 CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",m_vdpauConfig.outWidth,m_vdpauConfig.vidWidth,m_vdpauConfig.surfaceWidth);
887 CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",m_vdpauConfig.outHeight,m_vdpauConfig.vidHeight,m_vdpauConfig.surfaceHeight);
889 ReadFormatOf(avctx->codec_id, vdp_decoder_profile, m_vdpauConfig.vdpChromaType);
891 if (avctx->codec_id == AV_CODEC_ID_H264)
893 m_vdpauConfig.maxReferences = ref_frames;
894 if (m_vdpauConfig.maxReferences > 16) m_vdpauConfig.maxReferences = 16;
895 if (m_vdpauConfig.maxReferences < 5) m_vdpauConfig.maxReferences = 5;
897 else if (avctx->codec_id == AV_CODEC_ID_HEVC)
899 // The DPB works quite differently in hevc and there isn't a per-file max
900 // reference number, so we force the maximum number (source: upstream ffmpeg)
901 m_vdpauConfig.maxReferences = 16;
904 m_vdpauConfig.maxReferences = 2;
906 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_create(m_vdpauConfig.context->GetDevice(),
908 m_vdpauConfig.surfaceWidth,
909 m_vdpauConfig.surfaceHeight,
910 m_vdpauConfig.maxReferences,
911 &m_vdpauConfig.vdpDecoder);
912 if (CheckStatus(vdp_st, __LINE__))
916 CSingleLock lock(g_graphicsContext);
917 m_vdpauConfig.stats = &m_bufferStats;
918 m_vdpauConfig.vdpau = this;
919 m_bufferStats.Reset();
920 m_vdpauOutput.Start();
922 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT,
926 sizeof(m_vdpauConfig)))
928 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
932 CLog::Log(LOGERROR, "VDPAU::%s - vdpau output returned error", __FUNCTION__);
933 m_vdpauOutput.Dispose();
939 CLog::Log(LOGERROR, "VDPAU::%s - failed to init output", __FUNCTION__);
940 m_vdpauOutput.Dispose();
944 m_inMsgEvent.Reset();
945 m_vdpauConfigured = true;
950 int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags)
952 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
953 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
954 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
956 // while we are waiting to recover we can't do anything
957 CSingleLock lock(vdp->m_DecoderSection);
959 if(vdp->m_DisplayState != VDPAU_OPEN)
961 CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
965 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
966 surf = vdp->m_videoSurfaces.GetFree(surf != 0 ? surf : VDP_INVALID_HANDLE);
968 VdpStatus vdp_st = VDP_STATUS_ERROR;
969 if (surf == VDP_INVALID_HANDLE)
971 // create a new surface
972 VdpDecoderProfile profile;
973 ReadFormatOf(avctx->codec_id, profile, vdp->m_vdpauConfig.vdpChromaType);
975 vdp_st = vdp->m_vdpauConfig.context->GetProcs().vdp_video_surface_create(vdp->m_vdpauConfig.context->GetDevice(),
976 vdp->m_vdpauConfig.vdpChromaType,
980 vdp->CheckStatus(vdp_st, __LINE__);
981 if (vdp_st != VDP_STATUS_OK)
983 CLog::Log(LOGERROR, "CVDPAU::FFGetBuffer - No Video surface available could be created");
986 vdp->m_videoSurfaces.AddSurface(surf);
989 pic->data[1] = pic->data[2] = NULL;
990 pic->data[0] = (uint8_t*)(uintptr_t)surf;
991 pic->data[3] = (uint8_t*)(uintptr_t)surf;
992 pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0;
993 AVBufferRef *buffer = av_buffer_create(pic->data[3], 0, FFReleaseBuffer, ctx, 0);
996 CLog::Log(LOGERROR, "CVDPAU::%s - error creating buffer", __FUNCTION__);
999 pic->buf[0] = buffer;
1001 pic->reordered_opaque= avctx->reordered_opaque;
1005 void CDecoder::FFReleaseBuffer(void *opaque, uint8_t *data)
1007 CDecoder *vdp = (CDecoder*)((CDVDVideoCodecFFmpeg*)opaque)->GetHardware();
1009 VdpVideoSurface surf;
1011 CSingleLock lock(vdp->m_DecoderSection);
1013 surf = (VdpVideoSurface)(uintptr_t)data;
1015 vdp->m_videoSurfaces.ClearReference(surf);
1018 int CDecoder::Render(struct AVCodecContext *s, struct AVFrame *src,
1019 const VdpPictureInfo *info, uint32_t buffers_used,
1020 const VdpBitstreamBuffer *buffers)
1022 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque;
1023 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
1025 // while we are waiting to recover we can't do anything
1026 CSingleLock lock(vdp->m_DecoderSection);
1028 if(vdp->m_DisplayState != VDPAU_OPEN)
1031 if(src->linesize[0] || src->linesize[1] || src->linesize[2])
1033 CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid linesizes or offsets provided");
1038 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)src->data[3];
1040 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1041 if (!vdp->m_videoSurfaces.IsValid(surf))
1043 CLog::Log(LOGWARNING, "CVDPAU::FFDrawSlice - ignoring invalid buffer");
1047 uint32_t max_refs = 0;
1048 if(s->codec_id == AV_CODEC_ID_H264)
1051 if(vdp->m_vdpauConfig.vdpDecoder == VDP_INVALID_HANDLE
1052 || vdp->m_vdpauConfigured == false
1053 || vdp->m_vdpauConfig.maxReferences < max_refs)
1055 if(!vdp->ConfigVDPAU(s, max_refs))
1059 uint64_t startTime = CurrentHostCounter();
1060 uint16_t decoded, processed, rend;
1061 vdp->m_bufferStats.Get(decoded, processed, rend);
1062 vdp_st = vdp->m_vdpauConfig.context->GetProcs().vdp_decoder_render(vdp->m_vdpauConfig.vdpDecoder,
1063 surf, info, buffers_used, buffers);
1064 if (vdp->CheckStatus(vdp_st, __LINE__))
1067 uint64_t diff = CurrentHostCounter() - startTime;
1068 if (diff*1000/CurrentHostFrequency() > 30)
1070 if (g_advancedSettings.CanLogComponent(LOGVIDEO))
1071 CLog::Log(LOGDEBUG, "CVDPAU::DrawSlice - VdpDecoderRender long decoding: %d ms, dec: %d, proc: %d, rend: %d", (int)((diff*1000)/CurrentHostFrequency()), decoded, processed, rend);
1078 int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame)
1080 int result = Check(avctx);
1084 CSingleLock lock(m_DecoderSection);
1086 if (!m_vdpauConfigured)
1090 { // we have a new frame from decoder
1092 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pFrame->data[3];
1093 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1094 if (!m_videoSurfaces.IsValid(surf))
1096 CLog::Log(LOGWARNING, "CVDPAU::Decode - ignoring invalid buffer");
1099 m_videoSurfaces.MarkRender(surf);
1101 // send frame to output for processing
1102 CVdpauDecodedPicture pic;
1103 memset(&pic.DVDPic, 0, sizeof(pic.DVDPic));
1104 ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic);
1105 pic.videoSurface = surf;
1106 pic.DVDPic.color_matrix = avctx->colorspace;
1107 m_bufferStats.IncDecoded();
1108 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic));
1110 m_codecControl = pic.DVDPic.iFlags & (DVD_CODEC_CTRL_DRAIN | DVD_CODEC_CTRL_NO_POSTPROC);
1114 uint16_t decoded, processed, render;
1116 while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1118 if (msg->signal == COutputControlProtocol::ERROR)
1120 m_DisplayState = VDPAU_ERROR;
1126 m_bufferStats.Get(decoded, processed, render);
1128 uint64_t startTime = CurrentHostCounter();
1131 // first fill the buffers to keep vdpau busy
1132 // mixer will run with decoded >= 2. output is limited by number of output surfaces
1133 // In case mixer is bypassed we limit by looking at processed
1134 if (decoded < 3 && processed < 3)
1136 retval |= VC_BUFFER;
1138 else if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg))
1140 if (msg->signal == COutputDataProtocol::PICTURE)
1142 if (m_presentPicture)
1144 m_presentPicture->ReturnUnused();
1145 m_presentPicture = 0;
1148 m_presentPicture = *(CVdpauRenderPicture**)msg->data;
1149 m_presentPicture->vdpau = this;
1150 m_bufferStats.DecRender();
1151 m_bufferStats.Get(decoded, processed, render);
1152 retval |= VC_PICTURE;
1158 else if (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1160 if (msg->signal == COutputControlProtocol::STATS)
1162 m_bufferStats.Get(decoded, processed, render);
1166 m_DisplayState = VDPAU_ERROR;
1172 if (decoded < 3 && processed < 3)
1174 retval |= VC_BUFFER;
1177 if (!retval && !m_inMsgEvent.WaitMSec(2000))
1180 uint64_t diff = CurrentHostCounter() - startTime;
1181 if (retval & VC_PICTURE)
1183 m_bufferStats.SetParams(diff, m_codecControl);
1185 if (diff*1000/CurrentHostFrequency() > 50)
1187 if (g_advancedSettings.CanLogComponent(LOGVIDEO))
1188 CLog::Log(LOGDEBUG,"CVDPAU::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency()));
1193 CLog::Log(LOGERROR, "VDPAU::%s - timed out waiting for output message", __FUNCTION__);
1194 m_DisplayState = VDPAU_ERROR;
1201 bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
1203 CSingleLock lock(m_DecoderSection);
1205 if (m_DisplayState != VDPAU_OPEN)
1208 *picture = m_presentPicture->DVDPic;
1209 picture->vdpau = m_presentPicture;
1214 void CDecoder::Reset()
1216 CSingleLock lock(m_DecoderSection);
1218 if (!m_vdpauConfigured)
1222 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH,
1226 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
1230 CLog::Log(LOGERROR, "VDPAU::%s - flush returned error", __FUNCTION__);
1231 m_DisplayState = VDPAU_ERROR;
1234 m_bufferStats.Reset();
1238 CLog::Log(LOGERROR, "VDPAU::%s - flush timed out", __FUNCTION__);
1239 m_DisplayState = VDPAU_ERROR;
1243 bool CDecoder::CanSkipDeint()
1245 return m_bufferStats.CanSkipDeint();
1248 void CDecoder::ReturnRenderPicture(CVdpauRenderPicture *renderPic)
1250 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic));
1253 bool CDecoder::CheckStatus(VdpStatus vdp_st, int line)
1255 if (vdp_st != VDP_STATUS_OK)
1257 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);
1261 if(m_DisplayState == VDPAU_OPEN)
1263 if (vdp_st == VDP_STATUS_DISPLAY_PREEMPTED)
1265 m_DisplayEvent.Reset();
1266 m_DisplayState = VDPAU_LOST;
1268 else if (m_ErrorCount > 2)
1269 m_DisplayState = VDPAU_ERROR;
1278 //-----------------------------------------------------------------------------
1280 //-----------------------------------------------------------------------------
1282 CVdpauRenderPicture* CVdpauRenderPicture::Acquire()
1284 CSingleLock lock(renderPicSection);
1293 long CVdpauRenderPicture::Release()
1295 CSingleLock lock(renderPicSection);
1302 vdpau->ReturnRenderPicture(this);
1303 vdpau->ReleasePicReference();
1308 void CVdpauRenderPicture::ReturnUnused()
1310 { CSingleLock lock(renderPicSection);
1315 vdpau->ReturnRenderPicture(this);
1318 void CVdpauRenderPicture::Sync()
1321 CSingleLock lock(renderPicSection);
1326 glDeleteSync(fence);
1329 fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1334 //-----------------------------------------------------------------------------
1336 //-----------------------------------------------------------------------------
1337 CMixer::CMixer(CEvent *inMsgEvent) :
1338 CThread("Vdpau Mixer"),
1339 m_controlPort("ControlPort", inMsgEvent, &m_outMsgEvent),
1340 m_dataPort("DataPort", inMsgEvent, &m_outMsgEvent)
1342 m_inMsgEvent = inMsgEvent;
1350 void CMixer::Start()
1355 void CMixer::Dispose()
1358 m_outMsgEvent.Set();
1361 m_controlPort.Purge();
1365 bool CMixer::IsActive()
1370 void CMixer::OnStartup()
1372 CLog::Log(LOGNOTICE, "CMixer::OnStartup: Output Thread created");
1375 void CMixer::OnExit()
1377 CLog::Log(LOGNOTICE, "CMixer::OnExit: Output Thread terminated");
1384 M_TOP_UNCONFIGURED, // 2
1385 M_TOP_CONFIGURED, // 3
1386 M_TOP_CONFIGURED_WAIT1, // 4
1387 M_TOP_CONFIGURED_STEP1, // 5
1388 M_TOP_CONFIGURED_WAIT2, // 6
1389 M_TOP_CONFIGURED_STEP2, // 7
1392 int MIXER_parentStates[] = {
1395 0, //TOP_UNCONFIGURED
1397 3, //TOP_CONFIGURED_WAIT1
1398 3, //TOP_CONFIGURED_STEP1
1399 3, //TOP_CONFIGURED_WAIT2
1400 3, //TOP_CONFIGURED_STEP2
1403 void CMixer::StateMachine(int signal, Protocol *port, Message *msg)
1405 for (int state = m_state; ; state = MIXER_parentStates[state])
1410 if (port == &m_controlPort)
1414 case CMixerControlProtocol::FLUSH:
1416 msg->Reply(CMixerControlProtocol::ACC);
1423 std::string portName = port == NULL ? "timer" : port->portName;
1424 CLog::Log(LOGWARNING, "CMixer::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
1428 case M_TOP_ERROR: // TOP
1431 case M_TOP_UNCONFIGURED:
1432 if (port == &m_controlPort)
1436 case CMixerControlProtocol::INIT:
1438 data = (CVdpauConfig*)msg->data;
1446 m_state = M_TOP_CONFIGURED_WAIT1;
1447 msg->Reply(CMixerControlProtocol::ACC);
1451 msg->Reply(CMixerControlProtocol::ERROR);
1460 case M_TOP_CONFIGURED:
1461 if (port == &m_controlPort)
1465 case CMixerControlProtocol::FLUSH:
1467 msg->Reply(CMixerControlProtocol::ACC);
1468 m_state = M_TOP_CONFIGURED_WAIT1;
1474 else if (port == &m_dataPort)
1478 case CMixerDataProtocol::FRAME:
1479 CVdpauDecodedPicture *frame;
1480 frame = (CVdpauDecodedPicture*)msg->data;
1483 m_decodedPics.push(*frame);
1487 case CMixerDataProtocol::BUFFER:
1488 VdpOutputSurface *surf;
1489 surf = (VdpOutputSurface*)msg->data;
1492 m_outputSurfaces.push(*surf);
1502 case M_TOP_CONFIGURED_WAIT1:
1503 if (port == NULL) // timeout
1507 case CMixerControlProtocol::TIMEOUT:
1508 if (!m_decodedPics.empty() && !m_outputSurfaces.empty())
1510 m_state = M_TOP_CONFIGURED_STEP1;
1511 m_bStateMachineSelfTrigger = true;
1524 case M_TOP_CONFIGURED_STEP1:
1525 if (port == NULL) // timeout
1529 case CMixerControlProtocol::TIMEOUT:
1530 m_mixerInput.push_front(m_decodedPics.front());
1531 m_decodedPics.pop();
1532 if (m_mixerInput.size() < 2)
1534 m_state = M_TOP_CONFIGURED_WAIT1;
1542 m_state = M_TOP_CONFIGURED_WAIT1;
1543 m_extTimeout = 1000;
1546 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1547 m_outputSurfaces.pop();
1548 m_config.stats->IncProcessed();
1549 m_config.stats->DecDecoded();
1550 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1551 if (m_mixersteps > 1)
1553 m_state = M_TOP_CONFIGURED_WAIT2;
1559 m_state = M_TOP_CONFIGURED_WAIT1;
1569 case M_TOP_CONFIGURED_WAIT2:
1570 if (port == NULL) // timeout
1574 case CMixerControlProtocol::TIMEOUT:
1575 if (!m_outputSurfaces.empty())
1577 m_state = M_TOP_CONFIGURED_STEP2;
1578 m_bStateMachineSelfTrigger = true;
1591 case M_TOP_CONFIGURED_STEP2:
1592 if (port == NULL) // timeout
1596 case CMixerControlProtocol::TIMEOUT:
1597 m_processPicture.outputSurface = m_outputSurfaces.front();
1602 m_state = M_TOP_CONFIGURED_WAIT1;
1603 m_extTimeout = 1000;
1606 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1607 m_outputSurfaces.pop();
1608 m_config.stats->IncProcessed();
1609 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1611 m_state = M_TOP_CONFIGURED_WAIT1;
1620 default: // we are in no state, should not happen
1621 CLog::Log(LOGERROR, "CMixer::%s - no valid state: %d", __FUNCTION__, m_state);
1627 void CMixer::Process()
1629 Message *msg = NULL;
1630 Protocol *port = NULL;
1633 m_state = M_TOP_UNCONFIGURED;
1634 m_extTimeout = 1000;
1635 m_bStateMachineSelfTrigger = false;
1641 if (m_bStateMachineSelfTrigger)
1643 m_bStateMachineSelfTrigger = false;
1644 // self trigger state machine
1645 StateMachine(msg->signal, port, msg);
1646 if (!m_bStateMachineSelfTrigger)
1653 // check control port
1654 else if (m_controlPort.ReceiveOutMessage(&msg))
1657 port = &m_controlPort;
1660 else if (m_dataPort.ReceiveOutMessage(&msg))
1668 StateMachine(msg->signal, port, msg);
1669 if (!m_bStateMachineSelfTrigger)
1678 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
1685 msg = m_controlPort.GetMessage();
1686 msg->signal = CMixerControlProtocol::TIMEOUT;
1688 // signal timeout to state machine
1689 StateMachine(msg->signal, port, msg);
1690 if (!m_bStateMachineSelfTrigger)
1700 void CMixer::CreateVdpauMixer()
1702 CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer");
1704 InitCSCMatrix(m_config.vidWidth);
1706 VdpVideoMixerParameter parameters[] = {
1707 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
1708 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
1709 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE};
1711 void const * parameter_values[] = {
1712 &m_config.surfaceWidth,
1713 &m_config.surfaceHeight,
1714 &m_config.vdpChromaType};
1716 VdpStatus vdp_st = m_config.context->GetProcs().vdp_video_mixer_create(m_config.context->GetDevice(),
1717 m_config.context->GetFeatureCount(),
1718 m_config.context->GetFeatures(),
1723 CheckStatus(vdp_st, __LINE__);
1727 void CMixer::InitCSCMatrix(int Width)
1729 m_Procamp.struct_version = VDP_PROCAMP_VERSION;
1730 m_Procamp.brightness = 0.0;
1731 m_Procamp.contrast = 1.0;
1732 m_Procamp.saturation = 1.0;
1736 void CMixer::CheckFeatures()
1738 if (m_Upscale != m_config.upscale)
1741 m_Upscale = m_config.upscale;
1743 if (m_Brightness != CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Brightness ||
1744 m_Contrast != CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Contrast ||
1745 m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix)
1748 m_Brightness = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Brightness;
1749 m_Contrast = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Contrast;
1750 m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix;
1752 if (m_NoiseReduction != CMediaSettings::GetInstance().GetCurrentVideoSettings().m_NoiseReduction)
1754 m_NoiseReduction = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_NoiseReduction;
1755 SetNoiseReduction();
1757 if (m_Sharpness != CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Sharpness)
1759 m_Sharpness = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Sharpness;
1762 if (m_DeintMode != CMediaSettings::GetInstance().GetCurrentVideoSettings().m_DeinterlaceMode ||
1763 m_Deint != CMediaSettings::GetInstance().GetCurrentVideoSettings().m_InterlaceMethod)
1765 m_DeintMode = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_DeinterlaceMode;
1766 m_Deint = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_InterlaceMethod;
1771 void CMixer::SetPostProcFeatures(bool postProcEnabled)
1773 if (m_PostProc != postProcEnabled)
1775 if (postProcEnabled)
1777 SetNoiseReduction();
1784 m_PostProc = postProcEnabled;
1788 void CMixer::PostProcOff()
1792 if (m_videoMixer == VDP_INVALID_HANDLE)
1795 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
1796 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
1797 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE};
1799 VdpBool enabled[]={0,0,0};
1800 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1801 CheckStatus(vdp_st, __LINE__);
1803 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1805 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION};
1807 VdpBool enabled[]={0};
1808 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1809 CheckStatus(vdp_st, __LINE__);
1812 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1814 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS};
1816 VdpBool enabled[]={0};
1817 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1818 CheckStatus(vdp_st, __LINE__);
1824 bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix)
1826 // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4])
1827 // m00 = mRY = red: luma factor (contrast factor) (1.0)
1828 // m10 = mGY = green: luma factor (contrast factor) (1.0)
1829 // m20 = mBY = blue: luma factor (contrast factor) (1.0)
1831 // m01 = mRB = red: blue color diff coeff (0.0)
1832 // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg))
1833 // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5)
1835 // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5)
1836 // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg))
1837 // m22 = mBR = blue: red color diff coeff (0.0)
1839 // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255))
1840 // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg)
1841 // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255))
1852 // colour standard coefficients for red, geen, blue
1854 // colour diff zero position (use standard 8-bit coding precision)
1855 double CDZ = 128; //256*0.5
1856 // range excursion (use standard 8-bit coding precision)
1857 double EXC = 255; //256-1
1859 if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601)
1861 Kr = studioCSCKCoeffs601[0];
1862 Kg = studioCSCKCoeffs601[1];
1863 Kb = studioCSCKCoeffs601[2];
1865 else // assume VDP_COLOR_STANDARD_ITUR_BT_709
1867 Kr = studioCSCKCoeffs709[0];
1868 Kg = studioCSCKCoeffs709[1];
1869 Kb = studioCSCKCoeffs709[2];
1871 // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235
1872 studioCSCMatrix[R][Y] = 1.0;
1873 studioCSCMatrix[G][Y] = 1.0;
1874 studioCSCMatrix[B][Y] = 1.0;
1876 studioCSCMatrix[R][Cb] = 0.0;
1877 studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg;
1878 studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5;
1880 studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5;
1881 studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg;
1882 studioCSCMatrix[B][Cr] = 0.0;
1884 studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC;
1885 studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC;
1886 studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC;
1891 void CMixer::SetColor()
1895 if (m_Brightness != CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Brightness)
1896 m_Procamp.brightness = (float)((CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Brightness)-50) / 100;
1897 if (m_Contrast != CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Contrast)
1898 m_Procamp.contrast = (float)((CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Contrast)+50) / 100;
1900 VdpColorStandard colorStandard;
1901 switch(m_mixerInput[1].DVDPic.color_matrix)
1903 case AVCOL_SPC_BT709:
1904 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1906 case AVCOL_SPC_BT470BG:
1907 case AVCOL_SPC_SMPTE170M:
1908 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1910 case AVCOL_SPC_SMPTE240M:
1911 colorStandard = VDP_COLOR_STANDARD_SMPTE_240M;
1914 case AVCOL_SPC_UNSPECIFIED:
1917 if(m_config.surfaceWidth > 1000)
1918 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1920 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1923 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
1924 if (CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOSCREEN_LIMITEDRANGE))
1926 float studioCSC[3][4];
1927 GenerateStudioCSCMatrix(colorStandard, studioCSC);
1928 void const * pm_CSCMatix[] = { &studioCSC };
1929 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1933 vdp_st = m_config.context->GetProcs().vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix);
1934 if(vdp_st != VDP_STATUS_ERROR)
1936 void const * pm_CSCMatix[] = { &m_CSCMatrix };
1937 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1941 CheckStatus(vdp_st, __LINE__);
1944 void CMixer::SetNoiseReduction()
1946 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1949 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION };
1950 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL };
1953 if (!CMediaSettings::GetInstance().GetCurrentVideoSettings().m_NoiseReduction)
1955 VdpBool enabled[]= {0};
1956 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1957 CheckStatus(vdp_st, __LINE__);
1960 VdpBool enabled[]={1};
1961 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1962 CheckStatus(vdp_st, __LINE__);
1963 void* nr[] = { &CMediaSettings::GetInstance().GetCurrentVideoSettings().m_NoiseReduction };
1964 CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",CMediaSettings::GetInstance().GetCurrentVideoSettings().m_NoiseReduction);
1965 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, nr);
1966 CheckStatus(vdp_st, __LINE__);
1969 void CMixer::SetSharpness()
1971 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1974 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS };
1975 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL };
1978 if (!CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Sharpness)
1980 VdpBool enabled[]={0};
1981 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1982 CheckStatus(vdp_st, __LINE__);
1985 VdpBool enabled[]={1};
1986 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1987 CheckStatus(vdp_st, __LINE__);
1988 void* sh[] = { &CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Sharpness };
1989 CLog::Log(LOGNOTICE,"Setting Sharpness to %f",CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Sharpness);
1990 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, sh);
1991 CheckStatus(vdp_st, __LINE__);
1994 EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */)
1996 EINTERLACEMETHOD method = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_InterlaceMethod;
1997 if (method == VS_INTERLACEMETHOD_AUTO)
2000 // if (m_config.outHeight >= 720)
2001 // deint = g_advancedSettings.m_videoVDPAUdeintHD;
2003 // deint = g_advancedSettings.m_videoVDPAUdeintSD;
2007 if (m_config.vdpau->Supports(EINTERLACEMETHOD(deint)))
2009 method = EINTERLACEMETHOD(deint);
2011 CLog::Log(LOGNOTICE, "CVDPAU::GetDeinterlacingMethod: set de-interlacing to %d", deint);
2016 CLog::Log(LOGWARNING, "CVDPAU::GetDeinterlacingMethod: method for de-interlacing (advanced settings) not supported");
2023 void CMixer::SetDeinterlacing()
2027 if (m_videoMixer == VDP_INVALID_HANDLE)
2030 EDEINTERLACEMODE mode = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_DeinterlaceMode;
2031 EINTERLACEMETHOD method = GetDeinterlacingMethod(true);
2033 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
2034 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
2035 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE };
2037 if (mode == VS_DEINTERLACEMODE_OFF)
2039 VdpBool enabled[] = {0,0,0};
2040 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2044 if (method == VS_INTERLACEMETHOD_AUTO)
2046 VdpBool enabled[] = {1,0,0};
2047 if (g_advancedSettings.m_videoVDPAUtelecine)
2049 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2051 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2052 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF)
2054 VdpBool enabled[] = {1,0,0};
2055 if (g_advancedSettings.m_videoVDPAUtelecine)
2057 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2059 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2060 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF)
2062 VdpBool enabled[] = {1,1,0};
2063 if (g_advancedSettings.m_videoVDPAUtelecine)
2065 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2069 VdpBool enabled[]={0,0,0};
2070 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2073 CheckStatus(vdp_st, __LINE__);
2075 SetDeintSkipChroma();
2077 m_config.useInteropYuv = !CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEVDPAUMIXER);
2080 void CMixer::SetDeintSkipChroma()
2082 VdpVideoMixerAttribute attribute[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE};
2086 if (g_advancedSettings.m_videoVDPAUdeintSkipChromaHD && m_config.outHeight >= 720)
2091 void const *values[]={&val};
2092 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attribute), attribute, values);
2094 CheckStatus(vdp_st, __LINE__);
2097 void CMixer::SetHWUpscaling()
2099 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
2102 VdpBool enabled[]={1};
2103 switch (m_config.upscale)
2106 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
2108 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
2109 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2113 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
2115 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
2116 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2120 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2122 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2123 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2127 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2129 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2130 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2134 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2136 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2137 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2141 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2143 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2144 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2148 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2150 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2151 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2155 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2157 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2158 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2162 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2164 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2165 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2172 CheckStatus(vdp_st, __LINE__);
2176 void CMixer::DisableHQScaling()
2180 if (m_videoMixer == VDP_INVALID_HANDLE)
2183 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2185 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2186 VdpBool enabled[]={0};
2187 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2188 CheckStatus(vdp_st, __LINE__);
2191 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2193 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2194 VdpBool enabled[]={0};
2195 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2196 CheckStatus(vdp_st, __LINE__);
2199 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2201 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2202 VdpBool enabled[]={0};
2203 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2204 CheckStatus(vdp_st, __LINE__);
2207 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2209 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2210 VdpBool enabled[]={0};
2211 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2212 CheckStatus(vdp_st, __LINE__);
2215 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2217 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2218 VdpBool enabled[]={0};
2219 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2220 CheckStatus(vdp_st, __LINE__);
2223 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2225 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2226 VdpBool enabled[]={0};
2227 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2228 CheckStatus(vdp_st, __LINE__);
2231 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2233 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2234 VdpBool enabled[]={0};
2235 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2236 CheckStatus(vdp_st, __LINE__);
2239 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
2241 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
2242 VdpBool enabled[]={0};
2243 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2244 CheckStatus(vdp_st, __LINE__);
2247 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
2249 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
2250 VdpBool enabled[]={0};
2251 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2252 CheckStatus(vdp_st, __LINE__);
2260 m_NoiseReduction = 0.0;
2265 m_SeenInterlaceFlag = false;
2270 m_config.upscale = g_advancedSettings.m_videoVDPAUScaling;
2271 m_config.useInteropYuv = !CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEVDPAUMIXER);
2276 void CMixer::Uninit()
2279 while (!m_outputSurfaces.empty())
2281 m_outputSurfaces.pop();
2283 m_config.context->GetProcs().vdp_video_mixer_destroy(m_videoMixer);
2286 void CMixer::Flush()
2288 while (!m_mixerInput.empty())
2290 CVdpauDecodedPicture pic = m_mixerInput.back();
2291 m_mixerInput.pop_back();
2292 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2294 while (!m_decodedPics.empty())
2296 CVdpauDecodedPicture pic = m_decodedPics.front();
2297 m_decodedPics.pop();
2298 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2301 while (m_dataPort.ReceiveOutMessage(&msg))
2303 if (msg->signal == CMixerDataProtocol::FRAME)
2305 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2306 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2308 else if (msg->signal == CMixerDataProtocol::BUFFER)
2310 VdpOutputSurface *surf;
2311 surf = (VdpOutputSurface*)msg->data;
2312 m_outputSurfaces.push(*surf);
2318 void CMixer::InitCycle()
2323 m_config.stats->GetParams(latency, flags);
2324 if (flags & DVD_CODEC_CTRL_NO_POSTPROC)
2325 SetPostProcFeatures(false);
2327 SetPostProcFeatures(true);
2329 m_config.stats->SetCanSkipDeint(false);
2331 EDEINTERLACEMODE mode = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_DeinterlaceMode;
2332 EINTERLACEMETHOD method = GetDeinterlacingMethod();
2333 bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED;
2334 m_SeenInterlaceFlag |= interlaced;
2336 if (!(flags & DVD_CODEC_CTRL_NO_POSTPROC) &&
2337 (mode == VS_DEINTERLACEMODE_FORCE ||
2338 (mode == VS_DEINTERLACEMODE_AUTO && interlaced)))
2340 if((method == VS_INTERLACEMETHOD_AUTO && interlaced)
2341 || method == VS_INTERLACEMETHOD_VDPAU_BOB
2342 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2343 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2344 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2345 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2346 || method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE )
2348 if(method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2349 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2350 || !g_graphicsContext.IsFullScreenVideo())
2355 m_config.stats->SetCanSkipDeint(true);
2358 if (m_mixerInput[1].DVDPic.iFlags & DVD_CODEC_CTRL_SKIPDEINT)
2363 if(m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST)
2364 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2366 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2368 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2369 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2370 DVP_FLAG_REPEAT_TOP_FIELD |
2371 DVP_FLAG_INTERLACED);
2372 m_config.useInteropYuv = false;
2374 else if (method == VS_INTERLACEMETHOD_RENDER_BOB)
2377 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2378 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2379 m_config.useInteropYuv = true;
2383 CLog::Log(LOGERROR, "CMixer::%s - interlace method: %d not supported, setting to AUTO", __FUNCTION__, method);
2385 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2386 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2387 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2388 DVP_FLAG_REPEAT_TOP_FIELD |
2389 DVP_FLAG_INTERLACED);
2391 CMediaSettings::GetInstance().GetCurrentVideoSettings().m_InterlaceMethod = VS_INTERLACEMETHOD_AUTO;
2397 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2399 if (m_config.useInteropYuv)
2400 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2403 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2404 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2405 DVP_FLAG_REPEAT_TOP_FIELD |
2406 DVP_FLAG_INTERLACED);
2411 m_processPicture.crop = false;
2412 if (m_mixerInput[1].DVDPic.format == RENDER_FMT_VDPAU)
2414 m_processPicture.outputSurface = m_outputSurfaces.front();
2415 m_mixerInput[1].DVDPic.iWidth = m_config.outWidth;
2416 m_mixerInput[1].DVDPic.iHeight = m_config.outHeight;
2417 if (m_SeenInterlaceFlag)
2419 double ratio = (double)m_mixerInput[1].DVDPic.iDisplayHeight / m_mixerInput[1].DVDPic.iHeight;
2420 m_mixerInput[1].DVDPic.iDisplayHeight = lrint(ratio*(m_mixerInput[1].DVDPic.iHeight-NUM_CROP_PIX*2));
2421 m_processPicture.crop = true;
2426 m_mixerInput[1].DVDPic.iWidth = m_config.vidWidth;
2427 m_mixerInput[1].DVDPic.iHeight = m_config.vidHeight;
2430 m_processPicture.DVDPic = m_mixerInput[1].DVDPic;
2431 m_processPicture.videoSurface = m_mixerInput[1].videoSurface;
2434 void CMixer::FiniCycle()
2436 // Keep video surfaces for one 2 cycles longer than used
2437 // by mixer. This avoids blocking in decoder.
2438 // NVidia recommends num_ref + 5
2439 while (m_mixerInput.size() > 5)
2441 CVdpauDecodedPicture &tmp = m_mixerInput.back();
2442 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
2444 m_config.videoSurfaces->ClearRender(tmp.videoSurface);
2446 m_mixerInput.pop_back();
2450 void CMixer::ProcessPicture()
2452 if (m_processPicture.DVDPic.format == RENDER_FMT_VDPAU_420)
2457 if (m_mixerstep == 1)
2459 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD)
2460 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2462 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2465 VdpVideoSurface past_surfaces[4] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2466 VdpVideoSurface futu_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2467 uint32_t pastCount = 4;
2468 uint32_t futuCount = 2;
2470 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
2472 // use only 2 past 1 future for progressive/weave
2473 // (only used for postproc anyway eg noise reduction)
2474 if (m_mixerInput.size() > 3)
2475 past_surfaces[1] = m_mixerInput[3].videoSurface;
2476 if (m_mixerInput.size() > 2)
2477 past_surfaces[0] = m_mixerInput[2].videoSurface;
2478 futu_surfaces[0] = m_mixerInput[0].videoSurface;
2484 if(m_mixerstep == 0)
2486 if (m_mixerInput.size() > 3)
2488 past_surfaces[3] = m_mixerInput[3].videoSurface;
2489 past_surfaces[2] = m_mixerInput[3].videoSurface;
2491 if (m_mixerInput.size() > 2)
2493 past_surfaces[1] = m_mixerInput[2].videoSurface;
2494 past_surfaces[0] = m_mixerInput[2].videoSurface;
2496 futu_surfaces[0] = m_mixerInput[1].videoSurface;
2497 futu_surfaces[1] = m_mixerInput[0].videoSurface;
2501 if (m_mixerInput.size() > 3)
2503 past_surfaces[3] = m_mixerInput[3].videoSurface;
2505 if (m_mixerInput.size() > 2)
2507 past_surfaces[2] = m_mixerInput[2].videoSurface;
2508 past_surfaces[1] = m_mixerInput[2].videoSurface;
2510 past_surfaces[0] = m_mixerInput[1].videoSurface;
2511 futu_surfaces[0] = m_mixerInput[0].videoSurface;
2512 futu_surfaces[1] = m_mixerInput[0].videoSurface;
2514 if (m_mixerInput[0].DVDPic.pts != DVD_NOPTS_VALUE &&
2515 m_mixerInput[1].DVDPic.pts != DVD_NOPTS_VALUE)
2517 m_processPicture.DVDPic.pts = m_mixerInput[1].DVDPic.pts +
2518 (m_mixerInput[0].DVDPic.pts -
2519 m_mixerInput[1].DVDPic.pts) / 2;
2522 m_processPicture.DVDPic.pts = DVD_NOPTS_VALUE;
2523 m_processPicture.DVDPic.dts = DVD_NOPTS_VALUE;
2525 m_processPicture.DVDPic.iRepeatPicture = 0.0;
2531 sourceRect.x1 = m_config.vidWidth;
2532 sourceRect.y1 = m_config.vidHeight;
2537 destRect.x1 = m_config.outWidth;
2538 destRect.y1 = m_config.outHeight;
2540 // start vdpau video mixer
2541 vdp_st = m_config.context->GetProcs().vdp_video_mixer_render(m_videoMixer,
2547 m_mixerInput[1].videoSurface,
2551 m_processPicture.outputSurface,
2556 CheckStatus(vdp_st, __LINE__);
2560 bool CMixer::CheckStatus(VdpStatus vdp_st, int line)
2562 if (vdp_st != VDP_STATUS_OK)
2564 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);
2571 //-----------------------------------------------------------------------------
2573 //-----------------------------------------------------------------------------
2575 VdpauBufferPool::VdpauBufferPool()
2577 CVdpauRenderPicture *pic;
2578 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2580 pic = new CVdpauRenderPicture(renderPicSec);
2581 allRenderPics.push_back(pic);
2585 VdpauBufferPool::~VdpauBufferPool()
2587 CVdpauRenderPicture *pic;
2588 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2590 pic = allRenderPics[i];
2593 allRenderPics.clear();
2596 //-----------------------------------------------------------------------------
2598 //-----------------------------------------------------------------------------
2599 COutput::COutput(CEvent *inMsgEvent) :
2600 CThread("Vdpau Output"),
2601 m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent),
2602 m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent),
2603 m_mixer(&m_outMsgEvent)
2605 m_inMsgEvent = inMsgEvent;
2607 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i)
2609 m_bufferPool.freeRenderPics.push_back(i);
2613 void COutput::Start()
2622 m_bufferPool.freeRenderPics.clear();
2623 m_bufferPool.usedRenderPics.clear();
2626 void COutput::Dispose()
2628 CSingleLock lock(g_graphicsContext);
2630 m_outMsgEvent.Set();
2632 m_controlPort.Purge();
2636 void COutput::OnStartup()
2638 CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created");
2641 void COutput::OnExit()
2643 CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated");
2650 O_TOP_UNCONFIGURED, // 2
2651 O_TOP_CONFIGURED, // 3
2652 O_TOP_CONFIGURED_IDLE, // 4
2653 O_TOP_CONFIGURED_WORK, // 5
2656 int VDPAU_OUTPUT_parentStates[] = {
2659 0, //TOP_UNCONFIGURED
2661 3, //TOP_CONFIGURED_IDLE
2662 3, //TOP_CONFIGURED_WORK
2665 void COutput::StateMachine(int signal, Protocol *port, Message *msg)
2667 for (int state = m_state; ; state = VDPAU_OUTPUT_parentStates[state])
2672 if (port == &m_controlPort)
2676 case COutputControlProtocol::FLUSH:
2677 msg->Reply(COutputControlProtocol::ACC);
2679 case COutputControlProtocol::PRECLEANUP:
2680 msg->Reply(COutputControlProtocol::ACC);
2686 else if (port == &m_dataPort)
2690 case COutputDataProtocol::RETURNPIC:
2691 CVdpauRenderPicture *pic;
2692 pic = *((CVdpauRenderPicture**)msg->data);
2693 QueueReturnPicture(pic);
2700 std::string portName = port == NULL ? "timer" : port->portName;
2701 CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
2708 case O_TOP_UNCONFIGURED:
2709 if (port == &m_controlPort)
2713 case COutputControlProtocol::INIT:
2715 data = (CVdpauConfig*)msg->data;
2722 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::INIT,
2723 &reply, 1000, &m_config, sizeof(m_config)))
2725 if (reply->signal != CMixerControlProtocol::ACC)
2730 // set initial number of
2731 m_bufferPool.numOutputSurfaces = 4;
2735 m_state = O_TOP_CONFIGURED_IDLE;
2736 msg->Reply(COutputControlProtocol::ACC, &m_config, sizeof(m_config));
2740 m_state = O_TOP_ERROR;
2741 msg->Reply(COutputControlProtocol::ERROR);
2750 case O_TOP_CONFIGURED:
2751 if (port == &m_controlPort)
2755 case COutputControlProtocol::FLUSH:
2757 msg->Reply(COutputControlProtocol::ACC);
2759 case COutputControlProtocol::PRECLEANUP:
2762 msg->Reply(COutputControlProtocol::ACC);
2768 else if (port == &m_dataPort)
2772 case COutputDataProtocol::NEWFRAME:
2773 CVdpauDecodedPicture *frame;
2774 frame = (CVdpauDecodedPicture*)msg->data;
2777 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::FRAME,
2778 frame,sizeof(CVdpauDecodedPicture));
2781 case COutputDataProtocol::RETURNPIC:
2782 CVdpauRenderPicture *pic;
2783 pic = *((CVdpauRenderPicture**)msg->data);
2784 QueueReturnPicture(pic);
2785 m_controlPort.SendInMessage(COutputControlProtocol::STATS);
2786 m_state = O_TOP_CONFIGURED_WORK;
2793 else if (port == &m_mixer.m_dataPort)
2797 case CMixerDataProtocol::PICTURE:
2798 CVdpauProcessedPicture *pic;
2799 pic = (CVdpauProcessedPicture*)msg->data;
2800 m_bufferPool.processedPics.push(*pic);
2801 m_state = O_TOP_CONFIGURED_WORK;
2810 case O_TOP_CONFIGURED_IDLE:
2811 if (port == NULL) // timeout
2815 case COutputControlProtocol::TIMEOUT:
2816 if (ProcessSyncPicture())
2822 m_state = O_TOP_CONFIGURED_WORK;
2832 case O_TOP_CONFIGURED_WORK:
2833 if (port == NULL) // timeout
2837 case COutputControlProtocol::TIMEOUT:
2840 CVdpauRenderPicture *pic;
2841 pic = ProcessMixerPicture();
2844 m_config.stats->DecProcessed();
2845 m_config.stats->IncRender();
2846 m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic));
2852 m_state = O_TOP_CONFIGURED_IDLE;
2862 default: // we are in no state, should not happen
2863 CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state);
2869 void COutput::Process()
2871 Message *msg = NULL;
2872 Protocol *port = NULL;
2875 m_state = O_TOP_UNCONFIGURED;
2876 m_extTimeout = 1000;
2877 m_bStateMachineSelfTrigger = false;
2883 if (m_bStateMachineSelfTrigger)
2885 m_bStateMachineSelfTrigger = false;
2886 // self trigger state machine
2887 StateMachine(msg->signal, port, msg);
2888 if (!m_bStateMachineSelfTrigger)
2895 // check control port
2896 else if (m_controlPort.ReceiveOutMessage(&msg))
2899 port = &m_controlPort;
2902 else if (m_dataPort.ReceiveOutMessage(&msg))
2907 // check mixer data port
2908 else if (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2911 port = &m_mixer.m_dataPort;
2915 StateMachine(msg->signal, port, msg);
2916 if (!m_bStateMachineSelfTrigger)
2925 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
2932 msg = m_controlPort.GetMessage();
2933 msg->signal = COutputControlProtocol::TIMEOUT;
2935 // signal timeout to state machine
2936 StateMachine(msg->signal, port, msg);
2937 if (!m_bStateMachineSelfTrigger)
2948 bool COutput::Init()
2950 if (!CreateGlxContext())
2962 bool COutput::Uninit()
2966 while(ProcessSyncPicture())
2971 ReleaseBufferPool();
2972 DestroyGlxContext();
2976 void COutput::Flush()
2978 if (m_mixer.IsActive())
2981 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH,
2988 CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__);
2992 while (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2994 if (msg->signal == CMixerDataProtocol::PICTURE)
2996 CVdpauProcessedPicture pic = *(CVdpauProcessedPicture*)msg->data;
2997 m_bufferPool.processedPics.push(pic);
3002 while (m_dataPort.ReceiveOutMessage(&msg))
3004 if (msg->signal == COutputDataProtocol::NEWFRAME)
3006 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
3007 m_config.videoSurfaces->ClearRender(pic.videoSurface);
3009 else if (msg->signal == COutputDataProtocol::RETURNPIC)
3011 CVdpauRenderPicture *pic;
3012 pic = *((CVdpauRenderPicture**)msg->data);
3013 QueueReturnPicture(pic);
3018 while (m_dataPort.ReceiveInMessage(&msg))
3020 if (msg->signal == COutputDataProtocol::PICTURE)
3022 CVdpauRenderPicture *pic;
3023 pic = *((CVdpauRenderPicture**)msg->data);
3024 QueueReturnPicture(pic);
3028 // reset used render flag which was cleared on mixer flush
3029 std::deque<int>::iterator it;
3030 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3032 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[*it];
3033 if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3035 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it2;
3036 it2 = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3037 if (it2 == m_bufferPool.glVideoSurfaceMap.end())
3039 if (g_advancedSettings.CanLogComponent(LOGVIDEO))
3040 CLog::Log(LOGDEBUG, "COutput::Flush - gl surface not found");
3044 m_config.videoSurfaces->MarkRender(it2->second.sourceVuv);
3048 // clear processed pics
3049 while(!m_bufferPool.processedPics.empty())
3051 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
3052 if (procPic.DVDPic.format == RENDER_FMT_VDPAU)
3054 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &procPic.outputSurface, sizeof(procPic.outputSurface));
3056 else if (procPic.DVDPic.format == RENDER_FMT_VDPAU_420)
3058 m_config.videoSurfaces->ClearRender(procPic.videoSurface);
3060 m_bufferPool.processedPics.pop();
3064 bool COutput::HasWork()
3066 if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
3071 CVdpauRenderPicture* COutput::ProcessMixerPicture()
3073 CVdpauRenderPicture *retPic = NULL;
3075 if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
3077 int idx = m_bufferPool.freeRenderPics.front();
3078 retPic = m_bufferPool.allRenderPics[idx];
3079 m_bufferPool.freeRenderPics.pop_front();
3080 m_bufferPool.usedRenderPics.push_back(idx);
3081 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
3082 m_bufferPool.processedPics.pop();
3084 retPic->DVDPic = procPic.DVDPic;
3085 retPic->valid = true;
3086 if (retPic->DVDPic.format == RENDER_FMT_VDPAU)
3088 m_config.useInteropYuv = false;
3089 m_bufferPool.numOutputSurfaces = NUM_RENDER_PICS;
3091 GLMapSurface(false, procPic.outputSurface);
3092 retPic->sourceIdx = procPic.outputSurface;
3093 retPic->texture[0] = m_bufferPool.glOutputSurfaceMap[procPic.outputSurface].texture[0];
3094 retPic->texWidth = m_config.outWidth;
3095 retPic->texHeight = m_config.outHeight;
3096 retPic->crop.x1 = 0;
3097 retPic->crop.y1 = procPic.crop ? NUM_CROP_PIX : 0;
3098 retPic->crop.x2 = m_config.outWidth;
3099 retPic->crop.y2 = m_config.outHeight - retPic->crop.y1;
3103 m_config.useInteropYuv = true;
3104 GLMapSurface(true, procPic.videoSurface);
3105 retPic->sourceIdx = procPic.videoSurface;
3106 for (unsigned int i=0; i<4; ++i)
3107 retPic->texture[i] = m_bufferPool.glVideoSurfaceMap[procPic.videoSurface].texture[i];
3108 retPic->texWidth = m_config.surfaceWidth;
3109 retPic->texHeight = m_config.surfaceHeight;
3110 retPic->crop.x1 = 0;
3111 retPic->crop.y1 = 0;
3112 retPic->crop.x2 = m_config.surfaceWidth - m_config.vidWidth;
3113 retPic->crop.y2 = m_config.surfaceHeight - m_config.vidHeight;
3119 void COutput::QueueReturnPicture(CVdpauRenderPicture *pic)
3121 std::deque<int>::iterator it;
3122 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3124 if (m_bufferPool.allRenderPics[*it] == pic)
3130 if (it == m_bufferPool.usedRenderPics.end())
3132 CLog::Log(LOGWARNING, "COutput::QueueReturnPicture - pic not found");
3136 // check if already queued
3137 std::deque<int>::iterator it2 = find(m_bufferPool.syncRenderPics.begin(),
3138 m_bufferPool.syncRenderPics.end(),
3140 if (it2 == m_bufferPool.syncRenderPics.end())
3142 m_bufferPool.syncRenderPics.push_back(*it);
3145 ProcessSyncPicture();
3148 bool COutput::ProcessSyncPicture()
3150 CVdpauRenderPicture *pic;
3153 std::deque<int>::iterator it;
3154 for (it = m_bufferPool.syncRenderPics.begin(); it != m_bufferPool.syncRenderPics.end(); )
3156 pic = m_bufferPool.allRenderPics[*it];
3161 if (glIsSync(pic->fence))
3165 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3166 if(state == GL_SIGNALED)
3168 glDeleteSync(pic->fence);
3181 m_bufferPool.freeRenderPics.push_back(*it);
3183 std::deque<int>::iterator it2 = find(m_bufferPool.usedRenderPics.begin(),
3184 m_bufferPool.usedRenderPics.end(),
3186 if (it2 == m_bufferPool.usedRenderPics.end())
3188 CLog::Log(LOGERROR, "COutput::ProcessSyncPicture - pic not found in queue");
3192 m_bufferPool.usedRenderPics.erase(it2);
3194 it = m_bufferPool.syncRenderPics.erase(it);
3198 ProcessReturnPicture(pic);
3202 if (g_advancedSettings.CanLogComponent(LOGVIDEO))
3203 CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__);
3209 void COutput::ProcessReturnPicture(CVdpauRenderPicture *pic)
3211 if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3213 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3214 it = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3215 if (it == m_bufferPool.glVideoSurfaceMap.end())
3217 if (g_advancedSettings.CanLogComponent(LOGVIDEO))
3218 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3222 #ifdef GL_NV_vdpau_interop
3223 glVDPAUUnmapSurfacesNV(1, &(it->second.glVdpauSurface));
3225 VdpVideoSurface surf = it->second.sourceVuv;
3226 m_config.videoSurfaces->ClearRender(surf);
3228 else if (pic->DVDPic.format == RENDER_FMT_VDPAU)
3230 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3231 it = m_bufferPool.glOutputSurfaceMap.find(pic->sourceIdx);
3232 if (it == m_bufferPool.glOutputSurfaceMap.end())
3234 if (g_advancedSettings.CanLogComponent(LOGVIDEO))
3235 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3239 #ifdef GL_NV_vdpau_interop
3240 glVDPAUUnmapSurfacesNV(1, &(it->second.glVdpauSurface));
3242 VdpOutputSurface outSurf = it->second.sourceRgb;
3243 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &outSurf, sizeof(outSurf));
3247 bool COutput::EnsureBufferPool()
3251 // Creation of outputSurfaces
3252 VdpOutputSurface outputSurface;
3253 for (int i = m_bufferPool.outputSurfaces.size(); i < m_bufferPool.numOutputSurfaces; i++)
3255 vdp_st = m_config.context->GetProcs().vdp_output_surface_create(m_config.context->GetDevice(),
3256 VDP_RGBA_FORMAT_B8G8R8A8,
3260 if (CheckStatus(vdp_st, __LINE__))
3262 m_bufferPool.outputSurfaces.push_back(outputSurface);
3264 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3266 sizeof(VdpOutputSurface));
3267 CLog::Log(LOGNOTICE, "VDPAU::COutput::InitBufferPool - Output Surface created");
3272 void COutput::ReleaseBufferPool()
3276 CSingleLock lock(m_bufferPool.renderPicSec);
3278 // release all output surfaces
3279 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3281 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3283 vdp_st = m_config.context->GetProcs().vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3284 CheckStatus(vdp_st, __LINE__);
3286 m_bufferPool.outputSurfaces.clear();
3288 // wait for all fences
3289 XbmcThreads::EndTime timeout(1000);
3290 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3292 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[i];
3296 while (glIsSync(pic->fence))
3300 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3301 if(state == GL_SIGNALED || timeout.IsTimePast())
3303 glDeleteSync(pic->fence);
3314 if (timeout.IsTimePast())
3316 CLog::Log(LOGERROR, "COutput::%s - timeout waiting for fence", __FUNCTION__);
3318 ProcessSyncPicture();
3320 // invalidate all used render pictures
3321 for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i)
3323 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[m_bufferPool.usedRenderPics[i]];
3328 void COutput::PreCleanup()
3334 ProcessSyncPicture();
3336 CSingleLock lock(m_bufferPool.renderPicSec);
3337 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3339 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3342 // check if output surface is in use
3344 std::deque<int>::iterator it;
3345 CVdpauRenderPicture *pic;
3346 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3348 pic = m_bufferPool.allRenderPics[*it];
3349 if ((pic->sourceIdx == m_bufferPool.outputSurfaces[i]) && pic->valid)
3358 #ifdef GL_NV_vdpau_interop
3360 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it_map;
3361 it_map = m_bufferPool.glOutputSurfaceMap.find(m_bufferPool.outputSurfaces[i]);
3362 if (it_map == m_bufferPool.glOutputSurfaceMap.end())
3364 CLog::Log(LOGERROR, "%s - could not find gl surface", __FUNCTION__);
3367 glVDPAUUnregisterSurfaceNV(it_map->second.glVdpauSurface);
3368 glDeleteTextures(1, it_map->second.texture);
3369 m_bufferPool.glOutputSurfaceMap.erase(it_map);
3372 vdp_st = m_config.context->GetProcs().vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3373 CheckStatus(vdp_st, __LINE__);
3375 m_bufferPool.outputSurfaces[i] = VDP_INVALID_HANDLE;
3376 if (g_advancedSettings.CanLogComponent(LOGVIDEO))
3377 CLog::Log(LOGDEBUG, "VDPAU::PreCleanup - released output surface");
3382 void COutput::InitMixer()
3384 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3386 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3387 &m_bufferPool.outputSurfaces[i],
3388 sizeof(VdpOutputSurface));
3392 bool COutput::GLInit()
3394 #ifdef GL_NV_vdpau_interop
3395 glVDPAUInitNV = NULL;
3396 glVDPAUFiniNV = NULL;
3397 glVDPAURegisterOutputSurfaceNV = NULL;
3398 glVDPAURegisterVideoSurfaceNV = NULL;
3399 glVDPAUIsSurfaceNV = NULL;
3400 glVDPAUUnregisterSurfaceNV = NULL;
3401 glVDPAUSurfaceAccessNV = NULL;
3402 glVDPAUMapSurfacesNV = NULL;
3403 glVDPAUUnmapSurfacesNV = NULL;
3404 glVDPAUGetSurfaceivNV = NULL;
3407 #ifdef GL_NV_vdpau_interop
3409 glVDPAUInitNV = (PFNGLVDPAUINITNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUInitNV");
3411 glVDPAUFiniNV = (PFNGLVDPAUFININVPROC)glXGetProcAddress((GLubyte *) "glVDPAUFiniNV");
3412 if (!glVDPAURegisterOutputSurfaceNV)
3413 glVDPAURegisterOutputSurfaceNV = (PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterOutputSurfaceNV");
3414 if (!glVDPAURegisterVideoSurfaceNV)
3415 glVDPAURegisterVideoSurfaceNV = (PFNGLVDPAUREGISTERVIDEOSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterVideoSurfaceNV");
3416 if (!glVDPAUIsSurfaceNV)
3417 glVDPAUIsSurfaceNV = (PFNGLVDPAUISSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUIsSurfaceNV");
3418 if (!glVDPAUUnregisterSurfaceNV)
3419 glVDPAUUnregisterSurfaceNV = (PFNGLVDPAUUNREGISTERSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnregisterSurfaceNV");
3420 if (!glVDPAUSurfaceAccessNV)
3421 glVDPAUSurfaceAccessNV = (PFNGLVDPAUSURFACEACCESSNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUSurfaceAccessNV");
3422 if (!glVDPAUMapSurfacesNV)
3423 glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUMapSurfacesNV");
3424 if (!glVDPAUUnmapSurfacesNV)
3425 glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnmapSurfacesNV");
3426 if (!glVDPAUGetSurfaceivNV)
3427 glVDPAUGetSurfaceivNV = (PFNGLVDPAUGETSURFACEIVNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUGetSurfaceivNV");
3429 while (glGetError() != GL_NO_ERROR);
3430 glVDPAUInitNV(reinterpret_cast<void*>(m_config.context->GetDevice()), reinterpret_cast<void*>(m_config.context->GetProcs().vdp_get_proc_address));
3431 if (glGetError() != GL_NO_ERROR)
3433 CLog::Log(LOGERROR, "VDPAU::COutput - GLInitInterop glVDPAUInitNV failed");
3437 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop initialized");
3441 bool hasfence = glewIsSupported("GL_ARB_sync");
3442 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3444 m_bufferPool.allRenderPics[i]->usefence = hasfence;
3451 void COutput::GLMapSurface(bool yuv, uint32_t source)
3453 #ifdef GL_NV_vdpau_interop
3457 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3458 it = m_bufferPool.glVideoSurfaceMap.find(source);
3459 if (it == m_bufferPool.glVideoSurfaceMap.end())
3461 VdpauBufferPool::GLVideoSurface glSurface;
3462 VdpVideoSurface surf = source;
3464 if (surf == VDP_INVALID_HANDLE)
3467 glSurface.sourceVuv = surf;
3468 while (glGetError() != GL_NO_ERROR) ;
3469 glGenTextures(4, glSurface.texture);
3470 if (glGetError() != GL_NO_ERROR)
3472 CLog::Log(LOGERROR, "VDPAU::COutput error creating texture");
3475 glSurface.glVdpauSurface = glVDPAURegisterVideoSurfaceNV(reinterpret_cast<void*>(surf),
3476 GL_TEXTURE_2D, 4, glSurface.texture);
3478 if (glGetError() != GL_NO_ERROR)
3480 CLog::Log(LOGERROR, "VDPAU::COutput error register video surface");
3483 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3484 if (glGetError() != GL_NO_ERROR)
3486 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3489 m_bufferPool.glVideoSurfaceMap[surf] = glSurface;
3491 CLog::Log(LOGNOTICE, "VDPAU::COutput registered surface");
3494 while (glGetError() != GL_NO_ERROR) ;
3495 glVDPAUMapSurfacesNV(1, &m_bufferPool.glVideoSurfaceMap[source].glVdpauSurface);
3496 if (glGetError() != GL_NO_ERROR)
3498 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3507 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3508 it = m_bufferPool.glOutputSurfaceMap.find(source);
3509 if (it == m_bufferPool.glOutputSurfaceMap.end())
3511 unsigned int idx = 0;
3512 for (idx = 0; idx<m_bufferPool.outputSurfaces.size(); idx++)
3514 if (m_bufferPool.outputSurfaces[idx] == source)
3518 VdpauBufferPool::GLVideoSurface glSurface;
3519 glSurface.sourceRgb = m_bufferPool.outputSurfaces[idx];
3520 glGenTextures(1, glSurface.texture);
3521 glSurface.glVdpauSurface = glVDPAURegisterOutputSurfaceNV(reinterpret_cast<void*>(m_bufferPool.outputSurfaces[idx]),
3522 GL_TEXTURE_2D, 1, glSurface.texture);
3523 if (glGetError() != GL_NO_ERROR)
3525 CLog::Log(LOGERROR, "VDPAU::COutput error register output surface");
3528 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3529 if (glGetError() != GL_NO_ERROR)
3531 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3534 m_bufferPool.glOutputSurfaceMap[source] = glSurface;
3535 CLog::Log(LOGNOTICE, "VDPAU::COutput registered output surfaces");
3538 while (glGetError() != GL_NO_ERROR) ;
3539 glVDPAUMapSurfacesNV(1, &m_bufferPool.glOutputSurfaceMap[source].glVdpauSurface);
3540 if (glGetError() != GL_NO_ERROR)
3542 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3552 void COutput::GLUnmapSurfaces()
3554 #ifdef GL_NV_vdpau_interop
3557 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3558 for (it = m_bufferPool.glVideoSurfaceMap.begin(); it != m_bufferPool.glVideoSurfaceMap.end(); ++it)
3560 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3561 glDeleteTextures(4, it->second.texture);
3563 m_bufferPool.glVideoSurfaceMap.clear();
3566 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3567 for (it = m_bufferPool.glOutputSurfaceMap.begin(); it != m_bufferPool.glOutputSurfaceMap.end(); ++it)
3569 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3570 glDeleteTextures(1, it->second.texture);
3572 m_bufferPool.glOutputSurfaceMap.clear();
3576 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop finished");
3581 bool COutput::CheckStatus(VdpStatus vdp_st, int line)
3583 if (vdp_st != VDP_STATUS_OK)
3585 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);
3592 bool COutput::CreateGlxContext()
3594 GLXContext glContext;
3596 m_Display = g_Windowing.GetDisplay();
3597 glContext = g_Windowing.GetGlxContext();
3598 m_Window = g_Windowing.GetWindow();
3600 // Get our window attribs.
3601 XWindowAttributes wndattribs;
3602 XGetWindowAttributes(m_Display, m_Window, &wndattribs);
3605 XVisualInfo visInfo;
3606 visInfo.visualid = wndattribs.visual->visualid;
3608 XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals);
3611 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - could not find visual");
3614 visInfo = visuals[0];
3617 m_pixmap = XCreatePixmap(m_Display,
3624 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - Unable to create XPixmap");
3629 m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap);
3633 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not create glPixmap");
3637 m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True);
3639 if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext))
3641 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not make Pixmap current");
3645 CLog::Log(LOGNOTICE, "VDPAU::COutput::CreateGlxContext - created context");
3649 bool COutput::DestroyGlxContext()
3653 glXMakeCurrent(m_Display, None, NULL);
3654 glXDestroyContext(m_Display, m_glContext);
3659 glXDestroyPixmap(m_Display, m_glPixmap);
3663 XFreePixmap(m_Display, m_pixmap);