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 "DVDCodecs/DVDCodecUtils.h"
38 #define ARSIZE(x) (sizeof(x) / sizeof((x)[0]))
40 CVDPAU::Desc decoder_profiles[] = {
41 {"MPEG1", VDP_DECODER_PROFILE_MPEG1},
42 {"MPEG2_SIMPLE", VDP_DECODER_PROFILE_MPEG2_SIMPLE},
43 {"MPEG2_MAIN", VDP_DECODER_PROFILE_MPEG2_MAIN},
44 {"H264_BASELINE",VDP_DECODER_PROFILE_H264_BASELINE},
45 {"H264_MAIN", VDP_DECODER_PROFILE_H264_MAIN},
46 {"H264_HIGH", VDP_DECODER_PROFILE_H264_HIGH},
47 {"VC1_SIMPLE", VDP_DECODER_PROFILE_VC1_SIMPLE},
48 {"VC1_MAIN", VDP_DECODER_PROFILE_VC1_MAIN},
49 {"VC1_ADVANCED", VDP_DECODER_PROFILE_VC1_ADVANCED},
50 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
51 {"MPEG4_PART2_ASP", VDP_DECODER_PROFILE_MPEG4_PART2_ASP},
54 const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CVDPAU::Desc);
56 static float studioCSC[3][4] =
58 { 1.0f, 0.0f, 1.57480000f,-0.78740000f},
59 { 1.0f,-0.18737736f,-0.46813736f, 0.32775736f},
60 { 1.0f, 1.85556000f, 0.0f,-0.92780000f}
63 static struct SInterlaceMapping
65 const EINTERLACEMETHOD method;
66 const VdpVideoMixerFeature feature;
67 } g_interlace_mapping[] =
68 { {VS_INTERLACEMETHOD_VDPAU_TEMPORAL , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
69 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL}
70 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL , VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
71 , {VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF, VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}
72 , {VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE , VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE}
73 , {VS_INTERLACEMETHOD_NONE , (VdpVideoMixerFeature)-1}
76 //since libvdpau 0.4, vdp_device_create_x11() installs a callback on the Display*,
77 //if we unload libvdpau with dlclose(), we segfault on XCloseDisplay,
78 //so we just keep a static handle to libvdpau around
79 void* CVDPAU::dl_handle;
83 glXBindTexImageEXT = NULL;
84 glXReleaseTexImageEXT = NULL;
85 vdp_device = VDP_INVALID_HANDLE;
86 surfaceNum = presentSurfaceNum = 0;
87 picAge.b_age = picAge.ip_age[0] = picAge.ip_age[1] = 256*256*256*64;
88 vdpauConfigured = false;
89 m_DisplayState = VDPAU_OPEN;
90 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
95 if (!glXBindTexImageEXT)
96 glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT");
97 if (!glXReleaseTexImageEXT)
98 glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT");
100 totalAvailableOutputSurfaces = 0;
101 outputSurface = presentSurface = VDP_INVALID_HANDLE;
102 vdp_flip_target = VDP_INVALID_HANDLE;
103 vdp_flip_queue = VDP_INVALID_HANDLE;
104 vid_width = vid_height = OutWidth = OutHeight = 0;
105 surface_width = surface_height = 0;
107 memset(&decoder, 0, sizeof(decoder));
108 memset(&outRect, 0, sizeof(outRect));
109 memset(&outRectVid, 0, sizeof(outRectVid));
120 for (int i = 0; i < NUM_OUTPUT_SURFACES; i++)
121 outputSurfaces[i] = VDP_INVALID_HANDLE;
123 videoMixer = VDP_INVALID_HANDLE;
126 memset(m_features, 0, sizeof(m_features));
128 m_vdpauOutputMethod = OUTPUT_NONE;
130 upScale = g_advancedSettings.m_videoVDPAUScaling;
132 vdp_video_mixer_set_attribute_values = NULL;
133 vdp_generate_csc_matrix = NULL;
134 vdp_presentation_queue_target_destroy = NULL;
135 vdp_presentation_queue_create = NULL;
136 vdp_presentation_queue_destroy = NULL;
137 vdp_presentation_queue_display = NULL;
138 vdp_presentation_queue_block_until_surface_idle = NULL;
139 vdp_presentation_queue_target_create_x11 = NULL;
140 vdp_presentation_queue_query_surface_status = NULL;
141 vdp_presentation_queue_get_time = NULL;
142 vdp_get_error_string = NULL;
143 vdp_decoder_create = NULL;
144 vdp_decoder_destroy = NULL;
145 vdp_decoder_render = NULL;
146 vdp_decoder_query_caps = NULL;
147 vdp_preemption_callback_register = NULL;
148 dl_vdp_device_create_x11 = NULL;
149 dl_vdp_get_proc_address = NULL;
150 dl_vdp_preemption_callback_register = NULL;
155 tmpNoiseReduction = 0.0f;
157 vdp_get_proc_address = NULL;
158 vdp_device_destroy = NULL;
159 vdp_video_surface_create = NULL;
160 vdp_video_surface_destroy = NULL;
161 vdp_video_surface_put_bits_y_cb_cr = NULL;
162 vdp_video_surface_get_bits_y_cb_cr = NULL;
163 vdp_output_surface_put_bits_y_cb_cr = NULL;
164 vdp_output_surface_put_bits_native = NULL;
165 vdp_output_surface_create = NULL;
166 vdp_output_surface_destroy = NULL;
167 vdp_output_surface_get_bits_native = NULL;
168 vdp_output_surface_render_output_surface = NULL;
169 vdp_output_surface_put_bits_indexed = NULL;
170 vdp_video_mixer_create = NULL;
171 vdp_video_mixer_set_feature_enables = NULL;
172 vdp_video_mixer_query_parameter_support = NULL;
173 vdp_video_mixer_query_feature_support = NULL;
174 vdp_video_mixer_destroy = NULL;
175 vdp_video_mixer_render = NULL;
176 m_hwContext.bitstream_buffers_allocated = 0;
179 bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces)
181 if(avctx->coded_width == 0
182 || avctx->coded_height == 0)
184 CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init");
188 if ((avctx->codec_id == AV_CODEC_ID_MPEG4) && !g_advancedSettings.m_videoAllowMpeg4VDPAU)
193 dl_handle = dlopen("libvdpau.so.1", RTLD_LAZY);
196 const char* error = dlerror();
198 error = "dlerror() returned NULL";
200 CLog::Log(LOGNOTICE,"(VDPAU) Unable to get handle to libvdpau: %s", error);
201 //g_application.m_guiDialogKaiToast.QueueNotification(CGUIDialogKaiToast::Error, "VDPAU", error, 10000);
207 if (!m_dllAvUtil.Load())
212 if (vdp_device != VDP_INVALID_HANDLE)
214 SpewHardwareAvailable();
216 VdpDecoderProfile profile = 0;
217 if(avctx->codec_id == AV_CODEC_ID_H264)
218 profile = VDP_DECODER_PROFILE_H264_HIGH;
219 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
220 else if(avctx->codec_id == AV_CODEC_ID_MPEG4)
221 profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
225 if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width))
226 CLog::Log(LOGWARNING,"(VDPAU) width %i might not be supported because of hardware bug", avctx->width);
228 /* attempt to create a decoder with this width/height, some sizes are not supported by hw */
230 vdp_st = vdp_decoder_create(vdp_device, profile, avctx->coded_width, avctx->coded_height, 5, &decoder);
232 if(vdp_st != VDP_STATUS_OK)
234 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", vdp_get_error_string(vdp_st), vdp_st);
239 vdp_decoder_destroy(decoder);
240 CheckStatus(vdp_st, __LINE__);
243 InitCSCMatrix(avctx->coded_height);
245 /* finally setup ffmpeg */
246 memset(&m_hwContext, 0, sizeof(AVVDPAUContext));
247 m_hwContext.render = CVDPAU::Render;
248 m_hwContext.bitstream_buffers_allocated = 0;
249 avctx->get_buffer = CVDPAU::FFGetBuffer;
250 avctx->release_buffer = CVDPAU::FFReleaseBuffer;
251 avctx->draw_horiz_band = CVDPAU::FFDrawSlice;
252 avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
253 avctx->hwaccel_context = &m_hwContext;
254 avctx->thread_count = 1;
256 g_Windowing.Register(this);
269 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
274 while (!m_videoSurfaces.empty())
276 vdpau_render_state *render = m_videoSurfaces.back();
277 m_videoSurfaces.pop_back();
278 if (render->bitstream_buffers_allocated)
279 m_dllAvUtil.av_freep(&render->bitstream_buffers);
280 render->bitstream_buffers_allocated = 0;
284 if (m_hwContext.bitstream_buffers_allocated)
286 m_dllAvUtil.av_freep(&m_hwContext.bitstream_buffers);
289 g_Windowing.Unregister(this);
290 m_dllAvUtil.Unload();
293 bool CVDPAU::MakePixmapGL()
296 int fbConfigIndex = 0;
298 int doubleVisAttributes[] = {
299 GLX_RENDER_TYPE, GLX_RGBA_BIT,
305 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
306 GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
307 GLX_DOUBLEBUFFER, True,
308 GLX_Y_INVERTED_EXT, True,
309 GLX_X_RENDERABLE, True,
313 int pixmapAttribs[] = {
314 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
315 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
319 GLXFBConfig *fbConfigs;
320 fbConfigs = glXChooseFBConfig(m_Display, DefaultScreen(m_Display), doubleVisAttributes, &num);
323 CLog::Log(LOGERROR, "GLX Error: MakePixmap: No compatible framebuffers found");
326 CLog::Log(LOGDEBUG, "Found %d fbconfigs.", num);
328 CLog::Log(LOGDEBUG, "Using fbconfig index %d.", fbConfigIndex);
330 m_glPixmap = glXCreatePixmap(m_Display, fbConfigs[fbConfigIndex], m_Pixmap, pixmapAttribs);
334 CLog::Log(LOGINFO, "GLX Error: Could not create Pixmap");
343 bool CVDPAU::MakePixmap(int width, int height)
345 //pick the smallest dimensions, so we downscale with vdpau and upscale with opengl when appropriate
346 //this requires the least amount of gpu memory bandwidth
347 if (g_graphicsContext.GetWidth() < width || g_graphicsContext.GetHeight() < height || upScale)
349 //scale width to desktop size if the aspect ratio is the same or bigger than the desktop
350 if ((double)height * g_graphicsContext.GetWidth() / width <= (double)g_graphicsContext.GetHeight())
352 OutWidth = g_graphicsContext.GetWidth();
353 OutHeight = MathUtils::round_int((double)height * g_graphicsContext.GetWidth() / width);
355 else //scale height to the desktop size if the aspect ratio is smaller than the desktop
357 OutHeight = g_graphicsContext.GetHeight();
358 OutWidth = MathUtils::round_int((double)width * g_graphicsContext.GetHeight() / height);
367 CLog::Log(LOGNOTICE,"Creating %ix%i pixmap", OutWidth, OutHeight);
369 // Get our window attribs.
370 XWindowAttributes wndattribs;
371 XGetWindowAttributes(m_Display, DefaultRootWindow(m_Display), &wndattribs); // returns a status but I don't know what success is
373 m_Pixmap = XCreatePixmap(m_Display,
374 DefaultRootWindow(m_Display),
380 CLog::Log(LOGERROR, "GLX Error: MakePixmap: Unable to create XPixmap");
384 XGCValues values = {};
386 values.foreground = BlackPixel (m_Display, DefaultScreen (m_Display));
387 xgc = XCreateGC(m_Display, m_Pixmap, GCForeground, &values);
388 XFillRectangle(m_Display, m_Pixmap, xgc, 0, 0, OutWidth, OutHeight);
389 XFreeGC(m_Display, xgc);
397 void CVDPAU::BindPixmap()
399 CSharedLock lock(m_DecoderSection);
401 { CSharedLock dLock(m_DisplaySection);
402 if (m_DisplayState != VDPAU_OPEN)
408 if(presentSurface != VDP_INVALID_HANDLE)
410 VdpPresentationQueueStatus status;
413 vdp_st = vdp_presentation_queue_query_surface_status(
414 vdp_flip_queue, presentSurface, &status, &time);
415 CheckStatus(vdp_st, __LINE__);
416 while(status != VDP_PRESENTATION_QUEUE_STATUS_VISIBLE && vdp_st == VDP_STATUS_OK)
419 vdp_st = vdp_presentation_queue_query_surface_status(
420 vdp_flip_queue, presentSurface, &status, &time);
421 CheckStatus(vdp_st, __LINE__);
425 glXBindTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT, NULL);
427 else CLog::Log(LOGERROR,"(VDPAU) BindPixmap called without valid pixmap");
430 void CVDPAU::ReleasePixmap()
432 CSharedLock lock(m_DecoderSection);
434 { CSharedLock dLock(m_DisplaySection);
435 if (m_DisplayState != VDPAU_OPEN)
441 glXReleaseTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT);
443 else CLog::Log(LOGERROR,"(VDPAU) ReleasePixmap called without valid pixmap");
446 void CVDPAU::OnLostDevice()
448 CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event");
450 CExclusiveLock lock(m_DecoderSection);
454 m_DisplayState = VDPAU_LOST;
455 m_DisplayEvent.Reset();
458 void CVDPAU::OnResetDevice()
460 CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event");
462 CExclusiveLock lock(m_DisplaySection);
463 if (m_DisplayState == VDPAU_LOST)
465 m_DisplayState = VDPAU_RESET;
466 m_DisplayEvent.Set();
470 int CVDPAU::Check(AVCodecContext* avctx)
474 { CSharedLock lock(m_DisplaySection);
475 state = m_DisplayState;
478 if (state == VDPAU_LOST)
480 CLog::Log(LOGNOTICE,"CVDPAU::Check waiting for display reset event");
481 if (!m_DisplayEvent.WaitMSec(2000))
483 CLog::Log(LOGERROR, "CVDPAU::Check - device didn't reset in reasonable time");
488 CSharedLock lock(m_DisplaySection);
489 state = m_DisplayState;
492 if (state == VDPAU_RESET || state == VDPAU_ERROR)
494 CLog::Log(LOGNOTICE,"Attempting recovery");
496 CSingleLock gLock(g_graphicsContext);
497 CExclusiveLock lock(m_DecoderSection);
504 if (state == VDPAU_RESET)
512 bool CVDPAU::IsVDPAUFormat(PixelFormat format)
514 if (format == AV_PIX_FMT_VDPAU)
520 void CVDPAU::CheckFeatures()
522 if (videoMixer == VDP_INVALID_HANDLE)
524 CLog::Log(LOGNOTICE, " (VDPAU) Creating the video mixer");
525 // Creation of VideoMixer.
526 VdpVideoMixerParameter parameters[] = {
527 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
528 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
529 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
532 void const * parameter_values[] = {
540 tmpNoiseReduction = 0;
543 VdpStatus vdp_st = vdp_video_mixer_create(vdp_device,
550 CheckStatus(vdp_st, __LINE__);
555 if (tmpBrightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness ||
556 tmpContrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)
559 tmpBrightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness;
560 tmpContrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast;
562 if (tmpNoiseReduction != CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
564 tmpNoiseReduction = CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction;
567 if (tmpSharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
569 tmpSharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
572 if ( tmpDeintMode != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode ||
573 tmpDeintGUI != CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod ||
574 (tmpDeintGUI == VS_INTERLACEMETHOD_AUTO && tmpDeint != AutoInterlaceMethod()))
576 tmpDeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
577 tmpDeintGUI = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
578 if (tmpDeintGUI == VS_INTERLACEMETHOD_AUTO)
579 tmpDeint = AutoInterlaceMethod();
581 tmpDeint = tmpDeintGUI;
587 bool CVDPAU::Supports(VdpVideoMixerFeature feature)
589 for(int i = 0; i < m_feature_count; i++)
591 if(m_features[i] == feature)
597 bool CVDPAU::Supports(EINTERLACEMETHOD method)
599 if(method == VS_INTERLACEMETHOD_VDPAU_BOB
600 || method == VS_INTERLACEMETHOD_AUTO
601 || method == VS_INTERLACEMETHOD_AUTO_ION)
604 for(SInterlaceMapping* p = g_interlace_mapping; p->method != VS_INTERLACEMETHOD_NONE; p++)
606 if(p->method == method)
607 return Supports(p->feature);
612 EINTERLACEMETHOD CVDPAU::AutoInterlaceMethod()
614 return VS_INTERLACEMETHOD_VDPAU_TEMPORAL;
617 void CVDPAU::SetColor()
621 if (tmpBrightness != CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)
622 m_Procamp.brightness = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness)-50) / 100;
623 if (tmpContrast != CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)
624 m_Procamp.contrast = (float)((CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)+50) / 100;
626 if(vid_height >= 600 || vid_width > 1024)
627 vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_709, &m_CSCMatrix);
629 vdp_st = vdp_generate_csc_matrix(&m_Procamp, VDP_COLOR_STANDARD_ITUR_BT_601, &m_CSCMatrix);
631 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
632 if (CSettings::Get().GetBool("videoscreen.limitedrange"))
634 void const * pm_CSCMatix[] = { &studioCSC };
635 vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
639 void const * pm_CSCMatix[] = { &m_CSCMatrix };
640 vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, pm_CSCMatix);
642 CheckStatus(vdp_st, __LINE__);
645 void CVDPAU::SetNoiseReduction()
647 if(!Supports(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION))
650 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION };
651 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL };
654 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction)
656 VdpBool enabled[]= {0};
657 vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
658 CheckStatus(vdp_st, __LINE__);
661 VdpBool enabled[]={1};
662 vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
663 CheckStatus(vdp_st, __LINE__);
664 void* nr[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction };
665 CLog::Log(LOGNOTICE,"Setting Noise Reduction to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction);
666 vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, nr);
667 CheckStatus(vdp_st, __LINE__);
670 void CVDPAU::SetSharpness()
672 if(!Supports(VDP_VIDEO_MIXER_FEATURE_SHARPNESS))
675 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS };
676 VdpVideoMixerAttribute attributes[] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL };
679 if (!CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
681 VdpBool enabled[]={0};
682 vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
683 CheckStatus(vdp_st, __LINE__);
686 VdpBool enabled[]={1};
687 vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
688 CheckStatus(vdp_st, __LINE__);
689 void* sh[] = { &CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness };
690 CLog::Log(LOGNOTICE,"Setting Sharpness to %f",CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness);
691 vdp_st = vdp_video_mixer_set_attribute_values(videoMixer, ARSIZE(attributes), attributes, sh);
692 CheckStatus(vdp_st, __LINE__);
695 void CVDPAU::SetHWUpscaling()
697 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
698 if(!Supports(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1) || !upScale)
701 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 };
703 VdpBool enabled[]={1};
704 vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
705 CheckStatus(vdp_st, __LINE__);
709 void CVDPAU::SetDeinterlacing()
712 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
713 EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
714 if (method == VS_INTERLACEMETHOD_AUTO)
715 method = AutoInterlaceMethod();
717 VdpVideoMixerFeature feature[] = { VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL,
718 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL,
719 VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE };
720 if (mode == VS_DEINTERLACEMODE_OFF)
722 VdpBool enabled[]={0,0,0};
723 vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
727 if (method == VS_INTERLACEMETHOD_AUTO_ION)
729 if (vid_height <= 576)
731 VdpBool enabled[]={1,1,0};
732 vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
734 else if (vid_height > 576)
736 VdpBool enabled[]={1,0,0};
737 vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
740 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
741 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF)
743 VdpBool enabled[]={1,0,0};
744 vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
746 else if (method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
747 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF)
749 VdpBool enabled[]={1,1,0};
750 vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
752 else if (method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE)
754 VdpBool enabled[]={1,0,1};
755 vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
759 VdpBool enabled[]={0,0,0};
760 vdp_st = vdp_video_mixer_set_feature_enables(videoMixer, ARSIZE(feature), feature, enabled);
764 CheckStatus(vdp_st, __LINE__);
767 void CVDPAU::InitVDPAUProcs()
772 dl_vdp_device_create_x11 = (VdpStatus (*)(Display*, int, VdpDevice*, VdpStatus (**)(VdpDevice, VdpFuncId, void**)))dlsym(dl_handle, (const char*)"vdp_device_create_x11");
776 CLog::Log(LOGERROR,"(VDPAU) - %s in %s",error,__FUNCTION__);
777 vdp_device = VDP_INVALID_HANDLE;
779 //g_application.m_guiDialogKaiToast.QueueNotification(CGUIDialogKaiToast::Error, "VDPAU", error, 10000);
784 if (dl_vdp_device_create_x11)
786 CSingleLock lock(g_graphicsContext);
787 m_Display = g_Windowing.GetDisplay();
791 CLog::Log(LOGERROR,"(VDPAU) - Unable to get dl_vdp_device_create_x11 in %s", __FUNCTION__);
792 vdp_device = VDP_INVALID_HANDLE;
796 int mScreen = DefaultScreen(m_Display);
800 // tested on 64bit Ubuntu 11.10 and it deadlocked without this
801 XLockDisplay(m_Display);
802 vdp_st = dl_vdp_device_create_x11(m_Display, //x_display,
805 &vdp_get_proc_address);
806 XUnlockDisplay(m_Display);
808 CLog::Log(LOGNOTICE,"vdp_device = 0x%08x vdp_st = 0x%08x",vdp_device,vdp_st);
809 if (vdp_st != VDP_STATUS_OK)
811 CLog::Log(LOGERROR,"(VDPAU) unable to init VDPAU - vdp_st = 0x%x. Falling back.",vdp_st);
812 vdp_device = VDP_INVALID_HANDLE;
816 #define VDP_PROC(id, proc) \
818 vdp_st = vdp_get_proc_address(vdp_device, id, (void**)&proc); \
819 CheckStatus(vdp_st, __LINE__); \
822 VDP_PROC(VDP_FUNC_ID_GET_ERROR_STRING , vdp_get_error_string);
823 VDP_PROC(VDP_FUNC_ID_DEVICE_DESTROY , vdp_device_destroy);
824 VDP_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX , vdp_generate_csc_matrix);
825 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE , vdp_video_surface_create);
826 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , vdp_video_surface_destroy);
827 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , vdp_video_surface_put_bits_y_cb_cr);
828 VDP_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , vdp_video_surface_get_bits_y_cb_cr);
829 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , vdp_output_surface_put_bits_y_cb_cr);
830 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , vdp_output_surface_put_bits_native);
831 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , vdp_output_surface_create);
832 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , vdp_output_surface_destroy);
833 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , vdp_output_surface_get_bits_native);
834 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, vdp_output_surface_render_output_surface);
835 VDP_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , vdp_output_surface_put_bits_indexed);
836 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE , vdp_video_mixer_create);
837 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , vdp_video_mixer_set_feature_enables);
838 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY , vdp_video_mixer_destroy);
839 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER , vdp_video_mixer_render);
840 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , vdp_video_mixer_set_attribute_values);
841 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , vdp_video_mixer_query_parameter_support);
842 VDP_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , vdp_video_mixer_query_feature_support);
843 VDP_PROC(VDP_FUNC_ID_DECODER_CREATE , vdp_decoder_create);
844 VDP_PROC(VDP_FUNC_ID_DECODER_DESTROY , vdp_decoder_destroy);
845 VDP_PROC(VDP_FUNC_ID_DECODER_RENDER , vdp_decoder_render);
846 VDP_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , vdp_decoder_query_caps);
847 VDP_PROC(VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER , vdp_preemption_callback_register);
848 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY , vdp_presentation_queue_target_destroy);
849 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE , vdp_presentation_queue_create);
850 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY , vdp_presentation_queue_destroy);
851 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY , vdp_presentation_queue_display);
852 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE, vdp_presentation_queue_block_until_surface_idle);
853 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 , vdp_presentation_queue_target_create_x11);
854 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS , vdp_presentation_queue_query_surface_status);
855 VDP_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME , vdp_presentation_queue_get_time);
859 // set all vdpau resources to invalid
860 vdp_flip_target = VDP_INVALID_HANDLE;
861 vdp_flip_queue = VDP_INVALID_HANDLE;
862 videoMixer = VDP_INVALID_HANDLE;
863 totalAvailableOutputSurfaces = 0;
864 presentSurface = VDP_INVALID_HANDLE;
865 outputSurface = VDP_INVALID_HANDLE;
866 for (int i = 0; i < NUM_OUTPUT_SURFACES; i++)
867 outputSurfaces[i] = VDP_INVALID_HANDLE;
869 m_vdpauOutputMethod = OUTPUT_NONE;
871 CExclusiveLock lock(m_DisplaySection);
872 m_DisplayState = VDPAU_OPEN;
873 vdpauConfigured = false;
876 void CVDPAU::FiniVDPAUProcs()
878 if (vdp_device == VDP_INVALID_HANDLE) return;
881 vdp_st = vdp_device_destroy(vdp_device);
882 CheckStatus(vdp_st, __LINE__);
883 vdp_device = VDP_INVALID_HANDLE;
884 vdpauConfigured = false;
887 void CVDPAU::InitCSCMatrix(int Height)
890 m_Procamp.struct_version = VDP_PROCAMP_VERSION;
891 m_Procamp.brightness = 0.0;
892 m_Procamp.contrast = 1.0;
893 m_Procamp.saturation = 1.0;
895 vdp_st = vdp_generate_csc_matrix(&m_Procamp,
896 (Height < 720)? VDP_COLOR_STANDARD_ITUR_BT_601 : VDP_COLOR_STANDARD_ITUR_BT_709,
898 CheckStatus(vdp_st, __LINE__);
901 void CVDPAU::FiniVDPAUOutput()
905 if (vdp_device == VDP_INVALID_HANDLE || !vdpauConfigured) return;
907 CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
911 vdp_st = vdp_decoder_destroy(decoder);
912 if (CheckStatus(vdp_st, __LINE__))
914 decoder = VDP_INVALID_HANDLE;
916 for (unsigned int i = 0; i < m_videoSurfaces.size(); ++i)
918 vdpau_render_state *render = m_videoSurfaces[i];
919 if (render->surface != VDP_INVALID_HANDLE)
921 vdp_st = vdp_video_surface_destroy(render->surface);
922 render->surface = VDP_INVALID_HANDLE;
924 if (CheckStatus(vdp_st, __LINE__))
930 void CVDPAU::ReadFormatOf( AVCodecID codec
931 , VdpDecoderProfile &vdp_decoder_profile
932 , VdpChromaType &vdp_chroma_type)
936 case AV_CODEC_ID_MPEG1VIDEO:
937 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
938 vdp_chroma_type = VDP_CHROMA_TYPE_420;
940 case AV_CODEC_ID_MPEG2VIDEO:
941 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
942 vdp_chroma_type = VDP_CHROMA_TYPE_420;
944 case AV_CODEC_ID_H264:
945 vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
946 vdp_chroma_type = VDP_CHROMA_TYPE_420;
948 case AV_CODEC_ID_WMV3:
949 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
950 vdp_chroma_type = VDP_CHROMA_TYPE_420;
952 case AV_CODEC_ID_VC1:
953 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
954 vdp_chroma_type = VDP_CHROMA_TYPE_420;
956 #if (defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP)
957 case AV_CODEC_ID_MPEG4:
958 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
959 vdp_chroma_type = VDP_CHROMA_TYPE_420;
963 vdp_decoder_profile = 0;
970 bool CVDPAU::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
975 VdpDecoderProfile vdp_decoder_profile;
976 vid_width = avctx->width;
977 vid_height = avctx->height;
978 surface_width = avctx->coded_width;
979 surface_height = avctx->coded_height;
981 past[1] = past[0] = current = future = NULL;
982 CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",OutWidth,vid_width,surface_width);
983 CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",OutHeight,vid_height,surface_height);
984 ReadFormatOf(avctx->codec_id, vdp_decoder_profile, vdp_chroma_type);
986 if(avctx->codec_id == AV_CODEC_ID_H264)
988 max_references = ref_frames;
989 if (max_references > 16) max_references = 16;
990 if (max_references < 5) max_references = 5;
995 vdp_st = vdp_decoder_create(vdp_device,
1001 if (CheckStatus(vdp_st, __LINE__))
1004 m_vdpauOutputMethod = OUTPUT_NONE;
1006 vdpauConfigured = true;
1010 bool CVDPAU::ConfigOutputMethod(AVCodecContext *avctx, AVFrame *pFrame)
1014 if (m_vdpauOutputMethod == OUTPUT_PIXMAP)
1019 MakePixmap(avctx->width,avctx->height);
1021 vdp_st = vdp_presentation_queue_target_create_x11(vdp_device,
1022 m_Pixmap, //x_window,
1024 if (CheckStatus(vdp_st, __LINE__))
1027 vdp_st = vdp_presentation_queue_create(vdp_device,
1030 if (CheckStatus(vdp_st, __LINE__))
1033 totalAvailableOutputSurfaces = 0;
1035 int tmpMaxOutputSurfaces = NUM_OUTPUT_SURFACES;
1036 if (vid_width == FULLHD_WIDTH)
1037 tmpMaxOutputSurfaces = NUM_OUTPUT_SURFACES_FOR_FULLHD;
1039 // Creation of outputSurfaces
1040 for (int i = 0; i < NUM_OUTPUT_SURFACES && i < tmpMaxOutputSurfaces; i++)
1042 vdp_st = vdp_output_surface_create(vdp_device,
1043 VDP_RGBA_FORMAT_B8G8R8A8,
1046 &outputSurfaces[i]);
1047 if (CheckStatus(vdp_st, __LINE__))
1049 totalAvailableOutputSurfaces++;
1051 CLog::Log(LOGNOTICE, " (VDPAU) Total Output Surfaces Available: %i of a max (tmp: %i const: %i)",
1052 totalAvailableOutputSurfaces,
1053 tmpMaxOutputSurfaces,
1054 NUM_OUTPUT_SURFACES);
1056 // create 3 pitches of black lines needed for clipping top
1057 // and bottom lines when de-interlacing
1058 m_BlackBar = new uint32_t[3*OutWidth];
1059 memset(m_BlackBar, 0, 3*OutWidth*sizeof(uint32_t));
1061 surfaceNum = presentSurfaceNum = 0;
1062 outputSurface = presentSurface = VDP_INVALID_HANDLE;
1063 videoMixer = VDP_INVALID_HANDLE;
1065 m_vdpauOutputMethod = OUTPUT_PIXMAP;
1070 bool CVDPAU::FiniOutputMethod()
1074 if (vdp_flip_queue != VDP_INVALID_HANDLE)
1076 vdp_st = vdp_presentation_queue_destroy(vdp_flip_queue);
1077 vdp_flip_queue = VDP_INVALID_HANDLE;
1078 CheckStatus(vdp_st, __LINE__);
1081 if (vdp_flip_target != VDP_INVALID_HANDLE)
1083 vdp_st = vdp_presentation_queue_target_destroy(vdp_flip_target);
1084 vdp_flip_target = VDP_INVALID_HANDLE;
1085 CheckStatus(vdp_st, __LINE__);
1090 CLog::Log(LOGDEBUG, "GLX: Destroying glPixmap");
1091 glXDestroyPixmap(m_Display, m_glPixmap);
1097 CLog::Log(LOGDEBUG, "GLX: Destroying XPixmap");
1098 XFreePixmap(m_Display, m_Pixmap);
1102 outputSurface = presentSurface = VDP_INVALID_HANDLE;
1104 for (int i = 0; i < totalAvailableOutputSurfaces; i++)
1106 if (outputSurfaces[i] == VDP_INVALID_HANDLE)
1108 vdp_st = vdp_output_surface_destroy(outputSurfaces[i]);
1109 outputSurfaces[i] = VDP_INVALID_HANDLE;
1110 CheckStatus(vdp_st, __LINE__);
1113 if (videoMixer != VDP_INVALID_HANDLE)
1115 vdp_st = vdp_video_mixer_destroy(videoMixer);
1116 videoMixer = VDP_INVALID_HANDLE;
1117 CheckStatus(vdp_st, __LINE__);
1122 delete [] m_BlackBar;
1126 while (!m_DVDVideoPics.empty())
1127 m_DVDVideoPics.pop();
1132 void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der Laan -- VDPInfo
1135 CLog::Log(LOGNOTICE,"VDPAU Decoder capabilities:");
1136 CLog::Log(LOGNOTICE,"name level macbs width height");
1137 CLog::Log(LOGNOTICE,"------------------------------------");
1138 for(unsigned int x=0; x<decoder_profile_count; ++x)
1140 VdpBool is_supported = false;
1141 uint32_t max_level, max_macroblocks, max_width, max_height;
1142 rv = vdp_decoder_query_caps(vdp_device, decoder_profiles[x].id,
1143 &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
1144 if(rv == VDP_STATUS_OK && is_supported)
1146 CLog::Log(LOGNOTICE,"%-16s %2i %5i %5i %5i\n", decoder_profiles[x].name,
1147 max_level, max_macroblocks, max_width, max_height);
1150 CLog::Log(LOGNOTICE,"------------------------------------");
1151 m_feature_count = 0;
1152 #define CHECK_SUPPORT(feature) \
1154 VdpBool supported; \
1155 if(vdp_video_mixer_query_feature_support(vdp_device, feature, &supported) == VDP_STATUS_OK && supported) { \
1156 CLog::Log(LOGNOTICE, "Mixer feature: "#feature); \
1157 m_features[m_feature_count++] = feature; \
1161 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION);
1162 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_SHARPNESS);
1163 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL);
1164 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL);
1165 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE);
1166 #ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
1167 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1);
1168 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2);
1169 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3);
1170 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4);
1171 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5);
1172 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6);
1173 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7);
1174 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8);
1175 CHECK_SUPPORT(VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9);
1177 #undef CHECK_SUPPORT
1181 bool CVDPAU::IsSurfaceValid(vdpau_render_state *render)
1183 // find render state in queue
1186 for(i = 0; i < m_videoSurfaces.size(); ++i)
1188 if(m_videoSurfaces[i] == render)
1196 CLog::Log(LOGERROR,"%s - video surface not found", __FUNCTION__);
1199 if (m_videoSurfaces[i]->surface == VDP_INVALID_HANDLE)
1201 m_videoSurfaces[i]->state = 0;
1208 int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
1210 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
1211 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
1212 CVDPAU* vdp = (CVDPAU*)ctx->GetHardware();
1213 struct pictureAge* pA = &vdp->picAge;
1215 // while we are waiting to recover we can't do anything
1216 CSharedLock lock(vdp->m_DecoderSection);
1218 { CSharedLock dLock(vdp->m_DisplaySection);
1219 if(vdp->m_DisplayState != VDPAU_OPEN)
1221 CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
1226 vdpau_render_state * render = NULL;
1228 // find unused surface
1229 for(unsigned int i = 0; i < vdp->m_videoSurfaces.size(); i++)
1231 if(!(vdp->m_videoSurfaces[i]->state & (FF_VDPAU_STATE_USED_FOR_REFERENCE | FF_VDPAU_STATE_USED_FOR_RENDER)))
1233 render = vdp->m_videoSurfaces[i];
1239 VdpStatus vdp_st = VDP_STATUS_ERROR;
1242 // create a new surface
1243 VdpDecoderProfile profile;
1244 ReadFormatOf(avctx->codec_id, profile, vdp->vdp_chroma_type);
1245 render = (vdpau_render_state*)calloc(sizeof(vdpau_render_state), 1);
1248 CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - calloc failed");
1251 render->surface = VDP_INVALID_HANDLE;
1252 vdp->m_videoSurfaces.push_back(render);
1255 if (render->surface == VDP_INVALID_HANDLE)
1257 vdp_st = vdp->vdp_video_surface_create(vdp->vdp_device,
1258 vdp->vdp_chroma_type,
1260 avctx->coded_height,
1262 vdp->CheckStatus(vdp_st, __LINE__);
1263 if (vdp_st != VDP_STATUS_OK)
1266 CLog::Log(LOGERROR, "CVDPAU::FFGetBuffer - No Video surface available could be created");
1271 pic->data[1] = pic->data[2] = NULL;
1272 pic->data[0] = (uint8_t*)render;
1273 pic->data[3] = (uint8_t*)(uintptr_t)render->surface;
1275 pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0;
1279 pA->ip_age[0]= pA->ip_age[1]+1;
1289 pic->type= FF_BUFFER_TYPE_USER;
1291 render->state |= FF_VDPAU_STATE_USED_FOR_REFERENCE;
1292 pic->reordered_opaque= avctx->reordered_opaque;
1296 void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
1298 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
1299 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
1300 CVDPAU* vdp = (CVDPAU*)ctx->GetHardware();
1301 vdpau_render_state * render;
1304 CSharedLock lock(vdp->m_DecoderSection);
1306 render=(vdpau_render_state*)pic->data[0];
1309 CLog::Log(LOGERROR, "CVDPAU::FFReleaseBuffer - invalid context handle provided");
1316 // find render state in queue
1317 if (!vdp->IsSurfaceValid(render))
1319 CLog::Log(LOGDEBUG, "CVDPAU::FFReleaseBuffer - ignoring invalid buffer");
1323 render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE;
1326 VdpStatus CVDPAU::Render(VdpDecoder decoder, VdpVideoSurface target,
1327 VdpPictureInfo const *picture_info,
1328 uint32_t bitstream_buffer_count,
1329 VdpBitstreamBuffer const * bitstream_buffers)
1331 return VDP_STATUS_OK;
1334 void CVDPAU::FFDrawSlice(struct AVCodecContext *s,
1335 const AVFrame *src, int offset[4],
1336 int y, int type, int height)
1338 CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque;
1339 CVDPAU* vdp = (CVDPAU*)ctx->GetHardware();
1341 // while we are waiting to recover we can't do anything
1342 CSharedLock lock(vdp->m_DecoderSection);
1344 { CSharedLock dLock(vdp->m_DisplaySection);
1345 if(vdp->m_DisplayState != VDPAU_OPEN)
1350 if(src->linesize[0] || src->linesize[1] || src->linesize[2]
1351 || offset[0] || offset[1] || offset[2])
1353 CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid linesizes or offsets provided");
1358 vdpau_render_state * render;
1360 render = (vdpau_render_state*)src->data[0];
1363 CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid context handle provided");
1367 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1368 if (!vdp->IsSurfaceValid(render))
1370 CLog::Log(LOGWARNING, "CVDPAU::FFDrawSlice - ignoring invalid buffer");
1374 uint32_t max_refs = 0;
1375 if(s->codec_id == AV_CODEC_ID_H264)
1376 max_refs = vdp->m_hwContext.info.h264.num_ref_frames;
1378 if(vdp->decoder == VDP_INVALID_HANDLE
1379 || vdp->vdpauConfigured == false
1380 || vdp->max_references < max_refs)
1382 if(!vdp->ConfigVDPAU(s, max_refs))
1386 vdp_st = vdp->vdp_decoder_render(vdp->decoder,
1388 (VdpPictureInfo const *)&(vdp->m_hwContext.info),
1389 vdp->m_hwContext.bitstream_buffers_used,
1390 vdp->m_hwContext.bitstream_buffers);
1391 vdp->CheckStatus(vdp_st, __LINE__);
1394 int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame)
1396 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
1400 int result = Check(avctx);
1404 CSharedLock lock(m_DecoderSection);
1406 if (!vdpauConfigured)
1409 // configure vdpau output
1410 if (!ConfigOutputMethod(avctx, pFrame))
1413 outputSurface = outputSurfaces[surfaceNum];
1417 if (( (int)outRectVid.x1 != OutWidth ) ||
1418 ( (int)outRectVid.y1 != OutHeight ))
1422 outRectVid.x1 = OutWidth;
1423 outRectVid.y1 = OutHeight;
1426 EDEINTERLACEMODE mode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
1427 EINTERLACEMETHOD method = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
1428 if (method == VS_INTERLACEMETHOD_AUTO)
1429 method = AutoInterlaceMethod();
1432 { // we have a new frame from decoder
1434 vdpau_render_state * render = (vdpau_render_state*)pFrame->data[2];
1435 if(!render) // old style ffmpeg gave data on plane 0
1436 render = (vdpau_render_state*)pFrame->data[0];
1440 // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
1441 if (!IsSurfaceValid(render))
1443 CLog::Log(LOGWARNING, "CVDPAU::Decode - ignoring invalid buffer");
1447 render->state |= FF_VDPAU_STATE_USED_FOR_RENDER;
1449 ClearUsedForRender(&past[0]);
1455 DVDVideoPicture DVDPic;
1456 memset(&DVDPic, 0, sizeof(DVDVideoPicture));
1457 ((CDVDVideoCodecFFmpeg*)avctx->opaque)->GetPictureCommon(&DVDPic);
1458 m_DVDVideoPics.push(DVDPic);
1460 int pics = m_DVDVideoPics.size();
1465 // this should not normally happen
1466 CLog::Log(LOGERROR, "CVDPAU::Decode - invalid number of pictures in queue");
1468 m_DVDVideoPics.pop();
1471 if (mode == VS_DEINTERLACEMODE_FORCE
1472 || (mode == VS_DEINTERLACEMODE_AUTO && m_DVDVideoPics.front().iFlags & DVP_FLAG_INTERLACED))
1474 if((method == VS_INTERLACEMETHOD_AUTO_ION
1475 || method == VS_INTERLACEMETHOD_VDPAU_BOB
1476 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL
1477 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
1478 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL
1479 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
1480 || method == VS_INTERLACEMETHOD_VDPAU_INVERSE_TELECINE ))
1482 if((method == VS_INTERLACEMETHOD_AUTO_ION && vid_height > 576)
1483 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF
1484 || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_SPATIAL_HALF
1485 || avctx->skip_frame == AVDISCARD_NONREF)
1490 if(m_DVDVideoPics.front().iFlags & DVP_FLAG_TOP_FIELD_FIRST)
1491 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
1493 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
1498 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
1504 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
1508 else if(m_mixerstep == 1)
1509 { // no new frame given, output second field of old frame
1511 if(avctx->skip_frame == AVDISCARD_NONREF)
1513 ClearUsedForRender(&past[1]);
1514 m_DVDVideoPics.pop();
1519 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD)
1520 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
1522 m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
1526 CLog::Log(LOGERROR, "CVDPAU::Decode - invalid mixer state reached");
1530 VdpVideoSurface past_surfaces[2] = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
1531 VdpVideoSurface futu_surfaces[1] = { VDP_INVALID_HANDLE };
1533 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
1536 past_surfaces[1] = past[0]->surface;
1538 past_surfaces[0] = past[1]->surface;
1539 futu_surfaces[0] = future->surface;
1543 if(m_mixerstep == 1)
1547 past_surfaces[1] = past[1]->surface;
1548 past_surfaces[0] = past[1]->surface;
1550 futu_surfaces[0] = current->surface;
1555 past_surfaces[1] = past[1]->surface;
1556 past_surfaces[0] = current->surface;
1557 futu_surfaces[0] = future->surface;
1561 vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue,outputSurface,&time);
1563 VdpRect sourceRect = {0,0,vid_width, vid_height};
1565 vdp_st = vdp_video_mixer_render(videoMixer,
1580 CheckStatus(vdp_st, __LINE__);
1583 if (surfaceNum >= totalAvailableOutputSurfaces) surfaceNum = 0;
1585 if(m_mixerfield == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
1587 ClearUsedForRender(&past[0]);
1588 return VC_BUFFER | VC_PICTURE;
1592 // in order to clip top and bottom lines when de-interlacing
1593 // we black those lines as a work around for not working
1594 // background colour using the mixer
1595 // pixel perfect is preferred over overscanning or zooming
1597 VdpRect clipRect = outRectVid;
1598 clipRect.y1 = clipRect.y0 + 2;
1599 uint32_t *data[] = {m_BlackBar};
1600 uint32_t pitches[] = {outRectVid.x1};
1601 vdp_st = vdp_output_surface_put_bits_native(outputSurface,
1605 CheckStatus(vdp_st, __LINE__);
1607 clipRect = outRectVid;
1608 clipRect.y0 = clipRect.y1 - 2;
1609 vdp_st = vdp_output_surface_put_bits_native(outputSurface,
1613 CheckStatus(vdp_st, __LINE__);
1615 if(m_mixerstep == 1)
1619 ClearUsedForRender(&past[1]);
1620 return VC_BUFFER | VC_PICTURE;
1625 bool CVDPAU::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
1627 CSharedLock lock(m_DecoderSection);
1629 { CSharedLock dLock(m_DisplaySection);
1630 if (m_DisplayState != VDPAU_OPEN)
1634 *picture = m_DVDVideoPics.front();
1635 // if this is the first field of an interlaced frame, we'll need
1636 // this same picture for the second field later
1637 if (m_mixerstep != 1)
1638 m_DVDVideoPics.pop();
1640 picture->format = RENDER_FMT_VDPAU;
1641 picture->iFlags &= DVP_FLAG_DROPPED;
1642 picture->iWidth = OutWidth;
1643 picture->iHeight = OutHeight;
1644 picture->vdpau = this;
1648 picture->iRepeatPicture = -0.5;
1651 picture->dts = DVD_NOPTS_VALUE;
1652 picture->pts = DVD_NOPTS_VALUE;
1658 void CVDPAU::Reset()
1660 // invalidate surfaces and picture queue when seeking
1661 ClearUsedForRender(&past[0]);
1662 ClearUsedForRender(&past[1]);
1663 ClearUsedForRender(¤t);
1664 ClearUsedForRender(&future);
1666 while (!m_DVDVideoPics.empty())
1667 m_DVDVideoPics.pop();
1670 void CVDPAU::Present()
1672 //CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
1675 CSharedLock lock(m_DecoderSection);
1677 { CSharedLock dLock(m_DisplaySection);
1678 if (m_DisplayState != VDPAU_OPEN)
1682 presentSurface = outputSurface;
1684 vdp_st = vdp_presentation_queue_display(vdp_flip_queue,
1689 CheckStatus(vdp_st, __LINE__);
1692 bool CVDPAU::CheckStatus(VdpStatus vdp_st, int line)
1694 if (vdp_st != VDP_STATUS_OK)
1696 CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
1698 CExclusiveLock lock(m_DisplaySection);
1700 if(m_DisplayState == VDPAU_OPEN)
1702 if (vdp_st == VDP_STATUS_DISPLAY_PREEMPTED)
1704 m_DisplayEvent.Reset();
1705 m_DisplayState = VDPAU_LOST;
1708 m_DisplayState = VDPAU_ERROR;