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
///
void VideoContext::Reset() {
loaded = false;
StandardPaths::SetPathValue(_T("?video"),_T(""));
KeyFrames.Clear();
@ -164,7 +165,6 @@ void VideoContext::Reset() {
}
// Remove video data
loaded = false;
frame_n = 0;
length = 0;
fps = 0;
@ -221,7 +221,6 @@ void VideoContext::SetVideo(const wxString &filename) {
// Choose a provider
provider = VideoProviderFactoryManager::GetProvider(filename);
loaded = provider != NULL;
// Get subtitles provider
try {
@ -356,31 +355,14 @@ void VideoContext::JumpToFrame(int n) {
// Prevent intervention during playback
if (isPlaying && n != playNextFrame) return;
try {
// Set frame number
frame_n = n;
// Set frame number
frame_n = n;
// Display
UpdateDisplays(false);
// Display
UpdateDisplays(false);
// Update grid
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();
}
// Update grid
if (!isPlaying && Options.AsBool(_T("Highlight subs in frame"))) grid->Refresh(false);
}

View File

@ -195,8 +195,37 @@ void VideoDisplay::SetFrame(int frameNumber) {
// Render the new frame
if (context->IsLoaded()) {
AegiVideoFrame frame = context->GetFrame(frameNumber);
videoOut->UploadFrameData(frame);
AegiVideoFrame 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();
@ -289,18 +318,9 @@ void VideoDisplay::Render() try {
glFinish();
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) {
wxLogError(
_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")
wxLogError(
_T("An error occurred trying to render the video frame on the screen.\n")
_T("Error message reported: %s"),
err.GetMessage());
VideoContext::Get()->Reset();
@ -308,7 +328,6 @@ catch (const VideoOutException &err) {
catch (const wxChar *err) {
wxLogError(
_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"),
err);
VideoContext::Get()->Reset();
@ -316,7 +335,6 @@ catch (const wxChar *err) {
catch (...) {
wxLogError(
_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."));
VideoContext::Get()->Reset();
}

View File

@ -58,6 +58,9 @@
#define GL_CLAMP_TO_EDGE 0x812F
#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 {
/// @brief Structure tracking all precomputable information about a subtexture
struct TextureInfo {
@ -122,7 +125,7 @@ void VideoOutGL::DetectOpenGLCapabilities() {
// Test for supported internalformats
if (TestTexture(64, 64, GL_RGBA8)) internalFormat = GL_RGBA8;
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
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
if (textureIdList.size() > 0) {
glDeleteTextures(textureIdList.size(), &textureIdList[0]);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glDeleteTextures", err);
CHECK_INIT_ERROR(glDeleteTextures(textureIdList.size(), &textureIdList[0]));
textureIdList.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);
textureIdList.resize(textureRows * textureCols);
textureList.resize(textureRows * textureCols);
glGenTextures(textureIdList.size(), &textureIdList[0]);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glGenTextures", err);
CHECK_INIT_ERROR(glGenTextures(textureIdList.size(), &textureIdList[0]));
// Calculate the position information for each texture
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
glBindTexture(GL_TEXTURE_2D, ti.textureID);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glBindTexture", err);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, format, GL_UNSIGNED_BYTE, NULL);
CHECK_INIT_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID));
CHECK_INIT_ERROR(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);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glTexImage2D", err);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GLint mode = supportsGlClampToEdge ? GL_CLAMP_TO_EDGE : GL_CLAMP;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glTexParameteri(GL_TEXTURE_WRAP_S)", err);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glTexParameteri(GL_TEXTURE_WRAP_T)", err);
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode));
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode));
destX += ti.destW;
sourceX += ti.sourceW;
@ -270,26 +265,21 @@ void VideoOutGL::UploadFrameData(const AegiVideoFrame& frame) {
InitTextures(frame.w, frame.h, format, frame.GetBpp(0), frame.flipped);
// Set the row length, needed to be able to upload partial rows
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.w);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glPixelStorei(GL_UNPACK_ROW_LENGTH, FrameWidth)", err);
CHECK_ERROR(glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.w));
for (unsigned i = 0; i < textureList.size(); i++) {
TextureInfo& ti = textureList[i];
glBindTexture(GL_TEXTURE_2D, ti.textureID);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glBindTexture", err);
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);
CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID));
CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ti.sourceW,
ti.sourceH, format, GL_UNSIGNED_BYTE, frame.data[0] + ti.dataOffset));
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glPixelStorei(GL_UNPACK_ROW_LENGTH, default)", err);
CHECK_ERROR(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
}
void VideoOutGL::Render(int sw, int sh) {
glEnable(GL_TEXTURE_2D);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glEnable(GL_TEXTURE_2d)", err);
CHECK_ERROR(glEnable(GL_TEXTURE_2D));
for (unsigned i = 0; i < textureList.size(); i++) {
TextureInfo& ti = textureList[i];
@ -299,11 +289,8 @@ void VideoOutGL::Render(int sw, int sh) {
float destY = ti.destY * sh;
float destH = ti.destH * sh;
glBindTexture(GL_TEXTURE_2D, ti.textureID);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glBindTexture", err);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glColor4f", err);
CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID));
CHECK_ERROR(glColor4f(1.0f, 1.0f, 1.0f, 1.0f));
glBegin(GL_QUADS);
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.texLeft, ti.texBottom); glVertex2f(destX, destY + destH);
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);
if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glDisable(GL_TEXTURE_2d)", err);
CHECK_ERROR(glDisable(GL_TEXTURE_2D));
}
VideoOutGL::~VideoOutGL() {

View File

@ -102,22 +102,26 @@ public:
/// @brief Base class for all exceptions thrown by VideoOutGL
DEFINE_BASE_EXCEPTION_NOINNER(VideoOutException, Aegisub::Exception)
/// @class VideoOutUnsupportedException
/// @class VideoOutRenderException
/// @extends VideoOutException
/// @brief The user's video card does not support OpenGL to any usable extent
DEFINE_SIMPLE_EXCEPTION_NOINNER(VideoOutUnsupportedException, VideoOutException, "videoout/unsupported")
/// @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 {
/// @brief An OpenGL error occured while uploading or displaying a frame
class VideoOutRenderException : public VideoOutException {
public:
VideoOutOpenGLException(const wxChar *func, int err)
VideoOutRenderException(const wxChar *func, int err)
: VideoOutException(wxString::Format("%s failed with error code %d", func, err))
{ }
const wxChar * GetName() const { return L"videoout/opengl"; }
Exception * Copy() const { return new VideoOutOpenGLException(*this); }
const wxChar * GetName() const { return L"videoout/opengl/render"; }
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); }
};