Browse files

Merge pull request #468 from FernetMenta/mainline

fix crash on linux systems when refresh rate is changed
  • Loading branch information...
2 parents 8a0a87c + 12e90fb commit 01a556e5f6a2a1c01514b8c02270f35302f7679a @elupus elupus committed Nov 16, 2011
View
5 xbmc/ApplicationMessenger.cpp
@@ -43,6 +43,7 @@
#include "windowing/WindowingFactory.h"
#include "GUIInfoManager.h"
#include "utils/Splash.h"
+#include "cores/VideoRenderers/RenderManager.h"
#include "powermanagement/PowerManager.h"
@@ -232,6 +233,10 @@ void CApplicationMessenger::ProcessMessage(ThreadMessage *pMsg)
case POWERSTATE_MINIMIZE:
Minimize();
break;
+
+ case TMSG_RENDERER_FLUSH:
+ g_renderManager.Flush();
+ break;
}
}
break;
View
1 xbmc/ApplicationMessenger.h
@@ -76,6 +76,7 @@ class CGUIWindow;
#define TMSG_MINIMIZE 309
#define TMSG_TOGGLEFULLSCREEN 310
#define TMSG_SETLANGUAGE 311
+#define TMSG_RENDERER_FLUSH 312
#define TMSG_HTTPAPI 400
View
1 xbmc/cores/VideoRenderers/BaseRenderer.h
@@ -64,6 +64,7 @@ class CBaseRenderer
float GetAspectRatio() const;
virtual bool AddVideoPicture(DVDVideoPicture* picture) { return false; }
+ virtual void Flush() {};
virtual unsigned int GetProcessorSize() { return 0; }
View
16 xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -554,6 +554,20 @@ void CLinuxRendererGL::Reset()
}
}
+void CLinuxRendererGL::Flush()
+{
+ if (!m_bValidated)
+ return;
+
+ glFinish();
+
+ for (int i = 0 ; i < m_NumYV12Buffers ; i++)
+ (this->*m_textureDelete)(i);
+
+ glFinish();
+ m_bValidated = false;
+}
+
void CLinuxRendererGL::Update(bool bPauseDrawing)
{
if (!m_bConfigured) return;
@@ -1035,6 +1049,8 @@ void CLinuxRendererGL::UnInit()
CLog::Log(LOGDEBUG, "LinuxRendererGL: Cleaning up GL resources");
CSingleLock lock(g_graphicsContext);
+ glFinish();
+
if (m_rgbPbo)
{
glDeleteBuffersARB(1, &m_rgbPbo);
View
1 xbmc/cores/VideoRenderers/LinuxRendererGL.h
@@ -140,6 +140,7 @@ class CLinuxRendererGL : public CBaseRenderer
virtual unsigned int PreInit();
virtual void UnInit();
virtual void Reset(); /* resets renderer after seek for example */
+ virtual void Flush();
#ifdef HAVE_LIBVDPAU
virtual void AddProcessor(CVDPAU* vdpau);
View
29 xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -337,6 +337,35 @@ void CXBMCRenderManager::UnInit()
m_pRenderer->UnInit();
}
+bool CXBMCRenderManager::Flush()
+{
+ if (!m_pRenderer)
+ return true;
+
+ if (g_application.IsCurrentThread())
+ {
+ CLog::Log(LOGDEBUG, "%s - flushing renderer", __FUNCTION__);
+
+ CRetakeLock<CExclusiveLock> lock(m_sharedSection);
+ m_pRenderer->Flush();
+ m_flushEvent.Set();
+ }
+ else
+ {
+ ThreadMessage msg = {TMSG_RENDERER_FLUSH};
+ m_flushEvent.Reset();
+ g_application.getApplicationMessenger().SendMessage(msg, false);
+ if (!m_flushEvent.WaitMSec(1000))
+ {
+ CLog::Log(LOGERROR, "%s - timed out waiting for renderer to flush", __FUNCTION__);
+ return false;
+ }
+ else
+ return true;
+ }
+ return true;
+}
+
void CXBMCRenderManager::SetupScreenshot()
{
CSharedLock lock(m_sharedSection);
View
2 xbmc/cores/VideoRenderers/RenderManager.h
@@ -76,6 +76,7 @@ class CXBMCRenderManager
void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE);
unsigned int PreInit();
void UnInit();
+ bool Flush();
void AddOverlay(CDVDOverlay* o, double pts)
{
@@ -227,6 +228,7 @@ class CXBMCRenderManager
EPRESENTSTEP m_presentstep;
int m_presentsource;
CEvent m_presentevent;
+ CEvent m_flushEvent;
OVERLAY::CRenderer m_overlays;
View
2 xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
@@ -181,6 +181,8 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options
m_pCodecContext->codec_id = hints.codec;
m_pCodecContext->width = hints.width;
m_pCodecContext->height = hints.height;
+ m_pCodecContext->coded_width = hints.width;
+ m_pCodecContext->coded_height = hints.height;
if(vdp->Open(m_pCodecContext, pCodec->pix_fmts ? pCodec->pix_fmts[0] : PIX_FMT_NONE))
{
m_pHardware = vdp;
View
459 xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
@@ -73,12 +73,6 @@ static struct SInterlaceMapping
, {VS_INTERLACEMETHOD_NONE , (VdpVideoMixerFeature)-1}
};
-#define CHECK_VDPAU_RETURN(vdp, value) \
- do { \
- if(CheckStatus(vdp, __LINE__)) \
- return value; \
- } while(0);
-
//since libvdpau 0.4, vdp_device_create_x11() installs a callback on the Display*,
//if we unload libvdpau with dlclose(), we segfault on XCloseDisplay,
//so we just keep a static handle to libvdpau around
@@ -92,20 +86,21 @@ CVDPAU::CVDPAU()
surfaceNum = presentSurfaceNum = 0;
picAge.b_age = picAge.ip_age[0] = picAge.ip_age[1] = 256*256*256*64;
vdpauConfigured = false;
- recover = false;
+ m_DisplayState = VDPAU_OPEN;
m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
m_mixerstep = 0;
m_glPixmap = 0;
m_Pixmap = 0;
- m_glContext = 0;
if (!glXBindTexImageEXT)
glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXBindTexImageEXT");
if (!glXReleaseTexImageEXT)
glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte *) "glXReleaseTexImageEXT");
totalAvailableOutputSurfaces = 0;
outputSurface = presentSurface = VDP_INVALID_HANDLE;
+ vdp_flip_target = VDP_INVALID_HANDLE;
+ vdp_flip_queue = VDP_INVALID_HANDLE;
vid_width = vid_height = OutWidth = OutHeight = 0;
memset(&outRect, 0, sizeof(VdpRect));
memset(&outRectVid, 0, sizeof(VdpRect));
@@ -127,8 +122,8 @@ CVDPAU::CVDPAU()
bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces)
{
- if(avctx->width == 0
- || avctx->height == 0)
+ if(avctx->coded_width == 0
+ || avctx->coded_height == 0)
{
CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init");
return false;
@@ -150,6 +145,9 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su
}
}
+ if (!m_dllAvUtil.Load())
+ return false;
+
InitVDPAUProcs();
if (vdp_device != VDP_INVALID_HANDLE)
@@ -165,12 +163,12 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su
#endif
if(profile)
{
- if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->width))
+ if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width))
CLog::Log(LOGWARNING,"(VDPAU) width %i might not be supported because of hardware bug", avctx->width);
/* attempt to create a decoder with this width/height, some sizes are not supported by hw */
VdpStatus vdp_st;
- vdp_st = vdp_decoder_create(vdp_device, profile, avctx->width, avctx->height, 5, &decoder);
+ vdp_st = vdp_decoder_create(vdp_device, profile, avctx->coded_width, avctx->coded_height, 5, &decoder);
if(vdp_st != VDP_STATUS_OK)
{
@@ -183,14 +181,15 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su
CheckStatus(vdp_st, __LINE__);
}
- InitCSCMatrix(avctx->height);
- MakePixmap(avctx->width,avctx->height);
+ InitCSCMatrix(avctx->coded_height);
/* finally setup ffmpeg */
avctx->get_buffer = CVDPAU::FFGetBuffer;
avctx->release_buffer = CVDPAU::FFReleaseBuffer;
avctx->draw_horiz_band = CVDPAU::FFDrawSlice;
avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
+
+ g_Windowing.Register(this);
return true;
}
return false;
@@ -208,26 +207,8 @@ void CVDPAU::Close()
FiniVDPAUOutput();
FiniVDPAUProcs();
- if (m_glPixmap)
- {
- CLog::Log(LOGINFO, "GLX: Destroying glPixmap");
- glXReleaseTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT);
- glXDestroyPixmap(m_Display, m_glPixmap);
- m_glPixmap = NULL;
- }
- if (m_Pixmap)
- {
- CLog::Log(LOGINFO, "GLX: Destroying XPixmap");
- XFreePixmap(m_Display, m_Pixmap);
- m_Pixmap = NULL;
- }
-
- if (m_glContext)
- {
- CLog::Log(LOGINFO, "GLX: Destroying glContext");
- glXDestroyContext(m_Display, m_glContext);
- m_glContext = NULL;
- }
+ g_Windowing.Unregister(this);
+ m_dllAvUtil.Unload();
}
bool CVDPAU::MakePixmapGL()
@@ -275,36 +256,9 @@ bool CVDPAU::MakePixmapGL()
XFree(fbConfigs);
return false;
}
-
- /* to make the pixmap usable, it needs to have any context associated with it */
- GLXContext lastctx = glXGetCurrentContext();
- GLXDrawable lastdrw = glXGetCurrentDrawable();
-
- XVisualInfo *visInfo;
- visInfo = glXGetVisualFromFBConfig(m_Display, fbConfigs[fbConfigIndex]);
- if (!visInfo)
- {
- CLog::Log(LOGINFO, "GLX Error: Could not obtain X Visual Info for pixmap");
- XFree(fbConfigs);
- return false;
- }
XFree(fbConfigs);
- CLog::Log(LOGINFO, "GLX: Creating Pixmap context");
- m_glContext = glXCreateContext(m_Display, visInfo, NULL, True);
- XFree(visInfo);
-
- if (!glXMakeCurrent(m_Display, m_glPixmap, m_glContext))
- {
- CLog::Log(LOGINFO, "GLX Error: Could not make Pixmap current");
- return false;
- }
-
- /* restore what thread had before */
- glXMakeCurrent(m_Display, lastdrw, lastctx);
-
return true;
-
}
bool CVDPAU::MakePixmap(int width, int height)
@@ -363,6 +317,13 @@ bool CVDPAU::MakePixmap(int width, int height)
void CVDPAU::BindPixmap()
{
+ CSharedLock lock(m_DecoderSection);
+
+ { CSharedLock dLock(m_DisplaySection);
+ if (m_DisplayState != VDPAU_OPEN)
+ return;
+ }
+
if (m_glPixmap)
{
if(presentSurface != VDP_INVALID_HANDLE)
@@ -389,29 +350,81 @@ void CVDPAU::BindPixmap()
void CVDPAU::ReleasePixmap()
{
+ CSharedLock lock(m_DecoderSection);
+
+ { CSharedLock dLock(m_DisplaySection);
+ if (m_DisplayState != VDPAU_OPEN)
+ return;
+ }
+
if (m_glPixmap)
{
glXReleaseTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT);
}
else CLog::Log(LOGERROR,"(VDPAU) ReleasePixmap called without valid pixmap");
}
-bool CVDPAU::CheckRecover(bool force)
+void CVDPAU::OnLostDevice()
{
- if (recover || force)
+ CLog::Log(LOGNOTICE,"CVDPAU::OnLostDevice event");
+
+ { CExclusiveLock lock(m_DecoderSection);
+ FiniVDPAUOutput();
+ FiniVDPAUProcs();
+ }
+
+ CExclusiveLock lock(m_DisplaySection);
+ m_DisplayState = VDPAU_LOST;
+ m_DisplayEvent.Reset();
+}
+
+void CVDPAU::OnResetDevice()
+{
+ CLog::Log(LOGNOTICE,"CVDPAU::OnResetDevice event");
+
+ CExclusiveLock lock(m_DisplaySection);
+ if (m_DisplayState == VDPAU_LOST)
+ {
+ m_DisplayState = VDPAU_RESET;
+ m_DisplayEvent.Set();
+ }
+}
+
+int CVDPAU::Check(AVCodecContext* avctx)
+{
+ EDisplayState state;
+
+ { CSharedLock lock(m_DisplaySection);
+ state = m_DisplayState;
+ }
+
+ if (state == VDPAU_LOST)
+ {
+ CLog::Log(LOGNOTICE,"CVDPAU::Check waiting for display reset event");
+ if (!m_DisplayEvent.WaitMSec(2000))
+ {
+ CLog::Log(LOGERROR, "CVDPAU::Check - device didn't reset in reasonable time");
+ return VC_ERROR;
+ }
+ { CSharedLock lock(m_DisplaySection);
+ state = m_DisplayState;
+ }
+ }
+ if (state == VDPAU_RESET)
{
CLog::Log(LOGNOTICE,"Attempting recovery");
+ CSingleLock gLock(g_graphicsContext);
+ CExclusiveLock lock(m_DecoderSection);
+
FiniVDPAUOutput();
FiniVDPAUProcs();
- recover = false;
-
InitVDPAUProcs();
- return true;
+ return VC_FLUSHED;
}
- return false;
+ return 0;
}
bool CVDPAU::IsVDPAUFormat(PixelFormat format)
@@ -436,8 +449,8 @@ void CVDPAU::CheckFeatures()
};
void const * parameter_values[] = {
- &vid_width,
- &vid_height,
+ &surface_width,
+ &surface_height,
&vdp_chroma_type
};
@@ -746,14 +759,35 @@ void CVDPAU::InitVDPAUProcs()
#undef VDP_PROC
- vdp_st = vdp_preemption_callback_register(vdp_device,
- &VDPPreemptionCallbackFunction,
- (void*)this);
- CheckStatus(vdp_st, __LINE__);
+ // set all vdpau resources to invalid
+ vdp_flip_target = VDP_INVALID_HANDLE;
+ vdp_flip_queue = VDP_INVALID_HANDLE;
+ videoMixer = VDP_INVALID_HANDLE;
+ totalAvailableOutputSurfaces = 0;
+ presentSurface = VDP_INVALID_HANDLE;
+ outputSurface = VDP_INVALID_HANDLE;
+ for (int i = 0; i < NUM_OUTPUT_SURFACES; i++)
+ outputSurfaces[i] = VDP_INVALID_HANDLE;
+
+ m_vdpauOutputMethod = OUTPUT_NONE;
+
+ CExclusiveLock lock(m_DisplaySection);
+ m_DisplayState = VDPAU_OPEN;
+ vdpauConfigured = false;
}
void CVDPAU::FiniVDPAUProcs()
{
+ while (!m_videoSurfaces.empty())
+ {
+ vdpau_render_state *render = m_videoSurfaces.back();
+ m_videoSurfaces.pop_back();
+ if (render->bitstream_buffers_allocated)
+ m_dllAvUtil.av_freep(&render->bitstream_buffers);
+ render->bitstream_buffers_allocated = 0;
+ free(render);
+ }
+
if (vdp_device == VDP_INVALID_HANDLE) return;
VdpStatus vdp_st;
@@ -779,47 +813,32 @@ void CVDPAU::InitCSCMatrix(int Height)
void CVDPAU::FiniVDPAUOutput()
{
+ FiniOutputMethod();
+
if (vdp_device == VDP_INVALID_HANDLE || !vdpauConfigured) return;
CLog::Log(LOGNOTICE, " (VDPAU) %s", __FUNCTION__);
VdpStatus vdp_st;
vdp_st = vdp_decoder_destroy(decoder);
- CheckStatus(vdp_st, __LINE__);
+ if (CheckStatus(vdp_st, __LINE__))
+ return;
decoder = VDP_INVALID_HANDLE;
- vdp_st = vdp_presentation_queue_destroy(vdp_flip_queue);
- CheckStatus(vdp_st, __LINE__);
- vdp_flip_queue = VDP_INVALID_HANDLE;
-
- vdp_st = vdp_presentation_queue_target_destroy(vdp_flip_target);
- CheckStatus(vdp_st, __LINE__);
- vdp_flip_target = VDP_INVALID_HANDLE;
-
- outputSurface = presentSurface = VDP_INVALID_HANDLE;
-
- for (int i = 0; i < totalAvailableOutputSurfaces; i++)
+ while (!m_videoSurfaces.empty())
{
- vdp_st = vdp_output_surface_destroy(outputSurfaces[i]);
- CheckStatus(vdp_st, __LINE__);
- outputSurfaces[i] = VDP_INVALID_HANDLE;
- }
-
- vdp_st = vdp_video_mixer_destroy(videoMixer);
- CheckStatus(vdp_st, __LINE__);
- videoMixer = VDP_INVALID_HANDLE;
-
- for(unsigned int i = 0; i < m_videoSurfaces.size(); i++)
- {
- vdp_st = vdp_video_surface_destroy(m_videoSurfaces[i]->surface);
- CheckStatus(vdp_st, __LINE__);
- m_videoSurfaces[i]->surface = VDP_INVALID_HANDLE;
- free(m_videoSurfaces[i]);
+ vdpau_render_state *render = m_videoSurfaces.back();
+ m_videoSurfaces.pop_back();
+ if (render->bitstream_buffers_allocated)
+ m_dllAvUtil.av_freep(&render->bitstream_buffers);
+ render->bitstream_buffers_allocated = 0;
+ vdp_st = vdp_video_surface_destroy(render->surface);
+ render->surface = VDP_INVALID_HANDLE;
+ free(render);
+ if (CheckStatus(vdp_st, __LINE__))
+ return;
}
- m_videoSurfaces.clear();
- while (!m_DVDVideoPics.empty())
- m_DVDVideoPics.pop();
}
@@ -870,10 +889,12 @@ bool CVDPAU::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
VdpDecoderProfile vdp_decoder_profile;
vid_width = avctx->width;
vid_height = avctx->height;
+ surface_width = avctx->coded_width;
+ surface_height = avctx->coded_height;
past[1] = past[0] = current = future = NULL;
- CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i",OutWidth,vid_width);
- CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i",OutHeight,vid_height);
+ CLog::Log(LOGNOTICE, " (VDPAU) screenWidth:%i vidWidth:%i surfaceWidth:%i",OutWidth,vid_width,surface_width);
+ CLog::Log(LOGNOTICE, " (VDPAU) screenHeight:%i vidHeight:%i surfaceHeight:%i",OutHeight,vid_height,surface_height);
ReadFormatOf(avctx->pix_fmt, vdp_decoder_profile, vdp_chroma_type);
if(avctx->pix_fmt == PIX_FMT_VDPAU_H264)
@@ -887,21 +908,41 @@ bool CVDPAU::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
vdp_st = vdp_decoder_create(vdp_device,
vdp_decoder_profile,
- vid_width,
- vid_height,
+ surface_width,
+ surface_height,
max_references,
&decoder);
- CHECK_VDPAU_RETURN(vdp_st, false);
+ if (CheckStatus(vdp_st, __LINE__))
+ return false;
+
+ m_vdpauOutputMethod = OUTPUT_NONE;
+
+ vdpauConfigured = true;
+ return true;
+}
+
+bool CVDPAU::ConfigOutputMethod(AVCodecContext *avctx, AVFrame *pFrame)
+{
+ VdpStatus vdp_st;
+
+ if (m_vdpauOutputMethod == OUTPUT_PIXMAP)
+ return true;
+
+ FiniOutputMethod();
+
+ MakePixmap(avctx->width,avctx->height);
vdp_st = vdp_presentation_queue_target_create_x11(vdp_device,
m_Pixmap, //x_window,
&vdp_flip_target);
- CHECK_VDPAU_RETURN(vdp_st, false);
+ if (CheckStatus(vdp_st, __LINE__))
+ return false;
vdp_st = vdp_presentation_queue_create(vdp_device,
vdp_flip_target,
&vdp_flip_queue);
- CHECK_VDPAU_RETURN(vdp_st, false);
+ if (CheckStatus(vdp_st, __LINE__))
+ return false;
totalAvailableOutputSurfaces = 0;
@@ -917,7 +958,8 @@ bool CVDPAU::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
OutWidth,
OutHeight,
&outputSurfaces[i]);
- CHECK_VDPAU_RETURN(vdp_st, false);
+ if (CheckStatus(vdp_st, __LINE__))
+ return false;
totalAvailableOutputSurfaces++;
}
CLog::Log(LOGNOTICE, " (VDPAU) Total Output Surfaces Available: %i of a max (tmp: %i const: %i)",
@@ -926,9 +968,67 @@ bool CVDPAU::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
NUM_OUTPUT_SURFACES);
surfaceNum = presentSurfaceNum = 0;
- outputSurface = outputSurfaces[surfaceNum];
+ outputSurface = presentSurface = VDP_INVALID_HANDLE;
+ videoMixer = VDP_INVALID_HANDLE;
+
+ m_vdpauOutputMethod = OUTPUT_PIXMAP;
+
+ return true;
+}
+
+bool CVDPAU::FiniOutputMethod()
+{
+ VdpStatus vdp_st;
+
+ if (vdp_flip_queue != VDP_INVALID_HANDLE)
+ {
+ vdp_st = vdp_presentation_queue_destroy(vdp_flip_queue);
+ vdp_flip_queue = VDP_INVALID_HANDLE;
+ CheckStatus(vdp_st, __LINE__);
+ }
+
+ if (vdp_flip_target != VDP_INVALID_HANDLE)
+ {
+ vdp_st = vdp_presentation_queue_target_destroy(vdp_flip_target);
+ vdp_flip_target = VDP_INVALID_HANDLE;
+ CheckStatus(vdp_st, __LINE__);
+ }
+
+ if (m_glPixmap)
+ {
+ CLog::Log(LOGDEBUG, "GLX: Destroying glPixmap");
+ glXDestroyPixmap(m_Display, m_glPixmap);
+ m_glPixmap = NULL;
+ }
+
+ if (m_Pixmap)
+ {
+ CLog::Log(LOGDEBUG, "GLX: Destroying XPixmap");
+ XFreePixmap(m_Display, m_Pixmap);
+ m_Pixmap = NULL;
+ }
+
+ outputSurface = presentSurface = VDP_INVALID_HANDLE;
+
+ for (int i = 0; i < totalAvailableOutputSurfaces; i++)
+ {
+ if (outputSurfaces[i] == VDP_INVALID_HANDLE)
+ continue;
+ vdp_st = vdp_output_surface_destroy(outputSurfaces[i]);
+ outputSurfaces[i] = VDP_INVALID_HANDLE;
+ CheckStatus(vdp_st, __LINE__);
+ }
+
+ if (videoMixer != VDP_INVALID_HANDLE)
+ {
+ vdp_st = vdp_video_mixer_destroy(videoMixer);
+ videoMixer = VDP_INVALID_HANDLE;
+ if (CheckStatus(vdp_st, __LINE__));
+ }
+
+ while (!m_DVDVideoPics.empty())
+ m_DVDVideoPics.pop();
-vdpauConfigured = true;
return true;
}
@@ -981,6 +1081,21 @@ void CVDPAU::SpewHardwareAvailable() //Copyright (c) 2008 Wladimir J. van der L
}
+bool CVDPAU::IsSurfaceValid(vdpau_render_state *render)
+{
+ // find render state in queue
+ bool found(false);
+ for(unsigned int i = 0; i < m_videoSurfaces.size(); ++i)
+ {
+ if(m_videoSurfaces[i] == render)
+ {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
{
//CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
@@ -989,10 +1104,14 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
struct pictureAge* pA = &vdp->picAge;
// while we are waiting to recover we can't do anything
- if(vdp->recover)
- {
- CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
- return -1;
+ CSharedLock lock(vdp->m_DecoderSection);
+
+ { CSharedLock dLock(vdp->m_DisplaySection);
+ if(vdp->m_DisplayState != VDPAU_OPEN)
+ {
+ CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery");
+ return -1;
+ }
}
vdpau_render_state * render = NULL;
@@ -1015,10 +1134,15 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
VdpDecoderProfile profile;
ReadFormatOf(avctx->pix_fmt, profile, vdp->vdp_chroma_type);
render = (vdpau_render_state*)calloc(sizeof(vdpau_render_state), 1);
+ if (render == NULL)
+ {
+ CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - calloc failed");
+ return -1;
+ }
vdp_st = vdp->vdp_video_surface_create(vdp->vdp_device,
vdp->vdp_chroma_type,
- avctx->width,
- avctx->height,
+ avctx->coded_width,
+ avctx->coded_height,
&render->surface);
vdp->CheckStatus(vdp_st, __LINE__);
if (vdp_st != VDP_STATUS_OK)
@@ -1062,19 +1186,31 @@ int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic)
void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic)
{
//CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
- vdpau_render_state * render;
- int i;
+ CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque;
+ CVDPAU* vdp = (CVDPAU*)ctx->GetHardware();
+ vdpau_render_state * render;
+ unsigned int i;
+
+ CSharedLock lock(vdp->m_DecoderSection);
render=(vdpau_render_state*)pic->data[0];
if(!render)
{
- CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid context handle provided");
+ CLog::Log(LOGERROR, "CVDPAU::FFReleaseBuffer - invalid context handle provided");
return;
}
- render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE;
for(i=0; i<4; i++)
pic->data[i]= NULL;
+
+ // find render state in queue
+ if (!vdp->IsSurfaceValid(render))
+ {
+ CLog::Log(LOGDEBUG, "CVDPAU::FFReleaseBuffer - ignoring invalid buffer");
+ return;
+ }
+
+ render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE;
}
@@ -1085,9 +1221,14 @@ void CVDPAU::FFDrawSlice(struct AVCodecContext *s,
CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque;
CVDPAU* vdp = (CVDPAU*)ctx->GetHardware();
- /* while we are waiting to recover we can't do anything */
- if(vdp->recover)
- return;
+ // while we are waiting to recover we can't do anything
+ CSharedLock lock(vdp->m_DecoderSection);
+
+ { CSharedLock dLock(vdp->m_DisplaySection);
+ if(vdp->m_DisplayState != VDPAU_OPEN)
+ return;
+ }
+
if(src->linesize[0] || src->linesize[1] || src->linesize[2]
|| offset[0] || offset[1] || offset[2])
@@ -1106,6 +1247,13 @@ void CVDPAU::FFDrawSlice(struct AVCodecContext *s,
return;
}
+ // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
+ if (!vdp->IsSurfaceValid(render))
+ {
+ CLog::Log(LOGWARNING, "CVDPAU::FFDrawSlice - ignoring invalid buffer");
+ return;
+ }
+
uint32_t max_refs = 0;
if(s->pix_fmt == PIX_FMT_VDPAU_H264)
max_refs = render->info.h264.num_ref_frames;
@@ -1132,12 +1280,19 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame)
VdpStatus vdp_st;
VdpTime time;
- if (CheckRecover(false))
- return VC_FLUSHED;
+ CSharedLock lock(m_DecoderSection);
+
+ int result = Check(avctx);
+ if (result)
+ return result;
if (!vdpauConfigured)
return VC_ERROR;
+ // configure vdpau output
+ if (!ConfigOutputMethod(avctx, pFrame))
+ return VC_FLUSHED;
+
outputSurface = outputSurfaces[surfaceNum];
CheckFeatures();
@@ -1165,6 +1320,13 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame)
if(!render)
return VC_ERROR;
+ // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid
+ if (!IsSurfaceValid(render))
+ {
+ CLog::Log(LOGWARNING, "CVDPAU::Decode - ignoring invalid buffer");
+ return VC_BUFFER;
+ }
+
render->state |= FF_VDPAU_STATE_USED_FOR_RENDER;
ClearUsedForRender(&past[0]);
@@ -1279,6 +1441,8 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame)
vdp_st = vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue,outputSurface,&time);
+ VdpRect sourceRect = {0,0,vid_width, vid_height};
+
vdp_st = vdp_video_mixer_render(videoMixer,
VDP_INVALID_HANDLE,
0,
@@ -1288,7 +1452,7 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame)
current->surface,
1,
futu_surfaces,
- NULL,
+ &sourceRect,
outputSurface,
&(outRectVid),
&(outRectVid),
@@ -1318,6 +1482,13 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame)
bool CVDPAU::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
{
+ CSharedLock lock(m_DecoderSection);
+
+ { CSharedLock dLock(m_DisplaySection);
+ if (m_DisplayState != VDPAU_OPEN)
+ return false;
+ }
+
*picture = m_DVDVideoPics.front();
// if this is the first field of an interlaced frame, we'll need
// this same picture for the second field later
@@ -1358,6 +1529,14 @@ void CVDPAU::Present()
{
//CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
VdpStatus vdp_st;
+
+ CSharedLock lock(m_DecoderSection);
+
+ { CSharedLock dLock(m_DisplaySection);
+ if (m_DisplayState != VDPAU_OPEN)
+ return;
+ }
+
presentSurface = outputSurface;
vdp_st = vdp_presentation_queue_display(vdp_flip_queue,
@@ -1368,27 +1547,17 @@ void CVDPAU::Present()
CheckStatus(vdp_st, __LINE__);
}
-void CVDPAU::VDPPreemptionCallbackFunction(VdpDevice device, void* context)
-{
- CLog::Log(LOGERROR,"VDPAU Device Preempted - attempting recovery");
- CVDPAU* pCtx = (CVDPAU*)context;
- pCtx->recover = true;
-}
-
bool CVDPAU::CheckStatus(VdpStatus vdp_st, int line)
{
- if (vdp_st == VDP_STATUS_HANDLE_DEVICE_MISMATCH
- || vdp_st == VDP_STATUS_DISPLAY_PREEMPTED)
- recover = true;
-
- // no need to log errors about this case, as it will happen on cleanup
- if (vdp_st == VDP_STATUS_INVALID_HANDLE && recover && vdpauConfigured)
- return false;
-
if (vdp_st != VDP_STATUS_OK)
{
CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
- recover = true;
+
+ CExclusiveLock lock(m_DisplaySection);
+
+ if(m_DisplayState == VDPAU_OPEN)
+ m_DisplayState = VDPAU_RESET;
+
return true;
}
return false;
View
47 xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h
@@ -21,6 +21,7 @@
*
*/
+#include "DllAvUtil.h"
#include "DVDVideoCodec.h"
#include "DVDVideoCodecFFmpeg.h"
#include "libavcodec/vdpau.h"
@@ -32,7 +33,10 @@
#include <GL/glx.h>
#include <queue>
#include "threads/CriticalSection.h"
+#include "threads/SharedSection.h"
#include "settings/VideoSettings.h"
+#include "guilib/DispResource.h"
+#include "threads/Event.h"
namespace Surface { class CSurface; }
#define NUM_OUTPUT_SURFACES 4
@@ -44,6 +48,7 @@ namespace Surface { class CSurface; }
class CVDPAU
: public CDVDVideoCodecFFmpeg::IHardwareDecoder
+ , public IDispResource
{
public:
@@ -69,13 +74,8 @@ class CVDPAU
virtual void Reset();
virtual void Close();
- virtual int Check(AVCodecContext* avctx)
- {
- if(CheckRecover(false))
- return VC_FLUSHED;
- else
- return 0;
- }
+ virtual int Check(AVCodecContext* avctx);
+
virtual const std::string Name() { return "vdpau"; }
bool MakePixmap(int width, int height);
@@ -88,23 +88,20 @@ class CVDPAU
PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
GLXPixmap m_glPixmap;
Pixmap m_Pixmap;
- GLXContext m_glContext;
static void FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic);
static void FFDrawSlice(struct AVCodecContext *s,
const AVFrame *src, int offset[4],
int y, int type, int height);
static int FFGetBuffer(AVCodecContext *avctx, AVFrame *pic);
- static void VDPPreemptionCallbackFunction(VdpDevice device, void* context);
-
void Present();
bool ConfigVDPAU(AVCodecContext *avctx, int ref_frames);
void SpewHardwareAvailable();
void InitCSCMatrix(int Height);
bool CheckStatus(VdpStatus vdp_st, int line);
+ bool IsSurfaceValid(vdpau_render_state *render);
- bool CheckRecover(bool force = false);
void CheckFeatures();
void SetColor();
void SetNoiseReduction();
@@ -113,7 +110,6 @@ class CVDPAU
void SetHWUpscaling();
pictureAge picAge;
- bool recover;
vdpau_render_state *past[2], *current, *future;
int tmpDeintMode, tmpDeintGUI, tmpDeint;
float tmpNoiseReduction, tmpSharpness;
@@ -140,6 +136,8 @@ class CVDPAU
void InitVDPAUProcs();
void FiniVDPAUProcs();
void FiniVDPAUOutput();
+ bool ConfigOutputMethod(AVCodecContext *avctx, AVFrame *pFrame);
+ bool FiniOutputMethod();
VdpDevice vdp_device;
VdpGetProcAddress * vdp_get_proc_address;
@@ -206,6 +204,7 @@ class CVDPAU
int presentSurfaceNum;
int totalAvailableOutputSurfaces;
uint32_t vid_width, vid_height;
+ int surface_width, surface_height;
uint32_t max_references;
Display* m_Display;
bool vdpauConfigured;
@@ -227,4 +226,28 @@ class CVDPAU
, VdpChromaType &chroma_type);
std::vector<vdpau_render_state*> m_videoSurfaces;
+ DllAvUtil m_dllAvUtil;
+
+ enum VDPAUOutputMethod
+ {
+ OUTPUT_NONE,
+ OUTPUT_PIXMAP,
+ OUTPUT_GL_INTEROP_RGB,
+ OUTPUT_GL_INTEROP_YUV
+ };
+ VDPAUOutputMethod m_vdpauOutputMethod;
+
+ // OnLostDevice triggers transition from all states to LOST
+ // internal errors trigger transition from OPEN to RESET
+ // OnResetDevice triggers transition from LOST to RESET
+ enum EDisplayState
+ { VDPAU_OPEN
+ , VDPAU_RESET
+ , VDPAU_LOST
+ } m_DisplayState;
+ CSharedSection m_DecoderSection;
+ CSharedSection m_DisplaySection;
+ CEvent m_DisplayEvent;
+ virtual void OnLostDevice();
+ virtual void OnResetDevice();
};
View
33 xbmc/guilib/DispResource.h
@@ -0,0 +1,33 @@
+/*
+* Copyright (C) 2005-2008 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+#pragma once
+
+#ifdef HAS_GLX
+class IDispResource
+{
+public:
+ virtual ~IDispResource() {};
+ virtual void OnLostDevice() {};
+ virtual void OnResetDevice() {};
+};
+
+#endif
View
90 xbmc/windowing/X11/WinSystemX11.cpp
@@ -27,9 +27,18 @@
#include "WinSystemX11.h"
#include "settings/Settings.h"
#include "guilib/Texture.h"
+#include "guilib/DispResource.h"
#include "utils/log.h"
#include "XRandR.h"
#include <vector>
+#include "threads/SingleLock.h"
+#include <X11/Xlib.h>
+#include "cores/VideoRenderers/RenderManager.h"
+#include "utils/TimeUtils.h"
+
+#if defined(HAS_XRANDR)
+#include <X11/extensions/Xrandr.h>
+#endif
using namespace std;
@@ -42,6 +51,7 @@ CWinSystemX11::CWinSystemX11() : CWinSystemBase()
m_glWindow = 0;
m_wmWindow = 0;
m_bWasFullScreenBeforeMinimize = false;
+ m_dpyLostTime = 0;
}
CWinSystemX11::~CWinSystemX11()
@@ -126,6 +136,13 @@ bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RES
SDL_WM_SetIcon(SDL_CreateRGBSurfaceFrom(iconTexture.GetPixels(), iconTexture.GetWidth(), iconTexture.GetHeight(), 32, iconTexture.GetPitch(), 0xff0000, 0x00ff00, 0x0000ff, 0xff000000L), NULL);
SDL_WM_SetCaption("XBMC Media Center", NULL);
+ // register XRandR Events
+#if defined(HAS_XRANDR)
+ int iReturn;
+ XRRQueryExtension(m_dpy, &m_RREventBase, &iReturn);
+ XRRSelectInput(m_dpy, m_wmWindow, RRScreenChangeNotifyMask);
+#endif
+
m_bWindowCreated = true;
return true;
}
@@ -175,7 +192,10 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
mode.id = res.strId;
if(m_bFullScreen)
+ {
+ OnLostDevice();
g_xrandr.SetMode(out, mode);
+ }
else
g_xrandr.RestoreState();
#endif
@@ -444,4 +464,74 @@ bool CWinSystemX11::Show(bool raise)
XSync(m_dpy, False);
return true;
}
+
+void CWinSystemX11::CheckDisplayEvents()
+{
+#if defined(HAS_XRANDR)
+ bool bGotEvent(false);
+ bool bTimeout(false);
+ XEvent Event;
+ while (XCheckTypedEvent(m_dpy, m_RREventBase + RRScreenChangeNotify, &Event))
+ {
+ if (Event.type == m_RREventBase + RRScreenChangeNotify)
+ {
+ CLog::Log(LOGDEBUG, "%s: Received RandR event %i", __FUNCTION__, Event.type);
+ bGotEvent = true;
+ }
+ XRRUpdateConfiguration(&Event);
+ }
+
+ // check fail safe timer
+ if (m_dpyLostTime && CurrentHostCounter() - m_dpyLostTime > (uint64_t)3 * CurrentHostFrequency())
+ {
+ CLog::Log(LOGERROR, "%s - no display event after 3 seconds", __FUNCTION__);
+ bTimeout = true;
+ }
+
+ if (bGotEvent || bTimeout)
+ {
+ CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__);
+
+ CSingleLock lock(m_resourceSection);
+
+ // tell any shared resources
+ for (vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
+ (*i)->OnResetDevice();
+
+ // reset fail safe timer
+ m_dpyLostTime = 0;
+ }
+#endif
+}
+
+void CWinSystemX11::OnLostDevice()
+{
+ CLog::Log(LOGDEBUG, "%s - notify display change event", __FUNCTION__);
+
+ // make sure renderer has no invalid references
+ g_renderManager.Flush();
+
+ { CSingleLock lock(m_resourceSection);
+ for (vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
+ (*i)->OnLostDevice();
+ }
+
+ // fail safe timer
+ m_dpyLostTime = CurrentHostCounter();
+}
+
+void CWinSystemX11::Register(IDispResource *resource)
+{
+ CSingleLock lock(m_resourceSection);
+ m_resources.push_back(resource);
+}
+
+void CWinSystemX11::Unregister(IDispResource* resource)
+{
+ CSingleLock lock(m_resourceSection);
+ vector<IDispResource*>::iterator i = find(m_resources.begin(), m_resources.end(), resource);
+ if (i != m_resources.end())
+ m_resources.erase(i);
+}
+
#endif
View
11 xbmc/windowing/X11/WinSystemX11.h
@@ -26,6 +26,9 @@
#include "windowing/WinSystem.h"
#include "utils/Stopwatch.h"
#include <GL/glx.h>
+#include "threads/CriticalSection.h"
+
+class IDispResource;
class CWinSystemX11 : public CWinSystemBase
{
@@ -51,20 +54,28 @@ class CWinSystemX11 : public CWinSystemBase
virtual bool Restore() ;
virtual bool Hide();
virtual bool Show(bool raise = true);
+ virtual void Register(IDispResource *resource);
+ virtual void Unregister(IDispResource *resource);
// Local to WinSystemX11 only
Display* GetDisplay() { return m_dpy; }
GLXWindow GetWindow() { return m_glWindow; }
protected:
bool RefreshGlxContext();
+ void CheckDisplayEvents();
+ void OnLostDevice();
SDL_Surface* m_SDLSurface;
GLXContext m_glContext;
GLXWindow m_glWindow;
Window m_wmWindow;
Display* m_dpy;
bool m_bWasFullScreenBeforeMinimize;
+ int m_RREventBase;
+ CCriticalSection m_resourceSection;
+ std::vector<IDispResource*> m_resources;
+ uint64_t m_dpyLostTime;
private:
bool IsSuitableVisual(XVisualInfo *vInfo);
View
2 xbmc/windowing/X11/WinSystemX11GL.cpp
@@ -43,6 +43,8 @@ CWinSystemX11GL::~CWinSystemX11GL()
bool CWinSystemX11GL::PresentRenderImpl(const CDirtyRegionList& dirty)
{
+ CheckDisplayEvents();
+
if(m_iVSyncMode == 3)
{
glFinish();

0 comments on commit 01a556e

Please sign in to comment.