diff options
| author | Carl Hetherington <cth@carlh.net> | 2022-10-18 20:26:05 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2022-10-18 20:26:05 +0200 |
| commit | 94eff17bdb94c170d456c7dab5ad3d4c00af4b14 (patch) | |
| tree | 54281a554d800b49c149a69fe037035f903498ad /src/lib | |
| parent | 053bf81d7ef24843cc2eea62e24c2296fed48950 (diff) | |
| parent | c9a1e2040bf5600aeafdefe56a3bf46e15419a16 (diff) | |
Hopefully fix colour of Rec.2020 sources in the preview.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/ffmpeg_decoder.cc | 32 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.h | 4 | ||||
| -rw-r--r-- | src/lib/image.cc | 2 | ||||
| -rw-r--r-- | src/lib/raw_image_proxy.cc | 7 | ||||
| -rw-r--r-- | src/lib/raw_image_proxy.h | 4 | ||||
| -rw-r--r-- | src/lib/video_filter_graph.cc | 48 | ||||
| -rw-r--r-- | src/lib/video_filter_graph.h | 3 | ||||
| -rw-r--r-- | src/lib/video_filter_graph_set.cc | 62 | ||||
| -rw-r--r-- | src/lib/video_filter_graph_set.h | 61 | ||||
| -rw-r--r-- | src/lib/wscript | 1 |
10 files changed, 188 insertions, 36 deletions
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index a5b36d04f..27b7aa7b7 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -77,6 +77,7 @@ using namespace dcpomatic; FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> film, shared_ptr<const FFmpegContent> c, bool fast) : FFmpeg (c) , Decoder (film) + , _filter_graphs(c->filters(), dcp::Fraction(lrint(_ffmpeg_content->video_frame_rate().get_value_or(24) * 1000), 1000)) { if (c->video && c->video->use()) { video = make_shared<VideoDecoder>(this, c); @@ -401,13 +402,10 @@ FFmpegDecoder::seek (ContentTime time, bool accurate) AVSEEK_FLAG_BACKWARD ); - { - /* Force re-creation of filter graphs to reset them and hence to make sure - they don't have any pre-seek frames knocking about. - */ - boost::mutex::scoped_lock lm (_filter_graphs_mutex); - _filter_graphs.clear (); - } + /* Force re-creation of filter graphs to reset them and hence to make sure + they don't have any pre-seek frames knocking about. + */ + _filter_graphs.clear(); if (video_codec_context ()) { avcodec_flush_buffers (video_codec_context()); @@ -580,25 +578,7 @@ FFmpegDecoder::decode_and_process_video_packet (AVPacket* packet) void FFmpegDecoder::process_video_frame () { - boost::mutex::scoped_lock lm (_filter_graphs_mutex); - - shared_ptr<VideoFilterGraph> graph; - - auto i = _filter_graphs.begin(); - while (i != _filter_graphs.end() && !(*i)->can_process(dcp::Size(_video_frame->width, _video_frame->height), (AVPixelFormat) _video_frame->format)) { - ++i; - } - - if (i == _filter_graphs.end ()) { - dcp::Fraction vfr (lrint(_ffmpeg_content->video_frame_rate().get() * 1000), 1000); - graph = make_shared<VideoFilterGraph>(dcp::Size(_video_frame->width, _video_frame->height), (AVPixelFormat) _video_frame->format, vfr); - graph->setup (_ffmpeg_content->filters ()); - _filter_graphs.push_back (graph); - LOG_GENERAL (N_("New graph for %1x%2, pixel format %3"), _video_frame->width, _video_frame->height, _video_frame->format); - } else { - graph = *i; - } - + auto graph = _filter_graphs.get(dcp::Size(_video_frame->width, _video_frame->height), static_cast<AVPixelFormat>(_video_frame->format)); auto images = graph->process (_video_frame); for (auto const& i: images) { diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index e1a023453..9de44333c 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -27,6 +27,7 @@ #include "bitmap_text.h" #include "decoder.h" #include "ffmpeg.h" +#include "video_filter_graph_set.h" #include "util.h" extern "C" { #include <libavcodec/avcodec.h> @@ -76,8 +77,7 @@ private: void maybe_add_subtitle (); - std::list<std::shared_ptr<VideoFilterGraph>> _filter_graphs; - boost::mutex _filter_graphs_mutex; + VideoFilterGraphSet _filter_graphs; dcpomatic::ContentTime _pts_offset; boost::optional<dcpomatic::ContentTime> _current_subtitle_to; diff --git a/src/lib/image.cc b/src/lib/image.cc index 2ac84e26c..d84755df3 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -240,6 +240,7 @@ Image::crop_scale_window ( EnumIndexedVector<int, dcp::YUVToRGB> lut; lut[dcp::YUVToRGB::REC601] = SWS_CS_ITU601; lut[dcp::YUVToRGB::REC709] = SWS_CS_ITU709; + lut[dcp::YUVToRGB::REC2020] = SWS_CS_BT2020; /* The 3rd parameter here is: 0 -> source range MPEG (i.e. "video", 16-235) @@ -350,6 +351,7 @@ Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_fo EnumIndexedVector<int, dcp::YUVToRGB> lut; lut[dcp::YUVToRGB::REC601] = SWS_CS_ITU601; lut[dcp::YUVToRGB::REC709] = SWS_CS_ITU709; + lut[dcp::YUVToRGB::REC2020] = SWS_CS_BT2020; /* The 3rd parameter here is: 0 -> source range MPEG (i.e. "video", 16-235) diff --git a/src/lib/raw_image_proxy.cc b/src/lib/raw_image_proxy.cc index 9b486dd5c..c606ddd99 100644 --- a/src/lib/raw_image_proxy.cc +++ b/src/lib/raw_image_proxy.cc @@ -45,7 +45,7 @@ using boost::optional; using dcp::raw_convert; -RawImageProxy::RawImageProxy (shared_ptr<Image> image) +RawImageProxy::RawImageProxy(shared_ptr<const Image> image) : _image (image) { @@ -58,8 +58,9 @@ RawImageProxy::RawImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> soc xml->number_child<int>("Width"), xml->number_child<int>("Height") ); - _image = make_shared<Image>(static_cast<AVPixelFormat>(xml->number_child<int>("PixelFormat")), size, Image::Alignment::PADDED); - _image->read_from_socket (socket); + auto image = make_shared<Image>(static_cast<AVPixelFormat>(xml->number_child<int>("PixelFormat")), size, Image::Alignment::PADDED); + image->read_from_socket (socket); + _image = image; } diff --git a/src/lib/raw_image_proxy.h b/src/lib/raw_image_proxy.h index 1111b66c0..d5ae2457d 100644 --- a/src/lib/raw_image_proxy.h +++ b/src/lib/raw_image_proxy.h @@ -29,7 +29,7 @@ class RawImageProxy : public ImageProxy { public: - explicit RawImageProxy (std::shared_ptr<Image>); + explicit RawImageProxy(std::shared_ptr<const Image>); RawImageProxy (std::shared_ptr<cxml::Node> xml, std::shared_ptr<Socket> socket); Result image ( @@ -43,7 +43,7 @@ public: size_t memory_used () const override; private: - std::shared_ptr<Image> _image; + std::shared_ptr<const Image> _image; }; diff --git a/src/lib/video_filter_graph.cc b/src/lib/video_filter_graph.cc index 1cc142520..26f858437 100644 --- a/src/lib/video_filter_graph.cc +++ b/src/lib/video_filter_graph.cc @@ -21,6 +21,7 @@ #include "compose.hpp" #include "image.h" +#include "scope_guard.h" #include "video_filter_graph.h" extern "C" { #include <libavfilter/buffersrc.h> @@ -48,13 +49,56 @@ VideoFilterGraph::VideoFilterGraph (dcp::Size s, AVPixelFormat p, dcp::Fraction } +list<shared_ptr<const Image>> +VideoFilterGraph::process(shared_ptr<const Image> image) +{ + if (_copy) { + return { image }; + } + + auto frame = av_frame_alloc(); + if (!frame) { + throw std::bad_alloc(); + } + + ScopeGuard sg = [&frame]() { av_frame_free(&frame); }; + + for (int i = 0; i < image->planes(); ++i) { + frame->data[i] = image->data()[i]; + frame->linesize[i] = image->stride()[i]; + } + + frame->width = image->size().width; + frame->height = image->size().height; + frame->format = image->pixel_format(); + + int r = av_buffersrc_write_frame(_buffer_src_context, frame); + if (r < 0) { + throw DecodeError(String::compose(N_("could not push buffer into filter chain (%1)."), r)); + } + + list<shared_ptr<const Image>> images; + + while (true) { + if (av_buffersink_get_frame(_buffer_sink_context, _frame) < 0) { + break; + } + + images.push_back(make_shared<Image>(_frame, Image::Alignment::PADDED)); + av_frame_unref (_frame); + } + + return images; +} + + /** Take an AVFrame and process it using our configured filters, returning a * set of Images. Caller handles memory management of the input frame. */ -list<pair<shared_ptr<Image>, int64_t>> +list<pair<shared_ptr<const Image>, int64_t>> VideoFilterGraph::process (AVFrame* frame) { - list<pair<shared_ptr<Image>, int64_t>> images; + list<pair<shared_ptr<const Image>, int64_t>> images; if (_copy) { images.push_back (make_pair(make_shared<Image>(frame, Image::Alignment::PADDED), frame->best_effort_timestamp)); diff --git a/src/lib/video_filter_graph.h b/src/lib/video_filter_graph.h index d887e551b..1fb322282 100644 --- a/src/lib/video_filter_graph.h +++ b/src/lib/video_filter_graph.h @@ -28,7 +28,8 @@ public: VideoFilterGraph (dcp::Size s, AVPixelFormat p, dcp::Fraction r); bool can_process (dcp::Size s, AVPixelFormat p) const; - std::list<std::pair<std::shared_ptr<Image>, int64_t>> process (AVFrame * frame); + std::list<std::pair<std::shared_ptr<const Image>, int64_t>> process (AVFrame * frame); + std::list<std::shared_ptr<const Image>> process(std::shared_ptr<const Image> image); protected: std::string src_parameters () const override; diff --git a/src/lib/video_filter_graph_set.cc b/src/lib/video_filter_graph_set.cc new file mode 100644 index 000000000..dbae17d4c --- /dev/null +++ b/src/lib/video_filter_graph_set.cc @@ -0,0 +1,62 @@ +/* + Copyright (C) 2022 Carl Hetherington <cth@carlh.net> + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>. + +*/ + + +#include "dcpomatic_log.h" +#include "video_filter_graph.h" +#include "video_filter_graph_set.h" + +#include "i18n.h" + + +using std::make_shared; +using std::shared_ptr; + + +shared_ptr<VideoFilterGraph> +VideoFilterGraphSet::get(dcp::Size size, AVPixelFormat format) +{ + auto graph = std::find_if( + _graphs.begin(), + _graphs.end(), + [size, format](shared_ptr<VideoFilterGraph> g) { + return g->can_process(size, format); + }); + + if (graph != _graphs.end()) { + return *graph; + } + + auto new_graph = make_shared<VideoFilterGraph>(size, format, _frame_rate); + new_graph->setup(_filters); + _graphs.push_back(new_graph); + + LOG_GENERAL(N_("New graph for %1x%2, pixel format %3"), size.width, size.height, static_cast<int>(format)); + + return new_graph; +} + + +void +VideoFilterGraphSet::clear() +{ + _graphs.clear(); +} + diff --git a/src/lib/video_filter_graph_set.h b/src/lib/video_filter_graph_set.h new file mode 100644 index 000000000..935378432 --- /dev/null +++ b/src/lib/video_filter_graph_set.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2022 Carl Hetherington <cth@carlh.net> + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>. + +*/ + + +#ifndef DCPOMATIC_VIDEO_FILTER_GRAPH_SET_H +#define DCPOMATIC_VIDEO_FILTER_GRAPH_SET_H + + +#include <dcp/types.h> +extern "C" { +#include <libavutil/avutil.h> +} +#include <memory> +#include <vector> + + +class Filter; +class VideoFilterGraph; + + +class VideoFilterGraphSet +{ +public: + VideoFilterGraphSet(std::vector<Filter const*> filters, dcp::Fraction frame_rate) + : _filters(filters) + , _frame_rate(frame_rate) + {} + + VideoFilterGraphSet(VideoFilterGraphSet const&) = delete; + VideoFilterGraphSet& operator=(VideoFilterGraphSet const&) = delete; + + std::shared_ptr<VideoFilterGraph> get(dcp::Size size, AVPixelFormat format); + + void clear(); + +private: + std::vector<Filter const*> _filters; + dcp::Fraction _frame_rate; + std::vector<std::shared_ptr<VideoFilterGraph>> _graphs; +}; + + +#endif + diff --git a/src/lib/wscript b/src/lib/wscript index 55c4e735f..26fcb21e5 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -194,6 +194,7 @@ sources = """ video_content.cc video_decoder.cc video_filter_graph.cc + video_filter_graph_set.cc video_mxf_content.cc video_mxf_decoder.cc video_mxf_examiner.cc |
