From 1fc8c0c6d045404732497ba70bd2eccfbe4cc6f6 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 19 Mar 2024 16:29:13 +0100 Subject: Rename Encoder -> FilmEncoder, and subclasses. --- src/lib/dcp_decoder.cc | 1 + src/lib/dcp_encoder.cc | 180 ---------------------- src/lib/dcp_encoder.h | 79 ---------- src/lib/dcp_film_encoder.cc | 180 ++++++++++++++++++++++ src/lib/dcp_film_encoder.h | 79 ++++++++++ src/lib/encode_server.cc | 1 + src/lib/encode_server_finder.cc | 1 + src/lib/encoder.cc | 47 ------ src/lib/encoder.h | 71 --------- src/lib/ffmpeg_encoder.cc | 315 -------------------------------------- src/lib/ffmpeg_encoder.h | 98 ------------ src/lib/ffmpeg_file_encoder.cc | 2 +- src/lib/ffmpeg_file_encoder.h | 4 +- src/lib/ffmpeg_film_encoder.cc | 315 ++++++++++++++++++++++++++++++++++++++ src/lib/ffmpeg_film_encoder.h | 98 ++++++++++++ src/lib/film.cc | 2 +- src/lib/film_encoder.cc | 47 ++++++ src/lib/film_encoder.h | 70 +++++++++ src/lib/hints.h | 9 +- src/lib/make_dcp.cc | 4 +- src/lib/reel_writer.h | 1 + src/lib/subtitle_encoder.cc | 204 ------------------------ src/lib/subtitle_encoder.h | 64 -------- src/lib/subtitle_film_encoder.cc | 204 ++++++++++++++++++++++++ src/lib/subtitle_film_encoder.h | 64 ++++++++ src/lib/transcode_job.cc | 8 +- src/lib/transcode_job.h | 6 +- src/lib/wscript | 8 +- src/tools/dcpomatic.cc | 8 +- src/tools/dcpomatic_cli.cc | 4 +- src/tools/dcpomatic_combiner.cc | 1 + src/tools/dcpomatic_editor.cc | 1 + src/tools/dcpomatic_kdm.cc | 1 + src/wx/config_dialog.cc | 1 + src/wx/dcp_timeline.h | 2 + src/wx/export_video_file_dialog.h | 2 +- src/wx/film_viewer.h | 2 + src/wx/kdm_cpl_panel.cc | 1 + src/wx/timeline_content_view.cc | 1 + 39 files changed, 1101 insertions(+), 1085 deletions(-) delete mode 100644 src/lib/dcp_encoder.cc delete mode 100644 src/lib/dcp_encoder.h create mode 100644 src/lib/dcp_film_encoder.cc create mode 100644 src/lib/dcp_film_encoder.h delete mode 100644 src/lib/encoder.cc delete mode 100644 src/lib/encoder.h delete mode 100644 src/lib/ffmpeg_encoder.cc delete mode 100644 src/lib/ffmpeg_encoder.h create mode 100644 src/lib/ffmpeg_film_encoder.cc create mode 100644 src/lib/ffmpeg_film_encoder.h create mode 100644 src/lib/film_encoder.cc create mode 100644 src/lib/film_encoder.h delete mode 100644 src/lib/subtitle_encoder.cc delete mode 100644 src/lib/subtitle_encoder.h create mode 100644 src/lib/subtitle_film_encoder.cc create mode 100644 src/lib/subtitle_film_encoder.h (limited to 'src') diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc index d473476a0..ce471202f 100644 --- a/src/lib/dcp_decoder.cc +++ b/src/lib/dcp_decoder.cc @@ -32,6 +32,7 @@ #include "image.h" #include "j2k_image_proxy.h" #include "text_decoder.h" +#include "util.h" #include "video_decoder.h" #include #include diff --git a/src/lib/dcp_encoder.cc b/src/lib/dcp_encoder.cc deleted file mode 100644 index bd78312fa..000000000 --- a/src/lib/dcp_encoder.cc +++ /dev/null @@ -1,180 +0,0 @@ -/* - Copyright (C) 2012-2020 Carl Hetherington - - 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 . - -*/ - - -/** @file src/dcp_encoder.cc - * @brief A class which takes a Film and some Options, then uses those to encode the film into a DCP. - * - * A decoder is selected according to the content type, and the encoder can be specified - * as a parameter to the constructor. - */ - - -#include "audio_decoder.h" -#include "compose.hpp" -#include "dcp_encoder.h" -#include "film.h" -#include "j2k_encoder.h" -#include "job.h" -#include "player.h" -#include "player_video.h" -#include "referenced_reel_asset.h" -#include "text_content.h" -#include "video_decoder.h" -#include "writer.h" -#include -#include - -#include "i18n.h" - - -using std::cout; -using std::dynamic_pointer_cast; -using std::list; -using std::make_shared; -using std::shared_ptr; -using std::string; -using std::vector; -using std::weak_ptr; -using boost::optional; -#if BOOST_VERSION >= 106100 -using namespace boost::placeholders; -#endif -using namespace dcpomatic; - - -/** Construct a DCP encoder. - * @param film Film that we are encoding. - * @param job Job that this encoder is being used in. - */ -DCPEncoder::DCPEncoder (shared_ptr film, weak_ptr job) - : Encoder (film, job) - , _writer(film, job) - , _j2k_encoder(film, _writer) - , _finishing (false) - , _non_burnt_subtitles (false) -{ - _player_video_connection = _player.Video.connect(bind(&DCPEncoder::video, this, _1, _2)); - _player_audio_connection = _player.Audio.connect(bind(&DCPEncoder::audio, this, _1, _2)); - _player_text_connection = _player.Text.connect(bind(&DCPEncoder::text, this, _1, _2, _3, _4)); - _player_atmos_connection = _player.Atmos.connect(bind(&DCPEncoder::atmos, this, _1, _2, _3)); - - for (auto c: film->content ()) { - for (auto i: c->text) { - if (i->use() && !i->burn()) { - _non_burnt_subtitles = true; - } - } - } -} - -DCPEncoder::~DCPEncoder () -{ - /* We must stop receiving more video data before we die */ - _player_video_connection.release (); - _player_audio_connection.release (); - _player_text_connection.release (); - _player_atmos_connection.release (); -} - -void -DCPEncoder::go () -{ - _writer.start(); - _j2k_encoder.begin(); - - { - auto job = _job.lock (); - DCPOMATIC_ASSERT (job); - job->sub (_("Encoding")); - } - - if (_non_burnt_subtitles) { - _writer.write(_player.get_subtitle_fonts()); - } - - while (!_player.pass()) {} - - for (auto i: get_referenced_reel_assets(_film, _film->playlist())) { - _writer.write(i); - } - - _finishing = true; - _j2k_encoder.end(); - _writer.finish(_film->dir(_film->dcp_name())); -} - - -void -DCPEncoder::pause() -{ - _j2k_encoder.pause(); -} - - -void -DCPEncoder::resume() -{ - _j2k_encoder.resume(); -} - -void -DCPEncoder::video (shared_ptr data, DCPTime time) -{ - _j2k_encoder.encode(data, time); -} - -void -DCPEncoder::audio (shared_ptr data, DCPTime time) -{ - _writer.write(data, time); - - auto job = _job.lock (); - DCPOMATIC_ASSERT (job); - job->set_progress (float(time.get()) / _film->length().get()); -} - -void -DCPEncoder::text (PlayerText data, TextType type, optional track, DCPTimePeriod period) -{ - if (type == TextType::CLOSED_CAPTION || _non_burnt_subtitles) { - _writer.write(data, type, track, period); - } -} - - -void -DCPEncoder::atmos (shared_ptr data, DCPTime time, AtmosMetadata metadata) -{ - _writer.write(data, time, metadata); -} - - -optional -DCPEncoder::current_rate () const -{ - return _j2k_encoder.current_encoding_rate(); -} - -Frame -DCPEncoder::frames_done () const -{ - return _j2k_encoder.video_frames_enqueued(); -} diff --git a/src/lib/dcp_encoder.h b/src/lib/dcp_encoder.h deleted file mode 100644 index ce0b72204..000000000 --- a/src/lib/dcp_encoder.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright (C) 2012-2020 Carl Hetherington - - 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 . - -*/ - - -#include "atmos_metadata.h" -#include "dcp_text_track.h" -#include "dcpomatic_time.h" -#include "encoder.h" -#include "player_text.h" -#include "j2k_encoder.h" -#include "writer.h" -#include - - -class AudioBuffers; -class Film; -class Job; -class Player; -class PlayerVideo; - -struct frames_not_lost_when_threads_disappear; - - -/** @class DCPEncoder */ -class DCPEncoder : public Encoder -{ -public: - DCPEncoder (std::shared_ptr film, std::weak_ptr job); - ~DCPEncoder (); - - void go () override; - - boost::optional current_rate () const override; - Frame frames_done () const override; - - /** @return true if we are in the process of calling Encoder::process_end */ - bool finishing () const override { - return _finishing; - } - - void pause() override; - void resume() override; - -private: - - friend struct ::frames_not_lost_when_threads_disappear; - - void video (std::shared_ptr, dcpomatic::DCPTime); - void audio (std::shared_ptr, dcpomatic::DCPTime); - void text (PlayerText, TextType, boost::optional, dcpomatic::DCPTimePeriod); - void atmos (std::shared_ptr, dcpomatic::DCPTime, AtmosMetadata metadata); - - Writer _writer; - J2KEncoder _j2k_encoder; - bool _finishing; - bool _non_burnt_subtitles; - - boost::signals2::scoped_connection _player_video_connection; - boost::signals2::scoped_connection _player_audio_connection; - boost::signals2::scoped_connection _player_text_connection; - boost::signals2::scoped_connection _player_atmos_connection; -}; diff --git a/src/lib/dcp_film_encoder.cc b/src/lib/dcp_film_encoder.cc new file mode 100644 index 000000000..0403b2d90 --- /dev/null +++ b/src/lib/dcp_film_encoder.cc @@ -0,0 +1,180 @@ +/* + Copyright (C) 2012-2020 Carl Hetherington + + 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 . + +*/ + + +/** @file src/dcp_film_encoder.cc + * @brief A class which takes a Film and some Options, then uses those to encode the film into a DCP. + * + * A decoder is selected according to the content type, and the encoder can be specified + * as a parameter to the constructor. + */ + + +#include "audio_decoder.h" +#include "compose.hpp" +#include "dcp_film_encoder.h" +#include "film.h" +#include "j2k_encoder.h" +#include "job.h" +#include "player.h" +#include "player_video.h" +#include "referenced_reel_asset.h" +#include "text_content.h" +#include "video_decoder.h" +#include "writer.h" +#include +#include + +#include "i18n.h" + + +using std::cout; +using std::dynamic_pointer_cast; +using std::list; +using std::make_shared; +using std::shared_ptr; +using std::string; +using std::vector; +using std::weak_ptr; +using boost::optional; +#if BOOST_VERSION >= 106100 +using namespace boost::placeholders; +#endif +using namespace dcpomatic; + + +/** Construct a DCP encoder. + * @param film Film that we are encoding. + * @param job Job that this encoder is being used in. + */ +DCPFilmEncoder::DCPFilmEncoder(shared_ptr film, weak_ptr job) + : FilmEncoder(film, job) + , _writer(film, job) + , _j2k_encoder(film, _writer) + , _finishing (false) + , _non_burnt_subtitles (false) +{ + _player_video_connection = _player.Video.connect(bind(&DCPFilmEncoder::video, this, _1, _2)); + _player_audio_connection = _player.Audio.connect(bind(&DCPFilmEncoder::audio, this, _1, _2)); + _player_text_connection = _player.Text.connect(bind(&DCPFilmEncoder::text, this, _1, _2, _3, _4)); + _player_atmos_connection = _player.Atmos.connect(bind(&DCPFilmEncoder::atmos, this, _1, _2, _3)); + + for (auto c: film->content ()) { + for (auto i: c->text) { + if (i->use() && !i->burn()) { + _non_burnt_subtitles = true; + } + } + } +} + +DCPFilmEncoder::~DCPFilmEncoder() +{ + /* We must stop receiving more video data before we die */ + _player_video_connection.release (); + _player_audio_connection.release (); + _player_text_connection.release (); + _player_atmos_connection.release (); +} + +void +DCPFilmEncoder::go() +{ + _writer.start(); + _j2k_encoder.begin(); + + { + auto job = _job.lock (); + DCPOMATIC_ASSERT (job); + job->sub (_("Encoding")); + } + + if (_non_burnt_subtitles) { + _writer.write(_player.get_subtitle_fonts()); + } + + while (!_player.pass()) {} + + for (auto i: get_referenced_reel_assets(_film, _film->playlist())) { + _writer.write(i); + } + + _finishing = true; + _j2k_encoder.end(); + _writer.finish(_film->dir(_film->dcp_name())); +} + + +void +DCPFilmEncoder::pause() +{ + _j2k_encoder.pause(); +} + + +void +DCPFilmEncoder::resume() +{ + _j2k_encoder.resume(); +} + +void +DCPFilmEncoder::video(shared_ptr data, DCPTime time) +{ + _j2k_encoder.encode(data, time); +} + +void +DCPFilmEncoder::audio(shared_ptr data, DCPTime time) +{ + _writer.write(data, time); + + auto job = _job.lock (); + DCPOMATIC_ASSERT (job); + job->set_progress (float(time.get()) / _film->length().get()); +} + +void +DCPFilmEncoder::text(PlayerText data, TextType type, optional track, DCPTimePeriod period) +{ + if (type == TextType::CLOSED_CAPTION || _non_burnt_subtitles) { + _writer.write(data, type, track, period); + } +} + + +void +DCPFilmEncoder::atmos(shared_ptr data, DCPTime time, AtmosMetadata metadata) +{ + _writer.write(data, time, metadata); +} + + +optional +DCPFilmEncoder::current_rate() const +{ + return _j2k_encoder.current_encoding_rate(); +} + +Frame +DCPFilmEncoder::frames_done() const +{ + return _j2k_encoder.video_frames_enqueued(); +} diff --git a/src/lib/dcp_film_encoder.h b/src/lib/dcp_film_encoder.h new file mode 100644 index 000000000..fbc0aeb13 --- /dev/null +++ b/src/lib/dcp_film_encoder.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2012-2020 Carl Hetherington + + 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 . + +*/ + + +#include "atmos_metadata.h" +#include "dcp_text_track.h" +#include "dcpomatic_time.h" +#include "film_encoder.h" +#include "player_text.h" +#include "j2k_encoder.h" +#include "writer.h" +#include + + +class AudioBuffers; +class Film; +class Job; +class Player; +class PlayerVideo; + +struct frames_not_lost_when_threads_disappear; + + +/** @class DCPFilmEncoder */ +class DCPFilmEncoder : public FilmEncoder +{ +public: + DCPFilmEncoder(std::shared_ptr film, std::weak_ptr job); + ~DCPFilmEncoder(); + + void go () override; + + boost::optional current_rate () const override; + Frame frames_done () const override; + + /** @return true if we are in the process of calling Encoder::process_end */ + bool finishing () const override { + return _finishing; + } + + void pause() override; + void resume() override; + +private: + + friend struct ::frames_not_lost_when_threads_disappear; + + void video (std::shared_ptr, dcpomatic::DCPTime); + void audio (std::shared_ptr, dcpomatic::DCPTime); + void text (PlayerText, TextType, boost::optional, dcpomatic::DCPTimePeriod); + void atmos (std::shared_ptr, dcpomatic::DCPTime, AtmosMetadata metadata); + + Writer _writer; + J2KEncoder _j2k_encoder; + bool _finishing; + bool _non_burnt_subtitles; + + boost::signals2::scoped_connection _player_video_connection; + boost::signals2::scoped_connection _player_audio_connection; + boost::signals2::scoped_connection _player_text_connection; + boost::signals2::scoped_connection _player_atmos_connection; +}; diff --git a/src/lib/encode_server.cc b/src/lib/encode_server.cc index da5c7270e..68ee871f8 100644 --- a/src/lib/encode_server.cc +++ b/src/lib/encode_server.cc @@ -37,6 +37,7 @@ #include "image.h" #include "log.h" #include "player_video.h" +#include "util.h" #include "variant.h" #include "version.h" #include diff --git a/src/lib/encode_server_finder.cc b/src/lib/encode_server_finder.cc index 9ce9e1691..143569e16 100644 --- a/src/lib/encode_server_finder.cc +++ b/src/lib/encode_server_finder.cc @@ -26,6 +26,7 @@ #include "encode_server_description.h" #include "encode_server_finder.h" #include "exceptions.h" +#include "util.h" #include "variant.h" #include #include diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc deleted file mode 100644 index 5268d8620..000000000 --- a/src/lib/encoder.cc +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright (C) 2012-2017 Carl Hetherington - - 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 . - -*/ - - -/** @file src/encoder.cc - * @brief A class which takes a Film and some Options, then uses those to encode the film - * into some output format. - * - * A decoder is selected according to the content type, and the encoder can be specified - * as a parameter to the constructor. - */ - - -#include "encoder.h" -#include "player.h" - -#include "i18n.h" - - -/** Construct an encoder. - * @param film Film that we are encoding. - * @param job Job that this encoder is being used in. - */ -Encoder::Encoder (std::shared_ptr film, std::weak_ptr job) - : _film (film) - , _job (job) - , _player(film, Image::Alignment::PADDED) -{ - -} diff --git a/src/lib/encoder.h b/src/lib/encoder.h deleted file mode 100644 index aeaf7f620..000000000 --- a/src/lib/encoder.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - Copyright (C) 2012-2021 Carl Hetherington - - 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 . - -*/ - - -#ifndef DCPOMATIC_ENCODER_H -#define DCPOMATIC_ENCODER_H - - -#include "player.h" -#include "player_text.h" -#include - - -class Film; -class Encoder; -class Player; -class Job; -class PlayerVideo; -class AudioBuffers; - - -/** @class Encoder - * @brief Parent class for something that can encode a film into some format - */ -class Encoder -{ -public: - Encoder (std::shared_ptr film, std::weak_ptr job); - virtual ~Encoder () {} - - Encoder (Encoder const&) = delete; - Encoder& operator= (Encoder const&) = delete; - - virtual void go () = 0; - - /** @return the current frame rate over the last short while */ - virtual boost::optional current_rate () const { - return {}; - } - - /** @return the number of frames that are done */ - virtual Frame frames_done () const = 0; - virtual bool finishing () const = 0; - virtual void pause() {} - virtual void resume() {} - -protected: - std::shared_ptr _film; - std::weak_ptr _job; - Player _player; -}; - - -#endif diff --git a/src/lib/ffmpeg_encoder.cc b/src/lib/ffmpeg_encoder.cc deleted file mode 100644 index 60241b233..000000000 --- a/src/lib/ffmpeg_encoder.cc +++ /dev/null @@ -1,315 +0,0 @@ -/* - Copyright (C) 2017-2018 Carl Hetherington - - 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 . - -*/ - - -#include "butler.h" -#include "cross.h" -#include "ffmpeg_encoder.h" -#include "film.h" -#include "image.h" -#include "job.h" -#include "log.h" -#include "player.h" -#include "player_video.h" -#include "compose.hpp" -#include - -#include "i18n.h" - - -using std::cout; -using std::list; -using std::make_shared; -using std::shared_ptr; -using std::string; -using std::weak_ptr; -using boost::bind; -using boost::optional; -using namespace dcpomatic; -#if BOOST_VERSION >= 106100 -using namespace boost::placeholders; -#endif - - -FFmpegEncoder::FFmpegEncoder ( - shared_ptr film, - weak_ptr job, - boost::filesystem::path output, - ExportFormat format, - bool mixdown_to_stereo, - bool split_reels, - bool audio_stream_per_channel, - int x264_crf - ) - : Encoder (film, job) - , _output_audio_channels(mixdown_to_stereo ? 2 : (_film->audio_channels() > 8 ? 16 : _film->audio_channels())) - , _history (200) - , _output (output) - , _format (format) - , _split_reels (split_reels) - , _audio_stream_per_channel (audio_stream_per_channel) - , _x264_crf (x264_crf) - , _butler( - _film, - _player, - mixdown_to_stereo ? stereo_map() : many_channel_map(), - _output_audio_channels, - boost::bind(&PlayerVideo::force, FFmpegFileEncoder::pixel_format(format)), - VideoRange::VIDEO, - Image::Alignment::PADDED, - false, - false, - Butler::Audio::ENABLED - ) -{ - _player.set_always_burn_open_subtitles(); - _player.set_play_referenced(); -} - - -AudioMapping -FFmpegEncoder::stereo_map() const -{ - auto map = AudioMapping(_film->audio_channels(), 2); - float const overall_gain = 2 / (4 + sqrt(2)); - float const minus_3dB = 1 / sqrt(2); - switch (_film->audio_channels()) { - case 2: - map.set(dcp::Channel::LEFT, 0, 1); - map.set(dcp::Channel::RIGHT, 1, 1); - break; - case 4: - map.set(dcp::Channel::LEFT, 0, overall_gain); - map.set(dcp::Channel::RIGHT, 1, overall_gain); - map.set(dcp::Channel::CENTRE, 0, overall_gain * minus_3dB); - map.set(dcp::Channel::CENTRE, 1, overall_gain * minus_3dB); - map.set(dcp::Channel::LS, 0, overall_gain); - break; - case 6: - map.set(dcp::Channel::LEFT, 0, overall_gain); - map.set(dcp::Channel::RIGHT, 1, overall_gain); - map.set(dcp::Channel::CENTRE, 0, overall_gain * minus_3dB); - map.set(dcp::Channel::CENTRE, 1, overall_gain * minus_3dB); - map.set(dcp::Channel::LS, 0, overall_gain); - map.set(dcp::Channel::RS, 1, overall_gain); - break; - } - /* XXX: maybe we should do something better for >6 channel DCPs */ - return map; -} - - -AudioMapping -FFmpegEncoder::many_channel_map() const -{ - auto map = AudioMapping(_film->audio_channels(), _output_audio_channels); - for (int i = 0; i < _film->audio_channels(); ++i) { - map.set(i, i, 1); - } - return map; -} - - -void -FFmpegEncoder::go () -{ - { - auto job = _job.lock (); - DCPOMATIC_ASSERT (job); - job->sub (_("Encoding")); - } - - Waker waker; - - list file_encoders; - - int const files = _split_reels ? _film->reels().size() : 1; - for (int i = 0; i < files; ++i) { - - boost::filesystem::path filename = _output; - auto extension = dcp::filesystem::extension(filename); - filename = dcp::filesystem::change_extension(filename, ""); - - if (files > 1) { - /// TRANSLATORS: _reel%1 here is to be added to an export filename to indicate - /// which reel it is. Preserve the %1; it will be replaced with the reel number. - filename = filename.string() + String::compose(_("_reel%1"), i + 1); - } - - file_encoders.push_back ( - FileEncoderSet ( - _film->frame_size(), - _film->video_frame_rate(), - _film->audio_frame_rate(), - _output_audio_channels, - _format, - _audio_stream_per_channel, - _x264_crf, - _film->three_d(), - filename, - extension - ) - ); - } - - auto reel_periods = _film->reels (); - auto reel = reel_periods.begin (); - auto encoder = file_encoders.begin (); - - auto const video_frame = DCPTime::from_frames (1, _film->video_frame_rate ()); - int const audio_frames = video_frame.frames_round(_film->audio_frame_rate()); - std::vector interleaved(_output_audio_channels * audio_frames); - auto deinterleaved = make_shared(_output_audio_channels, audio_frames); - int const gets_per_frame = _film->three_d() ? 2 : 1; - for (DCPTime time; time < _film->length(); time += video_frame) { - - if (file_encoders.size() > 1 && !reel->contains(time)) { - /* Next reel and file */ - ++reel; - ++encoder; - DCPOMATIC_ASSERT (reel != reel_periods.end()); - DCPOMATIC_ASSERT (encoder != file_encoders.end()); - } - - for (int j = 0; j < gets_per_frame; ++j) { - Butler::Error e; - auto video = _butler.get_video(Butler::Behaviour::BLOCKING, &e); - _butler.rethrow(); - if (video.first) { - auto fe = encoder->get(video.first->eyes()); - if (fe) { - fe->video(video.first, video.second - reel->from); - } - } else { - if (e.code != Butler::Error::Code::FINISHED) { - throw DecodeError(String::compose("Error during decoding: %1", e.summary())); - } - } - } - - _history.event (); - - { - boost::mutex::scoped_lock lm (_mutex); - _last_time = time; - } - - auto job = _job.lock (); - if (job) { - job->set_progress(float(time.get()) / _film->length().get()); - } - - waker.nudge (); - - _butler.get_audio(Butler::Behaviour::BLOCKING, interleaved.data(), audio_frames); - /* XXX: inefficient; butler interleaves and we deinterleave again */ - float* p = interleaved.data(); - for (int j = 0; j < audio_frames; ++j) { - for (int k = 0; k < _output_audio_channels; ++k) { - deinterleaved->data(k)[j] = *p++; - } - } - encoder->audio (deinterleaved); - } - - for (auto i: file_encoders) { - i.flush (); - } -} - -optional -FFmpegEncoder::current_rate () const -{ - return _history.rate (); -} - -Frame -FFmpegEncoder::frames_done () const -{ - boost::mutex::scoped_lock lm (_mutex); - return _last_time.frames_round (_film->video_frame_rate ()); -} - -FFmpegEncoder::FileEncoderSet::FileEncoderSet ( - dcp::Size video_frame_size, - int video_frame_rate, - int audio_frame_rate, - int channels, - ExportFormat format, - bool audio_stream_per_channel, - int x264_crf, - bool three_d, - boost::filesystem::path output, - string extension - ) -{ - if (three_d) { - _encoders[Eyes::LEFT] = make_shared( - video_frame_size, video_frame_rate, audio_frame_rate, channels, format, - // TRANSLATORS: L here is an abbreviation for "left", to indicate the left-eye part of a 3D export - audio_stream_per_channel, x264_crf, String::compose("%1_%2%3", output.string(), _("L"), extension) - ); - _encoders[Eyes::RIGHT] = make_shared( - video_frame_size, video_frame_rate, audio_frame_rate, channels, format, - // TRANSLATORS: R here is an abbreviation for "right", to indicate the right-eye part of a 3D export - audio_stream_per_channel, x264_crf, String::compose("%1_%2%3", output.string(), _("R"), extension) - ); - } else { - _encoders[Eyes::BOTH] = make_shared( - video_frame_size, video_frame_rate, audio_frame_rate, channels, format, - audio_stream_per_channel, x264_crf, String::compose("%1%2", output.string(), extension) - ); - } -} - -shared_ptr -FFmpegEncoder::FileEncoderSet::get (Eyes eyes) const -{ - if (_encoders.size() == 1) { - /* We are doing a 2D export... */ - if (eyes == Eyes::LEFT) { - /* ...but we got some 3D data; put the left eye into the output... */ - eyes = Eyes::BOTH; - } else if (eyes == Eyes::RIGHT) { - /* ...and ignore the right eye.*/ - return {}; - } - } - - auto i = _encoders.find (eyes); - DCPOMATIC_ASSERT (i != _encoders.end()); - return i->second; -} - -void -FFmpegEncoder::FileEncoderSet::flush () -{ - for (auto& i: _encoders) { - i.second->flush (); - } -} - -void -FFmpegEncoder::FileEncoderSet::audio (shared_ptr a) -{ - for (auto& i: _encoders) { - i.second->audio (a); - } -} diff --git a/src/lib/ffmpeg_encoder.h b/src/lib/ffmpeg_encoder.h deleted file mode 100644 index 2d5c6af87..000000000 --- a/src/lib/ffmpeg_encoder.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - Copyright (C) 2017-2018 Carl Hetherington - - 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 . - -*/ - -#ifndef DCPOMATIC_FFMPEG_ENCODER_H -#define DCPOMATIC_FFMPEG_ENCODER_H - -#include "audio_mapping.h" -#include "butler.h" -#include "encoder.h" -#include "event_history.h" -#include "ffmpeg_file_encoder.h" - - -class FFmpegEncoder : public Encoder -{ -public: - FFmpegEncoder ( - std::shared_ptr film, - std::weak_ptr job, - boost::filesystem::path output, - ExportFormat format, - bool mixdown_to_stereo, - bool split_reels, - bool audio_stream_per_channel, - int x264_crf - ); - - void go () override; - - boost::optional current_rate () const override; - Frame frames_done () const override; - bool finishing () const override { - return false; - } - -private: - - class FileEncoderSet - { - public: - FileEncoderSet ( - dcp::Size video_frame_size, - int video_frame_rate, - int audio_frame_rate, - int channels, - ExportFormat, - bool audio_stream_per_channel, - int x264_crf, - bool three_d, - boost::filesystem::path output, - std::string extension - ); - - std::shared_ptr get (Eyes eyes) const; - void flush (); - void audio (std::shared_ptr); - - private: - std::map> _encoders; - }; - - AudioMapping stereo_map() const; - AudioMapping many_channel_map() const; - - int _output_audio_channels; - - mutable boost::mutex _mutex; - dcpomatic::DCPTime _last_time; - - EventHistory _history; - - boost::filesystem::path _output; - ExportFormat _format; - bool _split_reels; - bool _audio_stream_per_channel; - int _x264_crf; - - Butler _butler; -}; - -#endif diff --git a/src/lib/ffmpeg_file_encoder.cc b/src/lib/ffmpeg_file_encoder.cc index d7833265d..4547a8e8e 100644 --- a/src/lib/ffmpeg_file_encoder.cc +++ b/src/lib/ffmpeg_file_encoder.cc @@ -21,7 +21,7 @@ #include "compose.hpp" #include "cross.h" -#include "ffmpeg_encoder.h" +#include "ffmpeg_file_encoder.h" #include "ffmpeg_wrapper.h" #include "film.h" #include "image.h" diff --git a/src/lib/ffmpeg_file_encoder.h b/src/lib/ffmpeg_file_encoder.h index 78840d6a8..907eca53d 100644 --- a/src/lib/ffmpeg_file_encoder.h +++ b/src/lib/ffmpeg_file_encoder.h @@ -23,12 +23,14 @@ #define DCPOMATIC_FFMPEG_FILE_ENCODER_H +#include "audio_buffers.h" #include "audio_mapping.h" #include "dcpomatic_time.h" -#include "encoder.h" #include "event_history.h" #include "image_store.h" #include "log.h" +#include "player_text.h" +#include "player_video.h" #include #include LIBDCP_DISABLE_WARNINGS diff --git a/src/lib/ffmpeg_film_encoder.cc b/src/lib/ffmpeg_film_encoder.cc new file mode 100644 index 000000000..2d100f7bc --- /dev/null +++ b/src/lib/ffmpeg_film_encoder.cc @@ -0,0 +1,315 @@ +/* + Copyright (C) 2017-2018 Carl Hetherington + + 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 . + +*/ + + +#include "butler.h" +#include "cross.h" +#include "ffmpeg_film_encoder.h" +#include "film.h" +#include "image.h" +#include "job.h" +#include "log.h" +#include "player.h" +#include "player_video.h" +#include "compose.hpp" +#include + +#include "i18n.h" + + +using std::cout; +using std::list; +using std::make_shared; +using std::shared_ptr; +using std::string; +using std::weak_ptr; +using boost::bind; +using boost::optional; +using namespace dcpomatic; +#if BOOST_VERSION >= 106100 +using namespace boost::placeholders; +#endif + + +FFmpegFilmEncoder::FFmpegFilmEncoder( + shared_ptr film, + weak_ptr job, + boost::filesystem::path output, + ExportFormat format, + bool mixdown_to_stereo, + bool split_reels, + bool audio_stream_per_channel, + int x264_crf + ) + : FilmEncoder(film, job) + , _output_audio_channels(mixdown_to_stereo ? 2 : (_film->audio_channels() > 8 ? 16 : _film->audio_channels())) + , _history (200) + , _output (output) + , _format (format) + , _split_reels (split_reels) + , _audio_stream_per_channel (audio_stream_per_channel) + , _x264_crf (x264_crf) + , _butler( + _film, + _player, + mixdown_to_stereo ? stereo_map() : many_channel_map(), + _output_audio_channels, + boost::bind(&PlayerVideo::force, FFmpegFileEncoder::pixel_format(format)), + VideoRange::VIDEO, + Image::Alignment::PADDED, + false, + false, + Butler::Audio::ENABLED + ) +{ + _player.set_always_burn_open_subtitles(); + _player.set_play_referenced(); +} + + +AudioMapping +FFmpegFilmEncoder::stereo_map() const +{ + auto map = AudioMapping(_film->audio_channels(), 2); + float const overall_gain = 2 / (4 + sqrt(2)); + float const minus_3dB = 1 / sqrt(2); + switch (_film->audio_channels()) { + case 2: + map.set(dcp::Channel::LEFT, 0, 1); + map.set(dcp::Channel::RIGHT, 1, 1); + break; + case 4: + map.set(dcp::Channel::LEFT, 0, overall_gain); + map.set(dcp::Channel::RIGHT, 1, overall_gain); + map.set(dcp::Channel::CENTRE, 0, overall_gain * minus_3dB); + map.set(dcp::Channel::CENTRE, 1, overall_gain * minus_3dB); + map.set(dcp::Channel::LS, 0, overall_gain); + break; + case 6: + map.set(dcp::Channel::LEFT, 0, overall_gain); + map.set(dcp::Channel::RIGHT, 1, overall_gain); + map.set(dcp::Channel::CENTRE, 0, overall_gain * minus_3dB); + map.set(dcp::Channel::CENTRE, 1, overall_gain * minus_3dB); + map.set(dcp::Channel::LS, 0, overall_gain); + map.set(dcp::Channel::RS, 1, overall_gain); + break; + } + /* XXX: maybe we should do something better for >6 channel DCPs */ + return map; +} + + +AudioMapping +FFmpegFilmEncoder::many_channel_map() const +{ + auto map = AudioMapping(_film->audio_channels(), _output_audio_channels); + for (int i = 0; i < _film->audio_channels(); ++i) { + map.set(i, i, 1); + } + return map; +} + + +void +FFmpegFilmEncoder::go() +{ + { + auto job = _job.lock (); + DCPOMATIC_ASSERT (job); + job->sub (_("Encoding")); + } + + Waker waker; + + list file_encoders; + + int const files = _split_reels ? _film->reels().size() : 1; + for (int i = 0; i < files; ++i) { + + boost::filesystem::path filename = _output; + auto extension = dcp::filesystem::extension(filename); + filename = dcp::filesystem::change_extension(filename, ""); + + if (files > 1) { + /// TRANSLATORS: _reel%1 here is to be added to an export filename to indicate + /// which reel it is. Preserve the %1; it will be replaced with the reel number. + filename = filename.string() + String::compose(_("_reel%1"), i + 1); + } + + file_encoders.push_back ( + FileEncoderSet ( + _film->frame_size(), + _film->video_frame_rate(), + _film->audio_frame_rate(), + _output_audio_channels, + _format, + _audio_stream_per_channel, + _x264_crf, + _film->three_d(), + filename, + extension + ) + ); + } + + auto reel_periods = _film->reels (); + auto reel = reel_periods.begin (); + auto encoder = file_encoders.begin (); + + auto const video_frame = DCPTime::from_frames (1, _film->video_frame_rate ()); + int const audio_frames = video_frame.frames_round(_film->audio_frame_rate()); + std::vector interleaved(_output_audio_channels * audio_frames); + auto deinterleaved = make_shared(_output_audio_channels, audio_frames); + int const gets_per_frame = _film->three_d() ? 2 : 1; + for (DCPTime time; time < _film->length(); time += video_frame) { + + if (file_encoders.size() > 1 && !reel->contains(time)) { + /* Next reel and file */ + ++reel; + ++encoder; + DCPOMATIC_ASSERT (reel != reel_periods.end()); + DCPOMATIC_ASSERT (encoder != file_encoders.end()); + } + + for (int j = 0; j < gets_per_frame; ++j) { + Butler::Error e; + auto video = _butler.get_video(Butler::Behaviour::BLOCKING, &e); + _butler.rethrow(); + if (video.first) { + auto fe = encoder->get(video.first->eyes()); + if (fe) { + fe->video(video.first, video.second - reel->from); + } + } else { + if (e.code != Butler::Error::Code::FINISHED) { + throw DecodeError(String::compose("Error during decoding: %1", e.summary())); + } + } + } + + _history.event (); + + { + boost::mutex::scoped_lock lm (_mutex); + _last_time = time; + } + + auto job = _job.lock (); + if (job) { + job->set_progress(float(time.get()) / _film->length().get()); + } + + waker.nudge (); + + _butler.get_audio(Butler::Behaviour::BLOCKING, interleaved.data(), audio_frames); + /* XXX: inefficient; butler interleaves and we deinterleave again */ + float* p = interleaved.data(); + for (int j = 0; j < audio_frames; ++j) { + for (int k = 0; k < _output_audio_channels; ++k) { + deinterleaved->data(k)[j] = *p++; + } + } + encoder->audio (deinterleaved); + } + + for (auto i: file_encoders) { + i.flush (); + } +} + +optional +FFmpegFilmEncoder::current_rate() const +{ + return _history.rate (); +} + +Frame +FFmpegFilmEncoder::frames_done() const +{ + boost::mutex::scoped_lock lm (_mutex); + return _last_time.frames_round (_film->video_frame_rate ()); +} + +FFmpegFilmEncoder::FileEncoderSet::FileEncoderSet( + dcp::Size video_frame_size, + int video_frame_rate, + int audio_frame_rate, + int channels, + ExportFormat format, + bool audio_stream_per_channel, + int x264_crf, + bool three_d, + boost::filesystem::path output, + string extension + ) +{ + if (three_d) { + _encoders[Eyes::LEFT] = make_shared( + video_frame_size, video_frame_rate, audio_frame_rate, channels, format, + // TRANSLATORS: L here is an abbreviation for "left", to indicate the left-eye part of a 3D export + audio_stream_per_channel, x264_crf, String::compose("%1_%2%3", output.string(), _("L"), extension) + ); + _encoders[Eyes::RIGHT] = make_shared( + video_frame_size, video_frame_rate, audio_frame_rate, channels, format, + // TRANSLATORS: R here is an abbreviation for "right", to indicate the right-eye part of a 3D export + audio_stream_per_channel, x264_crf, String::compose("%1_%2%3", output.string(), _("R"), extension) + ); + } else { + _encoders[Eyes::BOTH] = make_shared( + video_frame_size, video_frame_rate, audio_frame_rate, channels, format, + audio_stream_per_channel, x264_crf, String::compose("%1%2", output.string(), extension) + ); + } +} + +shared_ptr +FFmpegFilmEncoder::FileEncoderSet::get(Eyes eyes) const +{ + if (_encoders.size() == 1) { + /* We are doing a 2D export... */ + if (eyes == Eyes::LEFT) { + /* ...but we got some 3D data; put the left eye into the output... */ + eyes = Eyes::BOTH; + } else if (eyes == Eyes::RIGHT) { + /* ...and ignore the right eye.*/ + return {}; + } + } + + auto i = _encoders.find (eyes); + DCPOMATIC_ASSERT (i != _encoders.end()); + return i->second; +} + +void +FFmpegFilmEncoder::FileEncoderSet::flush() +{ + for (auto& i: _encoders) { + i.second->flush (); + } +} + +void +FFmpegFilmEncoder::FileEncoderSet::audio(shared_ptr a) +{ + for (auto& i: _encoders) { + i.second->audio (a); + } +} diff --git a/src/lib/ffmpeg_film_encoder.h b/src/lib/ffmpeg_film_encoder.h new file mode 100644 index 000000000..ec6bb4594 --- /dev/null +++ b/src/lib/ffmpeg_film_encoder.h @@ -0,0 +1,98 @@ +/* + Copyright (C) 2017-2018 Carl Hetherington + + 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 . + +*/ + +#ifndef DCPOMATIC_FFMPEG_ENCODER_H +#define DCPOMATIC_FFMPEG_ENCODER_H + +#include "audio_mapping.h" +#include "butler.h" +#include "event_history.h" +#include "ffmpeg_file_encoder.h" +#include "film_encoder.h" + + +class FFmpegFilmEncoder : public FilmEncoder +{ +public: + FFmpegFilmEncoder( + std::shared_ptr film, + std::weak_ptr job, + boost::filesystem::path output, + ExportFormat format, + bool mixdown_to_stereo, + bool split_reels, + bool audio_stream_per_channel, + int x264_crf + ); + + void go () override; + + boost::optional current_rate () const override; + Frame frames_done () const override; + bool finishing () const override { + return false; + } + +private: + + class FileEncoderSet + { + public: + FileEncoderSet ( + dcp::Size video_frame_size, + int video_frame_rate, + int audio_frame_rate, + int channels, + ExportFormat, + bool audio_stream_per_channel, + int x264_crf, + bool three_d, + boost::filesystem::path output, + std::string extension + ); + + std::shared_ptr get (Eyes eyes) const; + void flush (); + void audio (std::shared_ptr); + + private: + std::map> _encoders; + }; + + AudioMapping stereo_map() const; + AudioMapping many_channel_map() const; + + int _output_audio_channels; + + mutable boost::mutex _mutex; + dcpomatic::DCPTime _last_time; + + EventHistory _history; + + boost::filesystem::path _output; + ExportFormat _format; + bool _split_reels; + bool _audio_stream_per_channel; + int _x264_crf; + + Butler _butler; +}; + +#endif diff --git a/src/lib/film.cc b/src/lib/film.cc index 540d0b9b9..fd703a72a 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -36,7 +36,7 @@ #include "cross.h" #include "dcp_content.h" #include "dcp_content_type.h" -#include "dcp_encoder.h" +#include "dcp_film_encoder.h" #include "dcpomatic_log.h" #include "digester.h" #include "environment_info.h" diff --git a/src/lib/film_encoder.cc b/src/lib/film_encoder.cc new file mode 100644 index 000000000..05b911daf --- /dev/null +++ b/src/lib/film_encoder.cc @@ -0,0 +1,47 @@ +/* + Copyright (C) 2012-2017 Carl Hetherington + + 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 . + +*/ + + +/** @file src/film_encoder.cc + * @brief A class which takes a Film and some Options, then uses those to encode the film + * into some output format. + * + * A decoder is selected according to the content type, and the encoder can be specified + * as a parameter to the constructor. + */ + + +#include "film_encoder.h" +#include "player.h" + +#include "i18n.h" + + +/** Construct a FilmEncoder. + * @param film Film that we are encoding. + * @param job Job that this encoder is being used in. + */ +FilmEncoder::FilmEncoder(std::shared_ptr film, std::weak_ptr job) + : _film (film) + , _job (job) + , _player(film, Image::Alignment::PADDED) +{ + +} diff --git a/src/lib/film_encoder.h b/src/lib/film_encoder.h new file mode 100644 index 000000000..ed7626c68 --- /dev/null +++ b/src/lib/film_encoder.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2012-2021 Carl Hetherington + + 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 . + +*/ + + +#ifndef DCPOMATIC_FILM_ENCODER_H +#define DCPOMATIC_FILM_ENCODER_H + + +#include "player.h" +#include "player_text.h" +#include + + +class Film; +class Player; +class Job; +class PlayerVideo; +class AudioBuffers; + + +/** @class FilmEncoder + * @brief Parent class for something that can encode a film into some format + */ +class FilmEncoder +{ +public: + FilmEncoder(std::shared_ptr film, std::weak_ptr job); + virtual ~FilmEncoder() {} + + FilmEncoder(FilmEncoder const&) = delete; + FilmEncoder& operator=(FilmEncoder const&) = delete; + + virtual void go () = 0; + + /** @return the current frame rate over the last short while */ + virtual boost::optional current_rate () const { + return {}; + } + + /** @return the number of frames that are done */ + virtual Frame frames_done () const = 0; + virtual bool finishing () const = 0; + virtual void pause() {} + virtual void resume() {} + +protected: + std::shared_ptr _film; + std::weak_ptr _job; + Player _player; +}; + + +#endif diff --git a/src/lib/hints.h b/src/lib/hints.h index 0d65edc21..e7a6646ef 100644 --- a/src/lib/hints.h +++ b/src/lib/hints.h @@ -20,15 +20,16 @@ #include "audio_analyser.h" -#include "signaller.h" -#include "player_text.h" #include "dcp_text_track.h" #include "dcpomatic_time.h" +#include "player_text.h" +#include "signaller.h" +#include "text_type.h" #include "weak_film.h" -#include #include -#include +#include #include +#include class Film; diff --git a/src/lib/make_dcp.cc b/src/lib/make_dcp.cc index ddd231243..41c5e8ec5 100644 --- a/src/lib/make_dcp.cc +++ b/src/lib/make_dcp.cc @@ -21,7 +21,7 @@ #include "config.h" #include "dcp_content.h" -#include "dcp_encoder.h" +#include "dcp_film_encoder.h" #include "dcp_transcode_job.h" #include "dcpomatic_log.h" #include "environment_info.h" @@ -94,7 +94,7 @@ make_dcp (shared_ptr film, TranscodeJob::ChangedBehaviour behaviour) LOG_GENERAL ("J2K bandwidth %1", film->j2k_bandwidth()); auto tj = make_shared(film, behaviour); - tj->set_encoder (make_shared(film, tj)); + tj->set_encoder(make_shared(film, tj)); JobManager::instance()->add (tj); return tj; diff --git a/src/lib/reel_writer.h b/src/lib/reel_writer.h index 0886482a8..6f47c6740 100644 --- a/src/lib/reel_writer.h +++ b/src/lib/reel_writer.h @@ -27,6 +27,7 @@ #include "player_text.h" #include "referenced_reel_asset.h" #include "render_text.h" +#include "text_type.h" #include "weak_film.h" #include #include diff --git a/src/lib/subtitle_encoder.cc b/src/lib/subtitle_encoder.cc deleted file mode 100644 index 8b1d9a15b..000000000 --- a/src/lib/subtitle_encoder.cc +++ /dev/null @@ -1,204 +0,0 @@ -/* - Copyright (C) 2019-2021 Carl Hetherington - - 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 . - -*/ - - -#include "compose.hpp" -#include "film.h" -#include "job.h" -#include "player.h" -#include "subtitle_encoder.h" -#include -#include -#include -#include -#include -#include - -#include "i18n.h" - - -using std::make_pair; -using std::make_shared; -using std::pair; -using std::shared_ptr; -using std::string; -using std::vector; -using boost::optional; -#if BOOST_VERSION >= 106100 -using namespace boost::placeholders; -#endif -using dcp::raw_convert; - - -/** @param output Directory, if there will be multiple output files, or a filename. - * @param initial_name Hint that may be used to create filenames, if @ref output is a directory. - * @param include_font true to refer to and export any font file (for Interop; ignored for SMPTE). - */ -SubtitleEncoder::SubtitleEncoder (shared_ptr film, shared_ptr job, boost::filesystem::path output, string initial_name, bool split_reels, bool include_font) - : Encoder (film, job) - , _split_reels (split_reels) - , _include_font (include_font) - , _reel_index (0) - , _length (film->length()) -{ - _player.set_play_referenced(); - _player.set_ignore_video(); - _player.set_ignore_audio(); - _player.Text.connect(boost::bind(&SubtitleEncoder::text, this, _1, _2, _3, _4)); - - string const extension = film->interop() ? ".xml" : ".mxf"; - - int const files = split_reels ? film->reels().size() : 1; - for (int i = 0; i < files; ++i) { - - boost::filesystem::path filename = output; - if (dcp::filesystem::is_directory(filename)) { - if (files > 1) { - /// TRANSLATORS: _reel%1 here is to be added to an export filename to indicate - /// which reel it is. Preserve the %1; it will be replaced with the reel number. - filename /= String::compose("%1_reel%2", initial_name, i + 1); - } else { - filename /= initial_name; - } - } - - _assets.push_back(make_pair(shared_ptr(), dcp::filesystem::change_extension(filename, extension))); - } - - for (auto i: film->reels()) { - _reels.push_back (i); - } - - _default_font = dcp::ArrayData (default_font_file()); -} - - -void -SubtitleEncoder::go () -{ - { - shared_ptr job = _job.lock (); - DCPOMATIC_ASSERT (job); - job->sub (_("Extracting")); - } - - _reel_index = 0; - - while (!_player.pass()) {} - - int reel = 0; - for (auto& i: _assets) { - if (!i.first) { - /* No subtitles arrived for this asset; make an empty one so we write something to the output */ - if (_film->interop()) { - auto s = make_shared(); - s->set_movie_title (_film->name()); - s->set_reel_number (raw_convert(reel + 1)); - i.first = s; - } else { - auto s = make_shared(); - s->set_content_title_text (_film->name()); - s->set_reel_number (reel + 1); - i.first = s; - } - } - - if (!_film->interop() || _include_font) { - for (auto j: _player.get_subtitle_fonts()) { - i.first->add_font(j->id(), j->data().get_value_or(_default_font)); - } - } - - i.first->write (i.second); - ++reel; - } -} - - -void -SubtitleEncoder::text (PlayerText subs, TextType type, optional track, dcpomatic::DCPTimePeriod period) -{ - if (type != TextType::OPEN_SUBTITLE) { - return; - } - - if (!_assets[_reel_index].first) { - shared_ptr asset; - auto lang = _film->subtitle_languages (); - if (_film->interop ()) { - auto s = make_shared(); - s->set_movie_title (_film->name()); - if (lang.first) { - s->set_language (lang.first->to_string()); - } - s->set_reel_number (raw_convert(_reel_index + 1)); - _assets[_reel_index].first = s; - } else { - auto s = make_shared(); - s->set_content_title_text (_film->name()); - if (lang.first) { - s->set_language (*lang.first); - } else if (track->language) { - s->set_language (track->language.get()); - } - s->set_edit_rate (dcp::Fraction (_film->video_frame_rate(), 1)); - s->set_reel_number (_reel_index + 1); - s->set_time_code_rate (_film->video_frame_rate()); - s->set_start_time (dcp::Time()); - if (_film->encrypted ()) { - s->set_key (_film->key ()); - } - _assets[_reel_index].first = s; - } - } - - for (auto i: subs.string) { - /* XXX: couldn't / shouldn't we use period here rather than getting time from the subtitle? */ - i.set_in (i.in()); - i.set_out (i.out()); - if (_film->interop() && !_include_font) { - i.unset_font (); - } - _assets[_reel_index].first->add (make_shared(i)); - } - - if (_split_reels && (_reel_index < int(_reels.size()) - 1) && period.from > _reels[_reel_index].from) { - ++_reel_index; - } - - _last = period.from; - - auto job = _job.lock (); - if (job) { - job->set_progress (float(period.from.get()) / _length.get()); - } -} - - -Frame -SubtitleEncoder::frames_done () const -{ - if (!_last) { - return 0; - } - - /* XXX: assuming 24fps here but I don't think it matters */ - return _last->seconds() * 24; -} diff --git a/src/lib/subtitle_encoder.h b/src/lib/subtitle_encoder.h deleted file mode 100644 index 0815b1fff..000000000 --- a/src/lib/subtitle_encoder.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - Copyright (C) 2019-2021 Carl Hetherington - - 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 . - -*/ - - -#include "dcp_text_track.h" -#include "dcpomatic_time.h" -#include "encoder.h" -#include "player_text.h" - - -namespace dcp { - class SubtitleAsset; -} - - -class Film; - - -/** @class SubtitleEncoder. - * @brief An `encoder' which extracts a film's subtitles to DCP XML format. - */ -class SubtitleEncoder : public Encoder -{ -public: - SubtitleEncoder (std::shared_ptr film, std::shared_ptr job, boost::filesystem::path output, std::string initial_name, bool split_reels, bool include_font); - - void go () override; - - /** @return the number of frames that are done */ - Frame frames_done () const override; - - bool finishing () const override { - return false; - } - -private: - void text (PlayerText subs, TextType type, boost::optional track, dcpomatic::DCPTimePeriod period); - - std::vector, boost::filesystem::path>> _assets; - std::vector _reels; - bool _split_reels; - bool _include_font; - int _reel_index; - boost::optional _last; - dcpomatic::DCPTime _length; - dcp::ArrayData _default_font; -}; diff --git a/src/lib/subtitle_film_encoder.cc b/src/lib/subtitle_film_encoder.cc new file mode 100644 index 000000000..93ccc177b --- /dev/null +++ b/src/lib/subtitle_film_encoder.cc @@ -0,0 +1,204 @@ +/* + Copyright (C) 2019-2021 Carl Hetherington + + 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 . + +*/ + + +#include "compose.hpp" +#include "film.h" +#include "job.h" +#include "player.h" +#include "subtitle_film_encoder.h" +#include +#include +#include +#include +#include +#include + +#include "i18n.h" + + +using std::make_pair; +using std::make_shared; +using std::pair; +using std::shared_ptr; +using std::string; +using std::vector; +using boost::optional; +#if BOOST_VERSION >= 106100 +using namespace boost::placeholders; +#endif +using dcp::raw_convert; + + +/** @param output Directory, if there will be multiple output files, or a filename. + * @param initial_name Hint that may be used to create filenames, if @ref output is a directory. + * @param include_font true to refer to and export any font file (for Interop; ignored for SMPTE). + */ +SubtitleFilmEncoder::SubtitleFilmEncoder(shared_ptr film, shared_ptr job, boost::filesystem::path output, string initial_name, bool split_reels, bool include_font) + : FilmEncoder(film, job) + , _split_reels (split_reels) + , _include_font (include_font) + , _reel_index (0) + , _length (film->length()) +{ + _player.set_play_referenced(); + _player.set_ignore_video(); + _player.set_ignore_audio(); + _player.Text.connect(boost::bind(&SubtitleFilmEncoder::text, this, _1, _2, _3, _4)); + + string const extension = film->interop() ? ".xml" : ".mxf"; + + int const files = split_reels ? film->reels().size() : 1; + for (int i = 0; i < files; ++i) { + + boost::filesystem::path filename = output; + if (dcp::filesystem::is_directory(filename)) { + if (files > 1) { + /// TRANSLATORS: _reel%1 here is to be added to an export filename to indicate + /// which reel it is. Preserve the %1; it will be replaced with the reel number. + filename /= String::compose("%1_reel%2", initial_name, i + 1); + } else { + filename /= initial_name; + } + } + + _assets.push_back(make_pair(shared_ptr(), dcp::filesystem::change_extension(filename, extension))); + } + + for (auto i: film->reels()) { + _reels.push_back (i); + } + + _default_font = dcp::ArrayData (default_font_file()); +} + + +void +SubtitleFilmEncoder::go() +{ + { + shared_ptr job = _job.lock (); + DCPOMATIC_ASSERT (job); + job->sub (_("Extracting")); + } + + _reel_index = 0; + + while (!_player.pass()) {} + + int reel = 0; + for (auto& i: _assets) { + if (!i.first) { + /* No subtitles arrived for this asset; make an empty one so we write something to the output */ + if (_film->interop()) { + auto s = make_shared(); + s->set_movie_title (_film->name()); + s->set_reel_number (raw_convert(reel + 1)); + i.first = s; + } else { + auto s = make_shared(); + s->set_content_title_text (_film->name()); + s->set_reel_number (reel + 1); + i.first = s; + } + } + + if (!_film->interop() || _include_font) { + for (auto j: _player.get_subtitle_fonts()) { + i.first->add_font(j->id(), j->data().get_value_or(_default_font)); + } + } + + i.first->write (i.second); + ++reel; + } +} + + +void +SubtitleFilmEncoder::text(PlayerText subs, TextType type, optional track, dcpomatic::DCPTimePeriod period) +{ + if (type != TextType::OPEN_SUBTITLE) { + return; + } + + if (!_assets[_reel_index].first) { + shared_ptr asset; + auto lang = _film->subtitle_languages (); + if (_film->interop ()) { + auto s = make_shared(); + s->set_movie_title (_film->name()); + if (lang.first) { + s->set_language (lang.first->to_string()); + } + s->set_reel_number (raw_convert(_reel_index + 1)); + _assets[_reel_index].first = s; + } else { + auto s = make_shared(); + s->set_content_title_text (_film->name()); + if (lang.first) { + s->set_language (*lang.first); + } else if (track->language) { + s->set_language (track->language.get()); + } + s->set_edit_rate (dcp::Fraction (_film->video_frame_rate(), 1)); + s->set_reel_number (_reel_index + 1); + s->set_time_code_rate (_film->video_frame_rate()); + s->set_start_time (dcp::Time()); + if (_film->encrypted ()) { + s->set_key (_film->key ()); + } + _assets[_reel_index].first = s; + } + } + + for (auto i: subs.string) { + /* XXX: couldn't / shouldn't we use period here rather than getting time from the subtitle? */ + i.set_in (i.in()); + i.set_out (i.out()); + if (_film->interop() && !_include_font) { + i.unset_font (); + } + _assets[_reel_index].first->add (make_shared(i)); + } + + if (_split_reels && (_reel_index < int(_reels.size()) - 1) && period.from > _reels[_reel_index].from) { + ++_reel_index; + } + + _last = period.from; + + auto job = _job.lock (); + if (job) { + job->set_progress (float(period.from.get()) / _length.get()); + } +} + + +Frame +SubtitleFilmEncoder::frames_done() const +{ + if (!_last) { + return 0; + } + + /* XXX: assuming 24fps here but I don't think it matters */ + return _last->seconds() * 24; +} diff --git a/src/lib/subtitle_film_encoder.h b/src/lib/subtitle_film_encoder.h new file mode 100644 index 000000000..54231794d --- /dev/null +++ b/src/lib/subtitle_film_encoder.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2019-2021 Carl Hetherington + + 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 . + +*/ + + +#include "dcp_text_track.h" +#include "dcpomatic_time.h" +#include "film_encoder.h" +#include "player_text.h" + + +namespace dcp { + class SubtitleAsset; +} + + +class Film; + + +/** @class SubtitleFilmEncoder. + * @brief An `encoder' which extracts a film's subtitles to DCP XML format. + */ +class SubtitleFilmEncoder : public FilmEncoder +{ +public: + SubtitleFilmEncoder(std::shared_ptr film, std::shared_ptr job, boost::filesystem::path output, std::string initial_name, bool split_reels, bool include_font); + + void go () override; + + /** @return the number of frames that are done */ + Frame frames_done () const override; + + bool finishing () const override { + return false; + } + +private: + void text (PlayerText subs, TextType type, boost::optional track, dcpomatic::DCPTimePeriod period); + + std::vector, boost::filesystem::path>> _assets; + std::vector _reels; + bool _split_reels; + bool _include_font; + int _reel_index; + boost::optional _last; + dcpomatic::DCPTime _length; + dcp::ArrayData _default_font; +}; diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index ba420ab94..98c6784a9 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -28,11 +28,11 @@ #include "compose.hpp" #include "content.h" #include "config.h" -#include "dcp_encoder.h" +#include "dcp_film_encoder.h" #include "dcpomatic_log.h" -#include "encoder.h" #include "examine_content_job.h" #include "film.h" +#include "film_encoder.h" #include "job_manager.h" #include "log.h" #include "transcode_job.h" @@ -84,7 +84,7 @@ TranscodeJob::json_name () const void -TranscodeJob::set_encoder (shared_ptr e) +TranscodeJob::set_encoder(shared_ptr e) { _encoder = e; } @@ -133,7 +133,7 @@ TranscodeJob::run () LOG_GENERAL(N_("Transcode job completed successfully: %1 fps"), dcp::locale_convert(frames_per_second(), 2, true)); - if (dynamic_pointer_cast(_encoder)) { + if (dynamic_pointer_cast(_encoder)) { try { Analytics::instance()->successful_dcp_encode(); } catch (FileError& e) { diff --git a/src/lib/transcode_job.h b/src/lib/transcode_job.h index 35870231d..720d7f99b 100644 --- a/src/lib/transcode_job.h +++ b/src/lib/transcode_job.h @@ -35,7 +35,7 @@ #undef IGNORE -class Encoder; +class FilmEncoder; struct frames_not_lost_when_threads_disappear; @@ -65,7 +65,7 @@ public: return true; } - void set_encoder (std::shared_ptr t); + void set_encoder(std::shared_ptr encoder); private: friend struct ::frames_not_lost_when_threads_disappear; @@ -75,7 +75,7 @@ private: int remaining_time () const override; - std::shared_ptr _encoder; + std::shared_ptr _encoder; ChangedBehaviour _changed; }; diff --git a/src/lib/wscript b/src/lib/wscript index 4eeeb578e..5e49b1fbf 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -68,9 +68,9 @@ sources = """ dcp_content.cc dcp_content_type.cc dcp_decoder.cc - dcp_encoder.cc dcp_examiner.cc dcp_digest_file.cc + dcp_film_encoder.cc dcp_subtitle.cc dcp_subtitle_content.cc dcp_subtitle_decoder.cc @@ -89,7 +89,6 @@ sources = """ dolby_cp750.cc email.cc empty.cc - encoder.cc encode_server.cc encode_server_finder.cc encoded_log_entry.cc @@ -107,14 +106,15 @@ sources = """ ffmpeg_audio_stream.cc ffmpeg_content.cc ffmpeg_decoder.cc - ffmpeg_encoder.cc ffmpeg_examiner.cc ffmpeg_file_encoder.cc + ffmpeg_film_encoder.cc ffmpeg_image_proxy.cc ffmpeg_stream.cc ffmpeg_subtitle_stream.cc ffmpeg_wrapper.cc film.cc + film_encoder.cc film_util.cc filter.cc font.cc @@ -187,7 +187,7 @@ sources = """ string_text_file_content.cc string_text_file_decoder.cc subtitle_analysis.cc - subtitle_encoder.cc + subtitle_film_encoder.cc territory_type.cc text_ring_buffers.cc text_type.cc diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index 5f723ba0f..de4ddebc2 100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@ -76,7 +76,7 @@ #include "lib/email.h" #include "lib/encode_server_finder.h" #include "lib/exceptions.h" -#include "lib/ffmpeg_encoder.h" +#include "lib/ffmpeg_film_encoder.h" #include "lib/film.h" #include "lib/font_config.h" #ifdef DCPOMATIC_GROK @@ -91,7 +91,7 @@ #include "lib/screen.h" #include "lib/send_kdm_email_job.h" #include "lib/signal_manager.h" -#include "lib/subtitle_encoder.h" +#include "lib/subtitle_film_encoder.h" #include "lib/text_content.h" #include "lib/transcode_job.h" #include "lib/update_checker.h" @@ -1029,7 +1029,7 @@ private: auto job = make_shared(_film, TranscodeJob::ChangedBehaviour::EXAMINE_THEN_STOP); job->set_encoder ( - make_shared ( + make_shared( _film, job, dialog.path(), dialog.format(), dialog.mixdown_to_stereo(), dialog.split_reels(), dialog.split_streams(), dialog.x264_crf()) ); JobManager::instance()->add (job); @@ -1044,7 +1044,7 @@ private: } auto job = make_shared(_film, TranscodeJob::ChangedBehaviour::EXAMINE_THEN_STOP); job->set_encoder( - make_shared(_film, job, dialog.path(), _film->isdcf_name(true), dialog.split_reels(), dialog.include_font()) + make_shared(_film, job, dialog.path(), _film->isdcf_name(true), dialog.split_reels(), dialog.include_font()) ); JobManager::instance()->add(job); } diff --git a/src/tools/dcpomatic_cli.cc b/src/tools/dcpomatic_cli.cc index c087f89e7..9eec498f9 100644 --- a/src/tools/dcpomatic_cli.cc +++ b/src/tools/dcpomatic_cli.cc @@ -25,7 +25,7 @@ #include "lib/cross.h" #include "lib/dcpomatic_log.h" #include "lib/encode_server_finder.h" -#include "lib/ffmpeg_encoder.h" +#include "lib/ffmpeg_film_encoder.h" #include "lib/film.h" #include "lib/filter.h" #ifdef DCPOMATIC_GROK @@ -519,7 +519,7 @@ main (int argc, char* argv[]) if (export_format) { auto job = std::make_shared(film, behaviour); job->set_encoder ( - std::make_shared ( + std::make_shared( film, job, *export_filename, *export_format == "mp4" ? ExportFormat::H264_AAC : ExportFormat::PRORES_HQ, false, false, false, 23 ) ); diff --git a/src/tools/dcpomatic_combiner.cc b/src/tools/dcpomatic_combiner.cc index 6588b23b4..a28e063e5 100644 --- a/src/tools/dcpomatic_combiner.cc +++ b/src/tools/dcpomatic_combiner.cc @@ -30,6 +30,7 @@ #include "lib/constants.h" #include "lib/cross.h" #include "lib/job_manager.h" +#include "lib/util.h" #include LIBDCP_DISABLE_WARNINGS #include diff --git a/src/tools/dcpomatic_editor.cc b/src/tools/dcpomatic_editor.cc index e1f541fe8..fc04ce017 100644 --- a/src/tools/dcpomatic_editor.cc +++ b/src/tools/dcpomatic_editor.cc @@ -29,6 +29,7 @@ #include "lib/cross.h" #include "lib/dcpomatic_log.h" #include "lib/null_log.h" +#include "lib/util.h" #include "lib/variant.h" #include #include diff --git a/src/tools/dcpomatic_kdm.cc b/src/tools/dcpomatic_kdm.cc index d6c8b3945..1eda05162 100644 --- a/src/tools/dcpomatic_kdm.cc +++ b/src/tools/dcpomatic_kdm.cc @@ -53,6 +53,7 @@ #include "lib/kdm_with_metadata.h" #include "lib/screen.h" #include "lib/send_kdm_email_job.h" +#include "lib/util.h" #include "lib/variant.h" #include #include diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index 04bb26c2e..05c3f281c 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -27,6 +27,7 @@ #include "static_text.h" #include "wx_variant.h" #include "lib/constants.h" +#include "lib/util.h" #include #include #include diff --git a/src/wx/dcp_timeline.h b/src/wx/dcp_timeline.h index 3413c2814..23644c03f 100644 --- a/src/wx/dcp_timeline.h +++ b/src/wx/dcp_timeline.h @@ -25,6 +25,8 @@ #include "timecode.h" #include "timeline.h" +#include "lib/change_signaller.h" +#include "lib/film_property.h" #include "lib/rect.h" #include LIBDCP_DISABLE_WARNINGS diff --git a/src/wx/export_video_file_dialog.h b/src/wx/export_video_file_dialog.h index beb33610b..4e626be6b 100644 --- a/src/wx/export_video_file_dialog.h +++ b/src/wx/export_video_file_dialog.h @@ -20,7 +20,7 @@ #include "table_dialog.h" -#include "lib/ffmpeg_encoder.h" +#include "lib/ffmpeg_file_encoder.h" #include LIBDCP_DISABLE_WARNINGS #include diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index 5824f8baa..63aa113d1 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -25,8 +25,10 @@ #include "video_view.h" +#include "lib/change_signaller.h" #include "lib/config.h" #include "lib/film_property.h" +#include "lib/player.h" #include "lib/player_text.h" #include "lib/signaller.h" #include "lib/timer.h" diff --git a/src/wx/kdm_cpl_panel.cc b/src/wx/kdm_cpl_panel.cc index 4e1eb8f34..523d0c369 100644 --- a/src/wx/kdm_cpl_panel.cc +++ b/src/wx/kdm_cpl_panel.cc @@ -23,6 +23,7 @@ #include "kdm_cpl_panel.h" #include "static_text.h" #include "wx_util.h" +#include #include LIBDCP_DISABLE_WARNINGS #include diff --git a/src/wx/timeline_content_view.cc b/src/wx/timeline_content_view.cc index cb0d10240..69a675c42 100644 --- a/src/wx/timeline_content_view.cc +++ b/src/wx/timeline_content_view.cc @@ -23,6 +23,7 @@ #include "timeline_content_view.h" #include "wx_util.h" #include "lib/content.h" +#include "lib/util.h" #include LIBDCP_DISABLE_WARNINGS #include -- cgit v1.2.3