forked from mia/Aegisub
Improve video operation errors somewhat. Updates #1020.
Originally committed to SVN as r3835.
This commit is contained in:
parent
dadd09ff49
commit
86f64b2962
4 changed files with 80 additions and 90 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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); }
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue