diff --git a/aegisub/src/video_context.cpp b/aegisub/src/video_context.cpp index 59f2056db..cdcf72d62 100644 --- a/aegisub/src/video_context.cpp +++ b/aegisub/src/video_context.cpp @@ -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); } diff --git a/aegisub/src/video_display.cpp b/aegisub/src/video_display.cpp index a0ed718ce..3bba27b74 100644 --- a/aegisub/src/video_display.cpp +++ b/aegisub/src/video_display.cpp @@ -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(); } diff --git a/aegisub/src/video_out_gl.cpp b/aegisub/src/video_out_gl.cpp index 780c82c2a..094563b6a 100644 --- a/aegisub/src/video_out_gl.cpp +++ b/aegisub/src/video_out_gl.cpp @@ -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() { diff --git a/aegisub/src/video_out_gl.h b/aegisub/src/video_out_gl.h index d180c325e..d7b7c539c 100644 --- a/aegisub/src/video_out_gl.h +++ b/aegisub/src/video_out_gl.h @@ -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); } };