\r
namespace caspar {\r
\r
+struct ffmpeg_error : virtual caspar_exception{};\r
+\r
static std::string av_error_str(int errn)\r
{\r
char buf[256];\r
return std::string(buf);\r
}\r
\r
+#define THROW_ON_ERROR(ret, source, func) \\r
+ if(ret < 0) \\r
+ { \\r
+ BOOST_THROW_EXCEPTION( \\r
+ ffmpeg_error() << \\r
+ msg_info(av_error_str(ret)) << \\r
+ source_info(narrow(source)) << \\r
+ boost::errinfo_api_function(func) << \\r
+ boost::errinfo_errno(AVUNERROR(ret))); \\r
+ }\r
+\r
+#define THROW_ON_ERROR_STR_(call) #call\r
+#define THROW_ON_ERROR_STR(call) THROW_ON_ERROR_STR_(call)\r
+\r
+#define THROW_ON_ERROR2(call, source) \\r
+ [&]() -> int \\r
+ { \\r
+ int ret = call; \\r
+ if(ret < 0) \\r
+ { \\r
+ BOOST_THROW_EXCEPTION( \\r
+ ffmpeg_error() << \\r
+ msg_info(av_error_str(ret)) << \\r
+ source_info(narrow(source)) << \\r
+ boost::errinfo_api_function(THROW_ON_ERROR_STR(call)) << \\r
+ boost::errinfo_errno(AVUNERROR(ret))); \\r
+ } \\r
+ return ret; \\r
+ }();\r
+\r
}
\ No newline at end of file
try\r
{\r
AVCodec* dec;\r
- index_ = av_find_best_stream(context.get(), AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0);\r
+ index_ = THROW_ON_ERROR2(av_find_best_stream(context.get(), AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0), "[audio_decoder]");\r
\r
- if(index_ < 0)\r
- {\r
- BOOST_THROW_EXCEPTION(\r
- file_read_error() <<\r
- msg_info(av_error_str(index_)) <<\r
- boost::errinfo_api_function("av_find_best_stream") <<\r
- boost::errinfo_errno(AVUNERROR(index_)));\r
- }\r
-\r
- const int ret = avcodec_open(context->streams[index_]->codec, dec);\r
- if(ret < 0)\r
- { \r
- BOOST_THROW_EXCEPTION(\r
- file_read_error() <<\r
- msg_info(av_error_str(ret)) <<\r
- boost::errinfo_api_function("avcodec_open") <<\r
- boost::errinfo_errno(AVUNERROR(ret)));\r
- }\r
+ THROW_ON_ERROR2(avcodec_open(context->streams[index_]->codec, dec), "[audio_decoder]");\r
}\r
catch(...)\r
{\r
buffer1_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2, 0);\r
int written_bytes = buffer1_.size() - FF_INPUT_BUFFER_PADDING_SIZE;\r
\r
- const int ret = avcodec_decode_audio3(codec_context_.get(), reinterpret_cast<int16_t*>(buffer1_.data()), &written_bytes, &pkt);\r
- if(ret < 0)\r
- { \r
- BOOST_THROW_EXCEPTION(\r
- invalid_operation() <<\r
- msg_info(av_error_str(ret)) <<\r
- boost::errinfo_api_function("avcodec_decode_audio2") <<\r
- boost::errinfo_errno(AVUNERROR(ret)));\r
- }\r
+ int ret = THROW_ON_ERROR2(avcodec_decode_audio3(codec_context_.get(), reinterpret_cast<int16_t*>(buffer1_.data()), &written_bytes, &pkt), "[audio_decoder]");\r
\r
// There might be several frames in one packet.\r
pkt.size -= ret;\r
\r
void push(const std::shared_ptr<AVFrame>& frame)\r
{ \r
- int errn = 0; \r
\r
if(!graph_)\r
{\r
// Input\r
std::stringstream args;\r
args << frame->width << ":" << frame->height << ":" << frame->format << ":" << 0 << ":" << 0 << ":" << 0 << ":" << 0; // don't care about pts and aspect_ratio\r
- errn = avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("buffer"), "src", args.str().c_str(), NULL, graph_.get());\r
- if(errn < 0)\r
- {\r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<\r
- boost::errinfo_api_function("avfilter_graph_create_filter") << boost::errinfo_errno(AVUNERROR(errn)));\r
- }\r
+ THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("buffer"), "src", args.str().c_str(), NULL, graph_.get()), "[filter]");\r
\r
// OPIX_FMT_BGRAutput\r
- errn = avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, pix_fmts, graph_.get());\r
- if(errn < 0)\r
- {\r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<\r
- boost::errinfo_api_function("avfilter_graph_create_filter") << boost::errinfo_errno(AVUNERROR(errn)));\r
- }\r
+ THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, pix_fmts, graph_.get()), "[filter]");\r
\r
AVFilterInOut* outputs = avfilter_inout_alloc();\r
AVFilterInOut* inputs = avfilter_inout_alloc();\r
inputs->pad_idx = 0;\r
inputs->next = NULL;\r
\r
- errn = avfilter_graph_parse(graph_.get(), filters_.c_str(), &inputs, &outputs, NULL);\r
+ int ret = avfilter_graph_parse(graph_.get(), filters_.c_str(), &inputs, &outputs, NULL);\r
\r
avfilter_inout_free(&inputs);\r
avfilter_inout_free(&outputs);\r
-\r
- if(errn < 0)\r
- {\r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<\r
- boost::errinfo_api_function("avfilter_graph_parse") << boost::errinfo_errno(AVUNERROR(errn)));\r
- }\r
\r
- errn = avfilter_graph_config(graph_.get(), NULL);\r
- if(errn < 0)\r
- {\r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) \r
- << boost::errinfo_api_function("avfilter_graph_config") << boost::errinfo_errno(AVUNERROR(errn)));\r
- }\r
+ THROW_ON_ERROR(ret, "[filter]", "avfilter_graph_parse");\r
+ \r
+ THROW_ON_ERROR2(avfilter_graph_config(graph_.get(), NULL), "[filter]");\r
\r
for(size_t n = 0; n < graph_->filter_count; ++n)\r
{\r
}\r
}\r
\r
- errn = av_vsrc_buffer_add_frame(buffersrc_ctx_, frame.get(), 0);\r
- if(errn < 0)\r
- {\r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) <<\r
- boost::errinfo_api_function("av_vsrc_buffer_add_frame") << boost::errinfo_errno(AVUNERROR(errn)));\r
- }\r
+ THROW_ON_ERROR2(av_vsrc_buffer_add_frame(buffersrc_ctx_, frame.get(), 0), "[filter]");\r
}\r
\r
std::vector<safe_ptr<AVFrame>> poll()\r
while (avfilter_poll_frame(buffersink_ctx_->inputs[0])) \r
{\r
AVFilterBufferRef *picref;\r
- av_vsink_buffer_get_video_buffer_ref(buffersink_ctx_, &picref, 0);\r
+ THROW_ON_ERROR2(av_vsink_buffer_get_video_buffer_ref(buffersink_ctx_, &picref, 0), "[filter]");\r
+\r
if (picref) \r
{ \r
safe_ptr<AVFrame> frame(avcodec_alloc_frame(), [=](AVFrame* p)\r
\r
decltype(org_yadif_filter_line) func = nullptr;\r
if(!parallel_line_func_pool.try_pop(func)) \r
- CASPAR_LOG(warning) << "Not enough scalable-yadif instances. Running non-scalable";\r
+ CASPAR_LOG(warning) << "Not enough scalable-yadif context instances. Running non-scalable";\r
else\r
yadif->filter_line = func;\r
\r
, start_(std::max(start, 0))\r
{ \r
is_running_ = true;\r
-\r
- int ret;\r
-\r
+ \r
AVFormatContext* weak_format_context_ = nullptr;\r
- ret = avformat_open_input(&weak_format_context_, narrow(filename).c_str(), nullptr, nullptr);\r
- if(ret < 0 || weak_format_context_ == nullptr)\r
- { \r
- BOOST_THROW_EXCEPTION(\r
- file_read_error() << \r
- source_info(narrow(print())) << \r
- msg_info(av_error_str(ret)) <<\r
- boost::errinfo_api_function("av_open_input_file") <<\r
- boost::errinfo_errno(AVUNERROR(ret)) <<\r
- boost::errinfo_file_name(narrow(filename)));\r
- }\r
+ THROW_ON_ERROR2(avformat_open_input(&weak_format_context_, narrow(filename).c_str(), nullptr, nullptr), print());\r
\r
format_context_.reset(weak_format_context_, av_close_input_file);\r
\r
- ret = avformat_find_stream_info(format_context_.get(), nullptr);\r
- if(ret < 0)\r
- { \r
- BOOST_THROW_EXCEPTION(\r
- file_read_error() << \r
- source_info(narrow(print())) << \r
- msg_info(av_error_str(ret)) <<\r
- boost::errinfo_api_function("av_find_stream_info") <<\r
- boost::errinfo_errno(AVUNERROR(ret)));\r
- }\r
+ THROW_ON_ERROR2(avformat_find_stream_info(format_context_.get(), nullptr), print());\r
\r
if(start_ != 0) \r
seek_frame(start_);\r
}\r
\r
void read_next_packet()\r
- { \r
+ { \r
+ int ret = 0;\r
+\r
std::shared_ptr<AVPacket> read_packet(new AVPacket, [](AVPacket* p)\r
{\r
av_free_packet(p);\r
});\r
av_init_packet(read_packet.get());\r
\r
- const int ret = av_read_frame(format_context_.get(), read_packet.get()); // read_packet is only valid until next call of av_read_frame.\r
- if(is_eof(ret)) // Use av_dup_packet to extend its life.\r
+ ret = av_read_frame(format_context_.get(), read_packet.get()); // read_packet is only valid until next call of av_read_frame. Use av_dup_packet to extend its life. \r
+ \r
+ if(is_eof(ret)) \r
{\r
if(loop_)\r
{\r
CASPAR_LOG(trace) << print() << " Received EOF. Stopping.";\r
}\r
}\r
- else if(ret < 0)\r
- {\r
- BOOST_THROW_EXCEPTION(\r
- file_read_error() <<\r
- msg_info(av_error_str(ret)) <<\r
- source_info(narrow(print())) << \r
- boost::errinfo_api_function("av_read_frame") <<\r
- boost::errinfo_errno(AVUNERROR(ret)));\r
- }\r
else\r
{ \r
- const int ret = av_dup_packet(read_packet.get());\r
- if(ret < 0)\r
- {\r
- BOOST_THROW_EXCEPTION(\r
- invalid_operation() <<\r
- msg_info(av_error_str(ret)) <<\r
- source_info(narrow(print())) << \r
- boost::errinfo_api_function("av_dup_packet") <<\r
- boost::errinfo_errno(AVUNERROR(ret)));\r
- }\r
+ THROW_ON_ERROR(ret, print(), "av_read_frame");\r
+\r
+ THROW_ON_ERROR2(av_dup_packet(read_packet.get()), print());\r
\r
// Make sure that the packet is correctly deallocated even if size and data is modified during decoding.\r
auto size = read_packet->size;\r
static const AVRational base_q = {1, AV_TIME_BASE};\r
\r
int stream_index = av_find_default_stream_index(format_context_.get());\r
- \r
- if(stream_index < 0)\r
- { \r
- BOOST_THROW_EXCEPTION(\r
- invalid_operation() << \r
- source_info(narrow(print())) << \r
- msg_info(av_error_str(stream_index)) <<\r
- boost::errinfo_api_function("av_find_default_stream_index") <<\r
- boost::errinfo_errno(AVUNERROR(stream_index)));\r
- }\r
+ THROW_ON_ERROR(stream_index, print(), "av_find_default_stream_index");\r
\r
const int ret = av_seek_frame(format_context_.get(), stream_index, frame, flags);\r
- if(ret < 0)\r
- { \r
- BOOST_THROW_EXCEPTION(\r
- invalid_operation() << \r
- source_info(narrow(print())) << \r
- msg_info(av_error_str(ret)) <<\r
- boost::errinfo_api_function("av_seek_frame") <<\r
- boost::errinfo_errno(AVUNERROR(ret)));\r
- }\r
-\r
+ THROW_ON_ERROR(ret, print(), "av_seek_frame");\r
+ \r
buffer_.push(nullptr);\r
} \r
\r
try\r
{\r
AVCodec* dec;\r
- index_ = av_find_best_stream(context.get(), AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);\r
-\r
- if(index_ < 0)\r
- {\r
- BOOST_THROW_EXCEPTION(\r
- file_read_error() <<\r
- msg_info(av_error_str(index_)) <<\r
- boost::errinfo_api_function("av_find_best_stream") <<\r
- boost::errinfo_errno(AVUNERROR(index_)));\r
- }\r
-\r
- const int ret = tbb_avcodec_open(context->streams[index_]->codec, dec);\r
- if(ret < 0)\r
- { \r
- BOOST_THROW_EXCEPTION(\r
- file_read_error() <<\r
- msg_info(av_error_str(ret)) <<\r
- boost::errinfo_api_function("tbb_avcodec_open") <<\r
- boost::errinfo_errno(AVUNERROR(ret)));\r
- }\r
+ index_ = THROW_ON_ERROR2(av_find_best_stream(context.get(), AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0), "[video_decoder]");\r
+ \r
+ THROW_ON_ERROR2(tbb_avcodec_open(context->streams[index_]->codec, dec), "[video_decoder]");\r
}\r
catch(...)\r
{\r
std::shared_ptr<AVFrame> decoded_frame(avcodec_alloc_frame(), av_free);\r
\r
int frame_finished = 0;\r
- const int ret = avcodec_decode_video2(codec_context_.get(), decoded_frame.get(), &frame_finished, &pkt);\r
- \r
- if(ret < 0)\r
- {\r
- BOOST_THROW_EXCEPTION(\r
- invalid_operation() <<\r
- msg_info(av_error_str(ret)) <<\r
- boost::errinfo_api_function("avcodec_decode_video") <<\r
- boost::errinfo_errno(AVUNERROR(ret)));\r
- }\r
+ THROW_ON_ERROR2(avcodec_decode_video2(codec_context_.get(), decoded_frame.get(), &frame_finished, &pkt), "[video_decocer]");\r
\r
- // if a decoder consumes less then the whole packet then something is wrong\r
- // that might be just harmless padding at the end or a problem with the\r
- // AVParser or demuxer which puted more then one frame in a AVPacket\r
+ // If a decoder consumes less then the whole packet then something is wrong\r
+ // that might be just harmless padding at the end, or a problem with the\r
+ // AVParser or demuxer which puted more then one frame in a AVPacket.\r
pkt.data = nullptr;\r
pkt.size = 0;\r
\r