Reduce error-handling bloat a bit

This commit is contained in:
Thomas Goyne 2015-07-28 14:50:01 -07:00
parent b0f4c9f1ad
commit d5dde6cff2
4 changed files with 59 additions and 64 deletions

View file

@ -77,27 +77,7 @@ void push_value(lua_State *L, std::vector<T> const& value) {
} }
} }
inline int exception_wrapper(lua_State *L, int (*func)(lua_State *L)) { 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();
}
}
/// Wrap a function which may throw exceptions and make it trigger lua errors /// Wrap a function which may throw exceptions and make it trigger lua errors
/// whenever it throws /// whenever it throws
template<int (*func)(lua_State *L)> template<int (*func)(lua_State *L)>

View file

@ -213,6 +213,27 @@ void argcheck(lua_State *L, bool cond, int narg, const char *msg) {
if (!cond) argerror(L, narg, 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 #ifdef _DEBUG
void LuaStackcheck::check_stack(int additional) { void LuaStackcheck::check_stack(int additional) {
int top = lua_gettop(L); int top = lua_gettop(L);

View file

@ -35,13 +35,20 @@
#include "utils.h" #include "utils.h"
#include "video_frame.h" #include "video_frame.h"
namespace {
template<typename Exception>
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) \ #define DO_CHECK_ERROR(cmd, Exception, msg) \
do { \ do { \
cmd; \ cmd; \
if (GLenum err = glGetError()) { \ GLenum err = glGetError(); \
LOG_E("video/out/gl") << msg << " failed with error code " << err; \ if (BOOST_UNLIKELY(err)) \
throw Exception(msg, err); \ throw_error<Exception>(err, msg); \
} \
} while(0); } while(0);
#define CHECK_INIT_ERROR(cmd) DO_CHECK_ERROR(cmd, VideoOutInitException, #cmd) #define CHECK_INIT_ERROR(cmd) DO_CHECK_ERROR(cmd, VideoOutInitException, #cmd)
#define CHECK_ERROR(cmd) DO_CHECK_ERROR(cmd, VideoOutRenderException, #cmd) #define CHECK_ERROR(cmd) DO_CHECK_ERROR(cmd, VideoOutRenderException, #cmd)

View file

@ -134,7 +134,6 @@ class YUV4MPEGVideoProvider final : public VideoProvider {
/// each frame header can be found /// each frame header can be found
std::vector<uint64_t> seek_table; std::vector<uint64_t> seek_table;
void CheckFileFormat();
void ParseFileHeader(const std::vector<std::string>& tags); void ParseFileHeader(const std::vector<std::string>& tags);
Y4M_FrameFlags ParseFrameHeader(const std::vector<std::string>& tags); Y4M_FrameFlags ParseFrameHeader(const std::vector<std::string>& tags);
std::vector<std::string> ReadHeader(uint64_t &startpos); std::vector<std::string> ReadHeader(uint64_t &startpos);
@ -162,7 +161,10 @@ public:
YUV4MPEGVideoProvider::YUV4MPEGVideoProvider(agi::fs::path const& filename) YUV4MPEGVideoProvider::YUV4MPEGVideoProvider(agi::fs::path const& filename)
: file(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; uint64_t pos = 0;
ParseFileHeader(ReadHeader(pos)); ParseFileHeader(ReadHeader(pos));
@ -185,10 +187,8 @@ YUV4MPEGVideoProvider::YUV4MPEGVideoProvider(agi::fs::path const& filename)
case Y4M_PIXFMT_420MPEG2: case Y4M_PIXFMT_420MPEG2:
case Y4M_PIXFMT_420PALDV: case Y4M_PIXFMT_420PALDV:
chroma_sz = (w * h) >> 2; break; chroma_sz = (w * h) >> 2; break;
case Y4M_PIXFMT_422:
chroma_sz = (w * h) >> 1; break;
/// @todo add support for more pixel formats
default: default:
/// @todo add support for more pixel formats
throw VideoOpenError("Unsupported pixel format"); throw VideoOpenError("Unsupported pixel format");
} }
frame_sz = luma_sz + chroma_sz*2; 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"); 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 /// @brief Read a frame or file header at a given file position
/// @param startpos The byte offset at where to start reading /// @param startpos The byte offset at where to start reading
/// @return A list of parameters /// @return A list of parameters
@ -266,22 +256,23 @@ void YUV4MPEGVideoProvider::ParseFileHeader(const std::vector<std::string>& tags
char type = tags[i][0]; char type = tags[i][0];
std::string tag = tags[i].substr(1); std::string tag = tags[i].substr(1);
const char *err = nullptr;
if (type == 'W') { if (type == 'W') {
if (!agi::util::try_parse(tag, &t_w)) if (!agi::util::try_parse(tag, &t_w))
throw VideoOpenError("ParseFileHeader: invalid width"); err = "invalid width";
} }
else if (type == 'H') { else if (type == 'H') {
if (!agi::util::try_parse(tag, &t_h)) if (!agi::util::try_parse(tag, &t_h))
throw VideoOpenError("ParseFileHeader: invalid height"); err = "invalid height";
} }
else if (type == 'F') { else if (type == 'F') {
size_t pos = tag.find(':'); size_t pos = tag.find(':');
if (pos == tag.npos) if (pos == tag.npos)
throw VideoOpenError("ParseFileHeader: invalid framerate"); err = "invalid framerate";
if (!agi::util::try_parse(tag.substr(0, pos), &t_fps_num) || if (!agi::util::try_parse(tag.substr(0, pos), &t_fps_num) ||
!agi::util::try_parse(tag.substr(pos + 1), &t_fps_den)) !agi::util::try_parse(tag.substr(pos + 1), &t_fps_den))
throw VideoOpenError("ParseFileHeader: invalid framerate"); err = "invalid framerate";
} }
else if (type == 'C') { else if (type == 'C') {
// technically this should probably be case sensitive, // technically this should probably be case sensitive,
@ -297,7 +288,7 @@ void YUV4MPEGVideoProvider::ParseFileHeader(const std::vector<std::string>& tags
else if (tag == "444alpha") t_pixfmt = Y4M_PIXFMT_444ALPHA; else if (tag == "444alpha") t_pixfmt = Y4M_PIXFMT_444ALPHA;
else if (tag == "mono") t_pixfmt = Y4M_PIXFMT_MONO; else if (tag == "mono") t_pixfmt = Y4M_PIXFMT_MONO;
else else
throw VideoOpenError("ParseFileHeader: invalid or unknown colorspace"); err = "invalid or unknown colorspace";
} }
else if (type == 'I') { else if (type == 'I') {
boost::to_lower(tag); boost::to_lower(tag);
@ -307,10 +298,13 @@ void YUV4MPEGVideoProvider::ParseFileHeader(const std::vector<std::string>& tags
else if (tag == "m") t_imode = Y4M_ILACE_MIXED; else if (tag == "m") t_imode = Y4M_ILACE_MIXED;
else if (tag == "?") t_imode = Y4M_ILACE_UNKNOWN; else if (tag == "?") t_imode = Y4M_ILACE_UNKNOWN;
else else
throw VideoOpenError("ParseFileHeader: invalid or unknown interlacing mode"); err = "invalid or unknown interlacing mode";
} }
else else
LOG_D("provider/video/yuv4mpeg") << "Unparsed tag: " << tags[i]; 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 // 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<std::string>& tags
// header flags. The spec doesn't explicitly say you have to allow this, // 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. // but the "reference implementation" (mjpegtools) does, so I'm doing it too.
if (inited) { if (inited) {
const char *err = nullptr;
if (t_w > 0 && t_w != w) if (t_w > 0 && t_w != w)
throw VideoOpenError("ParseFileHeader: illegal width change"); err = "illegal width change";
if (t_h > 0 && t_h != h) 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)) 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) 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) 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 { else {
w = t_w; w = t_w;
@ -346,12 +343,11 @@ void YUV4MPEGVideoProvider::ParseFileHeader(const std::vector<std::string>& tags
/// @return The flags set, as a binary mask /// @return The flags set, as a binary mask
/// This function is currently unimplemented (it will always return Y4M_FFLAG_NONE). /// This function is currently unimplemented (it will always return Y4M_FFLAG_NONE).
YUV4MPEGVideoProvider::Y4M_FrameFlags YUV4MPEGVideoProvider::ParseFrameHeader(const std::vector<std::string>& tags) { YUV4MPEGVideoProvider::Y4M_FrameFlags YUV4MPEGVideoProvider::ParseFrameHeader(const std::vector<std::string>& tags) {
if (tags.front() != "FRAME") if (tags.front() == "FRAME")
throw VideoOpenError("ParseFrameHeader: malformed frame header (bad magic)"); return Y4M_FFLAG_NONE;
/// @todo implement parsing of frame flags /// @todo implement parsing of frame flags
throw VideoOpenError("ParseFrameHeader: malformed frame header (bad magic)");
return Y4M_FFLAG_NONE;
} }
/// @brief Indexes the file /// @brief Indexes the file
@ -395,15 +391,6 @@ void YUV4MPEGVideoProvider::GetFrame(int n, VideoFrame &frame) {
n = mid(0, n, num_frames - 1); n = mid(0, n, num_frames - 1);
int uv_width = w / 2; 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<const unsigned char *>(file.read(seek_table[n], luma_sz + chroma_sz * 2)); auto src_y = reinterpret_cast<const unsigned char *>(file.read(seek_table[n], luma_sz + chroma_sz * 2));
auto src_u = src_y + luma_sz; auto src_u = src_y + luma_sz;