#include <common/exception/exceptions.h>\r
\r
#include <boost/assign.hpp>\r
+#include <boost/range/iterator_range.hpp>\r
+#include <boost/range/adaptors.hpp>\r
+#include <boost/assign.hpp>\r
+#include <boost/algorithm/string.hpp>\r
+#include <boost/foreach.hpp>\r
\r
#include <cstdio>\r
#include <sstream>\r
#pragma warning (pop)\r
#endif\r
\r
+\r
namespace caspar { namespace ffmpeg {\r
\r
static int query_formats_444(AVFilterContext *ctx)\r
return 0;\r
}\r
\r
+static int query_formats_420a(AVFilterContext *ctx)\r
+{\r
+ static const int pix_fmts[] = {PIX_FMT_YUVA420P, PIX_FMT_NONE};\r
+ avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));\r
+ return 0;\r
+}\r
+\r
static int query_formats_411(AVFilterContext *ctx)\r
{\r
static const int pix_fmts[] = {PIX_FMT_YUV411P, PIX_FMT_NONE};\r
\r
struct filter::implementation\r
{\r
- std::string filters_;\r
+ std::wstring filters_;\r
std::shared_ptr<AVFilterGraph> graph_; \r
AVFilterContext* buffersink_ctx_;\r
AVFilterContext* buffersrc_ctx_;\r
std::queue<safe_ptr<AVFrame>> bypass_;\r
\r
implementation(const std::wstring& filters, const std::vector<PixelFormat>& pix_fmts) \r
- : filters_(narrow(filters))\r
+ : filters_(filters)\r
, parallel_yadif_ctx_(nullptr)\r
, pix_fmts_(pix_fmts)\r
{\r
if(pix_fmts_.empty())\r
{\r
- pix_fmts_.push_back(PIX_FMT_YUVA420P);\r
- pix_fmts_.push_back(PIX_FMT_YUV444P);\r
- pix_fmts_.push_back(PIX_FMT_YUV422P);\r
- pix_fmts_.push_back(PIX_FMT_YUV420P);\r
- pix_fmts_.push_back(PIX_FMT_YUV411P);\r
- pix_fmts_.push_back(PIX_FMT_BGRA);\r
- pix_fmts_.push_back(PIX_FMT_ARGB);\r
- pix_fmts_.push_back(PIX_FMT_RGBA);\r
- pix_fmts_.push_back(PIX_FMT_ABGR);\r
- pix_fmts_.push_back(PIX_FMT_GRAY8);\r
- pix_fmts_.push_back(PIX_FMT_NONE);\r
+ pix_fmts_ = boost::assign::list_of\r
+ (PIX_FMT_YUVA420P)\r
+ (PIX_FMT_YUV444P)\r
+ (PIX_FMT_YUV422P)\r
+ (PIX_FMT_YUV420P)\r
+ (PIX_FMT_YUV411P)\r
+ (PIX_FMT_BGRA)\r
+ (PIX_FMT_ARGB)\r
+ (PIX_FMT_RGBA)\r
+ (PIX_FMT_ABGR)\r
+ (PIX_FMT_GRAY8);\r
}\r
- else\r
- pix_fmts_.push_back(PIX_FMT_NONE);\r
-\r
- std::transform(filters_.begin(), filters_.end(), filters_.begin(), ::tolower);\r
+ \r
+ pix_fmts_.push_back(PIX_FMT_NONE);\r
}\r
\r
void push(const std::shared_ptr<AVFrame>& frame)\r
buffersink_params->pixel_fmts = pix_fmts_.data();\r
THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, buffersink_params.get(), graph_.get()), "[filter]");\r
#endif\r
- AVFilterInOut* outputs = avfilter_inout_alloc();\r
AVFilterInOut* inputs = avfilter_inout_alloc();\r
- \r
+ AVFilterInOut* outputs = avfilter_inout_alloc();\r
+ \r
outputs->name = av_strdup("in");\r
outputs->filter_ctx = buffersrc_ctx_;\r
outputs->pad_idx = 0;\r
- outputs->next = NULL;\r
+ outputs->next = nullptr;\r
\r
inputs->name = av_strdup("out");\r
inputs->filter_ctx = buffersink_ctx_;\r
inputs->pad_idx = 0;\r
- inputs->next = NULL;\r
+ inputs->next = nullptr;\r
\r
- THROW_ON_ERROR2(avfilter_graph_parse(graph_.get(), filters_.c_str(), &inputs, &outputs, NULL), "[filter]");\r
+ std::string filters = boost::to_lower_copy(narrow(filters_));\r
+ THROW_ON_ERROR2(avfilter_graph_parse(graph_.get(), filters.c_str(), &inputs, &outputs, NULL), "[filter]");\r
\r
- for(size_t n = 0; n < graph_->filter_count; ++n)\r
- {\r
- auto filter_name = graph_->filters[n]->name;\r
- if(strstr(filter_name, "yadif") != 0)\r
- {\r
- if(frame->format == PIX_FMT_UYVY422)\r
- graph_->filters[n]->filter->query_formats = query_formats_422;\r
- if(frame->format == PIX_FMT_YUYV422)\r
- graph_->filters[n]->filter->query_formats = query_formats_422;\r
- if(frame->format == PIX_FMT_UYYVYY411)\r
- graph_->filters[n]->filter->query_formats = query_formats_411;\r
- else if(frame->format == PIX_FMT_YUV420P10)\r
- graph_->filters[n]->filter->query_formats = query_formats_420;\r
- else if(frame->format == PIX_FMT_YUV422P10)\r
- graph_->filters[n]->filter->query_formats = query_formats_422;\r
- else if(frame->format == PIX_FMT_YUV444P10)\r
- graph_->filters[n]->filter->query_formats = query_formats_444;\r
- }\r
- }\r
-\r
- avfilter_inout_free(&inputs);\r
- avfilter_inout_free(&outputs);\r
-\r
- THROW_ON_ERROR2(avfilter_graph_config(graph_.get(), NULL), "[filter]"); \r
+ auto yadif_filter = boost::adaptors::filtered([&](AVFilterContext* p){return strstr(p->name, "yadif") != 0;});\r
\r
- for(size_t n = 0; n < graph_->filter_count; ++n)\r
+ BOOST_FOREACH(auto filter_ctx, boost::make_iterator_range(graph_->filters, graph_->filters + graph_->filter_count) | yadif_filter)\r
{\r
- auto filter_name = graph_->filters[n]->name;\r
- if(strstr(filter_name, "yadif") != 0) \r
- parallel_yadif_ctx_ = make_parallel_yadif(graph_->filters[n]); \r
+ filter_ctx->filter->query_formats = [&]() -> int (*)(AVFilterContext*)\r
+ {\r
+ switch(frame->format)\r
+ {\r
+ case PIX_FMT_UYVY422: return query_formats_422;\r
+ case PIX_FMT_YUYV422: return query_formats_422;\r
+ case PIX_FMT_UYYVYY411: return query_formats_411;\r
+ case PIX_FMT_YUV420P10: return query_formats_420;\r
+ case PIX_FMT_YUV422P10: return query_formats_422;\r
+ case PIX_FMT_YUV444P10: return query_formats_444;\r
+ case PIX_FMT_YUV420P9: return query_formats_420;\r
+ case PIX_FMT_YUV422P9: return query_formats_422;\r
+ case PIX_FMT_YUV444P9: return query_formats_444;\r
+ case PIX_FMT_BGR24: return query_formats_444;\r
+ case PIX_FMT_RGB24: return query_formats_444;\r
+ case PIX_FMT_BGRA: return query_formats_420a;\r
+ case PIX_FMT_RGBA: return query_formats_420a;\r
+ case PIX_FMT_ABGR: return query_formats_420a;\r
+ case PIX_FMT_ARGB: return query_formats_420a;\r
+ default: return filter_ctx->filter->query_formats;\r
+ }\r
+ }();\r
}\r
+ \r
+ THROW_ON_ERROR2(avfilter_graph_config(graph_.get(), NULL), "[filter]"); \r
+ \r
+ BOOST_FOREACH(auto filter_ctx, boost::make_iterator_range(graph_->filters, graph_->filters + graph_->filter_count) | yadif_filter) \r
+ parallel_yadif_ctx_ = make_parallel_yadif(filter_ctx); \r
}\r
catch(...)\r
{\r
AVFilterBufferRef *picref;\r
THROW_ON_ERROR2(av_buffersink_get_buffer_ref(buffersink_ctx_, &picref, 0), "[filter]");\r
\r
- if (picref) \r
- { \r
- safe_ptr<AVFrame> frame(avcodec_alloc_frame(), [=](AVFrame* p)\r
- {\r
- av_free(p);\r
- avfilter_unref_buffer(picref);\r
- });\r
+ if (!picref) \r
+ return nullptr;\r
+ \r
+ safe_ptr<AVFrame> frame(avcodec_alloc_frame(), [=](AVFrame* p)\r
+ {\r
+ av_free(p);\r
+ avfilter_unref_buffer(picref);\r
+ });\r
\r
- avcodec_get_frame_defaults(frame.get()); \r
+ avcodec_get_frame_defaults(frame.get()); \r
\r
- memcpy(frame->data, picref->data, sizeof(frame->data));\r
- memcpy(frame->linesize, picref->linesize, sizeof(frame->linesize));\r
- frame->format = picref->format;\r
- frame->width = picref->video->w;\r
- frame->height = picref->video->h;\r
- frame->pkt_pos = picref->pos;\r
- frame->interlaced_frame = picref->video->interlaced;\r
- frame->top_field_first = picref->video->top_field_first;\r
- frame->key_frame = picref->video->key_frame;\r
- frame->pict_type = picref->video->pict_type;\r
- frame->sample_aspect_ratio = picref->video->sample_aspect_ratio;\r
+ memcpy(frame->data, picref->data, sizeof(frame->data));\r
+ memcpy(frame->linesize, picref->linesize, sizeof(frame->linesize));\r
+ frame->format = picref->format;\r
+ frame->width = picref->video->w;\r
+ frame->height = picref->video->h;\r
+ frame->pkt_pos = picref->pos;\r
+ frame->interlaced_frame = picref->video->interlaced;\r
+ frame->top_field_first = picref->video->top_field_first;\r
+ frame->key_frame = picref->video->key_frame;\r
+ frame->pict_type = picref->video->pict_type;\r
+ frame->sample_aspect_ratio = picref->video->sample_aspect_ratio;\r
\r
- return frame;\r
- }\r
+ return frame; \r
}\r
+\r
+ return nullptr;\r
}\r
catch(ffmpeg_error&)\r
{\r
{\r
BOOST_THROW_EXCEPTION(ffmpeg_error() << boost::errinfo_nested_exception(boost::current_exception()));\r
}\r
-\r
- return nullptr;\r
}\r
};\r
\r
filter& filter::operator=(filter&& other){impl_ = std::move(other.impl_); return *this;}\r
void filter::push(const std::shared_ptr<AVFrame>& frame){impl_->push(frame);}\r
std::shared_ptr<AVFrame> filter::poll(){return impl_->poll();}\r
-std::wstring filter::filter_str() const{return widen(impl_->filters_);}\r
+std::wstring filter::filter_str() const{return impl_->filters_;}\r
std::vector<safe_ptr<AVFrame>> filter::poll_all()\r
{ \r
std::vector<safe_ptr<AVFrame>> frames;\r