X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fproducer%2Ffilter%2Ffilter.cpp;h=aa83cf36662584a583fd758a55b3850c03d0a53b;hb=726897adbf881d3b75f171fff24f2b917ba5f05a;hp=dac2eef3dfbe4438524af646176a3afa7fb50ab3;hpb=40ee6eeb1cc1486ba665c05ec256b8196952c73e;p=casparcg diff --git a/modules/ffmpeg/producer/filter/filter.cpp b/modules/ffmpeg/producer/filter/filter.cpp index dac2eef3d..aa83cf366 100644 --- a/modules/ffmpeg/producer/filter/filter.cpp +++ b/modules/ffmpeg/producer/filter/filter.cpp @@ -19,11 +19,13 @@ * Author: Robert Nagy, ronag89@gmail.com */ -#include "../../stdafx.h" +#include "../../StdAfx.h" #include "filter.h" #include "../../ffmpeg_error.h" +#include "../../ffmpeg.h" +#include "../util/util.h" #include #include @@ -36,19 +38,19 @@ #include #include #include +#include #if defined(_MSC_VER) #pragma warning (push) #pragma warning (disable : 4244) #endif -extern "C" +extern "C" { #include #include #include #include #include - #include #include #include } @@ -57,15 +59,16 @@ extern "C" #endif namespace caspar { namespace ffmpeg { - struct filter::implementation { - std::string filtergraph_; + std::string filtergraph_; + + std::shared_ptr video_graph_; + AVFilterContext* video_graph_in_; + AVFilterContext* video_graph_out_; + + std::queue> fast_path_; - std::shared_ptr video_graph_; - AVFilterContext* video_graph_in_; - AVFilterContext* video_graph_out_; - implementation( int in_width, int in_height, @@ -74,7 +77,8 @@ struct filter::implementation boost::rational in_sample_aspect_ratio, AVPixelFormat in_pix_fmt, std::vector out_pix_fmts, - const std::string& filtergraph) + const std::string& filtergraph, + bool multithreaded) : filtergraph_(boost::to_lower_copy(filtergraph)) { if(out_pix_fmts.empty()) @@ -96,147 +100,160 @@ struct filter::implementation out_pix_fmts.push_back(AV_PIX_FMT_NONE); video_graph_.reset( - avfilter_graph_alloc(), + avfilter_graph_alloc(), [](AVFilterGraph* p) { avfilter_graph_free(&p); }); - - video_graph_->nb_threads = boost::thread::hardware_concurrency(); - video_graph_->thread_type = AVFILTER_THREAD_SLICE; - + + if (multithreaded) + { + video_graph_->nb_threads = 0; + video_graph_->thread_type = AVFILTER_THREAD_SLICE; + } + else + { + video_graph_->nb_threads = 1; + } + const auto vsrc_options = (boost::format("video_size=%1%x%2%:pix_fmt=%3%:time_base=%4%/%5%:pixel_aspect=%6%/%7%:frame_rate=%8%/%9%") % in_width % in_height % in_pix_fmt % in_time_base.numerator() % in_time_base.denominator() % in_sample_aspect_ratio.numerator() % in_sample_aspect_ratio.denominator() % in_frame_rate.numerator() % in_frame_rate.denominator()).str(); - - AVFilterContext* filt_vsrc = nullptr; + + AVFilterContext* filt_vsrc = nullptr; FF(avfilter_graph_create_filter( &filt_vsrc, - avfilter_get_by_name("buffer"), + avfilter_get_by_name("buffer"), "filter_buffer", - vsrc_options.c_str(), - nullptr, + vsrc_options.c_str(), + nullptr, video_graph_.get())); - + AVFilterContext* filt_vsink = nullptr; FF(avfilter_graph_create_filter( &filt_vsink, - avfilter_get_by_name("buffersink"), + avfilter_get_by_name("buffersink"), "filter_buffersink", - nullptr, - nullptr, + nullptr, + nullptr, video_graph_.get())); - + #pragma warning (push) #pragma warning (disable : 4245) FF(av_opt_set_int_list( - filt_vsink, - "pix_fmts", - out_pix_fmts.data(), + filt_vsink, + "pix_fmts", + out_pix_fmts.data(), -1, AV_OPT_SEARCH_CHILDREN)); #pragma warning (pop) - + configure_filtergraph( - *video_graph_, + *video_graph_, filtergraph_, *filt_vsrc, *filt_vsink); video_graph_in_ = filt_vsrc; video_graph_out_ = filt_vsink; - - CASPAR_LOG(info) - << u16(std::string("\n") - + avfilter_graph_dump( - video_graph_.get(), - nullptr)); + + if (is_logging_quiet_for_thread()) + CASPAR_LOG(trace) + << u16(std::string("\n") + + avfilter_graph_dump( + video_graph_.get(), + nullptr)); + else + CASPAR_LOG(debug) + << u16(std::string("\n") + + avfilter_graph_dump( + video_graph_.get(), + nullptr)); } - + void configure_filtergraph( - AVFilterGraph& graph, - const std::string& filtergraph, - AVFilterContext& source_ctx, + AVFilterGraph& graph, + const std::string& filtergraph, + AVFilterContext& source_ctx, AVFilterContext& sink_ctx) { - AVFilterInOut* outputs = nullptr; - AVFilterInOut* inputs = nullptr; - - try + if (!filtergraph.empty()) { - if(!filtergraph.empty()) - { - outputs = avfilter_inout_alloc(); - inputs = avfilter_inout_alloc(); - - CASPAR_VERIFY(outputs && inputs); - - outputs->name = av_strdup("in"); - outputs->filter_ctx = &source_ctx; - outputs->pad_idx = 0; - outputs->next = nullptr; - - inputs->name = av_strdup("out"); - inputs->filter_ctx = &sink_ctx; - inputs->pad_idx = 0; - inputs->next = nullptr; - - FF(avfilter_graph_parse( - &graph, - filtergraph.c_str(), - &inputs, - &outputs, - nullptr)); - } - else - { - FF(avfilter_link( - &source_ctx, - 0, - &sink_ctx, - 0)); - } + auto outputs = avfilter_inout_alloc(); + auto inputs = avfilter_inout_alloc(); + + CASPAR_VERIFY(outputs && inputs); - FF(avfilter_graph_config( - &graph, - nullptr)); + outputs->name = av_strdup("in"); + outputs->filter_ctx = &source_ctx; + outputs->pad_idx = 0; + outputs->next = nullptr; + + inputs->name = av_strdup("out"); + inputs->filter_ctx = &sink_ctx; + inputs->pad_idx = 0; + inputs->next = nullptr; + + FF(avfilter_graph_parse( + &graph, + filtergraph.c_str(), + inputs, + outputs, + nullptr)); } - catch(...) + else { - avfilter_inout_free(&outputs); - avfilter_inout_free(&inputs); - throw; + FF(avfilter_link( + &source_ctx, + 0, + &sink_ctx, + 0)); } + + FF(avfilter_graph_config(&graph, nullptr)); + } + + bool fast_path() const + { + return filtergraph_.empty(); } void push(const std::shared_ptr& src_av_frame) - { - FF(av_buffersrc_add_frame( - video_graph_in_, - src_av_frame.get())); + { + if (fast_path()) + fast_path_.push(src_av_frame); + else + FF(av_buffersrc_add_frame( + video_graph_in_, + src_av_frame.get())); } std::shared_ptr poll() { - std::shared_ptr filt_frame( - av_frame_alloc(), - [](AVFrame* p) - { - av_frame_free(&p); - }); - + if (fast_path()) + { + if (fast_path_.empty()) + return nullptr; + + auto result = fast_path_.front(); + fast_path_.pop(); + return result; + } + + auto filt_frame = create_frame(); + const auto ret = av_buffersink_get_frame( - video_graph_out_, + video_graph_out_, filt_frame.get()); - + if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) return nullptr; - + FF_RET(ret, "poll"); return filt_frame; @@ -251,8 +268,9 @@ filter::filter( boost::rational in_sample_aspect_ratio, AVPixelFormat in_pix_fmt, std::vector out_pix_fmts, - const std::string& filtergraph) - : impl_(new implementation( + const std::string& filtergraph, + bool multithreaded) + : impl_(new implementation( in_width, in_height, in_time_base, @@ -260,18 +278,18 @@ filter::filter( in_sample_aspect_ratio, in_pix_fmt, out_pix_fmts, - filtergraph)){} + filtergraph, + multithreaded)){} filter::filter(filter&& other) : impl_(std::move(other.impl_)){} filter& filter::operator=(filter&& other){impl_ = std::move(other.impl_); return *this;} void filter::push(const std::shared_ptr& frame){impl_->push(frame);} std::shared_ptr filter::poll(){return impl_->poll();} std::wstring filter::filter_str() const{return u16(impl_->filtergraph_);} std::vector> filter::poll_all() -{ +{ std::vector> frames; for(auto frame = poll(); frame; frame = poll()) frames.push_back(spl::make_shared_ptr(frame)); return frames; } - -}} \ No newline at end of file +}}