mirror of https://github.com/odrling/Aegisub
Improve video operation errors somewhat. Updates #1020.
Originally committed to SVN as r3835.
This commit is contained in:
parent
dadd09ff49
commit
86f64b2962
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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); }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue