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 9
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 //since libvdpau 0.4, vdp_device_create_x11() installs a callback on the Display*,
78 //if we unload libvdpau with dlclose(), we segfault on XCloseDisplay,
79 //so we just keep a static handle to libvdpau around
80 void* CDecoder::dl_handle;
82 //-----------------------------------------------------------------------------
83 // VDPAU Video Surface states
84 //-----------------------------------------------------------------------------
86 #define SURFACE_USED_FOR_REFERENCE 0x01
87 #define SURFACE_USED_FOR_RENDER 0x02
89 void CVideoSurfaces::AddSurface(VdpVideoSurface surf)
91 CSingleLock lock(m_section);
92 m_state[surf] = SURFACE_USED_FOR_REFERENCE;
95 void CVideoSurfaces::ClearReference(VdpVideoSurface surf)
97 CSingleLock lock(m_section);
98 if (m_state.find(surf) == m_state.end())
100 CLog::Log(LOGWARNING, "CVideoSurfaces::ClearReference - surface invalid");
103 m_state[surf] &= ~SURFACE_USED_FOR_REFERENCE;
104 if (m_state[surf] == 0)
106 m_freeSurfaces.push_back(surf);
110 bool CVideoSurfaces::MarkRender(VdpVideoSurface surf)
112 CSingleLock lock(m_section);
113 if (m_state.find(surf) == m_state.end())
115 CLog::Log(LOGWARNING, "CVideoSurfaces::MarkRender - surface invalid");
118 std::list<VdpVideoSurface>::iterator it;
119 it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
120 if (it != m_freeSurfaces.end())
122 m_freeSurfaces.erase(it);
124 m_state[surf] |= SURFACE_USED_FOR_RENDER;
128 void CVideoSurfaces::ClearRender(VdpVideoSurface surf)
130 CSingleLock lock(m_section);
131 if (m_state.find(surf) == m_state.end())
133 CLog::Log(LOGWARNING, "CVideoSurfaces::ClearRender - surface invalid");
136 m_state[surf] &= ~SURFACE_USED_FOR_RENDER;
137 if (m_state[surf] == 0)
139 m_freeSurfaces.push_back(surf);
143 bool CVideoSurfaces::IsValid(VdpVideoSurface surf)
145 CSingleLock lock(m_section);
146 if (m_state.find(surf) != m_state.end())
152 VdpVideoSurface CVideoSurfaces::GetFree(VdpVideoSurface surf)
154 CSingleLock lock(m_section);
155 if (m_state.find(surf) != m_state.end())
157 std::list<VdpVideoSurface>::iterator it;
158 it = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
159 if (it == m_freeSurfaces.end())
161 CLog::Log(LOGWARNING, "CVideoSurfaces::GetFree - surface not free");
165 m_freeSurfaces.erase(it);
166 m_state[surf] = SURFACE_USED_FOR_REFERENCE;
171 if (!m_freeSurfaces.empty())
173 VdpVideoSurface freeSurf = m_freeSurfaces.front();
174 m_freeSurfaces.pop_front();
175 m_state[freeSurf] = SURFACE_USED_FOR_REFERENCE;
179 return VDP_INVALID_HANDLE;
182 VdpVideoSurface CVideoSurfaces::GetAtIndex(int idx)
184 if (idx >= m_state.size())
185 return VDP_INVALID_HANDLE;
187 std::map<VdpVideoSurface, int>::iterator it = m_state.begin();
188 for(int i = 0; i < idx; i++)
193 VdpVideoSurface CVideoSurfaces::RemoveNext(bool skiprender)
195 CSingleLock lock(m_section);
196 VdpVideoSurface surf;
197 std::map<VdpVideoSurface, int>::iterator it;
198 for(it = m_state.begin(); it != m_state.end(); ++it)
200 if (skiprender && it->second & SURFACE_USED_FOR_RENDER)
205 std::list<VdpVideoSurface>::iterator it2;
206 it2 = std::find(m_freeSurfaces.begin(), m_freeSurfaces.end(), surf);
207 if (it2 != m_freeSurfaces.end())
208 m_freeSurfaces.erase(it2);
211 return VDP_INVALID_HANDLE;
214 void CVideoSurfaces::Reset()
216 CSingleLock lock(m_section);
217 m_freeSurfaces.clear();
221 int CVideoSurfaces::Size()
223 CSingleLock lock(m_section);
224 return m_state.size();
227 //-----------------------------------------------------------------------------
229 //-----------------------------------------------------------------------------
231 CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent)
233 m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
234 m_vdpauConfig.videoSurfaces = &m_videoSurfaces;
236 m_vdpauConfigured = false;
237 m_hwContext.bitstream_buffers_allocated = 0;
238 m_DisplayState = VDPAU_OPEN;
241 bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces)
243 if(avctx->coded_width == 0
244 || avctx->coded_height == 0)
246 CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init");
249 m_vdpauConfig.numRenderBuffers = surfaces;
250 m_decoderThread = CThread::GetCurrentThreadId();
252 if ((avctx->codec_id == AV_CODEC_ID_MPEG4) && !g_advancedSettings.m_videoAllowMpeg4VDPAU)
257 dl_handle = dlopen("libvdpau.so.1", RTLD_LAZY);
260 const char* error = dlerror();
262 error = "dlerror() returned NULL";
264 CLog::Log(LOGNOTICE,"(VDPAU) Unable to get handle to libvdpau: %s", error);
269 if (!m_dllAvUtil.Load())
273 m_presentPicture = 0;
275 if (m_vdpauConfig.vdpDevice != VDP_INVALID_HANDLE)
277 SpewHardwareAvailable();
279 VdpDecoderProfile profile = 0;
280 if(avctx->codec_id == AV_CODEC_ID_H264)
281 profile = VDP_DECODER_PROFILE_H264_HIGH;
282 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
283 else if(avctx->codec_id == AV_CODEC_ID_MPEG4)
284 profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
288 if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width))
289 CLog::Log(LOGWARNING,"(VDPAU) width %i might not be supported because of hardware bug", avctx->width);
291 /* attempt to create a decoder with this width/height, some sizes are not supported by hw */
293 vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_create(m_vdpauConfig.vdpDevice, profile, avctx->coded_width, avctx->coded_height, 5, &m_vdpauConfig.vdpDecoder);
295 if(vdp_st != VDP_STATUS_OK)
297 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", m_vdpauConfig.vdpProcs.vdp_get_error_string(vdp_st), vdp_st);
302 m_vdpauConfig.vdpProcs.vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
303 CheckStatus(vdp_st, __LINE__);
306 /* finally setup ffmpeg */
307 memset(&m_hwContext, 0, sizeof(AVVDPAUContext));
308 m_hwContext.render = CDecoder::Render;
309 m_hwContext.bitstream_buffers_allocated = 0;
310 avctx->get_buffer = CDecoder::FFGetBuffer;
311 avctx->reget_buffer = CDecoder::FFGetBuffer;
312 avctx->release_buffer = CDecoder::FFReleaseBuffer;
313 avctx->draw_horiz_band = CDecoder::FFDrawSlice;
314 avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
315 avctx->hwaccel_context = &m_hwContext;
316 avctx->thread_count = 1;
318 g_Windowing.Register(this);
324 CDecoder::~CDecoder()
329 void CDecoder::Close()
331 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
333 g_Windowing.Unregister(this);
335 CSingleLock lock(m_DecoderSection);
339 m_vdpauOutput.Dispose();
341 if (m_hwContext.bitstream_buffers_allocated)
343 m_dllAvUtil.av_freep(&m_hwContext.bitstream_buffers);
346 m_dllAvUtil.Unload();
349 long CDecoder::Release()
351 // check if we should do some pre-cleanup here
352 // a second decoder might need resources
353 if (m_vdpauConfigured == true)
355 CSingleLock lock(m_DecoderSection);
356 CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup");
359 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP,
363 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
367 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup returned error", __FUNCTION__);
368 m_DisplayState = VDPAU_ERROR;
373 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup timed out", __FUNCTION__);
374 m_DisplayState = VDPAU_ERROR;
377 VdpVideoSurface surf;
378 while((surf = m_videoSurfaces.RemoveNext(true)) != VDP_INVALID_HANDLE)
380 m_vdpauConfig.vdpProcs.vdp_video_surface_destroy(surf);
383 return IHardwareDecoder::Release();
386 long CDecoder::ReleasePicReference()
388 return IHardwareDecoder::Release();
391 void CDecoder::SetWidthHeight(int width, int height)
393 m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling;
395 //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate
396 //this requires the least amount of gpu memory bandwidth
397 if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || m_vdpauConfig.upscale >= 0)
399 //scale width to desktop size if the aspect ratio is the same or bigger than the desktop
400 if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight())
402 m_vdpauConfig.outWidth = g_graphicsContext.GetWidth();
403 m_vdpauConfig.outHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width);
405 else //scale height to the desktop size if the aspect ratio is smaller than the desktop
407 m_vdpauConfig.outHeight = g_graphicsContext.GetHeight();
408 m_vdpauConfig.outWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height);
413 m_vdpauConfig.outWidth = width;
414 m_vdpauConfig.outHeight = height;
416 CLog::Log(LOGDEBUG, "CVDPAU::SetWidthHeight Setting OutWidth: %i OutHeight: %i", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight);
419 void CDecoder::OnLostDevice()
421 CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event");
423 int count = g_graphicsContext.exit();
425 CSingleLock lock(m_DecoderSection);
429 m_DisplayState = VDPAU_LOST;
431 m_DisplayEvent.Reset();
433 g_graphicsContext.restore(count);
436 void CDecoder::OnResetDevice()
438 CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event");
440 int count = g_graphicsContext.exit();
442 CSingleLock lock(m_DecoderSection);
443 if (m_DisplayState == VDPAU_LOST)
445 m_DisplayState = VDPAU_RESET;
447 m_DisplayEvent.Set();
450 g_graphicsContext.restore(count);
453 int CDecoder::Check(AVCodecContext* avctx)
457 { CSingleLock lock(m_DecoderSection);
458 state = m_DisplayState;
461 if (state == VDPAU_LOST)
463 CLog::Log(LOGNOTICE,"CVDPAU::Check waiting for display reset event");
464 if (!m_DisplayEvent.WaitMSec(4000))
466 CLog::Log(LOGERROR, "CVDPAU::Check - device didn't reset in reasonable time");
471 CSingleLock lock(m_DecoderSection);
472 state = m_DisplayState;
475 if (state == VDPAU_RESET || state == VDPAU_ERROR)
477 CSingleLock lock(m_DecoderSection);
484 if (state == VDPAU_RESET)
492 bool CDecoder::IsVDPAUFormat(PixelFormat format)
494 if (format == AV_PIX_FMT_VDPAU)
500 bool CDecoder::Supports(VdpVideoMixerFeature feature)
502 for(int i = 0; i < m_vdpauConfig.featureCount; i++)
504 if(m_vdpauConfig.vdpFeatures[i] == feature)
510 bool CDecoder::Supports(EINTERLACEMETHOD method)
512 if(method == VS_INTERLACEMETHOD_VDPAU_BOB
513 || method == VS_INTERLACEMETHOD_AUTO)
516 if (!m_vdpauConfig.usePixmaps)
518 if (method == VS_INTERLACEMETHOD_RENDER_BOB)
522 if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE)
525 for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++)
527 if(p->method == method)
528 return Supports(p->feature);
533 EINTERLACEMETHOD CDecoder::AutoInterlaceMethod()
535 return VS_INTERLACEMETHOD_RENDER_BOB;
538 void CDecoder::InitVDPAUProcs()
543 dl_vdp_device_create_x11 = (VdpStatus (*)(Display*, int, VdpDevice*, VdpStatus (**)(VdpDevice, VdpFuncId, void**)))dlsym(dl_handle, (const char*)"vdp_device_create_x11");
547 CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__);
548 m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
552 if (dl_vdp_device_create_x11)
554 m_Display = XOpenDisplay(NULL);
557 int mScreen = g_Windowing.GetCurrentScreen();
561 vdp_st = dl_vdp_device_create_x11(m_Display, //x_display,
563 &m_vdpauConfig.vdpDevice,
564 &m_vdpauConfig.vdpProcs.vdp_get_proc_address);
566 CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",m_vdpauConfig.vdpDevice,vdp_st);
567 if (vdp_st != VDP_STATUS_OK)
569 CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x. Falling back.",vdp_st);
570 m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
574 #define VDP_PROC(id, proc) \
576 vdp_st = m_vdpauConfig.vdpProcs.vdp_get_proc_address(m_vdpauConfig.vdpDevice, id, (void**)&proc); \
577 CheckStatus(vdp_st, __LINE__); \
580 VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING , m_vdpauConfig.vdpProcs.vdp_get_error_string);
581 VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY , m_vdpauConfig.vdpProcs.vdp_device_destroy);
582 VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX , m_vdpauConfig.vdpProcs.vdp_generate_csc_matrix);
583 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE , m_vdpauConfig.vdpProcs.vdp_video_surface_create);
584 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , m_vdpauConfig.vdpProcs.vdp_video_surface_destroy);
585 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , m_vdpauConfig.vdpProcs.vdp_video_surface_put_bits_y_cb_cr);
586 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , m_vdpauConfig.vdpProcs.vdp_video_surface_get_bits_y_cb_cr);
587 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_y_cb_cr);
588 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_native);
589 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , m_vdpauConfig.vdpProcs.vdp_output_surface_create);
590 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , m_vdpauConfig.vdpProcs.vdp_output_surface_destroy);
591 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , m_vdpauConfig.vdpProcs.vdp_output_surface_get_bits_native);
592 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, m_vdpauConfig.vdpProcs.vdp_output_surface_render_output_surface);
593 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_indexed);
594 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE , m_vdpauConfig.vdpProcs.vdp_video_mixer_create);
595 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , m_vdpauConfig.vdpProcs.vdp_video_mixer_set_feature_enables);
596 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY , m_vdpauConfig.vdpProcs.vdp_video_mixer_destroy);
597 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER , m_vdpauConfig.vdpProcs.vdp_video_mixer_render);
598 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , m_vdpauConfig.vdpProcs.vdp_video_mixer_set_attribute_values);
599 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , m_vdpauConfig.vdpProcs.vdp_video_mixer_query_parameter_support);
600 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , m_vdpauConfig.vdpProcs.vdp_video_mixer_query_feature_support);
601 VDP_PROC(VDP_FUNC_ID_DECODER_CREATE , m_vdpauConfig.vdpProcs.vdp_decoder_create);
602 VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY , m_vdpauConfig.vdpProcs.vdp_decoder_destroy);
603 VDP_PROC(VDP_FUNC_ID_DECODER_RENDER , m_vdpauConfig.vdpProcs.vdp_decoder_render);
604 VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , m_vdpauConfig.vdpProcs.vdp_decoder_query_caps);
605 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY , m_vdpauConfig.vdpProcs.vdp_presentation_queue_target_destroy);
606 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE , m_vdpauConfig.vdpProcs.vdp_presentation_queue_create);
607 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY , m_vdpauConfig.vdpProcs.vdp_presentation_queue_destroy);
608 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY , m_vdpauConfig.vdpProcs.vdp_presentation_queue_display);
609 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE, m_vdpauConfig.vdpProcs.vdp_presentation_queue_block_until_surface_idle);
610 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 , m_vdpauConfig.vdpProcs.vdp_presentation_queue_target_create_x11);
611 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS , m_vdpauConfig.vdpProcs.vdp_presentation_queue_query_surface_status);
612 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME , m_vdpauConfig.vdpProcs.vdp_presentation_queue_get_time);
616 // set all vdpau resources to invalid
617 m_DisplayState = VDPAU_OPEN;
618 m_vdpauConfigured = false;
621 void CDecoder::FiniVDPAUProcs()
623 if (m_vdpauConfig.vdpDevice == VDP_INVALID_HANDLE) return;
626 vdp_st = m_vdpauConfig.vdpProcs.vdp_device_destroy(m_vdpauConfig.vdpDevice);
627 CheckStatus(vdp_st, __LINE__);
628 m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
631 void CDecoder::FiniVDPAUOutput()
633 if (m_vdpauConfig.vdpDevice == VDP_INVALID_HANDLE || !m_vdpauConfigured) return;
635 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
638 m_vdpauOutput.Dispose();
639 m_vdpauConfigured = false;
643 vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
644 if (CheckStatus(vdp_st, __LINE__))
646 m_vdpauConfig.vdpDecoder = VDP_INVALID_HANDLE;
648 CLog::Log(LOGDEBUG, "CVDPAU::FiniVDPAUOutput destroying %d video surfaces", m_videoSurfaces.Size());
650 VdpVideoSurface surf;
651 while((surf = m_videoSurfaces.RemoveNext()) != VDP_INVALID_HANDLE)
653 m_vdpauConfig.vdpProcs.vdp_video_surface_destroy(surf);
654 if (CheckStatus(vdp_st, __LINE__))
657 m_videoSurfaces.Reset();
660 void CDecoder::ReadFormatOf( AVCodecID codec
661 , VdpDecoderProfile &vdp_decoder_profile
662 , VdpChromaType &vdp_chroma_type)
666 case AV_CODEC_ID_MPEG1VIDEO:
667 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
668 vdp_chroma_type = VDP_CHROMA_TYPE_420;
670 case AV_CODEC_ID_MPEG2VIDEO:
671 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
672 vdp_chroma_type = VDP_CHROMA_TYPE_420;
674 case AV_CODEC_ID_H264:
675 vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
676 vdp_chroma_type = VDP_CHROMA_TYPE_420;
678 case AV_CODEC_ID_WMV3:
679 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
680 vdp_chroma_type = VDP_CHROMA_TYPE_420;
682 case AV_CODEC_ID_VC1:
683 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
684 vdp_chroma_type = VDP_CHROMA_TYPE_420;
686 case AV_CODEC_ID_MPEG4:
687 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
688 vdp_chroma_type = VDP_CHROMA_TYPE_420;
691 vdp_decoder_profile = 0;
697 bool CDecoder::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
702 VdpDecoderProfile vdp_decoder_profile;
704 m_vdpauConfig.vidWidth = avctx->width;
705 m_vdpauConfig.vidHeight = avctx->height;
706 m_vdpauConfig.surfaceWidth = avctx->coded_width;
707 m_vdpauConfig.surfaceHeight = avctx->coded_height;
709 SetWidthHeight(avctx->width,avctx->height);
711 CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",m_vdpauConfig.outWidth,m_vdpauConfig.vidWidth,m_vdpauConfig.surfaceWidth);
712 CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",m_vdpauConfig.outHeight,m_vdpauConfig.vidHeight,m_vdpauConfig.surfaceHeight);
714 ReadFormatOf(avctx->codec_id, vdp_decoder_profile, m_vdpauConfig.vdpChromaType);
716 if(avctx->codec_id == AV_CODEC_ID_H264)
718 m_vdpauConfig.maxReferences = ref_frames;
719 if (m_vdpauConfig.maxReferences > 16) m_vdpauConfig.maxReferences = 16;
720 if (m_vdpauConfig.maxReferences < 5) m_vdpauConfig.maxReferences = 5;
723 m_vdpauConfig.maxReferences = 2;
725 vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_create(m_vdpauConfig.vdpDevice,
727 m_vdpauConfig.surfaceWidth,
728 m_vdpauConfig.surfaceHeight,
729 m_vdpauConfig.maxReferences,
730 &m_vdpauConfig.vdpDecoder);
731 if (CheckStatus(vdp_st, __LINE__))
735 CSingleLock lock(g_graphicsContext);
736 m_vdpauConfig.stats = &m_bufferStats;
737 m_vdpauConfig.vdpau = this;
738 m_bufferStats.Reset();
739 m_vdpauOutput.Start();
741 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT,
745 sizeof(m_vdpauConfig)))
747 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
751 data = (CVdpauConfig*)reply->data;
754 m_vdpauConfig.usePixmaps = data->usePixmaps;
760 CLog::Log(LOGERROR, "VDPAU::%s - vdpau output returned error", __FUNCTION__);
761 m_vdpauOutput.Dispose();
767 CLog::Log(LOGERROR, "VDPAU::%s - failed to init output", __FUNCTION__);
768 m_vdpauOutput.Dispose();
772 m_inMsgEvent.Reset();
773 m_vdpauConfigured = true;
777 void CDecoder::SpewHardwareAvailable() //CopyrighVDPAUt (c) 2008 Wladimir J. van der Laan -- VDPInfo
780 CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:");
781 CLog::Log(LOGNOTICE,"name level macbs width height");
782 CLog::Log(LOGNOTICE,"------------------------------------");
783 for(unsigned int x=0; x<decoder_profile_count; ++x)
785 VdpBool is_supported = false;
786 uint32_t max_level, max_macroblocks, max_width, max_height;
787 rv = m_vdpauConfig.vdpProcs.vdp_decoder_query_caps(m_vdpauConfig.vdpDevice, decoder_profiles[x].id,
788 &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
789 if(rv == VDP_STATUS_OK && is_supported)
791 CLog::Log(LOGNOTICE,"%-16s %2i %5i %5i %5i\n", decoder_profiles[x].name,
792 max_level, max_macroblocks, max_width, max_height);
795 CLog::Log(LOGNOTICE,"------------------------------------");
796 m_vdpauConfig.featureCount = 0;
797 #define CHECK_SUPPORT(feature) \
800 if(m_vdpauConfig.vdpProcs.vdp_video_mixer_query_feature_support(m_vdpauConfig.vdpDevice, feature, &supported) == VDP_STATUS_OK && supported) { \
801 CLog::Log(LOGNOTICE, "Mixer feature: "#feature); \
802 m_vdpauConfig.vdpFeatures[m_vdpauConfig.featureCount++] = feature; \
806 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION);
807 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_SHARPNESS);
808 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL);
809 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL);
810 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE);
811 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
812 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1);
813 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2);
814 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3);
815 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4);
816 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5);
817 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6);
818 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7);
819 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8);
820 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9);
826 int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
828 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
829 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
830 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
832 // while we are waiting to recover we can't do anything
833 CSingleLock lock(vdp->m_DecoderSection);
835 if(vdp->m_DisplayState != VDPAU_OPEN)
837 CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
841 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
842 surf = vdp->m_videoSurfaces.GetFree(surf != 0 ? surf : VDP_INVALID_HANDLE);
844 VdpStatus vdp_st = VDP_STATUS_ERROR;
845 if (surf == VDP_INVALID_HANDLE)
847 // create a new surface
848 VdpDecoderProfile profile;
849 ReadFormatOf(avctx->codec_id, profile, vdp->m_vdpauConfig.vdpChromaType);
851 vdp_st = vdp->m_vdpauConfig.vdpProcs.vdp_video_surface_create(vdp->m_vdpauConfig.vdpDevice,
852 vdp->m_vdpauConfig.vdpChromaType,
856 vdp->CheckStatus(vdp_st, __LINE__);
857 if (vdp_st != VDP_STATUS_OK)
859 CLog::Log(LOGERROR, "CVDPAU::FFGetBuffer - No Video surface available could be created");
862 vdp->m_videoSurfaces.AddSurface(surf);
865 pic->data[1] = pic->data[2] = NULL;
866 pic->data[0] = (uint8_t*)(uintptr_t)surf;
867 pic->data[3] = (uint8_t*)(uintptr_t)surf;
869 pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0;
871 pic->type= FF_BUFFER_TYPE_USER;
873 pic->reordered_opaque= avctx->reordered_opaque;
877 void CDecoder::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
879 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
880 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
881 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
883 VdpVideoSurface surf;
886 CSingleLock lock(vdp->m_DecoderSection);
888 surf = (VdpVideoSurface)(uintptr_t)pic->data[3];
890 vdp->m_videoSurfaces.ClearReference(surf);
896 VdpStatus CDecoder::Render( VdpDecoder decoder, VdpVideoSurface target,
897 VdpPictureInfo const *picture_info,
898 uint32_t bitstream_buffer_count,
899 VdpBitstreamBuffer const * bitstream_buffers)
901 return VDP_STATUS_OK;
904 void CDecoder::FFDrawSlice(struct AVCodecContext *s,
905 const AVFrame *src, int offset[4],
906 int y, int type, int height)
908 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque;
909 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
911 // while we are waiting to recover we can't do anything
912 CSingleLock lock(vdp->m_DecoderSection);
914 if(vdp->m_DisplayState != VDPAU_OPEN)
917 if(src->linesize[0] || src->linesize[1] || src->linesize[2]
918 || offset[0] || offset[1] || offset[2])
920 CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid linesizes or offsets provided");
925 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)src->data[3];
927 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
928 if (!vdp->m_videoSurfaces.IsValid(surf))
930 CLog::Log(LOGWARNING, "CVDPAU::FFDrawSlice - ignoring invalid buffer");
934 uint32_t max_refs = 0;
935 if(s->codec_id == AV_CODEC_ID_H264)
936 max_refs = vdp->m_hwContext.info.h264.num_ref_frames;
938 if(vdp->m_vdpauConfig.vdpDecoder == VDP_INVALID_HANDLE
939 || vdp->m_vdpauConfigured == false
940 || vdp->m_vdpauConfig.maxReferences < max_refs)
942 if(!vdp->ConfigVDPAU(s, max_refs))
946 // uint64_t startTime = CurrentHostCounter();
947 uint16_t decoded, processed, rend;
948 vdp->m_bufferStats.Get(decoded, processed, rend);
949 vdp_st = vdp->m_vdpauConfig.vdpProcs.vdp_decoder_render(vdp->m_vdpauConfig.vdpDecoder,
951 (VdpPictureInfo const *)&(vdp->m_hwContext.info),
952 vdp->m_hwContext.bitstream_buffers_used,
953 vdp->m_hwContext.bitstream_buffers);
954 vdp->CheckStatus(vdp_st, __LINE__);
955 // uint64_t diff = CurrentHostCounter() - startTime;
956 // if (diff*1000/CurrentHostFrequency() > 30)
957 // CLog::Log(LOGWARNING,"CVDPAU::DrawSlice - VdpDecoderRender long decoding: %d ms, dec: %d, proc: %d, rend: %d", (int)((diff*1000)/CurrentHostFrequency()), decoded, processed, rend);
962 int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame)
964 int result = Check(avctx);
968 CSingleLock lock(m_DecoderSection);
970 if (!m_vdpauConfigured)
974 { // we have a new frame from decoder
976 VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)pFrame->data[3];
977 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
978 if (!m_videoSurfaces.IsValid(surf))
980 CLog::Log(LOGWARNING, "CVDPAU::Decode - ignoring invalid buffer");
983 m_videoSurfaces.MarkRender(surf);
985 // send frame to output for processing
986 CVdpauDecodedPicture pic;
987 memset(&pic.DVDPic, 0, sizeof(pic.DVDPic));
988 ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic);
989 pic.videoSurface = surf;
990 pic.DVDPic.color_matrix = avctx->colorspace;
991 m_bufferStats.IncDecoded();
992 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic));
995 // m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC);
999 uint16_t decoded, processed, render;
1001 while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1003 if (msg->signal == COutputControlProtocol::ERROR)
1005 m_DisplayState = VDPAU_ERROR;
1011 m_bufferStats.Get(decoded, processed, render);
1013 uint64_t startTime = CurrentHostCounter();
1016 if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg))
1018 if (msg->signal == COutputDataProtocol::PICTURE)
1020 if (m_presentPicture)
1022 m_presentPicture->ReturnUnused();
1023 m_presentPicture = 0;
1026 m_presentPicture = *(CVdpauRenderPicture**)msg->data;
1027 m_presentPicture->vdpau = this;
1028 m_bufferStats.DecRender();
1029 m_bufferStats.Get(decoded, processed, render);
1030 retval |= VC_PICTURE;
1036 else if (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
1038 if (msg->signal == COutputControlProtocol::STATS)
1040 m_bufferStats.Get(decoded, processed, render);
1044 m_DisplayState = VDPAU_ERROR;
1051 if (1) //(m_codecControl & DVP_FLAG_DRAIN))
1053 if (decoded + processed + render < 4)
1055 retval |= VC_BUFFER;
1060 if (decoded < 4 && (processed + render) < 3)
1062 retval |= VC_BUFFER;
1066 if (!retval && !m_inMsgEvent.WaitMSec(2000))
1069 uint64_t diff = CurrentHostCounter() - startTime;
1070 if (retval & VC_PICTURE)
1072 m_bufferStats.SetParams(diff, m_codecControl);
1074 if (diff*1000/CurrentHostFrequency() > 50)
1075 CLog::Log(LOGDEBUG,"CVDPAU::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency()));
1079 CLog::Log(LOGERROR, "VDPAU::%s - timed out waiting for output message", __FUNCTION__);
1080 m_DisplayState = VDPAU_ERROR;
1087 bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
1089 CSingleLock lock(m_DecoderSection);
1091 if (m_DisplayState != VDPAU_OPEN)
1094 *picture = m_presentPicture->DVDPic;
1095 picture->vdpau = m_presentPicture;
1100 void CDecoder::Reset()
1102 CSingleLock lock(m_DecoderSection);
1104 if (!m_vdpauConfigured)
1108 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH,
1112 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
1116 CLog::Log(LOGERROR, "VDPAU::%s - flush returned error", __FUNCTION__);
1117 m_DisplayState = VDPAU_ERROR;
1120 m_bufferStats.Reset();
1124 CLog::Log(LOGERROR, "VDPAU::%s - flush timed out", __FUNCTION__);
1125 m_DisplayState = VDPAU_ERROR;
1129 bool CDecoder::CanSkipDeint()
1131 return m_bufferStats.CanSkipDeint();
1134 void CDecoder::ReturnRenderPicture(CVdpauRenderPicture *renderPic)
1136 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic));
1139 bool CDecoder::CheckStatus(VdpStatus vdp_st, int line)
1141 if (vdp_st != VDP_STATUS_OK)
1143 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_vdpauConfig.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
1145 if(m_DisplayState == VDPAU_OPEN)
1147 if (vdp_st == VDP_STATUS_DISPLAY_PREEMPTED)
1149 m_DisplayEvent.Reset();
1150 m_DisplayState = VDPAU_LOST;
1153 m_DisplayState = VDPAU_ERROR;
1161 //-----------------------------------------------------------------------------
1163 //-----------------------------------------------------------------------------
1165 CVdpauRenderPicture* CVdpauRenderPicture::Acquire()
1167 CSingleLock lock(renderPicSection);
1176 long CVdpauRenderPicture::Release()
1178 CSingleLock lock(renderPicSection);
1185 vdpau->ReturnRenderPicture(this);
1186 vdpau->ReleasePicReference();
1191 void CVdpauRenderPicture::ReturnUnused()
1193 { CSingleLock lock(renderPicSection);
1198 vdpau->ReturnRenderPicture(this);
1201 void CVdpauRenderPicture::Sync()
1204 CSingleLock lock(renderPicSection);
1209 glDeleteSync(fence);
1212 fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1217 //-----------------------------------------------------------------------------
1219 //-----------------------------------------------------------------------------
1220 CMixer::CMixer(CEvent *inMsgEvent) :
1221 CThread("Vdpau Mixer Thread"),
1222 m_controlPort("ControlPort", inMsgEvent, &m_outMsgEvent),
1223 m_dataPort("DataPort", inMsgEvent, &m_outMsgEvent)
1225 m_inMsgEvent = inMsgEvent;
1233 void CMixer::Start()
1238 void CMixer::Dispose()
1241 m_outMsgEvent.Set();
1244 m_controlPort.Purge();
1248 bool CMixer::IsActive()
1253 void CMixer::OnStartup()
1255 CLog::Log(LOGNOTICE, "CMixer::OnStartup: Output Thread created");
1258 void CMixer::OnExit()
1260 CLog::Log(LOGNOTICE, "CMixer::OnExit: Output Thread terminated");
1267 M_TOP_UNCONFIGURED, // 2
1268 M_TOP_CONFIGURED, // 3
1269 M_TOP_CONFIGURED_WAIT1, // 4
1270 M_TOP_CONFIGURED_STEP1, // 5
1271 M_TOP_CONFIGURED_WAIT2, // 6
1272 M_TOP_CONFIGURED_STEP2, // 7
1275 int MIXER_parentStates[] = {
1278 0, //TOP_UNCONFIGURED
1280 3, //TOP_CONFIGURED_WAIT1
1281 3, //TOP_CONFIGURED_STEP1
1282 3, //TOP_CONFIGURED_WAIT2
1283 3, //TOP_CONFIGURED_STEP2
1286 void CMixer::StateMachine(int signal, Protocol *port, Message *msg)
1288 for (int state = m_state; ; state = MIXER_parentStates[state])
1293 if (port == &m_controlPort)
1297 case CMixerControlProtocol::FLUSH:
1299 msg->Reply(CMixerControlProtocol::ACC);
1306 std::string portName = port == NULL ? "timer" : port->portName;
1307 CLog::Log(LOGWARNING, "CMixer::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
1311 case M_TOP_ERROR: // TOP
1314 case M_TOP_UNCONFIGURED:
1315 if (port == &m_controlPort)
1319 case CMixerControlProtocol::INIT:
1321 data = (CVdpauConfig*)msg->data;
1329 m_state = M_TOP_CONFIGURED_WAIT1;
1330 msg->Reply(CMixerControlProtocol::ACC);
1334 msg->Reply(CMixerControlProtocol::ERROR);
1343 case M_TOP_CONFIGURED:
1344 if (port == &m_dataPort)
1348 case CMixerDataProtocol::FRAME:
1349 CVdpauDecodedPicture *frame;
1350 frame = (CVdpauDecodedPicture*)msg->data;
1353 m_decodedPics.push(*frame);
1357 case CMixerDataProtocol::BUFFER:
1358 VdpOutputSurface *surf;
1359 surf = (VdpOutputSurface*)msg->data;
1362 m_outputSurfaces.push(*surf);
1372 case M_TOP_CONFIGURED_WAIT1:
1373 if (port == NULL) // timeout
1377 case CMixerControlProtocol::TIMEOUT:
1378 if (!m_decodedPics.empty() && !m_outputSurfaces.empty())
1380 m_state = M_TOP_CONFIGURED_STEP1;
1381 m_bStateMachineSelfTrigger = true;
1385 // if (m_extTimeout != 0)
1387 // SetPostProcFeatures(false);
1388 // CLog::Log(LOGWARNING,"CVDPAU::Mixer timeout - decoded: %d, outputSurf: %d", (int)m_decodedPics.size(), (int)m_outputSurfaces.size());
1399 case M_TOP_CONFIGURED_STEP1:
1400 if (port == NULL) // timeout
1404 case CMixerControlProtocol::TIMEOUT:
1405 m_mixerInput.push_front(m_decodedPics.front());
1406 m_decodedPics.pop();
1407 if (m_mixerInput.size() < 2)
1409 m_state = M_TOP_CONFIGURED_WAIT1;
1417 m_state = M_TOP_CONFIGURED_WAIT1;
1418 m_extTimeout = 1000;
1421 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1422 m_outputSurfaces.pop();
1423 m_config.stats->IncProcessed();
1424 m_config.stats->DecDecoded();
1425 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1426 if (m_mixersteps > 1)
1428 m_state = M_TOP_CONFIGURED_WAIT2;
1434 m_state = M_TOP_CONFIGURED_WAIT1;
1444 case M_TOP_CONFIGURED_WAIT2:
1445 if (port == NULL) // timeout
1449 case CMixerControlProtocol::TIMEOUT:
1450 if (!m_outputSurfaces.empty())
1452 m_state = M_TOP_CONFIGURED_STEP2;
1453 m_bStateMachineSelfTrigger = true;
1457 // if (m_extTimeout != 0)
1459 // SetPostProcFeatures(false);
1460 // CLog::Log(LOGNOTICE,"---mixer wait2 decoded: %d, outputSurf: %d", (int)m_decodedPics.size(), (int)m_outputSurfaces.size());
1471 case M_TOP_CONFIGURED_STEP2:
1472 if (port == NULL) // timeout
1476 case CMixerControlProtocol::TIMEOUT:
1477 m_processPicture.outputSurface = m_outputSurfaces.front();
1482 m_state = M_TOP_CONFIGURED_WAIT1;
1483 m_extTimeout = 1000;
1486 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1487 m_outputSurfaces.pop();
1488 m_config.stats->IncProcessed();
1489 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1491 m_state = M_TOP_CONFIGURED_WAIT1;
1500 default: // we are in no state, should not happen
1501 CLog::Log(LOGERROR, "CMixer::%s - no valid state: %d", __FUNCTION__, m_state);
1507 void CMixer::Process()
1509 Message *msg = NULL;
1510 Protocol *port = NULL;
1513 m_state = M_TOP_UNCONFIGURED;
1514 m_extTimeout = 1000;
1515 m_bStateMachineSelfTrigger = false;
1521 if (m_bStateMachineSelfTrigger)
1523 m_bStateMachineSelfTrigger = false;
1524 // self trigger state machine
1525 StateMachine(msg->signal, port, msg);
1526 if (!m_bStateMachineSelfTrigger)
1533 // check control port
1534 else if (m_controlPort.ReceiveOutMessage(&msg))
1537 port = &m_controlPort;
1540 else if (m_dataPort.ReceiveOutMessage(&msg))
1548 StateMachine(msg->signal, port, msg);
1549 if (!m_bStateMachineSelfTrigger)
1558 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
1565 msg = m_controlPort.GetMessage();
1566 msg->signal = CMixerControlProtocol::TIMEOUT;
1568 // signal timeout to state machine
1569 StateMachine(msg->signal, port, msg);
1570 if (!m_bStateMachineSelfTrigger)
1580 void CMixer::CreateVdpauMixer()
1582 CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer");
1584 InitCSCMatrix(m_config.vidWidth);
1586 VdpVideoMixerParameter parameters[] = {
1587 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
1588 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
1589 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE};
1591 void const * parameter_values[] = {
1592 &m_config.surfaceWidth,
1593 &m_config.surfaceHeight,
1594 &m_config.vdpChromaType};
1596 VdpStatus vdp_st = VDP_STATUS_ERROR;
1597 vdp_st = m_config.vdpProcs.vdp_video_mixer_create(m_config.vdpDevice,
1598 m_config.featureCount,
1599 m_config.vdpFeatures,
1604 CheckStatus(vdp_st, __LINE__);
1606 // create 3 pitches of black lines needed for clipping top
1607 // and bottom lines when de-interlacing
1608 m_BlackBar = new uint32_t[3*m_config.outWidth];
1609 memset(m_BlackBar, 0, 3*m_config.outWidth*sizeof(uint32_t));
1613 void CMixer::InitCSCMatrix(int Width)
1615 m_Procamp.struct_version = VDP_PROCAMP_VERSION;
1616 m_Procamp.brightness = 0.0;
1617 m_Procamp.contrast = 1.0;
1618 m_Procamp.saturation = 1.0;
1622 void CMixer::CheckFeatures()
1624 if (m_Upscale != m_config.upscale)
1627 m_Upscale = m_config.upscale;
1629 if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness ||
1630 m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast ||
1631 m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix)
1634 m_Brightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness;
1635 m_Contrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast;
1636 m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix;
1638 if (m_NoiseReduction != CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1640 m_NoiseReduction = CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction;
1641 SetNoiseReduction();
1643 if (m_Sharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1645 m_Sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
1648 if (m_DeintMode != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode ||
1649 m_Deint != CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod)
1651 m_DeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1652 m_Deint = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1657 void CMixer::SetPostProcFeatures(bool postProcEnabled)
1659 if (m_PostProc != postProcEnabled)
1661 if (postProcEnabled)
1663 SetNoiseReduction();
1670 m_PostProc = postProcEnabled;
1674 void CMixer::PostProcOff()
1678 if (m_videoMixer == VDP_INVALID_HANDLE)
1681 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
1682 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
1683 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE};
1685 VdpBool enabled[]={0,0,0};
1686 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1687 CheckStatus(vdp_st, __LINE__);
1689 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1691 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION};
1693 VdpBool enabled[]={0};
1694 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1695 CheckStatus(vdp_st, __LINE__);
1698 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1700 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS};
1702 VdpBool enabled[]={0};
1703 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1704 CheckStatus(vdp_st, __LINE__);
1710 bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix)
1712 // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4])
1713 // m00 = mRY = red: luma factor (contrast factor) (1.0)
1714 // m10 = mGY = green: luma factor (contrast factor) (1.0)
1715 // m20 = mBY = blue: luma factor (contrast factor) (1.0)
1717 // m01 = mRB = red: blue color diff coeff (0.0)
1718 // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg))
1719 // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5)
1721 // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5)
1722 // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg))
1723 // m22 = mBR = blue: red color diff coeff (0.0)
1725 // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255))
1726 // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg)
1727 // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255))
1738 // colour standard coefficients for red, geen, blue
1740 // colour diff zero position (use standard 8-bit coding precision)
1741 double CDZ = 128; //256*0.5
1742 // range excursion (use standard 8-bit coding precision)
1743 double EXC = 255; //256-1
1745 if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601)
1747 Kr = studioCSCKCoeffs601[0];
1748 Kg = studioCSCKCoeffs601[1];
1749 Kb = studioCSCKCoeffs601[2];
1751 else // assume VDP_COLOR_STANDARD_ITUR_BT_709
1753 Kr = studioCSCKCoeffs709[0];
1754 Kg = studioCSCKCoeffs709[1];
1755 Kb = studioCSCKCoeffs709[2];
1757 // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235
1758 studioCSCMatrix[R][Y] = 1.0;
1759 studioCSCMatrix[G][Y] = 1.0;
1760 studioCSCMatrix[B][Y] = 1.0;
1762 studioCSCMatrix[R][Cb] = 0.0;
1763 studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg;
1764 studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5;
1766 studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5;
1767 studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg;
1768 studioCSCMatrix[B][Cr] = 0.0;
1770 studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC;
1771 studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC;
1772 studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC;
1777 void CMixer::SetColor()
1781 if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)
1782 m_Procamp.brightness = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)-50) / 100;
1783 if (m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)
1784 m_Procamp.contrast = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)+50) / 100;
1786 VdpColorStandard colorStandard;
1787 switch(m_mixerInput[1].DVDPic.color_matrix)
1789 case AVCOL_SPC_BT709:
1790 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1792 case AVCOL_SPC_BT470BG:
1793 case AVCOL_SPC_SMPTE170M:
1794 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1796 case AVCOL_SPC_SMPTE240M:
1797 colorStandard = VDP_COLOR_STANDARD_SMPTE_240M;
1800 case AVCOL_SPC_UNSPECIFIED:
1803 if(m_config.surfaceWidth > 1000)
1804 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1806 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1809 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
1810 if (CSettings::Get().GetBool("videoscreen.limitedrange"))
1812 float studioCSC[3][4];
1813 GenerateStudioCSCMatrix(colorStandard, studioCSC);
1814 void const * pm_CSCMatix[] = { &studioCSC };
1815 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1819 vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix);
1820 void const * pm_CSCMatix[] = { &m_CSCMatrix };
1821 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1824 CheckStatus(vdp_st, __LINE__);
1827 void CMixer::SetNoiseReduction()
1829 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1832 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION };
1833 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL };
1836 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1838 VdpBool enabled[]= {0};
1839 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1840 CheckStatus(vdp_st, __LINE__);
1843 VdpBool enabled[]={1};
1844 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1845 CheckStatus(vdp_st, __LINE__);
1846 void* nr[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction };
1847 CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction);
1848 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, nr);
1849 CheckStatus(vdp_st, __LINE__);
1852 void CMixer::SetSharpness()
1854 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1857 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS };
1858 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL };
1861 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1863 VdpBool enabled[]={0};
1864 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1865 CheckStatus(vdp_st, __LINE__);
1868 VdpBool enabled[]={1};
1869 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1870 CheckStatus(vdp_st, __LINE__);
1871 void* sh[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness };
1872 CLog::Log(LOGNOTICE,"Setting Sharpness to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness);
1873 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, sh);
1874 CheckStatus(vdp_st, __LINE__);
1877 EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */)
1879 EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1880 if (method == VS_INTERLACEMETHOD_AUTO)
1883 // if (m_config.outHeight >= 720)
1884 // deint = g_advancedSettings.m_videoVDPAUdeintHD;
1886 // deint = g_advancedSettings.m_videoVDPAUdeintSD;
1890 if (m_config.vdpau->Supports(EINTERLACEMETHOD(deint)))
1892 method = EINTERLACEMETHOD(deint);
1894 CLog::Log(LOGNOTICE, "CVDPAU::GetDeinterlacingMethod: set de-interlacing to %d", deint);
1899 CLog::Log(LOGWARNING, "CVDPAU::GetDeinterlacingMethod: method for de-interlacing (advanced settings) not supported");
1906 void CMixer::SetDeinterlacing()
1910 if (m_videoMixer == VDP_INVALID_HANDLE)
1913 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1914 EINTERLACEMETHOD method = GetDeinterlacingMethod(true);
1916 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
1917 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
1918 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE };
1920 if (mode == VS_DEINTERLACEMODE_OFF)
1922 VdpBool enabled[] = {0,0,0};
1923 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1927 if (method == VS_INTERLACEMETHOD_AUTO)
1929 VdpBool enabled[] = {1,0,0};
1930 if (g_advancedSettings.m_videoVDPAUtelecine)
1932 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1934 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
1935 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF)
1937 VdpBool enabled[] = {1,0,0};
1938 if (g_advancedSettings.m_videoVDPAUtelecine)
1940 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1942 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
1943 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF)
1945 VdpBool enabled[] = {1,1,0};
1946 if (g_advancedSettings.m_videoVDPAUtelecine)
1948 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1952 VdpBool enabled[]={0,0,0};
1953 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1956 CheckStatus(vdp_st, __LINE__);
1958 SetDeintSkipChroma();
1960 m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
1963 void CMixer::SetDeintSkipChroma()
1965 VdpVideoMixerAttribute attribute[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE};
1969 if (g_advancedSettings.m_videoVDPAUdeintSkipChromaHD && m_config.outHeight >= 720)
1974 void const *values[]={&val};
1975 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attribute), attribute, values);
1977 CheckStatus(vdp_st, __LINE__);
1980 void CMixer::SetHWUpscaling()
1982 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
1985 VdpBool enabled[]={1};
1986 switch (m_config.upscale)
1989 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
1991 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
1992 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1996 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
1998 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
1999 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2003 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2005 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2006 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2010 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2012 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2013 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2017 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2019 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2020 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2024 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2026 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2027 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2031 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2033 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2034 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2038 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2040 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2041 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2045 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2047 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2048 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2055 CheckStatus(vdp_st, __LINE__);
2059 void CMixer::DisableHQScaling()
2063 if (m_videoMixer == VDP_INVALID_HANDLE)
2066 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2068 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2069 VdpBool enabled[]={0};
2070 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2071 CheckStatus(vdp_st, __LINE__);
2074 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2076 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2077 VdpBool enabled[]={0};
2078 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2079 CheckStatus(vdp_st, __LINE__);
2082 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2084 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2085 VdpBool enabled[]={0};
2086 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2087 CheckStatus(vdp_st, __LINE__);
2090 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2092 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2093 VdpBool enabled[]={0};
2094 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2095 CheckStatus(vdp_st, __LINE__);
2098 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2100 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2101 VdpBool enabled[]={0};
2102 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2103 CheckStatus(vdp_st, __LINE__);
2106 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2108 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2109 VdpBool enabled[]={0};
2110 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2111 CheckStatus(vdp_st, __LINE__);
2114 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2116 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2117 VdpBool enabled[]={0};
2118 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2119 CheckStatus(vdp_st, __LINE__);
2122 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
2124 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
2125 VdpBool enabled[]={0};
2126 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2127 CheckStatus(vdp_st, __LINE__);
2130 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
2132 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
2133 VdpBool enabled[]={0};
2134 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2135 CheckStatus(vdp_st, __LINE__);
2144 m_NoiseReduction = 0.0;
2152 m_config.upscale = g_advancedSettings.m_videoVDPAUScaling;
2153 m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
2158 void CMixer::Uninit()
2161 while (!m_outputSurfaces.empty())
2163 m_outputSurfaces.pop();
2165 m_config.vdpProcs.vdp_video_mixer_destroy(m_videoMixer);
2167 delete [] m_BlackBar;
2170 void CMixer::Flush()
2172 while (!m_mixerInput.empty())
2174 CVdpauDecodedPicture pic = m_mixerInput.back();
2175 m_mixerInput.pop_back();
2176 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2178 while (!m_decodedPics.empty())
2180 CVdpauDecodedPicture pic = m_decodedPics.front();
2181 m_decodedPics.pop();
2182 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2185 while (m_dataPort.ReceiveOutMessage(&msg))
2187 if (msg->signal == CMixerDataProtocol::FRAME)
2189 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2190 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2192 else if (msg->signal == CMixerDataProtocol::BUFFER)
2194 VdpOutputSurface *surf;
2195 surf = (VdpOutputSurface*)msg->data;
2196 m_outputSurfaces.push(*surf);
2202 void CMixer::InitCycle()
2207 m_config.stats->GetParams(latency, flags);
2208 latency = (latency*1000)/CurrentHostFrequency();
2210 if (0) //flags & DVP_FLAG_NO_POSTPROC)
2211 SetPostProcFeatures(false);
2213 SetPostProcFeatures(true);
2215 m_config.stats->SetCanSkipDeint(false);
2217 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
2218 EINTERLACEMETHOD method = GetDeinterlacingMethod();
2219 bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED;
2222 if (//!(flags & DVP_FLAG_NO_POSTPROC) &&
2223 (mode == VS_DEINTERLACEMODE_FORCE ||
2224 (mode == VS_DEINTERLACEMODE_AUTO && interlaced)))
2226 if((method == VS_INTERLACEMETHOD_AUTO && interlaced)
2227 || method == VS_INTERLACEMETHOD_VDPAU_BOB
2228 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2229 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2230 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2231 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2232 || method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE )
2234 if(method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2235 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2236 || !g_graphicsContext.IsFullScreenVideo())
2241 m_config.stats->SetCanSkipDeint(true);
2245 if (0) //m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_DROPDEINT)
2250 if(m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST)
2251 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2253 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2255 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2256 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2257 DVP_FLAG_REPEAT_TOP_FIELD |
2258 DVP_FLAG_INTERLACED);
2259 m_config.useInteropYuv = false;
2261 else if (method == VS_INTERLACEMETHOD_RENDER_BOB)
2264 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2265 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2266 m_config.useInteropYuv = true;
2270 CLog::Log(LOGERROR, "CMixer::%s - interlace method: %d not supported, setting to AUTO", __FUNCTION__, method);
2272 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2273 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2274 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2275 DVP_FLAG_REPEAT_TOP_FIELD |
2276 DVP_FLAG_INTERLACED);
2278 CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod = VS_INTERLACEMETHOD_AUTO;
2284 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2286 if (m_config.useInteropYuv)
2287 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2290 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2291 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2292 DVP_FLAG_REPEAT_TOP_FIELD |
2293 DVP_FLAG_INTERLACED);
2298 if (m_mixerInput[1].DVDPic.format == RENDER_FMT_VDPAU)
2300 m_processPicture.outputSurface = m_outputSurfaces.front();
2301 m_mixerInput[1].DVDPic.iWidth = m_config.outWidth;
2302 m_mixerInput[1].DVDPic.iHeight = m_config.outHeight;
2306 m_mixerInput[1].DVDPic.iWidth = m_config.vidWidth;
2307 m_mixerInput[1].DVDPic.iHeight = m_config.vidHeight;
2310 m_processPicture.DVDPic = m_mixerInput[1].DVDPic;
2311 m_processPicture.videoSurface = m_mixerInput[1].videoSurface;
2314 void CMixer::FiniCycle()
2316 while (m_mixerInput.size() > 3)
2318 CVdpauDecodedPicture &tmp = m_mixerInput.back();
2319 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
2321 m_config.videoSurfaces->ClearRender(tmp.videoSurface);
2323 m_mixerInput.pop_back();
2324 // m_config.stats->DecDecoded();
2328 void CMixer::ProcessPicture()
2330 if (m_processPicture.DVDPic.format == RENDER_FMT_VDPAU_420)
2335 if (m_mixerstep == 1)
2337 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD)
2338 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2340 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2343 VdpVideoSurface past_surfaces[4] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2344 VdpVideoSurface futu_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2345 uint32_t pastCount = 4;
2346 uint32_t futuCount = 2;
2348 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
2350 // use only 2 past 1 future for progressive/weave
2351 // (only used for postproc anyway eg noise reduction)
2352 if (m_mixerInput.size() > 3)
2353 past_surfaces[1] = m_mixerInput[3].videoSurface;
2354 if (m_mixerInput.size() > 2)
2355 past_surfaces[0] = m_mixerInput[2].videoSurface;
2356 futu_surfaces[0] = m_mixerInput[0].videoSurface;
2362 if(m_mixerstep == 0)
2364 if (m_mixerInput.size() > 3)
2366 past_surfaces[3] = m_mixerInput[3].videoSurface;
2367 past_surfaces[2] = m_mixerInput[3].videoSurface;
2369 if (m_mixerInput.size() > 2)
2371 past_surfaces[1] = m_mixerInput[2].videoSurface;
2372 past_surfaces[0] = m_mixerInput[2].videoSurface;
2374 futu_surfaces[0] = m_mixerInput[1].videoSurface;
2375 futu_surfaces[1] = m_mixerInput[0].videoSurface;
2379 if (m_mixerInput.size() > 3)
2381 past_surfaces[3] = m_mixerInput[3].videoSurface;
2383 if (m_mixerInput.size() > 2)
2385 past_surfaces[2] = m_mixerInput[2].videoSurface;
2386 past_surfaces[1] = m_mixerInput[2].videoSurface;
2388 past_surfaces[0] = m_mixerInput[1].videoSurface;
2389 futu_surfaces[0] = m_mixerInput[1].videoSurface;
2390 futu_surfaces[1] = m_mixerInput[1].videoSurface;
2392 if (m_mixerInput[0].DVDPic.pts != DVD_NOPTS_VALUE &&
2393 m_mixerInput[1].DVDPic.pts != DVD_NOPTS_VALUE)
2395 m_processPicture.DVDPic.pts = m_mixerInput[1].DVDPic.pts +
2396 (m_mixerInput[0].DVDPic.pts -
2397 m_mixerInput[1].DVDPic.pts) / 2;
2400 m_processPicture.DVDPic.pts = DVD_NOPTS_VALUE;
2401 m_processPicture.DVDPic.dts = DVD_NOPTS_VALUE;
2403 m_processPicture.DVDPic.iRepeatPicture = 0.0;
2409 sourceRect.x1 = m_config.vidWidth;
2410 sourceRect.y1 = m_config.vidHeight;
2415 destRect.x1 = m_config.outWidth;
2416 destRect.y1 = m_config.outHeight;
2418 // start vdpau video mixer
2419 vdp_st = m_config.vdpProcs.vdp_video_mixer_render(m_videoMixer,
2425 m_mixerInput[1].videoSurface,
2429 m_processPicture.outputSurface,
2434 CheckStatus(vdp_st, __LINE__);
2436 if (m_mixerfield != VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
2438 // in order to clip top and bottom lines when de-interlacing
2439 // we black those lines as a work around for not working
2440 // background colour using the mixer
2441 // pixel perfect is preferred over overscanning or zooming
2443 VdpRect clipRect = destRect;
2444 clipRect.y1 = clipRect.y0 + 2;
2445 uint32_t *data[] = {m_BlackBar};
2446 uint32_t pitches[] = {destRect.x1};
2447 vdp_st = m_config.vdpProcs.vdp_output_surface_put_bits_native(m_processPicture.outputSurface,
2451 CheckStatus(vdp_st, __LINE__);
2453 clipRect = destRect;
2454 clipRect.y0 = clipRect.y1 - 2;
2455 vdp_st = m_config.vdpProcs.vdp_output_surface_put_bits_native(m_processPicture.outputSurface,
2459 CheckStatus(vdp_st, __LINE__);
2464 bool CMixer::CheckStatus(VdpStatus vdp_st, int line)
2466 if (vdp_st != VDP_STATUS_OK)
2468 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
2475 //-----------------------------------------------------------------------------
2477 //-----------------------------------------------------------------------------
2479 VdpauBufferPool::VdpauBufferPool()
2481 CVdpauRenderPicture *pic;
2482 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2484 pic = new CVdpauRenderPicture(renderPicSec);
2485 allRenderPics.push_back(pic);
2489 VdpauBufferPool::~VdpauBufferPool()
2491 CVdpauRenderPicture *pic;
2492 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2494 pic = allRenderPics[i];
2497 allRenderPics.clear();
2500 //-----------------------------------------------------------------------------
2502 //-----------------------------------------------------------------------------
2503 COutput::COutput(CEvent *inMsgEvent) :
2504 CThread("Vdpau Output Thread"),
2505 m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent),
2506 m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent),
2507 m_mixer(&m_outMsgEvent)
2509 m_inMsgEvent = inMsgEvent;
2511 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i)
2513 m_bufferPool.freeRenderPics.push_back(i);
2517 void COutput::Start()
2526 m_bufferPool.freeRenderPics.clear();
2527 m_bufferPool.usedRenderPics.clear();
2530 void COutput::Dispose()
2532 CSingleLock lock(g_graphicsContext);
2534 m_outMsgEvent.Set();
2536 m_controlPort.Purge();
2540 void COutput::OnStartup()
2542 CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created");
2545 void COutput::OnExit()
2547 CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated");
2554 O_TOP_UNCONFIGURED, // 2
2555 O_TOP_CONFIGURED, // 3
2556 O_TOP_CONFIGURED_IDLE, // 4
2557 O_TOP_CONFIGURED_WORK, // 5
2560 int VDPAU_OUTPUT_parentStates[] = {
2563 0, //TOP_UNCONFIGURED
2565 3, //TOP_CONFIGURED_IDLE
2566 3, //TOP_CONFIGURED_WORK
2569 void COutput::StateMachine(int signal, Protocol *port, Message *msg)
2571 for (int state = m_state; ; state = VDPAU_OUTPUT_parentStates[state])
2576 if (port == &m_controlPort)
2580 case COutputControlProtocol::FLUSH:
2581 msg->Reply(COutputControlProtocol::ACC);
2583 case COutputControlProtocol::PRECLEANUP:
2584 msg->Reply(COutputControlProtocol::ACC);
2590 else if (port == &m_dataPort)
2594 case COutputDataProtocol::RETURNPIC:
2595 CVdpauRenderPicture *pic;
2596 pic = *((CVdpauRenderPicture**)msg->data);
2597 QueueReturnPicture(pic);
2604 std::string portName = port == NULL ? "timer" : port->portName;
2605 CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
2612 case O_TOP_UNCONFIGURED:
2613 if (port == &m_controlPort)
2617 case COutputControlProtocol::INIT:
2619 data = (CVdpauConfig*)msg->data;
2626 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::INIT,
2627 &reply, 1000, &m_config, sizeof(m_config)))
2629 if (reply->signal != CMixerControlProtocol::ACC)
2634 // set initial number of
2635 m_bufferPool.numOutputSurfaces = 4;
2639 m_state = O_TOP_CONFIGURED_IDLE;
2640 msg->Reply(COutputControlProtocol::ACC, &m_config, sizeof(m_config));
2644 m_state = O_TOP_ERROR;
2645 msg->Reply(COutputControlProtocol::ERROR);
2654 case O_TOP_CONFIGURED:
2655 if (port == &m_controlPort)
2659 case COutputControlProtocol::FLUSH:
2661 msg->Reply(COutputControlProtocol::ACC);
2663 case COutputControlProtocol::PRECLEANUP:
2666 msg->Reply(COutputControlProtocol::ACC);
2672 else if (port == &m_dataPort)
2676 case COutputDataProtocol::NEWFRAME:
2677 CVdpauDecodedPicture *frame;
2678 frame = (CVdpauDecodedPicture*)msg->data;
2681 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::FRAME,
2682 frame,sizeof(CVdpauDecodedPicture));
2685 case COutputDataProtocol::RETURNPIC:
2686 CVdpauRenderPicture *pic;
2687 pic = *((CVdpauRenderPicture**)msg->data);
2688 QueueReturnPicture(pic);
2689 m_controlPort.SendInMessage(COutputControlProtocol::STATS);
2690 m_state = O_TOP_CONFIGURED_WORK;
2697 else if (port == &m_mixer.m_dataPort)
2701 case CMixerDataProtocol::PICTURE:
2702 CVdpauProcessedPicture *pic;
2703 pic = (CVdpauProcessedPicture*)msg->data;
2704 m_bufferPool.processedPics.push(*pic);
2705 m_state = O_TOP_CONFIGURED_WORK;
2714 case O_TOP_CONFIGURED_IDLE:
2715 if (port == NULL) // timeout
2719 case COutputControlProtocol::TIMEOUT:
2720 if (ProcessSyncPicture())
2726 m_state = O_TOP_CONFIGURED_WORK;
2736 case O_TOP_CONFIGURED_WORK:
2737 if (port == NULL) // timeout
2741 case COutputControlProtocol::TIMEOUT:
2744 CVdpauRenderPicture *pic;
2745 pic = ProcessMixerPicture();
2748 m_config.stats->DecProcessed();
2749 m_config.stats->IncRender();
2750 m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic));
2756 m_state = O_TOP_CONFIGURED_IDLE;
2766 default: // we are in no state, should not happen
2767 CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state);
2773 void COutput::Process()
2775 Message *msg = NULL;
2776 Protocol *port = NULL;
2779 m_state = O_TOP_UNCONFIGURED;
2780 m_extTimeout = 1000;
2781 m_bStateMachineSelfTrigger = false;
2787 if (m_bStateMachineSelfTrigger)
2789 m_bStateMachineSelfTrigger = false;
2790 // self trigger state machine
2791 StateMachine(msg->signal, port, msg);
2792 if (!m_bStateMachineSelfTrigger)
2799 // check control port
2800 else if (m_controlPort.ReceiveOutMessage(&msg))
2803 port = &m_controlPort;
2806 else if (m_dataPort.ReceiveOutMessage(&msg))
2811 // check mixer data port
2812 else if (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2815 port = &m_mixer.m_dataPort;
2819 StateMachine(msg->signal, port, msg);
2820 if (!m_bStateMachineSelfTrigger)
2829 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
2836 msg = m_controlPort.GetMessage();
2837 msg->signal = COutputControlProtocol::TIMEOUT;
2839 // signal timeout to state machine
2840 StateMachine(msg->signal, port, msg);
2841 if (!m_bStateMachineSelfTrigger)
2852 bool COutput::Init()
2854 if (!CreateGlxContext())
2866 bool COutput::Uninit()
2871 ReleaseBufferPool();
2872 DestroyGlxContext();
2876 void COutput::Flush()
2878 if (m_mixer.IsActive())
2881 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH,
2888 CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__);
2892 while (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2894 if (msg->signal == CMixerDataProtocol::PICTURE)
2896 CVdpauProcessedPicture pic = *(CVdpauProcessedPicture*)msg->data;
2897 m_bufferPool.processedPics.push(pic);
2902 while (m_dataPort.ReceiveOutMessage(&msg))
2904 if (msg->signal == COutputDataProtocol::NEWFRAME)
2906 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2907 m_config.videoSurfaces->ClearRender(pic.videoSurface);
2909 else if (msg->signal == COutputDataProtocol::RETURNPIC)
2911 CVdpauRenderPicture *pic;
2912 pic = *((CVdpauRenderPicture**)msg->data);
2913 QueueReturnPicture(pic);
2918 while (m_dataPort.ReceiveInMessage(&msg))
2920 if (msg->signal == COutputDataProtocol::PICTURE)
2922 CVdpauRenderPicture *pic;
2923 pic = *((CVdpauRenderPicture**)msg->data);
2924 QueueReturnPicture(pic);
2928 // reset used render flag which was cleared on mixer flush
2929 std::deque<int>::iterator it;
2930 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
2932 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[*it];
2933 if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
2935 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it2;
2936 it2 = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
2937 if (it2 == m_bufferPool.glVideoSurfaceMap.end())
2939 CLog::Log(LOGDEBUG, "COutput::Flush - gl surface not found");
2942 m_config.videoSurfaces->MarkRender(it2->second.sourceVuv);
2946 // clear processed pics
2947 while(!m_bufferPool.processedPics.empty())
2949 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
2950 if (procPic.DVDPic.format == RENDER_FMT_VDPAU)
2952 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &procPic.outputSurface, sizeof(procPic.outputSurface));
2954 else if (procPic.DVDPic.format == RENDER_FMT_VDPAU_420)
2956 m_config.videoSurfaces->ClearRender(procPic.videoSurface);
2958 m_bufferPool.processedPics.pop();
2962 bool COutput::HasWork()
2964 if (m_config.usePixmaps)
2966 if (!m_bufferPool.processedPics.empty() && FindFreePixmap() >= 0)
2968 if (!m_bufferPool.notVisiblePixmaps.empty() && !m_bufferPool.freeRenderPics.empty())
2974 if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
2980 CVdpauRenderPicture* COutput::ProcessMixerPicture()
2982 CVdpauRenderPicture *retPic = NULL;
2984 if (m_config.usePixmaps)
2986 if (!m_bufferPool.processedPics.empty() && FindFreePixmap() >= 0)
2988 unsigned int i = FindFreePixmap();
2989 VdpauBufferPool::Pixmaps *pixmap = &m_bufferPool.pixmaps[i];
2990 pixmap->used = true;
2991 CVdpauProcessedPicture pic = m_bufferPool.processedPics.front();
2992 m_bufferPool.processedPics.pop();
2993 pixmap->surface = pic.outputSurface;
2994 pixmap->DVDPic = pic.DVDPic;
2996 m_bufferPool.notVisiblePixmaps.push_back(i);
2997 m_config.vdpProcs.vdp_presentation_queue_display(pixmap->vdp_flip_queue,
2998 pixmap->surface,0,0,0);
3000 if (!m_bufferPool.notVisiblePixmaps.empty() && !m_bufferPool.freeRenderPics.empty())
3004 VdpPresentationQueueStatus status;
3005 int idx = m_bufferPool.notVisiblePixmaps.front();
3006 VdpauBufferPool::Pixmaps *pixmap = &m_bufferPool.pixmaps[idx];
3007 vdp_st = m_config.vdpProcs.vdp_presentation_queue_query_surface_status(
3008 pixmap->vdp_flip_queue, pixmap->surface, &status, &time);
3010 if (vdp_st == VDP_STATUS_OK && status == VDP_PRESENTATION_QUEUE_STATUS_VISIBLE)
3012 int idx = m_bufferPool.freeRenderPics.front();
3013 retPic = m_bufferPool.allRenderPics[idx];
3014 m_bufferPool.freeRenderPics.pop_front();
3015 m_bufferPool.usedRenderPics.push_back(idx);
3016 retPic->sourceIdx = pixmap->id;
3017 retPic->DVDPic = pixmap->DVDPic;
3018 retPic->valid = true;
3019 retPic->texture[0] = pixmap->texture;
3020 retPic->crop = CRect(0,0,0,0);
3021 m_bufferPool.notVisiblePixmaps.pop_front();
3022 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &pixmap->surface, sizeof(pixmap->surface));
3026 else if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
3028 int idx = m_bufferPool.freeRenderPics.front();
3029 retPic = m_bufferPool.allRenderPics[idx];
3030 m_bufferPool.freeRenderPics.pop_front();
3031 m_bufferPool.usedRenderPics.push_back(idx);
3032 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
3033 m_bufferPool.processedPics.pop();
3035 retPic->DVDPic = procPic.DVDPic;
3036 retPic->valid = true;
3037 if (retPic->DVDPic.format == RENDER_FMT_VDPAU)
3039 m_config.useInteropYuv = false;
3040 m_bufferPool.numOutputSurfaces = NUM_RENDER_PICS;
3043 retPic->sourceIdx = procPic.outputSurface;
3044 retPic->texture[0] = m_bufferPool.glOutputSurfaceMap[procPic.outputSurface].texture[0];
3045 retPic->crop = CRect(0,0,0,0);
3049 m_config.useInteropYuv = true;
3051 retPic->sourceIdx = procPic.videoSurface;
3052 for (unsigned int i=0; i<4; ++i)
3053 retPic->texture[i] = m_bufferPool.glVideoSurfaceMap[procPic.videoSurface].texture[i];
3054 retPic->texWidth = m_config.surfaceWidth;
3055 retPic->texHeight = m_config.surfaceHeight;
3056 retPic->crop.x1 = 0;
3057 retPic->crop.y1 = 0;
3058 retPic->crop.x2 = m_config.surfaceWidth - m_config.vidWidth;
3059 retPic->crop.y2 = m_config.surfaceHeight - m_config.vidHeight;
3065 void COutput::QueueReturnPicture(CVdpauRenderPicture *pic)
3067 std::deque<int>::iterator it;
3068 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3070 if (m_bufferPool.allRenderPics[*it] == pic)
3076 if (it == m_bufferPool.usedRenderPics.end())
3078 CLog::Log(LOGWARNING, "COutput::QueueReturnPicture - pic not found");
3082 // check if already queued
3083 std::deque<int>::iterator it2 = find(m_bufferPool.syncRenderPics.begin(),
3084 m_bufferPool.syncRenderPics.end(),
3086 if (it2 == m_bufferPool.syncRenderPics.end())
3088 m_bufferPool.syncRenderPics.push_back(*it);
3091 ProcessSyncPicture();
3094 bool COutput::ProcessSyncPicture()
3096 CVdpauRenderPicture *pic;
3099 std::deque<int>::iterator it;
3100 for (it = m_bufferPool.syncRenderPics.begin(); it != m_bufferPool.syncRenderPics.end(); )
3102 pic = m_bufferPool.allRenderPics[*it];
3107 if (glIsSync(pic->fence))
3111 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3112 if(state == GL_SIGNALED)
3114 glDeleteSync(pic->fence);
3127 m_bufferPool.freeRenderPics.push_back(*it);
3129 std::deque<int>::iterator it2 = find(m_bufferPool.usedRenderPics.begin(),
3130 m_bufferPool.usedRenderPics.end(),
3132 if (it2 == m_bufferPool.usedRenderPics.end())
3134 CLog::Log(LOGERROR, "COutput::ProcessSyncPicture - pic not found in queue");
3138 m_bufferPool.usedRenderPics.erase(it2);
3140 it = m_bufferPool.syncRenderPics.erase(it);
3144 ProcessReturnPicture(pic);
3148 CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__);
3154 void COutput::ProcessReturnPicture(CVdpauRenderPicture *pic)
3156 if (m_config.usePixmaps)
3158 m_bufferPool.pixmaps[pic->sourceIdx].used = false;
3161 else if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3163 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3164 it = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3165 if (it == m_bufferPool.glVideoSurfaceMap.end())
3167 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3170 VdpVideoSurface surf = it->second.sourceVuv;
3171 m_config.videoSurfaces->ClearRender(surf);
3173 else if (pic->DVDPic.format == RENDER_FMT_VDPAU)
3175 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3176 it = m_bufferPool.glOutputSurfaceMap.find(pic->sourceIdx);
3177 if (it == m_bufferPool.glOutputSurfaceMap.end())
3179 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3182 VdpOutputSurface outSurf = it->second.sourceRgb;
3183 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &outSurf, sizeof(outSurf));
3187 int COutput::FindFreePixmap()
3191 for (i = 0; i < m_bufferPool.pixmaps.size(); ++i)
3193 if (!m_bufferPool.pixmaps[i].used)
3196 if (i == m_bufferPool.pixmaps.size())
3202 bool COutput::EnsureBufferPool()
3206 // Creation of outputSurfaces
3207 VdpOutputSurface outputSurface;
3208 for (int i = m_bufferPool.outputSurfaces.size(); i < m_bufferPool.numOutputSurfaces; i++)
3210 vdp_st = m_config.vdpProcs.vdp_output_surface_create(m_config.vdpDevice,
3211 VDP_RGBA_FORMAT_B8G8R8A8,
3215 if (CheckStatus(vdp_st, __LINE__))
3217 m_bufferPool.outputSurfaces.push_back(outputSurface);
3219 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3221 sizeof(VdpOutputSurface));
3222 CLog::Log(LOGNOTICE, "VDPAU::COutput::InitBufferPool - Output Surface created");
3226 if (m_config.usePixmaps && m_bufferPool.pixmaps.empty())
3229 VdpauBufferPool::Pixmaps pixmap;
3230 unsigned int numPixmaps = NUM_RENDER_PICS;
3231 for (unsigned int i = 0; i < numPixmaps; i++)
3233 pixmap.pixmap = None;
3234 pixmap.glPixmap = None;
3235 pixmap.vdp_flip_queue = VDP_INVALID_HANDLE;
3236 pixmap.vdp_flip_target = VDP_INVALID_HANDLE;
3238 glXMakeCurrent(m_Display, None, NULL);
3239 vdp_st = m_config.vdpProcs.vdp_presentation_queue_target_create_x11(m_config.vdpDevice,
3240 pixmap.pixmap, //x_window,
3241 &pixmap.vdp_flip_target);
3243 CheckStatus(vdp_st, __LINE__);
3245 vdp_st = m_config.vdpProcs.vdp_presentation_queue_create(m_config.vdpDevice,
3246 pixmap.vdp_flip_target,
3247 &pixmap.vdp_flip_queue);
3248 CheckStatus(vdp_st, __LINE__);
3249 glXMakeCurrent(m_Display, m_glPixmap, m_glContext);
3252 pixmap.used = false;
3253 m_bufferPool.pixmaps.push_back(pixmap);
3261 void COutput::ReleaseBufferPool()
3265 CSingleLock lock(m_bufferPool.renderPicSec);
3267 if (m_config.usePixmaps)
3269 for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); ++i)
3271 if (m_bufferPool.pixmaps[i].vdp_flip_queue != VDP_INVALID_HANDLE)
3273 vdp_st = m_config.vdpProcs.vdp_presentation_queue_destroy(m_bufferPool.pixmaps[i].vdp_flip_queue);
3274 CheckStatus(vdp_st, __LINE__);
3276 if (m_bufferPool.pixmaps[i].vdp_flip_target != VDP_INVALID_HANDLE)
3278 vdp_st = m_config.vdpProcs.vdp_presentation_queue_target_destroy(m_bufferPool.pixmaps[i].vdp_flip_target);
3279 CheckStatus(vdp_st, __LINE__);
3281 if (m_bufferPool.pixmaps[i].glPixmap)
3283 glXDestroyPixmap(m_Display, m_bufferPool.pixmaps[i].glPixmap);
3285 if (m_bufferPool.pixmaps[i].pixmap)
3287 XFreePixmap(m_Display, m_bufferPool.pixmaps[i].pixmap);
3290 m_bufferPool.pixmaps.clear();
3293 // release all output surfaces
3294 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3296 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3298 vdp_st = m_config.vdpProcs.vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3299 CheckStatus(vdp_st, __LINE__);
3301 m_bufferPool.outputSurfaces.clear();
3303 // wait for all fences
3304 XbmcThreads::EndTime timeout(1000);
3305 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3307 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[i];
3311 while (glIsSync(pic->fence))
3315 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3316 if(state == GL_SIGNALED || timeout.IsTimePast())
3318 glDeleteSync(pic->fence);
3329 if (timeout.IsTimePast())
3331 CLog::Log(LOGERROR, "COutput::%s - timeout waiting for fence", __FUNCTION__);
3333 ProcessSyncPicture();
3335 // invalidate all used render pictures
3336 for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i)
3338 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[m_bufferPool.usedRenderPics[i]];
3343 void COutput::PreCleanup()
3349 ProcessSyncPicture();
3351 CSingleLock lock(m_bufferPool.renderPicSec);
3352 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3354 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3357 // check if output surface is in use
3359 std::deque<int>::iterator it;
3360 CVdpauRenderPicture *pic;
3361 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3363 pic = m_bufferPool.allRenderPics[*it];
3364 if ((pic->sourceIdx == m_bufferPool.outputSurfaces[i]) && pic->valid)
3373 #ifdef GL_NV_vdpau_interop
3375 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it_map;
3376 it_map = m_bufferPool.glOutputSurfaceMap.find(m_bufferPool.outputSurfaces[i]);
3377 if (it_map == m_bufferPool.glOutputSurfaceMap.end())
3379 CLog::Log(LOGERROR, "%s - could not find gl surface", __FUNCTION__);
3382 glVDPAUUnregisterSurfaceNV(it_map->second.glVdpauSurface);
3383 glDeleteTextures(1, it_map->second.texture);
3384 m_bufferPool.glOutputSurfaceMap.erase(it_map);
3387 vdp_st = m_config.vdpProcs.vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3388 CheckStatus(vdp_st, __LINE__);
3390 m_bufferPool.outputSurfaces[i] = VDP_INVALID_HANDLE;
3392 CLog::Log(LOGDEBUG, "VDPAU::PreCleanup - released output surface");
3397 void COutput::InitMixer()
3399 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3401 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3402 &m_bufferPool.outputSurfaces[i],
3403 sizeof(VdpOutputSurface));
3407 bool COutput::MakePixmap(VdpauBufferPool::Pixmaps &pixmap)
3409 CLog::Log(LOGNOTICE,"Creating %ix%i pixmap", m_config.outWidth, m_config.outHeight);
3411 // Get our window attribs.
3412 XWindowAttributes wndattribs;
3413 XGetWindowAttributes(m_Display, g_Windowing.GetWindow(), &wndattribs);
3415 pixmap.pixmap = XCreatePixmap(m_Display,
3416 g_Windowing.GetWindow(),
3422 CLog::Log(LOGERROR, "VDPAU::COUtput::MakePixmap - GLX Error: MakePixmap: Unable to create XPixmap");
3426 // XGCValues values = {};
3428 // values.foreground = BlackPixel (m_Display, DefaultScreen (m_Display));
3429 // xgc = XCreateGC(m_Display, pixmap.pixmap, GCForeground, &values);
3430 // XFillRectangle(m_Display, pixmap.pixmap, xgc, 0, 0, m_config.outWidth, m_config.outHeight);
3431 // XFreeGC(m_Display, xgc);
3433 if(!MakePixmapGL(pixmap))
3439 bool COutput::MakePixmapGL(VdpauBufferPool::Pixmaps &pixmap)
3442 int fbConfigIndex = 0;
3444 int doubleVisAttributes[] = {
3445 GLX_RENDER_TYPE, GLX_RGBA_BIT,
3451 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
3452 GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
3453 GLX_DOUBLEBUFFER, False,
3454 GLX_Y_INVERTED_EXT, True,
3455 GLX_X_RENDERABLE, True,
3459 int pixmapAttribs[] = {
3460 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
3461 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
3465 GLXFBConfig *fbConfigs;
3466 fbConfigs = glXChooseFBConfig(m_Display, g_Windowing.GetCurrentScreen(), doubleVisAttributes, &num);
3467 if (fbConfigs==NULL)
3469 CLog::Log(LOGERROR, "VDPAU::COutput::MakPixmapGL - No compatible framebuffers found");
3474 pixmap.glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], pixmap.pixmap, pixmapAttribs);
3476 if (!pixmap.glPixmap)
3478 CLog::Log(LOGERROR, "VDPAU::COutput::MakPixmapGL - Could not create Pixmap");
3486 bool COutput::GLInit()
3488 glXBindTexImageEXT = NULL;
3489 glXReleaseTexImageEXT = NULL;
3490 #ifdef GL_NV_vdpau_interop
3491 glVDPAUInitNV = NULL;
3492 glVDPAUFiniNV = NULL;
3493 glVDPAURegisterOutputSurfaceNV = NULL;
3494 glVDPAURegisterVideoSurfaceNV = NULL;
3495 glVDPAUIsSurfaceNV = NULL;
3496 glVDPAUUnregisterSurfaceNV = NULL;
3497 glVDPAUSurfaceAccessNV = NULL;
3498 glVDPAUMapSurfacesNV = NULL;
3499 glVDPAUUnmapSurfacesNV = NULL;
3500 glVDPAUGetSurfaceivNV = NULL;
3503 m_config.usePixmaps = false;
3505 #ifdef GL_NV_vdpau_interop
3506 if (glewIsSupported("GL_NV_vdpau_interop"))
3509 glVDPAUInitNV = (PFNGLVDPAUINITNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUInitNV");
3511 glVDPAUFiniNV = (PFNGLVDPAUFININVPROC)glXGetProcAddress((GLubyte *) "glVDPAUFiniNV");
3512 if (!glVDPAURegisterOutputSurfaceNV)
3513 glVDPAURegisterOutputSurfaceNV = (PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterOutputSurfaceNV");
3514 if (!glVDPAURegisterVideoSurfaceNV)
3515 glVDPAURegisterVideoSurfaceNV = (PFNGLVDPAUREGISTERVIDEOSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterVideoSurfaceNV");
3516 if (!glVDPAUIsSurfaceNV)
3517 glVDPAUIsSurfaceNV = (PFNGLVDPAUISSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUIsSurfaceNV");
3518 if (!glVDPAUUnregisterSurfaceNV)
3519 glVDPAUUnregisterSurfaceNV = (PFNGLVDPAUUNREGISTERSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnregisterSurfaceNV");
3520 if (!glVDPAUSurfaceAccessNV)
3521 glVDPAUSurfaceAccessNV = (PFNGLVDPAUSURFACEACCESSNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUSurfaceAccessNV");
3522 if (!glVDPAUMapSurfacesNV)
3523 glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUMapSurfacesNV");
3524 if (!glVDPAUUnmapSurfacesNV)
3525 glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnmapSurfacesNV");
3526 if (!glVDPAUGetSurfaceivNV)
3527 glVDPAUGetSurfaceivNV = (PFNGLVDPAUGETSURFACEIVNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUGetSurfaceivNV");
3529 CLog::Log(LOGNOTICE, "VDPAU::COutput GL interop supported");
3534 m_config.usePixmaps = true;
3535 CSettings::Get().SetBool("videoplayer.usevdpaumixer",true);
3537 if (!glXBindTexImageEXT)
3538 glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT");
3539 if (!glXReleaseTexImageEXT)
3540 glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT");
3542 #ifdef GL_NV_vdpau_interop
3543 if (!m_config.usePixmaps)
3545 while (glGetError() != GL_NO_ERROR);
3546 glVDPAUInitNV(reinterpret_cast<void*>(m_config.vdpDevice), reinterpret_cast<void*>(m_config.vdpProcs.vdp_get_proc_address));
3547 if (glGetError() != GL_NO_ERROR)
3549 CLog::Log(LOGERROR, "VDPAU::COutput - GLInitInterop glVDPAUInitNV failed");
3553 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop initialized");
3558 bool hasfence = glewIsSupported("GL_ARB_sync");
3559 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3561 m_bufferPool.allRenderPics[i]->usefence = hasfence;
3568 void COutput::GLMapSurfaces()
3570 #ifdef GL_NV_vdpau_interop
3571 if (m_config.usePixmaps)
3574 if (m_config.useInteropYuv)
3576 VdpauBufferPool::GLVideoSurface glSurface;
3577 VdpVideoSurface surf;
3578 if (m_config.videoSurfaces->Size() != m_bufferPool.glVideoSurfaceMap.size())
3580 for (unsigned int i = 0; i < m_config.videoSurfaces->Size(); i++)
3582 surf = m_config.videoSurfaces->GetAtIndex(i);
3584 if (surf == VDP_INVALID_HANDLE)
3587 if (m_bufferPool.glVideoSurfaceMap.find(surf) == m_bufferPool.glVideoSurfaceMap.end())
3589 glSurface.sourceVuv = surf;
3590 while (glGetError() != GL_NO_ERROR) ;
3591 glGenTextures(4, glSurface.texture);
3592 if (glGetError() != GL_NO_ERROR)
3594 CLog::Log(LOGERROR, "VDPAU::COutput error creating texture");
3597 glSurface.glVdpauSurface = glVDPAURegisterVideoSurfaceNV(reinterpret_cast<void*>(surf),
3598 GL_TEXTURE_2D, 4, glSurface.texture);
3600 if (glGetError() != GL_NO_ERROR)
3602 CLog::Log(LOGERROR, "VDPAU::COutput error register video surface");
3605 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3606 if (glGetError() != GL_NO_ERROR)
3608 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3611 glVDPAUMapSurfacesNV(1, &glSurface.glVdpauSurface);
3612 if (glGetError() != GL_NO_ERROR)
3614 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3617 m_bufferPool.glVideoSurfaceMap[surf] = glSurface;
3620 CLog::Log(LOGNOTICE, "VDPAU::COutput registered surface");
3627 if (m_bufferPool.glOutputSurfaceMap.size() != m_bufferPool.numOutputSurfaces)
3629 VdpauBufferPool::GLVideoSurface glSurface;
3630 for (unsigned int i = m_bufferPool.glOutputSurfaceMap.size(); i<m_bufferPool.outputSurfaces.size(); i++)
3632 glSurface.sourceRgb = m_bufferPool.outputSurfaces[i];
3633 glGenTextures(1, glSurface.texture);
3634 glSurface.glVdpauSurface = glVDPAURegisterOutputSurfaceNV(reinterpret_cast<void*>(m_bufferPool.outputSurfaces[i]),
3635 GL_TEXTURE_2D, 1, glSurface.texture);
3636 if (glGetError() != GL_NO_ERROR)
3638 CLog::Log(LOGERROR, "VDPAU::COutput error register output surface");
3641 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3642 if (glGetError() != GL_NO_ERROR)
3644 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3647 glVDPAUMapSurfacesNV(1, &glSurface.glVdpauSurface);
3648 if (glGetError() != GL_NO_ERROR)
3650 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3653 m_bufferPool.glOutputSurfaceMap[m_bufferPool.outputSurfaces[i]] = glSurface;
3657 CLog::Log(LOGNOTICE, "VDPAU::COutput registered output surfaces");
3663 void COutput::GLUnmapSurfaces()
3665 #ifdef GL_NV_vdpau_interop
3666 if (m_config.usePixmaps)
3670 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3671 for (it = m_bufferPool.glVideoSurfaceMap.begin(); it != m_bufferPool.glVideoSurfaceMap.end(); ++it)
3673 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3674 glDeleteTextures(4, it->second.texture);
3676 m_bufferPool.glVideoSurfaceMap.clear();
3679 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3680 for (it = m_bufferPool.glOutputSurfaceMap.begin(); it != m_bufferPool.glOutputSurfaceMap.end(); ++it)
3682 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3683 glDeleteTextures(1, it->second.texture);
3685 m_bufferPool.glOutputSurfaceMap.clear();
3689 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop finished");
3694 void COutput::GLBindPixmaps()
3696 if (!m_config.usePixmaps)
3699 for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); i++)
3702 glGenTextures(1, &m_bufferPool.pixmaps[i].texture);
3705 glBindTexture(GL_TEXTURE_2D, m_bufferPool.pixmaps[i].texture);
3708 glXBindTexImageEXT(m_Display, m_bufferPool.pixmaps[i].glPixmap, GLX_FRONT_LEFT_EXT, NULL);
3710 glBindTexture(GL_TEXTURE_2D, 0);
3713 CLog::Log(LOGNOTICE, "VDPAU::COutput: bound pixmaps");
3716 void COutput::GLUnbindPixmaps()
3718 if (!m_config.usePixmaps)
3721 for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); i++)
3724 if (!glIsTexture(m_bufferPool.pixmaps[i].texture))
3728 glBindTexture(GL_TEXTURE_2D, m_bufferPool.pixmaps[i].texture);
3731 glXReleaseTexImageEXT(m_Display, m_bufferPool.pixmaps[i].glPixmap, GLX_FRONT_LEFT_EXT);
3733 glBindTexture(GL_TEXTURE_2D, 0);
3735 glDeleteTextures(1, &m_bufferPool.pixmaps[i].texture);
3737 CLog::Log(LOGNOTICE, "VDPAU::COutput: unbound pixmaps");
3740 bool COutput::CheckStatus(VdpStatus vdp_st, int line)
3742 if (vdp_st != VDP_STATUS_OK)
3744 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
3751 bool COutput::CreateGlxContext()
3753 GLXContext glContext;
3755 m_Display = g_Windowing.GetDisplay();
3756 glContext = g_Windowing.GetGlxContext();
3757 m_Window = g_Windowing.GetWindow();
3759 // Get our window attribs.
3760 XWindowAttributes wndattribs;
3761 XGetWindowAttributes(m_Display, m_Window, &wndattribs);
3764 XVisualInfo visInfo;
3765 visInfo.visualid = wndattribs.visual->visualid;
3767 XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals);
3770 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - could not find visual");
3773 visInfo = visuals[0];
3776 m_pixmap = XCreatePixmap(m_Display,
3783 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - Unable to create XPixmap");
3788 m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap);
3792 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not create glPixmap");
3796 m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True);
3798 if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext))
3800 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not make Pixmap current");
3804 CLog::Log(LOGNOTICE, "VDPAU::COutput::CreateGlxContext - created context");
3808 bool COutput::DestroyGlxContext()
3812 glXMakeCurrent(m_Display, None, NULL);
3813 glXDestroyContext(m_Display, m_glContext);
3818 glXDestroyPixmap(m_Display, m_glPixmap);
3822 XFreePixmap(m_Display, m_pixmap);