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())
142 m_context->m_refCount++;
148 VDPAU_procs& CVDPAUContext::GetProcs()
153 VdpVideoMixerFeature* CVDPAUContext::GetFeatures()
155 return m_vdpFeatures;
158 int CVDPAUContext::GetFeatureCount()
160 return m_featureCount;
163 bool CVDPAUContext::LoadSymbols()
167 m_dlHandle = dlopen("libvdpau.so.1", RTLD_LAZY);
170 const char* error = dlerror();
172 error = "dlerror() returned NULL";
174 CLog::Log(LOGERROR,"VDPAU::LoadSymbols: Unable to get handle to lib: %s", error);
181 dl_vdp_device_create_x11 = (VdpStatus (*)(Display*, int, VdpDevice*, VdpStatus (**)(VdpDevice, VdpFuncId, void**)))dlsym(m_dlHandle, (const char*)"vdp_device_create_x11");
185 CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__);
186 m_vdpDevice = VDP_INVALID_HANDLE;
192 bool CVDPAUContext::CreateContext()
194 CLog::Log(LOGNOTICE,"VDPAU::CreateContext - creating decoder context");
197 { CSingleLock lock(g_graphicsContext);
199 m_display = XOpenDisplay(NULL);
200 mScreen = g_Windowing.GetCurrentScreen();
205 vdp_st = dl_vdp_device_create_x11(m_display,
208 &m_vdpProcs.vdp_get_proc_address);
210 CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",m_vdpDevice,vdp_st);
211 if (vdp_st != VDP_STATUS_OK)
213 CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x. Falling back.",vdp_st);
214 m_vdpDevice = VDP_INVALID_HANDLE;
219 SpewHardwareAvailable();
223 void CVDPAUContext::QueryProcs()
227 #define VDP_PROC(id, proc) \
229 vdp_st = m_vdpProcs.vdp_get_proc_address(m_vdpDevice, id, (void**)&proc); \
230 if (vdp_st != VDP_STATUS_OK) \
232 CLog::Log(LOGERROR, "CVDPAUContext::GetProcs - failed to get proc id"); \
236 VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING , m_vdpProcs.vdp_get_error_string);
237 VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY , m_vdpProcs.vdp_device_destroy);
238 VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX , m_vdpProcs.vdp_generate_csc_matrix);
239 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE , m_vdpProcs.vdp_video_surface_create);
240 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , m_vdpProcs.vdp_video_surface_destroy);
241 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , m_vdpProcs.vdp_video_surface_put_bits_y_cb_cr);
242 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , m_vdpProcs.vdp_video_surface_get_bits_y_cb_cr);
243 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , m_vdpProcs.vdp_output_surface_put_bits_y_cb_cr);
244 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , m_vdpProcs.vdp_output_surface_put_bits_native);
245 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , m_vdpProcs.vdp_output_surface_create);
246 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , m_vdpProcs.vdp_output_surface_destroy);
247 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , m_vdpProcs.vdp_output_surface_get_bits_native);
248 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, m_vdpProcs.vdp_output_surface_render_output_surface);
249 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , m_vdpProcs.vdp_output_surface_put_bits_indexed);
250 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE , m_vdpProcs.vdp_video_mixer_create);
251 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , m_vdpProcs.vdp_video_mixer_set_feature_enables);
252 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY , m_vdpProcs.vdp_video_mixer_destroy);
253 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER , m_vdpProcs.vdp_video_mixer_render);
254 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , m_vdpProcs.vdp_video_mixer_set_attribute_values);
255 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , m_vdpProcs.vdp_video_mixer_query_parameter_support);
256 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , m_vdpProcs.vdp_video_mixer_query_feature_support);
257 VDP_PROC(VDP_FUNC_ID_DECODER_CREATE , m_vdpProcs.vdp_decoder_create);
258 VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY , m_vdpProcs.vdp_decoder_destroy);
259 VDP_PROC(VDP_FUNC_ID_DECODER_RENDER , m_vdpProcs.vdp_decoder_render);
260 VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , m_vdpProcs.vdp_decoder_query_caps);
264 VdpDevice CVDPAUContext::GetDevice()
269 void CVDPAUContext::DestroyContext()
271 if (!m_vdpProcs.vdp_device_destroy)
274 m_vdpProcs.vdp_device_destroy(m_vdpDevice);
275 m_vdpDevice = VDP_INVALID_HANDLE;
278 void CVDPAUContext::SpewHardwareAvailable() //CopyrighVDPAUt (c) 2008 Wladimir J. van der Laan -- VDPInfo
281 CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:");
282 CLog::Log(LOGNOTICE,"name level macbs width height");
283 CLog::Log(LOGNOTICE,"------------------------------------");
284 for(unsigned int x=0; x<decoder_profile_count; ++x)
286 VdpBool is_supported = false;
287 uint32_t max_level, max_macroblocks, max_width, max_height;
288 rv = m_vdpProcs.vdp_decoder_query_caps(m_vdpDevice, decoder_profiles[x].id,
289 &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
290 if(rv == VDP_STATUS_OK && is_supported)
292 CLog::Log(LOGNOTICE,"%-16s %2i %5i %5i %5i\n", decoder_profiles[x].name,
293 max_level, max_macroblocks, max_width, max_height);
296 CLog::Log(LOGNOTICE,"------------------------------------");
298 #define CHECK_SUPPORT(feature) \
301 if(m_vdpProcs.vdp_video_mixer_query_feature_support(m_vdpDevice, feature, &supported) == VDP_STATUS_OK && supported) { \
302 CLog::Log(LOGNOTICE, "Mixer feature: "#feature); \
303 m_vdpFeatures[m_featureCount++] = feature; \
307 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION);
308 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_SHARPNESS);
309 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL);
310 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL);
311 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE);
312 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
313 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1);
314 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2);
315 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3);
316 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4);
317 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5);
318 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6);
319 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7);
320 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8);
321 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9);
326 bool CVDPAUContext::Supports(VdpVideoMixerFeature feature)
328 for(int i = 0; i < m_featureCount; i++)
330 if(m_vdpFeatures[i] == feature)
336 //-----------------------------------------------------------------------------
337 // VDPAU Video Surface states
338 //-----------------------------------------------------------------------------
340 #define SURFACE_USED_FOR_REFERENCE 0x01
341 #define SURFACE_USED_FOR_RENDER 0x02
343 void CVideoSurfaces::AddSurface(VdpVideoSurface surf)
345 CSingleLock lock(m_section);
346 m_state[surf] = SURFACE_USED_FOR_REFERENCE;
349 void CVideoSurfaces::ClearReference(VdpVideoSurface surf)
351 CSingleLock lock(m_section);
352 if (m_state.find(surf) == m_state.end())
354 CLog::Log(LOGWARNING, "CVideoSurfaces::ClearReference - surface invalid");
357 m_state[surf] &= ~SURFACE_USED_FOR_REFERENCE;
358 if (m_state[surf] == 0)
360 m_freeSurfaces.push_back(surf);
364 bool CVideoSurfaces::MarkRender(VdpVideoSurface surf)
366 CSingleLock lock(m_section);
367 if (m_state.find(surf) == m_state.end())
369 CLog::Log(LOGWARNING, "CVideoSurfaces::MarkRender - surface invalid");
372 std::list<VdpVideoSurface>::iterator it;
373 it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
374 if (it != m_freeSurfaces.end())
376 m_freeSurfaces.erase(it);
378 m_state[surf] |= SURFACE_USED_FOR_RENDER;
382 void CVideoSurfaces::ClearRender(VdpVideoSurface surf)
384 CSingleLock lock(m_section);
385 if (m_state.find(surf) == m_state.end())
387 CLog::Log(LOGWARNING, "CVideoSurfaces::ClearRender - surface invalid");
390 m_state[surf] &= ~SURFACE_USED_FOR_RENDER;
391 if (m_state[surf] == 0)
393 m_freeSurfaces.push_back(surf);
397 bool CVideoSurfaces::IsValid(VdpVideoSurface surf)
399 CSingleLock lock(m_section);
400 if (m_state.find(surf) != m_state.end())
406 VdpVideoSurface CVideoSurfaces::GetFree(VdpVideoSurface surf)
408 CSingleLock lock(m_section);
409 if (m_state.find(surf) != m_state.end())
411 std::list<VdpVideoSurface>::iterator it;
412 it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
413 if (it == m_freeSurfaces.end())
415 CLog::Log(LOGWARNING, "CVideoSurfaces::GetFree - surface not free");
419 m_freeSurfaces.erase(it);
420 m_state[surf] = SURFACE_USED_FOR_REFERENCE;
425 if (!m_freeSurfaces.empty())
427 VdpVideoSurface freeSurf = m_freeSurfaces.front();
428 m_freeSurfaces.pop_front();
429 m_state[freeSurf] = SURFACE_USED_FOR_REFERENCE;
433 return VDP_INVALID_HANDLE;
436 VdpVideoSurface CVideoSurfaces::GetAtIndex(int idx)
438 if (idx >= m_state.size())
439 return VDP_INVALID_HANDLE;
441 std::map<VdpVideoSurface, int>::iterator it = m_state.begin();
442 for(int i = 0; i < idx; i++)
447 VdpVideoSurface CVideoSurfaces::RemoveNext(bool skiprender)
449 CSingleLock lock(m_section);
450 VdpVideoSurface surf;
451 std::map<VdpVideoSurface, int>::iterator it;
452 for(it = m_state.begin(); it != m_state.end(); ++it)
454 if (skiprender && it->second & SURFACE_USED_FOR_RENDER)
459 std::list<VdpVideoSurface>::iterator it2;
460 it2 = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
461 if (it2 != m_freeSurfaces.end())
462 m_freeSurfaces.erase(it2);
465 return VDP_INVALID_HANDLE;
468 void CVideoSurfaces::Reset()
470 CSingleLock lock(m_section);
471 m_freeSurfaces.clear();
475 int CVideoSurfaces::Size()
477 CSingleLock lock(m_section);
478 return m_state.size();
481 //-----------------------------------------------------------------------------
483 //-----------------------------------------------------------------------------
485 CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent)
487 m_vdpauConfig.videoSurfaces = &m_videoSurfaces;
489 m_vdpauConfigured = false;
490 m_hwContext.bitstream_buffers_allocated = 0;
491 m_DisplayState = VDPAU_OPEN;
492 m_vdpauConfig.context = 0;
495 bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned int surfaces)
497 // check if user wants to decode this format with VDPAU
498 std::string gpuvendor = g_Windowing.GetRenderVendor();
499 std::transform(gpuvendor.begin(), gpuvendor.end(), gpuvendor.begin(), ::tolower);
500 // nvidia is whitelisted despite for mpeg-4 we need to query user settings
501 if ((gpuvendor.compare(0, 6, "nvidia") != 0) || (avctx->codec_id == AV_CODEC_ID_MPEG4) || (avctx->codec_id == AV_CODEC_ID_H263))
503 if (CDVDVideoCodec::IsCodecDisabled(g_vdpau_available, settings_count, avctx->codec_id))
507 #ifndef GL_NV_vdpau_interop
508 CLog::Log(LOGNOTICE, "VDPAU: compilation without required extension GL_NV_vdpau_interop");
511 if (!g_Windowing.IsExtSupported("GL_NV_vdpau_interop"))
513 CLog::Log(LOGNOTICE, "VDPAU::Open: required extension GL_NV_vdpau_interop not found");
517 if(avctx->coded_width == 0
518 || avctx->coded_height == 0)
520 CLog::Log(LOGWARNING,"VDPAU::Open: no width/height available, can't init");
523 m_vdpauConfig.numRenderBuffers = surfaces;
524 m_decoderThread = CThread::GetCurrentThreadId();
526 if (!CVDPAUContext::EnsureContext(&m_vdpauConfig.context))
529 m_DisplayState = VDPAU_OPEN;
530 m_vdpauConfigured = false;
532 if (!m_dllAvUtil.Load())
535 m_presentPicture = 0;
538 VdpDecoderProfile profile = 0;
540 // convert FFMPEG codec ID to VDPAU profile.
541 ReadFormatOf(avctx->codec_id, profile, m_vdpauConfig.vdpChromaType);
545 VdpBool is_supported = false;
546 uint32_t max_level, max_macroblocks, max_width, max_height;
548 // query device capabilities to ensure that VDPAU can handle the requested codec
549 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_query_caps(m_vdpauConfig.context->GetDevice(),
550 profile, &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
552 // test to make sure there is a possibility the codec will work
553 if (CheckStatus(vdp_st, __LINE__))
555 CLog::Log(LOGERROR, "VDPAU::Open: error %s(%d) checking for decoder support", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st);
559 if (max_width < avctx->coded_width || max_height < avctx->coded_height)
561 CLog::Log(LOGWARNING,"VDPAU::Open: requested picture dimensions (%i, %i) exceed hardware capabilities ( %i, %i).",
562 avctx->coded_width, avctx->coded_height, max_width, max_height);
566 if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width))
567 CLog::Log(LOGWARNING,"VDPAU::Open width %i might not be supported because of hardware bug", avctx->width);
569 // attempt to create a decoder with this width/height, some sizes are not supported by hw
570 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_create(m_vdpauConfig.context->GetDevice(), profile, avctx->coded_width, avctx->coded_height, 5, &m_vdpauConfig.vdpDecoder);
572 if (CheckStatus(vdp_st, __LINE__))
574 CLog::Log(LOGERROR, "VDPAU::Open: error: %s(%d) checking for decoder support", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st);
578 m_vdpauConfig.context->GetProcs().vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
579 CheckStatus(vdp_st, __LINE__);
581 // finally setup ffmpeg
582 memset(&m_hwContext, 0, sizeof(AVVDPAUContext));
583 m_hwContext.render = CDecoder::Render;
584 m_hwContext.bitstream_buffers_allocated = 0;
585 avctx->get_buffer = CDecoder::FFGetBuffer;
586 avctx->reget_buffer = CDecoder::FFGetBuffer;
587 avctx->release_buffer = CDecoder::FFReleaseBuffer;
588 avctx->draw_horiz_band = CDecoder::FFDrawSlice;
589 avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
590 avctx->hwaccel_context = &m_hwContext;
591 avctx->thread_count = 1;
593 g_Windowing.Register(this);
600 CDecoder::~CDecoder()
605 void CDecoder::Close()
607 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
609 g_Windowing.Unregister(this);
611 CSingleLock lock(m_DecoderSection);
614 m_vdpauOutput.Dispose();
616 if (m_hwContext.bitstream_buffers_allocated)
618 m_dllAvUtil.av_freep(&m_hwContext.bitstream_buffers);
621 m_dllAvUtil.Unload();
623 if (m_vdpauConfig.context)
624 m_vdpauConfig.context->Release();
625 m_vdpauConfig.context = 0;
628 long CDecoder::Release()
630 // check if we should do some pre-cleanup here
631 // a second decoder might need resources
632 if (m_vdpauConfigured == true)
634 CSingleLock lock(m_DecoderSection);
635 CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup");
638 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP,
642 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
646 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup returned error", __FUNCTION__);
647 m_DisplayState = VDPAU_ERROR;
652 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup timed out", __FUNCTION__);
653 m_DisplayState = VDPAU_ERROR;
656 VdpVideoSurface surf;
657 while((surf = m_videoSurfaces.RemoveNext(true)) != VDP_INVALID_HANDLE)
659 m_vdpauConfig.context->GetProcs().vdp_video_surface_destroy(surf);
662 return IHardwareDecoder::Release();
665 long CDecoder::ReleasePicReference()
667 return IHardwareDecoder::Release();
670 void CDecoder::SetWidthHeight(int width, int height)
672 m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling;
674 //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate
675 //this requires the least amount of gpu memory bandwidth
676 if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || m_vdpauConfig.upscale >= 0)
678 //scale width to desktop size if the aspect ratio is the same or bigger than the desktop
679 if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight())
681 m_vdpauConfig.outWidth = g_graphicsContext.GetWidth();
682 m_vdpauConfig.outHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width);
684 else //scale height to the desktop size if the aspect ratio is smaller than the desktop
686 m_vdpauConfig.outHeight = g_graphicsContext.GetHeight();
687 m_vdpauConfig.outWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height);
692 m_vdpauConfig.outWidth = width;
693 m_vdpauConfig.outHeight = height;
695 CLog::Log(LOGDEBUG, "CVDPAU::SetWidthHeight Setting OutWidth: %i OutHeight: %i", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight);
698 void CDecoder::OnLostDevice()
700 CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event");
702 int count = g_graphicsContext.exit();
704 CSingleLock lock(m_DecoderSection);
706 if (m_vdpauConfig.context)
707 m_vdpauConfig.context->Release();
708 m_vdpauConfig.context = 0;
710 m_DisplayState = VDPAU_LOST;
712 m_DisplayEvent.Reset();
714 g_graphicsContext.restore(count);
717 void CDecoder::OnResetDevice()
719 CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event");
721 int count = g_graphicsContext.exit();
723 CSingleLock lock(m_DecoderSection);
724 if (m_DisplayState == VDPAU_LOST)
726 m_DisplayState = VDPAU_RESET;
728 m_DisplayEvent.Set();
731 g_graphicsContext.restore(count);
734 int CDecoder::Check(AVCodecContext* avctx)
738 { CSingleLock lock(m_DecoderSection);
739 state = m_DisplayState;
742 if (state == VDPAU_LOST)
744 CLog::Log(LOGNOTICE,"CVDPAU::Check waiting for display reset event");
745 if (!m_DisplayEvent.WaitMSec(4000))
747 CLog::Log(LOGERROR, "CVDPAU::Check - device didn't reset in reasonable time");
752 CSingleLock lock(m_DecoderSection);
753 state = m_DisplayState;
756 if (state == VDPAU_RESET || state == VDPAU_ERROR)
758 CSingleLock lock(m_DecoderSection);
761 if (m_vdpauConfig.context)
762 m_vdpauConfig.context->Release();
763 m_vdpauConfig.context = 0;
765 if (CVDPAUContext::EnsureContext(&m_vdpauConfig.context))
767 m_DisplayState = VDPAU_OPEN;
768 m_vdpauConfigured = false;
771 if (state == VDPAU_RESET)
779 bool CDecoder::IsVDPAUFormat(PixelFormat format)
781 if (format == AV_PIX_FMT_VDPAU)
787 bool CDecoder::Supports(VdpVideoMixerFeature feature)
789 return m_vdpauConfig.context->Supports(feature);
792 bool CDecoder::Supports(EINTERLACEMETHOD method)
794 if(method == VS_INTERLACEMETHOD_VDPAU_BOB
795 || method == VS_INTERLACEMETHOD_AUTO)
798 if (method == VS_INTERLACEMETHOD_RENDER_BOB)
801 if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE)
804 for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++)
806 if(p->method == method)
807 return Supports(p->feature);
812 EINTERLACEMETHOD CDecoder::AutoInterlaceMethod()
814 return VS_INTERLACEMETHOD_RENDER_BOB;
817 void CDecoder::FiniVDPAUOutput()
819 if (!m_vdpauConfigured)
822 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
825 m_vdpauOutput.Dispose();
826 m_vdpauConfigured = false;
830 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
831 if (CheckStatus(vdp_st, __LINE__))
833 m_vdpauConfig.vdpDecoder = VDP_INVALID_HANDLE;
835 CLog::Log(LOGDEBUG, "CVDPAU::FiniVDPAUOutput destroying %d video surfaces", m_videoSurfaces.Size());
837 VdpVideoSurface surf;
838 while((surf = m_videoSurfaces.RemoveNext()) != VDP_INVALID_HANDLE)
840 m_vdpauConfig.context->GetProcs().vdp_video_surface_destroy(surf);
841 if (CheckStatus(vdp_st, __LINE__))
844 m_videoSurfaces.Reset();
847 void CDecoder::ReadFormatOf( AVCodecID codec
848 , VdpDecoderProfile &vdp_decoder_profile
849 , VdpChromaType &vdp_chroma_type)
853 case AV_CODEC_ID_MPEG1VIDEO:
854 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
855 vdp_chroma_type = VDP_CHROMA_TYPE_420;
857 case AV_CODEC_ID_MPEG2VIDEO:
858 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
859 vdp_chroma_type = VDP_CHROMA_TYPE_420;
861 case AV_CODEC_ID_H264:
862 vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
863 vdp_chroma_type = VDP_CHROMA_TYPE_420;
865 case AV_CODEC_ID_WMV3:
866 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
867 vdp_chroma_type = VDP_CHROMA_TYPE_420;
869 case AV_CODEC_ID_VC1:
870 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
871 vdp_chroma_type = VDP_CHROMA_TYPE_420;
873 case AV_CODEC_ID_MPEG4:
874 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
875 vdp_chroma_type = VDP_CHROMA_TYPE_420;
878 vdp_decoder_profile = 0;
884 bool CDecoder::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
889 VdpDecoderProfile vdp_decoder_profile;
891 m_vdpauConfig.vidWidth = avctx->width;
892 m_vdpauConfig.vidHeight = avctx->height;
893 m_vdpauConfig.surfaceWidth = avctx->coded_width;
894 m_vdpauConfig.surfaceHeight = avctx->coded_height;
896 SetWidthHeight(avctx->width,avctx->height);
898 CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",m_vdpauConfig.outWidth,m_vdpauConfig.vidWidth,m_vdpauConfig.surfaceWidth);
899 CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",m_vdpauConfig.outHeight,m_vdpauConfig.vidHeight,m_vdpauConfig.surfaceHeight);
901 ReadFormatOf(avctx->codec_id, vdp_decoder_profile, m_vdpauConfig.vdpChromaType);
903 if(avctx->codec_id == AV_CODEC_ID_H264)
905 m_vdpauConfig.maxReferences = ref_frames;
906 if (m_vdpauConfig.maxReferences > 16) m_vdpauConfig.maxReferences = 16;
907 if (m_vdpauConfig.maxReferences < 5) m_vdpauConfig.maxReferences = 5;
910 m_vdpauConfig.maxReferences = 2;
912 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_create(m_vdpauConfig.context->GetDevice(),
914 m_vdpauConfig.surfaceWidth,
915 m_vdpauConfig.surfaceHeight,
916 m_vdpauConfig.maxReferences,
917 &m_vdpauConfig.vdpDecoder);
918 if (CheckStatus(vdp_st, __LINE__))
922 CSingleLock lock(g_graphicsContext);
923 m_vdpauConfig.stats = &m_bufferStats;
924 m_vdpauConfig.vdpau = this;
925 m_bufferStats.Reset();
926 m_vdpauOutput.Start();
928 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT,
932 sizeof(m_vdpauConfig)))
934 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
938 CLog::Log(LOGERROR, "VDPAU::%s - vdpau output returned error", __FUNCTION__);
939 m_vdpauOutput.Dispose();
945 CLog::Log(LOGERROR, "VDPAU::%s - failed to init output", __FUNCTION__);
946 m_vdpauOutput.Dispose();
950 m_inMsgEvent.Reset();
951 m_vdpauConfigured = true;
956 int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
958 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
959 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
960 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
962 // while we are waiting to recover we can't do anything
963 CSingleLock lock(vdp->m_DecoderSection);
965 if(vdp->m_DisplayState != VDPAU_OPEN)
967 CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
971 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
972 surf = vdp->m_videoSurfaces.GetFree(surf != 0 ? surf : VDP_INVALID_HANDLE);
974 VdpStatus vdp_st = VDP_STATUS_ERROR;
975 if (surf == VDP_INVALID_HANDLE)
977 // create a new surface
978 VdpDecoderProfile profile;
979 ReadFormatOf(avctx->codec_id, profile, vdp->m_vdpauConfig.vdpChromaType);
981 vdp_st = vdp->m_vdpauConfig.context->GetProcs().vdp_video_surface_create(vdp->m_vdpauConfig.context->GetDevice(),
982 vdp->m_vdpauConfig.vdpChromaType,
986 vdp->CheckStatus(vdp_st, __LINE__);
987 if (vdp_st != VDP_STATUS_OK)
989 CLog::Log(LOGERROR, "CVDPAU::FFGetBuffer - No Video surface available could be created");
992 vdp->m_videoSurfaces.AddSurface(surf);
995 pic->data[1] = pic->data[2] = NULL;
996 pic->data[0] = (uint8_t*)(uintptr_t)surf;
997 pic->data[3] = (uint8_t*)(uintptr_t)surf;
999 pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0;
1001 pic->type= FF_BUFFER_TYPE_USER;
1003 pic->reordered_opaque= avctx->reordered_opaque;
1007 void CDecoder::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
1009 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
1010 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
1012 VdpVideoSurface surf;
1015 CSingleLock lock(vdp->m_DecoderSection);
1017 surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
1019 vdp->m_videoSurfaces.ClearReference(surf);
1025 VdpStatus CDecoder::Render( VdpDecoder decoder, VdpVideoSurface target,
1026 VdpPictureInfo const *picture_info,
1027 uint32_t bitstream_buffer_count,
1028 VdpBitstreamBuffer const * bitstream_buffers)
1030 return VDP_STATUS_OK;
1033 void CDecoder::FFDrawSlice(struct AVCodecContext *s,
1034 const AVFrame *src, int offset[4],
1035 int y, int type, int height)
1037 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque;
1038 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
1040 // while we are waiting to recover we can't do anything
1041 CSingleLock lock(vdp->m_DecoderSection);
1043 if(vdp->m_DisplayState != VDPAU_OPEN)
1046 if(src->linesize[0] || src->linesize[1] || src->linesize[2]
1047 || offset[0] || offset[1] || offset[2])
1049 CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid linesizes or offsets provided");
1054 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)src->data[3];
1056 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1057 if (!vdp->m_videoSurfaces.IsValid(surf))
1059 CLog::Log(LOGWARNING, "CVDPAU::FFDrawSlice - ignoring invalid buffer");
1063 uint32_t max_refs = 0;
1064 if(s->codec_id == AV_CODEC_ID_H264)
1065 max_refs = vdp->m_hwContext.info.h264.num_ref_frames;
1067 if(vdp->m_vdpauConfig.vdpDecoder == VDP_INVALID_HANDLE
1068 || vdp->m_vdpauConfigured == false
1069 || vdp->m_vdpauConfig.maxReferences < max_refs)
1071 if(!vdp->ConfigVDPAU(s, max_refs))
1075 uint64_t startTime = CurrentHostCounter();
1076 uint16_t decoded, processed, rend;
1077 vdp->m_bufferStats.Get(decoded, processed, rend);
1078 vdp_st = vdp->m_vdpauConfig.context->GetProcs().vdp_decoder_render(vdp->m_vdpauConfig.vdpDecoder,
1080 (VdpPictureInfo const *)&(vdp->m_hwContext.info),
1081 vdp->m_hwContext.bitstream_buffers_used,
1082 vdp->m_hwContext.bitstream_buffers);
1083 if (vdp->CheckStatus(vdp_st, __LINE__))
1084 vdp->m_DecoderError = true;
1086 vdp->m_DecoderError = false;
1088 uint64_t diff = CurrentHostCounter() - startTime;
1089 if (diff*1000/CurrentHostFrequency() > 30)
1090 CLog::Log(LOGDEBUG, "CVDPAU::DrawSlice - VdpDecoderRender long decoding: %d ms, dec: %d, proc: %d, rend: %d", (int)((diff*1000)/CurrentHostFrequency()), decoded, processed, rend);
1094 int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame)
1096 int result = Check(avctx);
1100 CSingleLock lock(m_DecoderSection);
1102 if (m_DecoderError && pFrame)
1105 if (!m_vdpauConfigured)
1109 { // we have a new frame from decoder
1111 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pFrame->data[3];
1112 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1113 if (!m_videoSurfaces.IsValid(surf))
1115 CLog::Log(LOGWARNING, "CVDPAU::Decode - ignoring invalid buffer");
1118 m_videoSurfaces.MarkRender(surf);
1120 // send frame to output for processing
1121 CVdpauDecodedPicture pic;
1122 memset(&pic.DVDPic, 0, sizeof(pic.DVDPic));
1123 ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic);
1124 pic.videoSurface = surf;
1125 pic.DVDPic.color_matrix = avctx->colorspace;
1126 m_bufferStats.IncDecoded();
1127 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic));
1130 // m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC);
1134 uint16_t decoded, processed, render;
1136 while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1138 if (msg->signal == COutputControlProtocol::ERROR)
1140 m_DisplayState = VDPAU_ERROR;
1146 m_bufferStats.Get(decoded, processed, render);
1148 uint64_t startTime = CurrentHostCounter();
1151 // first fill the buffers to keep vdpau busy
1152 // mixer will run with decoded >= 2. output is limited by number of output surfaces
1153 // In case mixer is bypassed we limit by looking at processed
1154 if (decoded < 3 && processed < 3)
1156 retval |= VC_BUFFER;
1158 else if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg))
1160 if (msg->signal == COutputDataProtocol::PICTURE)
1162 if (m_presentPicture)
1164 m_presentPicture->ReturnUnused();
1165 m_presentPicture = 0;
1168 m_presentPicture = *(CVdpauRenderPicture**)msg->data;
1169 m_presentPicture->vdpau = this;
1170 m_bufferStats.DecRender();
1171 m_bufferStats.Get(decoded, processed, render);
1172 retval |= VC_PICTURE;
1178 else if (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1180 if (msg->signal == COutputControlProtocol::STATS)
1182 m_bufferStats.Get(decoded, processed, render);
1186 m_DisplayState = VDPAU_ERROR;
1192 if (decoded < 3 && processed < 3)
1194 retval |= VC_BUFFER;
1197 if (!retval && !m_inMsgEvent.WaitMSec(2000))
1200 uint64_t diff = CurrentHostCounter() - startTime;
1201 if (retval & VC_PICTURE)
1203 m_bufferStats.SetParams(diff, m_codecControl);
1205 if (diff*1000/CurrentHostFrequency() > 50)
1206 CLog::Log(LOGDEBUG,"CVDPAU::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency()));
1210 CLog::Log(LOGERROR, "VDPAU::%s - timed out waiting for output message", __FUNCTION__);
1211 m_DisplayState = VDPAU_ERROR;
1218 bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
1220 CSingleLock lock(m_DecoderSection);
1222 if (m_DisplayState != VDPAU_OPEN)
1225 *picture = m_presentPicture->DVDPic;
1226 picture->vdpau = m_presentPicture;
1231 void CDecoder::Reset()
1233 CSingleLock lock(m_DecoderSection);
1235 if (!m_vdpauConfigured)
1239 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH,
1243 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
1247 CLog::Log(LOGERROR, "VDPAU::%s - flush returned error", __FUNCTION__);
1248 m_DisplayState = VDPAU_ERROR;
1251 m_bufferStats.Reset();
1255 CLog::Log(LOGERROR, "VDPAU::%s - flush timed out", __FUNCTION__);
1256 m_DisplayState = VDPAU_ERROR;
1260 bool CDecoder::CanSkipDeint()
1262 return m_bufferStats.CanSkipDeint();
1265 void CDecoder::ReturnRenderPicture(CVdpauRenderPicture *renderPic)
1267 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic));
1270 bool CDecoder::CheckStatus(VdpStatus vdp_st, int line)
1272 if (vdp_st != VDP_STATUS_OK)
1274 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);
1278 if(m_DisplayState == VDPAU_OPEN)
1280 if (vdp_st == VDP_STATUS_DISPLAY_PREEMPTED)
1282 m_DisplayEvent.Reset();
1283 m_DisplayState = VDPAU_LOST;
1285 else if (m_ErrorCount > 2)
1286 m_DisplayState = VDPAU_ERROR;
1295 //-----------------------------------------------------------------------------
1297 //-----------------------------------------------------------------------------
1299 CVdpauRenderPicture* CVdpauRenderPicture::Acquire()
1301 CSingleLock lock(renderPicSection);
1310 long CVdpauRenderPicture::Release()
1312 CSingleLock lock(renderPicSection);
1319 vdpau->ReturnRenderPicture(this);
1320 vdpau->ReleasePicReference();
1325 void CVdpauRenderPicture::ReturnUnused()
1327 { CSingleLock lock(renderPicSection);
1332 vdpau->ReturnRenderPicture(this);
1335 void CVdpauRenderPicture::Sync()
1338 CSingleLock lock(renderPicSection);
1343 glDeleteSync(fence);
1346 fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1351 //-----------------------------------------------------------------------------
1353 //-----------------------------------------------------------------------------
1354 CMixer::CMixer(CEvent *inMsgEvent) :
1355 CThread("Vdpau Mixer"),
1356 m_controlPort("ControlPort", inMsgEvent, &m_outMsgEvent),
1357 m_dataPort("DataPort", inMsgEvent, &m_outMsgEvent)
1359 m_inMsgEvent = inMsgEvent;
1367 void CMixer::Start()
1372 void CMixer::Dispose()
1375 m_outMsgEvent.Set();
1378 m_controlPort.Purge();
1382 bool CMixer::IsActive()
1387 void CMixer::OnStartup()
1389 CLog::Log(LOGNOTICE, "CMixer::OnStartup: Output Thread created");
1392 void CMixer::OnExit()
1394 CLog::Log(LOGNOTICE, "CMixer::OnExit: Output Thread terminated");
1401 M_TOP_UNCONFIGURED, // 2
1402 M_TOP_CONFIGURED, // 3
1403 M_TOP_CONFIGURED_WAIT1, // 4
1404 M_TOP_CONFIGURED_STEP1, // 5
1405 M_TOP_CONFIGURED_WAIT2, // 6
1406 M_TOP_CONFIGURED_STEP2, // 7
1409 int MIXER_parentStates[] = {
1412 0, //TOP_UNCONFIGURED
1414 3, //TOP_CONFIGURED_WAIT1
1415 3, //TOP_CONFIGURED_STEP1
1416 3, //TOP_CONFIGURED_WAIT2
1417 3, //TOP_CONFIGURED_STEP2
1420 void CMixer::StateMachine(int signal, Protocol *port, Message *msg)
1422 for (int state = m_state; ; state = MIXER_parentStates[state])
1427 if (port == &m_controlPort)
1431 case CMixerControlProtocol::FLUSH:
1433 msg->Reply(CMixerControlProtocol::ACC);
1440 std::string portName = port == NULL ? "timer" : port->portName;
1441 CLog::Log(LOGWARNING, "CMixer::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
1445 case M_TOP_ERROR: // TOP
1448 case M_TOP_UNCONFIGURED:
1449 if (port == &m_controlPort)
1453 case CMixerControlProtocol::INIT:
1455 data = (CVdpauConfig*)msg->data;
1463 m_state = M_TOP_CONFIGURED_WAIT1;
1464 msg->Reply(CMixerControlProtocol::ACC);
1468 msg->Reply(CMixerControlProtocol::ERROR);
1477 case M_TOP_CONFIGURED:
1478 if (port == &m_dataPort)
1482 case CMixerDataProtocol::FRAME:
1483 CVdpauDecodedPicture *frame;
1484 frame = (CVdpauDecodedPicture*)msg->data;
1487 m_decodedPics.push(*frame);
1491 case CMixerDataProtocol::BUFFER:
1492 VdpOutputSurface *surf;
1493 surf = (VdpOutputSurface*)msg->data;
1496 m_outputSurfaces.push(*surf);
1506 case M_TOP_CONFIGURED_WAIT1:
1507 if (port == NULL) // timeout
1511 case CMixerControlProtocol::TIMEOUT:
1512 if (!m_decodedPics.empty() && !m_outputSurfaces.empty())
1514 m_state = M_TOP_CONFIGURED_STEP1;
1515 m_bStateMachineSelfTrigger = true;
1528 case M_TOP_CONFIGURED_STEP1:
1529 if (port == NULL) // timeout
1533 case CMixerControlProtocol::TIMEOUT:
1534 m_mixerInput.push_front(m_decodedPics.front());
1535 m_decodedPics.pop();
1536 if (m_mixerInput.size() < 2)
1538 m_state = M_TOP_CONFIGURED_WAIT1;
1546 m_state = M_TOP_CONFIGURED_WAIT1;
1547 m_extTimeout = 1000;
1550 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1551 m_outputSurfaces.pop();
1552 m_config.stats->IncProcessed();
1553 m_config.stats->DecDecoded();
1554 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1555 if (m_mixersteps > 1)
1557 m_state = M_TOP_CONFIGURED_WAIT2;
1563 m_state = M_TOP_CONFIGURED_WAIT1;
1573 case M_TOP_CONFIGURED_WAIT2:
1574 if (port == NULL) // timeout
1578 case CMixerControlProtocol::TIMEOUT:
1579 if (!m_outputSurfaces.empty())
1581 m_state = M_TOP_CONFIGURED_STEP2;
1582 m_bStateMachineSelfTrigger = true;
1595 case M_TOP_CONFIGURED_STEP2:
1596 if (port == NULL) // timeout
1600 case CMixerControlProtocol::TIMEOUT:
1601 m_processPicture.outputSurface = m_outputSurfaces.front();
1606 m_state = M_TOP_CONFIGURED_WAIT1;
1607 m_extTimeout = 1000;
1610 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1611 m_outputSurfaces.pop();
1612 m_config.stats->IncProcessed();
1613 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1615 m_state = M_TOP_CONFIGURED_WAIT1;
1624 default: // we are in no state, should not happen
1625 CLog::Log(LOGERROR, "CMixer::%s - no valid state: %d", __FUNCTION__, m_state);
1631 void CMixer::Process()
1633 Message *msg = NULL;
1634 Protocol *port = NULL;
1637 m_state = M_TOP_UNCONFIGURED;
1638 m_extTimeout = 1000;
1639 m_bStateMachineSelfTrigger = false;
1645 if (m_bStateMachineSelfTrigger)
1647 m_bStateMachineSelfTrigger = false;
1648 // self trigger state machine
1649 StateMachine(msg->signal, port, msg);
1650 if (!m_bStateMachineSelfTrigger)
1657 // check control port
1658 else if (m_controlPort.ReceiveOutMessage(&msg))
1661 port = &m_controlPort;
1664 else if (m_dataPort.ReceiveOutMessage(&msg))
1672 StateMachine(msg->signal, port, msg);
1673 if (!m_bStateMachineSelfTrigger)
1682 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
1689 msg = m_controlPort.GetMessage();
1690 msg->signal = CMixerControlProtocol::TIMEOUT;
1692 // signal timeout to state machine
1693 StateMachine(msg->signal, port, msg);
1694 if (!m_bStateMachineSelfTrigger)
1704 void CMixer::CreateVdpauMixer()
1706 CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer");
1708 InitCSCMatrix(m_config.vidWidth);
1710 VdpVideoMixerParameter parameters[] = {
1711 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
1712 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
1713 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE};
1715 void const * parameter_values[] = {
1716 &m_config.surfaceWidth,
1717 &m_config.surfaceHeight,
1718 &m_config.vdpChromaType};
1720 VdpStatus vdp_st = VDP_STATUS_ERROR;
1721 vdp_st = m_config.context->GetProcs().vdp_video_mixer_create(m_config.context->GetDevice(),
1722 m_config.context->GetFeatureCount(),
1723 m_config.context->GetFeatures(),
1728 CheckStatus(vdp_st, __LINE__);
1732 void CMixer::InitCSCMatrix(int Width)
1734 m_Procamp.struct_version = VDP_PROCAMP_VERSION;
1735 m_Procamp.brightness = 0.0;
1736 m_Procamp.contrast = 1.0;
1737 m_Procamp.saturation = 1.0;
1741 void CMixer::CheckFeatures()
1743 if (m_Upscale != m_config.upscale)
1746 m_Upscale = m_config.upscale;
1748 if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness ||
1749 m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast ||
1750 m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix)
1753 m_Brightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness;
1754 m_Contrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast;
1755 m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix;
1757 if (m_NoiseReduction != CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1759 m_NoiseReduction = CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction;
1760 SetNoiseReduction();
1762 if (m_Sharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1764 m_Sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
1767 if (m_DeintMode != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode ||
1768 m_Deint != CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod)
1770 m_DeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1771 m_Deint = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1776 void CMixer::SetPostProcFeatures(bool postProcEnabled)
1778 if (m_PostProc != postProcEnabled)
1780 if (postProcEnabled)
1782 SetNoiseReduction();
1789 m_PostProc = postProcEnabled;
1793 void CMixer::PostProcOff()
1797 if (m_videoMixer == VDP_INVALID_HANDLE)
1800 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
1801 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
1802 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE};
1804 VdpBool enabled[]={0,0,0};
1805 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1806 CheckStatus(vdp_st, __LINE__);
1808 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1810 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION};
1812 VdpBool enabled[]={0};
1813 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1814 CheckStatus(vdp_st, __LINE__);
1817 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1819 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS};
1821 VdpBool enabled[]={0};
1822 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1823 CheckStatus(vdp_st, __LINE__);
1829 bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix)
1831 // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4])
1832 // m00 = mRY = red: luma factor (contrast factor) (1.0)
1833 // m10 = mGY = green: luma factor (contrast factor) (1.0)
1834 // m20 = mBY = blue: luma factor (contrast factor) (1.0)
1836 // m01 = mRB = red: blue color diff coeff (0.0)
1837 // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg))
1838 // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5)
1840 // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5)
1841 // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg))
1842 // m22 = mBR = blue: red color diff coeff (0.0)
1844 // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255))
1845 // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg)
1846 // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255))
1857 // colour standard coefficients for red, geen, blue
1859 // colour diff zero position (use standard 8-bit coding precision)
1860 double CDZ = 128; //256*0.5
1861 // range excursion (use standard 8-bit coding precision)
1862 double EXC = 255; //256-1
1864 if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601)
1866 Kr = studioCSCKCoeffs601[0];
1867 Kg = studioCSCKCoeffs601[1];
1868 Kb = studioCSCKCoeffs601[2];
1870 else // assume VDP_COLOR_STANDARD_ITUR_BT_709
1872 Kr = studioCSCKCoeffs709[0];
1873 Kg = studioCSCKCoeffs709[1];
1874 Kb = studioCSCKCoeffs709[2];
1876 // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235
1877 studioCSCMatrix[R][Y] = 1.0;
1878 studioCSCMatrix[G][Y] = 1.0;
1879 studioCSCMatrix[B][Y] = 1.0;
1881 studioCSCMatrix[R][Cb] = 0.0;
1882 studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg;
1883 studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5;
1885 studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5;
1886 studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg;
1887 studioCSCMatrix[B][Cr] = 0.0;
1889 studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC;
1890 studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC;
1891 studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC;
1896 void CMixer::SetColor()
1900 if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)
1901 m_Procamp.brightness = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)-50) / 100;
1902 if (m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)
1903 m_Procamp.contrast = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)+50) / 100;
1905 VdpColorStandard colorStandard;
1906 switch(m_mixerInput[1].DVDPic.color_matrix)
1908 case AVCOL_SPC_BT709:
1909 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1911 case AVCOL_SPC_BT470BG:
1912 case AVCOL_SPC_SMPTE170M:
1913 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1915 case AVCOL_SPC_SMPTE240M:
1916 colorStandard = VDP_COLOR_STANDARD_SMPTE_240M;
1919 case AVCOL_SPC_UNSPECIFIED:
1922 if(m_config.surfaceWidth > 1000)
1923 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1925 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1928 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
1929 if (CSettings::Get().GetBool("videoscreen.limitedrange"))
1931 float studioCSC[3][4];
1932 GenerateStudioCSCMatrix(colorStandard, studioCSC);
1933 void const * pm_CSCMatix[] = { &studioCSC };
1934 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1938 vdp_st = m_config.context->GetProcs().vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix);
1939 void const * pm_CSCMatix[] = { &m_CSCMatrix };
1940 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1943 CheckStatus(vdp_st, __LINE__);
1946 void CMixer::SetNoiseReduction()
1948 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1951 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION };
1952 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL };
1955 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1957 VdpBool enabled[]= {0};
1958 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1959 CheckStatus(vdp_st, __LINE__);
1962 VdpBool enabled[]={1};
1963 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1964 CheckStatus(vdp_st, __LINE__);
1965 void* nr[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction };
1966 CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction);
1967 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, nr);
1968 CheckStatus(vdp_st, __LINE__);
1971 void CMixer::SetSharpness()
1973 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1976 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS };
1977 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL };
1980 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1982 VdpBool enabled[]={0};
1983 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1984 CheckStatus(vdp_st, __LINE__);
1987 VdpBool enabled[]={1};
1988 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1989 CheckStatus(vdp_st, __LINE__);
1990 void* sh[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness };
1991 CLog::Log(LOGNOTICE,"Setting Sharpness to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness);
1992 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, sh);
1993 CheckStatus(vdp_st, __LINE__);
1996 EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */)
1998 EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1999 if (method == VS_INTERLACEMETHOD_AUTO)
2002 // if (m_config.outHeight >= 720)
2003 // deint = g_advancedSettings.m_videoVDPAUdeintHD;
2005 // deint = g_advancedSettings.m_videoVDPAUdeintSD;
2009 if (m_config.vdpau->Supports(EINTERLACEMETHOD(deint)))
2011 method = EINTERLACEMETHOD(deint);
2013 CLog::Log(LOGNOTICE, "CVDPAU::GetDeinterlacingMethod: set de-interlacing to %d", deint);
2018 CLog::Log(LOGWARNING, "CVDPAU::GetDeinterlacingMethod: method for de-interlacing (advanced settings) not supported");
2025 void CMixer::SetDeinterlacing()
2029 if (m_videoMixer == VDP_INVALID_HANDLE)
2032 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
2033 EINTERLACEMETHOD method = GetDeinterlacingMethod(true);
2035 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
2036 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
2037 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE };
2039 if (mode == VS_DEINTERLACEMODE_OFF)
2041 VdpBool enabled[] = {0,0,0};
2042 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2046 if (method == VS_INTERLACEMETHOD_AUTO)
2048 VdpBool enabled[] = {1,0,0};
2049 if (g_advancedSettings.m_videoVDPAUtelecine)
2051 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2053 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2054 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF)
2056 VdpBool enabled[] = {1,0,0};
2057 if (g_advancedSettings.m_videoVDPAUtelecine)
2059 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2061 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2062 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF)
2064 VdpBool enabled[] = {1,1,0};
2065 if (g_advancedSettings.m_videoVDPAUtelecine)
2067 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2071 VdpBool enabled[]={0,0,0};
2072 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2075 CheckStatus(vdp_st, __LINE__);
2077 SetDeintSkipChroma();
2079 m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
2082 void CMixer::SetDeintSkipChroma()
2084 VdpVideoMixerAttribute attribute[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE};
2088 if (g_advancedSettings.m_videoVDPAUdeintSkipChromaHD && m_config.outHeight >= 720)
2093 void const *values[]={&val};
2094 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attribute), attribute, values);
2096 CheckStatus(vdp_st, __LINE__);
2099 void CMixer::SetHWUpscaling()
2101 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
2104 VdpBool enabled[]={1};
2105 switch (m_config.upscale)
2108 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
2110 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
2111 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2115 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
2117 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
2118 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2122 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2124 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2125 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2129 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2131 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2132 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2136 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2138 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2139 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2143 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2145 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2146 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2150 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2152 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2153 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2157 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2159 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2160 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2164 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2166 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2167 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2174 CheckStatus(vdp_st, __LINE__);
2178 void CMixer::DisableHQScaling()
2182 if (m_videoMixer == VDP_INVALID_HANDLE)
2185 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2187 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2188 VdpBool enabled[]={0};
2189 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2190 CheckStatus(vdp_st, __LINE__);
2193 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2195 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2196 VdpBool enabled[]={0};
2197 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2198 CheckStatus(vdp_st, __LINE__);
2201 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2203 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2204 VdpBool enabled[]={0};
2205 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2206 CheckStatus(vdp_st, __LINE__);
2209 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2211 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2212 VdpBool enabled[]={0};
2213 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2214 CheckStatus(vdp_st, __LINE__);
2217 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2219 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2220 VdpBool enabled[]={0};
2221 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2222 CheckStatus(vdp_st, __LINE__);
2225 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2227 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2228 VdpBool enabled[]={0};
2229 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2230 CheckStatus(vdp_st, __LINE__);
2233 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2235 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2236 VdpBool enabled[]={0};
2237 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2238 CheckStatus(vdp_st, __LINE__);
2241 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
2243 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
2244 VdpBool enabled[]={0};
2245 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2246 CheckStatus(vdp_st, __LINE__);
2249 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
2251 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
2252 VdpBool enabled[]={0};
2253 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2254 CheckStatus(vdp_st, __LINE__);
2262 m_NoiseReduction = 0.0;
2267 m_SeenInterlaceFlag = false;
2272 m_config.upscale = g_advancedSettings.m_videoVDPAUScaling;
2273 m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
2278 void CMixer::Uninit()
2281 while (!m_outputSurfaces.empty())
2283 m_outputSurfaces.pop();
2285 m_config.context->GetProcs().vdp_video_mixer_destroy(m_videoMixer);
2288 void CMixer::Flush()
2290 while (!m_mixerInput.empty())
2292 CVdpauDecodedPicture pic = m_mixerInput.back();
2293 m_mixerInput.pop_back();
2294 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2296 while (!m_decodedPics.empty())
2298 CVdpauDecodedPicture pic = m_decodedPics.front();
2299 m_decodedPics.pop();
2300 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2303 while (m_dataPort.ReceiveOutMessage(&msg))
2305 if (msg->signal == CMixerDataProtocol::FRAME)
2307 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2308 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2310 else if (msg->signal == CMixerDataProtocol::BUFFER)
2312 VdpOutputSurface *surf;
2313 surf = (VdpOutputSurface*)msg->data;
2314 m_outputSurfaces.push(*surf);
2320 void CMixer::InitCycle()
2325 m_config.stats->GetParams(latency, flags);
2327 if (0) //flags & DVP_FLAG_NO_POSTPROC)
2328 SetPostProcFeatures(false);
2330 SetPostProcFeatures(true);
2332 m_config.stats->SetCanSkipDeint(false);
2334 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
2335 EINTERLACEMETHOD method = GetDeinterlacingMethod();
2336 bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED;
2337 m_SeenInterlaceFlag |= interlaced;
2340 if (//!(flags & DVP_FLAG_NO_POSTPROC) &&
2341 (mode == VS_DEINTERLACEMODE_FORCE ||
2342 (mode == VS_DEINTERLACEMODE_AUTO && interlaced)))
2344 if((method == VS_INTERLACEMETHOD_AUTO && interlaced)
2345 || method == VS_INTERLACEMETHOD_VDPAU_BOB
2346 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2347 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2348 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2349 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2350 || method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE )
2352 if(method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2353 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2354 || !g_graphicsContext.IsFullScreenVideo())
2359 m_config.stats->SetCanSkipDeint(true);
2363 if (0) //m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_DROPDEINT)
2368 if(m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST)
2369 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2371 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2373 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2374 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2375 DVP_FLAG_REPEAT_TOP_FIELD |
2376 DVP_FLAG_INTERLACED);
2377 m_config.useInteropYuv = false;
2379 else if (method == VS_INTERLACEMETHOD_RENDER_BOB)
2382 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2383 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2384 m_config.useInteropYuv = true;
2388 CLog::Log(LOGERROR, "CMixer::%s - interlace method: %d not supported, setting to AUTO", __FUNCTION__, method);
2390 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2391 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2392 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2393 DVP_FLAG_REPEAT_TOP_FIELD |
2394 DVP_FLAG_INTERLACED);
2396 CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod = VS_INTERLACEMETHOD_AUTO;
2402 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2404 if (m_config.useInteropYuv)
2405 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2408 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2409 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2410 DVP_FLAG_REPEAT_TOP_FIELD |
2411 DVP_FLAG_INTERLACED);
2416 if (m_mixerInput[1].DVDPic.format == RENDER_FMT_VDPAU)
2418 m_processPicture.outputSurface = m_outputSurfaces.front();
2419 m_mixerInput[1].DVDPic.iWidth = m_config.outWidth;
2420 m_mixerInput[1].DVDPic.iHeight = m_config.outHeight;
2421 if (m_SeenInterlaceFlag)
2423 double ratio = (double)m_mixerInput[1].DVDPic.iDisplayHeight / m_mixerInput[1].DVDPic.iHeight;
2424 m_mixerInput[1].DVDPic.iHeight -= 6;
2425 m_mixerInput[1].DVDPic.iDisplayHeight = lrint(ratio*m_mixerInput[1].DVDPic.iHeight);
2430 m_mixerInput[1].DVDPic.iWidth = m_config.vidWidth;
2431 m_mixerInput[1].DVDPic.iHeight = m_config.vidHeight;
2434 m_processPicture.DVDPic = m_mixerInput[1].DVDPic;
2435 m_processPicture.videoSurface = m_mixerInput[1].videoSurface;
2438 void CMixer::FiniCycle()
2440 // Keep video surfaces for one 2 cycles longer than used
2441 // by mixer. This avoids blocking in decoder.
2442 // NVidia recommends num_ref + 5
2443 while (m_mixerInput.size() > 5)
2445 CVdpauDecodedPicture &tmp = m_mixerInput.back();
2446 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
2448 m_config.videoSurfaces->ClearRender(tmp.videoSurface);
2450 m_mixerInput.pop_back();
2454 void CMixer::ProcessPicture()
2456 if (m_processPicture.DVDPic.format == RENDER_FMT_VDPAU_420)
2461 if (m_mixerstep == 1)
2463 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD)
2464 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2466 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2469 VdpVideoSurface past_surfaces[4] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2470 VdpVideoSurface futu_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2471 uint32_t pastCount = 4;
2472 uint32_t futuCount = 2;
2474 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
2476 // use only 2 past 1 future for progressive/weave
2477 // (only used for postproc anyway eg noise reduction)
2478 if (m_mixerInput.size() > 3)
2479 past_surfaces[1] = m_mixerInput[3].videoSurface;
2480 if (m_mixerInput.size() > 2)
2481 past_surfaces[0] = m_mixerInput[2].videoSurface;
2482 futu_surfaces[0] = m_mixerInput[0].videoSurface;
2488 if(m_mixerstep == 0)
2490 if (m_mixerInput.size() > 3)
2492 past_surfaces[3] = m_mixerInput[3].videoSurface;
2493 past_surfaces[2] = m_mixerInput[3].videoSurface;
2495 if (m_mixerInput.size() > 2)
2497 past_surfaces[1] = m_mixerInput[2].videoSurface;
2498 past_surfaces[0] = m_mixerInput[2].videoSurface;
2500 futu_surfaces[0] = m_mixerInput[1].videoSurface;
2501 futu_surfaces[1] = m_mixerInput[0].videoSurface;
2505 if (m_mixerInput.size() > 3)
2507 past_surfaces[3] = m_mixerInput[3].videoSurface;
2509 if (m_mixerInput.size() > 2)
2511 past_surfaces[2] = m_mixerInput[2].videoSurface;
2512 past_surfaces[1] = m_mixerInput[2].videoSurface;
2514 past_surfaces[0] = m_mixerInput[1].videoSurface;
2515 futu_surfaces[0] = m_mixerInput[0].videoSurface;
2516 futu_surfaces[1] = m_mixerInput[0].videoSurface;
2518 if (m_mixerInput[0].DVDPic.pts != DVD_NOPTS_VALUE &&
2519 m_mixerInput[1].DVDPic.pts != DVD_NOPTS_VALUE)
2521 m_processPicture.DVDPic.pts = m_mixerInput[1].DVDPic.pts +
2522 (m_mixerInput[0].DVDPic.pts -
2523 m_mixerInput[1].DVDPic.pts) / 2;
2526 m_processPicture.DVDPic.pts = DVD_NOPTS_VALUE;
2527 m_processPicture.DVDPic.dts = DVD_NOPTS_VALUE;
2529 m_processPicture.DVDPic.iRepeatPicture = 0.0;
2535 sourceRect.x1 = m_config.vidWidth;
2536 sourceRect.y1 = m_config.vidHeight;
2541 destRect.x1 = m_config.outWidth;
2542 destRect.y1 = m_config.outHeight;
2544 // start vdpau video mixer
2545 vdp_st = m_config.context->GetProcs().vdp_video_mixer_render(m_videoMixer,
2551 m_mixerInput[1].videoSurface,
2555 m_processPicture.outputSurface,
2560 CheckStatus(vdp_st, __LINE__);
2564 bool CMixer::CheckStatus(VdpStatus vdp_st, int line)
2566 if (vdp_st != VDP_STATUS_OK)
2568 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);
2575 //-----------------------------------------------------------------------------
2577 //-----------------------------------------------------------------------------
2579 VdpauBufferPool::VdpauBufferPool()
2581 CVdpauRenderPicture *pic;
2582 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2584 pic = new CVdpauRenderPicture(renderPicSec);
2585 allRenderPics.push_back(pic);
2589 VdpauBufferPool::~VdpauBufferPool()
2591 CVdpauRenderPicture *pic;
2592 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2594 pic = allRenderPics[i];
2597 allRenderPics.clear();
2600 //-----------------------------------------------------------------------------
2602 //-----------------------------------------------------------------------------
2603 COutput::COutput(CEvent *inMsgEvent) :
2604 CThread("Vdpau Output"),
2605 m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent),
2606 m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent),
2607 m_mixer(&m_outMsgEvent)
2609 m_inMsgEvent = inMsgEvent;
2611 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i)
2613 m_bufferPool.freeRenderPics.push_back(i);
2617 void COutput::Start()
2626 m_bufferPool.freeRenderPics.clear();
2627 m_bufferPool.usedRenderPics.clear();
2630 void COutput::Dispose()
2632 CSingleLock lock(g_graphicsContext);
2634 m_outMsgEvent.Set();
2636 m_controlPort.Purge();
2640 void COutput::OnStartup()
2642 CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created");
2645 void COutput::OnExit()
2647 CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated");
2654 O_TOP_UNCONFIGURED, // 2
2655 O_TOP_CONFIGURED, // 3
2656 O_TOP_CONFIGURED_IDLE, // 4
2657 O_TOP_CONFIGURED_WORK, // 5
2660 int VDPAU_OUTPUT_parentStates[] = {
2663 0, //TOP_UNCONFIGURED
2665 3, //TOP_CONFIGURED_IDLE
2666 3, //TOP_CONFIGURED_WORK
2669 void COutput::StateMachine(int signal, Protocol *port, Message *msg)
2671 for (int state = m_state; ; state = VDPAU_OUTPUT_parentStates[state])
2676 if (port == &m_controlPort)
2680 case COutputControlProtocol::FLUSH:
2681 msg->Reply(COutputControlProtocol::ACC);
2683 case COutputControlProtocol::PRECLEANUP:
2684 msg->Reply(COutputControlProtocol::ACC);
2690 else if (port == &m_dataPort)
2694 case COutputDataProtocol::RETURNPIC:
2695 CVdpauRenderPicture *pic;
2696 pic = *((CVdpauRenderPicture**)msg->data);
2697 QueueReturnPicture(pic);
2704 std::string portName = port == NULL ? "timer" : port->portName;
2705 CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
2712 case O_TOP_UNCONFIGURED:
2713 if (port == &m_controlPort)
2717 case COutputControlProtocol::INIT:
2719 data = (CVdpauConfig*)msg->data;
2726 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::INIT,
2727 &reply, 1000, &m_config, sizeof(m_config)))
2729 if (reply->signal != CMixerControlProtocol::ACC)
2734 // set initial number of
2735 m_bufferPool.numOutputSurfaces = 4;
2739 m_state = O_TOP_CONFIGURED_IDLE;
2740 msg->Reply(COutputControlProtocol::ACC, &m_config, sizeof(m_config));
2744 m_state = O_TOP_ERROR;
2745 msg->Reply(COutputControlProtocol::ERROR);
2754 case O_TOP_CONFIGURED:
2755 if (port == &m_controlPort)
2759 case COutputControlProtocol::FLUSH:
2761 msg->Reply(COutputControlProtocol::ACC);
2763 case COutputControlProtocol::PRECLEANUP:
2766 msg->Reply(COutputControlProtocol::ACC);
2772 else if (port == &m_dataPort)
2776 case COutputDataProtocol::NEWFRAME:
2777 CVdpauDecodedPicture *frame;
2778 frame = (CVdpauDecodedPicture*)msg->data;
2781 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::FRAME,
2782 frame,sizeof(CVdpauDecodedPicture));
2785 case COutputDataProtocol::RETURNPIC:
2786 CVdpauRenderPicture *pic;
2787 pic = *((CVdpauRenderPicture**)msg->data);
2788 QueueReturnPicture(pic);
2789 m_controlPort.SendInMessage(COutputControlProtocol::STATS);
2790 m_state = O_TOP_CONFIGURED_WORK;
2797 else if (port == &m_mixer.m_dataPort)
2801 case CMixerDataProtocol::PICTURE:
2802 CVdpauProcessedPicture *pic;
2803 pic = (CVdpauProcessedPicture*)msg->data;
2804 m_bufferPool.processedPics.push(*pic);
2805 m_state = O_TOP_CONFIGURED_WORK;
2814 case O_TOP_CONFIGURED_IDLE:
2815 if (port == NULL) // timeout
2819 case COutputControlProtocol::TIMEOUT:
2820 if (ProcessSyncPicture())
2826 m_state = O_TOP_CONFIGURED_WORK;
2836 case O_TOP_CONFIGURED_WORK:
2837 if (port == NULL) // timeout
2841 case COutputControlProtocol::TIMEOUT:
2844 CVdpauRenderPicture *pic;
2845 pic = ProcessMixerPicture();
2848 m_config.stats->DecProcessed();
2849 m_config.stats->IncRender();
2850 m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic));
2856 m_state = O_TOP_CONFIGURED_IDLE;
2866 default: // we are in no state, should not happen
2867 CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state);
2873 void COutput::Process()
2875 Message *msg = NULL;
2876 Protocol *port = NULL;
2879 m_state = O_TOP_UNCONFIGURED;
2880 m_extTimeout = 1000;
2881 m_bStateMachineSelfTrigger = false;
2887 if (m_bStateMachineSelfTrigger)
2889 m_bStateMachineSelfTrigger = false;
2890 // self trigger state machine
2891 StateMachine(msg->signal, port, msg);
2892 if (!m_bStateMachineSelfTrigger)
2899 // check control port
2900 else if (m_controlPort.ReceiveOutMessage(&msg))
2903 port = &m_controlPort;
2906 else if (m_dataPort.ReceiveOutMessage(&msg))
2911 // check mixer data port
2912 else if (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2915 port = &m_mixer.m_dataPort;
2919 StateMachine(msg->signal, port, msg);
2920 if (!m_bStateMachineSelfTrigger)
2929 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
2936 msg = m_controlPort.GetMessage();
2937 msg->signal = COutputControlProtocol::TIMEOUT;
2939 // signal timeout to state machine
2940 StateMachine(msg->signal, port, msg);
2941 if (!m_bStateMachineSelfTrigger)
2952 bool COutput::Init()
2954 if (!CreateGlxContext())
2966 bool COutput::Uninit()
2970 while(ProcessSyncPicture())
2975 ReleaseBufferPool();
2976 DestroyGlxContext();
2980 void COutput::Flush()
2982 if (m_mixer.IsActive())
2985 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH,
2992 CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__);
2996 while (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2998 if (msg->signal == CMixerDataProtocol::PICTURE)
3000 CVdpauProcessedPicture pic = *(CVdpauProcessedPicture*)msg->data;
3001 m_bufferPool.processedPics.push(pic);
3006 while (m_dataPort.ReceiveOutMessage(&msg))
3008 if (msg->signal == COutputDataProtocol::NEWFRAME)
3010 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
3011 m_config.videoSurfaces->ClearRender(pic.videoSurface);
3013 else if (msg->signal == COutputDataProtocol::RETURNPIC)
3015 CVdpauRenderPicture *pic;
3016 pic = *((CVdpauRenderPicture**)msg->data);
3017 QueueReturnPicture(pic);
3022 while (m_dataPort.ReceiveInMessage(&msg))
3024 if (msg->signal == COutputDataProtocol::PICTURE)
3026 CVdpauRenderPicture *pic;
3027 pic = *((CVdpauRenderPicture**)msg->data);
3028 QueueReturnPicture(pic);
3032 // reset used render flag which was cleared on mixer flush
3033 std::deque<int>::iterator it;
3034 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3036 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[*it];
3037 if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3039 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it2;
3040 it2 = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3041 if (it2 == m_bufferPool.glVideoSurfaceMap.end())
3043 CLog::Log(LOGDEBUG, "COutput::Flush - gl surface not found");
3046 m_config.videoSurfaces->MarkRender(it2->second.sourceVuv);
3050 // clear processed pics
3051 while(!m_bufferPool.processedPics.empty())
3053 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
3054 if (procPic.DVDPic.format == RENDER_FMT_VDPAU)
3056 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &procPic.outputSurface, sizeof(procPic.outputSurface));
3058 else if (procPic.DVDPic.format == RENDER_FMT_VDPAU_420)
3060 m_config.videoSurfaces->ClearRender(procPic.videoSurface);
3062 m_bufferPool.processedPics.pop();
3066 bool COutput::HasWork()
3068 if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
3073 CVdpauRenderPicture* COutput::ProcessMixerPicture()
3075 CVdpauRenderPicture *retPic = NULL;
3077 if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
3079 int idx = m_bufferPool.freeRenderPics.front();
3080 retPic = m_bufferPool.allRenderPics[idx];
3081 m_bufferPool.freeRenderPics.pop_front();
3082 m_bufferPool.usedRenderPics.push_back(idx);
3083 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
3084 m_bufferPool.processedPics.pop();
3086 retPic->DVDPic = procPic.DVDPic;
3087 retPic->valid = true;
3088 if (retPic->DVDPic.format == RENDER_FMT_VDPAU)
3090 m_config.useInteropYuv = false;
3091 m_bufferPool.numOutputSurfaces = NUM_RENDER_PICS;
3093 GLMapSurface(false, procPic.outputSurface);
3094 retPic->sourceIdx = procPic.outputSurface;
3095 retPic->texture[0] = m_bufferPool.glOutputSurfaceMap[procPic.outputSurface].texture[0];
3096 retPic->texWidth = m_config.outWidth;
3097 retPic->texHeight = m_config.outHeight;
3098 retPic->crop.x1 = 0;
3099 retPic->crop.y1 = (m_config.outHeight - retPic->DVDPic.iHeight) / 2;
3100 retPic->crop.x2 = m_config.outWidth;
3101 retPic->crop.y2 = m_config.outHeight - retPic->crop.y1;
3105 m_config.useInteropYuv = true;
3106 GLMapSurface(true, procPic.videoSurface);
3107 retPic->sourceIdx = procPic.videoSurface;
3108 for (unsigned int i=0; i<4; ++i)
3109 retPic->texture[i] = m_bufferPool.glVideoSurfaceMap[procPic.videoSurface].texture[i];
3110 retPic->texWidth = m_config.surfaceWidth;
3111 retPic->texHeight = m_config.surfaceHeight;
3112 retPic->crop.x1 = 0;
3113 retPic->crop.y1 = 0;
3114 retPic->crop.x2 = m_config.surfaceWidth - m_config.vidWidth;
3115 retPic->crop.y2 = m_config.surfaceHeight - m_config.vidHeight;
3121 void COutput::QueueReturnPicture(CVdpauRenderPicture *pic)
3123 std::deque<int>::iterator it;
3124 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3126 if (m_bufferPool.allRenderPics[*it] == pic)
3132 if (it == m_bufferPool.usedRenderPics.end())
3134 CLog::Log(LOGWARNING, "COutput::QueueReturnPicture - pic not found");
3138 // check if already queued
3139 std::deque<int>::iterator it2 = find(m_bufferPool.syncRenderPics.begin(),
3140 m_bufferPool.syncRenderPics.end(),
3142 if (it2 == m_bufferPool.syncRenderPics.end())
3144 m_bufferPool.syncRenderPics.push_back(*it);
3147 ProcessSyncPicture();
3150 bool COutput::ProcessSyncPicture()
3152 CVdpauRenderPicture *pic;
3155 std::deque<int>::iterator it;
3156 for (it = m_bufferPool.syncRenderPics.begin(); it != m_bufferPool.syncRenderPics.end(); )
3158 pic = m_bufferPool.allRenderPics[*it];
3163 if (glIsSync(pic->fence))
3167 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3168 if(state == GL_SIGNALED)
3170 glDeleteSync(pic->fence);
3183 m_bufferPool.freeRenderPics.push_back(*it);
3185 std::deque<int>::iterator it2 = find(m_bufferPool.usedRenderPics.begin(),
3186 m_bufferPool.usedRenderPics.end(),
3188 if (it2 == m_bufferPool.usedRenderPics.end())
3190 CLog::Log(LOGERROR, "COutput::ProcessSyncPicture - pic not found in queue");
3194 m_bufferPool.usedRenderPics.erase(it2);
3196 it = m_bufferPool.syncRenderPics.erase(it);
3200 ProcessReturnPicture(pic);
3204 CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__);
3210 void COutput::ProcessReturnPicture(CVdpauRenderPicture *pic)
3212 if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3214 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3215 it = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3216 if (it == m_bufferPool.glVideoSurfaceMap.end())
3218 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3221 #ifdef GL_NV_vdpau_interop
3222 glVDPAUUnmapSurfacesNV(1, &(it->second.glVdpauSurface));
3224 VdpVideoSurface surf = it->second.sourceVuv;
3225 m_config.videoSurfaces->ClearRender(surf);
3227 else if (pic->DVDPic.format == RENDER_FMT_VDPAU)
3229 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3230 it = m_bufferPool.glOutputSurfaceMap.find(pic->sourceIdx);
3231 if (it == m_bufferPool.glOutputSurfaceMap.end())
3233 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3236 #ifdef GL_NV_vdpau_interop
3237 glVDPAUUnmapSurfacesNV(1, &(it->second.glVdpauSurface));
3239 VdpOutputSurface outSurf = it->second.sourceRgb;
3240 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &outSurf, sizeof(outSurf));
3244 bool COutput::EnsureBufferPool()
3248 // Creation of outputSurfaces
3249 VdpOutputSurface outputSurface;
3250 for (int i = m_bufferPool.outputSurfaces.size(); i < m_bufferPool.numOutputSurfaces; i++)
3252 vdp_st = m_config.context->GetProcs().vdp_output_surface_create(m_config.context->GetDevice(),
3253 VDP_RGBA_FORMAT_B8G8R8A8,
3257 if (CheckStatus(vdp_st, __LINE__))
3259 m_bufferPool.outputSurfaces.push_back(outputSurface);
3261 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3263 sizeof(VdpOutputSurface));
3264 CLog::Log(LOGNOTICE, "VDPAU::COutput::InitBufferPool - Output Surface created");
3269 void COutput::ReleaseBufferPool()
3273 CSingleLock lock(m_bufferPool.renderPicSec);
3275 // release all output surfaces
3276 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3278 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3280 vdp_st = m_config.context->GetProcs().vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3281 CheckStatus(vdp_st, __LINE__);
3283 m_bufferPool.outputSurfaces.clear();
3285 // wait for all fences
3286 XbmcThreads::EndTime timeout(1000);
3287 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3289 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[i];
3293 while (glIsSync(pic->fence))
3297 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3298 if(state == GL_SIGNALED || timeout.IsTimePast())
3300 glDeleteSync(pic->fence);
3311 if (timeout.IsTimePast())
3313 CLog::Log(LOGERROR, "COutput::%s - timeout waiting for fence", __FUNCTION__);
3315 ProcessSyncPicture();
3317 // invalidate all used render pictures
3318 for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i)
3320 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[m_bufferPool.usedRenderPics[i]];
3325 void COutput::PreCleanup()
3331 ProcessSyncPicture();
3333 CSingleLock lock(m_bufferPool.renderPicSec);
3334 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3336 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3339 // check if output surface is in use
3341 std::deque<int>::iterator it;
3342 CVdpauRenderPicture *pic;
3343 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3345 pic = m_bufferPool.allRenderPics[*it];
3346 if ((pic->sourceIdx == m_bufferPool.outputSurfaces[i]) && pic->valid)
3355 #ifdef GL_NV_vdpau_interop
3357 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it_map;
3358 it_map = m_bufferPool.glOutputSurfaceMap.find(m_bufferPool.outputSurfaces[i]);
3359 if (it_map == m_bufferPool.glOutputSurfaceMap.end())
3361 CLog::Log(LOGERROR, "%s - could not find gl surface", __FUNCTION__);
3364 glVDPAUUnregisterSurfaceNV(it_map->second.glVdpauSurface);
3365 glDeleteTextures(1, it_map->second.texture);
3366 m_bufferPool.glOutputSurfaceMap.erase(it_map);
3369 vdp_st = m_config.context->GetProcs().vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3370 CheckStatus(vdp_st, __LINE__);
3372 m_bufferPool.outputSurfaces[i] = VDP_INVALID_HANDLE;
3374 CLog::Log(LOGDEBUG, "VDPAU::PreCleanup - released output surface");
3379 void COutput::InitMixer()
3381 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3383 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3384 &m_bufferPool.outputSurfaces[i],
3385 sizeof(VdpOutputSurface));
3389 bool COutput::GLInit()
3391 #ifdef GL_NV_vdpau_interop
3392 glVDPAUInitNV = NULL;
3393 glVDPAUFiniNV = NULL;
3394 glVDPAURegisterOutputSurfaceNV = NULL;
3395 glVDPAURegisterVideoSurfaceNV = NULL;
3396 glVDPAUIsSurfaceNV = NULL;
3397 glVDPAUUnregisterSurfaceNV = NULL;
3398 glVDPAUSurfaceAccessNV = NULL;
3399 glVDPAUMapSurfacesNV = NULL;
3400 glVDPAUUnmapSurfacesNV = NULL;
3401 glVDPAUGetSurfaceivNV = NULL;
3404 #ifdef GL_NV_vdpau_interop
3406 glVDPAUInitNV = (PFNGLVDPAUINITNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUInitNV");
3408 glVDPAUFiniNV = (PFNGLVDPAUFININVPROC)glXGetProcAddress((GLubyte *) "glVDPAUFiniNV");
3409 if (!glVDPAURegisterOutputSurfaceNV)
3410 glVDPAURegisterOutputSurfaceNV = (PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterOutputSurfaceNV");
3411 if (!glVDPAURegisterVideoSurfaceNV)
3412 glVDPAURegisterVideoSurfaceNV = (PFNGLVDPAUREGISTERVIDEOSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterVideoSurfaceNV");
3413 if (!glVDPAUIsSurfaceNV)
3414 glVDPAUIsSurfaceNV = (PFNGLVDPAUISSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUIsSurfaceNV");
3415 if (!glVDPAUUnregisterSurfaceNV)
3416 glVDPAUUnregisterSurfaceNV = (PFNGLVDPAUUNREGISTERSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnregisterSurfaceNV");
3417 if (!glVDPAUSurfaceAccessNV)
3418 glVDPAUSurfaceAccessNV = (PFNGLVDPAUSURFACEACCESSNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUSurfaceAccessNV");
3419 if (!glVDPAUMapSurfacesNV)
3420 glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUMapSurfacesNV");
3421 if (!glVDPAUUnmapSurfacesNV)
3422 glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnmapSurfacesNV");
3423 if (!glVDPAUGetSurfaceivNV)
3424 glVDPAUGetSurfaceivNV = (PFNGLVDPAUGETSURFACEIVNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUGetSurfaceivNV");
3426 while (glGetError() != GL_NO_ERROR);
3427 glVDPAUInitNV(reinterpret_cast<void*>(m_config.context->GetDevice()), reinterpret_cast<void*>(m_config.context->GetProcs().vdp_get_proc_address));
3428 if (glGetError() != GL_NO_ERROR)
3430 CLog::Log(LOGERROR, "VDPAU::COutput - GLInitInterop glVDPAUInitNV failed");
3434 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop initialized");
3438 bool hasfence = glewIsSupported("GL_ARB_sync");
3439 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3441 m_bufferPool.allRenderPics[i]->usefence = hasfence;
3448 void COutput::GLMapSurface(bool yuv, uint32_t source)
3450 #ifdef GL_NV_vdpau_interop
3454 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3455 it = m_bufferPool.glVideoSurfaceMap.find(source);
3456 if (it == m_bufferPool.glVideoSurfaceMap.end())
3458 VdpauBufferPool::GLVideoSurface glSurface;
3459 VdpVideoSurface surf = source;
3461 if (surf == VDP_INVALID_HANDLE)
3464 glSurface.sourceVuv = surf;
3465 while (glGetError() != GL_NO_ERROR) ;
3466 glGenTextures(4, glSurface.texture);
3467 if (glGetError() != GL_NO_ERROR)
3469 CLog::Log(LOGERROR, "VDPAU::COutput error creating texture");
3472 glSurface.glVdpauSurface = glVDPAURegisterVideoSurfaceNV(reinterpret_cast<void*>(surf),
3473 GL_TEXTURE_2D, 4, glSurface.texture);
3475 if (glGetError() != GL_NO_ERROR)
3477 CLog::Log(LOGERROR, "VDPAU::COutput error register video surface");
3480 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3481 if (glGetError() != GL_NO_ERROR)
3483 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3486 m_bufferPool.glVideoSurfaceMap[surf] = glSurface;
3488 CLog::Log(LOGNOTICE, "VDPAU::COutput registered surface");
3491 while (glGetError() != GL_NO_ERROR) ;
3492 glVDPAUMapSurfacesNV(1, &m_bufferPool.glVideoSurfaceMap[source].glVdpauSurface);
3493 if (glGetError() != GL_NO_ERROR)
3495 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3504 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3505 it = m_bufferPool.glOutputSurfaceMap.find(source);
3506 if (it == m_bufferPool.glOutputSurfaceMap.end())
3508 unsigned int idx = 0;
3509 for (idx = 0; idx<m_bufferPool.outputSurfaces.size(); idx++)
3511 if (m_bufferPool.outputSurfaces[idx] == source)
3515 VdpauBufferPool::GLVideoSurface glSurface;
3516 glSurface.sourceRgb = m_bufferPool.outputSurfaces[idx];
3517 glGenTextures(1, glSurface.texture);
3518 glSurface.glVdpauSurface = glVDPAURegisterOutputSurfaceNV(reinterpret_cast<void*>(m_bufferPool.outputSurfaces[idx]),
3519 GL_TEXTURE_2D, 1, glSurface.texture);
3520 if (glGetError() != GL_NO_ERROR)
3522 CLog::Log(LOGERROR, "VDPAU::COutput error register output surface");
3525 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3526 if (glGetError() != GL_NO_ERROR)
3528 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3531 m_bufferPool.glOutputSurfaceMap[source] = glSurface;
3532 CLog::Log(LOGNOTICE, "VDPAU::COutput registered output surfaces");
3535 while (glGetError() != GL_NO_ERROR) ;
3536 glVDPAUMapSurfacesNV(1, &m_bufferPool.glOutputSurfaceMap[source].glVdpauSurface);
3537 if (glGetError() != GL_NO_ERROR)
3539 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3549 void COutput::GLUnmapSurfaces()
3551 #ifdef GL_NV_vdpau_interop
3554 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3555 for (it = m_bufferPool.glVideoSurfaceMap.begin(); it != m_bufferPool.glVideoSurfaceMap.end(); ++it)
3557 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3558 glDeleteTextures(4, it->second.texture);
3560 m_bufferPool.glVideoSurfaceMap.clear();
3563 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3564 for (it = m_bufferPool.glOutputSurfaceMap.begin(); it != m_bufferPool.glOutputSurfaceMap.end(); ++it)
3566 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3567 glDeleteTextures(1, it->second.texture);
3569 m_bufferPool.glOutputSurfaceMap.clear();
3573 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop finished");
3578 bool COutput::CheckStatus(VdpStatus vdp_st, int line)
3580 if (vdp_st != VDP_STATUS_OK)
3582 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);
3589 bool COutput::CreateGlxContext()
3591 GLXContext glContext;
3593 m_Display = g_Windowing.GetDisplay();
3594 glContext = g_Windowing.GetGlxContext();
3595 m_Window = g_Windowing.GetWindow();
3597 // Get our window attribs.
3598 XWindowAttributes wndattribs;
3599 XGetWindowAttributes(m_Display, m_Window, &wndattribs);
3602 XVisualInfo visInfo;
3603 visInfo.visualid = wndattribs.visual->visualid;
3605 XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals);
3608 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - could not find visual");
3611 visInfo = visuals[0];
3614 m_pixmap = XCreatePixmap(m_Display,
3621 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - Unable to create XPixmap");
3626 m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap);
3630 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not create glPixmap");
3634 m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True);
3636 if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext))
3638 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not make Pixmap current");
3642 CLog::Log(LOGNOTICE, "VDPAU::COutput::CreateGlxContext - created context");
3646 bool COutput::DestroyGlxContext()
3650 glXMakeCurrent(m_Display, None, NULL);
3651 glXDestroyContext(m_Display, m_glContext);
3656 glXDestroyPixmap(m_Display, m_glPixmap);
3660 XFreePixmap(m_Display, m_pixmap);