X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fproducer%2Ffilter%2Ffilter.cpp;h=0b6b38d54ff1894becb962dc12c0edf6bfafdf03;hb=ca4193194e570781a824519791fa7cbdee032946;hp=9a5d26688c49fa825c40cb21ccc70a532d61270e;hpb=4adbd499aa7106aa49b58a4b62afc7f0cfdb6c80;p=casparcg diff --git a/modules/ffmpeg/producer/filter/filter.cpp b/modules/ffmpeg/producer/filter/filter.cpp index 9a5d26688..0b6b38d54 100644 --- a/modules/ffmpeg/producer/filter/filter.cpp +++ b/modules/ffmpeg/producer/filter/filter.cpp @@ -2,32 +2,34 @@ #include "filter.h" -#include "../../ffmpeg_error.h" +#include "parallel_yadif.h" -#include -#include -#include -#include +#include "../../ffmpeg_error.h" -#include +#include #include #include +#if defined(_MSC_VER) +#pragma warning (push) +#pragma warning (disable : 4244) +#endif extern "C" { - #define __STDC_CONSTANT_MACROS - #define __STDC_LIMIT_MACROS #include #include #include #include #include - #include + #include #include } +#if defined(_MSC_VER) +#pragma warning (pop) +#endif -namespace caspar { +namespace caspar { namespace ffmpeg { struct filter::implementation { @@ -35,17 +37,47 @@ struct filter::implementation std::shared_ptr graph_; AVFilterContext* buffersink_ctx_; AVFilterContext* buffersrc_ctx_; - - implementation(const std::wstring& filters) + std::shared_ptr parallel_yadif_ctx_; + std::vector pix_fmts_; + + implementation(const std::wstring& filters, const std::vector& pix_fmts) : filters_(narrow(filters)) + , parallel_yadif_ctx_(nullptr) + , pix_fmts_(pix_fmts) { + if(pix_fmts_.empty()) + { + pix_fmts_.push_back(PIX_FMT_YUV420P); + pix_fmts_.push_back(PIX_FMT_YUVA420P); + pix_fmts_.push_back(PIX_FMT_YUV422P); + pix_fmts_.push_back(PIX_FMT_YUV444P); + pix_fmts_.push_back(PIX_FMT_YUV411P); + pix_fmts_.push_back(PIX_FMT_ARGB); + pix_fmts_.push_back(PIX_FMT_RGBA); + pix_fmts_.push_back(PIX_FMT_ABGR); + pix_fmts_.push_back(PIX_FMT_GRAY8); + pix_fmts_.push_back(PIX_FMT_NONE); + } + else + pix_fmts_.push_back(PIX_FMT_NONE); + std::transform(filters_.begin(), filters_.end(), filters_.begin(), ::tolower); } + + std::vector> execute(const std::shared_ptr& frame) + { + if(!frame) + return std::vector>(); - void push(const safe_ptr& frame) - { - int errn = 0; + if(filters_.empty()) + return boost::assign::list_of(frame); + + push(frame); + return poll(); + } + void push(const std::shared_ptr& frame) + { if(!graph_) { graph_.reset(avfilter_graph_alloc(), [](AVFilterGraph* p){avfilter_graph_free(&p);}); @@ -53,26 +85,16 @@ struct filter::implementation // Input std::stringstream args; args << frame->width << ":" << frame->height << ":" << frame->format << ":" << 0 << ":" << 0 << ":" << 0 << ":" << 0; // don't care about pts and aspect_ratio - errn = avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("buffer"), "src", args.str().c_str(), NULL, graph_.get()); - if(errn < 0) - { - BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) << - boost::errinfo_api_function("avfilter_graph_create_filter") << boost::errinfo_errno(AVUNERROR(errn))); - } + THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("buffer"), "src", args.str().c_str(), NULL, graph_.get()), "[filter]"); - PixelFormat pix_fmts[] = { PIX_FMT_BGRA, PIX_FMT_NONE }; - - // Output - errn = avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, pix_fmts, graph_.get()); - if(errn < 0) - { - BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) << - boost::errinfo_api_function("avfilter_graph_create_filter") << boost::errinfo_errno(AVUNERROR(errn))); - } + // OPIX_FMT_BGRAutput + AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc(); + buffersink_params->pixel_fmts = pix_fmts_.data(); + THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, buffersink_params, graph_.get()), "[filter]"); AVFilterInOut* outputs = avfilter_inout_alloc(); AVFilterInOut* inputs = avfilter_inout_alloc(); - + outputs->name = av_strdup("in"); outputs->filter_ctx = buffersrc_ctx_; outputs->pad_idx = 0; @@ -83,27 +105,22 @@ struct filter::implementation inputs->pad_idx = 0; inputs->next = NULL; - errn = avfilter_graph_parse(graph_.get(), filters_.c_str(), &inputs, &outputs, NULL); - if(errn < 0) - { - BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) << - boost::errinfo_api_function("avfilter_graph_parse") << boost::errinfo_errno(AVUNERROR(errn))); - } + THROW_ON_ERROR2(avfilter_graph_parse(graph_.get(), filters_.c_str(), &inputs, &outputs, NULL), "[filter]"); - errn = avfilter_graph_config(graph_.get(), NULL); - if(errn < 0) + avfilter_inout_free(&inputs); + avfilter_inout_free(&outputs); + + THROW_ON_ERROR2(avfilter_graph_config(graph_.get(), NULL), "[filter]"); + + for(size_t n = 0; n < graph_->filter_count; ++n) { - BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) - << boost::errinfo_api_function("avfilter_graph_config") << boost::errinfo_errno(AVUNERROR(errn))); + auto filter_name = graph_->filters[n]->name; + if(strstr(filter_name, "yadif") != 0) + parallel_yadif_ctx_ = make_parallel_yadif(graph_->filters[n]); } } - errn = av_vsrc_buffer_add_frame(buffersrc_ctx_, frame.get(), 0); - if(errn < 0) - { - BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(av_error_str(errn)) << - boost::errinfo_api_function("av_vsrc_buffer_add_frame") << boost::errinfo_errno(AVUNERROR(errn))); - } + THROW_ON_ERROR2(av_vsrc_buffer_add_frame(buffersrc_ctx_, frame.get(), 0), "[filter]"); } std::vector> poll() @@ -116,29 +133,29 @@ struct filter::implementation while (avfilter_poll_frame(buffersink_ctx_->inputs[0])) { AVFilterBufferRef *picref; - av_vsink_buffer_get_video_buffer_ref(buffersink_ctx_, &picref, 0); + THROW_ON_ERROR2(av_buffersink_get_buffer_ref(buffersink_ctx_, &picref, 0), "[filter]"); + if (picref) { safe_ptr frame(avcodec_alloc_frame(), [=](AVFrame* p) { av_free(p); - avfilter_unref_buffer(picref); + avfilter_unref_buffer(picref); }); avcodec_get_frame_defaults(frame.get()); - for(size_t n = 0; n < 4; ++n) - { - frame->data[n] = picref->data[n]; - frame->linesize[n] = picref->linesize[n]; - } - - frame->format = picref->format; - frame->width = picref->video->w; - frame->height = picref->video->h; - frame->interlaced_frame = picref->video->interlaced; - frame->top_field_first = picref->video->top_field_first; - frame->key_frame = picref->video->key_frame; + memcpy(frame->data, picref->data, sizeof(frame->data)); + memcpy(frame->linesize, picref->linesize, sizeof(frame->linesize)); + frame->format = picref->format; + frame->width = picref->video->w; + frame->height = picref->video->h; + frame->pkt_pos = picref->pos; + frame->interlaced_frame = picref->video->interlaced; + frame->top_field_first = picref->video->top_field_first; + frame->key_frame = picref->video->key_frame; + frame->pict_type = picref->video->pict_type; + frame->sample_aspect_ratio = picref->video->sample_aspect_ratio; result.push_back(frame); } @@ -148,7 +165,9 @@ struct filter::implementation } }; -filter::filter(const std::wstring& filters) : impl_(new implementation(filters)){} -void filter::push(const safe_ptr& frame) {impl_->push(frame);} -std::vector> filter::poll() {return impl_->poll();} -} \ No newline at end of file +filter::filter(const std::wstring& filters, const std::vector& pix_fmts) : impl_(new implementation(filters, pix_fmts)){} +filter::filter(filter&& other) : impl_(std::move(other.impl_)){} +filter& filter::operator=(filter&& other){impl_ = std::move(other.impl_); return *this;} +std::vector> filter::execute(const std::shared_ptr& frame) {return impl_->execute(frame);} + +}} \ No newline at end of file