Add --auto-crop option to create CLI (#2968).
authorCarl Hetherington <cth@carlh.net>
Wed, 19 Mar 2025 16:20:23 +0000 (17:20 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 19 Mar 2025 20:11:17 +0000 (21:11 +0100)
doc/manual/dcpomatic_create.xml
src/lib/create_cli.cc
src/lib/create_cli.h
test/create_cli_test.cc

index ba98c878db841f5eb5eea82f2016fbcae62b244b..516b806ffcfc597bcbd5663279eb1f7b472c786c 100644 (file)
@@ -22,6 +22,7 @@
 <listitem><code>--j2k-bandwidth &lt;Mbit/s&gt;</code> &#8212; J2K bandwidth in Mbit/s</listitem>
 <listitem><code>--left-eye</code> &#8212; next piece of content is for the left eye</listitem>
 <listitem><code>--right-eye</code> &#8212; next piece of content is for the right eye</listitem>
+<listitem><code>--auto-crop</code> &#8212; next piece of content should be auto-cropped</listitem>
 <listitem><code>--channel &lt;channel&gt;</code> &#8212; next piece of content should be mapped to audio channel L, R, C, Lfe, Ls, Rs, BsL, BsR, HI, VI</listitem>
 <listitem><code>--gain</code> &#8212; next piece of content should have the given audio gain (in dB)</listitem>
 <listitem><code>--cpl &lt;id&gt;</code> &#8212; CPL ID to use from the next piece of content (which is a DCP)</listitem>
index c7a49ada99fdc6c8ffe4aa373aeeacbba7168196..96a889bc4f3aa0b9915b7fbe441e3f16860a92ff 100644 (file)
@@ -30,6 +30,7 @@
 #include "dcpomatic_log.h"
 #include "film.h"
 #include "image_content.h"
+#include "guess_crop.h"
 #include "job_manager.h"
 #include "ratio.h"
 #include "variant.h"
@@ -73,6 +74,7 @@ string CreateCLI::_help =
        "      --j2k-bandwidth <Mbit/s>  J2K bandwidth in Mbit/s\n"
        "      --left-eye                next piece of content is for the left eye\n"
        "      --right-eye               next piece of content is for the right eye\n"
+       "      --auto-crop               next piece of content should be auto-cropped\n"
        "      --channel <channel>       next piece of content should be mapped to audio channel L, R, C, Lfe, Ls, Rs, BsL, BsR, HI, VI\n"
        "      --gain                    next piece of content should have the given audio gain (in dB)\n"
        "      --cpl <id>                CPL ID to use from the next piece of content (which is a DCP)\n"
@@ -165,6 +167,7 @@ CreateCLI::CreateCLI(int argc, char* argv[])
        int64_t video_bit_rate_int = 0;
        optional<int> audio_channels;
        auto next_frame_type = VideoFrameType::TWO_D;
+       auto next_auto_crop = false;
        optional<dcp::Channel> channel;
        optional<float> gain;
        optional<boost::filesystem::path> kdm;
@@ -201,6 +204,9 @@ CreateCLI::CreateCLI(int argc, char* argv[])
                } else if (a == "--right-eye") {
                        next_frame_type = VideoFrameType::THREE_D_RIGHT;
                        claimed = true;
+               } else if (a == "--auto-crop") {
+                       next_auto_crop = true;
+                       claimed = true;
                } else if (a == "--twok") {
                        _twok = true;
                        claimed = true;
@@ -288,12 +294,14 @@ CreateCLI::CreateCLI(int argc, char* argv[])
                                Content c;
                                c.path = a;
                                c.frame_type = next_frame_type;
+                               c.auto_crop = next_auto_crop;
                                c.channel = channel;
                                c.gain = gain;
                                c.kdm = kdm;
                                c.cpl = cpl;
                                content.push_back(c);
                                next_frame_type = VideoFrameType::TWO_D;
+                               next_auto_crop = false;
                                channel = {};
                                gain = {};
                        }
@@ -477,6 +485,31 @@ CreateCLI::make_film(function<void (string)> error) const
                for (auto film_content: film_content_list) {
                        if (film_content->video) {
                                film_content->video->set_frame_type(cli_content.frame_type);
+                               if (cli_content.auto_crop) {
+                                       auto crop = guess_crop_by_brightness(
+                                               film,
+                                               film_content,
+                                               Config::instance()->auto_crop_threshold(),
+                                               std::min(
+                                                       dcpomatic::ContentTime::from_seconds(1),
+                                                       dcpomatic::ContentTime::from_frames(
+                                                               film_content->video->length(),
+                                                               film_content->video_frame_rate().get_value_or(24)
+                                                       )
+                                               )
+                                       );
+
+                                       error(fmt::format(
+                                               "Cropped {} to {} left, {} right, {} top and {} bottom",
+                                               film_content->path(0).string(),
+                                               crop.left,
+                                               crop.right,
+                                               crop.top,
+                                               crop.bottom
+                                       ));
+
+                                       film_content->video->set_crop(crop);
+                               }
                        }
                        if (film_content->audio && cli_content.channel) {
                                for (auto stream: film_content->audio->streams()) {
index 1ce345f1b735c77eeae17d7f312417dbf303377e..875fe10c12a76b49da881c4a451dd6e6dd860072 100644 (file)
@@ -41,6 +41,7 @@ public:
        struct Content {
                boost::filesystem::path path;
                VideoFrameType frame_type = VideoFrameType::TWO_D;
+               bool auto_crop = false;
                boost::optional<dcp::Channel> channel;
                boost::optional<float> gain;
                boost::optional<boost::filesystem::path> kdm;
index 9716fbef3a2535d8e4ce663263a28d23b29ae872..6499ef160a9aeb4802f44dd1aed66e62f05469d8 100644 (file)
 
 
 #include "lib/config.h"
+#include "lib/content.h"
 #include "lib/create_cli.h"
+#include "lib/dcp_content_type.h"
 #include "lib/film.h"
 #include "lib/ratio.h"
-#include "lib/dcp_content_type.h"
+#include "lib/video_content.h"
 #include "test.h"
+#include <fmt/format.h>
 #include <boost/test/unit_test.hpp>
 #include <boost/tokenizer.hpp>
 #include <boost/algorithm/string/predicate.hpp>
@@ -186,6 +189,26 @@ BOOST_AUTO_TEST_CASE (create_cli_test)
        BOOST_CHECK_EQUAL(cc._fourk, true);
        BOOST_CHECK (!cc.error);
 
+       cc = run("dcpomatic2_create --auto-crop foo.mp4 bar.mp4 --auto-crop baz.mp4");
+       BOOST_REQUIRE_EQUAL(cc.content.size(), 3U);
+       BOOST_CHECK(cc.content[0].auto_crop);
+       BOOST_CHECK(!cc.content[1].auto_crop);
+       BOOST_CHECK(cc.content[2].auto_crop);
+
+       cc = run("dcpomatic2_create --auto-crop foo.mp4 bar.mp4 --auto-crop baz.mp4");
+       BOOST_REQUIRE_EQUAL(cc.content.size(), 3U);
+       BOOST_CHECK(cc.content[0].auto_crop);
+       BOOST_CHECK(!cc.content[1].auto_crop);
+       BOOST_CHECK(cc.content[2].auto_crop);
+
+       auto pillarbox = TestPaths::private_data() / "pillarbox.png";
+       cc = run("dcpomatic2_create --auto-crop " + pillarbox.string());
+       auto film = cc.make_film(error);
+       BOOST_CHECK_EQUAL(film->content().size(), 1U);
+       BOOST_CHECK(film->content()[0]->video->actual_crop() == Crop(113, 262, 0, 0));
+       BOOST_CHECK_EQUAL(collected_error, fmt::format("Cropped {} to 113 left, 262 right, 0 top and 0 bottom", pillarbox.string()));
+       collected_error = "";
+
        cc = run ("dcpomatic2_create --video-bit-rate 120 foo.mp4");
        BOOST_REQUIRE_EQUAL (cc.content.size(), 1U);
        BOOST_CHECK_EQUAL (cc.content[0].path, "foo.mp4");
@@ -203,7 +226,7 @@ BOOST_AUTO_TEST_CASE (create_cli_test)
        BOOST_CHECK (*cc.content[1].channel == dcp::Channel::RIGHT);
        BOOST_CHECK_EQUAL (cc.content[2].path, "test/data/Lfe.wav");
        BOOST_CHECK (!cc.content[2].channel);
-       auto film = cc.make_film(out, error);
+       film = cc.make_film(error);
        BOOST_CHECK_EQUAL(film->audio_channels(), 6);
        BOOST_CHECK(collected_error.empty());