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 //-----------------------------------------------------------------------------
84 //-----------------------------------------------------------------------------
86 CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent)
88 m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
89 m_vdpauConfig.videoSurfaces = &m_videoSurfaces;
90 m_vdpauConfig.videoSurfaceSec = &m_videoSurfaceSec;
92 m_vdpauConfigured = false;
93 m_hwContext.bitstream_buffers_allocated = 0;
94 m_DisplayState = VDPAU_OPEN;
97 bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces)
99 if(avctx->coded_width == 0
100 || avctx->coded_height == 0)
102 CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init");
105 m_vdpauConfig.numRenderBuffers = surfaces;
106 m_decoderThread = CThread::GetCurrentThreadId();
108 if ((avctx->codec_id == AV_CODEC_ID_MPEG4) && !g_advancedSettings.m_videoAllowMpeg4VDPAU)
113 dl_handle = dlopen("libvdpau.so.1", RTLD_LAZY);
116 const char* error = dlerror();
118 error = "dlerror() returned NULL";
120 CLog::Log(LOGNOTICE,"(VDPAU) Unable to get handle to libvdpau: %s", error);
125 if (!m_dllAvUtil.Load())
129 m_presentPicture = 0;
131 if (m_vdpauConfig.vdpDevice != VDP_INVALID_HANDLE)
133 SpewHardwareAvailable();
135 VdpDecoderProfile profile = 0;
136 if(avctx->codec_id == AV_CODEC_ID_H264)
137 profile = VDP_DECODER_PROFILE_H264_HIGH;
138 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
139 else if(avctx->codec_id == AV_CODEC_ID_MPEG4)
140 profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
144 if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width))
145 CLog::Log(LOGWARNING,"(VDPAU) width %i might not be supported because of hardware bug", avctx->width);
147 /* attempt to create a decoder with this width/height, some sizes are not supported by hw */
149 vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_create(m_vdpauConfig.vdpDevice, profile, avctx->coded_width, avctx->coded_height, 5, &m_vdpauConfig.vdpDecoder);
151 if(vdp_st != VDP_STATUS_OK)
153 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", m_vdpauConfig.vdpProcs.vdp_get_error_string(vdp_st), vdp_st);
158 m_vdpauConfig.vdpProcs.vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
159 CheckStatus(vdp_st, __LINE__);
162 /* finally setup ffmpeg */
163 memset(&m_hwContext, 0, sizeof(AVVDPAUContext));
164 m_hwContext.render = CDecoder::Render;
165 m_hwContext.bitstream_buffers_allocated = 0;
166 avctx->get_buffer = CDecoder::FFGetBuffer;
167 avctx->release_buffer = CDecoder::FFReleaseBuffer;
168 avctx->draw_horiz_band = CDecoder::FFDrawSlice;
169 avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
170 avctx->hwaccel_context = &m_hwContext;
171 avctx->thread_count = 1;
173 g_Windowing.Register(this);
179 CDecoder::~CDecoder()
184 void CDecoder::Close()
186 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
188 g_Windowing.Unregister(this);
190 CSingleLock lock(m_DecoderSection);
194 m_vdpauOutput.Dispose();
196 while (!m_videoSurfaces.empty())
198 vdpau_render_state *render = m_videoSurfaces.back();
199 m_videoSurfaces.pop_back();
200 if (render->bitstream_buffers_allocated)
201 m_dllAvUtil.av_freep(&render->bitstream_buffers);
202 render->bitstream_buffers_allocated = 0;
206 if (m_hwContext.bitstream_buffers_allocated)
208 m_dllAvUtil.av_freep(&m_hwContext.bitstream_buffers);
211 m_dllAvUtil.Unload();
214 long CDecoder::Release()
216 // check if we should do some pre-cleanup here
217 // a second decoder might need resources
218 if (m_vdpauConfigured == true)
220 CSingleLock lock(m_DecoderSection);
221 CLog::Log(LOGNOTICE,"CVDPAU::Release pre-cleanup");
224 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP,
228 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
232 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup returned error", __FUNCTION__);
233 m_DisplayState = VDPAU_ERROR;
238 CLog::Log(LOGERROR, "VDPAU::%s - pre-cleanup timed out", __FUNCTION__);
239 m_DisplayState = VDPAU_ERROR;
242 for(unsigned int i = 0; i < m_videoSurfaces.size(); ++i)
244 vdpau_render_state *render = m_videoSurfaces[i];
245 if (render->surface != VDP_INVALID_HANDLE && !(render->state & FF_VDPAU_STATE_USED_FOR_RENDER))
247 m_vdpauConfig.vdpProcs.vdp_video_surface_destroy(render->surface);
248 render->surface = VDP_INVALID_HANDLE;
252 return IHardwareDecoder::Release();
255 long CDecoder::ReleasePicReference()
257 return IHardwareDecoder::Release();
260 void CDecoder::SetWidthHeight(int width, int height)
262 m_vdpauConfig.upscale = g_advancedSettings.m_videoVDPAUScaling;
264 //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate
265 //this requires the least amount of gpu memory bandwidth
266 if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || m_vdpauConfig.upscale >= 0)
268 //scale width to desktop size if the aspect ratio is the same or bigger than the desktop
269 if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight())
271 m_vdpauConfig.outWidth = g_graphicsContext.GetWidth();
272 m_vdpauConfig.outHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width);
274 else //scale height to the desktop size if the aspect ratio is smaller than the desktop
276 m_vdpauConfig.outHeight = g_graphicsContext.GetHeight();
277 m_vdpauConfig.outWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height);
282 m_vdpauConfig.outWidth = width;
283 m_vdpauConfig.outHeight = height;
285 CLog::Log(LOGDEBUG, "CVDPAU::SetWidthHeight Setting OutWidth: %i OutHeight: %i", m_vdpauConfig.outWidth, m_vdpauConfig.outHeight);
288 void CDecoder::OnLostDevice()
290 CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event");
292 int count = g_graphicsContext.exit();
294 CSingleLock lock(m_DecoderSection);
298 m_DisplayState = VDPAU_LOST;
300 m_DisplayEvent.Reset();
302 g_graphicsContext.restore(count);
305 void CDecoder::OnResetDevice()
307 CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event");
309 int count = g_graphicsContext.exit();
311 CSingleLock lock(m_DecoderSection);
312 if (m_DisplayState == VDPAU_LOST)
314 m_DisplayState = VDPAU_RESET;
316 m_DisplayEvent.Set();
319 g_graphicsContext.restore(count);
322 int CDecoder::Check(AVCodecContext* avctx)
326 { CSingleLock lock(m_DecoderSection);
327 state = m_DisplayState;
330 if (state == VDPAU_LOST)
332 CLog::Log(LOGNOTICE,"CVDPAU::Check waiting for display reset event");
333 if (!m_DisplayEvent.WaitMSec(2000))
335 CLog::Log(LOGERROR, "CVDPAU::Check - device didn't reset in reasonable time");
340 CSingleLock lock(m_DecoderSection);
341 state = m_DisplayState;
344 if (state == VDPAU_RESET || state == VDPAU_ERROR)
346 CSingleLock lock(m_DecoderSection);
353 if (state == VDPAU_RESET)
361 bool CDecoder::IsVDPAUFormat(PixelFormat format)
363 if (format == AV_PIX_FMT_VDPAU)
369 bool CDecoder::Supports(VdpVideoMixerFeature feature)
371 for(int i = 0; i < m_vdpauConfig.featureCount; i++)
373 if(m_vdpauConfig.vdpFeatures[i] == feature)
379 bool CDecoder::Supports(EINTERLACEMETHOD method)
381 if(method == VS_INTERLACEMETHOD_VDPAU_BOB
382 || method == VS_INTERLACEMETHOD_AUTO)
385 if (!m_vdpauConfig.usePixmaps)
387 if (method == VS_INTERLACEMETHOD_RENDER_BOB)
391 if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE)
394 for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++)
396 if(p->method == method)
397 return Supports(p->feature);
402 EINTERLACEMETHOD CDecoder::AutoInterlaceMethod()
404 return VS_INTERLACEMETHOD_RENDER_BOB;
407 void CDecoder::InitVDPAUProcs()
412 dl_vdp_device_create_x11 = (VdpStatus (*)(Display*, int, VdpDevice*, VdpStatus (**)(VdpDevice, VdpFuncId, void**)))dlsym(dl_handle, (const char*)"vdp_device_create_x11");
416 CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__);
417 m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
421 if (dl_vdp_device_create_x11)
423 m_Display = XOpenDisplay(NULL);
426 int mScreen = g_Windowing.GetCurrentScreen();
430 vdp_st = dl_vdp_device_create_x11(m_Display, //x_display,
432 &m_vdpauConfig.vdpDevice,
433 &m_vdpauConfig.vdpProcs.vdp_get_proc_address);
435 CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",m_vdpauConfig.vdpDevice,vdp_st);
436 if (vdp_st != VDP_STATUS_OK)
438 CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x. Falling back.",vdp_st);
439 m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
443 #define VDP_PROC(id, proc) \
445 vdp_st = m_vdpauConfig.vdpProcs.vdp_get_proc_address(m_vdpauConfig.vdpDevice, id, (void**)&proc); \
446 CheckStatus(vdp_st, __LINE__); \
449 VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING , m_vdpauConfig.vdpProcs.vdp_get_error_string);
450 VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY , m_vdpauConfig.vdpProcs.vdp_device_destroy);
451 VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX , m_vdpauConfig.vdpProcs.vdp_generate_csc_matrix);
452 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE , m_vdpauConfig.vdpProcs.vdp_video_surface_create);
453 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , m_vdpauConfig.vdpProcs.vdp_video_surface_destroy);
454 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , m_vdpauConfig.vdpProcs.vdp_video_surface_put_bits_y_cb_cr);
455 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , m_vdpauConfig.vdpProcs.vdp_video_surface_get_bits_y_cb_cr);
456 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_y_cb_cr);
457 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_native);
458 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , m_vdpauConfig.vdpProcs.vdp_output_surface_create);
459 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , m_vdpauConfig.vdpProcs.vdp_output_surface_destroy);
460 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , m_vdpauConfig.vdpProcs.vdp_output_surface_get_bits_native);
461 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, m_vdpauConfig.vdpProcs.vdp_output_surface_render_output_surface);
462 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , m_vdpauConfig.vdpProcs.vdp_output_surface_put_bits_indexed);
463 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE , m_vdpauConfig.vdpProcs.vdp_video_mixer_create);
464 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , m_vdpauConfig.vdpProcs.vdp_video_mixer_set_feature_enables);
465 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY , m_vdpauConfig.vdpProcs.vdp_video_mixer_destroy);
466 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER , m_vdpauConfig.vdpProcs.vdp_video_mixer_render);
467 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , m_vdpauConfig.vdpProcs.vdp_video_mixer_set_attribute_values);
468 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , m_vdpauConfig.vdpProcs.vdp_video_mixer_query_parameter_support);
469 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , m_vdpauConfig.vdpProcs.vdp_video_mixer_query_feature_support);
470 VDP_PROC(VDP_FUNC_ID_DECODER_CREATE , m_vdpauConfig.vdpProcs.vdp_decoder_create);
471 VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY , m_vdpauConfig.vdpProcs.vdp_decoder_destroy);
472 VDP_PROC(VDP_FUNC_ID_DECODER_RENDER , m_vdpauConfig.vdpProcs.vdp_decoder_render);
473 VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , m_vdpauConfig.vdpProcs.vdp_decoder_query_caps);
474 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY , m_vdpauConfig.vdpProcs.vdp_presentation_queue_target_destroy);
475 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE , m_vdpauConfig.vdpProcs.vdp_presentation_queue_create);
476 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY , m_vdpauConfig.vdpProcs.vdp_presentation_queue_destroy);
477 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY , m_vdpauConfig.vdpProcs.vdp_presentation_queue_display);
478 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE, m_vdpauConfig.vdpProcs.vdp_presentation_queue_block_until_surface_idle);
479 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 , m_vdpauConfig.vdpProcs.vdp_presentation_queue_target_create_x11);
480 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS , m_vdpauConfig.vdpProcs.vdp_presentation_queue_query_surface_status);
481 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME , m_vdpauConfig.vdpProcs.vdp_presentation_queue_get_time);
485 // set all vdpau resources to invalid
486 m_DisplayState = VDPAU_OPEN;
487 m_vdpauConfigured = false;
490 void CDecoder::FiniVDPAUProcs()
492 if (m_vdpauConfig.vdpDevice == VDP_INVALID_HANDLE) return;
495 vdp_st = m_vdpauConfig.vdpProcs.vdp_device_destroy(m_vdpauConfig.vdpDevice);
496 CheckStatus(vdp_st, __LINE__);
497 m_vdpauConfig.vdpDevice = VDP_INVALID_HANDLE;
500 void CDecoder::FiniVDPAUOutput()
502 if (m_vdpauConfig.vdpDevice == VDP_INVALID_HANDLE || !m_vdpauConfigured) return;
504 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
507 m_vdpauOutput.Dispose();
508 m_vdpauConfigured = false;
512 vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
513 if (CheckStatus(vdp_st, __LINE__))
515 m_vdpauConfig.vdpDecoder = VDP_INVALID_HANDLE;
517 CSingleLock lock(m_videoSurfaceSec);
518 CLog::Log(LOGDEBUG, "CVDPAU::FiniVDPAUOutput destroying %d video surfaces", (int)m_videoSurfaces.size());
520 for(unsigned int i = 0; i < m_videoSurfaces.size(); ++i)
522 vdpau_render_state *render = m_videoSurfaces[i];
523 if (render->surface != VDP_INVALID_HANDLE)
525 vdp_st = m_vdpauConfig.vdpProcs.vdp_video_surface_destroy(render->surface);
526 render->surface = VDP_INVALID_HANDLE;
528 if (CheckStatus(vdp_st, __LINE__))
533 void CDecoder::ReadFormatOf( AVCodecID codec
534 , VdpDecoderProfile &vdp_decoder_profile
535 , VdpChromaType &vdp_chroma_type)
539 case AV_CODEC_ID_MPEG1VIDEO:
540 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
541 vdp_chroma_type = VDP_CHROMA_TYPE_420;
543 case AV_CODEC_ID_MPEG2VIDEO:
544 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
545 vdp_chroma_type = VDP_CHROMA_TYPE_420;
547 case AV_CODEC_ID_H264:
548 vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
549 vdp_chroma_type = VDP_CHROMA_TYPE_420;
551 case AV_CODEC_ID_WMV3:
552 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
553 vdp_chroma_type = VDP_CHROMA_TYPE_420;
555 case AV_CODEC_ID_VC1:
556 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
557 vdp_chroma_type = VDP_CHROMA_TYPE_420;
559 case AV_CODEC_ID_MPEG4:
560 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
561 vdp_chroma_type = VDP_CHROMA_TYPE_420;
564 vdp_decoder_profile = 0;
570 bool CDecoder::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
575 VdpDecoderProfile vdp_decoder_profile;
577 m_vdpauConfig.vidWidth = avctx->width;
578 m_vdpauConfig.vidHeight = avctx->height;
579 m_vdpauConfig.surfaceWidth = avctx->coded_width;
580 m_vdpauConfig.surfaceHeight = avctx->coded_height;
582 SetWidthHeight(avctx->width,avctx->height);
584 CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",m_vdpauConfig.outWidth,m_vdpauConfig.vidWidth,m_vdpauConfig.surfaceWidth);
585 CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",m_vdpauConfig.outHeight,m_vdpauConfig.vidHeight,m_vdpauConfig.surfaceHeight);
587 ReadFormatOf(avctx->codec_id, vdp_decoder_profile, m_vdpauConfig.vdpChromaType);
589 if(avctx->codec_id == AV_CODEC_ID_H264)
591 m_vdpauConfig.maxReferences = ref_frames;
592 if (m_vdpauConfig.maxReferences > 16) m_vdpauConfig.maxReferences = 16;
593 if (m_vdpauConfig.maxReferences < 5) m_vdpauConfig.maxReferences = 5;
596 m_vdpauConfig.maxReferences = 2;
598 vdp_st = m_vdpauConfig.vdpProcs.vdp_decoder_create(m_vdpauConfig.vdpDevice,
600 m_vdpauConfig.surfaceWidth,
601 m_vdpauConfig.surfaceHeight,
602 m_vdpauConfig.maxReferences,
603 &m_vdpauConfig.vdpDecoder);
604 if (CheckStatus(vdp_st, __LINE__))
608 CSingleLock lock(g_graphicsContext);
609 m_vdpauConfig.stats = &m_bufferStats;
610 m_vdpauConfig.vdpau = this;
611 m_bufferStats.Reset();
612 m_vdpauOutput.Start();
614 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::INIT,
618 sizeof(m_vdpauConfig)))
620 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
624 data = (CVdpauConfig*)reply->data;
627 m_vdpauConfig.usePixmaps = data->usePixmaps;
633 CLog::Log(LOGERROR, "VDPAU::%s - vdpau output returned error", __FUNCTION__);
634 m_vdpauOutput.Dispose();
640 CLog::Log(LOGERROR, "VDPAU::%s - failed to init output", __FUNCTION__);
641 m_vdpauOutput.Dispose();
645 m_inMsgEvent.Reset();
646 m_vdpauConfigured = true;
650 void CDecoder::SpewHardwareAvailable() //CopyrighVDPAUt (c) 2008 Wladimir J. van der Laan -- VDPInfo
653 CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:");
654 CLog::Log(LOGNOTICE,"name level macbs width height");
655 CLog::Log(LOGNOTICE,"------------------------------------");
656 for(unsigned int x=0; x<decoder_profile_count; ++x)
658 VdpBool is_supported = false;
659 uint32_t max_level, max_macroblocks, max_width, max_height;
660 rv = m_vdpauConfig.vdpProcs.vdp_decoder_query_caps(m_vdpauConfig.vdpDevice, decoder_profiles[x].id,
661 &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
662 if(rv == VDP_STATUS_OK && is_supported)
664 CLog::Log(LOGNOTICE,"%-16s %2i %5i %5i %5i\n", decoder_profiles[x].name,
665 max_level, max_macroblocks, max_width, max_height);
668 CLog::Log(LOGNOTICE,"------------------------------------");
669 m_vdpauConfig.featureCount = 0;
670 #define CHECK_SUPPORT(feature) \
673 if(m_vdpauConfig.vdpProcs.vdp_video_mixer_query_feature_support(m_vdpauConfig.vdpDevice, feature, &supported) == VDP_STATUS_OK && supported) { \
674 CLog::Log(LOGNOTICE, "Mixer feature: "#feature); \
675 m_vdpauConfig.vdpFeatures[m_vdpauConfig.featureCount++] = feature; \
679 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION);
680 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_SHARPNESS);
681 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL);
682 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL);
683 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE);
684 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
685 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1);
686 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2);
687 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3);
688 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4);
689 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5);
690 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6);
691 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7);
692 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8);
693 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9);
699 bool CDecoder::IsSurfaceValid(vdpau_render_state *render)
701 // find render state in queue
704 for(i = 0; i < m_videoSurfaces.size(); ++i)
706 if(m_videoSurfaces[i] == render)
714 CLog::Log(LOGERROR,"%s - video surface not found", __FUNCTION__);
717 if (m_videoSurfaces[i]->surface == VDP_INVALID_HANDLE)
719 m_videoSurfaces[i]->state = 0;
726 int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
728 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
729 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
730 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
732 // while we are waiting to recover we can't do anything
733 CSingleLock lock(vdp->m_DecoderSection);
735 if(vdp->m_DisplayState != VDPAU_OPEN)
737 CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
741 vdpau_render_state * render = NULL;
743 // find unused surface
744 { CSingleLock lock(vdp->m_videoSurfaceSec);
745 for(unsigned int i = 0; i < vdp->m_videoSurfaces.size(); i++)
747 if(!(vdp->m_videoSurfaces[i]->state & (FF_VDPAU_STATE_USED_FOR_REFERENCE | FF_VDPAU_STATE_USED_FOR_RENDER)))
749 render = vdp->m_videoSurfaces[i];
756 VdpStatus vdp_st = VDP_STATUS_ERROR;
759 // create a new surface
760 VdpDecoderProfile profile;
761 ReadFormatOf(avctx->codec_id, profile, vdp->m_vdpauConfig.vdpChromaType);
762 render = (vdpau_render_state*)calloc(sizeof(vdpau_render_state), 1);
765 CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - calloc failed");
768 CSingleLock lock(vdp->m_videoSurfaceSec);
769 render->surface = VDP_INVALID_HANDLE;
770 vdp->m_videoSurfaces.push_back(render);
773 if (render->surface == VDP_INVALID_HANDLE)
775 vdp_st = vdp->m_vdpauConfig.vdpProcs.vdp_video_surface_create(vdp->m_vdpauConfig.vdpDevice,
776 vdp->m_vdpauConfig.vdpChromaType,
780 vdp->CheckStatus(vdp_st, __LINE__);
781 if (vdp_st != VDP_STATUS_OK)
784 CLog::Log(LOGERROR, "CVDPAU::FFGetBuffer - No Video surface available could be created");
789 pic->data[1] = pic->data[2] = NULL;
790 pic->data[0] = (uint8_t*)render;
791 pic->data[3] = (uint8_t*)(uintptr_t)render->surface;
793 pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0;
795 pic->type= FF_BUFFER_TYPE_USER;
797 render->state |= FF_VDPAU_STATE_USED_FOR_REFERENCE;
798 pic->reordered_opaque= avctx->reordered_opaque;
802 void CDecoder::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
804 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
805 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
806 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
808 vdpau_render_state * render;
811 CSingleLock lock(vdp->m_DecoderSection);
813 render=(vdpau_render_state*)pic->data[0];
816 CLog::Log(LOGERROR, "CVDPAU::FFReleaseBuffer - invalid context handle provided");
820 CSingleLock vLock(vdp->m_videoSurfaceSec);
821 render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE;
825 // find render state in queue
826 if (!vdp->IsSurfaceValid(render))
828 CLog::Log(LOGDEBUG, "CVDPAU::FFReleaseBuffer - ignoring invalid buffer");
832 render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE;
835 VdpStatus CDecoder::Render( VdpDecoder decoder, VdpVideoSurface target,
836 VdpPictureInfo const *picture_info,
837 uint32_t bitstream_buffer_count,
838 VdpBitstreamBuffer const * bitstream_buffers)
840 return VDP_STATUS_OK;
843 void CDecoder::FFDrawSlice(struct AVCodecContext *s,
844 const AVFrame *src, int offset[4],
845 int y, int type, int height)
847 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque;
848 CDecoder* vdp = (CDecoder*)ctx->GetHardware();
850 // while we are waiting to recover we can't do anything
851 CSingleLock lock(vdp->m_DecoderSection);
853 if(vdp->m_DisplayState != VDPAU_OPEN)
856 if(src->linesize[0] || src->linesize[1] || src->linesize[2]
857 || offset[0] || offset[1] || offset[2])
859 CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid linesizes or offsets provided");
864 vdpau_render_state * render;
866 render = (vdpau_render_state*)src->data[0];
869 CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid context handle provided");
873 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
874 if (!vdp->IsSurfaceValid(render))
876 CLog::Log(LOGWARNING, "CVDPAU::FFDrawSlice - ignoring invalid buffer");
880 uint32_t max_refs = 0;
881 if(s->codec_id == AV_CODEC_ID_H264)
882 max_refs = vdp->m_hwContext.info.h264.num_ref_frames;
884 if(vdp->m_vdpauConfig.vdpDecoder == VDP_INVALID_HANDLE
885 || vdp->m_vdpauConfigured == false
886 || vdp->m_vdpauConfig.maxReferences < max_refs)
888 if(!vdp->ConfigVDPAU(s, max_refs))
892 // uint64_t startTime = CurrentHostCounter();
893 uint16_t decoded, processed, rend;
894 vdp->m_bufferStats.Get(decoded, processed, rend);
895 vdp_st = vdp->m_vdpauConfig.vdpProcs.vdp_decoder_render(vdp->m_vdpauConfig.vdpDecoder,
897 (VdpPictureInfo const *)&(vdp->m_hwContext.info),
898 vdp->m_hwContext.bitstream_buffers_used,
899 vdp->m_hwContext.bitstream_buffers);
900 vdp->CheckStatus(vdp_st, __LINE__);
901 // uint64_t diff = CurrentHostCounter() - startTime;
902 // if (diff*1000/CurrentHostFrequency() > 30)
903 // CLog::Log(LOGWARNING,"CVDPAU::DrawSlice - VdpDecoderRender long decoding: %d ms, dec: %d, proc: %d, rend: %d", (int)((diff*1000)/CurrentHostFrequency()), decoded, processed, rend);
908 int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame)
910 int result = Check(avctx);
914 CSingleLock lock(m_DecoderSection);
916 if (!m_vdpauConfigured)
920 { // we have a new frame from decoder
922 vdpau_render_state * render = (vdpau_render_state*)pFrame->data[0];
925 CLog::Log(LOGERROR, "CVDPAU::Decode: no valid frame");
929 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
930 if (!IsSurfaceValid(render))
932 CLog::Log(LOGWARNING, "CVDPAU::Decode - ignoring invalid buffer");
936 CSingleLock lock(m_videoSurfaceSec);
937 render->state |= FF_VDPAU_STATE_USED_FOR_RENDER;
940 // send frame to output for processing
941 CVdpauDecodedPicture pic;
942 memset(&pic.DVDPic, 0, sizeof(pic.DVDPic));
943 ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&pic.DVDPic);
945 pic.DVDPic.color_matrix = avctx->colorspace;
946 m_bufferStats.IncDecoded();
947 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::NEWFRAME, &pic, sizeof(pic));
950 // m_codecControl = pic.DVDPic.iFlags & (DVP_FLAG_DRAIN | DVP_FLAG_NO_POSTPROC);
954 uint16_t decoded, processed, render;
956 while (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
958 if (msg->signal == COutputControlProtocol::ERROR)
960 m_DisplayState = VDPAU_ERROR;
966 m_bufferStats.Get(decoded, processed, render);
968 uint64_t startTime = CurrentHostCounter();
971 if (m_vdpauOutput.m_dataPort.ReceiveInMessage(&msg))
973 if (msg->signal == COutputDataProtocol::PICTURE)
975 if (m_presentPicture)
977 m_presentPicture->ReturnUnused();
978 m_presentPicture = 0;
981 m_presentPicture = *(CVdpauRenderPicture**)msg->data;
982 m_presentPicture->vdpau = this;
983 m_bufferStats.DecRender();
984 m_bufferStats.Get(decoded, processed, render);
985 retval |= VC_PICTURE;
991 else if (m_vdpauOutput.m_controlPort.ReceiveInMessage(&msg))
993 if (msg->signal == COutputControlProtocol::STATS)
995 m_bufferStats.Get(decoded, processed, render);
999 m_DisplayState = VDPAU_ERROR;
1006 if (1) //(m_codecControl & DVP_FLAG_DRAIN))
1008 if (decoded + processed + render < 4)
1010 retval |= VC_BUFFER;
1015 if (decoded < 4 && (processed + render) < 3)
1017 retval |= VC_BUFFER;
1021 if (!retval && !m_inMsgEvent.WaitMSec(2000))
1024 uint64_t diff = CurrentHostCounter() - startTime;
1025 if (retval & VC_PICTURE)
1027 m_bufferStats.SetParams(diff, m_codecControl);
1029 if (diff*1000/CurrentHostFrequency() > 50)
1030 CLog::Log(LOGDEBUG,"CVDPAU::Decode long wait: %d", (int)((diff*1000)/CurrentHostFrequency()));
1034 CLog::Log(LOGERROR, "VDPAU::%s - timed out waiting for output message", __FUNCTION__);
1035 m_DisplayState = VDPAU_ERROR;
1042 bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
1044 CSingleLock lock(m_DecoderSection);
1046 if (m_DisplayState != VDPAU_OPEN)
1049 *picture = m_presentPicture->DVDPic;
1050 picture->vdpau = m_presentPicture;
1055 void CDecoder::Reset()
1057 CSingleLock lock(m_DecoderSection);
1059 if (!m_vdpauConfigured)
1063 if (m_vdpauOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::FLUSH,
1067 bool success = reply->signal == COutputControlProtocol::ACC ? true : false;
1071 CLog::Log(LOGERROR, "VDPAU::%s - flush returned error", __FUNCTION__);
1072 m_DisplayState = VDPAU_ERROR;
1075 m_bufferStats.Reset();
1079 CLog::Log(LOGERROR, "VDPAU::%s - flush timed out", __FUNCTION__);
1080 m_DisplayState = VDPAU_ERROR;
1084 bool CDecoder::CanSkipDeint()
1086 return m_bufferStats.CanSkipDeint();
1089 void CDecoder::ReturnRenderPicture(CVdpauRenderPicture *renderPic)
1091 m_vdpauOutput.m_dataPort.SendOutMessage(COutputDataProtocol::RETURNPIC, &renderPic, sizeof(renderPic));
1094 bool CDecoder::CheckStatus(VdpStatus vdp_st, int line)
1096 if (vdp_st != VDP_STATUS_OK)
1098 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_vdpauConfig.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
1100 if(m_DisplayState == VDPAU_OPEN)
1102 if (vdp_st == VDP_STATUS_DISPLAY_PREEMPTED)
1104 m_DisplayEvent.Reset();
1105 m_DisplayState = VDPAU_LOST;
1108 m_DisplayState = VDPAU_ERROR;
1116 //-----------------------------------------------------------------------------
1118 //-----------------------------------------------------------------------------
1120 CVdpauRenderPicture* CVdpauRenderPicture::Acquire()
1122 CSingleLock lock(renderPicSection);
1131 long CVdpauRenderPicture::Release()
1133 CSingleLock lock(renderPicSection);
1140 vdpau->ReturnRenderPicture(this);
1141 vdpau->ReleasePicReference();
1146 void CVdpauRenderPicture::ReturnUnused()
1148 { CSingleLock lock(renderPicSection);
1153 vdpau->ReturnRenderPicture(this);
1156 void CVdpauRenderPicture::Sync()
1159 CSingleLock lock(renderPicSection);
1164 glDeleteSync(fence);
1167 fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1172 //-----------------------------------------------------------------------------
1174 //-----------------------------------------------------------------------------
1175 CMixer::CMixer(CEvent *inMsgEvent) :
1176 CThread("Vdpau Mixer Thread"),
1177 m_controlPort("ControlPort", inMsgEvent, &m_outMsgEvent),
1178 m_dataPort("DataPort", inMsgEvent, &m_outMsgEvent)
1180 m_inMsgEvent = inMsgEvent;
1188 void CMixer::Start()
1193 void CMixer::Dispose()
1196 m_outMsgEvent.Set();
1199 m_controlPort.Purge();
1203 bool CMixer::IsActive()
1208 void CMixer::OnStartup()
1210 CLog::Log(LOGNOTICE, "CMixer::OnStartup: Output Thread created");
1213 void CMixer::OnExit()
1215 CLog::Log(LOGNOTICE, "CMixer::OnExit: Output Thread terminated");
1222 M_TOP_UNCONFIGURED, // 2
1223 M_TOP_CONFIGURED, // 3
1224 M_TOP_CONFIGURED_WAIT1, // 4
1225 M_TOP_CONFIGURED_STEP1, // 5
1226 M_TOP_CONFIGURED_WAIT2, // 6
1227 M_TOP_CONFIGURED_STEP2, // 7
1230 int MIXER_parentStates[] = {
1233 0, //TOP_UNCONFIGURED
1235 3, //TOP_CONFIGURED_WAIT1
1236 3, //TOP_CONFIGURED_STEP1
1237 3, //TOP_CONFIGURED_WAIT2
1238 3, //TOP_CONFIGURED_STEP2
1241 void CMixer::StateMachine(int signal, Protocol *port, Message *msg)
1243 for (int state = m_state; ; state = MIXER_parentStates[state])
1248 if (port == &m_controlPort)
1252 case CMixerControlProtocol::FLUSH:
1254 msg->Reply(CMixerControlProtocol::ACC);
1261 std::string portName = port == NULL ? "timer" : port->portName;
1262 CLog::Log(LOGWARNING, "CMixer::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
1266 case M_TOP_ERROR: // TOP
1269 case M_TOP_UNCONFIGURED:
1270 if (port == &m_controlPort)
1274 case CMixerControlProtocol::INIT:
1276 data = (CVdpauConfig*)msg->data;
1284 m_state = M_TOP_CONFIGURED_WAIT1;
1285 msg->Reply(CMixerControlProtocol::ACC);
1289 msg->Reply(CMixerControlProtocol::ERROR);
1298 case M_TOP_CONFIGURED:
1299 if (port == &m_dataPort)
1303 case CMixerDataProtocol::FRAME:
1304 CVdpauDecodedPicture *frame;
1305 frame = (CVdpauDecodedPicture*)msg->data;
1308 m_decodedPics.push(*frame);
1312 case CMixerDataProtocol::BUFFER:
1313 VdpOutputSurface *surf;
1314 surf = (VdpOutputSurface*)msg->data;
1317 m_outputSurfaces.push(*surf);
1327 case M_TOP_CONFIGURED_WAIT1:
1328 if (port == NULL) // timeout
1332 case CMixerControlProtocol::TIMEOUT:
1333 if (!m_decodedPics.empty() && !m_outputSurfaces.empty())
1335 m_state = M_TOP_CONFIGURED_STEP1;
1336 m_bStateMachineSelfTrigger = true;
1340 // if (m_extTimeout != 0)
1342 // SetPostProcFeatures(false);
1343 // CLog::Log(LOGWARNING,"CVDPAU::Mixer timeout - decoded: %d, outputSurf: %d", (int)m_decodedPics.size(), (int)m_outputSurfaces.size());
1354 case M_TOP_CONFIGURED_STEP1:
1355 if (port == NULL) // timeout
1359 case CMixerControlProtocol::TIMEOUT:
1360 m_mixerInput.push_front(m_decodedPics.front());
1361 m_decodedPics.pop();
1362 if (m_mixerInput.size() < 2)
1364 m_state = M_TOP_CONFIGURED_WAIT1;
1372 m_state = M_TOP_CONFIGURED_WAIT1;
1373 m_extTimeout = 1000;
1376 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1377 m_outputSurfaces.pop();
1378 m_config.stats->IncProcessed();
1379 m_config.stats->DecDecoded();
1380 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1381 if (m_mixersteps > 1)
1383 m_state = M_TOP_CONFIGURED_WAIT2;
1389 m_state = M_TOP_CONFIGURED_WAIT1;
1399 case M_TOP_CONFIGURED_WAIT2:
1400 if (port == NULL) // timeout
1404 case CMixerControlProtocol::TIMEOUT:
1405 if (!m_outputSurfaces.empty())
1407 m_state = M_TOP_CONFIGURED_STEP2;
1408 m_bStateMachineSelfTrigger = true;
1412 // if (m_extTimeout != 0)
1414 // SetPostProcFeatures(false);
1415 // CLog::Log(LOGNOTICE,"---mixer wait2 decoded: %d, outputSurf: %d", (int)m_decodedPics.size(), (int)m_outputSurfaces.size());
1426 case M_TOP_CONFIGURED_STEP2:
1427 if (port == NULL) // timeout
1431 case CMixerControlProtocol::TIMEOUT:
1432 m_processPicture.outputSurface = m_outputSurfaces.front();
1437 m_state = M_TOP_CONFIGURED_WAIT1;
1438 m_extTimeout = 1000;
1441 if (m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
1442 m_outputSurfaces.pop();
1443 m_config.stats->IncProcessed();
1444 m_dataPort.SendInMessage(CMixerDataProtocol::PICTURE,&m_processPicture,sizeof(m_processPicture));
1446 m_state = M_TOP_CONFIGURED_WAIT1;
1455 default: // we are in no state, should not happen
1456 CLog::Log(LOGERROR, "CMixer::%s - no valid state: %d", __FUNCTION__, m_state);
1462 void CMixer::Process()
1464 Message *msg = NULL;
1465 Protocol *port = NULL;
1468 m_state = M_TOP_UNCONFIGURED;
1469 m_extTimeout = 1000;
1470 m_bStateMachineSelfTrigger = false;
1476 if (m_bStateMachineSelfTrigger)
1478 m_bStateMachineSelfTrigger = false;
1479 // self trigger state machine
1480 StateMachine(msg->signal, port, msg);
1481 if (!m_bStateMachineSelfTrigger)
1488 // check control port
1489 else if (m_controlPort.ReceiveOutMessage(&msg))
1492 port = &m_controlPort;
1495 else if (m_dataPort.ReceiveOutMessage(&msg))
1503 StateMachine(msg->signal, port, msg);
1504 if (!m_bStateMachineSelfTrigger)
1513 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
1520 msg = m_controlPort.GetMessage();
1521 msg->signal = CMixerControlProtocol::TIMEOUT;
1523 // signal timeout to state machine
1524 StateMachine(msg->signal, port, msg);
1525 if (!m_bStateMachineSelfTrigger)
1535 void CMixer::CreateVdpauMixer()
1537 CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer");
1539 InitCSCMatrix(m_config.vidWidth);
1541 VdpVideoMixerParameter parameters[] = {
1542 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
1543 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
1544 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE};
1546 void const * parameter_values[] = {
1547 &m_config.surfaceWidth,
1548 &m_config.surfaceHeight,
1549 &m_config.vdpChromaType};
1551 VdpStatus vdp_st = VDP_STATUS_ERROR;
1552 vdp_st = m_config.vdpProcs.vdp_video_mixer_create(m_config.vdpDevice,
1553 m_config.featureCount,
1554 m_config.vdpFeatures,
1559 CheckStatus(vdp_st, __LINE__);
1561 // create 3 pitches of black lines needed for clipping top
1562 // and bottom lines when de-interlacing
1563 m_BlackBar = new uint32_t[3*m_config.outWidth];
1564 memset(m_BlackBar, 0, 3*m_config.outWidth*sizeof(uint32_t));
1568 void CMixer::InitCSCMatrix(int Width)
1570 m_Procamp.struct_version = VDP_PROCAMP_VERSION;
1571 m_Procamp.brightness = 0.0;
1572 m_Procamp.contrast = 1.0;
1573 m_Procamp.saturation = 1.0;
1577 void CMixer::CheckFeatures()
1579 if (m_Upscale != m_config.upscale)
1582 m_Upscale = m_config.upscale;
1584 if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness ||
1585 m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast ||
1586 m_ColorMatrix != m_mixerInput[1].DVDPic.color_matrix)
1589 m_Brightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness;
1590 m_Contrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast;
1591 m_ColorMatrix = m_mixerInput[1].DVDPic.color_matrix;
1593 if (m_NoiseReduction != CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1595 m_NoiseReduction = CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction;
1596 SetNoiseReduction();
1598 if (m_Sharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1600 m_Sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
1603 if (m_DeintMode != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode ||
1604 m_Deint != CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod)
1606 m_DeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1607 m_Deint = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1612 void CMixer::SetPostProcFeatures(bool postProcEnabled)
1614 if (m_PostProc != postProcEnabled)
1616 if (postProcEnabled)
1618 SetNoiseReduction();
1625 m_PostProc = postProcEnabled;
1629 void CMixer::PostProcOff()
1633 if (m_videoMixer == VDP_INVALID_HANDLE)
1636 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
1637 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
1638 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE};
1640 VdpBool enabled[]={0,0,0};
1641 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1642 CheckStatus(vdp_st, __LINE__);
1644 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1646 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION};
1648 VdpBool enabled[]={0};
1649 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1650 CheckStatus(vdp_st, __LINE__);
1653 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1655 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS};
1657 VdpBool enabled[]={0};
1658 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1659 CheckStatus(vdp_st, __LINE__);
1665 bool CMixer::GenerateStudioCSCMatrix(VdpColorStandard colorStandard, VdpCSCMatrix &studioCSCMatrix)
1667 // instead use studioCSCKCoeffs601[3], studioCSCKCoeffs709[3] to generate float[3][4] matrix (float studioCSC[3][4])
1668 // m00 = mRY = red: luma factor (contrast factor) (1.0)
1669 // m10 = mGY = green: luma factor (contrast factor) (1.0)
1670 // m20 = mBY = blue: luma factor (contrast factor) (1.0)
1672 // m01 = mRB = red: blue color diff coeff (0.0)
1673 // m11 = mGB = green: blue color diff coeff (-2Kb(1-Kb)/(Kg))
1674 // m21 = mBB = blue: blue color diff coeff ((1-Kb)/0.5)
1676 // m02 = mRR = red: red color diff coeff ((1-Kr)/0.5)
1677 // m12 = mGR = green: red color diff coeff (-2Kr(1-Kr)/(Kg))
1678 // m22 = mBR = blue: red color diff coeff (0.0)
1680 // m03 = mRC = red: colour zero offset (brightness factor) (-(1-Kr)/0.5 * (128/255))
1681 // m13 = mGC = green: colour zero offset (brightness factor) ((256/255) * (Kb(1-Kb) + Kr(1-Kr)) / Kg)
1682 // m23 = mBC = blue: colour zero offset (brightness factor) (-(1-Kb)/0.5 * (128/255))
1693 // colour standard coefficients for red, geen, blue
1695 // colour diff zero position (use standard 8-bit coding precision)
1696 double CDZ = 128; //256*0.5
1697 // range excursion (use standard 8-bit coding precision)
1698 double EXC = 255; //256-1
1700 if (colorStandard == VDP_COLOR_STANDARD_ITUR_BT_601)
1702 Kr = studioCSCKCoeffs601[0];
1703 Kg = studioCSCKCoeffs601[1];
1704 Kb = studioCSCKCoeffs601[2];
1706 else // assume VDP_COLOR_STANDARD_ITUR_BT_709
1708 Kr = studioCSCKCoeffs709[0];
1709 Kg = studioCSCKCoeffs709[1];
1710 Kb = studioCSCKCoeffs709[2];
1712 // we keep luma unscaled to retain the levels present in source so that 16-235 luma is converted to RGB 16-235
1713 studioCSCMatrix[R][Y] = 1.0;
1714 studioCSCMatrix[G][Y] = 1.0;
1715 studioCSCMatrix[B][Y] = 1.0;
1717 studioCSCMatrix[R][Cb] = 0.0;
1718 studioCSCMatrix[G][Cb] = (double)-2 * Kb * (1 - Kb) / Kg;
1719 studioCSCMatrix[B][Cb] = (double)(1 - Kb) / 0.5;
1721 studioCSCMatrix[R][Cr] = (double)(1 - Kr) / 0.5;
1722 studioCSCMatrix[G][Cr] = (double)-2 * Kr * (1 - Kr) / Kg;
1723 studioCSCMatrix[B][Cr] = 0.0;
1725 studioCSCMatrix[R][C] = (double)-1 * studioCSCMatrix[R][Cr] * CDZ/EXC;
1726 studioCSCMatrix[G][C] = (double)-1 * (studioCSCMatrix[G][Cb] + studioCSCMatrix[G][Cr]) * CDZ/EXC;
1727 studioCSCMatrix[B][C] = (double)-1 * studioCSCMatrix[B][Cb] * CDZ/EXC;
1732 void CMixer::SetColor()
1736 if (m_Brightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)
1737 m_Procamp.brightness = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)-50) / 100;
1738 if (m_Contrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)
1739 m_Procamp.contrast = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)+50) / 100;
1741 VdpColorStandard colorStandard;
1742 switch(m_mixerInput[1].DVDPic.color_matrix)
1744 case AVCOL_SPC_BT709:
1745 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1747 case AVCOL_SPC_BT470BG:
1748 case AVCOL_SPC_SMPTE170M:
1749 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1751 case AVCOL_SPC_SMPTE240M:
1752 colorStandard = VDP_COLOR_STANDARD_SMPTE_240M;
1755 case AVCOL_SPC_UNSPECIFIED:
1758 if(m_config.surfaceWidth > 1000)
1759 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_709;
1761 colorStandard = VDP_COLOR_STANDARD_ITUR_BT_601;
1764 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
1765 if (CSettings::Get().GetBool("videoscreen.limitedrange"))
1767 float studioCSC[3][4];
1768 GenerateStudioCSCMatrix(colorStandard, studioCSC);
1769 void const * pm_CSCMatix[] = { &studioCSC };
1770 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1774 vdp_st = m_config.vdpProcs.vdp_generate_csc_matrix(&m_Procamp, colorStandard, &m_CSCMatrix);
1775 void const * pm_CSCMatix[] = { &m_CSCMatrix };
1776 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
1779 CheckStatus(vdp_st, __LINE__);
1782 void CMixer::SetNoiseReduction()
1784 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
1787 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION };
1788 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL };
1791 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
1793 VdpBool enabled[]= {0};
1794 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1795 CheckStatus(vdp_st, __LINE__);
1798 VdpBool enabled[]={1};
1799 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1800 CheckStatus(vdp_st, __LINE__);
1801 void* nr[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction };
1802 CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction);
1803 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, nr);
1804 CheckStatus(vdp_st, __LINE__);
1807 void CMixer::SetSharpness()
1809 if(!m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
1812 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS };
1813 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL };
1816 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
1818 VdpBool enabled[]={0};
1819 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1820 CheckStatus(vdp_st, __LINE__);
1823 VdpBool enabled[]={1};
1824 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1825 CheckStatus(vdp_st, __LINE__);
1826 void* sh[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness };
1827 CLog::Log(LOGNOTICE,"Setting Sharpness to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness);
1828 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attributes), attributes, sh);
1829 CheckStatus(vdp_st, __LINE__);
1832 EINTERLACEMETHOD CMixer::GetDeinterlacingMethod(bool log /* = false */)
1834 EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1835 if (method == VS_INTERLACEMETHOD_AUTO)
1838 // if (m_config.outHeight >= 720)
1839 // deint = g_advancedSettings.m_videoVDPAUdeintHD;
1841 // deint = g_advancedSettings.m_videoVDPAUdeintSD;
1845 if (m_config.vdpau->Supports(EINTERLACEMETHOD(deint)))
1847 method = EINTERLACEMETHOD(deint);
1849 CLog::Log(LOGNOTICE, "CVDPAU::GetDeinterlacingMethod: set de-interlacing to %d", deint);
1854 CLog::Log(LOGWARNING, "CVDPAU::GetDeinterlacingMethod: method for de-interlacing (advanced settings) not supported");
1861 void CMixer::SetDeinterlacing()
1865 if (m_videoMixer == VDP_INVALID_HANDLE)
1868 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1869 EINTERLACEMETHOD method = GetDeinterlacingMethod(true);
1871 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
1872 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
1873 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE };
1875 if (mode == VS_DEINTERLACEMODE_OFF)
1877 VdpBool enabled[] = {0,0,0};
1878 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1882 if (method == VS_INTERLACEMETHOD_AUTO)
1884 VdpBool enabled[] = {1,0,0};
1885 if (g_advancedSettings.m_videoVDPAUtelecine)
1887 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1889 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
1890 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF)
1892 VdpBool enabled[] = {1,0,0};
1893 if (g_advancedSettings.m_videoVDPAUtelecine)
1895 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1897 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
1898 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF)
1900 VdpBool enabled[] = {1,1,0};
1901 if (g_advancedSettings.m_videoVDPAUtelecine)
1903 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1907 VdpBool enabled[]={0,0,0};
1908 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1911 CheckStatus(vdp_st, __LINE__);
1913 SetDeintSkipChroma();
1915 m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
1918 void CMixer::SetDeintSkipChroma()
1920 VdpVideoMixerAttribute attribute[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE};
1924 if (g_advancedSettings.m_videoVDPAUdeintSkipChromaHD && m_config.outHeight >= 720)
1929 void const *values[]={&val};
1930 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_attribute_values(m_videoMixer, ARSIZE(attribute), attribute, values);
1932 CheckStatus(vdp_st, __LINE__);
1935 void CMixer::SetHWUpscaling()
1937 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
1940 VdpBool enabled[]={1};
1941 switch (m_config.upscale)
1944 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
1946 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
1947 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1951 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
1953 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
1954 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1958 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
1960 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
1961 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1965 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
1967 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
1968 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1972 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
1974 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
1975 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1979 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
1981 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
1982 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1986 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
1988 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
1989 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
1993 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
1995 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
1996 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2000 if (m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2002 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2003 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2010 CheckStatus(vdp_st, __LINE__);
2014 void CMixer::DisableHQScaling()
2018 if (m_videoMixer == VDP_INVALID_HANDLE)
2021 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1))
2023 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
2024 VdpBool enabled[]={0};
2025 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2026 CheckStatus(vdp_st, __LINE__);
2029 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2))
2031 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2 };
2032 VdpBool enabled[]={0};
2033 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2034 CheckStatus(vdp_st, __LINE__);
2037 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3))
2039 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3 };
2040 VdpBool enabled[]={0};
2041 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2042 CheckStatus(vdp_st, __LINE__);
2045 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4))
2047 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4 };
2048 VdpBool enabled[]={0};
2049 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2050 CheckStatus(vdp_st, __LINE__);
2053 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5))
2055 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5 };
2056 VdpBool enabled[]={0};
2057 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2058 CheckStatus(vdp_st, __LINE__);
2061 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6))
2063 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6 };
2064 VdpBool enabled[]={0};
2065 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2066 CheckStatus(vdp_st, __LINE__);
2069 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7))
2071 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7 };
2072 VdpBool enabled[]={0};
2073 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2074 CheckStatus(vdp_st, __LINE__);
2077 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8))
2079 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8 };
2080 VdpBool enabled[]={0};
2081 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2082 CheckStatus(vdp_st, __LINE__);
2085 if(m_config.vdpau->Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9))
2087 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9 };
2088 VdpBool enabled[]={0};
2089 vdp_st = m_config.vdpProcs.vdp_video_mixer_set_feature_enables(m_videoMixer, ARSIZE(feature), feature, enabled);
2090 CheckStatus(vdp_st, __LINE__);
2099 m_NoiseReduction = 0.0;
2107 m_config.upscale = g_advancedSettings.m_videoVDPAUScaling;
2108 m_config.useInteropYuv = !CSettings::Get().GetBool("videoplayer.usevdpaumixer");
2113 void CMixer::Uninit()
2116 while (!m_outputSurfaces.empty())
2118 m_outputSurfaces.pop();
2120 m_config.vdpProcs.vdp_video_mixer_destroy(m_videoMixer);
2122 delete [] m_BlackBar;
2125 void CMixer::Flush()
2127 while (!m_mixerInput.empty())
2129 CVdpauDecodedPicture pic = m_mixerInput.back();
2130 m_mixerInput.pop_back();
2131 CSingleLock lock(*m_config.videoSurfaceSec);
2133 pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
2135 while (!m_decodedPics.empty())
2137 CVdpauDecodedPicture pic = m_decodedPics.front();
2138 m_decodedPics.pop();
2139 CSingleLock lock(*m_config.videoSurfaceSec);
2141 pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
2144 while (m_dataPort.ReceiveOutMessage(&msg))
2146 if (msg->signal == CMixerDataProtocol::FRAME)
2148 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2149 CSingleLock lock(*m_config.videoSurfaceSec);
2151 pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
2153 else if (msg->signal == CMixerDataProtocol::BUFFER)
2155 VdpOutputSurface *surf;
2156 surf = (VdpOutputSurface*)msg->data;
2157 m_outputSurfaces.push(*surf);
2163 void CMixer::InitCycle()
2168 m_config.stats->GetParams(latency, flags);
2169 latency = (latency*1000)/CurrentHostFrequency();
2171 if (0) //flags & DVP_FLAG_NO_POSTPROC)
2172 SetPostProcFeatures(false);
2174 SetPostProcFeatures(true);
2176 m_config.stats->SetCanSkipDeint(false);
2178 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
2179 EINTERLACEMETHOD method = GetDeinterlacingMethod();
2180 bool interlaced = m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_INTERLACED;
2183 if (//!(flags & DVP_FLAG_NO_POSTPROC) &&
2184 (mode == VS_DEINTERLACEMODE_FORCE ||
2185 (mode == VS_DEINTERLACEMODE_AUTO && interlaced)))
2187 if((method == VS_INTERLACEMETHOD_AUTO && interlaced)
2188 || method == VS_INTERLACEMETHOD_VDPAU_BOB
2189 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
2190 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2191 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
2192 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2193 || method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE )
2195 if(method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
2196 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
2197 || !g_graphicsContext.IsFullScreenVideo())
2202 m_config.stats->SetCanSkipDeint(true);
2206 if (0) //m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_DROPDEINT)
2211 if(m_mixerInput[1].DVDPic.iFlags & DVP_FLAG_TOP_FIELD_FIRST)
2212 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2214 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2216 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2217 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2218 DVP_FLAG_REPEAT_TOP_FIELD |
2219 DVP_FLAG_INTERLACED);
2220 m_config.useInteropYuv = false;
2222 else if (method == VS_INTERLACEMETHOD_RENDER_BOB)
2225 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2226 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2227 m_config.useInteropYuv = true;
2231 CLog::Log(LOGERROR, "CMixer::%s - interlace method: %d not supported, setting to AUTO", __FUNCTION__, method);
2233 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2234 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2235 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2236 DVP_FLAG_REPEAT_TOP_FIELD |
2237 DVP_FLAG_INTERLACED);
2239 CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod = VS_INTERLACEMETHOD_AUTO;
2245 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
2247 if (m_config.useInteropYuv)
2248 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU_420;
2251 m_mixerInput[1].DVDPic.format = RENDER_FMT_VDPAU;
2252 m_mixerInput[1].DVDPic.iFlags &= ~(DVP_FLAG_TOP_FIELD_FIRST |
2253 DVP_FLAG_REPEAT_TOP_FIELD |
2254 DVP_FLAG_INTERLACED);
2259 if (m_mixerInput[1].DVDPic.format == RENDER_FMT_VDPAU)
2261 m_processPicture.outputSurface = m_outputSurfaces.front();
2262 m_mixerInput[1].DVDPic.iWidth = m_config.outWidth;
2263 m_mixerInput[1].DVDPic.iHeight = m_config.outHeight;
2267 m_mixerInput[1].DVDPic.iWidth = m_config.vidWidth;
2268 m_mixerInput[1].DVDPic.iHeight = m_config.vidHeight;
2271 m_processPicture.DVDPic = m_mixerInput[1].DVDPic;
2272 m_processPicture.render = m_mixerInput[1].render;
2275 void CMixer::FiniCycle()
2277 while (m_mixerInput.size() > 3)
2279 CVdpauDecodedPicture &tmp = m_mixerInput.back();
2280 if (tmp.render && m_processPicture.DVDPic.format != RENDER_FMT_VDPAU_420)
2282 CSingleLock lock(*m_config.videoSurfaceSec);
2283 tmp.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
2285 m_mixerInput.pop_back();
2286 // m_config.stats->DecDecoded();
2290 void CMixer::ProcessPicture()
2292 if (m_processPicture.DVDPic.format == RENDER_FMT_VDPAU_420)
2297 if (m_mixerstep == 1)
2299 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD)
2300 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
2302 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
2305 VdpVideoSurface past_surfaces[4] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2306 VdpVideoSurface futu_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
2307 uint32_t pastCount = 4;
2308 uint32_t futuCount = 2;
2310 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
2312 // use only 2 past 1 future for progressive/weave
2313 // (only used for postproc anyway eg noise reduction)
2314 if (m_mixerInput.size() > 3)
2315 past_surfaces[1] = m_mixerInput[3].render->surface;
2316 if (m_mixerInput.size() > 2)
2317 past_surfaces[0] = m_mixerInput[2].render->surface;
2318 futu_surfaces[0] = m_mixerInput[0].render->surface;
2324 if(m_mixerstep == 0)
2326 if (m_mixerInput.size() > 3)
2328 past_surfaces[3] = m_mixerInput[3].render->surface;
2329 past_surfaces[2] = m_mixerInput[3].render->surface;
2331 if (m_mixerInput.size() > 2)
2333 past_surfaces[1] = m_mixerInput[2].render->surface;
2334 past_surfaces[0] = m_mixerInput[2].render->surface;
2336 futu_surfaces[0] = m_mixerInput[1].render->surface;
2337 futu_surfaces[1] = m_mixerInput[0].render->surface;;
2341 if (m_mixerInput.size() > 3)
2343 past_surfaces[3] = m_mixerInput[3].render->surface;
2345 if (m_mixerInput.size() > 2)
2347 past_surfaces[2] = m_mixerInput[2].render->surface;
2348 past_surfaces[1] = m_mixerInput[2].render->surface;
2350 past_surfaces[0] = m_mixerInput[1].render->surface;
2351 futu_surfaces[0] = m_mixerInput[1].render->surface;
2352 futu_surfaces[1] = m_mixerInput[1].render->surface;
2354 if (m_mixerInput[0].DVDPic.pts != DVD_NOPTS_VALUE &&
2355 m_mixerInput[1].DVDPic.pts != DVD_NOPTS_VALUE)
2357 m_processPicture.DVDPic.pts = m_mixerInput[1].DVDPic.pts +
2358 (m_mixerInput[0].DVDPic.pts -
2359 m_mixerInput[1].DVDPic.pts) / 2;
2362 m_processPicture.DVDPic.pts = DVD_NOPTS_VALUE;
2363 m_processPicture.DVDPic.dts = DVD_NOPTS_VALUE;
2365 m_processPicture.DVDPic.iRepeatPicture = 0.0;
2371 sourceRect.x1 = m_config.vidWidth;
2372 sourceRect.y1 = m_config.vidHeight;
2377 destRect.x1 = m_config.outWidth;
2378 destRect.y1 = m_config.outHeight;
2380 // start vdpau video mixer
2381 vdp_st = m_config.vdpProcs.vdp_video_mixer_render(m_videoMixer,
2387 m_mixerInput[1].render->surface,
2391 m_processPicture.outputSurface,
2396 CheckStatus(vdp_st, __LINE__);
2398 if (m_mixerfield != VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
2400 // in order to clip top and bottom lines when de-interlacing
2401 // we black those lines as a work around for not working
2402 // background colour using the mixer
2403 // pixel perfect is preferred over overscanning or zooming
2405 VdpRect clipRect = destRect;
2406 clipRect.y1 = clipRect.y0 + 2;
2407 uint32_t *data[] = {m_BlackBar};
2408 uint32_t pitches[] = {destRect.x1};
2409 vdp_st = m_config.vdpProcs.vdp_output_surface_put_bits_native(m_processPicture.outputSurface,
2413 CheckStatus(vdp_st, __LINE__);
2415 clipRect = destRect;
2416 clipRect.y0 = clipRect.y1 - 2;
2417 vdp_st = m_config.vdpProcs.vdp_output_surface_put_bits_native(m_processPicture.outputSurface,
2421 CheckStatus(vdp_st, __LINE__);
2426 bool CMixer::CheckStatus(VdpStatus vdp_st, int line)
2428 if (vdp_st != VDP_STATUS_OK)
2430 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
2437 //-----------------------------------------------------------------------------
2439 //-----------------------------------------------------------------------------
2441 VdpauBufferPool::VdpauBufferPool()
2443 CVdpauRenderPicture *pic;
2444 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2446 pic = new CVdpauRenderPicture(renderPicSec);
2447 allRenderPics.push_back(pic);
2451 VdpauBufferPool::~VdpauBufferPool()
2453 CVdpauRenderPicture *pic;
2454 for (unsigned int i = 0; i < NUM_RENDER_PICS; i++)
2456 pic = allRenderPics[i];
2459 allRenderPics.clear();
2462 //-----------------------------------------------------------------------------
2464 //-----------------------------------------------------------------------------
2465 COutput::COutput(CEvent *inMsgEvent) :
2466 CThread("Vdpau Output Thread"),
2467 m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent),
2468 m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent),
2469 m_mixer(&m_outMsgEvent)
2471 m_inMsgEvent = inMsgEvent;
2473 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); ++i)
2475 m_bufferPool.freeRenderPics.push_back(i);
2479 void COutput::Start()
2488 m_bufferPool.freeRenderPics.clear();
2489 m_bufferPool.usedRenderPics.clear();
2492 void COutput::Dispose()
2494 CSingleLock lock(g_graphicsContext);
2496 m_outMsgEvent.Set();
2498 m_controlPort.Purge();
2502 void COutput::OnStartup()
2504 CLog::Log(LOGNOTICE, "COutput::OnStartup: Output Thread created");
2507 void COutput::OnExit()
2509 CLog::Log(LOGNOTICE, "COutput::OnExit: Output Thread terminated");
2516 O_TOP_UNCONFIGURED, // 2
2517 O_TOP_CONFIGURED, // 3
2518 O_TOP_CONFIGURED_IDLE, // 4
2519 O_TOP_CONFIGURED_WORK, // 5
2522 int VDPAU_OUTPUT_parentStates[] = {
2525 0, //TOP_UNCONFIGURED
2527 3, //TOP_CONFIGURED_IDLE
2528 3, //TOP_CONFIGURED_WORK
2531 void COutput::StateMachine(int signal, Protocol *port, Message *msg)
2533 for (int state = m_state; ; state = VDPAU_OUTPUT_parentStates[state])
2538 if (port == &m_controlPort)
2542 case COutputControlProtocol::FLUSH:
2543 msg->Reply(COutputControlProtocol::ACC);
2545 case COutputControlProtocol::PRECLEANUP:
2546 msg->Reply(COutputControlProtocol::ACC);
2552 else if (port == &m_dataPort)
2556 case COutputDataProtocol::RETURNPIC:
2557 CVdpauRenderPicture *pic;
2558 pic = *((CVdpauRenderPicture**)msg->data);
2559 QueueReturnPicture(pic);
2566 std::string portName = port == NULL ? "timer" : port->portName;
2567 CLog::Log(LOGWARNING, "COutput::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
2574 case O_TOP_UNCONFIGURED:
2575 if (port == &m_controlPort)
2579 case COutputControlProtocol::INIT:
2581 data = (CVdpauConfig*)msg->data;
2588 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::INIT,
2589 &reply, 1000, &m_config, sizeof(m_config)))
2591 if (reply->signal != CMixerControlProtocol::ACC)
2596 // set initial number of
2597 m_bufferPool.numOutputSurfaces = 4;
2601 m_state = O_TOP_CONFIGURED_IDLE;
2602 msg->Reply(COutputControlProtocol::ACC, &m_config, sizeof(m_config));
2606 m_state = O_TOP_ERROR;
2607 msg->Reply(COutputControlProtocol::ERROR);
2616 case O_TOP_CONFIGURED:
2617 if (port == &m_controlPort)
2621 case COutputControlProtocol::FLUSH:
2623 msg->Reply(COutputControlProtocol::ACC);
2625 case COutputControlProtocol::PRECLEANUP:
2628 msg->Reply(COutputControlProtocol::ACC);
2634 else if (port == &m_dataPort)
2638 case COutputDataProtocol::NEWFRAME:
2639 CVdpauDecodedPicture *frame;
2640 frame = (CVdpauDecodedPicture*)msg->data;
2643 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::FRAME,
2644 frame,sizeof(CVdpauDecodedPicture));
2647 case COutputDataProtocol::RETURNPIC:
2648 CVdpauRenderPicture *pic;
2649 pic = *((CVdpauRenderPicture**)msg->data);
2650 QueueReturnPicture(pic);
2651 m_controlPort.SendInMessage(COutputControlProtocol::STATS);
2652 m_state = O_TOP_CONFIGURED_WORK;
2659 else if (port == &m_mixer.m_dataPort)
2663 case CMixerDataProtocol::PICTURE:
2664 CVdpauProcessedPicture *pic;
2665 pic = (CVdpauProcessedPicture*)msg->data;
2666 m_bufferPool.processedPics.push(*pic);
2667 m_state = O_TOP_CONFIGURED_WORK;
2676 case O_TOP_CONFIGURED_IDLE:
2677 if (port == NULL) // timeout
2681 case COutputControlProtocol::TIMEOUT:
2682 if (ProcessSyncPicture())
2688 m_state = O_TOP_CONFIGURED_WORK;
2698 case O_TOP_CONFIGURED_WORK:
2699 if (port == NULL) // timeout
2703 case COutputControlProtocol::TIMEOUT:
2706 CVdpauRenderPicture *pic;
2707 pic = ProcessMixerPicture();
2710 m_config.stats->DecProcessed();
2711 m_config.stats->IncRender();
2712 m_dataPort.SendInMessage(COutputDataProtocol::PICTURE, &pic, sizeof(pic));
2718 m_state = O_TOP_CONFIGURED_IDLE;
2728 default: // we are in no state, should not happen
2729 CLog::Log(LOGERROR, "COutput::%s - no valid state: %d", __FUNCTION__, m_state);
2735 void COutput::Process()
2737 Message *msg = NULL;
2738 Protocol *port = NULL;
2741 m_state = O_TOP_UNCONFIGURED;
2742 m_extTimeout = 1000;
2743 m_bStateMachineSelfTrigger = false;
2749 if (m_bStateMachineSelfTrigger)
2751 m_bStateMachineSelfTrigger = false;
2752 // self trigger state machine
2753 StateMachine(msg->signal, port, msg);
2754 if (!m_bStateMachineSelfTrigger)
2761 // check control port
2762 else if (m_controlPort.ReceiveOutMessage(&msg))
2765 port = &m_controlPort;
2768 else if (m_dataPort.ReceiveOutMessage(&msg))
2773 // check mixer data port
2774 else if (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2777 port = &m_mixer.m_dataPort;
2781 StateMachine(msg->signal, port, msg);
2782 if (!m_bStateMachineSelfTrigger)
2791 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
2798 msg = m_controlPort.GetMessage();
2799 msg->signal = COutputControlProtocol::TIMEOUT;
2801 // signal timeout to state machine
2802 StateMachine(msg->signal, port, msg);
2803 if (!m_bStateMachineSelfTrigger)
2814 bool COutput::Init()
2816 if (!CreateGlxContext())
2828 bool COutput::Uninit()
2833 ReleaseBufferPool();
2834 DestroyGlxContext();
2838 void COutput::Flush()
2840 if (m_mixer.IsActive())
2843 if (m_mixer.m_controlPort.SendOutMessageSync(CMixerControlProtocol::FLUSH,
2850 CLog::Log(LOGERROR, "Coutput::%s - failed to flush mixer", __FUNCTION__);
2854 while (m_mixer.m_dataPort.ReceiveInMessage(&msg))
2856 if (msg->signal == CMixerDataProtocol::PICTURE)
2858 CVdpauProcessedPicture pic = *(CVdpauProcessedPicture*)msg->data;
2859 if (pic.DVDPic.format == RENDER_FMT_VDPAU_420)
2861 CSingleLock lock(*m_config.videoSurfaceSec);
2863 pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
2869 while (m_dataPort.ReceiveOutMessage(&msg))
2871 if (msg->signal == COutputDataProtocol::NEWFRAME)
2873 CVdpauDecodedPicture pic = *(CVdpauDecodedPicture*)msg->data;
2874 CSingleLock lock(*m_config.videoSurfaceSec);
2876 pic.render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
2878 else if (msg->signal == COutputDataProtocol::RETURNPIC)
2880 CVdpauRenderPicture *pic;
2881 pic = *((CVdpauRenderPicture**)msg->data);
2882 QueueReturnPicture(pic);
2887 while (m_dataPort.ReceiveInMessage(&msg))
2889 if (msg->signal == COutputDataProtocol::PICTURE)
2891 CVdpauRenderPicture *pic;
2892 pic = *((CVdpauRenderPicture**)msg->data);
2893 QueueReturnPicture(pic);
2897 // reset used render flag which was cleared on mixer flush
2898 std::deque<int>::iterator it;
2899 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
2901 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[*it];
2902 if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
2904 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it2;
2905 it2 = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
2906 if (it2 == m_bufferPool.glVideoSurfaceMap.end())
2908 CLog::Log(LOGDEBUG, "COutput::Flush - gl surface not found");
2911 vdpau_render_state *render = it2->second.sourceVuv;
2913 render->state |= FF_VDPAU_STATE_USED_FOR_RENDER;
2918 bool COutput::HasWork()
2920 if (m_config.usePixmaps)
2922 if (!m_bufferPool.processedPics.empty() && FindFreePixmap() >= 0)
2924 if (!m_bufferPool.notVisiblePixmaps.empty() && !m_bufferPool.freeRenderPics.empty())
2930 if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
2936 CVdpauRenderPicture* COutput::ProcessMixerPicture()
2938 CVdpauRenderPicture *retPic = NULL;
2940 if (m_config.usePixmaps)
2942 if (!m_bufferPool.processedPics.empty() && FindFreePixmap() >= 0)
2944 unsigned int i = FindFreePixmap();
2945 VdpauBufferPool::Pixmaps *pixmap = &m_bufferPool.pixmaps[i];
2946 pixmap->used = true;
2947 CVdpauProcessedPicture pic = m_bufferPool.processedPics.front();
2948 m_bufferPool.processedPics.pop();
2949 pixmap->surface = pic.outputSurface;
2950 pixmap->DVDPic = pic.DVDPic;
2952 m_bufferPool.notVisiblePixmaps.push_back(i);
2953 m_config.vdpProcs.vdp_presentation_queue_display(pixmap->vdp_flip_queue,
2954 pixmap->surface,0,0,0);
2956 if (!m_bufferPool.notVisiblePixmaps.empty() && !m_bufferPool.freeRenderPics.empty())
2960 VdpPresentationQueueStatus status;
2961 int idx = m_bufferPool.notVisiblePixmaps.front();
2962 VdpauBufferPool::Pixmaps *pixmap = &m_bufferPool.pixmaps[idx];
2963 vdp_st = m_config.vdpProcs.vdp_presentation_queue_query_surface_status(
2964 pixmap->vdp_flip_queue, pixmap->surface, &status, &time);
2966 if (vdp_st == VDP_STATUS_OK && status == VDP_PRESENTATION_QUEUE_STATUS_VISIBLE)
2968 int idx = m_bufferPool.freeRenderPics.front();
2969 retPic = m_bufferPool.allRenderPics[idx];
2970 m_bufferPool.freeRenderPics.pop_front();
2971 m_bufferPool.usedRenderPics.push_back(idx);
2972 retPic->sourceIdx = pixmap->id;
2973 retPic->DVDPic = pixmap->DVDPic;
2974 retPic->valid = true;
2975 retPic->texture[0] = pixmap->texture;
2976 retPic->crop = CRect(0,0,0,0);
2977 m_bufferPool.notVisiblePixmaps.pop_front();
2978 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &pixmap->surface, sizeof(pixmap->surface));
2982 else if (!m_bufferPool.processedPics.empty() && !m_bufferPool.freeRenderPics.empty())
2984 int idx = m_bufferPool.freeRenderPics.front();
2985 retPic = m_bufferPool.allRenderPics[idx];
2986 m_bufferPool.freeRenderPics.pop_front();
2987 m_bufferPool.usedRenderPics.push_back(idx);
2988 CVdpauProcessedPicture procPic = m_bufferPool.processedPics.front();
2989 m_bufferPool.processedPics.pop();
2991 retPic->DVDPic = procPic.DVDPic;
2992 retPic->valid = true;
2993 if (retPic->DVDPic.format == RENDER_FMT_VDPAU)
2995 m_config.useInteropYuv = false;
2996 m_bufferPool.numOutputSurfaces = NUM_RENDER_PICS;
2999 retPic->sourceIdx = procPic.outputSurface;
3000 retPic->texture[0] = m_bufferPool.glOutputSurfaceMap[procPic.outputSurface].texture[0];
3001 retPic->crop = CRect(0,0,0,0);
3005 m_config.useInteropYuv = true;
3007 retPic->sourceIdx = procPic.render->surface;
3008 for (unsigned int i=0; i<4; ++i)
3009 retPic->texture[i] = m_bufferPool.glVideoSurfaceMap[procPic.render->surface].texture[i];
3010 retPic->texWidth = m_config.surfaceWidth;
3011 retPic->texHeight = m_config.surfaceHeight;
3012 retPic->crop.x1 = 0;
3013 retPic->crop.y1 = 0;
3014 retPic->crop.x2 = m_config.surfaceWidth - m_config.vidWidth;
3015 retPic->crop.y2 = m_config.surfaceHeight - m_config.vidHeight;
3021 void COutput::QueueReturnPicture(CVdpauRenderPicture *pic)
3023 std::deque<int>::iterator it;
3024 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3026 if (m_bufferPool.allRenderPics[*it] == pic)
3032 if (it == m_bufferPool.usedRenderPics.end())
3034 CLog::Log(LOGWARNING, "COutput::QueueReturnPicture - pic not found");
3038 // check if already queued
3039 std::deque<int>::iterator it2 = find(m_bufferPool.syncRenderPics.begin(),
3040 m_bufferPool.syncRenderPics.end(),
3042 if (it2 == m_bufferPool.syncRenderPics.end())
3044 m_bufferPool.syncRenderPics.push_back(*it);
3047 ProcessSyncPicture();
3050 bool COutput::ProcessSyncPicture()
3052 CVdpauRenderPicture *pic;
3055 std::deque<int>::iterator it;
3056 for (it = m_bufferPool.syncRenderPics.begin(); it != m_bufferPool.syncRenderPics.end(); )
3058 pic = m_bufferPool.allRenderPics[*it];
3063 if (glIsSync(pic->fence))
3067 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3068 if(state == GL_SIGNALED)
3070 glDeleteSync(pic->fence);
3083 m_bufferPool.freeRenderPics.push_back(*it);
3085 std::deque<int>::iterator it2 = find(m_bufferPool.usedRenderPics.begin(),
3086 m_bufferPool.usedRenderPics.end(),
3088 if (it2 == m_bufferPool.usedRenderPics.end())
3090 CLog::Log(LOGERROR, "COutput::ProcessSyncPicture - pic not found in queue");
3094 m_bufferPool.usedRenderPics.erase(it2);
3096 it = m_bufferPool.syncRenderPics.erase(it);
3100 ProcessReturnPicture(pic);
3104 CLog::Log(LOGDEBUG, "COutput::%s - return of invalid render pic", __FUNCTION__);
3110 void COutput::ProcessReturnPicture(CVdpauRenderPicture *pic)
3112 if (m_config.usePixmaps)
3114 m_bufferPool.pixmaps[pic->sourceIdx].used = false;
3117 else if (pic->DVDPic.format == RENDER_FMT_VDPAU_420)
3119 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3120 it = m_bufferPool.glVideoSurfaceMap.find(pic->sourceIdx);
3121 if (it == m_bufferPool.glVideoSurfaceMap.end())
3123 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3126 vdpau_render_state *render = it->second.sourceVuv;
3127 CSingleLock lock(*m_config.videoSurfaceSec);
3128 render->state &= ~FF_VDPAU_STATE_USED_FOR_RENDER;
3130 else if (pic->DVDPic.format == RENDER_FMT_VDPAU)
3132 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3133 it = m_bufferPool.glOutputSurfaceMap.find(pic->sourceIdx);
3134 if (it == m_bufferPool.glOutputSurfaceMap.end())
3136 CLog::Log(LOGDEBUG, "COutput::ProcessReturnPicture - gl surface not found");
3139 VdpOutputSurface outSurf = it->second.sourceRgb;
3140 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER, &outSurf, sizeof(outSurf));
3144 int COutput::FindFreePixmap()
3148 for (i = 0; i < m_bufferPool.pixmaps.size(); ++i)
3150 if (!m_bufferPool.pixmaps[i].used)
3153 if (i == m_bufferPool.pixmaps.size())
3159 bool COutput::EnsureBufferPool()
3163 // Creation of outputSurfaces
3164 VdpOutputSurface outputSurface;
3165 for (int i = m_bufferPool.outputSurfaces.size(); i < m_bufferPool.numOutputSurfaces; i++)
3167 vdp_st = m_config.vdpProcs.vdp_output_surface_create(m_config.vdpDevice,
3168 VDP_RGBA_FORMAT_B8G8R8A8,
3172 if (CheckStatus(vdp_st, __LINE__))
3174 m_bufferPool.outputSurfaces.push_back(outputSurface);
3176 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3178 sizeof(VdpOutputSurface));
3179 CLog::Log(LOGNOTICE, "VDPAU::COutput::InitBufferPool - Output Surface created");
3183 if (m_config.usePixmaps && m_bufferPool.pixmaps.empty())
3186 VdpauBufferPool::Pixmaps pixmap;
3187 unsigned int numPixmaps = NUM_RENDER_PICS;
3188 for (unsigned int i = 0; i < numPixmaps; i++)
3190 pixmap.pixmap = None;
3191 pixmap.glPixmap = None;
3192 pixmap.vdp_flip_queue = VDP_INVALID_HANDLE;
3193 pixmap.vdp_flip_target = VDP_INVALID_HANDLE;
3195 glXMakeCurrent(m_Display, None, NULL);
3196 vdp_st = m_config.vdpProcs.vdp_presentation_queue_target_create_x11(m_config.vdpDevice,
3197 pixmap.pixmap, //x_window,
3198 &pixmap.vdp_flip_target);
3200 CheckStatus(vdp_st, __LINE__);
3202 vdp_st = m_config.vdpProcs.vdp_presentation_queue_create(m_config.vdpDevice,
3203 pixmap.vdp_flip_target,
3204 &pixmap.vdp_flip_queue);
3205 CheckStatus(vdp_st, __LINE__);
3206 glXMakeCurrent(m_Display, m_glPixmap, m_glContext);
3209 pixmap.used = false;
3210 m_bufferPool.pixmaps.push_back(pixmap);
3218 void COutput::ReleaseBufferPool()
3222 CSingleLock lock(m_bufferPool.renderPicSec);
3224 if (m_config.usePixmaps)
3226 for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); ++i)
3228 if (m_bufferPool.pixmaps[i].vdp_flip_queue != VDP_INVALID_HANDLE)
3230 vdp_st = m_config.vdpProcs.vdp_presentation_queue_destroy(m_bufferPool.pixmaps[i].vdp_flip_queue);
3231 CheckStatus(vdp_st, __LINE__);
3233 if (m_bufferPool.pixmaps[i].vdp_flip_target != VDP_INVALID_HANDLE)
3235 vdp_st = m_config.vdpProcs.vdp_presentation_queue_target_destroy(m_bufferPool.pixmaps[i].vdp_flip_target);
3236 CheckStatus(vdp_st, __LINE__);
3238 if (m_bufferPool.pixmaps[i].glPixmap)
3240 glXDestroyPixmap(m_Display, m_bufferPool.pixmaps[i].glPixmap);
3242 if (m_bufferPool.pixmaps[i].pixmap)
3244 XFreePixmap(m_Display, m_bufferPool.pixmaps[i].pixmap);
3247 m_bufferPool.pixmaps.clear();
3250 // release all output surfaces
3251 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3253 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3255 vdp_st = m_config.vdpProcs.vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3256 CheckStatus(vdp_st, __LINE__);
3258 m_bufferPool.outputSurfaces.clear();
3260 // wait for all fences
3261 XbmcThreads::EndTime timeout(1000);
3262 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3264 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[i];
3268 while (glIsSync(pic->fence))
3272 glGetSynciv(pic->fence, GL_SYNC_STATUS, 1, &length, &state);
3273 if(state == GL_SIGNALED || timeout.IsTimePast())
3275 glDeleteSync(pic->fence);
3286 if (timeout.IsTimePast())
3288 CLog::Log(LOGERROR, "COutput::%s - timeout waiting for fence", __FUNCTION__);
3290 ProcessSyncPicture();
3292 // invalidate all used render pictures
3293 for (unsigned int i = 0; i < m_bufferPool.usedRenderPics.size(); ++i)
3295 CVdpauRenderPicture *pic = m_bufferPool.allRenderPics[m_bufferPool.usedRenderPics[i]];
3300 void COutput::PreCleanup()
3306 ProcessSyncPicture();
3308 CSingleLock lock(m_bufferPool.renderPicSec);
3309 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3311 if (m_bufferPool.outputSurfaces[i] == VDP_INVALID_HANDLE)
3314 // check if output surface is in use
3316 std::deque<int>::iterator it;
3317 CVdpauRenderPicture *pic;
3318 for (it = m_bufferPool.usedRenderPics.begin(); it != m_bufferPool.usedRenderPics.end(); ++it)
3320 pic = m_bufferPool.allRenderPics[*it];
3321 if ((pic->sourceIdx == m_bufferPool.outputSurfaces[i]) && pic->valid)
3330 #ifdef GL_NV_vdpau_interop
3332 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it_map;
3333 it_map = m_bufferPool.glOutputSurfaceMap.find(m_bufferPool.outputSurfaces[i]);
3334 if (it_map == m_bufferPool.glOutputSurfaceMap.end())
3336 CLog::Log(LOGERROR, "%s - could not find gl surface", __FUNCTION__);
3339 glVDPAUUnregisterSurfaceNV(it_map->second.glVdpauSurface);
3340 glDeleteTextures(1, it_map->second.texture);
3341 m_bufferPool.glOutputSurfaceMap.erase(it_map);
3344 vdp_st = m_config.vdpProcs.vdp_output_surface_destroy(m_bufferPool.outputSurfaces[i]);
3345 CheckStatus(vdp_st, __LINE__);
3347 m_bufferPool.outputSurfaces[i] = VDP_INVALID_HANDLE;
3349 CLog::Log(LOGDEBUG, "VDPAU::PreCleanup - released output surface");
3354 void COutput::InitMixer()
3356 for (unsigned int i = 0; i < m_bufferPool.outputSurfaces.size(); ++i)
3358 m_mixer.m_dataPort.SendOutMessage(CMixerDataProtocol::BUFFER,
3359 &m_bufferPool.outputSurfaces[i],
3360 sizeof(VdpOutputSurface));
3364 bool COutput::MakePixmap(VdpauBufferPool::Pixmaps &pixmap)
3366 CLog::Log(LOGNOTICE,"Creating %ix%i pixmap", m_config.outWidth, m_config.outHeight);
3368 // Get our window attribs.
3369 XWindowAttributes wndattribs;
3370 XGetWindowAttributes(m_Display, g_Windowing.GetWindow(), &wndattribs);
3372 pixmap.pixmap = XCreatePixmap(m_Display,
3373 g_Windowing.GetWindow(),
3379 CLog::Log(LOGERROR, "VDPAU::COUtput::MakePixmap - GLX Error: MakePixmap: Unable to create XPixmap");
3383 // XGCValues values = {};
3385 // values.foreground = BlackPixel (m_Display, DefaultScreen (m_Display));
3386 // xgc = XCreateGC(m_Display, pixmap.pixmap, GCForeground, &values);
3387 // XFillRectangle(m_Display, pixmap.pixmap, xgc, 0, 0, m_config.outWidth, m_config.outHeight);
3388 // XFreeGC(m_Display, xgc);
3390 if(!MakePixmapGL(pixmap))
3396 bool COutput::MakePixmapGL(VdpauBufferPool::Pixmaps &pixmap)
3399 int fbConfigIndex = 0;
3401 int doubleVisAttributes[] = {
3402 GLX_RENDER_TYPE, GLX_RGBA_BIT,
3408 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
3409 GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
3410 GLX_DOUBLEBUFFER, False,
3411 GLX_Y_INVERTED_EXT, True,
3412 GLX_X_RENDERABLE, True,
3416 int pixmapAttribs[] = {
3417 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
3418 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
3422 GLXFBConfig *fbConfigs;
3423 fbConfigs = glXChooseFBConfig(m_Display, g_Windowing.GetCurrentScreen(), doubleVisAttributes, &num);
3424 if (fbConfigs==NULL)
3426 CLog::Log(LOGERROR, "VDPAU::COutput::MakPixmapGL - No compatible framebuffers found");
3431 pixmap.glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], pixmap.pixmap, pixmapAttribs);
3433 if (!pixmap.glPixmap)
3435 CLog::Log(LOGERROR, "VDPAU::COutput::MakPixmapGL - Could not create Pixmap");
3443 bool COutput::GLInit()
3445 glXBindTexImageEXT = NULL;
3446 glXReleaseTexImageEXT = NULL;
3447 #ifdef GL_NV_vdpau_interop
3448 glVDPAUInitNV = NULL;
3449 glVDPAUFiniNV = NULL;
3450 glVDPAURegisterOutputSurfaceNV = NULL;
3451 glVDPAURegisterVideoSurfaceNV = NULL;
3452 glVDPAUIsSurfaceNV = NULL;
3453 glVDPAUUnregisterSurfaceNV = NULL;
3454 glVDPAUSurfaceAccessNV = NULL;
3455 glVDPAUMapSurfacesNV = NULL;
3456 glVDPAUUnmapSurfacesNV = NULL;
3457 glVDPAUGetSurfaceivNV = NULL;
3460 m_config.usePixmaps = false;
3462 #ifdef GL_NV_vdpau_interop
3463 if (glewIsSupported("GL_NV_vdpau_interop"))
3466 glVDPAUInitNV = (PFNGLVDPAUINITNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUInitNV");
3468 glVDPAUFiniNV = (PFNGLVDPAUFININVPROC)glXGetProcAddress((GLubyte *) "glVDPAUFiniNV");
3469 if (!glVDPAURegisterOutputSurfaceNV)
3470 glVDPAURegisterOutputSurfaceNV = (PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterOutputSurfaceNV");
3471 if (!glVDPAURegisterVideoSurfaceNV)
3472 glVDPAURegisterVideoSurfaceNV = (PFNGLVDPAUREGISTERVIDEOSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAURegisterVideoSurfaceNV");
3473 if (!glVDPAUIsSurfaceNV)
3474 glVDPAUIsSurfaceNV = (PFNGLVDPAUISSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUIsSurfaceNV");
3475 if (!glVDPAUUnregisterSurfaceNV)
3476 glVDPAUUnregisterSurfaceNV = (PFNGLVDPAUUNREGISTERSURFACENVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnregisterSurfaceNV");
3477 if (!glVDPAUSurfaceAccessNV)
3478 glVDPAUSurfaceAccessNV = (PFNGLVDPAUSURFACEACCESSNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUSurfaceAccessNV");
3479 if (!glVDPAUMapSurfacesNV)
3480 glVDPAUMapSurfacesNV = (PFNGLVDPAUMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUMapSurfacesNV");
3481 if (!glVDPAUUnmapSurfacesNV)
3482 glVDPAUUnmapSurfacesNV = (PFNGLVDPAUUNMAPSURFACESNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUUnmapSurfacesNV");
3483 if (!glVDPAUGetSurfaceivNV)
3484 glVDPAUGetSurfaceivNV = (PFNGLVDPAUGETSURFACEIVNVPROC)glXGetProcAddress((GLubyte *) "glVDPAUGetSurfaceivNV");
3486 CLog::Log(LOGNOTICE, "VDPAU::COutput GL interop supported");
3491 m_config.usePixmaps = true;
3492 CSettings::Get().SetBool("videoplayer.usevdpaumixer",true);
3494 if (!glXBindTexImageEXT)
3495 glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT");
3496 if (!glXReleaseTexImageEXT)
3497 glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT");
3499 #ifdef GL_NV_vdpau_interop
3500 if (!m_config.usePixmaps)
3502 while (glGetError() != GL_NO_ERROR);
3503 glVDPAUInitNV(reinterpret_cast<void*>(m_config.vdpDevice), reinterpret_cast<void*>(m_config.vdpProcs.vdp_get_proc_address));
3504 if (glGetError() != GL_NO_ERROR)
3506 CLog::Log(LOGERROR, "VDPAU::COutput - GLInitInterop glVDPAUInitNV failed");
3510 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop initialized");
3515 bool hasfence = glewIsSupported("GL_ARB_sync");
3516 for (unsigned int i = 0; i < m_bufferPool.allRenderPics.size(); i++)
3518 m_bufferPool.allRenderPics[i]->usefence = hasfence;
3525 void COutput::GLMapSurfaces()
3527 #ifdef GL_NV_vdpau_interop
3528 if (m_config.usePixmaps)
3531 if (m_config.useInteropYuv)
3533 VdpauBufferPool::GLVideoSurface glSurface;
3534 if (m_config.videoSurfaces->size() != m_bufferPool.glVideoSurfaceMap.size())
3536 CSingleLock lock(*m_config.videoSurfaceSec);
3537 for (unsigned int i = 0; i < m_config.videoSurfaces->size(); i++)
3539 if ((*m_config.videoSurfaces)[i]->surface == VDP_INVALID_HANDLE)
3542 if (m_bufferPool.glVideoSurfaceMap.find((*m_config.videoSurfaces)[i]->surface) == m_bufferPool.glVideoSurfaceMap.end())
3544 glSurface.sourceVuv = (*m_config.videoSurfaces)[i];
3545 while (glGetError() != GL_NO_ERROR) ;
3546 glGenTextures(4, glSurface.texture);
3547 if (glGetError() != GL_NO_ERROR)
3549 CLog::Log(LOGERROR, "VDPAU::COutput error creating texture");
3552 glSurface.glVdpauSurface = glVDPAURegisterVideoSurfaceNV(reinterpret_cast<void*>((*m_config.videoSurfaces)[i]->surface),
3553 GL_TEXTURE_2D, 4, glSurface.texture);
3555 if (glGetError() != GL_NO_ERROR)
3557 CLog::Log(LOGERROR, "VDPAU::COutput error register video surface");
3560 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3561 if (glGetError() != GL_NO_ERROR)
3563 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3566 glVDPAUMapSurfacesNV(1, &glSurface.glVdpauSurface);
3567 if (glGetError() != GL_NO_ERROR)
3569 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3572 m_bufferPool.glVideoSurfaceMap[(*m_config.videoSurfaces)[i]->surface] = glSurface;
3575 CLog::Log(LOGNOTICE, "VDPAU::COutput registered surface");
3582 if (m_bufferPool.glOutputSurfaceMap.size() != m_bufferPool.numOutputSurfaces)
3584 VdpauBufferPool::GLVideoSurface glSurface;
3585 for (unsigned int i = m_bufferPool.glOutputSurfaceMap.size(); i<m_bufferPool.outputSurfaces.size(); i++)
3587 glSurface.sourceRgb = m_bufferPool.outputSurfaces[i];
3588 glGenTextures(1, glSurface.texture);
3589 glSurface.glVdpauSurface = glVDPAURegisterOutputSurfaceNV(reinterpret_cast<void*>(m_bufferPool.outputSurfaces[i]),
3590 GL_TEXTURE_2D, 1, glSurface.texture);
3591 if (glGetError() != GL_NO_ERROR)
3593 CLog::Log(LOGERROR, "VDPAU::COutput error register output surface");
3596 glVDPAUSurfaceAccessNV(glSurface.glVdpauSurface, GL_READ_ONLY);
3597 if (glGetError() != GL_NO_ERROR)
3599 CLog::Log(LOGERROR, "VDPAU::COutput error setting access");
3602 glVDPAUMapSurfacesNV(1, &glSurface.glVdpauSurface);
3603 if (glGetError() != GL_NO_ERROR)
3605 CLog::Log(LOGERROR, "VDPAU::COutput error mapping surface");
3608 m_bufferPool.glOutputSurfaceMap[m_bufferPool.outputSurfaces[i]] = glSurface;
3612 CLog::Log(LOGNOTICE, "VDPAU::COutput registered output surfaces");
3618 void COutput::GLUnmapSurfaces()
3620 #ifdef GL_NV_vdpau_interop
3621 if (m_config.usePixmaps)
3624 { CSingleLock lock(*m_config.videoSurfaceSec);
3625 std::map<VdpVideoSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3626 for (it = m_bufferPool.glVideoSurfaceMap.begin(); it != m_bufferPool.glVideoSurfaceMap.end(); ++it)
3628 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3629 glDeleteTextures(4, it->second.texture);
3631 m_bufferPool.glVideoSurfaceMap.clear();
3634 std::map<VdpOutputSurface, VdpauBufferPool::GLVideoSurface>::iterator it;
3635 for (it = m_bufferPool.glOutputSurfaceMap.begin(); it != m_bufferPool.glOutputSurfaceMap.end(); ++it)
3637 glVDPAUUnregisterSurfaceNV(it->second.glVdpauSurface);
3638 glDeleteTextures(1, it->second.texture);
3640 m_bufferPool.glOutputSurfaceMap.clear();
3644 CLog::Log(LOGNOTICE, "VDPAU::COutput: vdpau gl interop finished");
3649 void COutput::GLBindPixmaps()
3651 if (!m_config.usePixmaps)
3654 for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); i++)
3657 glGenTextures(1, &m_bufferPool.pixmaps[i].texture);
3660 glBindTexture(GL_TEXTURE_2D, m_bufferPool.pixmaps[i].texture);
3663 glXBindTexImageEXT(m_Display, m_bufferPool.pixmaps[i].glPixmap, GLX_FRONT_LEFT_EXT, NULL);
3665 glBindTexture(GL_TEXTURE_2D, 0);
3668 CLog::Log(LOGNOTICE, "VDPAU::COutput: bound pixmaps");
3671 void COutput::GLUnbindPixmaps()
3673 if (!m_config.usePixmaps)
3676 for (unsigned int i = 0; i < m_bufferPool.pixmaps.size(); i++)
3679 if (!glIsTexture(m_bufferPool.pixmaps[i].texture))
3683 glBindTexture(GL_TEXTURE_2D, m_bufferPool.pixmaps[i].texture);
3686 glXReleaseTexImageEXT(m_Display, m_bufferPool.pixmaps[i].glPixmap, GLX_FRONT_LEFT_EXT);
3688 glBindTexture(GL_TEXTURE_2D, 0);
3690 glDeleteTextures(1, &m_bufferPool.pixmaps[i].texture);
3692 CLog::Log(LOGNOTICE, "VDPAU::COutput: unbound pixmaps");
3695 bool COutput::CheckStatus(VdpStatus vdp_st, int line)
3697 if (vdp_st != VDP_STATUS_OK)
3699 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_config.vdpProcs.vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
3706 bool COutput::CreateGlxContext()
3708 GLXContext glContext;
3710 m_Display = g_Windowing.GetDisplay();
3711 glContext = g_Windowing.GetGlxContext();
3712 m_Window = g_Windowing.GetWindow();
3714 // Get our window attribs.
3715 XWindowAttributes wndattribs;
3716 XGetWindowAttributes(m_Display, m_Window, &wndattribs);
3719 XVisualInfo visInfo;
3720 visInfo.visualid = wndattribs.visual->visualid;
3722 XVisualInfo* visuals = XGetVisualInfo(m_Display, VisualIDMask, &visInfo, &nvisuals);
3725 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - could not find visual");
3728 visInfo = visuals[0];
3731 m_pixmap = XCreatePixmap(m_Display,
3738 CLog::Log(LOGERROR, "VDPAU::COutput::CreateGlxContext - Unable to create XPixmap");
3743 m_glPixmap = glXCreateGLXPixmap(m_Display, &visInfo, m_pixmap);
3747 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not create glPixmap");
3751 m_glContext = glXCreateContext(m_Display, &visInfo, glContext, True);
3753 if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext))
3755 CLog::Log(LOGINFO, "VDPAU::COutput::CreateGlxContext - Could not make Pixmap current");
3759 CLog::Log(LOGNOTICE, "VDPAU::COutput::CreateGlxContext - created context");
3763 bool COutput::DestroyGlxContext()
3767 glXMakeCurrent(m_Display, None, NULL);
3768 glXDestroyContext(m_Display, m_glContext);
3773 glXDestroyPixmap(m_Display, m_glPixmap);
3777 XFreePixmap(m_Display, m_pixmap);