Improve video operation errors somewhat. Updates #1020.

Originally committed to SVN as r3835.
This commit is contained in:
Thomas Goyne 2009-12-01 00:32:43 +00:00
parent dadd09ff49
commit 86f64b2962
4 changed files with 80 additions and 90 deletions

View file

@ -149,6 +149,7 @@ void VideoContext::Clear() {
/// @brief Reset /// @brief Reset
/// ///
void VideoContext::Reset() { void VideoContext::Reset() {
loaded = false;
StandardPaths::SetPathValue(_T("?video"),_T("")); StandardPaths::SetPathValue(_T("?video"),_T(""));
KeyFrames.Clear(); KeyFrames.Clear();
@ -164,7 +165,6 @@ void VideoContext::Reset() {
} }
// Remove video data // Remove video data
loaded = false;
frame_n = 0; frame_n = 0;
length = 0; length = 0;
fps = 0; fps = 0;
@ -221,7 +221,6 @@ void VideoContext::SetVideo(const wxString &filename) {
// Choose a provider // Choose a provider
provider = VideoProviderFactoryManager::GetProvider(filename); provider = VideoProviderFactoryManager::GetProvider(filename);
loaded = provider != NULL;
// Get subtitles provider // Get subtitles provider
try { try {
@ -356,31 +355,14 @@ void VideoContext::JumpToFrame(int n) {
// Prevent intervention during playback // Prevent intervention during playback
if (isPlaying && n != playNextFrame) return; if (isPlaying && n != playNextFrame) return;
try { // Set frame number
// Set frame number frame_n = n;
frame_n = n;
// Display // Display
UpdateDisplays(false); UpdateDisplays(false);
// Update grid // Update grid
if (!isPlaying && Options.AsBool(_T("Highlight subs in frame"))) grid->Refresh(false); if (!isPlaying && Options.AsBool(_T("Highlight subs in frame"))) grid->Refresh(false);
}
catch (const wxChar *err) {
wxLogError(
_T("Failed seeking video. The video will be closed because of this.\n")
_T("If you get this error regardless of which video file you use, and also if you use dummy video, Aegisub might not work with your graphics card's OpenGL driver.\n")
_T("Error message reported: %s"),
err);
Reset();
}
catch (...) {
wxLogError(
_T("Failed seeking video. The video will be closed because of this.\n")
_T("If you get this error regardless of which video file you use, and also if you use dummy video, Aegisub might not work with your graphics card's OpenGL driver.\n")
_T("No further error message given."));
Reset();
}
} }

View file

@ -195,8 +195,37 @@ void VideoDisplay::SetFrame(int frameNumber) {
// Render the new frame // Render the new frame
if (context->IsLoaded()) { if (context->IsLoaded()) {
AegiVideoFrame frame = context->GetFrame(frameNumber); AegiVideoFrame frame;
videoOut->UploadFrameData(frame); try {
frame = context->GetFrame(frameNumber);
}
catch (const wxChar *err) {
wxLogError(
_T("Failed seeking video. The video file may be corrupt or incomplete.\n")
_T("Error message reported: %s"),
err);
}
catch (...) {
wxLogError(
_T("Failed seeking video. The video file may be corrupt or incomplete.\n")
_T("No further error message given."));
}
try {
videoOut->UploadFrameData(frame);
}
catch (const VideoOutInitException& err) {
wxLogError(
L"Failed to initialize video display. Closing other running programs and updating your video card drivers may fix this.\n"
L"Error message reported: %s",
err.GetMessage());
context->Reset();
}
catch (const VideoOutRenderException& err) {
wxLogError(
L"Could not upload video frame to graphics card.\n"
L"Error message reported: %s",
err.GetMessage());
}
} }
Render(); Render();
@ -289,18 +318,9 @@ void VideoDisplay::Render() try {
glFinish(); glFinish();
SwapBuffers(); SwapBuffers();
} }
catch (const VideoOutUnsupportedException &err) {
wxLogError(
_T("An error occurred trying to render the video frame to screen.\n")
_T("Your graphics card does not appear to have a functioning OpenGL driver.\n")
_T("Error message reported: %s"),
err.GetMessage());
VideoContext::Get()->Reset();
}
catch (const VideoOutException &err) { catch (const VideoOutException &err) {
wxLogError( wxLogError(
_T("An error occurred trying to render the video frame to screen.\n") _T("An error occurred trying to render the video frame on the screen.\n")
_T("If you get this error regardless of which video file you use, and also if you use dummy video, Aegisub might not work with your graphics card's OpenGL driver.\n")
_T("Error message reported: %s"), _T("Error message reported: %s"),
err.GetMessage()); err.GetMessage());
VideoContext::Get()->Reset(); VideoContext::Get()->Reset();
@ -308,7 +328,6 @@ catch (const VideoOutException &err) {
catch (const wxChar *err) { catch (const wxChar *err) {
wxLogError( wxLogError(
_T("An error occurred trying to render the video frame to screen.\n") _T("An error occurred trying to render the video frame to screen.\n")
_T("If you get this error regardless of which video file you use, and also if you use dummy video, Aegisub might not work with your graphics card's OpenGL driver.\n")
_T("Error message reported: %s"), _T("Error message reported: %s"),
err); err);
VideoContext::Get()->Reset(); VideoContext::Get()->Reset();
@ -316,7 +335,6 @@ catch (const wxChar *err) {
catch (...) { catch (...) {
wxLogError( wxLogError(
_T("An error occurred trying to render the video frame to screen.\n") _T("An error occurred trying to render the video frame to screen.\n")
_T("If you get this error regardless of which video file you use, and also if you use dummy video, Aegisub might not work with your graphics card's OpenGL driver.\n")
_T("No further error message given.")); _T("No further error message given."));
VideoContext::Get()->Reset(); VideoContext::Get()->Reset();
} }

View file

@ -58,6 +58,9 @@
#define GL_CLAMP_TO_EDGE 0x812F #define GL_CLAMP_TO_EDGE 0x812F
#endif #endif
#define CHECK_INIT_ERROR(cmd) cmd; if (GLenum err = glGetError()) throw VideoOutInitException(_T(#cmd), err)
#define CHECK_ERROR(cmd) cmd; if (GLenum err = glGetError()) throw VideoOutRenderException(_T(#cmd), err)
namespace { namespace {
/// @brief Structure tracking all precomputable information about a subtexture /// @brief Structure tracking all precomputable information about a subtexture
struct TextureInfo { struct TextureInfo {
@ -122,7 +125,7 @@ void VideoOutGL::DetectOpenGLCapabilities() {
// Test for supported internalformats // Test for supported internalformats
if (TestTexture(64, 64, GL_RGBA8)) internalFormat = GL_RGBA8; if (TestTexture(64, 64, GL_RGBA8)) internalFormat = GL_RGBA8;
else if (TestTexture(64, 64, GL_RGBA)) internalFormat = GL_RGBA; else if (TestTexture(64, 64, GL_RGBA)) internalFormat = GL_RGBA;
else throw VideoOutUnsupportedException(L"Could not create a 64x64 RGB texture in any format."); else throw VideoOutInitException(L"Could not create a 64x64 RGB texture in any format.");
// Test for the maximum supported texture size // Test for the maximum supported texture size
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
@ -161,8 +164,7 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo
// Clean up old textures // Clean up old textures
if (textureIdList.size() > 0) { if (textureIdList.size() > 0) {
glDeleteTextures(textureIdList.size(), &textureIdList[0]); CHECK_INIT_ERROR(glDeleteTextures(textureIdList.size(), &textureIdList[0]));
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glDeleteTextures", err);
textureIdList.clear(); textureIdList.clear();
textureList.clear(); textureList.clear();
} }
@ -172,8 +174,7 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo
textureCols = (int)ceil(double(width) / maxTextureSize); textureCols = (int)ceil(double(width) / maxTextureSize);
textureIdList.resize(textureRows * textureCols); textureIdList.resize(textureRows * textureCols);
textureList.resize(textureRows * textureCols); textureList.resize(textureRows * textureCols);
glGenTextures(textureIdList.size(), &textureIdList[0]); CHECK_INIT_ERROR(glGenTextures(textureIdList.size(), &textureIdList[0]));
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glGenTextures", err);
// Calculate the position information for each texture // Calculate the position information for each texture
int sourceY = 0; int sourceY = 0;
@ -235,21 +236,15 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo
} }
// Actually create the texture and set the scaling mode // Actually create the texture and set the scaling mode
glBindTexture(GL_TEXTURE_2D, ti.textureID); CHECK_INIT_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID));
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glBindTexture", err); CHECK_INIT_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, format, GL_UNSIGNED_BYTE, NULL));
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, format, GL_UNSIGNED_BYTE, NULL);
wxLogDebug("VideoOutGL::InitTextures: Using texture size: %dx%d\n", w, h); wxLogDebug("VideoOutGL::InitTextures: Using texture size: %dx%d\n", w, h);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glTexImage2D", err); CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glTexParameteri(GL_TEXTURE_MIN_FILTER)", err);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glTexParameteri(GL_TEXTURE_MAG_FILTER)", err);
GLint mode = supportsGlClampToEdge ? GL_CLAMP_TO_EDGE : GL_CLAMP; GLint mode = supportsGlClampToEdge ? GL_CLAMP_TO_EDGE : GL_CLAMP;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode); CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode));
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glTexParameteri(GL_TEXTURE_WRAP_S)", err); CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glTexParameteri(GL_TEXTURE_WRAP_T)", err);
destX += ti.destW; destX += ti.destW;
sourceX += ti.sourceW; sourceX += ti.sourceW;
@ -270,26 +265,21 @@ void VideoOutGL::UploadFrameData(const AegiVideoFrame& frame) {
InitTextures(frame.w, frame.h, format, frame.GetBpp(0), frame.flipped); InitTextures(frame.w, frame.h, format, frame.GetBpp(0), frame.flipped);
// Set the row length, needed to be able to upload partial rows // Set the row length, needed to be able to upload partial rows
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.w); CHECK_ERROR(glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.w));
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glPixelStorei(GL_UNPACK_ROW_LENGTH, FrameWidth)", err);
for (unsigned i = 0; i < textureList.size(); i++) { for (unsigned i = 0; i < textureList.size(); i++) {
TextureInfo& ti = textureList[i]; TextureInfo& ti = textureList[i];
glBindTexture(GL_TEXTURE_2D, ti.textureID); CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID));
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glBindTexture", err); CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ti.sourceW,
ti.sourceH, format, GL_UNSIGNED_BYTE, frame.data[0] + ti.dataOffset));
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ti.sourceW, ti.sourceH, format, GL_UNSIGNED_BYTE, frame.data[0] + ti.dataOffset);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glTexSubImage2D", err);
} }
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); CHECK_ERROR(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glPixelStorei(GL_UNPACK_ROW_LENGTH, default)", err);
} }
void VideoOutGL::Render(int sw, int sh) { void VideoOutGL::Render(int sw, int sh) {
glEnable(GL_TEXTURE_2D); CHECK_ERROR(glEnable(GL_TEXTURE_2D));
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glEnable(GL_TEXTURE_2d)", err);
for (unsigned i = 0; i < textureList.size(); i++) { for (unsigned i = 0; i < textureList.size(); i++) {
TextureInfo& ti = textureList[i]; TextureInfo& ti = textureList[i];
@ -299,11 +289,8 @@ void VideoOutGL::Render(int sw, int sh) {
float destY = ti.destY * sh; float destY = ti.destY * sh;
float destH = ti.destH * sh; float destH = ti.destH * sh;
glBindTexture(GL_TEXTURE_2D, ti.textureID); CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID));
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glBindTexture", err); CHECK_ERROR(glColor4f(1.0f, 1.0f, 1.0f, 1.0f));
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glColor4f", err);
glBegin(GL_QUADS); glBegin(GL_QUADS);
glTexCoord2f(ti.texLeft, ti.texTop); glVertex2f(destX, destY); glTexCoord2f(ti.texLeft, ti.texTop); glVertex2f(destX, destY);
@ -311,10 +298,9 @@ void VideoOutGL::Render(int sw, int sh) {
glTexCoord2f(ti.texRight, ti.texBottom); glVertex2f(destX + destW, destY + destH); glTexCoord2f(ti.texRight, ti.texBottom); glVertex2f(destX + destW, destY + destH);
glTexCoord2f(ti.texLeft, ti.texBottom); glVertex2f(destX, destY + destH); glTexCoord2f(ti.texLeft, ti.texBottom); glVertex2f(destX, destY + destH);
glEnd(); glEnd();
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"GL_QUADS", err); if (GLenum err = glGetError()) throw VideoOutRenderException(L"GL_QUADS", err);
} }
glDisable(GL_TEXTURE_2D); CHECK_ERROR(glDisable(GL_TEXTURE_2D));
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glDisable(GL_TEXTURE_2d)", err);
} }
VideoOutGL::~VideoOutGL() { VideoOutGL::~VideoOutGL() {

View file

@ -102,22 +102,26 @@ public:
/// @brief Base class for all exceptions thrown by VideoOutGL /// @brief Base class for all exceptions thrown by VideoOutGL
DEFINE_BASE_EXCEPTION_NOINNER(VideoOutException, Aegisub::Exception) DEFINE_BASE_EXCEPTION_NOINNER(VideoOutException, Aegisub::Exception)
/// @class VideoOutUnsupportedException /// @class VideoOutRenderException
/// @extends VideoOutException /// @extends VideoOutException
/// @brief The user's video card does not support OpenGL to any usable extent /// @brief An OpenGL error occured while uploading or displaying a frame
DEFINE_SIMPLE_EXCEPTION_NOINNER(VideoOutUnsupportedException, VideoOutException, "videoout/unsupported") class VideoOutRenderException : public VideoOutException {
/// @class VideoOutOpenGLException
/// @extends VideoOutException
/// @brief An OpenGL error occured.
///
/// Unlike VideoOutUnsupportedException, these errors are likely to be video-specific
/// and/or due to an Aegisub bug.
class VideoOutOpenGLException : public VideoOutException {
public: public:
VideoOutOpenGLException(const wxChar *func, int err) VideoOutRenderException(const wxChar *func, int err)
: VideoOutException(wxString::Format("%s failed with error code %d", func, err)) : VideoOutException(wxString::Format("%s failed with error code %d", func, err))
{ } { }
const wxChar * GetName() const { return L"videoout/opengl"; } const wxChar * GetName() const { return L"videoout/opengl/render"; }
Exception * Copy() const { return new VideoOutOpenGLException(*this); } Exception * Copy() const { return new VideoOutRenderException(*this); }
};
/// @class VideoOutOpenGLException
/// @extends VideoOutException
/// @brief An OpenGL error occured while setting up the video display
class VideoOutInitException : public VideoOutException {
public:
VideoOutInitException(const wxChar *func, int err)
: VideoOutException(wxString::Format("%s failed with error code %d", func, err))
{ }
VideoOutInitException(const wxChar *err) : VideoOutException(err) { }
const wxChar * GetName() const { return L"videoout/opengl/init"; }
Exception * Copy() const { return new VideoOutInitException(*this); }
}; };