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 CDecoder::Desc decoder_profiles[] = {
46 {"MPEG1", VDP_DECODER_PROFILE_MPEG1},
47 {"MPEG2_SIMPLE", VDP_DECODER_PROFILE_MPEG2_SIMPLE},
48 {"MPEG2_MAIN", VDP_DECODER_PROFILE_MPEG2_MAIN},
49 {"H264_BASELINE",VDP_DECODER_PROFILE_H264_BASELINE},
50 {"H264_MAIN", VDP_DECODER_PROFILE_H264_MAIN},
51 {"H264_HIGH", VDP_DECODER_PROFILE_H264_HIGH},
52 {"VC1_SIMPLE", VDP_DECODER_PROFILE_VC1_SIMPLE},
53 {"VC1_MAIN", VDP_DECODER_PROFILE_VC1_MAIN},
54 {"VC1_ADVANCED", VDP_DECODER_PROFILE_VC1_ADVANCED},
55 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
56 {"MPEG4_PART2_ASP", VDP_DECODER_PROFILE_MPEG4_PART2_ASP},
59 const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CDecoder::Desc);
61 static struct SInterlaceMapping
63 const EINTERLACEMETHOD method;
64 const VdpVideoMixerFeature feature;
65 } g_interlace_mapping[] =
66 { {VS_INTERLACEMETHOD_VDPAU_TEMPORAL , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
67 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
68 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
69 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
70 , {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE}
71 , {VS_INTERLACEMETHOD_NONE , (VdpVideoMixerFeature)-1}
74 static float studioCSCKCoeffs601[3] = {0.299, 0.587, 0.114}; //BT601 {Kr, Kg, Kb}
75 static float studioCSCKCoeffs709[3] = {0.2126, 0.7152, 0.0722}; //BT709 {Kr, Kg, Kb}
77 //-----------------------------------------------------------------------------
78 //-----------------------------------------------------------------------------
80 CVDPAUContext *CVDPAUContext::m_context = 0;
81 CCriticalSection CVDPAUContext::m_section;
82 Display *CVDPAUContext::m_display = 0;
83 void *CVDPAUContext::m_dlHandle = 0;
85 CVDPAUContext::CVDPAUContext()
91 void CVDPAUContext::Release()
93 CSingleLock lock(m_section);
104 void CVDPAUContext::Close()
106 CLog::Log(LOGNOTICE, "VDPAU::Close - closing decoder context");
110 bool CVDPAUContext::EnsureContext(CVDPAUContext **ctx)
112 CSingleLock lock(m_section);
116 m_context->m_refCount++;
121 m_context = new CVDPAUContext();
124 CSingleLock gLock(g_graphicsContext);
125 if (!m_context->LoadSymbols() || !m_context->CreateContext())
133 m_context->m_refCount++;
139 VDPAU_procs& CVDPAUContext::GetProcs()
144 VdpVideoMixerFeature* CVDPAUContext::GetFeatures()
146 return m_vdpFeatures;
149 int CVDPAUContext::GetFeatureCount()
151 return m_featureCount;
154 bool CVDPAUContext::LoadSymbols()
158 m_dlHandle = dlopen("libvdpau.so.1", RTLD_LAZY);
161 const char* error = dlerror();
163 error = "dlerror() returned NULL";
165 CLog::Log(LOGERROR,"VDPAU::LoadSymbols: Unable to get handle to lib: %s", error);
172 dl_vdp_device_create_x11 = (VdpStatus (*)(Display*, int, VdpDevice*, VdpStatus (**)(VdpDevice, VdpFuncId, void**)))dlsym(m_dlHandle, (const char*)"vdp_device_create_x11");
176 CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__);
177 m_vdpDevice = VDP_INVALID_HANDLE;
183 bool CVDPAUContext::CreateContext()
185 CLog::Log(LOGNOTICE,"VDPAU::CreateContext - creating decoder context");
188 { CSingleLock lock(g_graphicsContext);
190 m_display = XOpenDisplay(NULL);
191 mScreen = g_Windowing.GetCurrentScreen();
196 vdp_st = dl_vdp_device_create_x11(m_display,
199 &m_vdpProcs.vdp_get_proc_address);
201 CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",m_vdpDevice,vdp_st);
202 if (vdp_st != VDP_STATUS_OK)
204 CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x. Falling back.",vdp_st);
205 m_vdpDevice = VDP_INVALID_HANDLE;
210 SpewHardwareAvailable();
214 void CVDPAUContext::QueryProcs()
218 #define VDP_PROC(id, proc) \
220 vdp_st = m_vdpProcs.vdp_get_proc_address(m_vdpDevice, id, (void**)&proc); \
221 if (vdp_st != VDP_STATUS_OK) \
223 CLog::Log(LOGERROR, "CVDPAUContext::GetProcs - failed to get proc id"); \
227 VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING , m_vdpProcs.vdp_get_error_string);
228 VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY , m_vdpProcs.vdp_device_destroy);
229 VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX , m_vdpProcs.vdp_generate_csc_matrix);
230 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE , m_vdpProcs.vdp_video_surface_create);
231 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , m_vdpProcs.vdp_video_surface_destroy);
232 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , m_vdpProcs.vdp_video_surface_put_bits_y_cb_cr);
233 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , m_vdpProcs.vdp_video_surface_get_bits_y_cb_cr);
234 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , m_vdpProcs.vdp_output_surface_put_bits_y_cb_cr);
235 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , m_vdpProcs.vdp_output_surface_put_bits_native);
236 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , m_vdpProcs.vdp_output_surface_create);
237 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , m_vdpProcs.vdp_output_surface_destroy);
238 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , m_vdpProcs.vdp_output_surface_get_bits_native);
239 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, m_vdpProcs.vdp_output_surface_render_output_surface);
240 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , m_vdpProcs.vdp_output_surface_put_bits_indexed);
241 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE , m_vdpProcs.vdp_video_mixer_create);
242 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , m_vdpProcs.vdp_video_mixer_set_feature_enables);
243 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY , m_vdpProcs.vdp_video_mixer_destroy);
244 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER , m_vdpProcs.vdp_video_mixer_render);
245 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , m_vdpProcs.vdp_video_mixer_set_attribute_values);
246 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , m_vdpProcs.vdp_video_mixer_query_parameter_support);
247 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , m_vdpProcs.vdp_video_mixer_query_feature_support);
248 VDP_PROC(VDP_FUNC_ID_DECODER_CREATE , m_vdpProcs.vdp_decoder_create);
249 VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY , m_vdpProcs.vdp_decoder_destroy);
250 VDP_PROC(VDP_FUNC_ID_DECODER_RENDER , m_vdpProcs.vdp_decoder_render);
251 VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , m_vdpProcs.vdp_decoder_query_caps);
255 VdpDevice CVDPAUContext::GetDevice()
260 void CVDPAUContext::DestroyContext()
262 if (!m_vdpProcs.vdp_device_destroy)
265 m_vdpProcs.vdp_device_destroy(m_vdpDevice);
266 m_vdpDevice = VDP_INVALID_HANDLE;
269 void CVDPAUContext::SpewHardwareAvailable() //CopyrighVDPAUt (c) 2008 Wladimir J. van der Laan -- VDPInfo
272 CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:");
273 CLog::Log(LOGNOTICE,"name level macbs width height");
274 CLog::Log(LOGNOTICE,"------------------------------------");
275 for(unsigned int x=0; x<decoder_profile_count; ++x)
277 VdpBool is_supported = false;
278 uint32_t max_level, max_macroblocks, max_width, max_height;
279 rv = m_vdpProcs.vdp_decoder_query_caps(m_vdpDevice, decoder_profiles[x].id,
280 &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
281 if(rv == VDP_STATUS_OK && is_supported)
283 CLog::Log(LOGNOTICE,"%-16s %2i %5i %5i %5i\n", decoder_profiles[x].name,
284 max_level, max_macroblocks, max_width, max_height);
287 CLog::Log(LOGNOTICE,"------------------------------------");
289 #define CHECK_SUPPORT(feature) \
292 if(m_vdpProcs.vdp_video_mixer_query_feature_support(m_vdpDevice, feature, &supported) == VDP_STATUS_OK && supported) { \
293 CLog::Log(LOGNOTICE, "Mixer feature: "#feature); \
294 m_vdpFeatures[m_featureCount++] = feature; \
298 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION);
299 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_SHARPNESS);
300 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL);
301 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL);
302 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE);
303 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
304 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1);
305 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2);
306 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3);
307 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4);
308 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5);
309 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6);
310 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7);
311 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8);
312 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9);
317 bool CVDPAUContext::Supports(VdpVideoMixerFeature feature)
319 for(int i = 0; i < m_featureCount; i++)
321 if(m_vdpFeatures[i] == feature)
327 //-----------------------------------------------------------------------------
328 // VDPAU Video Surface states
329 //-----------------------------------------------------------------------------
331 #define SURFACE_USED_FOR_REFERENCE 0x01
332 #define SURFACE_USED_FOR_RENDER 0x02
334 void CVideoSurfaces::AddSurface(VdpVideoSurface surf)
336 CSingleLock lock(m_section);
337 m_state[surf] = SURFACE_USED_FOR_REFERENCE;
340 void CVideoSurfaces::ClearReference(VdpVideoSurface surf)
342 CSingleLock lock(m_section);
343 if (m_state.find(surf) == m_state.end())
345 CLog::Log(LOGWARNING, "CVideoSurfaces::ClearReference - surface invalid");
348 m_state[surf] &= ~SURFACE_USED_FOR_REFERENCE;
349 if (m_state[surf] == 0)
351 m_freeSurfaces.push_back(surf);
355 bool CVideoSurfaces::MarkRender(VdpVideoSurface surf)
357 CSingleLock lock(m_section);
358 if (m_state.find(surf) == m_state.end())
360 CLog::Log(LOGWARNING, "CVideoSurfaces::MarkRender - surface invalid");
363 std::list<VdpVideoSurface>::iterator it;
364 it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
365 if (it != m_freeSurfaces.end())
367 m_freeSurfaces.erase(it);
369 m_state[surf] |= SURFACE_USED_FOR_RENDER;
373 void CVideoSurfaces::ClearRender(VdpVideoSurface surf)
375 CSingleLock lock(m_section);
376 if (m_state.find(surf) == m_state.end())
378 CLog::Log(LOGWARNING, "CVideoSurfaces::ClearRender - surface invalid");
381 m_state[surf] &= ~SURFACE_USED_FOR_RENDER;
382 if (m_state[surf] == 0)
384 m_freeSurfaces.push_back(surf);
388 bool CVideoSurfaces::IsValid(VdpVideoSurface surf)
390 CSingleLock lock(m_section);
391 if (m_state.find(surf) != m_state.end())
397 VdpVideoSurface CVideoSurfaces::GetFree(VdpVideoSurface surf)
399 CSingleLock lock(m_section);
400 if (m_state.find(surf) != m_state.end())
402 std::list<VdpVideoSurface>::iterator it;
403 it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
404 if (it == m_freeSurfaces.end())
406 CLog::Log(LOGWARNING, "CVideoSurfaces::GetFree - surface not free");
410 m_freeSurfaces.erase(it);
411 m_state[surf] = SURFACE_USED_FOR_REFERENCE;
416 if (!m_freeSurfaces.empty())
418 VdpVideoSurface freeSurf = m_freeSurfaces.front();
419 m_freeSurfaces.pop_front();
420 m_state[freeSurf] = SURFACE_USED_FOR_REFERENCE;
424 return VDP_INVALID_HANDLE;
427 VdpVideoSurface CVideoSurfaces::GetAtIndex(int idx)
429 if (idx >= m_state.size())
430 return VDP_INVALID_HANDLE;
432 std::map<VdpVideoSurface, int>::iterator it = m_state.begin();
433 for(int i = 0; i < idx; i++)
438 VdpVideoSurface CVideoSurfaces::RemoveNext(bool skiprender)
440 CSingleLock lock(m_section);
441 VdpVideoSurface surf;
442 std::map<VdpVideoSurface, int>::iterator it;
443 for(it = m_state.begin(); it != m_state.end(); ++it)
445 if (skiprender && it->second & SURFACE_USED_FOR_RENDER)
450 std::list<VdpVideoSurface>::iterator it2;
451 it2 = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
452 if (it2 != m_freeSurfaces.end())
453 m_freeSurfaces.erase(it2);
456 return VDP_INVALID_HANDLE;
459 void CVideoSurfaces::Reset()
461 CSingleLock lock(m_section);
462 m_freeSurfaces.clear();
466 int CVideoSurfaces::Size()
468 CSingleLock lock(m_section);
469 return m_state.size();
472 //-----------------------------------------------------------------------------
474 //-----------------------------------------------------------------------------
476 CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent)
478 m_vdpauConfig.videoSurfaces = &m_videoSurfaces;
480 m_vdpauConfigured = false;
481 m_hwContext.bitstream_buffers_allocated = 0;
482 m_DisplayState = VDPAU_OPEN;
483 m_vdpauConfig.context = 0;
486 bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces)
488 if(avctx->coded_width == 0
489 || avctx->coded_height == 0)
491 CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init");
494 m_vdpauConfig.numRenderBuffers = surfaces;
495 m_decoderThread = CThread::GetCurrentThreadId();
497 if ((avctx->codec_id == AV_CODEC_ID_MPEG4) && !g_advancedSettings.m_videoAllowMpeg4VDPAU)
500 if (!CVDPAUContext::EnsureContext(&m_vdpauConfig.context))
503 m_DisplayState = VDPAU_OPEN;
504 m_vdpauConfigured = false;
506 if (!m_dllAvUtil.Load())
509 m_presentPicture = 0;
512 VdpDecoderProfile profile = 0;
513 if(avctx->codec_id == AV_CODEC_ID_H264)
514 profile = VDP_DECODER_PROFILE_H264_HIGH;
515 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
516 else if(avctx->codec_id == AV_CODEC_ID_MPEG4)
517 profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
521 if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width))
522 CLog::Log(LOGWARNING,"(VDPAU) width %i might not be supported because of hardware bug", avctx->width);
524 /* attempt to create a decoder with this width/height, some sizes are not supported by hw */
526 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_create(m_vdpauConfig.context->GetDevice(), profile, avctx->coded_width, avctx->coded_height, 5, &m_vdpauConfig.vdpDecoder);
528 if(vdp_st != VDP_STATUS_OK)
530 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st);
534 m_vdpauConfig.context->GetProcs().vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
535 CheckStatus(vdp_st, __LINE__);
538 /* finally setup ffmpeg */
539 memset(&m_hwContext, 0, sizeof(AVVDPAUContext));
540 m_hwContext.render = CDecoder::Render;
541 m_hwContext.bitstream_buffers_allocated = 0;
542 avctx->get_buffer = CDecoder::FFGetBuffer;
543 avctx->reget_buffer = CDecoder::FFGetBuffer;
544 avctx->release_buffer = CDecoder::FFReleaseBuffer;
545 avctx->draw_horiz_band = CDecoder::FFDrawSlice;
546 avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
547 avctx->hwaccel_context = &m_hwContext;
548 avctx->thread_count = 1;
550 g_Windowing.Register(this);
556 CDecoder::~CDecoder()
561 void CDecoder::Close()
563 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
565 g_Windowing.Unregister(this);
567 CSingleLock lock(m_DecoderSection);
570 m_vdpauOutput.Dispose();
572 if (m_hwContext.bitstream_buffers_allocated)
574 m_dllAvUtil.av_freep(&m_hwContext.bitstream_buffers);
577 m_dllAvUtil.Unload();
579 if (m_vdpauConfig.context)
580 m_vdpauConfig.context->Release();
581 m_vdpauConfig.context = 0;
584 long CDecoder::Release()
586 // check if we should do some pre-cleanup here
587 // a second decoder might need resources
588 if (m_vdpauConfigured == true)
590 CSingleLock lock(m_DecoderSection);
591 CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup");
594 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP,
598 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
602 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup returned error", __FUNCTION__);
603 m_DisplayState = VDPAU_ERROR;
608 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup timed out", __FUNCTION__);
609 m_DisplayState = VDPAU_ERROR;
612 VdpVideoSurface surf;
613 while((surf = m_videoSurfaces.RemoveNext(true)) != VDP_INVALID_HANDLE)
615 m_vdpauConfig.context->GetProcs().vdp_video_surface_destroy(surf);
618 return IHardwareDecoder::Release();
621 long CDecoder::ReleasePicReference()
623 return IHardwareDecoder::Release();
626 void CDecoder::SetWidthHeight(int width, int height)
628 m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling;
630 //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate
631 //this requires the least amount of gpu memory bandwidth
632 if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || m_vdpauConfig.upscale >= 0)
634 //scale width to desktop size if the aspect ratio is the same or bigger than the desktop
635 if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight())
637 m_vdpauConfig.outWidth = g_graphicsContext.GetWidth();
638 m_vdpauConfig.outHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width);
640 else //scale height to the desktop size if the aspect ratio is smaller than the desktop
642 m_vdpauConfig.outHeight = g_graphicsContext.GetHeight();
643 m_vdpauConfig.outWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height);
648 m_vdpauConfig.outWidth = width;
649 m_vdpauConfig.outHeight = height;
651 CLog::Log(LOGDEBUG, "CVDPAU::SetWidthHeight Setting OutWidth: %i OutHeight: %i", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight);
654 void CDecoder::OnLostDevice()
656 CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event");
658 int count = g_graphicsContext.exit();
660 CSingleLock lock(m_DecoderSection);
662 if (m_vdpauConfig.context)
663 m_vdpauConfig.context->Release();
664 m_vdpauConfig.context = 0;
666 m_DisplayState = VDPAU_LOST;
668 m_DisplayEvent.Reset();
670 g_graphicsContext.restore(count);
673 void CDecoder::OnResetDevice()
675 CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event");
677 int count = g_graphicsContext.exit();
679 CSingleLock lock(m_DecoderSection);
680 if (m_DisplayState == VDPAU_LOST)
682 m_DisplayState = VDPAU_RESET;
684 m_DisplayEvent.Set();
687 g_graphicsContext.restore(count);
690 int CDecoder::Check(AVCodecContext* avctx)
694 { CSingleLock lock(m_DecoderSection);
695 state = m_DisplayState;
698 if (state == VDPAU_LOST)
700 CLog::Log(LOGNOTICE,"CVDPAU::Check waiting for display reset event");
701 if (!m_DisplayEvent.WaitMSec(4000))
703 CLog::Log(LOGERROR, "CVDPAU::Check - device didn't reset in reasonable time");
708 CSingleLock lock(m_DecoderSection);
709 state = m_DisplayState;
712 if (state == VDPAU_RESET || state == VDPAU_ERROR)
714 CSingleLock lock(m_DecoderSection);
717 if (m_vdpauConfig.context)
718 m_vdpauConfig.context->Release();
719 m_vdpauConfig.context = 0;
721 if (CVDPAUContext::EnsureContext(&m_vdpauConfig.context))
723 m_DisplayState = VDPAU_OPEN;
724 m_vdpauConfigured = false;
727 if (state == VDPAU_RESET)
735 bool CDecoder::IsVDPAUFormat(PixelFormat format)
737 if (format == AV_PIX_FMT_VDPAU)
743 bool CDecoder::Supports(VdpVideoMixerFeature feature)
745 return m_vdpauConfig.context->Supports(feature);
748 bool CDecoder::Supports(EINTERLACEMETHOD method)
750 if(method == VS_INTERLACEMETHOD_VDPAU_BOB
751 || method == VS_INTERLACEMETHOD_AUTO)
754 if (method == VS_INTERLACEMETHOD_RENDER_BOB)
757 if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE)
760 for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++)
762 if(p->method == method)
763 return Supports(p->feature);
768 EINTERLACEMETHOD CDecoder::AutoInterlaceMethod()
770 return VS_INTERLACEMETHOD_RENDER_BOB;
773 void CDecoder::FiniVDPAUOutput()
775 if (!m_vdpauConfigured)
778 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
781 m_vdpauOutput.Dispose();
782 m_vdpauConfigured = false;
786 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
787 if (CheckStatus(vdp_st, __LINE__))
789 m_vdpauConfig.vdpDecoder = VDP_INVALID_HANDLE;
791 CLog::Log(LOGDEBUG, "CVDPAU::FiniVDPAUOutput destroying %d video surfaces", m_videoSurfaces.Size());
793 VdpVideoSurface surf;
794 while((surf = m_videoSurfaces.RemoveNext()) != VDP_INVALID_HANDLE)
796 m_vdpauConfig.context->GetProcs().vdp_video_surface_destroy(surf);
797 if (CheckStatus(vdp_st, __LINE__))
800 m_videoSurfaces.Reset();
803 void CDecoder::ReadFormatOf( AVCodecID codec
804 , VdpDecoderProfile &vdp_decoder_profile
805 , VdpChromaType &vdp_chroma_type)
809 case AV_CODEC_ID_MPEG1VIDEO:
810 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
811 vdp_chroma_type = VDP_CHROMA_TYPE_420;
813 case AV_CODEC_ID_MPEG2VIDEO:
814 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
815 vdp_chroma_type = VDP_CHROMA_TYPE_420;
817 case AV_CODEC_ID_H264:
818 vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
819 vdp_chroma_type = VDP_CHROMA_TYPE_420;
821 case AV_CODEC_ID_WMV3:
822 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
823 vdp_chroma_type = VDP_CHROMA_TYPE_420;
825 case AV_CODEC_ID_VC1:
826 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
827 vdp_chroma_type = VDP_CHROMA_TYPE_420;
829 case AV_CODEC_ID_MPEG4:
830 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
831 vdp_chroma_type = VDP_CHROMA_TYPE_420;
834 vdp_decoder_profile = 0;
840 bool CDecoder::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
845 VdpDecoderProfile vdp_decoder_profile;
847 m_vdpauConfig.vidWidth = avctx->width;
848 m_vdpauConfig.vidHeight = avctx->height;
849 m_vdpauConfig.surfaceWidth = avctx->coded_width;
850 m_vdpauConfig.surfaceHeight = avctx->coded_height;
852 SetWidthHeight(avctx->width,avctx->height);
854 CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",m_vdpauConfig.outWidth,m_vdpauConfig.vidWidth,m_vdpauConfig.surfaceWidth);
855 CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",m_vdpauConfig.outHeight,m_vdpauConfig.vidHeight,m_vdpauConfig.surfaceHeight);
857 ReadFormatOf(avctx->codec_id, vdp_decoder_profile, m_vdpauConfig.vdpChromaType);
859 if(avctx->codec_id == AV_CODEC_ID_H264)
861 m_vdpauConfig.maxReferences = ref_frames;
862 if (m_vdpauConfig.maxReferences > 16) m_vdpauConfig.maxReferences = 16;
863 if (m_vdpauConfig.maxReferences < 5) m_vdpauConfig.maxReferences = 5;
866 m_vdpauConfig.maxReferences = 2;
868 vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_create(m_vdpauConfig.context->GetDevice(),
870 m_vdpauConfig.surfaceWidth,
871 m_vdpauConfig.surfaceHeight,
872 m_vdpauConfig.maxReferences,
873 &m_vdpauConfig.vdpDecoder);
874 if (CheckStatus(vdp_st, __LINE__))
878 CSingleLock lock(g_graphicsContext);
879 m_vdpauConfig.stats = &m_bufferStats;
880 m_vdpauConfig.vdpau = this;
881 m_bufferStats.Reset();
882 m_vdpauOutput.Start();
884 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT,
888 sizeof(m_vdpauConfig)))
890 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
894 CLog::Log(LOGERROR, "VDPAU::%s - vdpau output returned error", __FUNCTION__);
895 m_vdpauOutput.Dispose();
901 CLog::Log(LOGERROR, "VDPAU::%s - failed to init output", __FUNCTION__);
902 m_vdpauOutput.Dispose();
906 m_inMsgEvent.Reset();
907 m_vdpauConfigured = true;
911 int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
913 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
914 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
915 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
917 // while we are waiting to recover we can't do anything
918 CSingleLock lock(vdp->m_DecoderSection);
920 if(vdp->m_DisplayState != VDPAU_OPEN)
922 CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
926 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
927 surf = vdp->m_videoSurfaces.GetFree(surf != 0 ? surf : VDP_INVALID_HANDLE);
929 VdpStatus vdp_st = VDP_STATUS_ERROR;
930 if (surf == VDP_INVALID_HANDLE)
932 // create a new surface
933 VdpDecoderProfile profile;
934 ReadFormatOf(avctx->codec_id, profile, vdp->m_vdpauConfig.vdpChromaType);
936 vdp_st = vdp->m_vdpauConfig.context->GetProcs().vdp_video_surface_create(vdp->m_vdpauConfig.context->GetDevice(),
937 vdp->m_vdpauConfig.vdpChromaType,
941 vdp->CheckStatus(vdp_st, __LINE__);
942 if (vdp_st != VDP_STATUS_OK)
944 CLog::Log(LOGERROR, "CVDPAU::FFGetBuffer - No Video surface available could be created");
947 vdp->m_videoSurfaces.AddSurface(surf);
950 pic->data[1] = pic->data[2] = NULL;
951 pic->data[0] = (uint8_t*)(uintptr_t)surf;
952 pic->data[3] = (uint8_t*)(uintptr_t)surf;
954 pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0;
956 pic->type= FF_BUFFER_TYPE_USER;
958 pic->reordered_opaque= avctx->reordered_opaque;
962 void CDecoder::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
964 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
965 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
967 VdpVideoSurface surf;
970 CSingleLock lock(vdp->m_DecoderSection);
972 surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
974 vdp->m_videoSurfaces.ClearReference(surf);
980 VdpStatus CDecoder::Render( VdpDecoder decoder, VdpVideoSurface target,
981 VdpPictureInfo const *picture_info,
982 uint32_t bitstream_buffer_count,
983 VdpBitstreamBuffer const * bitstream_buffers)
985 return VDP_STATUS_OK;
988 void CDecoder::FFDrawSlice(struct AVCodecContext *s,
989 const AVFrame *src, int offset[4],
990 int y, int type, int height)
992 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque;
993 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
995 // while we are waiting to recover we can't do anything
996 CSingleLock lock(vdp->m_DecoderSection);
998 if(vdp->m_DisplayState != VDPAU_OPEN)
1001 if(src->linesize[0] || src->linesize[1] || src->linesize[2]
1002 || offset[0] || offset[1] || offset[2])
1004 CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid linesizes or offsets provided");
1009 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)src->data[3];
1011 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1012 if (!vdp->m_videoSurfaces.IsValid(surf))
1014 CLog::Log(LOGWARNING, "CVDPAU::FFDrawSlice - ignoring invalid buffer");
1018 uint32_t max_refs = 0;
1019 if(s->codec_id == AV_CODEC_ID_H264)
1020 max_refs = vdp->m_hwContext.info.h264.num_ref_frames;
1022 if(vdp->m_vdpauConfig.vdpDecoder == VDP_INVALID_HANDLE
1023 || vdp->m_vdpauConfigured == false
1024 || vdp->m_vdpauConfig.maxReferences < max_refs)
1026 if(!vdp->ConfigVDPAU(s, max_refs))
1030 uint64_t startTime = CurrentHostCounter();
1031 uint16_t decoded, processed, rend;
1032 vdp->m_bufferStats.Get(decoded, processed, rend);
1033 vdp_st = vdp->m_vdpauConfig.context->GetProcs().vdp_decoder_render(vdp->m_vdpauConfig.vdpDecoder,
1035 (VdpPictureInfo const *)&(vdp->m_hwContext.info),
1036 vdp->m_hwContext.bitstream_buffers_used,
1037 vdp->m_hwContext.bitstream_buffers);
1038 vdp->CheckStatus(vdp_st, __LINE__);
1039 uint64_t diff = CurrentHostCounter() - startTime;
1040 if (diff*1000/CurrentHostFrequency() > 30)
1041 CLog::Log(LOGDEBUG, "CVDPAU::DrawSlice - VdpDecoderRender long decoding: %d ms, dec: %d, proc: %d, rend: %d", (int)((diff*1000)/CurrentHostFrequency()), decoded, processed, rend);
1045 int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame)
1047 int result = Check(avctx);
1051 CSingleLock lock(m_DecoderSection);
1053 if (!m_vdpauConfigured)
1057 { // we have a new frame from decoder
1059 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pFrame->data[3];
1060 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1061 if (!m_videoSurfaces.IsValid(surf))
1063 CLog::Log(LOGWARNING, "CVDPAU::Decode - ignoring invalid buffer");
1066 m_videoSurfaces.MarkRender(surf);
1068 // send frame to output for processing
1069 CVdpauDecodedPicture pic;
1070 memset(&pic.DVDPic, 0, sizeof(pic.DVDPic));
1071 ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic);
1072 pic.videoSurface = surf;
1073 pic.DVDPic.color_matrix = avctx->colorspace;
1074 m_bufferStats.IncDecoded();
1075 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic));
1078 // m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC);
1082 uint16_t decoded, processed, render;
1084 while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1086 if (msg->signal == COutputControlProtocol::ERROR)
1088 m_DisplayState = VDPAU_ERROR;
1094 m_bufferStats.Get(decoded, processed, render);
1096 uint64_t startTime = CurrentHostCounter();
1099 // first fill the buffers to keep vdpau busy
1100 // mixer will run with decoded >= 2. output is limited by number of output surfaces
1101 // In case mixer is bypassed we limit by looking at processed
1102 if (decoded < 3 && processed < 3)
1104 retval |= VC_BUFFER;
1106 else if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg))
1108 if (msg->signal == COutputDataProtocol::PICTURE)
1110 if (m_presentPicture)
1112 m_presentPicture->ReturnUnused();
1113 m_presentPicture = 0;
1116 m_presentPicture = *(CVdpauRenderPicture**)msg->data;
1117 m_presentPicture->vdpau = this;
1118 m_bufferStats.DecRender();
1119 m_bufferStats.Get(decoded, processed, render);
1120 retval |= VC_PICTURE;
1126 else if (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1128 if (msg->signal == COutputControlProtocol::STATS)
1130 m_bufferStats.Get(decoded, processed, render);
1134 m_DisplayState = VDPAU_ERROR;
1140 if (decoded < 3 && processed < 3)
1142 retval |= VC_BUFFER;
1145 if (!retval && !m_inMsgEvent.WaitMSec(2000))
1148 uint64_t diff = CurrentHostCounter() - startTime;
1149 if (retval & VC_PICTURE)
1151 m_bufferStats.SetParams(diff, m_codecControl);
1153 if (diff*1000/CurrentHostFrequency() > 50)
1154 CLog::Log(LOGDEBUG,"CVDPAU::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency()));
1158 CLog::Log(LOGERROR, "VDPAU::%s - timed out waiting for output message", __FUNCTION__);
1159 m_DisplayState = VDPAU_ERROR;
1166 bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
1168 CSingleLock lock(m_DecoderSection);
1170 if (m_DisplayState != VDPAU_OPEN)
1173 *picture = m_presentPicture->DVDPic;
1174 picture->vdpau = m_presentPicture;
1179 void CDecoder::Reset()
1181 CSingleLock lock(m_DecoderSection);
1183 if (!m_vdpauConfigured)
1187 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH,
1191 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
1195 CLog::Log(LOGERROR, "VDPAU::%s - flush returned error", __FUNCTION__);
1196 m_DisplayState = VDPAU_ERROR;
1199 m_bufferStats.Reset();
1203 CLog::Log(LOGERROR, "VDPAU::%s - flush timed out", __FUNCTION__);
1204 m_DisplayState = VDPAU_ERROR;
1208 bool CDecoder::CanSkipDeint()
1210 return m_bufferStats.CanSkipDeint();
1213 void CDecoder::ReturnRenderPicture(CVdpauRenderPicture *renderPic)
1215 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic));
1218 bool CDecoder::CheckStatus(VdpStatus vdp_st, int line)
1220 if (vdp_st != VDP_STATUS_OK)
1222 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);
1224 if(m_DisplayState == VDPAU_OPEN)
1226 if (vdp_st == VDP_STATUS_DISPLAY_PREEMPTED)
1228 m_DisplayEvent.Reset();
1229 m_DisplayState = VDPAU_LOST;
1232 m_DisplayState = VDPAU_ERROR;
1240 //-----------------------------------------------------------------------------
1242 //-----------------------------------------------------------------------------
1244 CVdpauRenderPicture* CVdpauRenderPicture::Acquire()
1246 CSingleLock lock(renderPicSection);
1255 long CVdpauRenderPicture::Release()
1257 CSingleLock lock(renderPicSection);
1264 vdpau->ReturnRenderPicture(this);
1265 vdpau->ReleasePicReference();
1270 void CVdpauRenderPicture::ReturnUnused()
1272 { CSingleLock lock(renderPicSection);
1277 vdpau->ReturnRenderPicture(this);
1280 void CVdpauRenderPicture::Sync()
1283 CSingleLock lock(renderPicSection);
1288 glDeleteSync(fence);
1291 fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1296 //-----------------------------------------------------------------------------
1298 //-----------------------------------------------------------------------------
1299 CMixer::CMixer(CEvent *inMsgEvent) :
1300 CThread("Vdpau Mixer"),
1301 m_controlPort("ControlPort", inMsgEvent, &m_outMsgEvent),
1302 m_dataPort("DataPort", inMsgEvent, &m_outMsgEvent)
1304 m_inMsgEvent = inMsgEvent;
1312 void CMixer::Start()
1317 void CMixer::Dispose()
1320 m_outMsgEvent.Set();
1323 m_controlPort.Purge();
1327 bool CMixer::IsActive()
1332 void CMixer::OnStartup()
1334 CLog::Log(LOGNOTICE, "CMixer::OnStartup: Output Thread created");
1337 void CMixer::OnExit()
1339 CLog::Log(LOGNOTICE, "CMixer::OnExit: Output Thread terminated");
1346 M_TOP_UNCONFIGURED, // 2
1347 M_TOP_CONFIGURED, // 3
1348 M_TOP_CONFIGURED_WAIT1, // 4
1349 M_TOP_CONFIGURED_STEP1, // 5
1350 M_TOP_CONFIGURED_WAIT2, // 6
1351 M_TOP_CONFIGURED_STEP2, // 7
1354 int MIXER_parentStates[] = {
1357 0, //TOP_UNCONFIGURED
1359 3, //TOP_CONFIGURED_WAIT1
1360 3, //TOP_CONFIGURED_STEP1
1361 3, //TOP_CONFIGURED_WAIT2
1362 3, //TOP_CONFIGURED_STEP2
1365 void CMixer::StateMachine(int signal, Protocol *port, Message *msg)
1367 for (int state = m_state; ; state = MIXER_parentStates[state])
1372 if (port == &m_controlPort)
1376 case CMixerControlProtocol::FLUSH:
1378 msg->Reply(CMixerControlProtocol::ACC);
1385 std::string portName = port == NULL ? "timer" : port->portName;
1386 CLog::Log(LOGWARNING, "CMixer::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
1390 case M_TOP_ERROR: // TOP
1393 case M_TOP_UNCONFIGURED:
1394 if (port == &m_controlPort)
1398 case CMixerControlProtocol::INIT:
1400 data = (CVdpauConfig*)msg->data;
1408 m_state = M_TOP_CONFIGURED_WAIT1;
1409 msg->Reply(CMixerControlProtocol::ACC);
1413 msg->Reply(CMixerControlProtocol::ERROR);
1422 case M_TOP_CONFIGURED:
1423 if (port == &m_dataPort)
1427 case CMixerDataProtocol::FRAME:
1428 CVdpauDecodedPicture *frame;
1429 frame = (CVdpauDecodedPicture*)msg->data;
1432 m_decodedPics.push(*frame);
1436 case CMixerDataProtocol::BUFFER:
1437 VdpOutputSurface *surf;
1438 surf = (VdpOutputSurface*)msg->data;
1441 m_outputSurfaces.push(*surf);
1451 case M_TOP_CONFIGURED_WAIT1:
1452 if (port == NULL) // timeout
1456 case CMixerControlProtocol::TIMEOUT:
1457 if (!m_decodedPics.empty() && !m_outputSurfaces.empty())
1459 m_state = M_TOP_CONFIGURED_STEP1;
1460 m_bStateMachineSelfTrigger = true;
1473 case M_TOP_CONFIGURED_STEP1:
1474 if (port == NULL) // timeout
1478 case CMixerControlProtocol::TIMEOUT:
1479 m_mixerInput.push_front(m_decodedPics.front());
1480 m_decodedPics.pop();
1481 if (m_mixerInput.size() < 2)
1483 m_state = M_TOP_CONFIGURED_WAIT1;
1491 m_state = M_TOP_CONFIGURED_WAIT1;
1492 m_extTimeout = 1000;
1495 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1496 m_outputSurfaces.pop();
1497 m_config.stats->IncProcessed();
1498 m_config.stats->DecDecoded();
1499 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1500 if (m_mixersteps > 1)
1502 m_state = M_TOP_CONFIGURED_WAIT2;
1508 m_state = M_TOP_CONFIGURED_WAIT1;
1518 case M_TOP_CONFIGURED_WAIT2:
1519 if (port == NULL) // timeout
1523 case CMixerControlProtocol::TIMEOUT:
1524 if (!m_outputSurfaces.empty())
1526 m_state = M_TOP_CONFIGURED_STEP2;
1527 m_bStateMachineSelfTrigger = true;
1540 case M_TOP_CONFIGURED_STEP2:
1541 if (port == NULL) // timeout
1545 case CMixerControlProtocol::TIMEOUT:
1546 m_processPicture.outputSurface = m_outputSurfaces.front();
1551 m_state = M_TOP_CONFIGURED_WAIT1;
1552 m_extTimeout = 1000;
1555 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1556 m_outputSurfaces.pop();
1557 m_config.stats->IncProcessed();
1558 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1560 m_state = M_TOP_CONFIGURED_WAIT1;
1569 default: // we are in no state, should not happen
1570 CLog::Log(LOGERROR, "CMixer::%s - no valid state: %d", __FUNCTION__, m_state);
1576 void CMixer::Process()
1578 Message *msg = NULL;
1579 Protocol *port = NULL;
1582 m_state = M_TOP_UNCONFIGURED;
1583 m_extTimeout = 1000;
1584 m_bStateMachineSelfTrigger = false;
1590 if (m_bStateMachineSelfTrigger)
1592 m_bStateMachineSelfTrigger = false;
1593 // self trigger state machine
1594 StateMachine(msg->signal, port, msg);
1595 if (!m_bStateMachineSelfTrigger)
1602 // check control port
1603 else if (m_controlPort.ReceiveOutMessage(&msg))
1606 port = &m_controlPort;
1609 else if (m_dataPort.ReceiveOutMessage(&msg))
1617 StateMachine(msg->signal, port, msg);
1618 if (!m_bStateMachineSelfTrigger)
1627 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
1634 msg = m_controlPort.GetMessage();
1635 msg->signal = CMixerControlProtocol::TIMEOUT;
1637 // signal timeout to state machine
1638 StateMachine(msg->signal, port, msg);
1639 if (!m_bStateMachineSelfTrigger)
1649 void CMixer::CreateVdpauMixer()
1651 CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer");
1653 InitCSCMatrix(m_config.vidWidth);
1655 VdpVideoMixerParameter parameters[] = {
1656 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
1657 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
1658 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE};
1660 void const * parameter_values[] = {
1661 &m_config.surfaceWidth,
1662 &m_config.surfaceHeight,
1663 &m_config.vdpChromaType};
1665 VdpStatus vdp_st = VDP_STATUS_ERROR;
1666 vdp_st = m_config.context->GetProcs().vdp_video_mixer_create(m_config.context->GetDevice(),
1667 m_config.context->GetFeatureCount(),
1668 m_config.context->GetFeatures(),
1673 CheckStatus(vdp_st, __LINE__);
1675 // create 3 pitches of black lines needed for clipping top
1676 // and bottom lines when de-interlacing
1677 m_BlackBar = new uint32_t[3*m_config.outWidth];
1678 memset(m_BlackBar, 0, 3*m_config.outWidth*sizeof(uint32_t));
1682 void CMixer::InitCSCMatrix(int Width)
1684 m_Procamp.struct_version = VDP_PROCAMP_VERSION;
1685 m_Procamp.brightness = 0.0;
1686 m_Procamp.contrast = 1.0;
1687 m_Procamp.saturation = 1.0;
1691 void CMixer::CheckFeatures()
1693 if (m_Upscale != m_config.upscale)
1696 m_Upscale = m_config.upscale;
1698 if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness ||
1699 m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast ||
1700 m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix)
1703 m_Brightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness;
1704 m_Contrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast;
1705 m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix;
1707 if (m_NoiseReduction != CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1709 m_NoiseReduction = CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction;
1710 SetNoiseReduction();
1712 if (m_Sharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1714 m_Sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
1717 if (m_DeintMode != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode ||
1718 m_Deint != CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod)
1720 m_DeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1721 m_Deint = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1726 void CMixer::SetPostProcFeatures(bool postProcEnabled)
1728 if (m_PostProc != postProcEnabled)
1730 if (postProcEnabled)
1732 SetNoiseReduction();
1739 m_PostProc = postProcEnabled;
1743 void CMixer::PostProcOff()
1747 if (m_videoMixer == VDP_INVALID_HANDLE)
1750 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
1751 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
1752 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE};
1754 VdpBool enabled[]={0,0,0};
1755 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1756 CheckStatus(vdp_st, __LINE__);
1758 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1760 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION};
1762 VdpBool enabled[]={0};
1763 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1764 CheckStatus(vdp_st, __LINE__);
1767 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1769 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS};
1771 VdpBool enabled[]={0};
1772 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1773 CheckStatus(vdp_st, __LINE__);
1779 bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix)
1781 // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4])
1782 // m00 = mRY = red: luma factor (contrast factor) (1.0)
1783 // m10 = mGY = green: luma factor (contrast factor) (1.0)
1784 // m20 = mBY = blue: luma factor (contrast factor) (1.0)
1786 // m01 = mRB = red: blue color diff coeff (0.0)
1787 // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg))
1788 // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5)
1790 // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5)
1791 // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg))
1792 // m22 = mBR = blue: red color diff coeff (0.0)
1794 // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255))
1795 // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg)
1796 // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255))
1807 // colour standard coefficients for red, geen, blue
1809 // colour diff zero position (use standard 8-bit coding precision)
1810 double CDZ = 128; //256*0.5
1811 // range excursion (use standard 8-bit coding precision)
1812 double EXC = 255; //256-1
1814 if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601)
1816 Kr = studioCSCKCoeffs601[0];
1817 Kg = studioCSCKCoeffs601[1];
1818 Kb = studioCSCKCoeffs601[2];
1820 else // assume VDP_COLOR_STANDARD_ITUR_BT_709
1822 Kr = studioCSCKCoeffs709[0];
1823 Kg = studioCSCKCoeffs709[1];
1824 Kb = studioCSCKCoeffs709[2];
1826 // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235
1827 studioCSCMatrix[R][Y] = 1.0;
1828 studioCSCMatrix[G][Y] = 1.0;
1829 studioCSCMatrix[B][Y] = 1.0;
1831 studioCSCMatrix[R][Cb] = 0.0;
1832 studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg;
1833 studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5;
1835 studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5;
1836 studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg;
1837 studioCSCMatrix[B][Cr] = 0.0;
1839 studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC;
1840 studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC;
1841 studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC;
1846 void CMixer::SetColor()
1850 if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)
1851 m_Procamp.brightness = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)-50) / 100;
1852 if (m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)
1853 m_Procamp.contrast = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)+50) / 100;
1855 VdpColorStandard colorStandard;
1856 switch(m_mixerInput[1].DVDPic.color_matrix)
1858 case AVCOL_SPC_BT709:
1859 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1861 case AVCOL_SPC_BT470BG:
1862 case AVCOL_SPC_SMPTE170M:
1863 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1865 case AVCOL_SPC_SMPTE240M:
1866 colorStandard = VDP_COLOR_STANDARD_SMPTE_240M;
1869 case AVCOL_SPC_UNSPECIFIED:
1872 if(m_config.surfaceWidth > 1000)
1873 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1875 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1878 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
1879 if (CSettings::Get().GetBool("videoscreen.limitedrange"))
1881 float studioCSC[3][4];
1882 GenerateStudioCSCMatrix(colorStandard, studioCSC);
1883 void const * pm_CSCMatix[] = { &studioCSC };
1884 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1888 vdp_st = m_config.context->GetProcs().vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix);
1889 void const * pm_CSCMatix[] = { &m_CSCMatrix };
1890 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1893 CheckStatus(vdp_st, __LINE__);
1896 void CMixer::SetNoiseReduction()
1898 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1901 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION };
1902 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL };
1905 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1907 VdpBool enabled[]= {0};
1908 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1909 CheckStatus(vdp_st, __LINE__);
1912 VdpBool enabled[]={1};
1913 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1914 CheckStatus(vdp_st, __LINE__);
1915 void* nr[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction };
1916 CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction);
1917 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, nr);
1918 CheckStatus(vdp_st, __LINE__);
1921 void CMixer::SetSharpness()
1923 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1926 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS };
1927 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL };
1930 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1932 VdpBool enabled[]={0};
1933 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1934 CheckStatus(vdp_st, __LINE__);
1937 VdpBool enabled[]={1};
1938 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1939 CheckStatus(vdp_st, __LINE__);
1940 void* sh[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness };
1941 CLog::Log(LOGNOTICE,"Setting Sharpness to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness);
1942 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, sh);
1943 CheckStatus(vdp_st, __LINE__);
1946 EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */)
1948 EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1949 if (method == VS_INTERLACEMETHOD_AUTO)
1952 // if (m_config.outHeight >= 720)
1953 // deint = g_advancedSettings.m_videoVDPAUdeintHD;
1955 // deint = g_advancedSettings.m_videoVDPAUdeintSD;
1959 if (m_config.vdpau->Supports(EINTERLACEMETHOD(deint)))
1961 method = EINTERLACEMETHOD(deint);
1963 CLog::Log(LOGNOTICE, "CVDPAU::GetDeinterlacingMethod: set de-interlacing to %d", deint);
1968 CLog::Log(LOGWARNING, "CVDPAU::GetDeinterlacingMethod: method for de-interlacing (advanced settings) not supported");
1975 void CMixer::SetDeinterlacing()
1979 if (m_videoMixer == VDP_INVALID_HANDLE)
1982 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1983 EINTERLACEMETHOD method = GetDeinterlacingMethod(true);
1985 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
1986 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
1987 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE };
1989 if (mode == VS_DEINTERLACEMODE_OFF)
1991 VdpBool enabled[] = {0,0,0};
1992 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1996 if (method == VS_INTERLACEMETHOD_AUTO)
1998 VdpBool enabled[] = {1,0,0};
1999 if (g_advancedSettings.m_videoVDPAUtelecine)
2001 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2003 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2004 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF)
2006 VdpBool enabled[] = {1,0,0};
2007 if (g_advancedSettings.m_videoVDPAUtelecine)
2009 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2011 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2012 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF)
2014 VdpBool enabled[] = {1,1,0};
2015 if (g_advancedSettings.m_videoVDPAUtelecine)
2017 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2021 VdpBool enabled[]={0,0,0};
2022 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2025 CheckStatus(vdp_st, __LINE__);
2027 SetDeintSkipChroma();
2029 m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
2032 void CMixer::SetDeintSkipChroma()
2034 VdpVideoMixerAttribute attribute[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE};
2038 if (g_advancedSettings.m_videoVDPAUdeintSkipChromaHD && m_config.outHeight >= 720)
2043 void const *values[]={&val};
2044 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attribute), attribute, values);
2046 CheckStatus(vdp_st, __LINE__);
2049 void CMixer::SetHWUpscaling()
2051 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
2054 VdpBool enabled[]={1};
2055 switch (m_config.upscale)
2058 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
2060 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
2061 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2065 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
2067 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
2068 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2072 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2074 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2075 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2079 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2081 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2082 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2086 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2088 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2089 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2093 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2095 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2096 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2100 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2102 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2103 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2107 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2109 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2110 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2114 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2116 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2117 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2124 CheckStatus(vdp_st, __LINE__);
2128 void CMixer::DisableHQScaling()
2132 if (m_videoMixer == VDP_INVALID_HANDLE)
2135 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2137 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2138 VdpBool enabled[]={0};
2139 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2140 CheckStatus(vdp_st, __LINE__);
2143 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2145 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2146 VdpBool enabled[]={0};
2147 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2148 CheckStatus(vdp_st, __LINE__);
2151 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2153 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2154 VdpBool enabled[]={0};
2155 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2156 CheckStatus(vdp_st, __LINE__);
2159 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2161 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2162 VdpBool enabled[]={0};
2163 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2164 CheckStatus(vdp_st, __LINE__);
2167 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2169 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2170 VdpBool enabled[]={0};
2171 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2172 CheckStatus(vdp_st, __LINE__);
2175 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2177 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2178 VdpBool enabled[]={0};
2179 vdp_st = m_config.context->GetProcs().vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2180 CheckStatus(vdp_st, __LINE__);
2183 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2185 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
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_L8))
2193 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
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_L9))
2201 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
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__);
2212 m_NoiseReduction = 0.0;
2220 m_config.upscale = g_advancedSettings.m_videoVDPAUScaling;
2221 m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
2226 void CMixer::Uninit()
2229 while (!m_outputSurfaces.empty())
2231 m_outputSurfaces.pop();
2233 m_config.context->GetProcs().vdp_video_mixer_destroy(m_videoMixer);
2235 delete [] m_BlackBar;
2238 void CMixer::Flush()
2240 while (!m_mixerInput.empty())
2242 CVdpauDecodedPicture pic = m_mixerInput.back();
2243 m_mixerInput.pop_back();
2244 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2246 while (!m_decodedPics.empty())
2248 CVdpauDecodedPicture pic = m_decodedPics.front();
2249 m_decodedPics.pop();
2250 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2253 while (m_dataPort.ReceiveOutMessage(&msg))
2255 if (msg->signal == CMixerDataProtocol::FRAME)
2257 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2258 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2260 else if (msg->signal == CMixerDataProtocol::BUFFER)
2262 VdpOutputSurface *surf;
2263 surf = (VdpOutputSurface*)msg->data;
2264 m_outputSurfaces.push(*surf);
2270 void CMixer::InitCycle()
2275 m_config.stats->GetParams(latency, flags);
2277 if (0) //flags & DVP_FLAG_NO_POSTPROC)
2278 SetPostProcFeatures(false);
2280 SetPostProcFeatures(true);
2282 m_config.stats->SetCanSkipDeint(false);
2284 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
2285 EINTERLACEMETHOD method = GetDeinterlacingMethod();
2286 bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED;
2289 if (//!(flags & DVP_FLAG_NO_POSTPROC) &&
2290 (mode == VS_DEINTERLACEMODE_FORCE ||
2291 (mode == VS_DEINTERLACEMODE_AUTO && interlaced)))
2293 if((method == VS_INTERLACEMETHOD_AUTO && interlaced)
2294 || method == VS_INTERLACEMETHOD_VDPAU_BOB
2295 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2296 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2297 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2298 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2299 || method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE )
2301 if(method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2302 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2303 || !g_graphicsContext.IsFullScreenVideo())
2308 m_config.stats->SetCanSkipDeint(true);
2312 if (0) //m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_DROPDEINT)
2317 if(m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST)
2318 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2320 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2322 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2323 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2324 DVP_FLAG_REPEAT_TOP_FIELD |
2325 DVP_FLAG_INTERLACED);
2326 m_config.useInteropYuv = false;
2328 else if (method == VS_INTERLACEMETHOD_RENDER_BOB)
2331 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2332 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2333 m_config.useInteropYuv = true;
2337 CLog::Log(LOGERROR, "CMixer::%s - interlace method: %d not supported, setting to AUTO", __FUNCTION__, method);
2339 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2340 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2341 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2342 DVP_FLAG_REPEAT_TOP_FIELD |
2343 DVP_FLAG_INTERLACED);
2345 CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod = VS_INTERLACEMETHOD_AUTO;
2351 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2353 if (m_config.useInteropYuv)
2354 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2357 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2358 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2359 DVP_FLAG_REPEAT_TOP_FIELD |
2360 DVP_FLAG_INTERLACED);
2365 if (m_mixerInput[1].DVDPic.format == RENDER_FMT_VDPAU)
2367 m_processPicture.outputSurface = m_outputSurfaces.front();
2368 m_mixerInput[1].DVDPic.iWidth = m_config.outWidth;
2369 m_mixerInput[1].DVDPic.iHeight = m_config.outHeight;
2373 m_mixerInput[1].DVDPic.iWidth = m_config.vidWidth;
2374 m_mixerInput[1].DVDPic.iHeight = m_config.vidHeight;
2377 m_processPicture.DVDPic = m_mixerInput[1].DVDPic;
2378 m_processPicture.videoSurface = m_mixerInput[1].videoSurface;
2381 void CMixer::FiniCycle()
2383 // Keep video surfaces for one 2 cycles longer than used
2384 // by mixer. This avoids blocking in decoder.
2385 // NVidia recommends num_ref + 5
2386 while (m_mixerInput.size() > 5)
2388 CVdpauDecodedPicture &tmp = m_mixerInput.back();
2389 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
2391 m_config.videoSurfaces->ClearRender(tmp.videoSurface);
2393 m_mixerInput.pop_back();
2397 void CMixer::ProcessPicture()
2399 if (m_processPicture.DVDPic.format == RENDER_FMT_VDPAU_420)
2404 if (m_mixerstep == 1)
2406 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD)
2407 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2409 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2412 VdpVideoSurface past_surfaces[4] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2413 VdpVideoSurface futu_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2414 uint32_t pastCount = 4;
2415 uint32_t futuCount = 2;
2417 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
2419 // use only 2 past 1 future for progressive/weave
2420 // (only used for postproc anyway eg noise reduction)
2421 if (m_mixerInput.size() > 3)
2422 past_surfaces[1] = m_mixerInput[3].videoSurface;
2423 if (m_mixerInput.size() > 2)
2424 past_surfaces[0] = m_mixerInput[2].videoSurface;
2425 futu_surfaces[0] = m_mixerInput[0].videoSurface;
2431 if(m_mixerstep == 0)
2433 if (m_mixerInput.size() > 3)
2435 past_surfaces[3] = m_mixerInput[3].videoSurface;
2436 past_surfaces[2] = m_mixerInput[3].videoSurface;
2438 if (m_mixerInput.size() > 2)
2440 past_surfaces[1] = m_mixerInput[2].videoSurface;
2441 past_surfaces[0] = m_mixerInput[2].videoSurface;
2443 futu_surfaces[0] = m_mixerInput[1].videoSurface;
2444 futu_surfaces[1] = m_mixerInput[0].videoSurface;
2448 if (m_mixerInput.size() > 3)
2450 past_surfaces[3] = m_mixerInput[3].videoSurface;
2452 if (m_mixerInput.size() > 2)
2454 past_surfaces[2] = m_mixerInput[2].videoSurface;
2455 past_surfaces[1] = m_mixerInput[2].videoSurface;
2457 past_surfaces[0] = m_mixerInput[1].videoSurface;
2458 futu_surfaces[0] = m_mixerInput[1].videoSurface;
2459 futu_surfaces[1] = m_mixerInput[1].videoSurface;
2461 if (m_mixerInput[0].DVDPic.pts != DVD_NOPTS_VALUE &&
2462 m_mixerInput[1].DVDPic.pts != DVD_NOPTS_VALUE)
2464 m_processPicture.DVDPic.pts = m_mixerInput[1].DVDPic.pts +
2465 (m_mixerInput[0].DVDPic.pts -
2466 m_mixerInput[1].DVDPic.pts) / 2;
2469 m_processPicture.DVDPic.pts = DVD_NOPTS_VALUE;
2470 m_processPicture.DVDPic.dts = DVD_NOPTS_VALUE;
2472 m_processPicture.DVDPic.iRepeatPicture = 0.0;
2478 sourceRect.x1 = m_config.vidWidth;
2479 sourceRect.y1 = m_config.vidHeight;
2484 destRect.x1 = m_config.outWidth;
2485 destRect.y1 = m_config.outHeight;
2487 // start vdpau video mixer
2488 vdp_st = m_config.context->GetProcs().vdp_video_mixer_render(m_videoMixer,
2494 m_mixerInput[1].videoSurface,
2498 m_processPicture.outputSurface,
2503 CheckStatus(vdp_st, __LINE__);
2505 if (m_mixerfield != VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
2507 // in order to clip top and bottom lines when de-interlacing
2508 // we black those lines as a work around for not working
2509 // background colour using the mixer
2510 // pixel perfect is preferred over overscanning or zooming
2512 VdpRect clipRect = destRect;
2513 clipRect.y1 = clipRect.y0 + 2;
2514 uint32_t *data[] = {m_BlackBar};
2515 uint32_t pitches[] = {destRect.x1};
2516 vdp_st = m_config.context->GetProcs().vdp_output_surface_put_bits_native(m_processPicture.outputSurface,
2520 CheckStatus(vdp_st, __LINE__);
2522 clipRect = destRect;
2523 clipRect.y0 = clipRect.y1 - 2;
2524 vdp_st = m_config.context->GetProcs().vdp_output_surface_put_bits_native(m_processPicture.outputSurface,
2528 CheckStatus(vdp_st, __LINE__);
2533 bool CMixer::CheckStatus(VdpStatus vdp_st, int line)
2535 if (vdp_st != VDP_STATUS_OK)
2537 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);
2544 //-----------------------------------------------------------------------------
2546 //-----------------------------------------------------------------------------
2548 VdpauBufferPool::VdpauBufferPool()
2550 CVdpauRenderPicture *pic;
2551 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2553 pic = new CVdpauRenderPicture(renderPicSec);
2554 allRenderPics.push_back(pic);
2558 VdpauBufferPool::~VdpauBufferPool()
2560 CVdpauRenderPicture *pic;
2561 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2563 pic = allRenderPics[i];
2566 allRenderPics.clear();
2569 //-----------------------------------------------------------------------------
2571 //-----------------------------------------------------------------------------
2572 COutput::COutput(CEvent *inMsgEvent) :
2573 CThread("Vdpau Output"),
2574 m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent),
2575 m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent),
2576 m_mixer(&m_outMsgEvent)
2578 m_inMsgEvent = inMsgEvent;
2580 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i)
2582 m_bufferPool.freeRenderPics.push_back(i);
2586 void COutput::Start()
2595 m_bufferPool.freeRenderPics.clear();
2596 m_bufferPool.usedRenderPics.clear();
2599 void COutput::Dispose()
2601 CSingleLock lock(g_graphicsContext);
2603 m_outMsgEvent.Set();
2605 m_controlPort.Purge();
2609 void COutput::OnStartup()
2611 CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created");
2614 void COutput::OnExit()
2616 CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated");
2623 O_TOP_UNCONFIGURED, // 2
2624 O_TOP_CONFIGURED, // 3
2625 O_TOP_CONFIGURED_IDLE, // 4
2626 O_TOP_CONFIGURED_WORK, // 5
2629 int VDPAU_OUTPUT_parentStates[] = {
2632 0, //TOP_UNCONFIGURED
2634 3, //TOP_CONFIGURED_IDLE
2635 3, //TOP_CONFIGURED_WORK
2638 void COutput::StateMachine(int signal, Protocol *port, Message *msg)
2640 for (int state = m_state; ; state = VDPAU_OUTPUT_parentStates[state])
2645 if (port == &m_controlPort)
2649 case COutputControlProtocol::FLUSH:
2650 msg->Reply(COutputControlProtocol::ACC);
2652 case COutputControlProtocol::PRECLEANUP:
2653 msg->Reply(COutputControlProtocol::ACC);
2659 else if (port == &m_dataPort)
2663 case COutputDataProtocol::RETURNPIC:
2664 CVdpauRenderPicture *pic;
2665 pic = *((CVdpauRenderPicture**)msg->data);
2666 QueueReturnPicture(pic);
2673 std::string portName = port == NULL ? "timer" : port->portName;
2674 CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
2681 case O_TOP_UNCONFIGURED:
2682 if (port == &m_controlPort)
2686 case COutputControlProtocol::INIT:
2688 data = (CVdpauConfig*)msg->data;
2695 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::INIT,
2696 &reply, 1000, &m_config, sizeof(m_config)))
2698 if (reply->signal != CMixerControlProtocol::ACC)
2703 // set initial number of
2704 m_bufferPool.numOutputSurfaces = 4;
2708 m_state = O_TOP_CONFIGURED_IDLE;
2709 msg->Reply(COutputControlProtocol::ACC, &m_config, sizeof(m_config));
2713 m_state = O_TOP_ERROR;
2714 msg->Reply(COutputControlProtocol::ERROR);
2723 case O_TOP_CONFIGURED:
2724 if (port == &m_controlPort)
2728 case COutputControlProtocol::FLUSH:
2730 msg->Reply(COutputControlProtocol::ACC);
2732 case COutputControlProtocol::PRECLEANUP:
2735 msg->Reply(COutputControlProtocol::ACC);
2741 else if (port == &m_dataPort)
2745 case COutputDataProtocol::NEWFRAME:
2746 CVdpauDecodedPicture *frame;
2747 frame = (CVdpauDecodedPicture*)msg->data;
2750 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::FRAME,
2751 frame,sizeof(CVdpauDecodedPicture));
2754 case COutputDataProtocol::RETURNPIC:
2755 CVdpauRenderPicture *pic;
2756 pic = *((CVdpauRenderPicture**)msg->data);
2757 QueueReturnPicture(pic);
2758 m_controlPort.SendInMessage(COutputControlProtocol::STATS);
2759 m_state = O_TOP_CONFIGURED_WORK;
2766 else if (port == &m_mixer.m_dataPort)
2770 case CMixerDataProtocol::PICTURE:
2771 CVdpauProcessedPicture *pic;
2772 pic = (CVdpauProcessedPicture*)msg->data;
2773 m_bufferPool.processedPics.push(*pic);
2774 m_state = O_TOP_CONFIGURED_WORK;
2783 case O_TOP_CONFIGURED_IDLE:
2784 if (port == NULL) // timeout
2788 case COutputControlProtocol::TIMEOUT:
2789 if (ProcessSyncPicture())
2795 m_state = O_TOP_CONFIGURED_WORK;
2805 case O_TOP_CONFIGURED_WORK:
2806 if (port == NULL) // timeout
2810 case COutputControlProtocol::TIMEOUT:
2813 CVdpauRenderPicture *pic;
2814 pic = ProcessMixerPicture();
2817 m_config.stats->DecProcessed();
2818 m_config.stats->IncRender();
2819 m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic));
2825 m_state = O_TOP_CONFIGURED_IDLE;
2835 default: // we are in no state, should not happen
2836 CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state);
2842 void COutput::Process()
2844 Message *msg = NULL;
2845 Protocol *port = NULL;
2848 m_state = O_TOP_UNCONFIGURED;
2849 m_extTimeout = 1000;
2850 m_bStateMachineSelfTrigger = false;
2856 if (m_bStateMachineSelfTrigger)
2858 m_bStateMachineSelfTrigger = false;
2859 // self trigger state machine
2860 StateMachine(msg->signal, port, msg);
2861 if (!m_bStateMachineSelfTrigger)
2868 // check control port
2869 else if (m_controlPort.ReceiveOutMessage(&msg))
2872 port = &m_controlPort;
2875 else if (m_dataPort.ReceiveOutMessage(&msg))
2880 // check mixer data port
2881 else if (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2884 port = &m_mixer.m_dataPort;
2888 StateMachine(msg->signal, port, msg);
2889 if (!m_bStateMachineSelfTrigger)
2898 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
2905 msg = m_controlPort.GetMessage();
2906 msg->signal = COutputControlProtocol::TIMEOUT;
2908 // signal timeout to state machine
2909 StateMachine(msg->signal, port, msg);
2910 if (!m_bStateMachineSelfTrigger)
2921 bool COutput::Init()
2923 if (!CreateGlxContext())
2935 bool COutput::Uninit()
2939 ReleaseBufferPool();
2940 DestroyGlxContext();
2944 void COutput::Flush()
2946 if (m_mixer.IsActive())
2949 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH,
2956 CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__);
2960 while (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2962 if (msg->signal == CMixerDataProtocol::PICTURE)
2964 CVdpauProcessedPicture pic = *(CVdpauProcessedPicture*)msg->data;
2965 m_bufferPool.processedPics.push(pic);
2970 while (m_dataPort.ReceiveOutMessage(&msg))
2972 if (msg->signal == COutputDataProtocol::NEWFRAME)
2974 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2975 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2977 else if (msg->signal == COutputDataProtocol::RETURNPIC)
2979 CVdpauRenderPicture *pic;
2980 pic = *((CVdpauRenderPicture**)msg->data);
2981 QueueReturnPicture(pic);
2986 while (m_dataPort.ReceiveInMessage(&msg))
2988 if (msg->signal == COutputDataProtocol::PICTURE)
2990 CVdpauRenderPicture *pic;
2991 pic = *((CVdpauRenderPicture**)msg->data);
2992 QueueReturnPicture(pic);
2996 // reset used render flag which was cleared on mixer flush
2997 std::deque<int>::iterator it;
2998 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3000 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[*it];
3001 if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3003 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it2;
3004 it2 = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3005 if (it2 == m_bufferPool.glVideoSurfaceMap.end())
3007 CLog::Log(LOGDEBUG, "COutput::Flush - gl surface not found");
3010 m_config.videoSurfaces->MarkRender(it2->second.sourceVuv);
3014 // clear processed pics
3015 while(!m_bufferPool.processedPics.empty())
3017 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
3018 if (procPic.DVDPic.format == RENDER_FMT_VDPAU)
3020 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &procPic.outputSurface, sizeof(procPic.outputSurface));
3022 else if (procPic.DVDPic.format == RENDER_FMT_VDPAU_420)
3024 m_config.videoSurfaces->ClearRender(procPic.videoSurface);
3026 m_bufferPool.processedPics.pop();
3030 bool COutput::HasWork()
3032 if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
3037 CVdpauRenderPicture* COutput::ProcessMixerPicture()
3039 CVdpauRenderPicture *retPic = NULL;
3041 if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
3043 int idx = m_bufferPool.freeRenderPics.front();
3044 retPic = m_bufferPool.allRenderPics[idx];
3045 m_bufferPool.freeRenderPics.pop_front();
3046 m_bufferPool.usedRenderPics.push_back(idx);
3047 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
3048 m_bufferPool.processedPics.pop();
3050 retPic->DVDPic = procPic.DVDPic;
3051 retPic->valid = true;
3052 if (retPic->DVDPic.format == RENDER_FMT_VDPAU)
3054 m_config.useInteropYuv = false;
3055 m_bufferPool.numOutputSurfaces = NUM_RENDER_PICS;
3058 retPic->sourceIdx = procPic.outputSurface;
3059 retPic->texture[0] = m_bufferPool.glOutputSurfaceMap[procPic.outputSurface].texture[0];
3060 retPic->crop = CRect(0,0,0,0);
3064 m_config.useInteropYuv = true;
3066 retPic->sourceIdx = procPic.videoSurface;
3067 for (unsigned int i=0; i<4; ++i)
3068 retPic->texture[i] = m_bufferPool.glVideoSurfaceMap[procPic.videoSurface].texture[i];
3069 retPic->texWidth = m_config.surfaceWidth;
3070 retPic->texHeight = m_config.surfaceHeight;
3071 retPic->crop.x1 = 0;
3072 retPic->crop.y1 = 0;
3073 retPic->crop.x2 = m_config.surfaceWidth - m_config.vidWidth;
3074 retPic->crop.y2 = m_config.surfaceHeight - m_config.vidHeight;
3080 void COutput::QueueReturnPicture(CVdpauRenderPicture *pic)
3082 std::deque<int>::iterator it;
3083 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3085 if (m_bufferPool.allRenderPics[*it] == pic)
3091 if (it == m_bufferPool.usedRenderPics.end())
3093 CLog::Log(LOGWARNING, "COutput::QueueReturnPicture - pic not found");
3097 // check if already queued
3098 std::deque<int>::iterator it2 = find(m_bufferPool.syncRenderPics.begin(),
3099 m_bufferPool.syncRenderPics.end(),
3101 if (it2 == m_bufferPool.syncRenderPics.end())
3103 m_bufferPool.syncRenderPics.push_back(*it);
3106 ProcessSyncPicture();
3109 bool COutput::ProcessSyncPicture()
3111 CVdpauRenderPicture *pic;
3114 std::deque<int>::iterator it;
3115 for (it = m_bufferPool.syncRenderPics.begin(); it != m_bufferPool.syncRenderPics.end(); )
3117 pic = m_bufferPool.allRenderPics[*it];
3122 if (glIsSync(pic->fence))
3126 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3127 if(state == GL_SIGNALED)
3129 glDeleteSync(pic->fence);
3142 m_bufferPool.freeRenderPics.push_back(*it);
3144 std::deque<int>::iterator it2 = find(m_bufferPool.usedRenderPics.begin(),
3145 m_bufferPool.usedRenderPics.end(),
3147 if (it2 == m_bufferPool.usedRenderPics.end())
3149 CLog::Log(LOGERROR, "COutput::ProcessSyncPicture - pic not found in queue");
3153 m_bufferPool.usedRenderPics.erase(it2);
3155 it = m_bufferPool.syncRenderPics.erase(it);
3159 ProcessReturnPicture(pic);
3163 CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__);
3169 void COutput::ProcessReturnPicture(CVdpauRenderPicture *pic)
3171 if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3173 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3174 it = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3175 if (it == m_bufferPool.glVideoSurfaceMap.end())
3177 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3180 VdpVideoSurface surf = it->second.sourceVuv;
3181 m_config.videoSurfaces->ClearRender(surf);
3183 else if (pic->DVDPic.format == RENDER_FMT_VDPAU)
3185 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3186 it = m_bufferPool.glOutputSurfaceMap.find(pic->sourceIdx);
3187 if (it == m_bufferPool.glOutputSurfaceMap.end())
3189 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3192 VdpOutputSurface outSurf = it->second.sourceRgb;
3193 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &outSurf, sizeof(outSurf));
3197 bool COutput::EnsureBufferPool()
3201 // Creation of outputSurfaces
3202 VdpOutputSurface outputSurface;
3203 for (int i = m_bufferPool.outputSurfaces.size(); i < m_bufferPool.numOutputSurfaces; i++)
3205 vdp_st = m_config.context->GetProcs().vdp_output_surface_create(m_config.context->GetDevice(),
3206 VDP_RGBA_FORMAT_B8G8R8A8,
3210 if (CheckStatus(vdp_st, __LINE__))
3212 m_bufferPool.outputSurfaces.push_back(outputSurface);
3214 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3216 sizeof(VdpOutputSurface));
3217 CLog::Log(LOGNOTICE, "VDPAU::COutput::InitBufferPool - Output Surface created");
3222 void COutput::ReleaseBufferPool()
3226 CSingleLock lock(m_bufferPool.renderPicSec);
3228 // release all output surfaces
3229 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3231 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3233 vdp_st = m_config.context->GetProcs().vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3234 CheckStatus(vdp_st, __LINE__);
3236 m_bufferPool.outputSurfaces.clear();
3238 // wait for all fences
3239 XbmcThreads::EndTime timeout(1000);
3240 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3242 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[i];
3246 while (glIsSync(pic->fence))
3250 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3251 if(state == GL_SIGNALED || timeout.IsTimePast())
3253 glDeleteSync(pic->fence);
3264 if (timeout.IsTimePast())
3266 CLog::Log(LOGERROR, "COutput::%s - timeout waiting for fence", __FUNCTION__);
3268 ProcessSyncPicture();
3270 // invalidate all used render pictures
3271 for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i)
3273 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[m_bufferPool.usedRenderPics[i]];
3278 void COutput::PreCleanup()
3284 ProcessSyncPicture();
3286 CSingleLock lock(m_bufferPool.renderPicSec);
3287 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3289 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3292 // check if output surface is in use
3294 std::deque<int>::iterator it;
3295 CVdpauRenderPicture *pic;
3296 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3298 pic = m_bufferPool.allRenderPics[*it];
3299 if ((pic->sourceIdx == m_bufferPool.outputSurfaces[i]) && pic->valid)
3308 #ifdef GL_NV_vdpau_interop
3310 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it_map;
3311 it_map = m_bufferPool.glOutputSurfaceMap.find(m_bufferPool.outputSurfaces[i]);
3312 if (it_map == m_bufferPool.glOutputSurfaceMap.end())
3314 CLog::Log(LOGERROR, "%s - could not find gl surface", __FUNCTION__);
3317 glVDPAUUnregisterSurfaceNV(it_map->second.glVdpauSurface);
3318 glDeleteTextures(1, it_map->second.texture);
3319 m_bufferPool.glOutputSurfaceMap.erase(it_map);
3322 vdp_st = m_config.context->GetProcs().vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3323 CheckStatus(vdp_st, __LINE__);
3325 m_bufferPool.outputSurfaces[i] = VDP_INVALID_HANDLE;
3327 CLog::Log(LOGDEBUG, "VDPAU::PreCleanup - released output surface");
3332 void COutput::InitMixer()
3334 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3336 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3337 &m_bufferPool.outputSurfaces[i],
3338 sizeof(VdpOutputSurface));
3342 bool COutput::GLInit()
3344 #ifdef GL_NV_vdpau_interop
3345 glVDPAUInitNV = NULL;
3346 glVDPAUFiniNV = NULL;
3347 glVDPAURegisterOutputSurfaceNV = NULL;
3348 glVDPAURegisterVideoSurfaceNV = NULL;
3349 glVDPAUIsSurfaceNV = NULL;
3350 glVDPAUUnregisterSurfaceNV = NULL;
3351 glVDPAUSurfaceAccessNV = NULL;
3352 glVDPAUMapSurfacesNV = NULL;
3353 glVDPAUUnmapSurfacesNV = NULL;
3354 glVDPAUGetSurfaceivNV = NULL;
3357 #ifdef GL_NV_vdpau_interop
3358 if (glewIsSupported("GL_NV_vdpau_interop"))
3361 glVDPAUInitNV = (PFNGLVDPAUINITNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUInitNV");
3363 glVDPAUFiniNV = (PFNGLVDPAUFININVPROC)glXGetProcAddress((GLubyte *) "glVDPAUFiniNV");
3364 if (!glVDPAURegisterOutputSurfaceNV)
3365 glVDPAURegisterOutputSurfaceNV = (PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterOutputSurfaceNV");
3366 if (!glVDPAURegisterVideoSurfaceNV)
3367 glVDPAURegisterVideoSurfaceNV = (PFNGLVDPAUREGISTERVIDEOSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterVideoSurfaceNV");
3368 if (!glVDPAUIsSurfaceNV)
3369 glVDPAUIsSurfaceNV = (PFNGLVDPAUISSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUIsSurfaceNV");
3370 if (!glVDPAUUnregisterSurfaceNV)
3371 glVDPAUUnregisterSurfaceNV = (PFNGLVDPAUUNREGISTERSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnregisterSurfaceNV");
3372 if (!glVDPAUSurfaceAccessNV)
3373 glVDPAUSurfaceAccessNV = (PFNGLVDPAUSURFACEACCESSNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUSurfaceAccessNV");
3374 if (!glVDPAUMapSurfacesNV)
3375 glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUMapSurfacesNV");
3376 if (!glVDPAUUnmapSurfacesNV)
3377 glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnmapSurfacesNV");
3378 if (!glVDPAUGetSurfaceivNV)
3379 glVDPAUGetSurfaceivNV = (PFNGLVDPAUGETSURFACEIVNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUGetSurfaceivNV");
3381 CLog::Log(LOGNOTICE, "VDPAU::COutput GL interop supported");
3386 // TODO should be detected before vdpau is opened, though very unlikely
3387 // that this code is hit
3388 CLog::Log(LOGERROR, "VDPAU::COutput driver does not support GL_NV_vdpau_interop");
3391 #ifdef GL_NV_vdpau_interop
3392 while (glGetError() != GL_NO_ERROR);
3393 glVDPAUInitNV(reinterpret_cast<void*>(m_config.context->GetDevice()), reinterpret_cast<void*>(m_config.context->GetProcs().vdp_get_proc_address));
3394 if (glGetError() != GL_NO_ERROR)
3396 CLog::Log(LOGERROR, "VDPAU::COutput - GLInitInterop glVDPAUInitNV failed");
3400 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop initialized");
3404 bool hasfence = glewIsSupported("GL_ARB_sync");
3405 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3407 m_bufferPool.allRenderPics[i]->usefence = hasfence;
3414 void COutput::GLMapSurfaces()
3416 #ifdef GL_NV_vdpau_interop
3418 if (m_config.useInteropYuv)
3420 VdpauBufferPool::GLVideoSurface glSurface;
3421 VdpVideoSurface surf;
3422 if (m_config.videoSurfaces->Size() != m_bufferPool.glVideoSurfaceMap.size())
3424 for (unsigned int i = 0; i < m_config.videoSurfaces->Size(); i++)
3426 surf = m_config.videoSurfaces->GetAtIndex(i);
3428 if (surf == VDP_INVALID_HANDLE)
3431 if (m_bufferPool.glVideoSurfaceMap.find(surf) == m_bufferPool.glVideoSurfaceMap.end())
3433 glSurface.sourceVuv = surf;
3434 while (glGetError() != GL_NO_ERROR) ;
3435 glGenTextures(4, glSurface.texture);
3436 if (glGetError() != GL_NO_ERROR)
3438 CLog::Log(LOGERROR, "VDPAU::COutput error creating texture");
3441 glSurface.glVdpauSurface = glVDPAURegisterVideoSurfaceNV(reinterpret_cast<void*>(surf),
3442 GL_TEXTURE_2D, 4, glSurface.texture);
3444 if (glGetError() != GL_NO_ERROR)
3446 CLog::Log(LOGERROR, "VDPAU::COutput error register video surface");
3449 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3450 if (glGetError() != GL_NO_ERROR)
3452 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3455 glVDPAUMapSurfacesNV(1, &glSurface.glVdpauSurface);
3456 if (glGetError() != GL_NO_ERROR)
3458 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3461 m_bufferPool.glVideoSurfaceMap[surf] = glSurface;
3464 CLog::Log(LOGNOTICE, "VDPAU::COutput registered surface");
3471 if (m_bufferPool.glOutputSurfaceMap.size() != m_bufferPool.numOutputSurfaces)
3473 VdpauBufferPool::GLVideoSurface glSurface;
3474 for (unsigned int i = m_bufferPool.glOutputSurfaceMap.size(); i<m_bufferPool.outputSurfaces.size(); i++)
3476 glSurface.sourceRgb = m_bufferPool.outputSurfaces[i];
3477 glGenTextures(1, glSurface.texture);
3478 glSurface.glVdpauSurface = glVDPAURegisterOutputSurfaceNV(reinterpret_cast<void*>(m_bufferPool.outputSurfaces[i]),
3479 GL_TEXTURE_2D, 1, glSurface.texture);
3480 if (glGetError() != GL_NO_ERROR)
3482 CLog::Log(LOGERROR, "VDPAU::COutput error register output surface");
3485 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3486 if (glGetError() != GL_NO_ERROR)
3488 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3491 glVDPAUMapSurfacesNV(1, &glSurface.glVdpauSurface);
3492 if (glGetError() != GL_NO_ERROR)
3494 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3497 m_bufferPool.glOutputSurfaceMap[m_bufferPool.outputSurfaces[i]] = glSurface;
3501 CLog::Log(LOGNOTICE, "VDPAU::COutput registered output surfaces");
3507 void COutput::GLUnmapSurfaces()
3509 #ifdef GL_NV_vdpau_interop
3512 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3513 for (it = m_bufferPool.glVideoSurfaceMap.begin(); it != m_bufferPool.glVideoSurfaceMap.end(); ++it)
3515 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3516 glDeleteTextures(4, it->second.texture);
3518 m_bufferPool.glVideoSurfaceMap.clear();
3521 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3522 for (it = m_bufferPool.glOutputSurfaceMap.begin(); it != m_bufferPool.glOutputSurfaceMap.end(); ++it)
3524 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3525 glDeleteTextures(1, it->second.texture);
3527 m_bufferPool.glOutputSurfaceMap.clear();
3531 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop finished");
3536 bool COutput::CheckStatus(VdpStatus vdp_st, int line)
3538 if (vdp_st != VDP_STATUS_OK)
3540 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);
3547 bool COutput::CreateGlxContext()
3549 GLXContext glContext;
3551 m_Display = g_Windowing.GetDisplay();
3552 glContext = g_Windowing.GetGlxContext();
3553 m_Window = g_Windowing.GetWindow();
3555 // Get our window attribs.
3556 XWindowAttributes wndattribs;
3557 XGetWindowAttributes(m_Display, m_Window, &wndattribs);
3560 XVisualInfo visInfo;
3561 visInfo.visualid = wndattribs.visual->visualid;
3563 XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals);
3566 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - could not find visual");
3569 visInfo = visuals[0];
3572 m_pixmap = XCreatePixmap(m_Display,
3579 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - Unable to create XPixmap");
3584 m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap);
3588 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not create glPixmap");
3592 m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True);
3594 if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext))
3596 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not make Pixmap current");
3600 CLog::Log(LOGNOTICE, "VDPAU::COutput::CreateGlxContext - created context");
3604 bool COutput::DestroyGlxContext()
3608 glXMakeCurrent(m_Display, None, NULL);
3609 glXDestroyContext(m_Display, m_glContext);
3614 glXDestroyPixmap(m_Display, m_glPixmap);
3618 XFreePixmap(m_Display, m_pixmap);