2 Copyright (C) 2021 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
23 #include "dcp_video.h"
24 #include "dcpomatic_log.h"
25 #include "j2k_encoder_cpu_backend.h"
26 #include "player_video.h"
28 #include <dcp/openjpeg_image.h>
29 #include <dcp/j2k_transcode.h>
34 using std::shared_ptr;
35 using boost::optional;
36 #if BOOST_VERSION >= 106100
37 using namespace boost::placeholders;
41 optional<dcp::ArrayData>
42 J2KEncoderCPUBackend::encode (DCPVideo video)
45 auto const comment = Config::instance()->dcp_j2k_comment();
47 /* This was empirically derived by a user: see #1902 */
48 int const minimum_size = 16384;
49 LOG_GENERAL ("Using minimum frame size %1", minimum_size);
51 auto xyz = DCPVideo::convert_to_xyz (video.frame(), boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2));
55 auto enc = dcp::compress_j2k (
57 video.j2k_bandwidth(),
58 video.frames_per_second(),
59 video.frame()->eyes() == Eyes::LEFT || video.frame()->eyes() == Eyes::RIGHT,
60 video.resolution() == Resolution::FOUR_K,
61 comment.empty() ? "libdcp" : comment
64 if (enc.size() >= minimum_size) {
65 LOG_GENERAL (N_("Frame %1 encoded size was OK (%2)"), video.index(), enc.size());
69 LOG_GENERAL (N_("Frame %1 encoded size was small (%2); adding noise at level %3 with pixel skip %4"), video.index(), enc.size(), noise_amount, pixel_skip);
71 /* The JPEG2000 is too low-bitrate for some decoders <cough>DSS200</cough> so add some noise
72 * and try again. This is slow but hopefully won't happen too often. We have to do
73 * convert_to_xyz() again because compress_j2k() corrupts its xyz parameter.
76 xyz = DCPVideo::convert_to_xyz (video.frame(), boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2));
77 auto const size = xyz->size ();
78 auto const pixels = size.width * size.height;
79 dcpomatic::RNG rng(42);
80 for (auto c = 0; c < 3; ++c) {
81 auto p = xyz->data(c);
82 auto e = xyz->data(c) + pixels;
84 *p = std::min(4095, std::max(0, *p + (rng.get() % noise_amount)));
94 /* Something's gone badly wrong if this much noise doesn't help */
95 DCPOMATIC_ASSERT (noise_amount < 16);
98 switch (video.frame()->eyes()) {
100 LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for mono"), video.index());
103 LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for L"), video.index());
106 LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for R"), video.index());
111 } catch (std::exception& e) {
112 LOG_ERROR (N_("Local encode failed (%1)"), e.what());