diff --git a/libaegisub/include/libaegisub/lua/utils.h b/libaegisub/include/libaegisub/lua/utils.h index a7beb8ebc..c5a65d6e4 100644 --- a/libaegisub/include/libaegisub/lua/utils.h +++ b/libaegisub/include/libaegisub/lua/utils.h @@ -77,27 +77,7 @@ void push_value(lua_State *L, std::vector const& value) { } } -inline int exception_wrapper(lua_State *L, int (*func)(lua_State *L)) { - try { - return func(L); - } - catch (agi::Exception const& e) { - push_value(L, e.GetMessage()); - return lua_error(L); - } - catch (std::exception const& e) { - push_value(L, e.what()); - return lua_error(L); - } - catch (error_tag) { - // Error message is already on the stack - return lua_error(L); - } - catch (...) { - std::terminate(); - } -} - +int exception_wrapper(lua_State *L, int (*func)(lua_State *L)); /// Wrap a function which may throw exceptions and make it trigger lua errors /// whenever it throws template diff --git a/libaegisub/lua/utils.cpp b/libaegisub/lua/utils.cpp index 9dd577bfb..2cde75f46 100644 --- a/libaegisub/lua/utils.cpp +++ b/libaegisub/lua/utils.cpp @@ -213,6 +213,27 @@ void argcheck(lua_State *L, bool cond, int narg, const char *msg) { if (!cond) argerror(L, narg, msg); } +int exception_wrapper(lua_State *L, int (*func)(lua_State *L)) { + try { + return func(L); + } + catch (agi::Exception const& e) { + push_value(L, e.GetMessage()); + return lua_error(L); + } + catch (std::exception const& e) { + push_value(L, e.what()); + return lua_error(L); + } + catch (error_tag) { + // Error message is already on the stack + return lua_error(L); + } + catch (...) { + std::terminate(); + } +} + #ifdef _DEBUG void LuaStackcheck::check_stack(int additional) { int top = lua_gettop(L); diff --git a/src/video_out_gl.cpp b/src/video_out_gl.cpp index 3f73361cb..75c6eae6b 100644 --- a/src/video_out_gl.cpp +++ b/src/video_out_gl.cpp @@ -35,13 +35,20 @@ #include "utils.h" #include "video_frame.h" +namespace { +template +BOOST_NOINLINE void throw_error(GLenum err, const char *msg) { + LOG_E("video/out/gl") << msg << " failed with error code " << err; + throw Exception(msg, err); +} +} + #define DO_CHECK_ERROR(cmd, Exception, msg) \ do { \ cmd; \ - if (GLenum err = glGetError()) { \ - LOG_E("video/out/gl") << msg << " failed with error code " << err; \ - throw Exception(msg, err); \ - } \ + GLenum err = glGetError(); \ + if (BOOST_UNLIKELY(err)) \ + throw_error(err, msg); \ } while(0); #define CHECK_INIT_ERROR(cmd) DO_CHECK_ERROR(cmd, VideoOutInitException, #cmd) #define CHECK_ERROR(cmd) DO_CHECK_ERROR(cmd, VideoOutRenderException, #cmd) diff --git a/src/video_provider_yuv4mpeg.cpp b/src/video_provider_yuv4mpeg.cpp index 5f0761483..583cebcec 100644 --- a/src/video_provider_yuv4mpeg.cpp +++ b/src/video_provider_yuv4mpeg.cpp @@ -134,7 +134,6 @@ class YUV4MPEGVideoProvider final : public VideoProvider { /// each frame header can be found std::vector seek_table; - void CheckFileFormat(); void ParseFileHeader(const std::vector& tags); Y4M_FrameFlags ParseFrameHeader(const std::vector& tags); std::vector ReadHeader(uint64_t &startpos); @@ -162,7 +161,10 @@ public: YUV4MPEGVideoProvider::YUV4MPEGVideoProvider(agi::fs::path const& filename) : file(filename) { - CheckFileFormat(); + if (file.size() < 10) + throw VideoNotSupported("File is not a YUV4MPEG file (too small)"); + if (strncmp("YUV4MPEG2 ", file.read(0, 10), 10)) + throw VideoNotSupported("File is not a YUV4MPEG file (bad magic)"); uint64_t pos = 0; ParseFileHeader(ReadHeader(pos)); @@ -185,10 +187,8 @@ YUV4MPEGVideoProvider::YUV4MPEGVideoProvider(agi::fs::path const& filename) case Y4M_PIXFMT_420MPEG2: case Y4M_PIXFMT_420PALDV: chroma_sz = (w * h) >> 2; break; - case Y4M_PIXFMT_422: - chroma_sz = (w * h) >> 1; break; - /// @todo add support for more pixel formats default: + /// @todo add support for more pixel formats throw VideoOpenError("Unsupported pixel format"); } frame_sz = luma_sz + chroma_sz*2; @@ -198,16 +198,6 @@ YUV4MPEGVideoProvider::YUV4MPEGVideoProvider(agi::fs::path const& filename) throw VideoOpenError("Unable to determine file length"); } -/// @brief Checks if the file is an YUV4MPEG file or not -/// Note that it reports the error by throwing an exception, -/// not by returning a false value. -void YUV4MPEGVideoProvider::CheckFileFormat() { - if (file.size() < 10) - throw VideoNotSupported("CheckFileFormat: File is not a YUV4MPEG file (too small)"); - if (strncmp("YUV4MPEG2 ", file.read(0, 10), 10)) - throw VideoNotSupported("CheckFileFormat: File is not a YUV4MPEG file (bad magic)"); -} - /// @brief Read a frame or file header at a given file position /// @param startpos The byte offset at where to start reading /// @return A list of parameters @@ -266,22 +256,23 @@ void YUV4MPEGVideoProvider::ParseFileHeader(const std::vector& tags char type = tags[i][0]; std::string tag = tags[i].substr(1); + const char *err = nullptr; if (type == 'W') { if (!agi::util::try_parse(tag, &t_w)) - throw VideoOpenError("ParseFileHeader: invalid width"); + err = "invalid width"; } else if (type == 'H') { if (!agi::util::try_parse(tag, &t_h)) - throw VideoOpenError("ParseFileHeader: invalid height"); + err = "invalid height"; } else if (type == 'F') { size_t pos = tag.find(':'); if (pos == tag.npos) - throw VideoOpenError("ParseFileHeader: invalid framerate"); + err = "invalid framerate"; if (!agi::util::try_parse(tag.substr(0, pos), &t_fps_num) || !agi::util::try_parse(tag.substr(pos + 1), &t_fps_den)) - throw VideoOpenError("ParseFileHeader: invalid framerate"); + err = "invalid framerate"; } else if (type == 'C') { // technically this should probably be case sensitive, @@ -297,7 +288,7 @@ void YUV4MPEGVideoProvider::ParseFileHeader(const std::vector& tags else if (tag == "444alpha") t_pixfmt = Y4M_PIXFMT_444ALPHA; else if (tag == "mono") t_pixfmt = Y4M_PIXFMT_MONO; else - throw VideoOpenError("ParseFileHeader: invalid or unknown colorspace"); + err = "invalid or unknown colorspace"; } else if (type == 'I') { boost::to_lower(tag); @@ -307,10 +298,13 @@ void YUV4MPEGVideoProvider::ParseFileHeader(const std::vector& tags else if (tag == "m") t_imode = Y4M_ILACE_MIXED; else if (tag == "?") t_imode = Y4M_ILACE_UNKNOWN; else - throw VideoOpenError("ParseFileHeader: invalid or unknown interlacing mode"); + err = "invalid or unknown interlacing mode"; } else LOG_D("provider/video/yuv4mpeg") << "Unparsed tag: " << tags[i]; + + if (err) + throw VideoOpenError(err); } // The point of all this is to allow multiple YUV4MPEG2 headers in a single file @@ -318,16 +312,19 @@ void YUV4MPEGVideoProvider::ParseFileHeader(const std::vector& tags // header flags. The spec doesn't explicitly say you have to allow this, // but the "reference implementation" (mjpegtools) does, so I'm doing it too. if (inited) { + const char *err = nullptr; if (t_w > 0 && t_w != w) - throw VideoOpenError("ParseFileHeader: illegal width change"); + err = "illegal width change"; if (t_h > 0 && t_h != h) - throw VideoOpenError("ParseFileHeader: illegal height change"); + err = "illegal height change"; if ((t_fps_num > 0 && t_fps_den > 0) && (t_fps_num != fps_rat.num || t_fps_den != fps_rat.den)) - throw VideoOpenError("ParseFileHeader: illegal framerate change"); + err = "illegal framerate change"; if (t_pixfmt != Y4M_PIXFMT_NONE && t_pixfmt != pixfmt) - throw VideoOpenError("ParseFileHeader: illegal colorspace change"); + err = "illegal colorspace change"; if (t_imode != Y4M_ILACE_NOTSET && t_imode != imode) - throw VideoOpenError("ParseFileHeader: illegal interlacing mode change"); + err = "illegal interlacing mode change"; + if (err) + throw VideoOpenError(err); } else { w = t_w; @@ -346,12 +343,11 @@ void YUV4MPEGVideoProvider::ParseFileHeader(const std::vector& tags /// @return The flags set, as a binary mask /// This function is currently unimplemented (it will always return Y4M_FFLAG_NONE). YUV4MPEGVideoProvider::Y4M_FrameFlags YUV4MPEGVideoProvider::ParseFrameHeader(const std::vector& tags) { - if (tags.front() != "FRAME") - throw VideoOpenError("ParseFrameHeader: malformed frame header (bad magic)"); + if (tags.front() == "FRAME") + return Y4M_FFLAG_NONE; /// @todo implement parsing of frame flags - - return Y4M_FFLAG_NONE; + throw VideoOpenError("ParseFrameHeader: malformed frame header (bad magic)"); } /// @brief Indexes the file @@ -395,15 +391,6 @@ void YUV4MPEGVideoProvider::GetFrame(int n, VideoFrame &frame) { n = mid(0, n, num_frames - 1); int uv_width = w / 2; - switch (pixfmt) { - case Y4M_PIXFMT_420JPEG: - case Y4M_PIXFMT_420MPEG2: - case Y4M_PIXFMT_420PALDV: - break; - /// @todo add support for more pixel formats - default: - throw VideoNotSupported("YUV4MPEG video provider: GetFrame: Unsupported source colorspace"); - } auto src_y = reinterpret_cast(file.read(seek_table[n], luma_sz + chroma_sz * 2)); auto src_u = src_y + luma_sz;