]> git.sesse.net Git - casparcg/blobdiff - modules/ffmpeg/producer/filter/filter.cpp
[ffmpeg] Ported 2.0.7 ffmpeg producer to 2.1.0 while still keeping the usage of the...
[casparcg] / modules / ffmpeg / producer / filter / filter.cpp
index ac16815e4bb7411a626bae91caa514b8a4ed0669..aa83cf36662584a583fd758a55b3850c03d0a53b 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "../../ffmpeg_error.h"
 #include "../../ffmpeg.h"
+#include "../util/util.h"
 
 #include <common/assert.h>
 #include <common/except.h>
 #include <cstdio>
 #include <sstream>
 #include <string>
+#include <queue>
 
 #if defined(_MSC_VER)
 #pragma warning (push)
 #pragma warning (disable : 4244)
 #endif
-extern "C" 
+extern "C"
 {
        #include <libavutil/avutil.h>
        #include <libavutil/imgutils.h>
@@ -57,15 +59,16 @@ extern "C"
 #endif
 
 namespace caspar { namespace ffmpeg {
-       
 struct filter::implementation
 {
-       std::string                                             filtergraph_;
+       std::string                                                             filtergraph_;
+
+       std::shared_ptr<AVFilterGraph>                  video_graph_;
+    AVFilterContext*                                           video_graph_in_;
+    AVFilterContext*                                           video_graph_out_;
+
+       std::queue<std::shared_ptr<AVFrame>>    fast_path_;
 
-       std::shared_ptr<AVFilterGraph>  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<int> in_sample_aspect_ratio,
                        AVPixelFormat in_pix_fmt,
                        std::vector<AVPixelFormat> 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,148 +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  = 0;
-               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;
-               
-               if (!is_logging_disabled_for_thread())
-                       CASPAR_LOG(info)
-                               <<      u16(std::string("\n") 
+
+               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(), 
+                                                       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();
+                       auto outputs = avfilter_inout_alloc();
+                       auto inputs  = avfilter_inout_alloc();
 
-                               CASPAR_VERIFY(outputs && inputs);
+                       CASPAR_VERIFY(outputs && inputs);
 
-                               outputs->name       = av_strdup("in");
-                               outputs->filter_ctx = &source_ctx;
-                               outputs->pad_idx    = 0;
-                               outputs->next       = 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;
+                       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(), 
+                       FF(avfilter_graph_parse(
+                                       &graph,
+                                       filtergraph.c_str(),
                                        inputs,
                                        outputs,
                                        nullptr));
-                       } 
-                       else 
-                       {
-                               FF(avfilter_link(
-                                       &source_ctx, 
-                                       0, 
-                                       &sink_ctx, 
-                                       0));
-                       }
-
-                       FF(avfilter_graph_config(
-                               &graph, 
-                               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<AVFrame>& 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<AVFrame> poll()
        {
-               std::shared_ptr<AVFrame> 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;
@@ -252,8 +268,9 @@ filter::filter(
                boost::rational<int> in_sample_aspect_ratio,
                AVPixelFormat in_pix_fmt,
                std::vector<AVPixelFormat> 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,
@@ -261,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<AVFrame>& frame){impl_->push(frame);}
 std::shared_ptr<AVFrame> filter::poll(){return impl_->poll();}
 std::wstring filter::filter_str() const{return u16(impl_->filtergraph_);}
 std::vector<spl::shared_ptr<AVFrame>> filter::poll_all()
-{      
+{
        std::vector<spl::shared_ptr<AVFrame>> frames;
        for(auto frame = poll(); frame; frame = poll())
                frames.push_back(spl::make_shared_ptr(frame));
        return frames;
 }
-
 }}