diff options
| author | Carl Hetherington <cth@carlh.net> | 2025-08-22 23:50:28 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2025-08-25 11:22:27 +0200 |
| commit | 6ea9b75c5fc4736f19a424796a3d2c7550fb16dc (patch) | |
| tree | fc826b31fc5bc5edab88ff1b4c5759e95afd4cef | |
| parent | b02325ff69686381f40fee39df35666e58df367e (diff) | |
Add cover sheet magic strings for marker positions (#3076).
| -rw-r--r-- | doc/manual/dcpomatic.xml | 79 | ||||
| -rw-r--r-- | src/lib/cover_sheet.cc | 46 | ||||
| -rw-r--r-- | test/cover_sheet_test.cc | 68 | ||||
| m--------- | test/data | 0 | ||||
| -rw-r--r-- | test/wscript | 1 |
5 files changed, 194 insertions, 0 deletions
diff --git a/doc/manual/dcpomatic.xml b/doc/manual/dcpomatic.xml index f74299ac9..975d8bb7c 100644 --- a/doc/manual/dcpomatic.xml +++ b/doc/manual/dcpomatic.xml @@ -3325,6 +3325,85 @@ DCP that has been made: </table> <para> +You can also insert the timecode of any of the DCP's markers using <code>$</code> with the marker's name: +</para> + +<table> +<tgroup cols='2' align='left' colsep='1' rowsep='1'> +<tbody> +<row> +<entry><code>$FFOC</code></entry><entry>First frame of content</entry> +</row> +<row> +<entry><code>$LFOC</code></entry><entry>Last frame of content</entry> +</row> +<row> +<entry><code>$FFTC</code></entry><entry>First frame of title credits</entry> +</row> +<row> +<entry><code>$LFTC</code></entry><entry>Last frame of title credits</entry> +</row> +<row> +<entry><code>$FFOI</code></entry><entry>First frame of intermission</entry> +</row> +<row> +<entry><code>$LFOI</code></entry><entry>Last frame of intermission</entry> +</row> +<row> +<entry><code>$FFEC</code></entry><entry>First frame of end credits</entry> +</row> +<row> +<entry><code>$LFEC</code></entry><entry>Last frame of end credits</entry> +</row> +<row> +<entry><code>$FFMC</code></entry><entry>First frame of moving credits</entry> +</row> +<row> +<entry><code>$LFMC</code></entry><entry>Last frame of moving credits</entry> +</row> +<row> +<entry><code>$FFOB</code></entry><entry>First frame of ratings band</entry> +</row> +<row> +<entry><code>$LFOB</code></entry><entry>Last frame of ratings band</entry> +</row> +</tbody> +</tgroup> +</table> + +<para> +These magic strings will be replaced with ‘Unknown’ if the marker is not defined. +Alternatively, adding <code>_LINE</code> to a marker magic string will make the +timecode appear if the marker is set, otherwise the whole line containing the magic string +will be removed. +</para> + +<para> +For example, a cover sheet defined as +</para> + +<para> +<programlisting> +Hello: $FFMC +Goodbye: $FFMC_LINE +</programlisting> +</para> + +<para> +will be written as +</para> + +<para> +<programlisting> +Hello: Unknown +</programlisting> +</para> + +<para> +if the <code>FFMC</code> marker is undefined. +</para> + +<para> Clicking <guilabel>Reset to default text</guilabel> will replace the current cover sheet with DCP-o-matic's default. </para> diff --git a/src/lib/cover_sheet.cc b/src/lib/cover_sheet.cc index 52296fac7..b0450dbd0 100644 --- a/src/lib/cover_sheet.cc +++ b/src/lib/cover_sheet.cc @@ -33,6 +33,7 @@ using std::shared_ptr; using std::string; +using std::vector; void @@ -105,6 +106,51 @@ dcpomatic::write_cover_sheet(shared_ptr<const Film> film, boost::filesystem::pat boost::algorithm::replace_all(text, "$LENGTH", length); + auto const markers = film->markers(); + + auto marker = [&markers, &text, film](dcp::Marker marker) { + auto iter = markers.find(marker); + auto const tag = "$" + marker_to_string(marker); + auto const tag_line = tag + "_LINE"; + + if (iter != markers.end()) { + auto const timecode = time_to_hmsf(iter->second, film->video_frame_rate()); + boost::algorithm::replace_all(text, tag_line, timecode); + boost::algorithm::replace_all(text, tag, timecode); + } else { + vector<string> before_lines; + vector<string> after_lines; + boost::algorithm::split(before_lines, text, boost::is_any_of("\n")); + if (!before_lines.empty()) { + before_lines.pop_back(); + } + for (auto& line: before_lines) { + if (line.find(tag_line) == std::string::npos) { + after_lines.push_back(line); + } + } + text.clear(); + for (auto const& line: after_lines) { + text += line + "\n"; + } + + boost::algorithm::replace_all(text, tag, _("Unknown")); + } + }; + + marker(dcp::Marker::FFOC); + marker(dcp::Marker::LFOC); + marker(dcp::Marker::FFTC); + marker(dcp::Marker::LFTC); + marker(dcp::Marker::FFOI); + marker(dcp::Marker::LFOI); + marker(dcp::Marker::FFEC); + marker(dcp::Marker::LFEC); + marker(dcp::Marker::FFMC); + marker(dcp::Marker::LFMC); + marker(dcp::Marker::FFOB); + marker(dcp::Marker::LFOB); + file.checked_write(text.c_str(), text.length()); } diff --git a/test/cover_sheet_test.cc b/test/cover_sheet_test.cc new file mode 100644 index 000000000..484b99ec8 --- /dev/null +++ b/test/cover_sheet_test.cc @@ -0,0 +1,68 @@ +/* + Copyright (C) 2025 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 "lib/config.h" +#include "lib/cover_sheet.h" +#include "lib/dcpomatic_time.h" +#include "lib/film.h" +#include "test.h" +#include <boost/test/unit_test.hpp> + + +BOOST_AUTO_TEST_CASE(cover_sheet_test) +{ + ConfigRestorer cr; + + auto film = new_test_film("cover_sheet_test"); + film->set_video_frame_rate(24); + + film->set_marker(dcp::Marker::FFOC, dcpomatic::DCPTime::from_frames(24 * 6 + 9, 24)); + film->set_marker(dcp::Marker::LFOC, dcpomatic::DCPTime::from_frames(24 * 42 + 15, 24)); + film->set_marker(dcp::Marker::FFTC, dcpomatic::DCPTime::from_frames(24 * 95 + 4, 24)); + film->set_marker(dcp::Marker::LFTC, dcpomatic::DCPTime::from_frames(24 * 106 + 1, 24)); + film->set_marker(dcp::Marker::FFOI, dcpomatic::DCPTime::from_frames(24 * 112 + 0, 24)); + film->set_marker(dcp::Marker::LFOI, dcpomatic::DCPTime::from_frames(24 * 142 + 6, 24)); + film->set_marker(dcp::Marker::FFEC, dcpomatic::DCPTime::from_frames(24 * 216 + 23, 24)); + film->set_marker(dcp::Marker::LFEC, dcpomatic::DCPTime::from_frames(24 * 242 + 21, 24)); + film->set_marker(dcp::Marker::FFMC, dcpomatic::DCPTime::from_frames(24 * 250 + 23, 24)); + film->set_marker(dcp::Marker::LFMC, dcpomatic::DCPTime::from_frames(24 * 251 + 21, 24)); + + Config::instance()->set_cover_sheet( + "First frame of content: $FFOC\n" + "Last frame of content: $LFOC\n" + "First frame of title credits: $FFTC\n" + "Last frame of title credits: $LFTC\n" + "First frame of intermission: $FFOI\n" + "Last frame of intermission: $LFOI\n" + "First frame of end credits: $FFEC\n" + "Last frame of end credits: $LFEC\n" + "First frame of moving credits: $FFMC\n" + "Last frame of moving credits: $LFMC\n" + "First frame of ratings band: $FFOB\n" + "Last frame of ratings band: $LFOB\n" + "First frame of ratings band (to remove): $FFOB_LINE\n" + "Last frame of ratings band (to remove): $LFOB_LINE\n" + ); + + dcpomatic::write_cover_sheet(film, "test/data/dcp_digest_test_dcp", "build/test/cover_sheet.txt"); + check_text_file("test/data/cover_sheet.txt", "build/test/cover_sheet.txt"); +} + diff --git a/test/data b/test/data -Subproject d1292b1ce9a2ee42320e7d3b94e94ea1e6101db +Subproject 0e08d315725cb18acd04880eb6c7f463f003873 diff --git a/test/wscript b/test/wscript index d9529d0b8..4bd2c8891 100644 --- a/test/wscript +++ b/test/wscript @@ -72,6 +72,7 @@ def build(bld): config_test.cc content_test.cc copy_dcp_details_to_film_test.cc + cover_sheet_test.cc cpl_hash_test.cc cpl_metadata_test.cc create_cli_test.cc |
